import of openssh-5.8p1 openssh-5.8p1
authorLuke Howard <lukeh@padl.com>
Mon, 21 Mar 2011 07:50:36 +0000 (03:50 -0400)
committerLuke Howard <lukeh@padl.com>
Mon, 21 Mar 2011 07:50:36 +0000 (03:50 -0400)
471 files changed:
CREDITS [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENCE [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
OVERVIEW [new file with mode: 0644]
PROTOCOL [new file with mode: 0644]
PROTOCOL.agent [new file with mode: 0644]
PROTOCOL.certkeys [new file with mode: 0644]
PROTOCOL.mux [new file with mode: 0644]
README [new file with mode: 0644]
README.dns [new file with mode: 0644]
README.platform [new file with mode: 0644]
README.privsep [new file with mode: 0644]
README.tun [new file with mode: 0644]
TODO [new file with mode: 0644]
WARNING.RNG [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
acss.c [new file with mode: 0644]
acss.h [new file with mode: 0644]
addrmatch.c [new file with mode: 0644]
atomicio.c [new file with mode: 0644]
atomicio.h [new file with mode: 0644]
audit-bsm.c [new file with mode: 0644]
audit-linux.c [new file with mode: 0644]
audit.c [new file with mode: 0644]
audit.h [new file with mode: 0644]
auth-bsdauth.c [new file with mode: 0644]
auth-chall.c [new file with mode: 0644]
auth-krb5.c [new file with mode: 0644]
auth-options.c [new file with mode: 0644]
auth-options.h [new file with mode: 0644]
auth-pam.c [new file with mode: 0644]
auth-pam.h [new file with mode: 0644]
auth-passwd.c [new file with mode: 0644]
auth-rh-rsa.c [new file with mode: 0644]
auth-rhosts.c [new file with mode: 0644]
auth-rsa.c [new file with mode: 0644]
auth-shadow.c [new file with mode: 0644]
auth-sia.c [new file with mode: 0644]
auth-sia.h [new file with mode: 0644]
auth-skey.c [new file with mode: 0644]
auth.c [new file with mode: 0644]
auth.h [new file with mode: 0644]
auth1.c [new file with mode: 0644]
auth2-chall.c [new file with mode: 0644]
auth2-gss.c [new file with mode: 0644]
auth2-hostbased.c [new file with mode: 0644]
auth2-jpake.c [new file with mode: 0644]
auth2-kbdint.c [new file with mode: 0644]
auth2-none.c [new file with mode: 0644]
auth2-passwd.c [new file with mode: 0644]
auth2-pubkey.c [new file with mode: 0644]
auth2.c [new file with mode: 0644]
authfd.c [new file with mode: 0644]
authfd.h [new file with mode: 0644]
authfile.c [new file with mode: 0644]
authfile.h [new file with mode: 0644]
bufaux.c [new file with mode: 0644]
bufbn.c [new file with mode: 0644]
bufec.c [new file with mode: 0644]
buffer.c [new file with mode: 0644]
buffer.h [new file with mode: 0644]
buildpkg.sh.in [new file with mode: 0644]
canohost.c [new file with mode: 0644]
canohost.h [new file with mode: 0644]
channels.c [new file with mode: 0644]
channels.h [new file with mode: 0644]
cipher-3des1.c [new file with mode: 0644]
cipher-acss.c [new file with mode: 0644]
cipher-aes.c [new file with mode: 0644]
cipher-bf1.c [new file with mode: 0644]
cipher-ctr.c [new file with mode: 0644]
cipher.c [new file with mode: 0644]
cipher.h [new file with mode: 0644]
cleanup.c [new file with mode: 0644]
clientloop.c [new file with mode: 0644]
clientloop.h [new file with mode: 0644]
compat.c [new file with mode: 0644]
compat.h [new file with mode: 0644]
compress.c [new file with mode: 0644]
compress.h [new file with mode: 0644]
config.guess [new file with mode: 0755]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0755]
configure [new file with mode: 0755]
configure.ac [new file with mode: 0644]
contrib/Makefile [new file with mode: 0644]
contrib/README [new file with mode: 0644]
contrib/aix/README [new file with mode: 0644]
contrib/aix/buildbff.sh [new file with mode: 0755]
contrib/aix/inventory.sh [new file with mode: 0755]
contrib/aix/pam.conf [new file with mode: 0644]
contrib/caldera/openssh.spec [new file with mode: 0644]
contrib/caldera/ssh-host-keygen [new file with mode: 0755]
contrib/caldera/sshd.init [new file with mode: 0755]
contrib/caldera/sshd.pam [new file with mode: 0644]
contrib/cygwin/Makefile [new file with mode: 0644]
contrib/cygwin/README [new file with mode: 0644]
contrib/cygwin/ssh-host-config [new file with mode: 0644]
contrib/cygwin/ssh-user-config [new file with mode: 0644]
contrib/cygwin/sshd-inetd [new file with mode: 0644]
contrib/findssl.sh [new file with mode: 0644]
contrib/gnome-ssh-askpass1.c [new file with mode: 0644]
contrib/gnome-ssh-askpass2.c [new file with mode: 0644]
contrib/hpux/README [new file with mode: 0644]
contrib/hpux/egd [new file with mode: 0644]
contrib/hpux/egd.rc [new file with mode: 0755]
contrib/hpux/sshd [new file with mode: 0644]
contrib/hpux/sshd.rc [new file with mode: 0755]
contrib/redhat/gnome-ssh-askpass.csh [new file with mode: 0644]
contrib/redhat/gnome-ssh-askpass.sh [new file with mode: 0644]
contrib/redhat/openssh.spec [new file with mode: 0644]
contrib/redhat/sshd.init [new file with mode: 0755]
contrib/redhat/sshd.init.old [new file with mode: 0755]
contrib/redhat/sshd.pam [new file with mode: 0644]
contrib/redhat/sshd.pam.old [new file with mode: 0644]
contrib/solaris/README [new file with mode: 0755]
contrib/ssh-copy-id [new file with mode: 0644]
contrib/ssh-copy-id.1 [new file with mode: 0644]
contrib/sshd.pam.freebsd [new file with mode: 0644]
contrib/sshd.pam.generic [new file with mode: 0644]
contrib/suse/openssh.spec [new file with mode: 0644]
contrib/suse/rc.config.sshd [new file with mode: 0644]
contrib/suse/rc.sshd [new file with mode: 0644]
contrib/suse/sysconfig.ssh [new file with mode: 0644]
crc32.c [new file with mode: 0644]
crc32.h [new file with mode: 0644]
deattack.c [new file with mode: 0644]
deattack.h [new file with mode: 0644]
defines.h [new file with mode: 0644]
dh.c [new file with mode: 0644]
dh.h [new file with mode: 0644]
dispatch.c [new file with mode: 0644]
dispatch.h [new file with mode: 0644]
dns.c [new file with mode: 0644]
dns.h [new file with mode: 0644]
entropy.c [new file with mode: 0644]
entropy.h [new file with mode: 0644]
fatal.c [new file with mode: 0644]
fixpaths [new file with mode: 0755]
fixprogs [new file with mode: 0755]
groupaccess.c [new file with mode: 0644]
groupaccess.h [new file with mode: 0644]
gss-genr.c [new file with mode: 0644]
gss-serv-krb5.c [new file with mode: 0644]
gss-serv.c [new file with mode: 0644]
hostfile.c [new file with mode: 0644]
hostfile.h [new file with mode: 0644]
includes.h [new file with mode: 0644]
install-sh [new file with mode: 0755]
jpake.c [new file with mode: 0644]
jpake.h [new file with mode: 0644]
kex.c [new file with mode: 0644]
kex.h [new file with mode: 0644]
kexdh.c [new file with mode: 0644]
kexdhc.c [new file with mode: 0644]
kexdhs.c [new file with mode: 0644]
kexecdh.c [new file with mode: 0644]
kexecdhc.c [new file with mode: 0644]
kexecdhs.c [new file with mode: 0644]
kexgex.c [new file with mode: 0644]
kexgexc.c [new file with mode: 0644]
kexgexs.c [new file with mode: 0644]
key.c [new file with mode: 0644]
key.h [new file with mode: 0644]
log.c [new file with mode: 0644]
log.h [new file with mode: 0644]
loginrec.c [new file with mode: 0644]
loginrec.h [new file with mode: 0644]
logintest.c [new file with mode: 0644]
mac.c [new file with mode: 0644]
mac.h [new file with mode: 0644]
match.c [new file with mode: 0644]
match.h [new file with mode: 0644]
md-sha256.c [new file with mode: 0644]
md5crypt.c [new file with mode: 0644]
md5crypt.h [new file with mode: 0644]
mdoc2man.awk [new file with mode: 0644]
misc.c [new file with mode: 0644]
misc.h [new file with mode: 0644]
mkinstalldirs [new file with mode: 0755]
moduli [new file with mode: 0644]
moduli.0 [new file with mode: 0644]
moduli.5 [new file with mode: 0644]
moduli.c [new file with mode: 0644]
monitor.c [new file with mode: 0644]
monitor.h [new file with mode: 0644]
monitor_fdpass.c [new file with mode: 0644]
monitor_fdpass.h [new file with mode: 0644]
monitor_mm.c [new file with mode: 0644]
monitor_mm.h [new file with mode: 0644]
monitor_wrap.c [new file with mode: 0644]
monitor_wrap.h [new file with mode: 0644]
msg.c [new file with mode: 0644]
msg.h [new file with mode: 0644]
mux.c [new file with mode: 0644]
myproposal.h [new file with mode: 0644]
nchan.c [new file with mode: 0644]
nchan.ms [new file with mode: 0644]
nchan2.ms [new file with mode: 0644]
openbsd-compat/Makefile.in [new file with mode: 0644]
openbsd-compat/base64.c [new file with mode: 0644]
openbsd-compat/base64.h [new file with mode: 0644]
openbsd-compat/basename.c [new file with mode: 0644]
openbsd-compat/bindresvport.c [new file with mode: 0644]
openbsd-compat/bsd-arc4random.c [new file with mode: 0644]
openbsd-compat/bsd-asprintf.c [new file with mode: 0644]
openbsd-compat/bsd-closefrom.c [new file with mode: 0644]
openbsd-compat/bsd-cray.c [new file with mode: 0644]
openbsd-compat/bsd-cray.h [new file with mode: 0644]
openbsd-compat/bsd-cygwin_util.c [new file with mode: 0644]
openbsd-compat/bsd-cygwin_util.h [new file with mode: 0644]
openbsd-compat/bsd-getpeereid.c [new file with mode: 0644]
openbsd-compat/bsd-misc.c [new file with mode: 0644]
openbsd-compat/bsd-misc.h [new file with mode: 0644]
openbsd-compat/bsd-nextstep.c [new file with mode: 0644]
openbsd-compat/bsd-nextstep.h [new file with mode: 0644]
openbsd-compat/bsd-openpty.c [new file with mode: 0644]
openbsd-compat/bsd-poll.c [new file with mode: 0644]
openbsd-compat/bsd-poll.h [new file with mode: 0644]
openbsd-compat/bsd-snprintf.c [new file with mode: 0644]
openbsd-compat/bsd-statvfs.c [new file with mode: 0644]
openbsd-compat/bsd-statvfs.h [new file with mode: 0644]
openbsd-compat/bsd-waitpid.c [new file with mode: 0644]
openbsd-compat/bsd-waitpid.h [new file with mode: 0644]
openbsd-compat/charclass.h [new file with mode: 0644]
openbsd-compat/daemon.c [new file with mode: 0644]
openbsd-compat/dirname.c [new file with mode: 0644]
openbsd-compat/fake-rfc2553.c [new file with mode: 0644]
openbsd-compat/fake-rfc2553.h [new file with mode: 0644]
openbsd-compat/fmt_scaled.c [new file with mode: 0644]
openbsd-compat/getcwd.c [new file with mode: 0644]
openbsd-compat/getgrouplist.c [new file with mode: 0644]
openbsd-compat/getopt.c [new file with mode: 0644]
openbsd-compat/getrrsetbyname.c [new file with mode: 0644]
openbsd-compat/getrrsetbyname.h [new file with mode: 0644]
openbsd-compat/glob.c [new file with mode: 0644]
openbsd-compat/glob.h [new file with mode: 0644]
openbsd-compat/inet_aton.c [new file with mode: 0644]
openbsd-compat/inet_ntoa.c [new file with mode: 0644]
openbsd-compat/inet_ntop.c [new file with mode: 0644]
openbsd-compat/mktemp.c [new file with mode: 0644]
openbsd-compat/openbsd-compat.h [new file with mode: 0644]
openbsd-compat/openssl-compat.c [new file with mode: 0644]
openbsd-compat/openssl-compat.h [new file with mode: 0644]
openbsd-compat/port-aix.c [new file with mode: 0644]
openbsd-compat/port-aix.h [new file with mode: 0644]
openbsd-compat/port-irix.c [new file with mode: 0644]
openbsd-compat/port-irix.h [new file with mode: 0644]
openbsd-compat/port-linux.c [new file with mode: 0644]
openbsd-compat/port-linux.h [new file with mode: 0644]
openbsd-compat/port-solaris.c [new file with mode: 0644]
openbsd-compat/port-solaris.h [new file with mode: 0644]
openbsd-compat/port-tun.c [new file with mode: 0644]
openbsd-compat/port-tun.h [new file with mode: 0644]
openbsd-compat/port-uw.c [new file with mode: 0644]
openbsd-compat/port-uw.h [new file with mode: 0644]
openbsd-compat/pwcache.c [new file with mode: 0644]
openbsd-compat/readpassphrase.c [new file with mode: 0644]
openbsd-compat/readpassphrase.h [new file with mode: 0644]
openbsd-compat/realpath.c [new file with mode: 0644]
openbsd-compat/regress/Makefile.in [new file with mode: 0644]
openbsd-compat/regress/closefromtest.c [new file with mode: 0644]
openbsd-compat/regress/snprintftest.c [new file with mode: 0644]
openbsd-compat/regress/strduptest.c [new file with mode: 0644]
openbsd-compat/regress/strtonumtest.c [new file with mode: 0644]
openbsd-compat/rresvport.c [new file with mode: 0644]
openbsd-compat/setenv.c [new file with mode: 0644]
openbsd-compat/setproctitle.c [new file with mode: 0644]
openbsd-compat/sha2.c [new file with mode: 0755]
openbsd-compat/sha2.h [new file with mode: 0755]
openbsd-compat/sigact.c [new file with mode: 0644]
openbsd-compat/sigact.h [new file with mode: 0644]
openbsd-compat/strlcat.c [new file with mode: 0644]
openbsd-compat/strlcpy.c [new file with mode: 0644]
openbsd-compat/strmode.c [new file with mode: 0644]
openbsd-compat/strptime.c [new file with mode: 0644]
openbsd-compat/strsep.c [new file with mode: 0644]
openbsd-compat/strtoll.c [new file with mode: 0644]
openbsd-compat/strtonum.c [new file with mode: 0644]
openbsd-compat/strtoul.c [new file with mode: 0644]
openbsd-compat/sys-queue.h [new file with mode: 0644]
openbsd-compat/sys-tree.h [new file with mode: 0644]
openbsd-compat/timingsafe_bcmp.c [new file with mode: 0644]
openbsd-compat/vis.c [new file with mode: 0644]
openbsd-compat/vis.h [new file with mode: 0644]
openbsd-compat/xcrypt.c [new file with mode: 0644]
openbsd-compat/xmmap.c [new file with mode: 0644]
openssh.xml.in [new file with mode: 0644]
opensshd.init.in [new file with mode: 0755]
packet.c [new file with mode: 0644]
packet.h [new file with mode: 0644]
pathnames.h [new file with mode: 0644]
pkcs11.h [new file with mode: 0644]
platform.c [new file with mode: 0644]
platform.h [new file with mode: 0644]
progressmeter.c [new file with mode: 0644]
progressmeter.h [new file with mode: 0644]
readconf.c [new file with mode: 0644]
readconf.h [new file with mode: 0644]
readpass.c [new file with mode: 0644]
regress/Makefile [new file with mode: 0644]
regress/README.regress [new file with mode: 0644]
regress/addrmatch.sh [new file with mode: 0644]
regress/agent-getpeereid.sh [new file with mode: 0644]
regress/agent-pkcs11.sh [new file with mode: 0644]
regress/agent-ptrace.sh [new file with mode: 0644]
regress/agent-timeout.sh [new file with mode: 0644]
regress/agent.sh [new file with mode: 0644]
regress/banner.sh [new file with mode: 0644]
regress/broken-pipe.sh [new file with mode: 0644]
regress/brokenkeys.sh [new file with mode: 0644]
regress/bsd.regress.mk [new file with mode: 0644]
regress/cert-hostkey.sh [new file with mode: 0644]
regress/cert-userkey.sh [new file with mode: 0644]
regress/cfgmatch.sh [new file with mode: 0644]
regress/cipher-speed.sh [new file with mode: 0644]
regress/conch-ciphers.sh [new file with mode: 0644]
regress/connect-privsep.sh [new file with mode: 0644]
regress/connect.sh [new file with mode: 0644]
regress/dsa_ssh2.prv [new file with mode: 0644]
regress/dsa_ssh2.pub [new file with mode: 0644]
regress/dynamic-forward.sh [new file with mode: 0644]
regress/envpass.sh [new file with mode: 0644]
regress/exit-status.sh [new file with mode: 0644]
regress/forcecommand.sh [new file with mode: 0644]
regress/forwarding.sh [new file with mode: 0644]
regress/host-expand.sh [new file with mode: 0644]
regress/kextype.sh [new file with mode: 0644]
regress/key-options.sh [new file with mode: 0644]
regress/keygen-change.sh [new file with mode: 0644]
regress/keygen-convert.sh [new file with mode: 0644]
regress/keyscan.sh [new file with mode: 0644]
regress/keytype.sh [new file with mode: 0644]
regress/localcommand.sh [new file with mode: 0644]
regress/login-timeout.sh [new file with mode: 0644]
regress/multiplex.sh [new file with mode: 0644]
regress/portnum.sh [new file with mode: 0644]
regress/proto-mismatch.sh [new file with mode: 0644]
regress/proto-version.sh [new file with mode: 0644]
regress/proxy-connect.sh [new file with mode: 0644]
regress/putty-ciphers.sh [new file with mode: 0644]
regress/putty-kex.sh [new file with mode: 0644]
regress/putty-transfer.sh [new file with mode: 0644]
regress/reconfigure.sh [new file with mode: 0644]
regress/reexec.sh [new file with mode: 0644]
regress/rekey.sh [new file with mode: 0644]
regress/rsa_openssh.prv [new file with mode: 0644]
regress/rsa_openssh.pub [new file with mode: 0644]
regress/rsa_ssh2.prv [new file with mode: 0644]
regress/runtests.sh [new file with mode: 0755]
regress/scp-ssh-wrapper.sh [new file with mode: 0644]
regress/scp.sh [new file with mode: 0644]
regress/sftp-badcmds.sh [new file with mode: 0644]
regress/sftp-batch.sh [new file with mode: 0644]
regress/sftp-cmds.sh [new file with mode: 0644]
regress/sftp-glob.sh [new file with mode: 0644]
regress/sftp.sh [new file with mode: 0644]
regress/ssh-com-client.sh [new file with mode: 0644]
regress/ssh-com-keygen.sh [new file with mode: 0644]
regress/ssh-com-sftp.sh [new file with mode: 0644]
regress/ssh-com.sh [new file with mode: 0644]
regress/ssh2putty.sh [new file with mode: 0755]
regress/sshd-log-wrapper.sh [new file with mode: 0644]
regress/stderr-after-eof.sh [new file with mode: 0644]
regress/stderr-data.sh [new file with mode: 0644]
regress/t4.ok [new file with mode: 0644]
regress/t5.ok [new file with mode: 0644]
regress/test-exec.sh [new file with mode: 0644]
regress/transfer.sh [new file with mode: 0644]
regress/try-ciphers.sh [new file with mode: 0644]
regress/yes-head.sh [new file with mode: 0644]
rijndael.c [new file with mode: 0644]
rijndael.h [new file with mode: 0644]
roaming.h [new file with mode: 0644]
roaming_client.c [new file with mode: 0644]
roaming_common.c [new file with mode: 0644]
roaming_dummy.c [new file with mode: 0644]
roaming_serv.c [new file with mode: 0644]
rsa.c [new file with mode: 0644]
rsa.h [new file with mode: 0644]
schnorr.c [new file with mode: 0644]
schnorr.h [new file with mode: 0644]
scp.0 [new file with mode: 0644]
scp.1 [new file with mode: 0644]
scp.c [new file with mode: 0644]
servconf.c [new file with mode: 0644]
servconf.h [new file with mode: 0644]
serverloop.c [new file with mode: 0644]
serverloop.h [new file with mode: 0644]
session.c [new file with mode: 0644]
session.h [new file with mode: 0644]
sftp-client.c [new file with mode: 0644]
sftp-client.h [new file with mode: 0644]
sftp-common.c [new file with mode: 0644]
sftp-common.h [new file with mode: 0644]
sftp-glob.c [new file with mode: 0644]
sftp-server-main.c [new file with mode: 0644]
sftp-server.0 [new file with mode: 0644]
sftp-server.8 [new file with mode: 0644]
sftp-server.c [new file with mode: 0644]
sftp.0 [new file with mode: 0644]
sftp.1 [new file with mode: 0644]
sftp.c [new file with mode: 0644]
sftp.h [new file with mode: 0644]
ssh-add.0 [new file with mode: 0644]
ssh-add.1 [new file with mode: 0644]
ssh-add.c [new file with mode: 0644]
ssh-agent.0 [new file with mode: 0644]
ssh-agent.1 [new file with mode: 0644]
ssh-agent.c [new file with mode: 0644]
ssh-dss.c [new file with mode: 0644]
ssh-ecdsa.c [new file with mode: 0644]
ssh-gss.h [new file with mode: 0644]
ssh-keygen.0 [new file with mode: 0644]
ssh-keygen.1 [new file with mode: 0644]
ssh-keygen.c [new file with mode: 0644]
ssh-keyscan.0 [new file with mode: 0644]
ssh-keyscan.1 [new file with mode: 0644]
ssh-keyscan.c [new file with mode: 0644]
ssh-keysign.0 [new file with mode: 0644]
ssh-keysign.8 [new file with mode: 0644]
ssh-keysign.c [new file with mode: 0644]
ssh-pkcs11-client.c [new file with mode: 0644]
ssh-pkcs11-helper.0 [new file with mode: 0644]
ssh-pkcs11-helper.8 [new file with mode: 0644]
ssh-pkcs11-helper.c [new file with mode: 0644]
ssh-pkcs11.c [new file with mode: 0644]
ssh-pkcs11.h [new file with mode: 0644]
ssh-rand-helper.0 [new file with mode: 0644]
ssh-rand-helper.8 [new file with mode: 0644]
ssh-rand-helper.c [new file with mode: 0644]
ssh-rsa.c [new file with mode: 0644]
ssh.0 [new file with mode: 0644]
ssh.1 [new file with mode: 0644]
ssh.c [new file with mode: 0644]
ssh.h [new file with mode: 0644]
ssh1.h [new file with mode: 0644]
ssh2.h [new file with mode: 0644]
ssh_config [new file with mode: 0644]
ssh_config.0 [new file with mode: 0644]
ssh_config.5 [new file with mode: 0644]
ssh_prng_cmds.in [new file with mode: 0644]
sshconnect.c [new file with mode: 0644]
sshconnect.h [new file with mode: 0644]
sshconnect1.c [new file with mode: 0644]
sshconnect2.c [new file with mode: 0644]
sshd.0 [new file with mode: 0644]
sshd.8 [new file with mode: 0644]
sshd.c [new file with mode: 0644]
sshd_config [new file with mode: 0644]
sshd_config.0 [new file with mode: 0644]
sshd_config.5 [new file with mode: 0644]
sshlogin.c [new file with mode: 0644]
sshlogin.h [new file with mode: 0644]
sshpty.c [new file with mode: 0644]
sshpty.h [new file with mode: 0644]
sshtty.c [new file with mode: 0644]
survey.sh.in [new file with mode: 0644]
ttymodes.c [new file with mode: 0644]
ttymodes.h [new file with mode: 0644]
uidswap.c [new file with mode: 0644]
uidswap.h [new file with mode: 0644]
umac.c [new file with mode: 0644]
umac.h [new file with mode: 0644]
uuencode.c [new file with mode: 0644]
uuencode.h [new file with mode: 0644]
version.h [new file with mode: 0644]
xmalloc.c [new file with mode: 0644]
xmalloc.h [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
new file mode 100644 (file)
index 0000000..eaf105a
--- /dev/null
+++ b/CREDITS
@@ -0,0 +1,105 @@
+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
+
+Ahsan Rashid <arms@sco.com> - UnixWare long passwords
+Alain St-Denis <Alain.St-Denis@ec.gc.ca> - Irix fix
+Alexandre Oliva <oliva@lsd.ic.unicamp.br> - AIX fixes
+Andre Lucas <andre@ae-35.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@redhat.com> - Cygwin support
+Chad Mynhier <mynhier@interstel.net> - Solaris Process Contract support
+Dan Brosemer <odin@linuxfreak.com> - Autoconf support, build fixes
+Darren Hall <dhall@virage.org> - AIX patches
+Darren Tucker <dtucker@zip.com.au> - AIX BFF package scripts
+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
+Dag-Erling Smørgrav <des at freebsd.org> - Challenge-Response PAM code.
+Dhiraj Gulati <dgulati@sco.com> - UnixWare long passwords
+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@unixuser.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@pobox.com> - 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 Cawlfield <cawlfiel@us.ibm.com> - AIX 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 Steffens <michael_steffens at hp.com> - HP-UX fixes
+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
+Peter Stuge <stuge@cdy.org> - mdoc2man.awk script
+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
+Robert Dahlem <Robert.Dahlem at siemens.com> - Reliant Unix fixes
+Roumen Petrov <openssh@roumenpetrov.info> - Compile & configure fixes
+SAKAI Kiyotaka <ksakai@kso.netwk.ntt-at.co.jp> - Multiple bugfixes
+Simon Wilkinson <sxw@dcs.ed.ac.uk> - PAM fixes, Compat with MIT KrbV
+Solar Designer <solar@openwall.com> - many patches and technical assistance
+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
+Wendy Palm <wendyp at cray.com> - Cray support.
+Zack Weinberg <zack@wolery.cumb.org> - GNOME askpass enhancement
+
+Apologies to anyone I have missed.
+
+Damien Miller <djm@mindrot.org>
+
+$Id: CREDITS,v 1.81 2006/08/30 17:24:41 djm Exp $
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..993e0cb
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,1232 @@
+20110204
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2011/01/31 21:42:15
+     [PROTOCOL.mux]
+     cut'n'pasto; from bert.wesarg AT googlemail.com
+   - djm@cvs.openbsd.org 2011/02/04 00:44:21
+     [key.c]
+     fix uninitialised nonce variable; reported by Mateusz Kocielski
+   - djm@cvs.openbsd.org 2011/02/04 00:44:43
+     [version.h]
+     openssh-5.8
+ - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+   [contrib/suse/openssh.spec] update versions in docs and spec files.
+ - Release OpenSSH 5.8p1
+
+20110128
+ - (djm) [openbsd-compat/port-linux.c] Check whether SELinux is enabled
+   before attempting setfscreatecon(). Check whether matchpathcon()
+   succeeded before using its result. Patch from cjwatson AT debian.org;
+   bz#1851
+
+20110125
+ - (djm) [configure.ac Makefile.in ssh.c openbsd-compat/port-linux.c
+   openbsd-compat/port-linux.h] Move SELinux-specific code from ssh.c to
+   port-linux.c to avoid compilation errors. Add -lselinux to ssh when
+   building with SELinux support to avoid linking failure; report from
+   amk AT spamfence.net; ok dtucker
+
+20110122
+ - (dtucker) [configure.ac openbsd-compat/openssl-compat.{c,h}] Add
+   RSA_get_default_method() for the benefit of openssl versions that don't
+   have it (at least openssl-engine-0.9.6b).  Found and tested by Kevin Brott,
+   ok djm@.
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2011/01/22 09:18:53
+     [version.h]
+     crank to OpenSSH-5.7
+ - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+   [contrib/suse/openssh.spec] update versions in docs and spec files.
+ - (djm) Release 5.7p1
+
+20110119
+ - (tim) [contrib/caldera/openssh.spec] Use CFLAGS from Makefile instead
+   of RPM so build completes. Signatures were changed to .asc since 4.1p1.
+ - (djm) [configure.ac] Disable ECC on OpenSSL <0.9.8g. Releases prior to
+   0.9.8 lacked it, and 0.9.8a through 0.9.8d have proven buggy in pre-
+   release testing (random crashes and failure to load ECC keys).
+   ok dtucker@
+
+20110117
+ - (djm) [regress/Makefile] use $TEST_SSH_KEYGEN instead of the one in
+   $PATH, fix cleanup of droppings; reported by openssh AT
+   roumenpetrov.info; ok dtucker@
+ - (djm) [regress/agent-ptrace.sh] Fix false failure on OS X by adding
+   its unique snowflake of a gdb error to the ones we look for.
+ - (djm) [regress/agent-getpeereid.sh] leave stdout attached when running
+   ssh-add to avoid $SUDO failures on Linux
+ - (dtucker) [openbsd-compat/port-linux.c] Bug #1838: Add support for the new
+   Linux OOM-killer magic values that changed in 2.6.36 kernels, with fallback
+   to the old values.  Feedback from vapier at gentoo org and djm, ok djm.
+ - (djm) [configure.ac regress/agent-getpeereid.sh regress/multiplex.sh]
+   [regress/sftp-glob.sh regress/test-exec.sh] Rework how feature tests are
+   disabled on platforms that do not support them; add a "config_defined()"
+   shell function that greps for defines in config.h and use them to decide
+   on feature tests.
+   Convert a couple of existing grep's over config.h to use the new function
+   Add a define "FILESYSTEM_NO_BACKSLASH" for filesystem that can't represent
+   backslash characters in filenames, enable it for Cygwin and use it to turn
+   of tests for quotes backslashes in sftp-glob.sh.
+   based on discussion with vinschen AT redhat.com and dtucker@; ok dtucker@
+ - (tim) [regress/agent-getpeereid.sh] shell portability fix.
+ - (dtucker) [openbsd-compat/port-linux.c] Fix minor bug caught by -Werror on
+   the tinderbox.
+ - (dtucker) [LICENCE Makefile.in audit-bsm.c audit-linux.c audit.c audit.h
+   configure.ac defines.h loginrec.c]  Bug #1402: add linux audit subsystem
+   support, based on patches from Tomas Mraz and jchadima at redhat.
+
+20110116
+ - (dtucker) [Makefile.in configure.ac regress/kextype.sh] Skip sha256-based
+   on configurations that don't have it.
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2011/01/16 11:50:05
+     [clientloop.c]
+     Use atomicio when flushing protocol 1 std{out,err} buffers at
+     session close. This was a latent bug exposed by setting a SIGCHLD
+     handler and spotted by kevin.brott AT gmail.com; ok dtucker@
+   - djm@cvs.openbsd.org 2011/01/16 11:50:36
+     [sshconnect.c]
+     reset the SIGPIPE handler when forking to execute child processes;
+     ok dtucker@
+   - djm@cvs.openbsd.org 2011/01/16 12:05:59
+     [clientloop.c]
+     a couple more tweaks to the post-close protocol 1 stderr/stdout flush:
+     now that we use atomicio(), convert them from while loops to if statements
+     add test and cast to compile cleanly with -Wsigned
+
+20110114
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2011/01/13 21:54:53
+     [mux.c]
+     correct error messages; patch from bert.wesarg AT googlemail.com
+   - djm@cvs.openbsd.org 2011/01/13 21:55:25
+     [PROTOCOL.mux]
+     correct protocol names and add a couple of missing protocol number
+     defines; patch from bert.wesarg AT googlemail.com
+ - (djm) [Makefile.in] Use shell test to disable ecdsa key generating in
+   host-key-force target rather than a substitution that is replaced with a
+   comment so that the Makefile.in is still a syntactically valid Makefile
+   (useful to run the distprep target)
+ - (tim) [regress/cert-hostkey.sh] Typo. Missing $ on variable name.
+ - (tim) [regress/cert-hostkey.sh] Add missing TEST_SSH_ECC guard around some
+   ecdsa bits.
+
+20110113
+ - (djm) [misc.c] include time.h for nanosleep() prototype
+ - (tim) [Makefile.in] test the ECC bits if we have the capability. ok djm
+ - (tim) [Makefile.in configure.ac opensshd.init.in] Add support for generating
+   ecdsa keys. ok djm.
+ - (djm) [entropy.c] cast OPENSSL_VERSION_NUMBER to u_long to avoid
+   gcc warning on platforms where it defaults to int
+ - (djm) [regress/Makefile] add a few more generated files to the clean
+   target
+ - (djm) [myproposal.h] Fix reversed OPENSSL_VERSION_NUMBER test and bad
+   #define that was causing diffie-hellman-group-exchange-sha256 to be
+   incorrectly disabled
+ - (djm) [regress/kextype.sh] Testing diffie-hellman-group-exchange-sha256
+   should not depend on ECC support
+
+20110112
+ - OpenBSD CVS Sync
+   - nicm@cvs.openbsd.org 2010/10/08 21:48:42
+     [openbsd-compat/glob.c]
+     Extend GLOB_LIMIT to cover readdir and stat and bump the malloc limit
+     from ARG_MAX to 64K.
+     Fixes glob-using programs (notably ftp) able to be triggered to hit
+     resource limits.
+     Idea from a similar NetBSD change, original problem reported by jasper@.
+     ok millert tedu jasper
+   - djm@cvs.openbsd.org 2011/01/12 01:53:14
+     avoid some integer overflows mostly with GLOB_APPEND and GLOB_DOOFFS
+     and sanity check arguments (these will be unnecessary when we switch
+     struct glob members from being type into to size_t in the future);
+     "looks ok" tedu@ feedback guenther@
+ - (djm) [configure.ac] Turn on -Wno-unused-result for gcc >= 4.4 to avoid
+   silly warnings on write() calls we don't care succeed or not.
+ - (djm) [configure.ac] Fix broken test for gcc >= 4.4 with per-compiler
+   flag tests that don't depend on gcc version at all; suggested by and
+   ok dtucker@
+
+20110111
+ - (tim) [regress/host-expand.sh] Fix for building outside of read only
+   source tree.
+ - (djm) [platform.c] Some missing includes that show up under -Werror
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2011/01/08 10:51:51
+     [clientloop.c]
+     use host and not options.hostname, as the latter may have unescaped
+     substitution characters
+   - djm@cvs.openbsd.org 2011/01/11 06:06:09
+     [sshlogin.c]
+     fd leak on error paths; from zinovik@
+     NB. Id sync only; we use loginrec.c that was also audited and fixed
+     recently
+   - djm@cvs.openbsd.org 2011/01/11 06:13:10
+     [clientloop.c ssh-keygen.c sshd.c]
+     some unsigned long long casts that make things a bit easier for
+     portable without resorting to dropping PRIu64 formats everywhere
+
+20110109
+ - (djm) [Makefile.in] list ssh_host_ecdsa key in PATHSUBS; spotted by
+   openssh AT roumenpetrov.info
+
+20110108
+ - (djm) [regress/keytype.sh] s/echo -n/echon/ to repair failing regress
+   test on OSX and others. Reported by imorgan AT nas.nasa.gov
+
+20110107
+ - (djm) [regress/cert-hostkey.sh regress/cert-userkey.sh] fix shell test
+   for no-ECC case. Patch from cristian.ionescu-idbohrn AT axis.com
+   - djm@cvs.openbsd.org 2011/01/06 22:23:53
+     [ssh.c]
+     unbreak %n expansion in LocalCommand; patch from bert.wesarg AT
+     googlemail.com; ok markus@
+   - djm@cvs.openbsd.org 2011/01/06 22:23:02
+     [clientloop.c]
+     when exiting due to ServerAliveTimeout, mention the hostname that caused
+     it (useful with backgrounded controlmaster)
+   - djm@cvs.openbsd.org 2011/01/06 22:46:21
+     [regress/Makefile regress/host-expand.sh]
+     regress test for LocalCommand %n expansion from bert.wesarg AT
+     googlemail.com; ok markus@
+   - djm@cvs.openbsd.org 2011/01/06 23:01:35
+     [sshconnect.c]
+     reset SIGCHLD handler to SIG_DFL when execuring LocalCommand;
+     ok markus@
+
+20110106
+ - (djm) OpenBSD CVS Sync
+   - markus@cvs.openbsd.org 2010/12/08 22:46:03
+     [scp.1 scp.c]
+     add a new -3 option to scp: Copies between two remote hosts are
+     transferred through the local host.  Without this option the data
+     is copied directly between the two remote hosts. ok djm@ (bugzilla #1837)
+   - jmc@cvs.openbsd.org 2010/12/09 14:13:33
+     [scp.1 scp.c]
+     scp.1: grammer fix
+     scp.c: add -3 to usage()
+   - markus@cvs.openbsd.org 2010/12/14 11:59:06
+     [sshconnect.c]
+     don't mention key type in key-changed-warning, since we also print
+     this warning if a new key type appears. ok djm@
+   - djm@cvs.openbsd.org 2010/12/15 00:49:27
+     [readpass.c]
+     fix ControlMaster=ask regression
+     reset SIGCHLD handler before fork (and restore it after) so we don't miss
+     the the askpass child's exit status. Correct test for exit status/signal to
+     account for waitpid() failure; with claudio@ ok claudio@ markus@
+   - djm@cvs.openbsd.org 2010/12/24 21:41:48
+     [auth-options.c]
+     don't send the actual forced command in a debug message; ok markus deraadt
+   - otto@cvs.openbsd.org 2011/01/04 20:44:13
+     [ssh-keyscan.c]
+     handle ecdsa-sha2 with various key lengths; hint and ok djm@
+
+20110104
+ - (djm) [configure.ac Makefile.in] Use mandoc as preferred manpage
+   formatter if it is present, followed by nroff and groff respectively.
+   Fixes distprep target on OpenBSD (which has bumped groff/nroff to ports
+   in favour of mandoc). feedback and ok tim
+
+20110103
+ - (djm) [Makefile.in] revert local hack I didn't intend to commit
+
+20110102
+ - (djm) [loginrec.c] Fix some fd leaks on error paths. ok dtucker
+ - (djm) [configure.ac] Check whether libdes is needed when building
+   with Heimdal krb5 support. On OpenBSD this library no longer exists,
+   so linking it unconditionally causes a build failure; ok dtucker
+
+20101226
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/12/08 04:02:47
+     [ssh_config.5 sshd_config.5]
+     explain that IPQoS arguments are separated by whitespace; iirc requested
+     by jmc@ a while back
+
+20101205
+ - (dtucker) openbsd-compat/openssl-compat.c] remove sleep leftover from
+   debugging.  Spotted by djm.
+ - (dtucker) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/12/03 23:49:26
+     [schnorr.c]
+     check that g^x^q === 1 mod p; recommended by JPAKE author Feng Hao
+     (this code is still disabled, but apprently people are treating it as
+     a reference implementation)
+   - djm@cvs.openbsd.org 2010/12/03 23:55:27
+     [auth-rsa.c]
+     move check for revoked keys to run earlier (in auth_rsa_key_allowed)
+     bz#1829; patch from ldv AT altlinux.org; ok markus@
+   - djm@cvs.openbsd.org 2010/12/04 00:18:01
+     [sftp-server.c sftp.1 sftp-client.h sftp.c PROTOCOL sftp-client.c]
+     add a protocol extension to support a hard link operation. It is
+     available through the "ln" command in the client. The old "ln"
+     behaviour of creating a symlink is available using its "-s" option
+     or through the preexisting "symlink" command; based on a patch from
+     miklos AT szeredi.hu in bz#1555; ok markus@
+   - djm@cvs.openbsd.org 2010/12/04 13:31:37
+     [hostfile.c]
+     fix fd leak; spotted and ok dtucker
+   - djm@cvs.openbsd.org 2010/12/04 00:21:19
+     [regress/sftp-cmds.sh]
+     adjust for hard-link support
+ - (dtucker) [regress/Makefile] Id sync.
+
+20101204
+ - (djm) [openbsd-compat/bindresvport.c] Use arc4random_uniform(range)
+   instead of (arc4random() % range)
+ - (dtucker) [configure.ac moduli.c openbsd-compat/openssl-compat.{c,h}]  Add
+   shims for the new, non-deprecated OpenSSL key generation functions for
+   platforms that don't have the new interfaces.
+
+20101201
+ - OpenBSD CVS Sync
+   - deraadt@cvs.openbsd.org 2010/11/20 05:12:38
+     [auth2-pubkey.c]
+     clean up cases of ;;
+   - djm@cvs.openbsd.org 2010/11/21 01:01:13
+     [clientloop.c misc.c misc.h ssh-agent.1 ssh-agent.c]
+     honour $TMPDIR for client xauth and ssh-agent temporary directories;
+     feedback and ok markus@
+   - djm@cvs.openbsd.org 2010/11/21 10:57:07
+     [authfile.c]
+     Refactor internals of private key loading and saving to work on memory
+     buffers rather than directly on files. This will make a few things
+     easier to do in the future; ok markus@
+   - djm@cvs.openbsd.org 2010/11/23 02:35:50
+     [auth.c]
+     use strict_modes already passed as function argument over referencing
+     global options.strict_modes
+   - djm@cvs.openbsd.org 2010/11/23 23:57:24
+     [clientloop.c]
+     avoid NULL deref on receiving a channel request on an unknown or invalid
+     channel; report bz#1842 from jchadima AT redhat.com; ok dtucker@
+   - djm@cvs.openbsd.org 2010/11/24 01:24:14
+     [channels.c]
+     remove a debug() that pollutes stderr on client connecting to a server
+     in debug mode (channel_close_fds is called transitively from the session
+     code post-fork); bz#1719, ok dtucker
+   - djm@cvs.openbsd.org 2010/11/25 04:10:09
+     [session.c]
+     replace close() loop for fds 3->64 with closefrom();
+     ok markus deraadt dtucker
+   - djm@cvs.openbsd.org 2010/11/26 05:52:49
+     [scp.c]
+     Pass through ssh command-line flags and options when doing remote-remote
+     transfers, e.g. to enable agent forwarding which is particularly useful
+     in this case; bz#1837 ok dtucker@
+   - markus@cvs.openbsd.org 2010/11/29 18:57:04
+     [authfile.c]
+     correctly load comment for encrypted rsa1 keys;
+     report/fix Joachim Schipper; ok djm@
+   - djm@cvs.openbsd.org 2010/11/29 23:45:51
+     [auth.c hostfile.c hostfile.h ssh.c ssh_config.5 sshconnect.c]
+     [sshconnect.h sshconnect2.c]
+     automatically order the hostkeys requested by the client based on
+     which hostkeys are already recorded in known_hosts. This avoids
+     hostkey warnings when connecting to servers with new ECDSA keys
+     that are preferred by default; with markus@
+
+20101124
+ - (dtucker) [platform.c session.c] Move the getluid call out of session.c and
+   into the platform-specific code  Only affects SCO, tested by and ok tim@.
+ - (djm) [loginrec.c] Relax permission requirement on btmp logs to allow
+   group read/write. ok dtucker@
+ - (dtucker) [packet.c] Remove redundant local declaration of "int tos".
+ - (djm) [defines.h] Add IP DSCP defines
+
+20101122
+ - (dtucker) Bug #1840: fix warning when configuring --with-ssl-engine, patch
+   from vapier at gentoo org.
+
+20101120
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/11/05 02:46:47
+     [packet.c]
+     whitespace KNF
+   - djm@cvs.openbsd.org 2010/11/10 01:33:07
+     [kexdhc.c kexdhs.c kexgexc.c kexgexs.c key.c moduli.c]
+     use only libcrypto APIs that are retained with OPENSSL_NO_DEPRECATED.
+     these have been around for years by this time. ok markus
+   - djm@cvs.openbsd.org 2010/11/13 23:27:51
+     [clientloop.c misc.c misc.h packet.c packet.h readconf.c readconf.h]
+     [servconf.c servconf.h session.c ssh.c ssh_config.5 sshd_config.5]
+     allow ssh and sshd to set arbitrary TOS/DSCP/QoS values instead of
+     hardcoding lowdelay/throughput.
+     
+     bz#1733 patch from philipp AT redfish-solutions.com; ok markus@ deraadt@
+   - jmc@cvs.openbsd.org 2010/11/15 07:40:14
+     [ssh_config.5]
+     libary -> library;
+   - jmc@cvs.openbsd.org 2010/11/18 15:01:00
+     [scp.1 sftp.1 ssh.1 sshd_config.5]
+     add IPQoS to the various -o lists, and zap some trailing whitespace;
+
+20101111
+ - (djm) [servconf.c ssh-add.c ssh-keygen.c] don't look for ECDSA keys on
+   platforms that don't support ECC. Fixes some spurious warnings reported
+   by tim@
+
+20101109
+ - (tim) [regress/kextype.sh] Not all platforms have time in /usr/bin.
+   Feedback from dtucker@
+ - (tim) [configure.ac openbsd-compat/bsd-misc.h openbsd-compat/bsd-misc.c] Add
+   support for platforms missing isblank(). ok djm@
+
+20101108
+ - (tim) [regress/Makefile] Fixes to allow building/testing outside source
+   tree.
+ - (tim) [regress/kextype.sh] Shell portability fix.
+
+20101107
+ - (dtucker) [platform.c] includes.h instead of defines.h so that we get
+   the correct typedefs.
+
+20101105
+ - (djm) [loginrec.c loginrec.h] Use correct uid_t/pid_t types instead of
+   int. Should fix bz#1817 cleanly; ok dtucker@
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/09/22 12:26:05
+     [regress/Makefile regress/kextype.sh]
+     regress test for each of the key exchange algorithms that we support
+   - djm@cvs.openbsd.org 2010/10/28 11:22:09
+     [authfile.c key.c key.h ssh-keygen.c]
+     fix a possible NULL deref on loading a corrupt ECDH key
+     
+     store ECDH group information in private keys files as "named groups"
+     rather than as a set of explicit group parameters (by setting
+     the OPENSSL_EC_NAMED_CURVE flag). This makes for shorter key files and
+     retrieves the group's OpenSSL NID that we need for various things.
+   - jmc@cvs.openbsd.org 2010/10/28 18:33:28
+     [scp.1 ssh-add.1 ssh-keygen.1 ssh.1 ssh_config.5 sshd.8 sshd_config.5]
+     knock out some "-*- nroff -*-" lines;
+   - djm@cvs.openbsd.org 2010/11/04 02:45:34
+     [sftp-server.c]
+     umask should be parsed as octal. reported by candland AT xmission.com;
+     ok markus@
+ - (dtucker) [configure.ac platform.{c,h} session.c
+   openbsd-compat/port-solaris.{c,h}] Bug #1824: Add Solaris Project support.
+   Patch from cory.erickson at csu mnscu edu with a bit of rework from me.
+   ok djm@
+ - (dtucker) [platform.c platform.h session.c] Add a platform hook to run
+   after the user's groups are established and move the selinux calls into it.
+ - (dtucker) [platform.c session.c] Move the AIX setpcred+chroot hack into
+   platform.c
+ - (dtucker) [platform.c session.c] Move the BSDI setpgrp into platform.c.
+ - (dtucker) [platform.c] Only call setpgrp on BSDI if running as root to
+   retain previous behavior.
+ - (dtucker) [platform.c session.c] Move the PAM credential establishment for
+   the LOGIN_CAP case into platform.c.
+ - (dtucker) platform.c session.c] Move the USE_LIBIAF fragment into
+   platform.c
+ - (dtucker) [platform.c session.c] Move aix_usrinfo frament into platform.c.
+ - (dtucker) [platform.c session.c] Move irix setusercontext fragment into
+   platform.c.
+ - (dtucker) [platform.c session.c] Move PAM credential establishment for the
+   non-LOGIN_CAP case into platform.c.
+ - (dtucker) [platform.c platform.h session.c] Move the Cygwin special-case
+   check into platform.c
+ - (dtucker) [regress/keytype.sh] Import new test.
+ - (dtucker) [Makefile configure.ac regress/Makefile regress/keytype.sh]
+   Import recent changes to regress/Makefile, pass a flag to enable ECC tests
+   from configure through to regress/Makefile and use it in the tests.
+ - (dtucker) [regress/kextype.sh] Add missing "test".
+ - (dtucker) [regress/kextype.sh] Make sha256 test depend on ECC.  This is not
+   strictly correct since while ECC requires sha256 the reverse is not true
+   however it does prevent spurious test failures.
+ - (dtucker) [platform.c] Need servconf.h and extern options.
+
+20101025
+ - (tim) [openbsd-compat/glob.h] Remove sys/cdefs.h include that came with
+   1.12 to unbreak Solaris build.
+   ok djm@
+ - (dtucker) [defines.h] Use SIZE_T_MAX for SIZE_MAX for platforms that have a
+   native one.
+
+20101024
+ - (dtucker) [includes.h] Add missing ifdef GLOB_HAS_GL_STATV to fix build.
+ - (dtucker) [regress/cert-hostkey.sh] Disable ECC-based tests on platforms
+   which don't have ECC support in libcrypto.
+ - (dtucker) [regress/cert-userkey.sh] Disable ECC-based tests on platforms
+   which don't have ECC support in libcrypto.
+ - (dtucker) [defines.h] Add SIZE_MAX for the benefit of platforms that don't
+   have it.
+ - (dtucker) OpenBSD CVS Sync
+   - sthen@cvs.openbsd.org 2010/10/23 22:06:12
+     [sftp.c]
+     escape '[' in filename tab-completion; fix a type while there.
+     ok djm@
+
+20101021
+ - OpenBSD CVS Sync
+   - dtucker@cvs.openbsd.org 2010/10/12 02:22:24
+     [mux.c]
+     Typo in confirmation message.  bz#1827, patch from imorgan at
+     nas nasa gov
+   - djm@cvs.openbsd.org 2010/08/31 12:24:09
+     [regress/cert-hostkey.sh regress/cert-userkey.sh]
+     tests for ECDSA certificates
+
+20101011
+ - (djm) [canohost.c] Zero a4 instead of addr to better match type.
+   bz#1825, reported by foo AT mailinator.com
+ - (djm) [sshconnect.c] Need signal.h for prototype for kill(2)
+
+20101011
+ - (djm) [configure.ac] Use = instead of == in shell tests. Patch from
+   dr AT vasco.com
+
+20101007
+ - (djm) [ssh-agent.c] Fix type for curve name.
+ - (djm) OpenBSD CVS Sync
+   - matthew@cvs.openbsd.org 2010/09/24 13:33:00
+     [misc.c misc.h configure.ac openbsd-compat/openbsd-compat.h]
+     [openbsd-compat/timingsafe_bcmp.c]
+     Add timingsafe_bcmp(3) to libc, mention that it's already in the
+     kernel in kern(9), and remove it from OpenSSH.
+     ok deraadt@, djm@
+     NB. re-added under openbsd-compat/ for portable OpenSSH
+   - djm@cvs.openbsd.org 2010/09/25 09:30:16
+     [sftp.c configure.ac openbsd-compat/glob.c openbsd-compat/glob.h]
+     make use of new glob(3) GLOB_KEEPSTAT extension to save extra server
+     rountrips to fetch per-file stat(2) information.
+     NB. update openbsd-compat/ glob(3) implementation from OpenBSD libc to
+     match.
+   - djm@cvs.openbsd.org 2010/09/26 22:26:33
+     [sftp.c]
+     when performing an "ls" in columnated (short) mode, only call
+     ioctl(TIOCGWINSZ) once to get the window width instead of per-
+     filename
+   - djm@cvs.openbsd.org 2010/09/30 11:04:51
+     [servconf.c]
+     prevent free() of string in .rodata when overriding AuthorizedKeys in
+     a Match block; patch from rein AT basefarm.no
+   - djm@cvs.openbsd.org 2010/10/01 23:05:32
+     [cipher-3des1.c cipher-bf1.c cipher-ctr.c openbsd-compat/openssl-compat.h]
+     adapt to API changes in openssl-1.0.0a
+     NB. contains compat code to select correct API for older OpenSSL
+   - djm@cvs.openbsd.org 2010/10/05 05:13:18
+     [sftp.c sshconnect.c]
+     use default shell /bin/sh if $SHELL is ""; ok markus@
+   - djm@cvs.openbsd.org 2010/10/06 06:39:28
+     [clientloop.c ssh.c sshconnect.c sshconnect.h]
+     kill proxy command on fatal() (we already kill it on clean exit);
+     ok markus@
+   - djm@cvs.openbsd.org 2010/10/06 21:10:21
+     [sshconnect.c]
+     swapped args to kill(2)
+ - (djm) [openbsd-compat/glob.c] restore ARG_MAX compat code.
+ - (djm) [cipher-acss.c] Add missing header.
+ - (djm) [openbsd-compat/Makefile.in] Actually link timingsafe_bcmp
+
+20100924
+ - (djm) OpenBSD CVS Sync
+   - naddy@cvs.openbsd.org 2010/09/10 15:19:29
+     [ssh-keygen.1]
+     * mention ECDSA in more places
+     * less repetition in FILES section
+     * SSHv1 keys are still encrypted with 3DES
+     help and ok jmc@
+   - djm@cvs.openbsd.org 2010/09/11 21:44:20
+     [ssh.1]
+     mention RFC 5656 for ECC stuff
+   - jmc@cvs.openbsd.org 2010/09/19 21:30:05
+     [sftp.1]
+     more wacky macro fixing;
+   - djm@cvs.openbsd.org 2010/09/20 04:41:47
+     [ssh.c]
+     install a SIGCHLD handler to reap expiried child process; ok markus@
+   - djm@cvs.openbsd.org 2010/09/20 04:50:53
+     [jpake.c schnorr.c]
+     check that received values are smaller than the group size in the
+     disabled and unfinished J-PAKE code.
+     avoids catastrophic security failure found by Sebastien Martini
+   - djm@cvs.openbsd.org 2010/09/20 04:54:07
+     [jpake.c]
+     missing #include
+   - djm@cvs.openbsd.org 2010/09/20 07:19:27
+     [mux.c]
+     "atomically" create the listening mux socket by binding it on a temorary
+     name and then linking it into position after listen() has succeeded.
+     this allows the mux clients to determine that the server socket is
+     either ready or stale without races. stale server sockets are now
+     automatically removed
+     ok deraadt
+   - djm@cvs.openbsd.org 2010/09/22 05:01:30
+     [kex.c kex.h kexecdh.c kexecdhc.c kexecdhs.c readconf.c readconf.h]
+     [servconf.c servconf.h ssh_config.5 sshconnect2.c sshd.c sshd_config.5]
+     add a KexAlgorithms knob to the client and server configuration to allow
+     selection of which key exchange methods are used by ssh(1) and sshd(8)
+     and their order of preference.
+     ok markus@
+   - jmc@cvs.openbsd.org 2010/09/22 08:30:08
+     [ssh.1 ssh_config.5]
+     ssh.1: add kexalgorithms to the -o list
+     ssh_config.5: format the kexalgorithms in a more consistent
+     (prettier!) way
+     ok djm
+   - djm@cvs.openbsd.org 2010/09/22 22:58:51
+     [atomicio.c atomicio.h misc.c misc.h scp.c sftp-client.c]
+     [sftp-client.h sftp.1 sftp.c]
+     add an option per-read/write callback to atomicio
+
+     factor out bandwidth limiting code from scp(1) into a generic bandwidth
+     limiter that can be attached using the atomicio callback mechanism
+
+     add a bandwidth limit option to sftp(1) using the above
+     "very nice" markus@
+   - jmc@cvs.openbsd.org 2010/09/23 13:34:43
+     [sftp.c]
+     add [-l limit] to usage();
+   - jmc@cvs.openbsd.org 2010/09/23 13:36:46
+     [scp.1 sftp.1]
+     add KexAlgorithms to the -o list;
+
+20100910
+ - (dtucker) [openbsd-compat/port-linux.c] Check is_selinux_enabled for exact
+   return code since it can apparently return -1 under some conditions.  From
+   openssh bugs werbittewas de, ok djm@
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/08/31 12:33:38
+     [ssh-add.c ssh-agent.c ssh-keygen.c ssh-keysign.c ssh.c sshd.c]
+     reintroduce commit from tedu@, which I pulled out for release
+     engineering:
+       OpenSSL_add_all_algorithms is the name of the function we have a
+       man page for, so use that.  ok djm
+   - jmc@cvs.openbsd.org 2010/08/31 17:40:54
+     [ssh-agent.1]
+     fix some macro abuse;
+   - jmc@cvs.openbsd.org 2010/08/31 21:14:58
+     [ssh.1]
+     small text tweak to accommodate previous;
+   - naddy@cvs.openbsd.org 2010/09/01 15:21:35
+     [servconf.c]
+     pick up ECDSA host key by default; ok djm@
+   - markus@cvs.openbsd.org 2010/09/02 16:07:25
+     [ssh-keygen.c]
+     permit -b 256, 384 or 521 as key size for ECDSA; ok djm@
+   - markus@cvs.openbsd.org 2010/09/02 16:08:39
+     [ssh.c]
+     unbreak ControlPersist=yes for ControlMaster=yes; ok djm@
+   - naddy@cvs.openbsd.org 2010/09/02 17:21:50
+     [ssh-keygen.c]
+     Switch ECDSA default key size to 256 bits, which according to RFC5656
+     should still be better than our current RSA-2048 default.
+     ok djm@, markus@
+   - jmc@cvs.openbsd.org 2010/09/03 11:09:29
+     [scp.1]
+     add an EXIT STATUS section for /usr/bin;
+   - jmc@cvs.openbsd.org 2010/09/04 09:38:34
+     [ssh-add.1 ssh.1]
+     two more EXIT STATUS sections;
+   - naddy@cvs.openbsd.org 2010/09/06 17:10:19
+     [sshd_config]
+     add ssh_host_ecdsa_key to /etc; from Mattieu Baptiste
+     <mattieu.b@gmail.com>
+     ok deraadt@
+   - djm@cvs.openbsd.org 2010/09/08 03:54:36
+     [authfile.c]
+     typo
+   - deraadt@cvs.openbsd.org 2010/09/08 04:13:31
+     [compress.c]
+     work around name-space collisions some buggy compilers (looking at you
+     gcc, at least in earlier versions, but this does not forgive your current
+     transgressions) seen between zlib and openssl
+     ok djm
+   - djm@cvs.openbsd.org 2010/09/09 10:45:45
+     [kex.c kex.h kexecdh.c key.c key.h monitor.c ssh-ecdsa.c]
+     ECDH/ECDSA compliance fix: these methods vary the hash function they use
+     (SHA256/384/512) depending on the length of the curve in use. The previous
+     code incorrectly used SHA256 in all cases.
+     
+     This fix will cause authentication failure when using 384 or 521-bit curve
+     keys if one peer hasn't been upgraded and the other has. (256-bit curve
+     keys work ok). In particular you may need to specify HostkeyAlgorithms
+     when connecting to a server that has not been upgraded from an upgraded
+     client.
+     
+     ok naddy@
+ - (djm) [authfd.c authfile.c bufec.c buffer.h configure.ac kex.h kexecdh.c]
+   [kexecdhc.c kexecdhs.c key.c key.h myproposal.h packet.c readconf.c]
+   [ssh-agent.c ssh-ecdsa.c ssh-keygen.c ssh.c] Disable ECDH and ECDSA on
+   platforms that don't have the requisite OpenSSL support. ok dtucker@
+ - (dtucker) [kex.h key.c packet.h ssh-agent.c ssh.c] A few more ECC ifdefs
+   for missing headers and compiler warnings.
+
+20100831
+ - OpenBSD CVS Sync
+   - jmc@cvs.openbsd.org 2010/08/08 19:36:30
+     [ssh-keysign.8 ssh.1 sshd.8]
+     use the same template for all FILES sections; i.e. -compact/.Pp where we
+     have multiple items, and .Pa for path names;
+   - tedu@cvs.openbsd.org 2010/08/12 23:34:39
+     [ssh-add.c ssh-agent.c ssh-keygen.c ssh-keysign.c ssh.c sshd.c]
+     OpenSSL_add_all_algorithms is the name of the function we have a man page
+     for, so use that.  ok djm
+   - djm@cvs.openbsd.org 2010/08/16 04:06:06
+     [ssh-add.c ssh-agent.c ssh-keygen.c ssh-keysign.c ssh.c sshd.c]
+     backout previous temporarily; discussed with deraadt@
+   - djm@cvs.openbsd.org 2010/08/31 09:58:37
+     [auth-options.c auth1.c auth2.c bufaux.c buffer.h kex.c key.c packet.c]
+     [packet.h ssh-dss.c ssh-rsa.c]
+     Add buffer_get_cstring() and related functions that verify that the
+     string extracted from the buffer contains no embedded \0 characters*
+     This prevents random (possibly malicious) crap from being appended to
+     strings where it would not be noticed if the string is used with
+     a string(3) function.
+     
+     Use the new API in a few sensitive places.
+     
+     * actually, we allow a single one at the end of the string for now because
+     we don't know how many deployed implementations get this wrong, but don't
+     count on this to remain indefinitely.
+   - djm@cvs.openbsd.org 2010/08/31 11:54:45
+     [PROTOCOL PROTOCOL.agent PROTOCOL.certkeys auth2-jpake.c authfd.c]
+     [authfile.c buffer.h dns.c kex.c kex.h key.c key.h monitor.c]
+     [monitor_wrap.c myproposal.h packet.c packet.h pathnames.h readconf.c]
+     [ssh-add.1 ssh-add.c ssh-agent.1 ssh-agent.c ssh-keygen.1 ssh-keygen.c]
+     [ssh-keyscan.1 ssh-keyscan.c ssh-keysign.8 ssh.1 ssh.c ssh2.h]
+     [ssh_config.5 sshconnect.c sshconnect2.c sshd.8 sshd.c sshd_config.5]
+     [uuencode.c uuencode.h bufec.c kexecdh.c kexecdhc.c kexecdhs.c ssh-ecdsa.c]
+     Implement Elliptic Curve Cryptography modes for key exchange (ECDH) and
+     host/user keys (ECDSA) as specified by RFC5656. ECDH and ECDSA offer
+     better performance than plain DH and DSA at the same equivalent symmetric
+     key length, as well as much shorter keys.
+     
+     Only the mandatory sections of RFC5656 are implemented, specifically the
+     three REQUIRED curves nistp256, nistp384 and nistp521 and only ECDH and
+     ECDSA. Point compression (optional in RFC5656 is NOT implemented).
+     
+     Certificate host and user keys using the new ECDSA key types are supported.
+     
+     Note that this code has not been tested for interoperability and may be
+     subject to change.
+     
+     feedback and ok markus@
+ - (djm) [Makefile.in] Add new ECC files
+ - (djm) [bufec.c kexecdh.c kexecdhc.c kexecdhs.c ssh-ecdsa.c] include
+   includes.h
+
+20100827
+ - (dtucker) [contrib/redhat/sshd.init] Bug #1810: initlog is deprecated,
+   remove.  Patch from martynas at venck us 
+
+20100823
+ - (djm) Release OpenSSH-5.6p1
+
+20100816
+ - (dtucker) [configure.ac openbsd-compat/Makefile.in
+   openbsd-compat/openbsd-compat.h openbsd-compat/strptime.c] Add strptime to
+   the compat library which helps on platforms like old IRIX.  Based on work
+   by djm, tested by Tom Christensen.
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/08/12 21:49:44
+     [ssh.c]
+     close any extra file descriptors inherited from parent at start and
+     reopen stdin/stdout to /dev/null when forking for ControlPersist.
+     
+     prevents tools that fork and run a captive ssh for communication from
+     failing to exit when the ssh completes while they wait for these fds to
+     close. The inherited fds may persist arbitrarily long if a background
+     mux master has been started by ControlPersist. cvs and scp were effected
+     by this.
+     
+     "please commit" markus@
+ - (djm) [regress/README.regress] typo
+
+20100812
+ - (tim) [regress/login-timeout.sh regress/reconfigure.sh regress/reexec.sh
+   regress/test-exec.sh] Under certain conditions when testing with sudo
+   tests would fail because the pidfile could not be read by a regular user.
+   "cat: cannot open ...../regress/pidfile: Permission denied (error 13)"
+   Make sure cat is run by $SUDO.  no objection from me. djm@
+ - (tim) [auth.c] add cast to quiet compiler. Change only affects SVR5 systems.
+
+20100809
+ - (djm) bz#1561: don't bother setting IFF_UP on tun(4) device if it is
+   already set. Makes FreeBSD user openable tunnels useful; patch from
+   richard.burakowski+ossh AT mrburak.net, ok dtucker@
+ - (dtucker) bug #1530: strip trailing ":" from hostname in ssh-copy-id.
+   based in part on a patch from Colin Watson, ok djm@
+
+20100809
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/08/08 16:26:42
+     [version.h]
+     crank to 5.6
+ - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+   [contrib/suse/openssh.spec] Crank version numbers
+
+20100805
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/08/04 05:37:01
+     [ssh.1 ssh_config.5 sshd.8]
+     Remove mentions of weird "addr/port" alternate address format for IPv6
+     addresses combinations. It hasn't worked for ages and we have supported
+     the more commen "[addr]:port" format for a long time. ok jmc@ markus@
+   - djm@cvs.openbsd.org 2010/08/04 05:40:39
+     [PROTOCOL.certkeys ssh-keygen.c]
+     tighten the rules for certificate encoding by requiring that options
+     appear in lexical order and make our ssh-keygen comply. ok markus@
+   - djm@cvs.openbsd.org 2010/08/04 05:42:47
+     [auth.c auth2-hostbased.c authfile.c authfile.h ssh-keysign.8]
+     [ssh-keysign.c ssh.c]
+     enable certificates for hostbased authentication, from Iain Morgan;
+     "looks ok" markus@
+   - djm@cvs.openbsd.org 2010/08/04 05:49:22
+     [authfile.c]
+     commited the wrong version of the hostbased certificate diff; this
+     version replaces some strlc{py,at} verbosity with xasprintf() at
+     the request of markus@
+   - djm@cvs.openbsd.org 2010/08/04 06:07:11
+     [ssh-keygen.1 ssh-keygen.c]
+     Support CA keys in PKCS#11 tokens; feedback and ok markus@
+   - djm@cvs.openbsd.org 2010/08/04 06:08:40
+     [ssh-keysign.c]
+     clean for -Wuninitialized (Id sync only; portable had this change)
+   - djm@cvs.openbsd.org 2010/08/05 13:08:42
+     [channels.c]
+     Fix a trio of bugs in the local/remote window calculation for datagram
+     data channels (i.e. TunnelForward):
+     
+     Calculate local_consumed correctly in channel_handle_wfd() by measuring
+     the delta to buffer_len(c->output) from when we start to when we finish.
+     The proximal problem here is that the output_filter we use in portable
+     modified the length of the dequeued datagram (to futz with the headers
+     for !OpenBSD).
+     
+     In channel_output_poll(), don't enqueue datagrams that won't fit in the
+     peer's advertised packet size (highly unlikely to ever occur) or which
+     won't fit in the peer's remaining window (more likely).
+     
+     In channel_input_data(), account for the 4-byte string header in
+     datagram packets that we accept from the peer and enqueue in c->output.
+     
+     report, analysis and testing 2/3 cases from wierbows AT us.ibm.com;
+     "looks good" markus@
+
+20100803
+ - (dtucker) [monitor.c] Bug #1795: Initialize the values to be returned from
+   PAM to sane values in case the PAM method doesn't write to them.  Spotted by
+   Bitman Zhou, ok djm@.
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/07/16 04:45:30
+     [ssh-keygen.c]
+     avoid bogus compiler warning
+   - djm@cvs.openbsd.org 2010/07/16 14:07:35
+     [ssh-rsa.c]
+     more timing paranoia - compare all parts of the expected decrypted
+     data before returning. AFAIK not exploitable in the SSH protocol.
+     "groovy" deraadt@
+   - djm@cvs.openbsd.org 2010/07/19 03:16:33
+     [sftp-client.c]
+     bz#1797: fix swapped args in upload_dir_internal(), breaking recursive
+     upload depth checks and causing verbose printing of transfers to always
+     be turned on; patch from imorgan AT nas.nasa.gov
+   - djm@cvs.openbsd.org 2010/07/19 09:15:12
+     [clientloop.c readconf.c readconf.h ssh.c ssh_config.5]
+     add a "ControlPersist" option that automatically starts a background
+     ssh(1) multiplex master when connecting. This connection can stay alive
+     indefinitely, or can be set to automatically close after a user-specified
+     duration of inactivity. bz#1330 - patch by dwmw2 AT infradead.org, but
+     further hacked on by wmertens AT cisco.com, apb AT cequrux.com,
+     martin-mindrot-bugzilla AT earth.li and myself; "looks ok" markus@
+   - djm@cvs.openbsd.org 2010/07/21 02:10:58
+     [misc.c]
+     sync timingsafe_bcmp() with the one dempsky@ committed to sys/lib/libkern
+   - dtucker@cvs.openbsd.org 2010/07/23 08:49:25
+     [ssh.1]
+     Ciphers is documented in ssh_config(5) these days
+
+20100819
+ - (dtucker) [contrib/ssh-copy-ud.1] Bug #1786: update ssh-copy-id.1 with more
+   details about its behaviour WRT existing directories.  Patch from
+   asguthrie at gmail com, ok djm.
+
+20100716
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/07/02 04:32:44
+     [misc.c]
+     unbreak strdelim() skipping past quoted strings, e.g.
+     AllowUsers "blah blah" blah
+     was broken; report and fix in bz#1757 from bitman.zhou AT centrify.com
+     ok dtucker;
+   - djm@cvs.openbsd.org 2010/07/12 22:38:52
+     [ssh.c]
+     Make ExitOnForwardFailure work with fork-after-authentication ("ssh -f")
+     for protocol 2. ok markus@
+   - djm@cvs.openbsd.org 2010/07/12 22:41:13
+     [ssh.c ssh_config.5]
+     expand %h to the hostname in ssh_config Hostname options. While this
+     sounds useless, it is actually handy for working with unqualified
+     hostnames:
+     
+     Host *.*
+        Hostname %h
+     Host *
+        Hostname %h.example.org
+     
+     "I like it" markus@
+   - djm@cvs.openbsd.org 2010/07/13 11:52:06
+     [auth-rsa.c channels.c jpake.c key.c misc.c misc.h monitor.c]
+     [packet.c ssh-rsa.c]
+     implement a timing_safe_cmp() function to compare memory without leaking
+     timing information by short-circuiting like memcmp() and use it for
+     some of the more sensitive comparisons (though nothing high-value was
+     readily attackable anyway); "looks ok" markus@
+   - djm@cvs.openbsd.org 2010/07/13 23:13:16
+     [auth-rsa.c channels.c jpake.c key.c misc.c misc.h monitor.c packet.c]
+     [ssh-rsa.c]
+     s/timing_safe_cmp/timingsafe_bcmp/g
+   - jmc@cvs.openbsd.org 2010/07/14 17:06:58
+     [ssh.1]
+     finally ssh synopsis looks nice again! this commit just removes a ton of
+     hacks we had in place to make it work with old groff;
+   - schwarze@cvs.openbsd.org 2010/07/15 21:20:38
+     [ssh-keygen.1]
+     repair incorrect block nesting, which screwed up indentation;
+     problem reported and fix OK by jmc@
+
+20100714
+ - (tim) [contrib/redhat/openssh.spec] Bug 1796: Test for skip_x11_askpass
+   (line 77) should have been for no_x11_askpass. 
+
+20100702
+ - (djm) OpenBSD CVS Sync
+   - jmc@cvs.openbsd.org 2010/06/26 00:57:07
+     [ssh_config.5]
+     tweak previous;
+   - djm@cvs.openbsd.org 2010/06/26 23:04:04
+     [ssh.c]
+     oops, forgot to #include <canohost.h>; spotted and patch from chl@
+   - djm@cvs.openbsd.org 2010/06/29 23:15:30
+     [ssh-keygen.1 ssh-keygen.c]
+     allow import (-i) and export (-e) of PEM and PKCS#8 encoded keys;
+     bz#1749; ok markus@
+   - djm@cvs.openbsd.org 2010/06/29 23:16:46
+     [auth2-pubkey.c sshd_config.5]
+     allow key options (command="..." and friends) in AuthorizedPrincipals;
+     ok markus@
+   - jmc@cvs.openbsd.org 2010/06/30 07:24:25
+     [ssh-keygen.1]
+     tweak previous;
+   - jmc@cvs.openbsd.org 2010/06/30 07:26:03
+     [ssh-keygen.c]
+     sort usage();
+   - jmc@cvs.openbsd.org 2010/06/30 07:28:34
+     [sshd_config.5]
+     tweak previous;
+   - millert@cvs.openbsd.org 2010/07/01 13:06:59
+     [scp.c]
+     Fix a longstanding problem where if you suspend scp at the
+     password/passphrase prompt the terminal mode is not restored.
+     OK djm@
+   - phessler@cvs.openbsd.org 2010/06/27 19:19:56
+     [regress/Makefile]
+     fix how we run the tests so we can successfully use SUDO='sudo -E'
+     in our env
+   - djm@cvs.openbsd.org 2010/06/29 23:59:54
+     [cert-userkey.sh]
+     regress tests for key options in AuthorizedPrincipals
+
+20100627
+ - (tim) [openbsd-compat/port-uw.c] Reorder includes. auth-options.h now needs
+   key.h.
+
+20100626
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/05/21 05:00:36
+     [misc.c]
+     colon() returns char*, so s/return (0)/return NULL/
+   - markus@cvs.openbsd.org 2010/06/08 21:32:19
+     [ssh-pkcs11.c]
+     check length of value returned  C_GetAttributValue for != 0
+     from mdrtbugzilla@codefive.co.uk; bugzilla #1773; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/17 07:07:30
+     [mux.c]
+     Correct sizing of object to be allocated by calloc(), replacing
+     sizeof(state) with sizeof(*state). This worked by accident since
+     the struct contained a single int at present, but could have broken
+     in the future. patch from hyc AT symas.com
+   - djm@cvs.openbsd.org 2010/06/18 00:58:39
+     [sftp.c]
+     unbreak ls in working directories that contains globbing characters in
+     their pathnames. bz#1655 reported by vgiffin AT apple.com
+   - djm@cvs.openbsd.org 2010/06/18 03:16:03
+     [session.c]
+     Missing check for chroot_director == "none" (we already checked against
+     NULL); bz#1564 from Jan.Pechanec AT Sun.COM
+   - djm@cvs.openbsd.org 2010/06/18 04:43:08
+     [sftp-client.c]
+     fix memory leak in do_realpath() error path; bz#1771, patch from
+     anicka AT suse.cz
+   - djm@cvs.openbsd.org 2010/06/22 04:22:59
+     [servconf.c sshd_config.5]
+     expose some more sshd_config options inside Match blocks:
+       AuthorizedKeysFile AuthorizedPrincipalsFile
+       HostbasedUsesNameFromPacketOnly PermitTunnel
+     bz#1764; feedback from imorgan AT nas.nasa.gov; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/22 04:32:06
+     [ssh-keygen.c]
+     standardise error messages when attempting to open private key
+     files to include "progname: filename: error reason"
+     bz#1783; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/22 04:49:47
+     [auth.c]
+     queue auth debug messages for bad ownership or permissions on the user's
+     keyfiles. These messages will be sent after the user has successfully
+     authenticated (where our client will display them with LogLevel=debug).
+     bz#1554; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/22 04:54:30
+     [ssh-keyscan.c]
+     replace verbose and overflow-prone Linebuf code with read_keyfile_line()
+     based on patch from joachim AT joachimschipper.nl; bz#1565; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/22 04:59:12
+     [session.c]
+     include the user name on "subsystem request for ..." log messages;
+     bz#1571; ok dtucker@
+   - djm@cvs.openbsd.org 2010/06/23 02:59:02
+     [ssh-keygen.c]
+     fix printing of extensions in v01 certificates that I broke in r1.190
+   - djm@cvs.openbsd.org 2010/06/25 07:14:46
+     [channels.c mux.c readconf.c readconf.h ssh.h]
+     bz#1327: remove hardcoded limit of 100 permitopen clauses and port
+     forwards per direction; ok markus@ stevesk@
+   - djm@cvs.openbsd.org 2010/06/25 07:20:04
+     [channels.c session.c]
+     bz#1750: fix requirement for /dev/null inside ChrootDirectory for
+     internal-sftp accidentally introduced in r1.253 by removing the code
+     that opens and dup /dev/null to stderr and modifying the channels code
+     to read stderr but discard it instead; ok markus@
+   - djm@cvs.openbsd.org 2010/06/25 08:46:17
+     [auth1.c auth2-none.c]
+     skip the initial check for access with an empty password when
+     PermitEmptyPasswords=no; bz#1638; ok markus@
+   - djm@cvs.openbsd.org 2010/06/25 23:10:30
+     [ssh.c]
+     log the hostname and address that we connected to at LogLevel=verbose
+     after authentication is successful to mitigate "phishing" attacks by
+     servers with trusted keys that accept authentication silently and
+     automatically before presenting fake password/passphrase prompts;
+     "nice!" markus@
+   - djm@cvs.openbsd.org 2010/06/25 23:10:30
+     [ssh.c]
+     log the hostname and address that we connected to at LogLevel=verbose
+     after authentication is successful to mitigate "phishing" attacks by
+     servers with trusted keys that accept authentication silently and
+     automatically before presenting fake password/passphrase prompts;
+     "nice!" markus@
+
+20100622
+ - (djm) [loginrec.c] crank LINFO_NAMESIZE (username length) to 512
+   bz#1579; ok dtucker
+
+20100618
+ - (djm) [contrib/ssh-copy-id] Update key file explicitly under ~
+   rather than assuming that $CWD == $HOME. bz#1500, patch from
+   timothy AT gelter.com
+
+20100617
+ - (tim) [contrib/cygwin/README] Remove a reference to the obsolete
+   minires-devel package, and to add the reference to the libedit-devel
+   package since CYgwin now provides libedit. Patch from Corinna Vinschen.
+
+20100521
+ - (djm) OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/05/07 11:31:26
+     [regress/Makefile regress/cert-userkey.sh]
+     regress tests for AuthorizedPrincipalsFile and "principals=" key option.
+     feedback and ok markus@
+   - djm@cvs.openbsd.org 2010/05/11 02:58:04
+     [auth-rsa.c]
+     don't accept certificates marked as "cert-authority" here; ok markus@
+   - djm@cvs.openbsd.org 2010/05/14 00:47:22
+     [ssh-add.c]
+     check that the certificate matches the corresponding private key before
+     grafting it on
+   - djm@cvs.openbsd.org 2010/05/14 23:29:23
+     [channels.c channels.h mux.c ssh.c]
+     Pause the mux channel while waiting for reply from aynch callbacks.
+     Prevents misordering of replies if new requests arrive while waiting.
+     
+     Extend channel open confirm callback to allow signalling failure
+     conditions as well as success. Use this to 1) fix a memory leak, 2)
+     start using the above pause mechanism and 3) delay sending a success/
+     failure message on mux slave session open until we receive a reply from
+     the server.
+     
+     motivated by and with feedback from markus@
+   - markus@cvs.openbsd.org 2010/05/16 12:55:51
+     [PROTOCOL.mux clientloop.h mux.c readconf.c readconf.h ssh.1 ssh.c]
+     mux support for remote forwarding with dynamic port allocation,
+     use with
+        LPORT=`ssh -S muxsocket -R0:localhost:25 -O forward somehost`
+     feedback and ok djm@
+   - djm@cvs.openbsd.org 2010/05/20 11:25:26
+     [auth2-pubkey.c]
+     fix logspam when key options (from="..." especially) deny non-matching
+     keys; reported by henning@ also bz#1765; ok markus@ dtucker@
+   - djm@cvs.openbsd.org 2010/05/20 23:46:02
+     [PROTOCOL.certkeys auth-options.c ssh-keygen.c]
+     Move the permit-* options to the non-critical "extensions" field for v01
+     certificates. The logic is that if another implementation fails to
+     implement them then the connection just loses features rather than fails
+     outright.
+     
+     ok markus@
+
+20100511
+ - (dtucker) [Makefile.in] Bug #1770: Link libopenbsd-compat twice to solve
+   circular dependency problem on old or odd platforms.  From Tom Lane, ok
+   djm@.
+ - (djm) [openbsd-compat/openssl-compat.h] Fix build breakage on older
+   libcrypto by defining OPENSSL_[DR]SA_MAX_MODULUS_BITS if they aren't
+   already. ok dtucker@
+
+20100510
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/04/23 01:47:41
+     [ssh-keygen.c]
+     bz#1740: display a more helpful error message when $HOME is
+     inaccessible while trying to create .ssh directory. Based on patch
+     from jchadima AT redhat.com; ok dtucker@
+   - djm@cvs.openbsd.org 2010/04/23 22:27:38
+     [mux.c]
+     set "detach_close" flag when registering channel cleanup callbacks.
+     This causes the channel to close normally when its fds close and
+     hangs when terminating a mux slave using ~. bz#1758; ok markus@
+   - djm@cvs.openbsd.org 2010/04/23 22:42:05
+     [session.c]
+     set stderr to /dev/null for subsystems rather than just closing it.
+     avoids hangs if a subsystem or shell initialisation writes to stderr.
+     bz#1750; ok markus@
+   - djm@cvs.openbsd.org 2010/04/23 22:48:31
+     [ssh-keygen.c]
+     refuse to generate keys longer than OPENSSL_[RD]SA_MAX_MODULUS_BITS,
+     since we would refuse to use them anyway. bz#1516; ok dtucker@
+   - djm@cvs.openbsd.org 2010/04/26 22:28:24
+     [sshconnect2.c]
+     bz#1502: authctxt.success is declared as an int, but passed by
+     reference to function that accepts sig_atomic_t*. Convert it to
+     the latter; ok markus@ dtucker@
+   - djm@cvs.openbsd.org 2010/05/01 02:50:50
+     [PROTOCOL.certkeys]
+     typo; jmeltzer@
+   - dtucker@cvs.openbsd.org 2010/05/05 04:22:09
+     [sftp.c]
+     restore mput and mget which got lost in the tab-completion changes.
+     found by Kenneth Whitaker, ok djm@
+   - djm@cvs.openbsd.org 2010/05/07 11:30:30
+     [auth-options.c auth-options.h auth.c auth.h auth2-pubkey.c]
+     [key.c servconf.c servconf.h sshd.8 sshd_config.5]
+     add some optional indirection to matching of principal names listed
+     in certificates. Currently, a certificate must include the a user's name
+     to be accepted for authentication. This change adds the ability to
+     specify a list of certificate principal names that are acceptable.
+     
+     When authenticating using a CA trusted through ~/.ssh/authorized_keys,
+     this adds a new principals="name1[,name2,...]" key option.
+     
+     For CAs listed through sshd_config's TrustedCAKeys option, a new config
+     option "AuthorizedPrincipalsFile" specifies a per-user file containing
+     the list of acceptable names.
+     
+     If either option is absent, the current behaviour of requiring the
+     username to appear in principals continues to apply.
+     
+     These options are useful for role accounts, disjoint account namespaces
+     and "user@realm"-style naming policies in certificates.
+     
+     feedback and ok markus@
+   - jmc@cvs.openbsd.org 2010/05/07 12:49:17
+     [sshd_config.5]
+     tweak previous;
+
+20100423
+ - (dtucker) [configure.ac] Bug #1756: Check for the existence of a lib64 dir
+   in the openssl install directory (some newer openssl versions do this on at
+   least some amd64 platforms).
+
+20100418
+ - OpenBSD CVS Sync
+   - jmc@cvs.openbsd.org 2010/04/16 06:45:01
+     [ssh_config.5]
+     tweak previous; ok djm
+   - jmc@cvs.openbsd.org 2010/04/16 06:47:04
+     [ssh-keygen.1 ssh-keygen.c]
+     tweak previous; ok djm
+   - djm@cvs.openbsd.org 2010/04/16 21:14:27
+     [sshconnect.c]
+     oops, %r => remote username, not %u
+   - djm@cvs.openbsd.org 2010/04/16 01:58:45
+     [regress/cert-hostkey.sh regress/cert-userkey.sh]
+     regression tests for v01 certificate format
+     includes interop tests for v00 certs
+ - (dtucker) [contrib/aix/buildbff.sh] Fix creation of ssh_prng_cmds.default
+   file.
+
+20100416
+ - (djm) Release openssh-5.5p1
+ - OpenBSD CVS Sync
+   - djm@cvs.openbsd.org 2010/03/26 03:13:17
+     [bufaux.c]
+     allow buffer_get_int_ret/buffer_get_int64_ret to take a NULL pointer
+     argument to allow skipping past values in a buffer
+   - jmc@cvs.openbsd.org 2010/03/26 06:54:36
+     [ssh.1]
+     tweak previous;
+   - jmc@cvs.openbsd.org 2010/03/27 14:26:55
+     [ssh_config.5]
+     tweak previous; ok dtucker
+   - djm@cvs.openbsd.org 2010/04/10 00:00:16
+     [ssh.c]
+     bz#1746 - suppress spurious tty warning when using -O and stdin
+     is not a tty; ok dtucker@ markus@
+   - djm@cvs.openbsd.org 2010/04/10 00:04:30
+     [sshconnect.c]
+     fix terminology: we didn't find a certificate in known_hosts, we found
+     a CA key
+   - djm@cvs.openbsd.org 2010/04/10 02:08:44
+     [clientloop.c]
+     bz#1698: kill channel when pty allocation requests fail. Fixed
+     stuck client if the server refuses pty allocation.
+     ok dtucker@ "think so" markus@
+   - djm@cvs.openbsd.org 2010/04/10 02:10:56
+     [sshconnect2.c]
+     show the key type that we are offering in debug(), helps distinguish
+     between certs and plain keys as the path to the private key is usually
+     the same.
+   - djm@cvs.openbsd.org 2010/04/10 05:48:16
+     [mux.c]
+     fix NULL dereference; from matthew.haub AT alumni.adelaide.edu.au
+   - djm@cvs.openbsd.org 2010/04/14 22:27:42
+     [ssh_config.5 sshconnect.c]
+     expand %r => remote username in ssh_config:ProxyCommand;
+     ok deraadt markus
+   - markus@cvs.openbsd.org 2010/04/15 20:32:55
+     [ssh-pkcs11.c]
+     retry lookup for private key if there's no matching key with CKA_SIGN
+     attribute enabled; this fixes fixes MuscleCard support (bugzilla #1736)
+     ok djm@
+   - djm@cvs.openbsd.org 2010/04/16 01:47:26
+     [PROTOCOL.certkeys auth-options.c auth-options.h auth-rsa.c]
+     [auth2-pubkey.c authfd.c key.c key.h myproposal.h ssh-add.c]
+     [ssh-agent.c ssh-dss.c ssh-keygen.1 ssh-keygen.c ssh-rsa.c]
+     [sshconnect.c sshconnect2.c sshd.c]
+     revised certificate format ssh-{dss,rsa}-cert-v01@openssh.com with the
+     following changes:
+     
+     move the nonce field to the beginning of the certificate where it can
+     better protect against chosen-prefix attacks on the signature hash
+     
+     Rename "constraints" field to "critical options"
+     
+     Add a new non-critical "extensions" field
+     
+     Add a serial number
+     
+     The older format is still support for authentication and cert generation
+     (use "ssh-keygen -t v00 -s ca_key ..." to generate a v00 certificate)
+     
+     ok markus@
+
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..09dfd66
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,265 @@
+1. Prerequisites
+----------------
+
+You will need working installations of Zlib and OpenSSL.
+
+Zlib 1.1.4 or 1.2.1.2 or greater (ealier 1.2.x versions have problems):
+http://www.gzip.org/zlib/
+
+OpenSSL 0.9.6 or greater:
+http://www.openssl.org/
+
+(OpenSSL 0.9.5a is partially supported, but some ciphers (SSH protocol 1
+Blowfish) do not work correctly.)
+
+The remaining items are optional.
+
+NB. If you operating system supports /dev/random, you should configure
+OpenSSL to use it. OpenSSH relies on OpenSSL's direct support of
+/dev/random, or failing that, either prngd or egd.  If you don't have
+any of these you will have to rely on ssh-rand-helper, which is inferior
+to a good kernel-based solution or prngd.
+
+PRNGD:
+
+If your system lacks kernel-based random collection, the use of Lutz
+Jaenicke's PRNGd is recommended.
+
+http://prngd.sourceforge.net/
+
+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/
+
+PAM:
+
+OpenSSH can utilise Pluggable Authentication Modules (PAM) if your
+system supports it. PAM is standard most Linux distributions, Solaris,
+HP-UX 11, AIX >= 5.2, FreeBSD and NetBSD.
+
+Information about the various PAM implementations are available:
+
+Solaris PAM:   http://www.sun.com/software/solaris/pam/
+Linux PAM:     http://www.kernel.org/pub/linux/libs/pam/
+OpenPAM:       http://www.openpam.org/
+
+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@pobox.com> has written an excellent X11
+passphrase requester. This is maintained separately at:
+
+http://www.jmknoble.net/software/x11-ssh-askpass/
+
+TCP Wrappers:
+
+If you wish to use the TCP wrappers functionality you will need at least
+tcpd.h and libwrap.a, either in the standard include and library paths,
+or in the directory specified by --with-tcp-wrappers.  Version 7.6 is
+known to work.
+
+http://ftp.porcupine.org/pub/security/index.html
+
+S/Key Libraries:
+
+If you wish to use --with-skey then you will need the library below
+installed.  No other S/Key library is currently known to be supported.
+
+http://www.sparc.spb.su/solaris/skey/
+
+LibEdit:
+
+sftp supports command-line editing via NetBSD's libedit.  If your platform
+has it available natively you can use that, alternatively you might try
+these multi-platform ports:
+
+http://www.thrysoee.dk/editline/
+http://sourceforge.net/projects/libedit/
+
+Autoconf:
+
+If you modify configure.ac or configure doesn't exist (eg if you checked
+the code out of CVS yourself) then you will need autoconf-2.61 to rebuild
+the automatically generated files by running "autoreconf".  Earlier
+versions may also work but this is not guaranteed.
+
+http://www.gnu.org/software/autoconf/
+
+Basic Security Module (BSM):
+
+Native BSM support is know to exist in Solaris from at least 2.5.1,
+FreeBSD 6.1 and OS X.  Alternatively, you may use the OpenBSM
+implementation (http://www.openbsm.org).
+
+
+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 Privilege Separation (which is enabled by default)
+then you will also need to create the user, group and directory used by
+sshd for privilege separation.  See README.privsep for details.
+
+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-audit=[module] enable additional auditing via the specified module.
+Currently, drivers for "debug" (additional info via syslog) and "bsm"
+(Sun's Basic Security Module) are supported.
+
+--with-pam enables PAM support. If PAM support is compiled in, it must
+also be enabled in sshd_config (refer to the UsePAM directive).
+
+--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-osfsia, --without-osfsia will enable or disable OSF1's Security
+Integration Architecture.  The default for OSF1 machines is enable.
+
+--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.
+
+--with-md5-passwords will enable the use of MD5 passwords. Enable this
+if your operating system uses MD5 passwords and the system crypt() does
+not support them directly (see the crypt(3/3c) man page). If enabled, the
+resulting binary will support both MD5 and traditional crypt passwords.
+
+--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 sshd.pid file is
+created.
+
+--with-xauth=PATH specifies the location of the xauth binary
+
+--with-ssl-dir=DIR allows you to specify where your OpenSSL libraries
+are installed.
+
+--with-ssl-engine enables OpenSSL's (hardware) ENGINE support
+
+--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. (Optional) Send survey
+-------------------------
+
+$ make survey
+[check the contents of the file "survey" to ensure there's no information
+that you consider sensitive]
+$ make send-survey
+
+This will send configuration information for the currently configured
+host to a survey address.  This will help determine which configurations
+are actually in use, and what valid combinations of configure options
+exist.  The raw data is available only to the OpenSSH developers, however
+summary data may be published.
+
+5. 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: INSTALL,v 1.85 2010/02/11 22:34:22 djm Exp $
diff --git a/LICENCE b/LICENCE
new file mode 100644 (file)
index 0000000..120d6fd
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,339 @@
+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 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>
+
+3)
+    ssh-keyscan 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.
+
+4)
+    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.
+
+5)
+    One component of the ssh source code is under a 3-clause BSD license,
+    held by the University of California, since we pulled these parts from
+    original Berkeley code.
+
+     * 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. 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.
+
+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
+       Daniel Kouril
+       Wesley Griffin
+       Per Allansson
+       Nils Nordman
+       Simon Wilkinson
+
+    Portable OpenSSH additionally includes code from the following copyright
+    holders, also under the 2-term BSD license:
+
+       Ben Lindstrom
+       Tim Rice
+       Andre Lucas
+       Chris Adams
+       Corinna Vinschen
+       Cray Inc.
+       Denis Parker
+       Gert Doering
+       Jakob Schlyter
+       Jason Downs
+       Juha Yrjölä
+       Michael Stone
+       Networks Associates Technology, Inc.
+       Solar Designer
+       Todd C. Miller
+       Wayne Schroeder
+       William Jones
+       Darren Tucker
+       Sun Microsystems
+       The SCO Group
+       Daniel Walsh
+       Red Hat, Inc
+
+     * 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.
+
+8) Portable OpenSSH contains the following additional licenses:
+
+    a) md5crypt.c, md5crypt.h
+
+        * "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
+
+    b) snprintf replacement
+
+       * Copyright Patrick Powell 1995
+       * This code is based on code written by Patrick Powell
+       * (papowell@astart.com) It may be used for any purpose as long as this
+       * notice remains intact on all source code distributions
+
+    c) Compatibility code (openbsd-compat)
+
+       Apart from the previously mentioned licenses, various pieces of code
+       in the openbsd-compat/ subdirectory are licensed as follows:
+
+       Some code is licensed under a 3-term BSD license, to the following
+       copyright holders:
+
+       Todd C. Miller
+       Theo de Raadt
+       Damien Miller
+       Eric P. Allman
+       The Regents of the University of California
+       Constantin S. Svintsoff
+
+       * 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. 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.
+
+       Some code is licensed under an ISC-style license, to the following
+       copyright holders:
+
+       Internet Software Consortium.
+       Todd C. Miller
+       Reyk Floeter
+       Chad Mynhier
+
+       * 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 TODD C. MILLER DISCLAIMS ALL
+       * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+       * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER 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.
+
+       Some code is licensed under a MIT-style license to the following
+       copyright holders:
+
+       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.                                                           *
+       ****************************************************************************/
+
+
+------
+$OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $
diff --git a/Makefile.in b/Makefile.in
new file mode 100644 (file)
index 0000000..870a7f1
--- /dev/null
@@ -0,0 +1,469 @@
+# $Id: Makefile.in,v 1.320.4.1 2011/02/04 00:42:13 djm Exp $
+
+# uncomment if you run a non bourne compatable shell. Ie. csh
+#SHELL = @SH@
+
+AUTORECONF=autoreconf
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+libexecdir=@libexecdir@
+datadir=@datadir@
+datarootdir=@datarootdir@
+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
+SSH_KEYSIGN=$(libexecdir)/ssh-keysign
+SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper
+RAND_HELPER=$(libexecdir)/ssh-rand-helper
+PRIVSEP_PATH=@PRIVSEP_PATH@
+SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@
+STRIP_OPT=@STRIP_OPT@
+
+PATHS= -DSSHDIR=\"$(sysconfdir)\" \
+       -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \
+       -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \
+       -D_PATH_SFTP_SERVER=\"$(SFTP_SERVER)\" \
+       -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \
+       -D_PATH_SSH_PKCS11_HELPER=\"$(SSH_PKCS11_HELPER)\" \
+       -D_PATH_SSH_PIDDIR=\"$(piddir)\" \
+       -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \
+       -DSSH_RAND_HELPER=\"$(RAND_HELPER)\"
+
+CC=@CC@
+LD=@LD@
+CFLAGS=@CFLAGS@
+CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@
+LIBS=@LIBS@
+SSHLIBS=@SSHLIBS@
+SSHDLIBS=@SSHDLIBS@
+LIBEDIT=@LIBEDIT@
+AR=@AR@
+AWK=@AWK@
+RANLIB=@RANLIB@
+INSTALL=@INSTALL@
+PERL=@PERL@
+SED=@SED@
+ENT=@ENT@
+XAUTH_PATH=@XAUTH_PATH@
+LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@
+EXEEXT=@EXEEXT@
+MANFMT=@MANFMT@
+
+INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
+INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+
+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
+
+LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+       canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+       cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
+       compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
+       log.o match.o md-sha256.o moduli.o nchan.o packet.o \
+       readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
+       atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
+       monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
+       kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \
+       msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o jpake.o \
+       schnorr.o ssh-pkcs11.o
+
+SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+       sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+       roaming_common.o roaming_client.o
+
+SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
+       audit.o audit-bsm.o audit-linux.o platform.o \
+       sshpty.o sshlogin.o servconf.o serverloop.o \
+       auth.o auth1.o auth2.o auth-options.o session.o \
+       auth-chall.o auth2-chall.o groupaccess.o \
+       auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
+       auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-jpake.o \
+       monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \
+       auth-krb5.o \
+       auth2-gss.o gss-serv.o gss-serv-krb5.o \
+       loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+       sftp-server.o sftp-common.o \
+       roaming_common.o roaming_serv.o
+
+MANPAGES       = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
+MANPAGES_IN    = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
+MANTYPE                = @MANTYPE@
+
+CONFIGFILES=sshd_config.out ssh_config.out moduli.out
+CONFIGFILES_IN=sshd_config ssh_config moduli
+
+PATHSUBS       = \
+       -e 's|/etc/ssh/ssh_prng_cmds|$(sysconfdir)/ssh_prng_cmds|g' \
+       -e 's|/etc/ssh/ssh_config|$(sysconfdir)/ssh_config|g' \
+       -e 's|/etc/ssh/ssh_known_hosts|$(sysconfdir)/ssh_known_hosts|g' \
+       -e 's|/etc/ssh/sshd_config|$(sysconfdir)/sshd_config|g' \
+       -e 's|/usr/libexec|$(libexecdir)|g' \
+       -e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \
+       -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \
+       -e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \
+       -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \
+       -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \
+       -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \
+       -e 's|/etc/moduli|$(sysconfdir)/moduli|g' \
+       -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \
+       -e 's|/etc/ssh/sshrc|$(sysconfdir)/sshrc|g' \
+       -e 's|/usr/X11R6/bin/xauth|$(XAUTH_PATH)|g' \
+       -e 's|/var/empty|$(PRIVSEP_PATH)|g' \
+       -e 's|/usr/bin:/bin:/usr/sbin:/sbin|@user_path@|g'
+
+FIXPATHSCMD    = $(SED) $(PATHSUBS)
+
+all: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS)
+
+$(LIBSSH_OBJS): Makefile.in config.h
+$(SSHOBJS): Makefile.in config.h
+$(SSHDOBJS): Makefile.in 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 $(SSHLIBS) $(LIBS)
+
+sshd$(EXEEXT): libssh.a        $(LIBCOMPAT) $(SSHDOBJS)
+       $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS)
+
+scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o
+       $(LD) -o $@ scp.o progressmeter.o bufaux.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 ssh-pkcs11-client.o
+       $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.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-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readconf.o
+       $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o
+       $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
+
+ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+       $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+
+sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
+       $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+
+sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
+       $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
+
+ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
+       $(LD) -o $@ ssh-rand-helper.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} | $(AWK) -f $(srcdir)/mdoc2man.awk > $@; \
+       else \
+               $(FIXPATHSCMD) $${manpage} > $@; \
+       fi
+
+$(CONFIGFILES): $(CONFIGFILES_IN)
+       conffile=`echo $@ | sed 's/.out$$//'`; \
+       $(FIXPATHSCMD) $(srcdir)/$${conffile} > $@
+
+ssh_prng_cmds.out:     ssh_prng_cmds
+       if test ! -z "$(INSTALL_SSH_PRNG_CMDS)"; then \
+               $(PERL) $(srcdir)/fixprogs ssh_prng_cmds $(ENT); \
+       fi
+
+# fake rule to stop make trying to compile moduli.o into a binary "moduli.o"
+moduli:
+       echo
+
+clean: regressclean
+       rm -f *.o *.a $(TARGETS) logintest config.cache config.log
+       rm -f *.out core survey
+       (cd openbsd-compat && $(MAKE) clean)
+
+distclean:     regressclean
+       rm -f *.o *.a $(TARGETS) logintest config.cache config.log
+       rm -f *.out core opensshd.init openssh.xml
+       rm -f Makefile buildpkg.sh config.h config.status ssh_prng_cmds
+       rm -f survey.sh openbsd-compat/regress/Makefile *~ 
+       rm -rf autom4te.cache
+       (cd openbsd-compat && $(MAKE) distclean)
+       if test -d pkg ; then \
+               rm -fr pkg ; \
+       fi
+
+veryclean: distclean
+       rm -f configure config.h.in *.0
+
+mrproper: veryclean
+
+realclean: veryclean
+
+catman-do:
+       @for f in $(MANPAGES_IN) ; do \
+               base=`echo $$f | sed 's/\..*$$//'` ; \
+               echo "$$f -> $$base.0" ; \
+               $(MANFMT) $$f | cat -v | sed -e 's/.\^H//g' \
+                       >$$base.0 ; \
+       done
+
+distprep: catman-do
+       $(AUTORECONF)
+       -rm -rf autom4te.cache
+
+install: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) install-files install-sysconf host-key check-config
+install-nokeys: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) install-files install-sysconf
+install-nosysconf: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS) install-files
+
+check-config:
+       -$(DESTDIR)$(sbindir)/sshd -t -f $(DESTDIR)$(sysconfdir)/sshd_config
+
+install-files:
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(sbindir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)1
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)5
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(mandir)/$(mansubdir)8
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(libexecdir)
+       (umask 022 ; $(srcdir)/mkinstalldirs $(DESTDIR)$(PRIVSEP_PATH))
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh$(EXEEXT) $(DESTDIR)$(bindir)/ssh$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) scp$(EXEEXT) $(DESTDIR)$(bindir)/scp$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh-add$(EXEEXT) $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh-agent$(EXEEXT) $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
+       if test ! -z "$(INSTALL_SSH_RAND_HELPER)" ; then \
+               $(INSTALL) -m 0755 $(STRIP_OPT) ssh-rand-helper$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-rand-helper$(EXEEXT) ; \
+       fi
+       $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+       $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+       $(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 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5
+       $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5
+       $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5
+       $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
+       if [ ! -z "$(INSTALL_SSH_RAND_HELPER)" ]; then \
+               $(INSTALL) -m 644 ssh-rand-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8 ; \
+       fi
+       $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+       $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+       $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+       $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.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
+
+install-sysconf:
+       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 ] && [ ! -z "$(INSTALL_SSH_PRNG_CMDS)" ]; then \
+               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 "$(sysconfdir)/ssh_host_key" ] ; then \
+                       echo "$(sysconfdir)/ssh_host_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t rsa1 -f $(sysconfdir)/ssh_host_key -N "" ; \
+               fi ; \
+               if [ -f $(sysconfdir)/ssh_host_dsa_key ] ; then \
+                       echo "$(sysconfdir)/ssh_host_dsa_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t dsa -f $(sysconfdir)/ssh_host_dsa_key -N "" ; \
+               fi ; \
+               if [ -f $(sysconfdir)/ssh_host_rsa_key ] ; then \
+                       echo "$(sysconfdir)/ssh_host_rsa_key already exists, skipping." ; \
+               else \
+                       ./ssh-keygen -t rsa -f $(sysconfdir)/ssh_host_rsa_key -N "" ; \
+               fi ; \
+               if [ -z "@COMMENT_OUT_ECC@" ] ; then \
+                   if [ -f $(sysconfdir)/ssh_host_ecdsa_key ] ; then \
+                       echo "$(sysconfdir)/ssh_host_ecdsa_key already exists, skipping." ; \
+                   else \
+                       ./ssh-keygen -t ecdsa -f $(sysconfdir)/ssh_host_ecdsa_key -N "" ; \
+                   fi ; \
+               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 ""
+       test -z "@COMMENT_OUT_ECC@" && ./ssh-keygen -t ecdsa -f $(DESTDIR)$(sysconfdir)/ssh_host_ecdsa_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)$(SSH_KEYSIGN)$(EXEEXT)
+       -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
+       -rm -f $(DESTDIR)$(RAND_HELPER)$(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/ssh-rand-helper.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+
+tests interop-tests:   $(TARGETS)
+       BUILDDIR=`pwd`; \
+       [ -d `pwd`/regress ]  ||  mkdir -p `pwd`/regress; \
+       [ -f `pwd`/regress/Makefile ]  || \
+           ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile ; \
+       TEST_SHELL="@TEST_SHELL@"; \
+       TEST_SSH_SSH="$${BUILDDIR}/ssh"; \
+       TEST_SSH_SSHD="$${BUILDDIR}/sshd"; \
+       TEST_SSH_SSHAGENT="$${BUILDDIR}/ssh-agent"; \
+       TEST_SSH_SSHADD="$${BUILDDIR}/ssh-add"; \
+       TEST_SSH_SSHKEYGEN="$${BUILDDIR}/ssh-keygen"; \
+       TEST_SSH_SSHPKCS11HELPER="$${BUILDDIR}/ssh-pkcs11-helper"; \
+       TEST_SSH_SSHKEYSCAN="$${BUILDDIR}/ssh-keyscan"; \
+       TEST_SSH_SFTP="$${BUILDDIR}/sftp"; \
+       TEST_SSH_SFTPSERVER="$${BUILDDIR}/sftp-server"; \
+       TEST_SSH_PLINK="plink"; \
+       TEST_SSH_PUTTYGEN="puttygen"; \
+       TEST_SSH_CONCH="conch"; \
+       TEST_SSH_IPV6="@TEST_SSH_IPV6@" ; \
+       TEST_SSH_ECC="@TEST_SSH_ECC@" ; \
+       TEST_SSH_SHA256="@TEST_SSH_SHA256@" ; \
+       cd $(srcdir)/regress || exit $$?; \
+       $(MAKE) \
+               .OBJDIR="$${BUILDDIR}/regress" \
+               .CURDIR="`pwd`" \
+               BUILDDIR="$${BUILDDIR}" \
+               OBJ="$${BUILDDIR}/regress/" \
+               PATH="$${BUILDDIR}:$${PATH}" \
+               TEST_SHELL="$${TEST_SHELL}" \
+               TEST_SSH_SSH="$${TEST_SSH_SSH}" \
+               TEST_SSH_SSHD="$${TEST_SSH_SSHD}" \
+               TEST_SSH_SSHAGENT="$${TEST_SSH_SSHAGENT}" \
+               TEST_SSH_SSHADD="$${TEST_SSH_SSHADD}" \
+               TEST_SSH_SSHKEYGEN="$${TEST_SSH_SSHKEYGEN}" \
+               TEST_SSH_SSHPKCS11HELPER="$${TEST_SSH_SSHPKCS11HELPER}" \
+               TEST_SSH_SSHKEYSCAN="$${TEST_SSH_SSHKEYSCAN}" \
+               TEST_SSH_SFTP="$${TEST_SSH_SFTP}" \
+               TEST_SSH_SFTPSERVER="$${TEST_SSH_SFTPSERVER}" \
+               TEST_SSH_PLINK="$${TEST_SSH_PLINK}" \
+               TEST_SSH_PUTTYGEN="$${TEST_SSH_PUTTYGEN}" \
+               TEST_SSH_CONCH="$${TEST_SSH_CONCH}" \
+               TEST_SSH_IPV6="$${TEST_SSH_IPV6}" \
+               TEST_SSH_ECC="$${TEST_SSH_ECC}" \
+               TEST_SSH_SHA256="$${TEST_SSH_SHA256}" \
+               EXEEXT="$(EXEEXT)" \
+               $@ && echo all tests passed
+
+compat-tests: $(LIBCOMPAT)
+       (cd openbsd-compat/regress && $(MAKE))
+
+regressclean:
+       if [ -f regress/Makefile ] && [ -r regress/Makefile ]; then \
+               (cd regress && $(MAKE) clean) \
+       fi
+
+survey: survey.sh ssh
+       @$(SHELL) ./survey.sh > survey
+       @echo 'The survey results have been placed in the file "survey" in the'
+       @echo 'current directory.  Please review the file then send with'
+       @echo '"make send-survey".'
+
+send-survey:   survey
+       mail portable-survey@mindrot.org <survey
+
+package: $(CONFIGFILES) ssh_prng_cmds.out $(MANPAGES) $(TARGETS)
+       if [ "@MAKE_PACKAGE_SUPPORTED@" = yes ]; then \
+               sh buildpkg.sh; \
+       fi
+
diff --git a/OVERVIEW b/OVERVIEW
new file mode 100644 (file)
index 0000000..2e1cc0b
--- /dev/null
+++ b/OVERVIEW
@@ -0,0 +1,168 @@
+[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.
+
+  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)
+       uidswap.c    uid-swapping
+       xmalloc.c    "safe" malloc routines
+
+$OpenBSD: OVERVIEW,v 1.11 2006/08/03 03:34:41 deraadt Exp $
diff --git a/PROTOCOL b/PROTOCOL
new file mode 100644 (file)
index 0000000..c281960
--- /dev/null
+++ b/PROTOCOL
@@ -0,0 +1,294 @@
+This documents OpenSSH's deviations and extensions to the published SSH
+protocol.
+
+Note that OpenSSH's sftp and sftp-server implement revision 3 of the SSH
+filexfer protocol described in:
+
+http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
+
+Newer versions of the draft will not be supported, though some features
+are individually implemented as extensions described below.
+
+The protocol used by OpenSSH's ssh-agent is described in the file
+PROTOCOL.agent
+
+1. Transport protocol changes
+
+1.1. transport: Protocol 2 MAC algorithm "umac-64@openssh.com"
+
+This is a new transport-layer MAC method using the UMAC algorithm
+(rfc4418). This method is identical to the "umac-64" method documented
+in:
+
+http://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
+
+1.2. transport: Protocol 2 compression algorithm "zlib@openssh.com"
+
+This transport-layer compression method uses the zlib compression
+algorithm (identical to the "zlib" method in rfc4253), but delays the
+start of compression until after authentication has completed. This
+avoids exposing compression code to attacks from unauthenticated users.
+
+The method is documented in:
+
+http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
+
+1.3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com",
+     "ssh-dsa-cert-v00@openssh.com",
+     "ecdsa-sha2-nistp256-cert-v01@openssh.com",
+     "ecdsa-sha2-nistp384-cert-v01@openssh.com" and
+     "ecdsa-sha2-nistp521-cert-v01@openssh.com"
+
+OpenSSH introduces new public key algorithms to support certificate
+authentication for users and hostkeys. These methods are documented in
+the file PROTOCOL.certkeys
+
+1.4. transport: Elliptic Curve cryptography
+
+OpenSSH supports ECC key exchange and public key authentication as
+specified in RFC5656. Only the ecdsa-sha2-nistp256, ecdsa-sha2-nistp384
+and ecdsa-sha2-nistp521 curves over GF(p) are supported. Elliptic
+curve points encoded using point compression are NOT accepted or
+generated.
+
+2. Connection protocol changes
+
+2.1. connection: Channel write close extension "eow@openssh.com"
+
+The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF
+message to allow an endpoint to signal its peer that it will send no
+more data over a channel. Unfortunately, there is no symmetric way for
+an endpoint to request that its peer should cease sending data to it
+while still keeping the channel open for the endpoint to send data to
+the peer.
+
+This is desirable, since it saves the transmission of data that would
+otherwise need to be discarded and it allows an endpoint to signal local
+processes of the condition, e.g. by closing the corresponding file
+descriptor.
+
+OpenSSH implements a channel extension message to perform this
+signalling: "eow@openssh.com" (End Of Write). This message is sent by
+an endpoint when the local output of a session channel is closed or
+experiences a write error. The message is formatted as follows:
+
+       byte            SSH_MSG_CHANNEL_REQUEST
+       uint32          recipient channel
+       string          "eow@openssh.com"
+       boolean         FALSE
+
+On receiving this message, the peer SHOULD cease sending data of
+the channel and MAY signal the process from which the channel data
+originates (e.g. by closing its read file descriptor).
+
+As with the symmetric SSH_MSG_CHANNEL_EOF message, the channel does
+remain open after a "eow@openssh.com" has been sent and more data may
+still be sent in the other direction. This message does not consume
+window space and may be sent even if no window space is available.
+
+NB. due to certain broken SSH implementations aborting upon receipt
+of this message (in contravention of RFC4254 section 5.4), this
+message is only sent to OpenSSH peers (identified by banner).
+Other SSH implementations may be whitelisted to receive this message
+upon request.
+
+2.2. connection: disallow additional sessions extension
+     "no-more-sessions@openssh.com"
+
+Most SSH connections will only ever request a single session, but a
+attacker may abuse a running ssh client to surreptitiously open
+additional sessions under their control. OpenSSH provides a global
+request "no-more-sessions@openssh.com" to mitigate this attack.
+
+When an OpenSSH client expects that it will never open another session
+(i.e. it has been started with connection multiplexing disabled), it
+will send the following global request:
+
+       byte            SSH_MSG_GLOBAL_REQUEST
+       string          "no-more-sessions@openssh.com"
+       char            want-reply
+
+On receipt of such a message, an OpenSSH server will refuse to open
+future channels of type "session" and instead immediately abort the
+connection.
+
+Note that this is not a general defence against compromised clients
+(that is impossible), but it thwarts a simple attack.
+
+NB. due to certain broken SSH implementations aborting upon receipt
+of this message, the no-more-sessions request is only sent to OpenSSH
+servers (identified by banner). Other SSH implementations may be
+whitelisted to receive this message upon request.
+
+2.3. connection: Tunnel forward extension "tun@openssh.com"
+
+OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com"
+channel type. This channel type supports forwarding of network packets
+with datagram boundaries intact between endpoints equipped with 
+interfaces like the BSD tun(4) device. Tunnel forwarding channels are
+requested by the client with the following packet:
+
+       byte            SSH_MSG_CHANNEL_OPEN
+       string          "tun@openssh.com"
+       uint32          sender channel
+       uint32          initial window size
+       uint32          maximum packet size
+       uint32          tunnel mode
+       uint32          remote unit number
+
+The "tunnel mode" parameter specifies whether the tunnel should forward
+layer 2 frames or layer 3 packets. It may take one of the following values:
+
+       SSH_TUNMODE_POINTOPOINT  1              /* layer 3 packets */
+       SSH_TUNMODE_ETHERNET     2              /* layer 2 frames */
+
+The "tunnel unit number" specifies the remote interface number, or may
+be 0x7fffffff to allow the server to automatically chose an interface. A
+server that is not willing to open a client-specified unit should refuse
+the request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful
+open, the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS.
+
+Once established the client and server may exchange packet or frames
+over the tunnel channel by encapsulating them in SSH protocol strings
+and sending them as channel data. This ensures that packet boundaries
+are kept intact. Specifically, packets are transmitted using normal
+SSH_MSG_CHANNEL_DATA packets:
+
+       byte            SSH_MSG_CHANNEL_DATA
+       uint32          recipient channel
+       string          data
+
+The contents of the "data" field for layer 3 packets is:
+
+       uint32                  packet length
+       uint32                  address family
+       byte[packet length - 4] packet data
+
+The "address family" field identifies the type of packet in the message.
+It may be one of:
+
+       SSH_TUN_AF_INET         2               /* IPv4 */
+       SSH_TUN_AF_INET6        24              /* IPv6 */
+
+The "packet data" field consists of the IPv4/IPv6 datagram itself
+without any link layer header.
+
+The contents of the "data" field for layer 2 packets is:
+
+       uint32                  packet length
+       byte[packet length]     frame
+
+The "frame" field contains an IEEE 802.3 Ethernet frame, including
+header.
+
+3. SFTP protocol changes
+
+3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
+
+When OpenSSH's sftp-server was implemented, the order of the arguments
+to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
+the reversal was not noticed until the server was widely deployed. Since
+fixing this to follow the specification would cause incompatibility, the
+current order was retained. For correct operation, clients should send
+SSH_FXP_SYMLINK as follows:
+
+       uint32          id
+       string          targetpath
+       string          linkpath
+
+3.2. sftp: Server extension announcement in SSH_FXP_VERSION
+
+OpenSSH's sftp-server lists the extensions it supports using the
+standard extension announcement mechanism in the SSH_FXP_VERSION server
+hello packet:
+
+       uint32          3               /* protocol version */
+       string          ext1-name
+       string          ext1-version
+       string          ext2-name
+       string          ext2-version
+       ...
+       string          extN-name
+       string          extN-version
+
+Each extension reports its integer version number as an ASCII encoded
+string, e.g. "1". The version will be incremented if the extension is
+ever changed in an incompatible way. The server MAY advertise the same
+extension with multiple versions (though this is unlikely). Clients MUST
+check the version number before attempting to use the extension.
+
+3.3. sftp: Extension request "posix-rename@openssh.com"
+
+This operation provides a rename operation with POSIX semantics, which
+are different to those provided by the standard SSH_FXP_RENAME in
+draft-ietf-secsh-filexfer-02.txt. This request is implemented as a
+SSH_FXP_EXTENDED request with the following format:
+
+       uint32          id
+       string          "posix-rename@openssh.com"
+       string          oldpath
+       string          newpath
+
+On receiving this request the server will perform the POSIX operation
+rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+3.4. sftp: Extension requests "statvfs@openssh.com" and
+         "fstatvfs@openssh.com"
+
+These requests correspond to the statvfs and fstatvfs POSIX system
+interfaces. The "statvfs@openssh.com" request operates on an explicit
+pathname, and is formatted as follows:
+
+       uint32          id
+       string          "statvfs@openssh.com"
+       string          path
+
+The "fstatvfs@openssh.com" operates on an open file handle:
+
+       uint32          id
+       string          "fstatvfs@openssh.com"
+       string          handle
+
+These requests return a SSH_FXP_STATUS reply on failure. On success they
+return the following SSH_FXP_EXTENDED_REPLY reply:
+
+       uint32          id
+       uint64          f_bsize         /* file system block size */
+       uint64          f_frsize        /* fundamental fs block size */
+       uint64          f_blocks        /* number of blocks (unit f_frsize) */
+       uint64          f_bfree         /* free blocks in file system */
+       uint64          f_bavail        /* free blocks for non-root */
+       uint64          f_files         /* total file inodes */
+       uint64          f_ffree         /* free file inodes */
+       uint64          f_favail        /* free file inodes for to non-root */
+       uint64          f_fsid          /* file system id */
+       uint64          f_flag          /* bit mask of f_flag values */
+       uint64          f_namemax       /* maximum filename length */
+
+The values of the f_flag bitmask are as follows:
+
+       #define SSH_FXE_STATVFS_ST_RDONLY       0x1     /* read-only */
+       #define SSH_FXE_STATVFS_ST_NOSUID       0x2     /* no setuid */
+
+Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
+advertised in the SSH_FXP_VERSION hello with version "2".
+
+10. sftp: Extension request "hardlink@openssh.com"
+
+This request is for creating a hard link to a regular file. This
+request is implemented as a SSH_FXP_EXTENDED request with the
+following format:
+
+       uint32          id
+       string          "hardlink@openssh.com"
+       string          oldpath
+       string          newpath
+
+On receiving this request the server will perform the operation
+link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+$OpenBSD: PROTOCOL,v 1.17 2010/12/04 00:18:01 djm Exp $
diff --git a/PROTOCOL.agent b/PROTOCOL.agent
new file mode 100644 (file)
index 0000000..de94d03
--- /dev/null
@@ -0,0 +1,560 @@
+This describes the protocol used by OpenSSH's ssh-agent.
+
+OpenSSH's agent supports managing keys for the standard SSH protocol
+2 as well as the legacy SSH protocol 1. Support for these key types
+is almost completely disjoint - in all but a few cases, operations on
+protocol 2 keys cannot see or affect protocol 1 keys and vice-versa.
+
+Protocol 1 and protocol 2 keys are separated because of the differing
+cryptographic usage: protocol 1 private RSA keys are used to decrypt
+challenges that were encrypted with the corresponding public key,
+whereas protocol 2 RSA private keys are used to sign challenges with
+a private key for verification with the corresponding public key. It
+is considered unsound practice to use the same key for signing and
+encryption.
+
+With a couple of exceptions, the protocol message names used in this
+document indicate which type of key the message relates to. SSH_*
+messages refer to protocol 1 keys only. SSH2_* messages refer to
+protocol 2 keys. Furthermore, the names also indicate whether the
+message is a request to the agent (*_AGENTC_*) or a reply from the
+agent (*_AGENT_*). Section 3 below contains the mapping of the
+protocol message names to their integer values.
+
+1. Data types
+
+Because of support for legacy SSH protocol 1 keys, OpenSSH's agent
+protocol makes use of some data types not defined in RFC 4251.
+
+1.1 uint16
+
+The "uint16" data type is a simple MSB-first 16 bit unsigned integer
+encoded in two bytes.
+
+1.2 mpint1
+
+The "mpint1" type represents an arbitrary precision integer (bignum).
+Its format is as follows:
+
+       uint16                  bits
+       byte[(bits + 7) / 8]    bignum
+
+"bignum" contains an unsigned arbitrary precision integer encoded as
+eight bits per byte in big-endian (MSB first) format.
+
+Note the difference between the "mpint1" encoding and the "mpint"
+encoding defined in RFC 4251. Also note that the length of the encoded
+integer is specified in bits, not bytes and that the byte length of
+the integer must be calculated by rounding up the number of bits to the
+nearest eight.
+
+2. Protocol Messages
+
+All protocol messages are prefixed with their length in bytes, encoded
+as a 32 bit unsigned integer. Specifically:
+
+       uint32                  message_length
+       byte[message_length]    message
+
+The following message descriptions refer only to the content the
+"message" field.
+
+2.1 Generic server responses
+
+The following generic messages may be sent by the server in response to
+requests from the client. On success the agent may reply either with:
+
+       byte                    SSH_AGENT_SUCCESS
+
+or a request-specific success message.
+
+On failure, the agent may reply with:
+
+       byte                    SSH_AGENT_FAILURE
+
+SSH_AGENT_FAILURE messages are also sent in reply to unknown request
+types.
+
+2.2 Adding keys to the agent
+
+Keys are added to the agent using the SSH_AGENTC_ADD_RSA_IDENTITY and
+SSH2_AGENTC_ADD_IDENTITY requests for protocol 1 and protocol 2 keys
+respectively.
+
+Two variants of these requests are SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+and SSH2_AGENTC_ADD_ID_CONSTRAINED - these add keys with optional
+"constraints" on their usage.
+
+OpenSSH may be built with support for keys hosted on a smartcard
+or other hardware security module. These keys may be added
+to the agent using the SSH_AGENTC_ADD_SMARTCARD_KEY and
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED requests.
+
+2.2.1 Key constraints
+
+The OpenSSH agent supports some basic optional constraints on key usage.
+At present there are two constraints defined.
+
+The first constraint limits the validity duration of a key. It is
+encoded as:
+
+       byte                    SSH_AGENT_CONSTRAIN_LIFETIME
+       uint32                  seconds
+
+Where "seconds" contains the number of seconds that the key shall remain
+valid measured from the moment that the agent receives it. After the
+validity period has expired, OpenSSH's agent will erase these keys from
+memory.
+
+The second constraint requires the agent to seek explicit user
+confirmation before performing private key operations with the loaded
+key. This constraint is encoded as:
+
+       byte                    SSH_AGENT_CONSTRAIN_CONFIRM
+
+Zero or more constraints may be specified when adding a key with one
+of the *_CONSTRAINED requests. Multiple constraints are appended
+consecutively to the end of the request:
+
+       byte                    constraint1_type
+       ....                    constraint1_data
+       byte                    constraint2_type
+       ....                    constraint2_data
+       ....
+       byte                    constraintN_type
+       ....                    constraintN_data
+
+Such a sequence of zero or more constraints will be referred to below
+as "constraint[]". Agents may determine whether there are constraints
+by checking whether additional data exists in the "add key" request
+after the key data itself. OpenSSH will refuse to add a key if it
+contains unknown constraints.
+
+2.2.2 Add protocol 1 key
+
+A client may add a protocol 1 key to an agent with the following
+request:
+
+       byte                    SSH_AGENTC_ADD_RSA_IDENTITY or
+                               SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+       uint32                  ignored
+       mpint1                  rsa_n
+       mpint1                  rsa_e
+       mpint1                  rsa_d
+       mpint1                  rsa_iqmp
+       mpint1                  rsa_q
+       mpint1                  rsa_p
+       string                  key_comment
+       constraint[]            key_constraints
+
+Note that there is some redundancy in the key parameters; a key could be
+fully specified using just rsa_q, rsa_p and rsa_e at the cost of extra
+computation.
+
+"key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_RSA_IDENTITY.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.3 Add protocol 2 key
+
+The OpenSSH agent supports DSA, ECDSA and RSA keys for protocol 2. DSA
+keys may be added using the following request
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-dss"
+       mpint                   dsa_p
+       mpint                   dsa_q
+       mpint                   dsa_g
+       mpint                   dsa_public_key
+       mpint                   dsa_private_key
+       string                  key_comment
+       constraint[]            key_constraints
+
+DSA certificates may be added with:
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-dss-cert-v00@openssh.com"
+       string                  certificate
+       mpint                   dsa_private_key
+       string                  key_comment
+       constraint[]            key_constraints
+
+ECDSA keys may be added using the following request
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ecdsa-sha2-nistp256" |
+                               "ecdsa-sha2-nistp384" |
+                               "ecdsa-sha2-nistp521"
+       string                  ecdsa_curve_name
+       string                  ecdsa_public_key
+       mpint                   ecdsa_private
+       string                  key_comment
+       constraint[]            key_constraints
+
+ECDSA certificates may be added with:
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ecdsa-sha2-nistp256-cert-v01@openssh.com" |
+                               "ecdsa-sha2-nistp384-cert-v01@openssh.com" |
+                               "ecdsa-sha2-nistp521-cert-v01@openssh.com"
+       string                  certificate
+       mpint                   ecdsa_private_key
+       string                  key_comment
+       constraint[]            key_constraints
+
+RSA keys may be added with this request:
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-rsa"
+       mpint                   rsa_n
+       mpint                   rsa_e
+       mpint                   rsa_d
+       mpint                   rsa_iqmp
+       mpint                   rsa_p
+       mpint                   rsa_q
+       string                  key_comment
+       constraint[]            key_constraints
+
+RSA certificates may be added with this request:
+
+       byte                    SSH2_AGENTC_ADD_IDENTITY or
+                               SSH2_AGENTC_ADD_ID_CONSTRAINED
+       string                  "ssh-rsa-cert-v00@openssh.com"
+       string                  certificate
+       mpint                   rsa_d
+       mpint                   rsa_iqmp
+       mpint                   rsa_p
+       mpint                   rsa_q
+       string                  key_comment
+       constraint[]            key_constraints
+
+Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
+order to the protocol 1 add keys message. As with the corresponding
+protocol 1 "add key" request, the private key is overspecified to avoid
+redundant processing.
+
+For DSA, ECDSA and RSA key add requests, "key_constraints" may only be
+present if the request type is SSH2_AGENTC_ADD_ID_CONSTRAINED.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.4 Loading keys from a smartcard
+
+The OpenSSH agent may have optional smartcard support built in to it. If
+so, it supports an operation to load keys from a smartcard. Technically,
+only the public components of the keys are loaded into the agent so
+this operation really arranges for future private key operations to be
+delegated to the smartcard.
+
+       byte                    SSH_AGENTC_ADD_SMARTCARD_KEY or
+                               SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
+       string                  reader_id
+       string                  pin
+       constraint[]            key_constraints
+
+"reader_id" is an identifier to a smartcard reader and "pin"
+is a PIN or passphrase used to unlock the private key(s) on the
+device. "key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED.
+
+This operation may load all SSH keys that are unlocked using the
+"pin" on the specified reader. The type of key loaded (protocol 1
+or protocol 2) will be specified by the smartcard itself, it is not
+client-specified.
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully loaded or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.3 Removing multiple keys
+
+A client may request that an agent delete all protocol 1 keys using the
+following request:
+
+       byte                    SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES
+
+This message requests the deletion of all protocol 2 keys:
+
+       byte                    SSH2_AGENTC_REMOVE_ALL_IDENTITIES
+
+On success, the agent will delete all keys of the requested type and
+reply with a SSH_AGENT_SUCCESS message. If an error occurred, the agent
+will reply with SSH_AGENT_FAILURE.
+
+Note that, to delete all keys (both protocol 1 and 2), a client
+must send both a SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES and a
+SSH2_AGENTC_REMOVE_ALL_IDENTITIES request.
+
+2.4 Removing specific keys
+
+2.4.1 Removing a protocol 1 key
+
+Removal of a protocol 1 key may be requested with the following message:
+
+       byte                    SSH_AGENTC_REMOVE_RSA_IDENTITY
+       uint32                  key_bits
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+
+Note that key_bits is strictly redundant, as it may be inferred by the
+length of rsa_n.
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.2 Removing a protocol 2 key
+
+Protocol 2 keys may be removed with the following request:
+
+       byte                    SSH2_AGENTC_REMOVE_IDENTITY
+       string                  key_blob
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for any of the supported protocol 2 key types.
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.3 Removing keys loaded from a smartcard
+
+A client may request that a server remove one or more smartcard-hosted
+keys using this message:
+
+       byte                    SSH_AGENTC_REMOVE_SMARTCARD_KEY
+       string                  reader_id
+       string                  pin
+
+"reader_id" the an identifier to a smartcard reader and "pin" is a PIN
+or passphrase used to unlock the private key(s) on the device.
+
+When this message is received, and if the agent supports
+smartcard-hosted keys, it will delete all keys that are hosted on the
+specified smartcard that may be accessed with the given "pin".
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully removed or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.5 Requesting a list of known keys
+
+An agent may be requested to list which keys it holds. Different
+requests exist for protocol 1 and protocol 2 keys.
+
+2.5.1 Requesting a list of protocol 1 keys
+
+To request a list of protocol 1 keys that are held in the agent, a
+client may send the following message:
+
+       byte                    SSH_AGENTC_REQUEST_RSA_IDENTITIES
+
+The agent will reply with the following message:
+
+       byte                    SSH_AGENT_RSA_IDENTITIES_ANSWER
+       uint32                  num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+       uint32                  bits
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+       string                  key_comment
+
+2.5.2 Requesting a list of protocol 2 keys
+
+A client may send the following message to request a list of
+protocol 2 keys that are stored in the agent:
+
+       byte                    SSH2_AGENTC_REQUEST_IDENTITIES
+
+The agent will reply with the following message header:
+
+       byte                    SSH2_AGENT_IDENTITIES_ANSWER
+       uint32                  num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+       string                  key_blob
+       string                  key_comment
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for any of the supported protocol 2 key types.
+
+2.6 Private key operations
+
+The purpose of the agent is to perform private key operations, such as
+signing and encryption without requiring a passphrase to unlock the
+key and without allowing the private key itself to be exposed. There
+are separate requests for the protocol 1 and protocol 2 private key
+operations.
+
+2.6.1 Protocol 1 private key challenge
+
+The private key operation used in version 1 of the SSH protocol is
+decrypting a challenge that has been encrypted with a public key.
+It may be requested using this message:
+
+       byte                    SSH_AGENTC_RSA_CHALLENGE
+       uint32                  ignored
+       mpint1                  rsa_e
+       mpint1                  rsa_n
+       mpint1                  encrypted_challenge
+       byte[16]                session_id
+       uint32                  response_type /* must be 1 */
+
+"rsa_e" and "rsa_n" are used to identify which private key to use.
+"encrypted_challenge" is a challenge blob that has (presumably)
+been encrypted with the public key and must be in the range 
+1 <= encrypted_challenge < 2^256. "session_id" is the SSH protocol 1
+session ID (computed from the server host key, the server semi-ephemeral
+key and the session cookie).
+
+"ignored" and "response_type" exist for compatibility with legacy
+implementations. "response_type" must be equal to 1; other response
+types are not supported.
+
+On receiving this request, the server decrypts the "encrypted_challenge"
+using the private key matching the supplied (rsa_e, rsa_n) values. For
+the response derivation, the decrypted challenge is represented as an
+unsigned, big-endian integer encoded in a 32 byte buffer (i.e. values
+smaller than 2^248 will have leading 0 bytes).
+
+The response value is then calculated as:
+
+       response = MD5(decrypted_challenge || session_id)
+
+and returned in the following message
+
+       byte                    SSH_AGENT_RSA_RESPONSE
+       byte[16]                response
+
+If the agent cannot find the key specified by the supplied (rsa_e,
+rsa_n) then it will return SSH_AGENT_FAILURE.
+
+2.6.2 Protocol 2 private key signature request
+
+A client may use the following message to request signing of data using
+a protocol 2 key:
+
+       byte                    SSH2_AGENTC_SIGN_REQUEST
+       string                  key_blob
+       string                  data
+       uint32                  flags
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for any of the supported protocol 2 key types. "flags" is
+a bit-mask, but at present only one possible value is defined (see below
+for its meaning):
+
+       SSH_AGENT_OLD_SIGNATURE         1
+
+Upon receiving this request, the agent will look up the private key that
+corresponds to the public key contained in key_blob. It will use this
+private key to sign the "data" and produce a signature blob using the
+key type-specific method described in RFC 4253 section 6.6 "Public Key
+Algorithms".
+
+An exception to this is for "ssh-dss" keys where the "flags" word
+contains the value SSH_AGENT_OLD_SIGNATURE. In this case, a legacy
+signature encoding is used in lieu of the standard one. In this case,
+the DSA signature blob is encoded as:
+
+       byte[40]                signature
+
+The signature will be returned in the response message:
+
+       byte                    SSH2_AGENT_SIGN_RESPONSE
+       string                  signature_blob
+
+If the agent cannot find the key specified by the supplied key_blob then
+it will return SSH_AGENT_FAILURE.
+
+2.7 Locking or unlocking an agent
+
+The agent supports temporary locking with a passphrase to suspend
+processing of sensitive operations until it has been unlocked with the
+same passphrase. To lock an agent, a client send the following request:
+
+       byte                    SSH_AGENTC_LOCK
+       string                  passphrase
+
+Upon receipt of this message and if the agent is not already locked,
+it will suspend processing requests and return a SSH_AGENT_SUCCESS
+reply. If the agent is already locked, it will return SSH_AGENT_FAILURE.
+
+While locked, the agent will refuse all requests except
+SSH_AGENTC_UNLOCK, SSH_AGENTC_REQUEST_RSA_IDENTITIES and
+SSH2_AGENTC_REQUEST_IDENTITIES. The "request identities" requests are
+treated specially by a locked agent: it will always return an empty list
+of keys.
+
+To unlock an agent, a client may request:
+
+       byte                    SSH_AGENTC_UNLOCK
+       string                  passphrase
+
+If the passphrase matches and the agent is locked, then it will resume
+processing all requests and return SSH_AGENT_SUCCESS. If the agent
+is not locked or the passphrase does not match then it will return
+SSH_AGENT_FAILURE.
+
+Locking and unlocking affects both protocol 1 and protocol 2 keys.
+
+3. Protocol message numbers
+
+3.1 Requests from client to agent for protocol 1 key operations
+
+       SSH_AGENTC_REQUEST_RSA_IDENTITIES               1
+       SSH_AGENTC_RSA_CHALLENGE                        3
+       SSH_AGENTC_ADD_RSA_IDENTITY                     7
+       SSH_AGENTC_REMOVE_RSA_IDENTITY                  8
+       SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES            9
+       SSH_AGENTC_ADD_RSA_ID_CONSTRAINED               24
+
+3.2 Requests from client to agent for protocol 2 key operations
+
+       SSH2_AGENTC_REQUEST_IDENTITIES                  11
+       SSH2_AGENTC_SIGN_REQUEST                        13
+       SSH2_AGENTC_ADD_IDENTITY                        17
+       SSH2_AGENTC_REMOVE_IDENTITY                     18
+       SSH2_AGENTC_REMOVE_ALL_IDENTITIES               19
+       SSH2_AGENTC_ADD_ID_CONSTRAINED                  25
+
+3.3 Key-type independent requests from client to agent
+
+       SSH_AGENTC_ADD_SMARTCARD_KEY                    20
+       SSH_AGENTC_REMOVE_SMARTCARD_KEY                 21
+       SSH_AGENTC_LOCK                                 22
+       SSH_AGENTC_UNLOCK                               23
+       SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED        26
+
+3.4 Generic replies from agent to client
+
+       SSH_AGENT_FAILURE                               5
+       SSH_AGENT_SUCCESS                               6
+
+3.5 Replies from agent to client for protocol 1 key operations
+
+       SSH_AGENT_RSA_IDENTITIES_ANSWER                 2
+       SSH_AGENT_RSA_RESPONSE                          4
+
+3.6 Replies from agent to client for protocol 2 key operations
+
+       SSH2_AGENT_IDENTITIES_ANSWER                    12
+       SSH2_AGENT_SIGN_RESPONSE                        14
+
+3.7 Key constraint identifiers
+
+       SSH_AGENT_CONSTRAIN_LIFETIME                    1
+       SSH_AGENT_CONSTRAIN_CONFIRM                     2
+
+$OpenBSD: PROTOCOL.agent,v 1.6 2010/08/31 11:54:45 djm Exp $
diff --git a/PROTOCOL.certkeys b/PROTOCOL.certkeys
new file mode 100644 (file)
index 0000000..2f97649
--- /dev/null
@@ -0,0 +1,256 @@
+This document describes a simple public-key certificate authentication
+system for use by SSH.
+
+Background
+----------
+
+The SSH protocol currently supports a simple public key authentication
+mechanism. Unlike other public key implementations, SSH eschews the use
+of X.509 certificates and uses raw keys. This approach has some benefits
+relating to simplicity of configuration and minimisation of attack
+surface, but it does not support the important use-cases of centrally
+managed, passwordless authentication and centrally certified host keys.
+
+These protocol extensions build on the simple public key authentication
+system already in SSH to allow certificate-based authentication. The
+certificates used are not traditional X.509 certificates, with numerous
+options and complex encoding rules, but something rather more minimal: a
+key, some identity information and usage options that have been signed
+with some other trusted key.
+
+A sshd server may be configured to allow authentication via certified
+keys, by extending the existing ~/.ssh/authorized_keys mechanism to
+allow specification of certification authority keys in addition to
+raw user keys. The ssh client will support automatic verification of
+acceptance of certified host keys, by adding a similar ability to
+specify CA keys in ~/.ssh/known_hosts.
+
+Certified keys are represented using new key types:
+
+    ssh-rsa-cert-v01@openssh.com
+    ssh-dss-cert-v01@openssh.com
+    ecdsa-sha2-nistp256-cert-v01@openssh.com
+    ecdsa-sha2-nistp384-cert-v01@openssh.com
+    ecdsa-sha2-nistp521-cert-v01@openssh.com
+
+These include certification information along with the public key
+that is used to sign challenges. ssh-keygen performs the CA signing
+operation.
+
+Protocol extensions
+-------------------
+
+The SSH wire protocol includes several extensibility mechanisms.
+These modifications shall take advantage of namespaced public key
+algorithm names to add support for certificate authentication without
+breaking the protocol - implementations that do not support the
+extensions will simply ignore them.
+
+Authentication using the new key formats described below proceeds
+using the existing SSH "publickey" authentication method described
+in RFC4252 section 7.
+
+New public key formats
+----------------------
+
+The certificate key types take a similar high-level format (note: data
+types and encoding are as per RFC4251 section 5). The serialised wire
+encoding of these certificates is also used for storing them on disk.
+
+#define SSH_CERT_TYPE_USER    1
+#define SSH_CERT_TYPE_HOST    2
+
+RSA certificate
+
+    string    "ssh-rsa-cert-v01@openssh.com"
+    string    nonce
+    mpint     e
+    mpint     n
+    uint64    serial
+    uint32    type
+    string    key id
+    string    valid principals
+    uint64    valid after
+    uint64    valid before
+    string    critical options
+    string    extensions
+    string    reserved
+    string    signature key
+    string    signature
+
+DSA certificate
+
+    string    "ssh-dss-cert-v01@openssh.com"
+    string    nonce
+    mpint     p
+    mpint     q
+    mpint     g
+    mpint     y
+    uint64    serial
+    uint32    type
+    string    key id
+    string    valid principals
+    uint64    valid after
+    uint64    valid before
+    string    critical options
+    string    extensions
+    string    reserved
+    string    signature key
+    string    signature
+
+ECDSA certificate
+
+    string    "ecdsa-sha2-nistp256@openssh.com" |
+              "ecdsa-sha2-nistp384@openssh.com" |
+              "ecdsa-sha2-nistp521@openssh.com"
+    string    nonce
+    string    curve
+    string    public_key
+    uint64    serial
+    uint32    type
+    string    key id
+    string    valid principals
+    uint64    valid after
+    uint64    valid before
+    string    critical options
+    string    extensions
+    string    reserved
+    string    signature key
+    string    signature
+
+The nonce field is a CA-provided random bitstring of arbitrary length
+(but typically 16 or 32 bytes) included to make attacks that depend on
+inducing collisions in the signature hash infeasible.
+
+e and n are the RSA exponent and public modulus respectively.
+
+p, q, g, y are the DSA parameters as described in FIPS-186-2.
+
+curve and public key are respectively the ECDSA "[identifier]" and "Q"
+defined in section 3.1 of RFC5656.
+
+serial is an optional certificate serial number set by the CA to
+provide an abbreviated way to refer to certificates from that CA.
+If a CA does not wish to number its certificates it must set this
+field to zero.
+
+type specifies whether this certificate is for identification of a user
+or a host using a SSH_CERT_TYPE_... value.
+
+key id is a free-form text field that is filled in by the CA at the time
+of signing; the intention is that the contents of this field are used to
+identify the identity principal in log messages.
+
+"valid principals" is a string containing zero or more principals as
+strings packed inside it. These principals list the names for which this
+certificate is valid; hostnames for SSH_CERT_TYPE_HOST certificates and
+usernames for SSH_CERT_TYPE_USER certificates. As a special case, a
+zero-length "valid principals" field means the certificate is valid for
+any principal of the specified type. XXX DNS wildcards?
+
+"valid after" and "valid before" specify a validity period for the
+certificate. Each represents a time in seconds since 1970-01-01
+00:00:00. A certificate is considered valid if:
+
+    valid after <= current time < valid before
+
+criticial options is a set of zero or more key options encoded as
+below. All such options are "critical" in the sense that an implementation
+must refuse to authorise a key that has an unrecognised option.
+
+extensions is a set of zero or more optional extensions. These extensions
+are not critical, and an implementation that encounters one that it does
+not recognise may safely ignore it.
+
+The reserved field is currently unused and is ignored in this version of
+the protocol.
+
+signature key contains the CA key used to sign the certificate.
+The valid key types for CA keys are ssh-rsa, ssh-dss and the ECDSA types
+ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained"
+certificates, where the signature key type is a certificate type itself
+are NOT supported. Note that it is possible for a RSA certificate key to
+be signed by a DSS or ECDSA CA key and vice-versa.
+
+signature is computed over all preceding fields from the initial string
+up to, and including the signature key. Signatures are computed and
+encoded according to the rules defined for the CA's public key algorithm
+(RFC4253 section 6.6 for ssh-rsa and ssh-dss, RFC5656 for the ECDSA
+types).
+
+Critical options
+----------------
+
+The critical options section of the certificate specifies zero or more
+options on the certificates validity. The format of this field
+is a sequence of zero or more tuples:
+
+    string       name
+    string       data
+
+Options must be lexically ordered by "name" if they appear in the
+sequence.
+
+The name field identifies the option and the data field encodes
+option-specific information (see below). All options are
+"critical", if an implementation does not recognise a option
+then the validating party should refuse to accept the certificate.
+
+The supported options and the contents and structure of their
+data fields are:
+
+Name                    Format        Description
+-----------------------------------------------------------------------------
+force-command           string        Specifies a command that is executed
+                                      (replacing any the user specified on the
+                                      ssh command-line) whenever this key is
+                                      used for authentication.
+
+source-address          string        Comma-separated list of source addresses
+                                      from which this certificate is accepted
+                                      for authentication. Addresses are
+                                      specified in CIDR format (nn.nn.nn.nn/nn
+                                      or hhhh::hhhh/nn).
+                                      If this option is not present then
+                                      certificates may be presented from any
+                                      source address.
+
+Extensions
+----------
+
+The extensions section of the certificate specifies zero or more
+non-critical certificate extensions. The encoding and ordering of
+extensions in this field is identical to that of the critical options.
+If an implementation does not recognise an extension, then it should
+ignore it.
+
+The supported extensions and the contents and structure of their data
+fields are:
+
+Name                    Format        Description
+-----------------------------------------------------------------------------
+permit-X11-forwarding   empty         Flag indicating that X11 forwarding
+                                      should be permitted. X11 forwarding will
+                                      be refused if this option is absent.
+
+permit-agent-forwarding empty         Flag indicating that agent forwarding
+                                      should be allowed. Agent forwarding
+                                      must not be permitted unless this
+                                      option is present.
+
+permit-port-forwarding  empty         Flag indicating that port-forwarding
+                                      should be allowed. If this option is
+                                      not present then no port forwarding will
+                                      be allowed.
+
+permit-pty              empty         Flag indicating that PTY allocation
+                                      should be permitted. In the absence of
+                                      this option PTY allocation will be
+                                      disabled.
+
+permit-user-rc          empty         Flag indicating that execution of
+                                      ~/.ssh/rc should be permitted. Execution
+                                      of this script will not be permitted if
+                                      this option is not present.
+
+$OpenBSD: PROTOCOL.certkeys,v 1.8 2010/08/31 11:54:45 djm Exp $
diff --git a/PROTOCOL.mux b/PROTOCOL.mux
new file mode 100644 (file)
index 0000000..2a5817b
--- /dev/null
@@ -0,0 +1,203 @@
+This document describes the multiplexing protocol used by ssh(1)'s
+ControlMaster connection-sharing.
+
+Most messages from the client to the server contain a "request id" field.
+This field is returned in replies as "client request id" to facilitate
+matching of responses to requests.
+
+1. Connection setup
+
+When a multiplexing connection is made to a ssh(1) operating as a
+ControlMaster from a ssh(1) in multiplex slave mode, the first
+action of each is to exchange hello messages:
+
+       uint32  MUX_MSG_HELLO
+       uint32  protocol version
+       string  extension name [optional]
+       string  extension value [optional]
+       ...
+
+The current version of the mux protocol is 4. A slave should refuse
+to connect to a master that speaks an unsupported protocol version.
+Following the version identifier are zero or more extensions
+represented as a name/value pair. No extensions are currently
+defined.
+
+2. Opening sessions
+
+To open a new multiplexed session, a client may send the following
+request:
+
+       uint32  MUX_C_NEW_SESSION
+       uint32  request id
+       string  reserved
+       bool    want tty flag
+       bool    want X11 forwarding flag
+       bool    want agent flag
+       bool    subsystem flag
+       uint32  escape char
+       string  terminal type
+       string  command
+       string  environment string 0 [optional]
+       ...
+
+To disable the use of an escape character, "escape char" may be set
+to 0xffffffff. "terminal type" is generally set to the value of
+$TERM. zero or more environment strings may follow the command.
+
+The client then sends its standard input, output and error file
+descriptors (in that order) using Unix domain socket control messages.
+
+The contents of "reserved" are currently ignored.
+
+If successful, the server will reply with MUX_S_SESSION_OPENED
+
+       uint32  MUX_S_SESSION_OPENED
+       uint32  client request id
+       uint32  session id
+
+Otherwise it will reply with an error: MUX_S_PERMISSION_DENIED or
+MUX_S_FAILURE.
+
+Once the server has received the fds, it will respond with MUX_S_OK
+indicating that the session is up. The client now waits for the
+session to end. When it does, the server will send an exit status
+message:
+
+       uint32  MUX_S_EXIT_MESSAGE
+       uint32  session id
+       uint32  exit value
+
+The client should exit with this value to mimic the behaviour of a
+non-multiplexed ssh(1) connection. Two additional cases that the
+client must cope with are it receiving a signal itself and the
+server disconnecting without sending an exit message.
+
+3. Health checks
+
+The client may request a health check/PID report from a server:
+
+       uint32  MUX_C_ALIVE_CHECK
+       uint32  request id
+
+The server replies with:
+
+       uint32  MUX_S_ALIVE
+       uint32  client request id
+       uint32  server pid
+
+4. Remotely terminating a master
+
+A client may request that a master terminate immediately:
+
+       uint32  MUX_C_TERMINATE
+       uint32  request id
+
+The server will reply with one of MUX_S_OK or MUX_S_PERMISSION_DENIED.
+
+5. Requesting establishment of port forwards
+
+A client may request the master to establish a port forward:
+
+       uint32  MUX_C_OPEN_FWD
+       uint32  request id
+       uint32  forwarding type
+       string  listen host
+       string  listen port
+       string  connect host
+       string  connect port
+
+forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC.
+
+A server may reply with a MUX_S_OK, a MUX_S_REMOTE_PORT, a
+MUX_S_PERMISSION_DENIED or a MUX_S_FAILURE.
+
+For dynamically allocated listen port the server replies with
+
+       uint32  MUX_S_REMOTE_PORT
+       uint32  client request id
+       uint32  allocated remote listen port
+
+6. Requesting closure of port forwards
+
+Note: currently unimplemented (server will always reply with MUX_S_FAILURE).
+
+A client may request the master to close a port forward:
+
+       uint32  MUX_C_CLOSE_FWD
+       uint32  request id
+       string  listen host
+       string  listen port
+       string  connect host
+       string  connect port
+
+A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
+MUX_S_FAILURE.
+
+7. Requesting stdio forwarding
+
+A client may request the master to establish a stdio forwarding:
+
+       uint32  MUX_C_NEW_STDIO_FWD
+       uint32  request id
+       string  reserved
+       string  connect host
+       string  connect port
+
+The client then sends its standard input and output file descriptors
+(in that order) using Unix domain socket control messages.
+
+The contents of "reserved" are currently ignored.
+
+A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED
+or a MUX_S_FAILURE.
+
+8. Status messages
+
+The MUX_S_OK message is empty:
+
+       uint32  MUX_S_OK
+       uint32  client request id
+
+The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
+
+       uint32  MUX_S_PERMISSION_DENIED
+       uint32  client request id
+       string  reason
+
+       uint32  MUX_S_FAILURE
+       uint32  client request id
+       string  reason
+
+9. Protocol numbers
+
+#define MUX_MSG_HELLO          0x00000001
+#define MUX_C_NEW_SESSION      0x10000002
+#define MUX_C_ALIVE_CHECK      0x10000004
+#define MUX_C_TERMINATE                0x10000005
+#define MUX_C_OPEN_FWD         0x10000006
+#define MUX_C_CLOSE_FWD                0x10000007
+#define MUX_C_NEW_STDIO_FWD    0x10000008
+#define MUX_S_OK               0x80000001
+#define MUX_S_PERMISSION_DENIED        0x80000002
+#define MUX_S_FAILURE          0x80000003
+#define MUX_S_EXIT_MESSAGE     0x80000004
+#define MUX_S_ALIVE            0x80000005
+#define MUX_S_SESSION_OPENED   0x80000006
+#define MUX_S_REMOTE_PORT      0x80000007
+
+#define MUX_FWD_LOCAL  1
+#define MUX_FWD_REMOTE 2
+#define MUX_FWD_DYNAMIC        3
+
+XXX TODO
+XXX extended status (e.g. report open channels / forwards)
+XXX graceful close (delete listening socket, but keep existing sessions active)
+XXX lock (maybe)
+XXX watch in/out traffic (pre/post crypto)
+XXX inject packet (what about replies)
+XXX server->client error/warning notifications
+XXX port0 rfwd (need custom response message)
+XXX send signals via mux
+
+$OpenBSD: PROTOCOL.mux,v 1.4 2011/01/31 21:42:15 djm Exp $
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..4f69506
--- /dev/null
+++ b/README
@@ -0,0 +1,65 @@
+See http://www.openssh.com/txt/release-5.8 for the release notes.
+
+- A Japanese translation of this document and of the OpenSSH FAQ is
+- available at http://www.unixuser.org/~haruyama/security/openssh/index.html
+- Thanks to HARUYAMA Seigo <haruyama@unixuser.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, 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 AIX, Cygwin, HP-UX, Linux, MacOS/X,
+NetBSD, OpenBSD, OpenServer, Solaris, Unicos, and UnixWare.
+
+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.Code contribution are welcomed, 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.openpam.org
+    http://www.kernel.org/pub/linux/libs/pam/ 
+    (PAM also 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: README,v 1.75.4.1 2011/02/04 00:57:50 djm Exp $
diff --git a/README.dns b/README.dns
new file mode 100644 (file)
index 0000000..9787918
--- /dev/null
@@ -0,0 +1,47 @@
+How to verify host keys using OpenSSH and DNS
+---------------------------------------------
+
+OpenSSH contains support for verifying host keys using DNS as described in
+draft-ietf-secsh-dns-05.txt. The document contains very brief instructions
+on how to use this feature. Configuring DNS is out of the scope of this
+document.
+
+
+(1) Server: Generate and publish the DNS RR
+
+To create a DNS resource record (RR) containing a fingerprint of the
+public host key, use the following command:
+
+       ssh-keygen -r hostname -f keyfile -g
+
+where "hostname" is your fully qualified hostname and "keyfile" is the
+file containing the public host key file. If you have multiple keys,
+you should generate one RR for each key.
+
+In the example above, ssh-keygen will print the fingerprint in a
+generic DNS RR format parsable by most modern name server
+implementations. If your nameserver has support for the SSHFP RR
+you can omit the -g flag and ssh-keygen will print a standard SSHFP RR.
+
+To publish the fingerprint using the DNS you must add the generated RR
+to your DNS zone file and sign your zone.
+
+
+(2) Client: Enable ssh to verify host keys using DNS
+
+To enable the ssh client to verify host keys using DNS, you have to
+add the following option to the ssh configuration file
+($HOME/.ssh/config or /etc/ssh/ssh_config):
+
+    VerifyHostKeyDNS yes
+
+Upon connection the client will try to look up the fingerprint RR
+using DNS. If the fingerprint received from the DNS server matches
+the remote host key, the user will be notified.
+
+
+       Jakob Schlyter
+       Wesley Griffin
+
+
+$OpenBSD: README.dns,v 1.2 2003/10/14 19:43:23 jakob Exp $
diff --git a/README.platform b/README.platform
new file mode 100644 (file)
index 0000000..d198232
--- /dev/null
@@ -0,0 +1,96 @@
+This file contains notes about OpenSSH on specific platforms.
+
+AIX
+---
+As of OpenSSH 3.8p1, sshd will now honour an accounts password expiry
+settings, where previously it did not.  Because of this, it's possible for
+sites that have used OpenSSH's sshd exclusively to have accounts which
+have passwords expired longer than the inactive time (ie the "Weeks between
+password EXPIRATION and LOCKOUT" setting in SMIT or the maxexpired
+chuser attribute).
+
+Accounts in this state must have their passwords reset manually by the
+administrator.  As a precaution, it is recommended that the administrative
+passwords be reset before upgrading from OpenSSH <3.8.
+
+As of OpenSSH 4.0, configure will attempt to detect if your version
+and maintenance level of AIX has a working getaddrinfo, and will use it
+if found.  This will enable IPv6 support.  If for some reason configure
+gets it wrong, or if you want to build binaries to work on earlier MLs
+than the build host then you can add "-DBROKEN_GETADDRINFO" to CFLAGS
+to force the previous IPv4-only behaviour.
+
+IPv6 known to work: 5.1ML7 5.2ML2 5.2ML5
+IPv6 known broken: 4.3.3ML11 5.1ML4
+
+If you wish to use dynamic libraries that aren't in the normal system
+locations (eg IBM's OpenSSL and zlib packages) then you will need to
+define the environment variable blibpath before running configure, eg
+
+blibpath=/lib:/usr/lib:/opt/freeware/lib ./configure \
+  --with-ssl-dir=/opt/freeware --with-zlib=/opt/freeware
+
+If sshd is built with the WITH_AIXAUTHENTICATE option (which is enabled
+by default) then sshd checks that users are permitted via the
+loginrestrictions() function, in particular that the user has the
+"rlogin" attribute set.  This check is not done for the root account,
+instead the PermitRootLogin setting in sshd_config is used.
+
+
+Cygwin
+------
+To build on Cygwin, OpenSSH requires the following packages:
+gcc, gcc-mingw-core, mingw-runtime, binutils, make, openssl,
+openssl-devel, zlib, minres, minires-devel.
+
+
+Darwin and MacOS X
+------------------
+Darwin does not provide a tun(4) driver required for OpenSSH-based
+virtual private networks. The BSD manpage still exists, but the driver
+has been removed in recent releases of Darwin and MacOS X.
+
+Nevertheless, tunnel support is known to work with Darwin 8 and
+MacOS X 10.4 in Point-to-Point (Layer 3) and Ethernet (Layer 2) mode
+using a third party driver. More information is available at:
+       http://www-user.rhrk.uni-kl.de/~nissler/tuntap/
+
+
+Linux
+-----
+
+Some Linux distributions (including Red Hat/Fedora/CentOS) include
+headers and library links in the -devel RPMs rather than the main
+binary RPMs. If you get an error about headers, or complaining about a
+missing prerequisite then you may need to install the equivalent
+development packages.  On Redhat based distros these may be openssl-devel,
+zlib-devel and pam-devel, on Debian based distros these may be
+libssl-dev, libz-dev and libpam-dev.
+
+
+Solaris
+-------
+If you enable BSM auditing on Solaris, you need to update audit_event(4)
+for praudit(1m) to give sensible output.  The following line needs to be
+added to /etc/security/audit_event:
+
+       32800:AUE_openssh:OpenSSH login:lo
+
+The BSM audit event range available for third party TCB applications is
+32768 - 65535.  Event number 32800 has been choosen for AUE_openssh.
+There is no official registry of 3rd party event numbers, so if this
+number is already in use on your system, you may change it at build time
+by configure'ing --with-cflags=-DAUE_openssh=32801 then rebuilding.
+
+
+Platforms using PAM
+-------------------
+As of OpenSSH 4.3p1, sshd will no longer check /etc/nologin itself when
+PAM is enabled.  To maintain existing behaviour, pam_nologin should be
+added to sshd's session stack which will prevent users from starting shell
+sessions.  Alternatively, pam_nologin can be added to either the auth or
+account stacks which will prevent authentication entirely, but will still
+return the output from pam_nologin to the client.
+
+
+$Id: README.platform,v 1.10 2009/08/28 23:14:48 dtucker Exp $
diff --git a/README.privsep b/README.privsep
new file mode 100644 (file)
index 0000000..f565e72
--- /dev/null
@@ -0,0 +1,63 @@
+Privilege separation, or privsep, is method in OpenSSH by which
+operations that require root privilege are performed by a separate
+privileged monitor process.  Its purpose is to prevent privilege
+escalation by containing corruption to an unprivileged process.
+More information is available at:
+       http://www.citi.umich.edu/u/provos/ssh/privsep.html
+
+Privilege separation is now enabled by default; see the
+UsePrivilegeSeparation option in sshd_config(5).
+
+On systems which lack mmap or anonymous (MAP_ANON) memory mapping,
+compression must be disabled in order for privilege separation to
+function.
+
+When privsep is enabled, during the pre-authentication phase sshd will
+chroot(2) to "/var/empty" and change its privileges to the "sshd" user
+and its primary group.  sshd is a pseudo-account that should not be
+used by other daemons, and must be locked and should contain a
+"nologin" or invalid shell.
+
+You should do something like the following to prepare the privsep
+preauth environment:
+
+       # mkdir /var/empty
+       # chown root:sys /var/empty
+       # chmod 755 /var/empty
+       # groupadd sshd
+       # useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd
+
+/var/empty should not contain any files.
+
+configure supports the following options to change the default
+privsep user and chroot directory:
+
+  --with-privsep-path=xxx Path for privilege separation chroot
+  --with-privsep-user=user Specify non-privileged user for privilege separation
+
+Privsep requires operating system support for file descriptor passing.
+Compression will be disabled on systems without a working mmap MAP_ANON.
+
+PAM-enabled OpenSSH is known to function with privsep on AIX, FreeBSD, 
+HP-UX (including Trusted Mode), Linux, NetBSD and Solaris.
+
+On Cygwin, Tru64 Unix, OpenServer, and Unicos only the pre-authentication
+part of privsep is supported.  Post-authentication privsep is disabled
+automatically (so you won't see the additional process mentioned below).
+
+Note that for a normal interactive login with a shell, enabling privsep
+will require 1 additional process per login session.
+
+Given the following process listing (from HP-UX):
+
+     UID   PID  PPID  C    STIME TTY       TIME COMMAND
+    root  1005     1  0 10:45:17 ?         0:08 /opt/openssh/sbin/sshd -u0
+    root  6917  1005  0 15:19:16 ?         0:00 sshd: stevesk [priv]
+ stevesk  6919  6917  0 15:19:17 ?         0:03 sshd: stevesk@2
+ stevesk  6921  6919  0 15:19:17 pts/2     0:00 -bash
+
+process 1005 is the sshd process listening for new connections.
+process 6917 is the privileged monitor process, 6919 is the user owned
+sshd process and 6921 is the shell process.
+
+$Id: README.privsep,v 1.16 2005/06/04 23:21:41 djm Exp $
diff --git a/README.tun b/README.tun
new file mode 100644 (file)
index 0000000..5e1cb07
--- /dev/null
@@ -0,0 +1,132 @@
+How to use OpenSSH-based virtual private networks
+-------------------------------------------------
+
+OpenSSH contains support for VPN tunneling using the tun(4) network
+tunnel pseudo-device which is available on most platforms, either for
+layer 2 or 3 traffic.
+
+The following brief instructions on how to use this feature use
+a network configuration specific to the OpenBSD operating system.
+
+(1) Server: Enable support for SSH tunneling
+
+To enable the ssh server to accept tunnel requests from the client, you
+have to add the following option to the ssh server configuration file
+(/etc/ssh/sshd_config):
+
+       PermitTunnel yes
+
+Restart the server or send the hangup signal (SIGHUP) to let the server
+reread it's configuration.
+
+(2) Server: Restrict client access and assign the tunnel
+
+The OpenSSH server simply uses the file /root/.ssh/authorized_keys to
+restrict the client to connect to a specified tunnel and to
+automatically start the related interface configuration command. These
+settings are optional but recommended:
+
+       tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... reyk@openbsd.org
+
+(3) Client: Configure the local network tunnel interface
+
+Use the hostname.if(5) interface-specific configuration file to set up
+the network tunnel configuration with OpenBSD. For example, use the
+following configuration in /etc/hostname.tun0 to set up the layer 3
+tunnel on the client:
+
+       inet 192.168.5.1 255.255.255.252 192.168.5.2
+
+OpenBSD also supports layer 2 tunneling over the tun device by adding
+the link0 flag:
+
+       inet 192.168.1.78 255.255.255.0 192.168.1.255 link0
+
+Layer 2 tunnels can be used in combination with an Ethernet bridge(4)
+interface, like the following example for /etc/bridgename.bridge0:
+
+       add tun0
+       add sis0
+       up
+
+(4) Client: Configure the OpenSSH client
+
+To establish tunnel forwarding for connections to a specified
+remote host by default, use the following ssh client configuration for
+the privileged user (in /root/.ssh/config):
+
+       Host sshgateway
+               Tunnel yes
+               TunnelDevice 0:any
+               PermitLocalCommand yes
+               LocalCommand sh /etc/netstart tun0
+
+A more complicated configuration is possible to establish a tunnel to
+a remote host which is not directly accessible by the client.
+The following example describes a client configuration to connect to
+the remote host over two ssh hops in between. It uses the OpenSSH
+ProxyCommand in combination with the nc(1) program to forward the final
+ssh tunnel destination over multiple ssh sessions.
+
+       Host access.somewhere.net
+               User puffy
+       Host dmzgw
+               User puffy
+               ProxyCommand ssh access.somewhere.net nc dmzgw 22
+       Host sshgateway
+               Tunnel Ethernet
+               TunnelDevice 0:any
+               PermitLocalCommand yes
+               LocalCommand sh /etc/netstart tun0
+               ProxyCommand ssh dmzgw nc sshgateway 22
+
+The following network plan illustrates the previous configuration in
+combination with layer 2 tunneling and Ethernet bridging.
+
++--------+       (          )      +----------------------+
+| Client |------(  Internet  )-----| access.somewhere.net |
++--------+       (          )      +----------------------+
+    : 192.168.1.78                             |
+    :.............................         +-------+
+     Forwarded ssh connection    :         | dmzgw |
+     Layer 2 tunnel              :         +-------+
+                                 :             |
+                                 :             |
+                                 :      +------------+
+                                 :......| sshgateway |
+                                      | +------------+
+--- real connection                 Bridge ->  |          +----------+
+... "virtual connection"                     [ X ]--------| somehost |
+[X] switch                                                +----------+
+                                                          192.168.1.25
+
+(5) Client: Connect to the server and establish the tunnel
+
+Finally connect to the OpenSSH server to establish the tunnel by using
+the following command:
+
+       ssh sshgateway
+
+It is also possible to tell the client to fork into the background after
+the connection has been successfully established:
+
+       ssh -f sshgateway true
+
+Without the ssh configuration done in step (4), it is also possible
+to use the following command lines:
+
+       ssh -fw 0:1 sshgateway true
+       ifconfig tun0 192.168.5.1 192.168.5.2 netmask 255.255.255.252
+
+Using OpenSSH tunnel forwarding is a simple way to establish secure
+and ad hoc virtual private networks. Possible fields of application
+could be wireless networks or administrative VPN tunnels.
+
+Nevertheless, ssh tunneling requires some packet header overhead and
+runs on top of TCP. It is still suggested to use the IP Security
+Protocol (IPSec) for robust and permanent VPN connections and to
+interconnect corporate networks.
+
+       Reyk Floeter
+
+$OpenBSD: README.tun,v 1.4 2006/03/28 00:12:31 deraadt Exp $
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..e8aaa4b
--- /dev/null
+++ b/TODO
@@ -0,0 +1,86 @@
+Documentation:
+
+- Update the docs
+  - Update README
+  - Update INSTALL
+  - Merge INSTALL & README.privsep
+
+- 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?
+
+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".
+
+- More platforms for for setproctitle() emulation (testing needed)
+
+- Improve PAM ChallengeResponseAuthentication
+ - 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)
+
+- 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)
+
+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
+
+- Replace the whole u_intXX_t evilness in acconfig.h with something better???
+ - Do it in configure.ac
+
+- Consider splitting the u_intXX_t test for sys/bitype.h  into seperate test
+  to allow people to (right/wrongfully) link against Bind directly.
+
+- Consider splitting configure.ac into seperate files which do logically
+  similar tests. E.g move all the type detection stuff into one file,
+  entropy related stuff into another.
+
+Packaging:
+- HP-UX: Provide DEPOT package scripts.
+  (gilbert.r.loomis@saic.com)
+
+PrivSep Issues:
+- mmap() issues.
+  + /dev/zero solution (Solaris)
+  + No/broken MAP_ANON (Irix)
+  + broken /dev/zero parse (Linux)
+- PAM
+  + See above PAM notes
+- AIX
+  + usrinfo() does not set TTY, but only required for legacy systems.  Works
+    with PrivSep.
+- OSF
+  + SIA is broken
+- Cygwin
+  + Privsep for Pre-auth only (no fd passing)
+
+$Id: TODO,v 1.58 2004/12/06 11:40:11 dtucker Exp $
diff --git a/WARNING.RNG b/WARNING.RNG
new file mode 100644 (file)
index 0000000..97da74f
--- /dev/null
@@ -0,0 +1,95 @@
+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 (as of 3.1 and beyond) comes as an external application
+that allows the local admin to decide on how to implement entropy
+collection.
+
+The default entropy 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 default 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.
+
+Tuning the random helper can be done by running ./ssh-random-helper in
+very verbose mode ("-vvv") and identifying the commands that are taking
+excessive amounts of time or hanging altogher.  Any problem commands can
+be modified or removed from ssh_prng_cmds.
+
+The default 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).
+
+
+How to avoid the default entropy code?
+
+The best way is to read the OpenSSL documentation and recompile OpenSSL
+to use prngd or egd.  Some platforms (like earily solaris) have 3rd
+party /dev/random devices that can be also used for this task.
+
+If you are forced to use ssh-rand-helper consider still downloading
+prngd/egd and configure OpenSSH using --with-prngd-port=xx or
+--with-prngd-socket=xx (refer to INSTALL for more information).
+
+$Id: WARNING.RNG,v 1.8 2005/05/26 01:47:54 djm Exp $
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644 (file)
index 0000000..b68a470
--- /dev/null
@@ -0,0 +1,86 @@
+dnl $Id: aclocal.m4,v 1.6 2005/09/19 16:33:39 tim Exp $
+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, 1, [Define if you have $1 in $2])
+               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/acss.c b/acss.c
new file mode 100644 (file)
index 0000000..86e2c01
--- /dev/null
+++ b/acss.c
@@ -0,0 +1,267 @@
+/*     $Id: acss.c,v 1.4 2006/07/24 04:51:01 djm Exp $ */
+/*
+ * Copyright (c) 2004 The OpenBSD project
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#if !defined(EVP_CTRL_SET_ACSS_MODE) && (OPENSSL_VERSION_NUMBER >= 0x00906000L)
+
+#include "acss.h"
+
+/* decryption sbox */
+static unsigned char sboxdec[] = {
+       0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76,
+       0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b,
+       0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96,
+       0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b,
+       0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12,
+       0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f,
+       0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90,
+       0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91,
+       0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74,
+       0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75,
+       0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94,
+       0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95,
+       0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10,
+       0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11,
+       0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92,
+       0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f,
+       0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16,
+       0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b,
+       0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6,
+       0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb,
+       0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72,
+       0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f,
+       0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0,
+       0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1,
+       0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14,
+       0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15,
+       0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4,
+       0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5,
+       0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70,
+       0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71,
+       0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2,
+       0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff
+};
+
+/* encryption sbox */
+static unsigned char sboxenc[] = {
+       0x33, 0x3b, 0x73, 0x15, 0x53, 0x5b, 0x13, 0x75,
+       0x3d, 0x35, 0x7d, 0x1b, 0x5d, 0x55, 0x1d, 0x7b,
+       0x67, 0x6f, 0x27, 0x81, 0xc7, 0xcf, 0x87, 0x21,
+       0x69, 0x61, 0x29, 0x8f, 0xc9, 0xc1, 0x89, 0x2f,
+       0xe3, 0xeb, 0xa3, 0x05, 0x43, 0x4b, 0x03, 0xa5,
+       0xed, 0xe5, 0xad, 0x0b, 0x4d, 0x45, 0x0d, 0xab,
+       0xea, 0xe2, 0xaa, 0x00, 0x4a, 0x42, 0x0a, 0xa0,
+       0xe8, 0xe0, 0xa8, 0x02, 0x48, 0x40, 0x08, 0xa2,
+       0x3e, 0x36, 0x7e, 0x14, 0x5e, 0x56, 0x1e, 0x74,
+       0x3c, 0x34, 0x7c, 0x16, 0x5c, 0x54, 0x1c, 0x76,
+       0x6a, 0x62, 0x2a, 0x80, 0xca, 0xc2, 0x8a, 0x20,
+       0x68, 0x60, 0x28, 0x82, 0xc8, 0xc0, 0x88, 0x22,
+       0xee, 0xe6, 0xae, 0x04, 0x4e, 0x46, 0x0e, 0xa4,
+       0xec, 0xe4, 0xac, 0x06, 0x4c, 0x44, 0x0c, 0xa6,
+       0xe7, 0xef, 0xa7, 0x01, 0x47, 0x4f, 0x07, 0xa1,
+       0xe9, 0xe1, 0xa9, 0x0f, 0x49, 0x41, 0x09, 0xaf,
+       0x63, 0x6b, 0x23, 0x85, 0xc3, 0xcb, 0x83, 0x25,
+       0x6d, 0x65, 0x2d, 0x8b, 0xcd, 0xc5, 0x8d, 0x2b,
+       0x37, 0x3f, 0x77, 0x11, 0x57, 0x5f, 0x17, 0x71,
+       0x39, 0x31, 0x79, 0x1f, 0x59, 0x51, 0x19, 0x7f,
+       0xb3, 0xbb, 0xf3, 0x95, 0xd3, 0xdb, 0x93, 0xf5,
+       0xbd, 0xb5, 0xfd, 0x9b, 0xdd, 0xd5, 0x9d, 0xfb,
+       0xba, 0xb2, 0xfa, 0x90, 0xda, 0xd2, 0x9a, 0xf0,
+       0xb8, 0xb0, 0xf8, 0x92, 0xd8, 0xd0, 0x98, 0xf2,
+       0x6e, 0x66, 0x2e, 0x84, 0xce, 0xc6, 0x8e, 0x24,
+       0x6c, 0x64, 0x2c, 0x86, 0xcc, 0xc4, 0x8c, 0x26,
+       0x3a, 0x32, 0x7a, 0x10, 0x5a, 0x52, 0x1a, 0x70,
+       0x38, 0x30, 0x78, 0x12, 0x58, 0x50, 0x18, 0x72,
+       0xbe, 0xb6, 0xfe, 0x94, 0xde, 0xd6, 0x9e, 0xf4,
+       0xbc, 0xb4, 0xfc, 0x96, 0xdc, 0xd4, 0x9c, 0xf6,
+       0xb7, 0xbf, 0xf7, 0x91, 0xd7, 0xdf, 0x97, 0xf1,
+       0xb9, 0xb1, 0xf9, 0x9f, 0xd9, 0xd1, 0x99, 0xff
+};
+
+static unsigned char reverse[] = {
+       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+       0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+       0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+       0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+       0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+       0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+       0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+       0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+       0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+       0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+       0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+       0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+       0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+       0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+       0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+       0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+       0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+       0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+       0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+       0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+       0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+       0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+       0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+       0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+       0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+       0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+       0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+       0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+       0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+       0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+/*
+ * Two linear feedback shift registers are used:
+ *
+ * lfsr17:  polynomial of degree 17, primitive modulo 2 (listed in Schneier)
+ *          x^15 + x + 1
+ * lfsr25:  polynomial of degree 25, not know if primitive modulo 2
+ *          x^13 + x^5 + x^4 + x^1 + 1
+ *
+ * Output bits are discarded, instead the feedback bits are added to produce
+ * the cipher stream.  Depending on the mode, feedback bytes may be inverted
+ * bit-wise before addition.
+ *
+ * The lfsrs are seeded with bytes from the raw key:
+ *
+ * lfsr17:  byte 0[0:7] at bit 9
+ *          byte 1[0:7] at bit 0
+ *
+ * lfsr25:  byte 2[0:4] at bit 16
+ *          byte 2[5:7] at bit 22
+ *          byte 3[0:7] at bit 8
+ *          byte 4[0:7] at bit 0
+ *
+ * To prevent 0 cycles, 1's are inject at bit 8 in lfrs17 and bit 21 in
+ * lfsr25.
+ *
+ */
+
+int
+acss(ACSS_KEY *key, unsigned long len, const unsigned char *in,
+    unsigned char *out)
+{
+       unsigned long i;
+       unsigned long lfsr17tmp, lfsr25tmp, lfsrsumtmp;
+
+       lfsrsumtmp = lfsr17tmp = lfsr25tmp = 0;
+
+       /* keystream is sum of lfsrs */
+       for (i = 0; i < len; i++) {
+               lfsr17tmp = key->lfsr17 ^ (key->lfsr17 >> 14);
+               key->lfsr17 = (key->lfsr17 >> 8)
+                       ^ (lfsr17tmp << 9)
+                       ^ (lfsr17tmp << 12)
+                       ^ (lfsr17tmp << 15);
+               key->lfsr17 &= 0x1ffff; /* 17 bit LFSR */
+
+               lfsr25tmp = key->lfsr25
+                       ^ (key->lfsr25 >> 3)
+                       ^ (key->lfsr25 >> 4)
+                       ^ (key->lfsr25 >> 12);
+               key->lfsr25 = (key->lfsr25 >> 8) ^ (lfsr25tmp << 17);
+               key->lfsr25 &= 0x1ffffff;       /* 25 bit LFSR */
+
+               lfsrsumtmp = key->lfsrsum;
+
+               /* addition */
+               switch (key->mode) {
+               case ACSS_AUTHENTICATE:
+               case ACSS_DATA:
+                       key->lfsrsum = 0xff & ~(key->lfsr17 >> 9);
+                       key->lfsrsum += key->lfsr25 >> 17;
+                       break;
+               case ACSS_SESSIONKEY:
+                       key->lfsrsum = key->lfsr17 >> 9;
+                       key->lfsrsum += key->lfsr25 >> 17;
+                       break;
+               case ACSS_TITLEKEY:
+                       key->lfsrsum = key->lfsr17 >> 9;
+                       key->lfsrsum += 0xff & ~(key->lfsr25 >> 17);
+                       break;
+               default:
+                       return 1;
+               }
+               key->lfsrsum += (lfsrsumtmp >> 8);
+
+               if (key->encrypt) {
+                       out[i] = sboxenc[(in[i] ^ key->lfsrsum) & 0xff];
+               } else {
+                       out[i] = (sboxdec[in[i]] ^ key->lfsrsum) & 0xff;
+               }
+       }
+
+       return 0;
+}
+
+static void
+acss_seed(ACSS_KEY *key)
+{
+       int i;
+
+       /* if available, mangle with subkey */
+       if (key->subkey_avilable) {
+               for (i = 0; i < ACSS_KEYSIZE; i++)
+                       key->seed[i] = reverse[key->data[i] ^ key->subkey[i]];
+       } else {
+               for (i = 0; i < ACSS_KEYSIZE; i++)
+                       key->seed[i] = reverse[key->data[i]];
+       }
+
+       /* seed lfsrs */
+       key->lfsr17 = key->seed[1]
+               | (key->seed[0] << 9)
+               | (1 << 8);     /* inject 1 at bit 9 */
+       key->lfsr25 = key->seed[4]
+               | (key->seed[3] << 8)
+               | ((key->seed[2] & 0x1f) << 16)
+               | ((key->seed[2] & 0xe0) << 17)
+                       | (1 << 21);    /* inject 1 at bit 22 */
+
+       key->lfsrsum = 0;
+}
+
+void
+acss_setkey(ACSS_KEY *key, const unsigned char *data, int enc, int mode)
+{
+       memcpy(key->data, data, sizeof(key->data));
+       memset(key->subkey, 0, sizeof(key->subkey));
+
+       if (enc != -1)
+               key->encrypt = enc;
+       key->mode = mode;
+       key->subkey_avilable = 0;
+
+       acss_seed(key);
+}
+
+void
+acss_setsubkey(ACSS_KEY *key, const unsigned char *subkey)
+{
+       memcpy(key->subkey, subkey, sizeof(key->subkey));
+       key->subkey_avilable = 1;
+       acss_seed(key);
+}
+#endif
diff --git a/acss.h b/acss.h
new file mode 100644 (file)
index 0000000..91b4895
--- /dev/null
+++ b/acss.h
@@ -0,0 +1,47 @@
+/*     $Id: acss.h,v 1.2 2004/02/06 04:22:43 dtucker Exp $ */
+/*
+ * Copyright (c) 2004 The OpenBSD project
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ACSS_H_
+#define _ACSS_H_
+
+/* 40bit key */
+#define ACSS_KEYSIZE           5
+
+/* modes of acss */
+#define ACSS_AUTHENTICATE      0
+#define ACSS_SESSIONKEY                1
+#define ACSS_TITLEKEY          2
+#define ACSS_DATA              3
+
+typedef struct acss_key_st {
+       unsigned int    lfsr17;         /* current state of lfsrs */
+       unsigned int    lfsr25;
+       unsigned int    lfsrsum;
+       unsigned char   seed[ACSS_KEYSIZE];
+       unsigned char   data[ACSS_KEYSIZE];
+       unsigned char   subkey[ACSS_KEYSIZE];
+       int             encrypt;        /* XXX make these bit flags? */
+       int             mode;
+       int             seeded;
+       int             subkey_avilable;
+} ACSS_KEY;
+
+void acss_setkey(ACSS_KEY *, const unsigned char *, int, int);
+void acss_setsubkey(ACSS_KEY *, const unsigned char *);
+int acss(ACSS_KEY *, unsigned long, const unsigned char *, unsigned char *);
+
+#endif /* ifndef _ACSS_H_ */
diff --git a/addrmatch.c b/addrmatch.c
new file mode 100644 (file)
index 0000000..5b6773c
--- /dev/null
@@ -0,0 +1,500 @@
+/*     $OpenBSD: addrmatch.c,v 1.5 2010/02/26 20:29:54 djm Exp $ */
+
+/*
+ * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "match.h"
+#include "log.h"
+#include "xmalloc.h"
+
+struct xaddr {
+       sa_family_t     af;
+       union {
+               struct in_addr          v4;
+               struct in6_addr         v6;
+               u_int8_t                addr8[16];
+               u_int32_t               addr32[4];
+       } xa;               /* 128-bit address */
+       u_int32_t       scope_id;       /* iface scope id for v6 */
+#define v4     xa.v4
+#define v6     xa.v6
+#define addr8  xa.addr8
+#define addr32 xa.addr32
+};
+
+static int
+addr_unicast_masklen(int af)
+{
+       switch (af) {
+       case AF_INET:
+               return 32;
+       case AF_INET6:
+               return 128;
+       default:
+               return -1;
+       }
+}
+
+static inline int
+masklen_valid(int af, u_int masklen)
+{
+       switch (af) {
+       case AF_INET:
+               return masklen <= 32 ? 0 : -1;
+       case AF_INET6:
+               return masklen <= 128 ? 0 : -1;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Convert struct sockaddr to struct xaddr
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_sa_to_xaddr(struct sockaddr *sa, socklen_t slen, struct xaddr *xa)
+{
+       struct sockaddr_in *in4 = (struct sockaddr_in *)sa;
+       struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
+
+       memset(xa, '\0', sizeof(*xa));
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               if (slen < sizeof(*in4))
+                       return -1;
+               xa->af = AF_INET;
+               memcpy(&xa->v4, &in4->sin_addr, sizeof(xa->v4));
+               break;
+       case AF_INET6:
+               if (slen < sizeof(*in6))
+                       return -1;
+               xa->af = AF_INET6;
+               memcpy(&xa->v6, &in6->sin6_addr, sizeof(xa->v6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+               xa->scope_id = in6->sin6_scope_id;
+#endif
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_netmask(int af, u_int l, struct xaddr *n)
+{
+       int i;
+
+       if (masklen_valid(af, l) != 0 || n == NULL)
+               return -1;
+
+       memset(n, '\0', sizeof(*n));
+       switch (af) {
+       case AF_INET:
+               n->af = AF_INET;
+               if (l == 0)
+                       return 0;
+               n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff);
+               return 0;
+       case AF_INET6:
+               n->af = AF_INET6;
+               for (i = 0; i < 4 && l >= 32; i++, l -= 32)
+                       n->addr32[i] = 0xffffffffU;
+               if (i < 4 && l != 0)
+                       n->addr32[i] = htonl((0xffffffff << (32 - l)) &
+                           0xffffffff);
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Perform logical AND of addresses 'a' and 'b', storing result in 'dst'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_and(struct xaddr *dst, const struct xaddr *a, const struct xaddr *b)
+{
+       int i;
+
+       if (dst == NULL || a == NULL || b == NULL || a->af != b->af)
+               return -1;
+
+       memcpy(dst, a, sizeof(*dst));
+       switch (a->af) {
+       case AF_INET:
+               dst->v4.s_addr &= b->v4.s_addr;
+               return 0;
+       case AF_INET6:
+               dst->scope_id = a->scope_id;
+               for (i = 0; i < 4; i++)
+                       dst->addr32[i] &= b->addr32[i];
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Compare addresses 'a' and 'b'
+ * Return 0 if addresses are identical, -1 if (a < b) or 1 if (a > b)
+ */
+static int
+addr_cmp(const struct xaddr *a, const struct xaddr *b)
+{
+       int i;
+
+       if (a->af != b->af)
+               return a->af == AF_INET6 ? 1 : -1;
+
+       switch (a->af) {
+       case AF_INET:
+               if (a->v4.s_addr == b->v4.s_addr)
+                       return 0;
+               return ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr) ? 1 : -1;
+       case AF_INET6:
+               for (i = 0; i < 16; i++)
+                       if (a->addr8[i] - b->addr8[i] != 0)
+                               return a->addr8[i] > b->addr8[i] ? 1 : -1;
+               if (a->scope_id == b->scope_id)
+                       return 0;
+               return a->scope_id > b->scope_id ? 1 : -1;
+       default:
+               return -1;
+       }
+}
+
+/*
+ * Parse string address 'p' into 'n'
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_pton(const char *p, struct xaddr *n)
+{
+       struct addrinfo hints, *ai;
+
+       memset(&hints, '\0', sizeof(hints));
+       hints.ai_flags = AI_NUMERICHOST;
+
+       if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
+               return -1;
+
+       if (ai == NULL || ai->ai_addr == NULL)
+               return -1;
+
+       if (n != NULL &&
+           addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
+               freeaddrinfo(ai);
+               return -1;
+       }
+
+       freeaddrinfo(ai);
+       return 0;
+}
+
+/*
+ * Perform bitwise negation of address
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_invert(struct xaddr *n)
+{
+       int i;
+
+       if (n == NULL)
+               return (-1);
+
+       switch (n->af) {
+       case AF_INET:
+               n->v4.s_addr = ~n->v4.s_addr;
+               return (0);
+       case AF_INET6:
+               for (i = 0; i < 4; i++)
+                       n->addr32[i] = ~n->addr32[i];
+               return (0);
+       default:
+               return (-1);
+       }
+}
+
+/*
+ * Calculate a netmask of length 'l' for address family 'af' and
+ * store it in 'n'.
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+addr_hostmask(int af, u_int l, struct xaddr *n)
+{
+       if (addr_netmask(af, l, n) == -1 || addr_invert(n) == -1)
+               return (-1);
+       return (0);
+}
+
+/*
+ * Test whether address 'a' is all zeros (i.e. 0.0.0.0 or ::)
+ * Returns 0 on if address is all-zeros, -1 if not all zeros or on failure.
+ */
+static int
+addr_is_all0s(const struct xaddr *a)
+{
+       int i;
+
+       switch (a->af) {
+       case AF_INET:
+               return (a->v4.s_addr == 0 ? 0 : -1);
+       case AF_INET6:;
+               for (i = 0; i < 4; i++)
+                       if (a->addr32[i] != 0)
+                               return (-1);
+               return (0);
+       default:
+               return (-1);
+       }
+}
+
+/*
+ * Test whether host portion of address 'a', as determined by 'masklen'
+ * is all zeros.
+ * Returns 0 on if host portion of address is all-zeros,
+ * -1 if not all zeros or on failure.
+ */
+static int
+addr_host_is_all0s(const struct xaddr *a, u_int masklen)
+{
+       struct xaddr tmp_addr, tmp_mask, tmp_result;
+
+       memcpy(&tmp_addr, a, sizeof(tmp_addr));
+       if (addr_hostmask(a->af, masklen, &tmp_mask) == -1)
+               return (-1);
+       if (addr_and(&tmp_result, &tmp_addr, &tmp_mask) == -1)
+               return (-1);
+       return (addr_is_all0s(&tmp_result));
+}
+
+/*
+ * Parse a CIDR address (x.x.x.x/y or xxxx:yyyy::/z).
+ * Return -1 on parse error, -2 on inconsistency or 0 on success.
+ */
+static int
+addr_pton_cidr(const char *p, struct xaddr *n, u_int *l)
+{
+       struct xaddr tmp;
+       long unsigned int masklen = 999;
+       char addrbuf[64], *mp, *cp;
+
+       /* Don't modify argument */
+       if (p == NULL || strlcpy(addrbuf, p, sizeof(addrbuf)) > sizeof(addrbuf))
+               return -1;
+
+       if ((mp = strchr(addrbuf, '/')) != NULL) {
+               *mp = '\0';
+               mp++;
+               masklen = strtoul(mp, &cp, 10);
+               if (*mp == '\0' || *cp != '\0' || masklen > 128)
+                       return -1;
+       }
+
+       if (addr_pton(addrbuf, &tmp) == -1)
+               return -1;
+
+       if (mp == NULL)
+               masklen = addr_unicast_masklen(tmp.af);
+       if (masklen_valid(tmp.af, masklen) == -1)
+               return -2;
+       if (addr_host_is_all0s(&tmp, masklen) != 0)
+               return -2;
+
+       if (n != NULL)
+               memcpy(n, &tmp, sizeof(*n));
+       if (l != NULL)
+               *l = masklen;
+
+       return 0;
+}
+
+static int
+addr_netmatch(const struct xaddr *host, const struct xaddr *net, u_int masklen)
+{
+       struct xaddr tmp_mask, tmp_result;
+
+       if (host->af != net->af)
+               return -1;
+
+       if (addr_netmask(host->af, masklen, &tmp_mask) == -1)
+               return -1;
+       if (addr_and(&tmp_result, host, &tmp_mask) == -1)
+               return -1;
+       return addr_cmp(&tmp_result, net);
+}
+
+/*
+ * Match "addr" against list pattern list "_list", which may contain a
+ * mix of CIDR addresses and old-school wildcards.
+ *
+ * If addr is NULL, then no matching is performed, but _list is parsed
+ * and checked for well-formedness.
+ *
+ * Returns 1 on match found (never returned when addr == NULL).
+ * Returns 0 on if no match found, or no errors found when addr == NULL.
+ * Returns -1 on negated match found (never returned when addr == NULL).
+ * Returns -2 on invalid list entry.
+ */
+int
+addr_match_list(const char *addr, const char *_list)
+{
+       char *list, *cp, *o;
+       struct xaddr try_addr, match_addr;
+       u_int masklen, neg;
+       int ret = 0, r;
+
+       if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
+               debug2("%s: couldn't parse address %.100s", __func__, addr);
+               return 0;
+       }
+       if ((o = list = strdup(_list)) == NULL)
+               return -1;
+       while ((cp = strsep(&list, ",")) != NULL) {
+               neg = *cp == '!';
+               if (neg)
+                       cp++;
+               if (*cp == '\0') {
+                       ret = -2;
+                       break;
+               }
+               /* Prefer CIDR address matching */
+               r = addr_pton_cidr(cp, &match_addr, &masklen);
+               if (r == -2) {
+                       error("Inconsistent mask length for "
+                           "network \"%.100s\"", cp);
+                       ret = -2;
+                       break;
+               } else if (r == 0) {
+                       if (addr != NULL && addr_netmatch(&try_addr,
+                           &match_addr, masklen) == 0) {
+ foundit:
+                               if (neg) {
+                                       ret = -1;
+                                       break;
+                               }
+                               ret = 1;
+                       }
+                       continue;
+               } else {
+                       /* If CIDR parse failed, try wildcard string match */
+                       if (addr != NULL && match_pattern(addr, cp) == 1)
+                               goto foundit;
+               }
+       }
+       xfree(o);
+
+       return ret;
+}
+
+/*
+ * Match "addr" against list CIDR list "_list". Lexical wildcards and
+ * negation are not supported. If "addr" == NULL, will verify structure
+ * of "_list".
+ *
+ * Returns 1 on match found (never returned when addr == NULL).
+ * Returns 0 on if no match found, or no errors found when addr == NULL.
+ * Returns -1 on error
+ */
+int
+addr_match_cidr_list(const char *addr, const char *_list)
+{
+       char *list, *cp, *o;
+       struct xaddr try_addr, match_addr;
+       u_int masklen;
+       int ret = 0, r;
+
+       if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
+               debug2("%s: couldn't parse address %.100s", __func__, addr);
+               return 0;
+       }
+       if ((o = list = strdup(_list)) == NULL)
+               return -1;
+       while ((cp = strsep(&list, ",")) != NULL) {
+               if (*cp == '\0') {
+                       error("%s: empty entry in list \"%.100s\"",
+                           __func__, o);
+                       ret = -1;
+                       break;
+               }
+
+               /*
+                * NB. This function is called in pre-auth with untrusted data,
+                * so be extra paranoid about junk reaching getaddrino (via
+                * addr_pton_cidr).
+                */
+
+               /* Stop junk from reaching getaddrinfo. +3 is for masklen */
+               if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
+                       error("%s: list entry \"%.100s\" too long",
+                           __func__, cp);
+                       ret = -1;
+                       break;
+               }
+#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
+               if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
+                       error("%s: list entry \"%.100s\" contains invalid "
+                           "characters", __func__, cp);
+                       ret = -1;
+               }
+
+               /* Prefer CIDR address matching */
+               r = addr_pton_cidr(cp, &match_addr, &masklen);
+               if (r == -1) {
+                       error("Invalid network entry \"%.100s\"", cp);
+                       ret = -1;
+                       break;
+               } else if (r == -2) {
+                       error("Inconsistent mask length for "
+                           "network \"%.100s\"", cp);
+                       ret = -1;
+                       break;
+               } else if (r == 0 && addr != NULL) {
+                       if (addr_netmatch(&try_addr, &match_addr,
+                           masklen) == 0)
+                               ret = 1;
+                       continue;
+               }
+       }
+       xfree(o);
+
+       return ret;
+}
diff --git a/atomicio.c b/atomicio.c
new file mode 100644 (file)
index 0000000..601b3c3
--- /dev/null
@@ -0,0 +1,165 @@
+/* $OpenBSD: atomicio.c,v 1.26 2010/09/22 22:58:51 djm Exp $ */
+/*
+ * Copyright (c) 2006 Damien Miller. All rights reserved.
+ * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
+ * 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"
+
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+# endif
+#endif
+#include <string.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+
+/*
+ * ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t
+atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
+    int (*cb)(void *, size_t), void *cb_arg)
+{
+       char *s = _s;
+       size_t pos = 0;
+       ssize_t res;
+       struct pollfd pfd;
+
+       pfd.fd = fd;
+       pfd.events = f == read ? POLLIN : POLLOUT;
+       while (n > pos) {
+               res = (f) (fd, s + pos, n - pos);
+               switch (res) {
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                               (void)poll(&pfd, 1, -1);
+                               continue;
+                       }
+                       return 0;
+               case 0:
+                       errno = EPIPE;
+                       return pos;
+               default:
+                       pos += (size_t)res;
+                       if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
+                               errno = EINTR;
+                               return pos;
+                       }
+               }
+       }
+       return pos;
+}
+
+size_t
+atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
+{
+       return atomicio6(f, fd, _s, n, NULL, NULL);
+}
+
+/*
+ * ensure all of data on socket comes through. f==readv || f==writev
+ */
+size_t
+atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt,
+    int (*cb)(void *, size_t), void *cb_arg)
+{
+       size_t pos = 0, rem;
+       ssize_t res;
+       struct iovec iov_array[IOV_MAX], *iov = iov_array;
+       struct pollfd pfd;
+
+       if (iovcnt > IOV_MAX) {
+               errno = EINVAL;
+               return 0;
+       }
+       /* Make a copy of the iov array because we may modify it below */
+       memcpy(iov, _iov, iovcnt * sizeof(*_iov));
+
+#ifndef BROKEN_READV_COMPARISON
+       pfd.fd = fd;
+       pfd.events = f == readv ? POLLIN : POLLOUT;
+#endif
+       for (; iovcnt > 0 && iov[0].iov_len > 0;) {
+               res = (f) (fd, iov, iovcnt);
+               switch (res) {
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+#ifndef BROKEN_READV_COMPARISON
+                               (void)poll(&pfd, 1, -1);
+#endif
+                               continue;
+                       }
+                       return 0;
+               case 0:
+                       errno = EPIPE;
+                       return pos;
+               default:
+                       rem = (size_t)res;
+                       pos += rem;
+                       /* skip completed iov entries */
+                       while (iovcnt > 0 && rem >= iov[0].iov_len) {
+                               rem -= iov[0].iov_len;
+                               iov++;
+                               iovcnt--;
+                       }
+                       /* This shouldn't happen... */
+                       if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
+                               errno = EFAULT;
+                               return 0;
+                       }
+                       if (iovcnt == 0)
+                               break;
+                       /* update pointer in partially complete iov */
+                       iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
+                       iov[0].iov_len -= rem;
+               }
+               if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
+                       errno = EINTR;
+                       return pos;
+               }
+       }
+       return pos;
+}
+
+size_t
+atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt)
+{
+       return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
+}
diff --git a/atomicio.h b/atomicio.h
new file mode 100644 (file)
index 0000000..0d728ac
--- /dev/null
@@ -0,0 +1,51 @@
+/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller.  All rights reserved.
+ * 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.
+ */
+
+#ifndef _ATOMICIO_H
+#define _ATOMICIO_H
+
+/*
+ * Ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t
+atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
+    int (*cb)(void *, size_t), void *);
+size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+
+#define vwrite (ssize_t (*)(int, void *, size_t))write
+
+/*
+ * ensure all of data on socket comes through. f==readv || f==writev
+ */
+size_t
+atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt, int (*cb)(void *, size_t), void *);
+size_t atomiciov(ssize_t (*)(int, const struct iovec *, int),
+    int, const struct iovec *, int);
+
+#endif /* _ATOMICIO_H */
diff --git a/audit-bsm.c b/audit-bsm.c
new file mode 100644 (file)
index 0000000..f196d4f
--- /dev/null
@@ -0,0 +1,380 @@
+/* $Id: audit-bsm.c,v 1.7 2011/01/17 10:15:29 dtucker Exp $ */
+
+/*
+ * TODO
+ *
+ * - deal with overlap between this and sys_auth_allowed_user
+ *   sys_auth_record_login and record_failed_login.
+ */
+
+/*
+ * Copyright 1988-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * 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.
+ *
+ */
+/* #pragma ident       "@(#)bsmaudit.c 1.1     01/09/17 SMI" */
+
+#include "includes.h"
+#if defined(USE_BSM_AUDIT)
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ssh.h"
+#include "log.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "xmalloc.h"
+
+#ifndef AUE_openssh
+# define AUE_openssh     32800
+#endif
+#include <bsm/audit.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#include <bsm/audit_record.h>
+#include <locale.h>
+
+#if defined(HAVE_GETAUDIT_ADDR)
+#define        AuditInfoStruct         auditinfo_addr
+#define AuditInfoTermID                au_tid_addr_t
+#define SetAuditFunc(a,b)      setaudit_addr((a),(b))
+#define SetAuditFuncText       "setaudit_addr"
+#define AUToSubjectFunc                au_to_subject_ex
+#define AUToReturnFunc(a,b)    au_to_return32((a), (int32_t)(b))
+#else
+#define        AuditInfoStruct         auditinfo
+#define AuditInfoTermID                au_tid_t
+#define SetAuditFunc(a,b)      setaudit(a)
+#define SetAuditFuncText       "setaudit"
+#define AUToSubjectFunc                au_to_subject
+#define AUToReturnFunc(a,b)    au_to_return((a), (u_int)(b))
+#endif
+
+#ifndef cannot_audit
+extern int     cannot_audit(int);
+#endif
+extern void    aug_init(void);
+extern void    aug_save_auid(au_id_t);
+extern void    aug_save_uid(uid_t);
+extern void    aug_save_euid(uid_t);
+extern void    aug_save_gid(gid_t);
+extern void    aug_save_egid(gid_t);
+extern void    aug_save_pid(pid_t);
+extern void    aug_save_asid(au_asid_t);
+extern void    aug_save_tid(dev_t, unsigned int);
+extern void    aug_save_tid_ex(dev_t, u_int32_t *, u_int32_t);
+extern int     aug_save_me(void);
+extern int     aug_save_namask(void);
+extern void    aug_save_event(au_event_t);
+extern void    aug_save_sorf(int);
+extern void    aug_save_text(char *);
+extern void    aug_save_text1(char *);
+extern void    aug_save_text2(char *);
+extern void    aug_save_na(int);
+extern void    aug_save_user(char *);
+extern void    aug_save_path(char *);
+extern int     aug_save_policy(void);
+extern void    aug_save_afunc(int (*)(int));
+extern int     aug_audit(void);
+extern int     aug_na_selected(void);
+extern int     aug_selected(void);
+extern int     aug_daemon_session(void);
+
+#ifndef HAVE_GETTEXT
+# define gettext(a)    (a)
+#endif
+
+extern Authctxt *the_authctxt;
+static AuditInfoTermID ssh_bsm_tid;
+
+/* Below is the low-level BSM interface code */
+
+/*
+ * aug_get_machine is only required on IPv6 capable machines, we use a
+ * different mechanism in audit_connection_from() for IPv4-only machines.
+ * getaudit_addr() is only present on IPv6 capable machines.
+ */
+#if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
+extern int     aug_get_machine(char *, u_int32_t *, u_int32_t *);
+#else
+static int
+aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
+{
+       struct addrinfo *ai; 
+       struct sockaddr_in *in4;
+       struct sockaddr_in6 *in6;
+       int ret = 0, r;
+
+       if ((r = getaddrinfo(host, NULL, NULL, &ai)) != 0) {
+               error("BSM audit: getaddrinfo failed for %.100s: %.100s", host,
+                   r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
+               return -1;
+       }
+       
+       switch (ai->ai_family) {
+       case AF_INET:
+               in4 = (struct sockaddr_in *)ai->ai_addr;
+               *type = AU_IPv4;
+               memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
+               break;
+#ifdef AU_IPv6
+       case AF_INET6: 
+               in6 = (struct sockaddr_in6 *)ai->ai_addr;
+               *type = AU_IPv6;
+               memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
+               break;
+#endif
+       default:
+               error("BSM audit: unknown address family for %.100s: %d",
+                   host, ai->ai_family);
+               ret = -1;
+       }
+       freeaddrinfo(ai);
+       return ret;
+}
+#endif
+
+/*
+ * Check if the specified event is selected (enabled) for auditing.
+ * Returns 1 if the event is selected, 0 if not and -1 on failure.
+ */
+static int
+selected(char *username, uid_t uid, au_event_t event, int sf)
+{
+       int rc, sorf;
+       char naflags[512];
+       struct au_mask mask;
+
+       mask.am_success = mask.am_failure = 0;
+       if (uid < 0) {
+               /* get flags for non-attributable (to a real user) events */
+               rc = getacna(naflags, sizeof(naflags));
+               if (rc == 0)
+                       (void) getauditflagsbin(naflags, &mask);
+       } else
+               rc = au_user_mask(username, &mask);
+
+       sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
+       return(au_preselect(event, &mask, sorf, AU_PRS_REREAD));
+}
+
+static void
+bsm_audit_record(int typ, char *string, au_event_t event_no)
+{
+       int             ad, rc, sel;
+       uid_t           uid = -1;
+       gid_t           gid = -1;
+       pid_t           pid = getpid();
+       AuditInfoTermID tid = ssh_bsm_tid;
+
+       if (the_authctxt != NULL && the_authctxt->valid) {
+               uid = the_authctxt->pw->pw_uid;
+               gid = the_authctxt->pw->pw_gid;
+       }
+
+       rc = (typ == 0) ? 0 : -1;
+       sel = selected(the_authctxt->user, uid, event_no, rc);
+       debug3("BSM audit: typ %d rc %d \"%s\"", typ, rc, string);
+       if (!sel)
+               return; /* audit event does not match mask, do not write */
+
+       debug3("BSM audit: writing audit new record");
+       ad = au_open();
+
+       (void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
+           pid, pid, &tid));
+       (void) au_write(ad, au_to_text(string));
+       (void) au_write(ad, AUToReturnFunc(typ, rc));
+
+       rc = au_close(ad, AU_TO_WRITE, event_no);
+       if (rc < 0)
+               error("BSM audit: %s failed to write \"%s\" record: %s",
+                   __func__, string, strerror(errno));
+}
+
+static void
+bsm_audit_session_setup(void)
+{
+       int rc;
+       struct AuditInfoStruct info;
+       au_mask_t mask;
+
+       if (the_authctxt == NULL) {
+               error("BSM audit: session setup internal error (NULL ctxt)");
+               return;
+       }
+
+       if (the_authctxt->valid)
+               info.ai_auid = the_authctxt->pw->pw_uid;
+       else
+               info.ai_auid = -1;
+       info.ai_asid = getpid();
+       mask.am_success = 0;
+       mask.am_failure = 0;
+
+       (void) au_user_mask(the_authctxt->user, &mask);
+
+       info.ai_mask.am_success  = mask.am_success;
+       info.ai_mask.am_failure  = mask.am_failure;
+
+       info.ai_termid = ssh_bsm_tid;
+
+       rc = SetAuditFunc(&info, sizeof(info));
+       if (rc < 0)
+               error("BSM audit: %s: %s failed: %s", __func__,
+                   SetAuditFuncText, strerror(errno));
+}
+
+static void
+bsm_audit_bad_login(const char *what)
+{
+       char textbuf[BSM_TEXTBUFSZ];
+
+       if (the_authctxt->valid) {
+               (void) snprintf(textbuf, sizeof (textbuf),
+                       gettext("invalid %s for user %s"),
+                           what, the_authctxt->user);
+               bsm_audit_record(4, textbuf, AUE_openssh);
+       } else {
+               (void) snprintf(textbuf, sizeof (textbuf),
+                       gettext("invalid user name \"%s\""),
+                           the_authctxt->user);
+               bsm_audit_record(3, textbuf, AUE_openssh);
+       }
+}
+
+/* Below is the sshd audit API code */
+
+void
+audit_connection_from(const char *host, int port)
+{
+       AuditInfoTermID *tid = &ssh_bsm_tid;
+       char buf[1024];
+
+       if (cannot_audit(0))
+               return;
+       debug3("BSM audit: connection from %.100s port %d", host, port);
+
+       /* populate our terminal id structure */
+#if defined(HAVE_GETAUDIT_ADDR)
+       tid->at_port = (dev_t)port;
+       aug_get_machine((char *)host, &(tid->at_addr[0]), &(tid->at_type));
+       snprintf(buf, sizeof(buf), "%08x %08x %08x %08x", tid->at_addr[0],
+           tid->at_addr[1], tid->at_addr[2], tid->at_addr[3]);
+       debug3("BSM audit: iptype %d machine ID %s", (int)tid->at_type, buf);
+#else
+       /* this is used on IPv4-only machines */
+       tid->port = (dev_t)port;
+       tid->machine = inet_addr(host);
+       snprintf(buf, sizeof(buf), "%08x", tid->machine);
+       debug3("BSM audit: machine ID %s", buf);
+#endif
+}
+
+void
+audit_run_command(const char *command)
+{
+       /* not implemented */
+}
+
+void
+audit_session_open(struct logininfo *li)
+{
+       /* not implemented */
+}
+
+void
+audit_session_close(struct logininfo *li)
+{
+       /* not implemented */
+}
+
+void
+audit_event(ssh_audit_event_t event)
+{
+       char    textbuf[BSM_TEXTBUFSZ];
+       static int logged_in = 0;
+       const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
+
+       if (cannot_audit(0))
+               return;
+
+       switch(event) {
+       case SSH_AUTH_SUCCESS:
+               logged_in = 1;
+               bsm_audit_session_setup();
+               snprintf(textbuf, sizeof(textbuf),
+                   gettext("successful login %s"), user);
+               bsm_audit_record(0, textbuf, AUE_openssh);
+               break;
+
+       case SSH_CONNECTION_CLOSE:
+               /*
+                * We can also get a close event if the user attempted auth
+                * but never succeeded.
+                */
+               if (logged_in) {
+                       snprintf(textbuf, sizeof(textbuf),
+                           gettext("sshd logout %s"), the_authctxt->user);
+                       bsm_audit_record(0, textbuf, AUE_logout);
+               } else {
+                       debug("%s: connection closed without authentication",
+                           __func__);
+               }
+               break;
+
+       case SSH_NOLOGIN:
+               bsm_audit_record(1,
+                   gettext("logins disabled by /etc/nologin"), AUE_openssh);
+               break;
+
+       case SSH_LOGIN_EXCEED_MAXTRIES:
+               snprintf(textbuf, sizeof(textbuf),
+                   gettext("too many tries for user %s"), the_authctxt->user);
+               bsm_audit_record(1, textbuf, AUE_openssh);
+               break;
+
+       case SSH_LOGIN_ROOT_DENIED:
+               bsm_audit_record(2, gettext("not_console"), AUE_openssh);
+               break;
+
+       case SSH_AUTH_FAIL_PASSWD:
+               bsm_audit_bad_login("password");
+               break;
+
+       case SSH_AUTH_FAIL_KBDINT:
+               bsm_audit_bad_login("interactive password entry");
+               break;
+
+       default:
+               debug("%s: unhandled event %d", __func__, event);
+       }
+}
+#endif /* BSM */
diff --git a/audit-linux.c b/audit-linux.c
new file mode 100644 (file)
index 0000000..b3ee2f4
--- /dev/null
@@ -0,0 +1,126 @@
+/* $Id: audit-linux.c,v 1.1 2011/01/17 10:15:30 dtucker Exp $ */
+
+/*
+ * Copyright 2010 Red Hat, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * 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.
+ *
+ * Red Hat author: Jan F. Chadima <jchadima@redhat.com>
+ */
+
+#include "includes.h"
+#if defined(USE_LINUX_AUDIT)
+#include <libaudit.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "log.h"
+#include "audit.h"
+#include "canohost.h"
+
+const char* audit_username(void);
+
+int
+linux_audit_record_event(int uid, const char *username,
+    const char *hostname, const char *ip, const char *ttyn, int success)
+{
+       int audit_fd, rc, saved_errno;
+
+       audit_fd = audit_open();
+       if (audit_fd < 0) {
+               if (errno == EINVAL || errno == EPROTONOSUPPORT ||
+                   errno == EAFNOSUPPORT)
+                       return 1; /* No audit support in kernel */
+               else
+                       return 0; /* Must prevent login */
+       }
+       rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN,
+           NULL, "login", username ? username : "(unknown)",
+           username == NULL ? uid : -1, hostname, ip, ttyn, success);
+       saved_errno = errno;
+       close(audit_fd);
+       /*
+        * Do not report error if the error is EPERM and sshd is run as non
+        * root user.
+        */
+       if ((rc == -EPERM) && (geteuid() != 0))
+               rc = 0;
+       errno = saved_errno;
+       return (rc >= 0);
+}
+
+/* Below is the sshd audit API code */
+
+void
+audit_connection_from(const char *host, int port)
+{
+}
+       /* not implemented */
+
+void
+audit_run_command(const char *command)
+{
+       /* not implemented */
+}
+
+void
+audit_session_open(struct logininfo *li)
+{
+       if (linux_audit_record_event(li->uid, NULL, li->hostname,
+           NULL, li->line, 1) == 0)
+               fatal("linux_audit_write_entry failed: %s", strerror(errno));
+}
+
+void
+audit_session_close(struct logininfo *li)
+{
+       /* not implemented */
+}
+
+void
+audit_event(ssh_audit_event_t event)
+{
+       switch(event) {
+       case SSH_AUTH_SUCCESS:
+       case SSH_CONNECTION_CLOSE:
+       case SSH_NOLOGIN:
+       case SSH_LOGIN_EXCEED_MAXTRIES:
+       case SSH_LOGIN_ROOT_DENIED:
+               break;
+
+       case SSH_AUTH_FAIL_NONE:
+       case SSH_AUTH_FAIL_PASSWD:
+       case SSH_AUTH_FAIL_KBDINT:
+       case SSH_AUTH_FAIL_PUBKEY:
+       case SSH_AUTH_FAIL_HOSTBASED:
+       case SSH_AUTH_FAIL_GSSAPI:
+       case SSH_INVALID_USER:
+               linux_audit_record_event(-1, audit_username(), NULL,
+                       get_remote_ipaddr(), "sshd", 0);
+               break;
+
+       default:
+               debug("%s: unhandled event %d", __func__, event);
+       }
+}
+
+#endif /* USE_LINUX_AUDIT */
diff --git a/audit.c b/audit.c
new file mode 100644 (file)
index 0000000..ced57fa
--- /dev/null
+++ b/audit.c
@@ -0,0 +1,186 @@
+/* $Id: audit.c,v 1.6 2011/01/17 10:15:30 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2004, 2005 Darren Tucker.  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 <stdarg.h>
+#include <string.h>
+
+#ifdef SSH_AUDIT_EVENTS
+
+#include "audit.h"
+#include "log.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+
+/*
+ * Care must be taken when using this since it WILL NOT be initialized when
+ * audit_connection_from() is called and MAY NOT be initialized when
+ * audit_event(CONNECTION_ABANDON) is called.  Test for NULL before using.
+ */
+extern Authctxt *the_authctxt;
+
+/* Maybe add the audit class to struct Authmethod? */
+ssh_audit_event_t
+audit_classify_auth(const char *method)
+{
+       if (strcmp(method, "none") == 0)
+               return SSH_AUTH_FAIL_NONE;
+       else if (strcmp(method, "password") == 0)
+               return SSH_AUTH_FAIL_PASSWD;
+       else if (strcmp(method, "publickey") == 0 ||
+           strcmp(method, "rsa") == 0)
+               return SSH_AUTH_FAIL_PUBKEY;
+       else if (strncmp(method, "keyboard-interactive", 20) == 0 ||
+           strcmp(method, "challenge-response") == 0)
+               return SSH_AUTH_FAIL_KBDINT;
+       else if (strcmp(method, "hostbased") == 0 ||
+           strcmp(method, "rhosts-rsa") == 0)
+               return SSH_AUTH_FAIL_HOSTBASED;
+       else if (strcmp(method, "gssapi-with-mic") == 0)
+               return SSH_AUTH_FAIL_GSSAPI;
+       else
+               return SSH_AUDIT_UNKNOWN;
+}
+
+/* helper to return supplied username */
+const char *
+audit_username(void)
+{
+       static const char unknownuser[] = "(unknown user)";
+       static const char invaliduser[] = "(invalid user)";
+
+       if (the_authctxt == NULL || the_authctxt->user == NULL)
+               return (unknownuser);
+       if (!the_authctxt->valid)
+               return (invaliduser);
+       return (the_authctxt->user);
+}
+
+const char *
+audit_event_lookup(ssh_audit_event_t ev)
+{
+       int i;
+       static struct event_lookup_struct {
+               ssh_audit_event_t event;
+               const char *name;
+       } event_lookup[] = {
+               {SSH_LOGIN_EXCEED_MAXTRIES,     "LOGIN_EXCEED_MAXTRIES"},
+               {SSH_LOGIN_ROOT_DENIED,         "LOGIN_ROOT_DENIED"},
+               {SSH_AUTH_SUCCESS,              "AUTH_SUCCESS"},
+               {SSH_AUTH_FAIL_NONE,            "AUTH_FAIL_NONE"},
+               {SSH_AUTH_FAIL_PASSWD,          "AUTH_FAIL_PASSWD"},
+               {SSH_AUTH_FAIL_KBDINT,          "AUTH_FAIL_KBDINT"},
+               {SSH_AUTH_FAIL_PUBKEY,          "AUTH_FAIL_PUBKEY"},
+               {SSH_AUTH_FAIL_HOSTBASED,       "AUTH_FAIL_HOSTBASED"},
+               {SSH_AUTH_FAIL_GSSAPI,          "AUTH_FAIL_GSSAPI"},
+               {SSH_INVALID_USER,              "INVALID_USER"},
+               {SSH_NOLOGIN,                   "NOLOGIN"},
+               {SSH_CONNECTION_CLOSE,          "CONNECTION_CLOSE"},
+               {SSH_CONNECTION_ABANDON,        "CONNECTION_ABANDON"},
+               {SSH_AUDIT_UNKNOWN,             "AUDIT_UNKNOWN"}
+       };
+
+       for (i = 0; event_lookup[i].event != SSH_AUDIT_UNKNOWN; i++)
+               if (event_lookup[i].event == ev)
+                       break;
+       return(event_lookup[i].name);
+}
+
+# ifndef CUSTOM_SSH_AUDIT_EVENTS
+/*
+ * Null implementations of audit functions.
+ * These get used if SSH_AUDIT_EVENTS is defined but no audit module is enabled.
+ */
+
+/*
+ * Called after a connection has been accepted but before any authentication
+ * has been attempted.
+ */
+void
+audit_connection_from(const char *host, int port)
+{
+       debug("audit connection from %s port %d euid %d", host, port,
+           (int)geteuid());
+}
+
+/*
+ * Called when various events occur (see audit.h for a list of possible
+ * events and what they mean).
+ */
+void
+audit_event(ssh_audit_event_t event)
+{
+       debug("audit event euid %d user %s event %d (%s)", geteuid(),
+           audit_username(), event, audit_event_lookup(event));
+}
+
+/*
+ * Called when a user session is started.  Argument is the tty allocated to
+ * the session, or NULL if no tty was allocated.
+ *
+ * Note that this may be called multiple times if multiple sessions are used
+ * within a single connection.
+ */
+void
+audit_session_open(struct logininfo *li)
+{
+       const char *t = li->line ? li->line : "(no tty)";
+
+       debug("audit session open euid %d user %s tty name %s", geteuid(),
+           audit_username(), t);
+}
+
+/*
+ * Called when a user session is closed.  Argument is the tty allocated to
+ * the session, or NULL if no tty was allocated.
+ *
+ * Note that this may be called multiple times if multiple sessions are used
+ * within a single connection.
+ */
+void
+audit_session_close(struct logininfo *li)
+{
+       const char *t = li->line ? li->line : "(no tty)";
+
+       debug("audit session close euid %d user %s tty name %s", geteuid(),
+           audit_username(), t);
+}
+
+/*
+ * This will be called when a user runs a non-interactive command.  Note that
+ * it may be called multiple times for a single connection since SSH2 allows
+ * multiple sessions within a single connection.
+ */
+void
+audit_run_command(const char *command)
+{
+       debug("audit run command euid %d user %s command '%.200s'", geteuid(),
+           audit_username(), command);
+}
+# endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
+#endif /* SSH_AUDIT_EVENTS */
diff --git a/audit.h b/audit.h
new file mode 100644 (file)
index 0000000..92ede5b
--- /dev/null
+++ b/audit.h
@@ -0,0 +1,57 @@
+/* $Id: audit.h,v 1.4 2011/01/17 10:15:30 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2004, 2005 Darren Tucker.  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_AUDIT_H
+# define _SSH_AUDIT_H
+
+#include "loginrec.h"
+
+enum ssh_audit_event_type {
+       SSH_LOGIN_EXCEED_MAXTRIES,
+       SSH_LOGIN_ROOT_DENIED,
+       SSH_AUTH_SUCCESS,
+       SSH_AUTH_FAIL_NONE,
+       SSH_AUTH_FAIL_PASSWD,
+       SSH_AUTH_FAIL_KBDINT,   /* keyboard-interactive or challenge-response */
+       SSH_AUTH_FAIL_PUBKEY,   /* ssh2 pubkey or ssh1 rsa */
+       SSH_AUTH_FAIL_HOSTBASED,        /* ssh2 hostbased or ssh1 rhostsrsa */
+       SSH_AUTH_FAIL_GSSAPI,
+       SSH_INVALID_USER,
+       SSH_NOLOGIN,            /* denied by /etc/nologin, not implemented */
+       SSH_CONNECTION_CLOSE,   /* closed after attempting auth or session */
+       SSH_CONNECTION_ABANDON, /* closed without completing auth */
+       SSH_AUDIT_UNKNOWN
+};
+typedef enum ssh_audit_event_type ssh_audit_event_t;
+
+void   audit_connection_from(const char *, int);
+void   audit_event(ssh_audit_event_t);
+void   audit_session_open(struct logininfo *);
+void   audit_session_close(struct logininfo *);
+void   audit_run_command(const char *);
+ssh_audit_event_t audit_classify_auth(const char *);
+
+#endif /* _SSH_AUDIT_H */
diff --git a/auth-bsdauth.c b/auth-bsdauth.c
new file mode 100644 (file)
index 0000000..0b3262b
--- /dev/null
@@ -0,0 +1,138 @@
+/* $OpenBSD: auth-bsdauth.c,v 1.11 2007/09/21 08:15:29 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+
+#ifdef BSD_AUTH
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "buffer.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+static void *
+bsdauth_init_ctx(Authctxt *authctxt)
+{
+       return authctxt;
+}
+
+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 = xcalloc(*numprompts, sizeof(char *));
+       *echo_on = xcalloc(*numprompts, sizeof(u_int));
+       (*prompts)[0] = xstrdup(challenge);
+
+       return 0;
+}
+
+int
+bsdauth_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Authctxt *authctxt = ctx;
+       int authok;
+
+       if (!authctxt->valid)
+               return -1;
+
+       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
+};
+
+KbdintDevice mm_bsdauth_device = {
+       "bsdauth",
+       bsdauth_init_ctx,
+       mm_bsdauth_query,
+       mm_bsdauth_respond,
+       bsdauth_free_ctx
+};
+#endif
diff --git a/auth-chall.c b/auth-chall.c
new file mode 100644 (file)
index 0000000..919b1ea
--- /dev/null
@@ -0,0 +1,123 @@
+/* $OpenBSD: auth-chall.c,v 1.12 2006/08/03 03:34:41 deraadt 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "servconf.h"
+
+/* limited protocol v1 interface to kbd-interactive authentication */
+
+extern KbdintDevice *devices[];
+static KbdintDevice *device;
+extern ServerOptions options;
+
+char *
+get_challenge(Authctxt *authctxt)
+{
+       char *challenge, *name, *info, **prompts;
+       u_int i, numprompts;
+       u_int *echo_on;
+
+#ifdef USE_PAM
+       if (!options.use_pam)
+               remove_kbdint_device("pam");
+#endif
+
+       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], *name, *info, **prompts;
+       u_int i, numprompts, *echo_on;
+       int authenticated = 0;
+
+       if (device == NULL)
+               return 0;
+       if (authctxt->kbdintctxt == NULL)
+               return 0;
+       resp[0] = (char *)response;
+       switch (device->respond(authctxt->kbdintctxt, 1, resp)) {
+       case 0: /* Success */
+               authenticated = 1;
+               break;
+       case 1: /* Postponed - retry with empty query for PAM */
+               if ((device->query(authctxt->kbdintctxt, &name, &info,
+                   &numprompts, &prompts, &echo_on)) != 0)
+                       break;
+               if (numprompts == 0 &&
+                   device->respond(authctxt->kbdintctxt, 0, resp) == 0)
+                       authenticated = 1;
+
+               for (i = 0; i < numprompts; i++)
+                       xfree(prompts[i]);
+               xfree(prompts);
+               xfree(name);
+               xfree(echo_on);
+               xfree(info);
+               break;
+       }
+       device->free_ctx(authctxt->kbdintctxt);
+       authctxt->kbdintctxt = NULL;
+       return authenticated;
+}
+void
+abandon_challenge_response(Authctxt *authctxt)
+{
+       if (authctxt->kbdintctxt != NULL) {
+               device->free_ctx(authctxt->kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+       }
+}
diff --git a/auth-krb5.c b/auth-krb5.c
new file mode 100644 (file)
index 0000000..d019fe2
--- /dev/null
@@ -0,0 +1,256 @@
+/* $OpenBSD: auth-krb5.c,v 1.19 2006/08/03 03:34:41 deraadt Exp $ */
+/*
+ *    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 $
+ */
+/*
+ * Copyright (c) 2002 Daniel Kouril.  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 <sys/types.h>
+#include <pwd.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "packet.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+
+#ifdef KRB5
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <krb5.h>
+
+extern ServerOptions    options;
+
+static int
+krb5_init(void *context)
+{
+       Authctxt *authctxt = (Authctxt *)context;
+       krb5_error_code problem;
+
+       if (authctxt->krb5_ctx == NULL) {
+               problem = krb5_init_context(&authctxt->krb5_ctx);
+               if (problem)
+                       return (problem);
+       }
+       return (0);
+}
+
+int
+auth_krb5_password(Authctxt *authctxt, const char *password)
+{
+#ifndef HEIMDAL
+       krb5_creds creds;
+       krb5_principal server;
+#endif
+       krb5_error_code problem;
+       krb5_ccache ccache = NULL;
+       int len;
+       char *client, *platform_client;
+
+       /* get platform-specific kerberos client principal name (if it exists) */
+       platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
+       client = platform_client ? platform_client : authctxt->pw->pw_name;
+
+       temporarily_use_uid(authctxt->pw);
+
+       problem = krb5_init(authctxt);
+       if (problem)
+               goto out;
+
+       problem = krb5_parse_name(authctxt->krb5_ctx, client,
+                   &authctxt->krb5_user);
+       if (problem)
+               goto out;
+
+#ifdef HEIMDAL
+       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache);
+       if (problem)
+               goto out;
+
+       problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
+               authctxt->krb5_user);
+       if (problem)
+               goto out;
+
+       restore_uid();
+
+       problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
+           ccache, password, 1, NULL);
+
+       temporarily_use_uid(authctxt->pw);
+
+       if (problem)
+               goto out;
+
+       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
+           &authctxt->krb5_fwd_ccache);
+       if (problem)
+               goto out;
+
+       problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache,
+           authctxt->krb5_fwd_ccache);
+       krb5_cc_destroy(authctxt->krb5_ctx, ccache);
+       ccache = NULL;
+       if (problem)
+               goto out;
+
+#else
+       problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
+           authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
+       if (problem)
+               goto out;
+
+       problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
+           KRB5_NT_SRV_HST, &server);
+       if (problem)
+               goto out;
+
+       restore_uid();
+       problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
+           NULL, NULL, NULL);
+       krb5_free_principal(authctxt->krb5_ctx, server);
+       temporarily_use_uid(authctxt->pw);
+       if (problem)
+               goto out;
+
+       if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) {
+               problem = -1;
+               goto out;
+       }
+
+       problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &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_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
+                                &creds);
+       if (problem)
+               goto out;
+#endif
+
+       authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
+
+       len = strlen(authctxt->krb5_ticket_file) + 6;
+       authctxt->krb5_ccname = xmalloc(len);
+       snprintf(authctxt->krb5_ccname, len, "FILE:%s",
+           authctxt->krb5_ticket_file);
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
+#endif
+
+ out:
+       restore_uid();
+       
+       if (platform_client != NULL)
+               xfree(platform_client);
+
+       if (problem) {
+               if (ccache)
+                       krb5_cc_destroy(authctxt->krb5_ctx, ccache);
+
+               if (authctxt->krb5_ctx != NULL && problem!=-1)
+                       debug("Kerberos password authentication failed: %s",
+                           krb5_get_err_text(authctxt->krb5_ctx, problem));
+               else
+                       debug("Kerberos password authentication failed: %d",
+                           problem);
+
+               krb5_cleanup_proc(authctxt);
+
+               if (options.kerberos_or_local_passwd)
+                       return (-1);
+               else
+                       return (0);
+       }
+       return (authctxt->valid ? 1 : 0);
+}
+
+void
+krb5_cleanup_proc(Authctxt *authctxt)
+{
+       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_ctx) {
+               krb5_free_context(authctxt->krb5_ctx);
+               authctxt->krb5_ctx = NULL;
+       }
+}
+
+#ifndef HEIMDAL
+krb5_error_code
+ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
+       int tmpfd, ret;
+       char ccname[40];
+       mode_t old_umask;
+
+       ret = snprintf(ccname, sizeof(ccname),
+           "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
+       if (ret < 0 || (size_t)ret >= sizeof(ccname))
+               return ENOMEM;
+
+       old_umask = umask(0177);
+       tmpfd = mkstemp(ccname + strlen("FILE:"));
+       umask(old_umask);
+       if (tmpfd == -1) {
+               logit("mkstemp(): %.100s", strerror(errno));
+               return errno;
+       }
+
+       if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
+               logit("fchmod(): %.100s", strerror(errno));
+               close(tmpfd);
+               return errno;
+       }
+       close(tmpfd);
+
+       return (krb5_cc_resolve(ctx, ccname, ccache));
+}
+#endif /* !HEIMDAL */
+#endif /* KRB5 */
diff --git a/auth-options.c b/auth-options.c
new file mode 100644 (file)
index 0000000..eae45cf
--- /dev/null
@@ -0,0 +1,649 @@
+/* $OpenBSD: auth-options.c,v 1.54 2010/12/24 21:41:48 djm 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".
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <netdb.h>
+#include <pwd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "match.h"
+#include "log.h"
+#include "canohost.h"
+#include "buffer.h"
+#include "channels.h"
+#include "servconf.h"
+#include "misc.h"
+#include "key.h"
+#include "auth-options.h"
+#include "hostfile.h"
+#include "auth.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.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;
+int no_user_rc = 0;
+int key_is_cert_authority = 0;
+
+/* "command=" option. */
+char *forced_command = NULL;
+
+/* "environment=" options. */
+struct envstring *custom_environment = NULL;
+
+/* "tunnel=" option. */
+int forced_tun_device = -1;
+
+/* "principals=" option. */
+char *authorized_principals = 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;
+       no_user_rc = 0;
+       key_is_cert_authority = 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;
+       }
+       if (authorized_principals) {
+               xfree(authorized_principals);
+               authorized_principals = NULL;
+       }
+       forced_tun_device = -1;
+       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 = "cert-authority";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       key_is_cert_authority = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-port-forwarding";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       auth_debug_add("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) {
+                       auth_debug_add("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) {
+                       auth_debug_add("X11 forwarding disabled.");
+                       no_x11_forwarding_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-pty";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       auth_debug_add("Pty allocation disabled.");
+                       no_pty_flag = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "no-user-rc";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       auth_debug_add("User rc file execution disabled.");
+                       no_user_rc = 1;
+                       opts += strlen(cp);
+                       goto next_option;
+               }
+               cp = "command=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       opts += strlen(cp);
+                       if (forced_command != NULL)
+                               xfree(forced_command);
+                       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);
+                               auth_debug_add("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(forced_command);
+                               forced_command = NULL;
+                               goto bad_option;
+                       }
+                       forced_command[i] = '\0';
+                       auth_debug_add("Forced command.");
+                       opts++;
+                       goto next_option;
+               }
+               cp = "principals=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       opts += strlen(cp);
+                       if (authorized_principals != NULL)
+                               xfree(authorized_principals);
+                       authorized_principals = xmalloc(strlen(opts) + 1);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               if (*opts == '\\' && opts[1] == '"') {
+                                       opts += 2;
+                                       authorized_principals[i++] = '"';
+                                       continue;
+                               }
+                               authorized_principals[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               auth_debug_add("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(authorized_principals);
+                               authorized_principals = NULL;
+                               goto bad_option;
+                       }
+                       authorized_principals[i] = '\0';
+                       auth_debug_add("principals: %.900s",
+                           authorized_principals);
+                       opts++;
+                       goto next_option;
+               }
+               cp = "environment=\"";
+               if (options.permit_user_env &&
+                   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);
+                               auth_debug_add("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(s);
+                               goto bad_option;
+                       }
+                       s[i] = '\0';
+                       auth_debug_add("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.use_dns);
+                       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);
+                               auth_debug_add("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       patterns[i] = '\0';
+                       opts++;
+                       switch (match_host_and_ip(remote_host, remote_ip,
+                           patterns)) {
+                       case 1:
+                               xfree(patterns);
+                               /* Host name matches. */
+                               goto next_option;
+                       case -1:
+                               debug("%.100s, line %lu: invalid criteria",
+                                   file, linenum);
+                               auth_debug_add("%.100s, line %lu: "
+                                   "invalid criteria", file, linenum);
+                               /* FALLTHROUGH */
+                       case 0:
+                               xfree(patterns);
+                               logit("Authentication tried for %.100s with "
+                                   "correct key but not from a permitted "
+                                   "host (host=%.200s, ip=%.200s).",
+                                   pw->pw_name, remote_host, remote_ip);
+                               auth_debug_add("Your host '%.200s' is not "
+                                   "permitted to use this key for login.",
+                                   remote_host);
+                               break;
+                       }
+                       /* deny access */
+                       return 0;
+               }
+               cp = "permitopen=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       char *host, *p;
+                       int 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);
+                               auth_debug_add("%.100s, line %lu: missing "
+                                   "end quote", file, linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       patterns[i] = '\0';
+                       opts++;
+                       p = patterns;
+                       host = hpdelim(&p);
+                       if (host == NULL || strlen(host) >= NI_MAXHOST) {
+                               debug("%.100s, line %lu: Bad permitopen "
+                                   "specification <%.100s>", file, linenum,
+                                   patterns);
+                               auth_debug_add("%.100s, line %lu: "
+                                   "Bad permitopen specification", file,
+                                   linenum);
+                               xfree(patterns);
+                               goto bad_option;
+                       }
+                       host = cleanhostname(host);
+                       if (p == NULL || (port = a2port(p)) <= 0) {
+                               debug("%.100s, line %lu: Bad permitopen port "
+                                   "<%.100s>", file, linenum, p ? p : "");
+                               auth_debug_add("%.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;
+               }
+               cp = "tunnel=\"";
+               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+                       char *tun = NULL;
+                       opts += strlen(cp);
+                       tun = xmalloc(strlen(opts) + 1);
+                       i = 0;
+                       while (*opts) {
+                               if (*opts == '"')
+                                       break;
+                               tun[i++] = *opts++;
+                       }
+                       if (!*opts) {
+                               debug("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               auth_debug_add("%.100s, line %lu: missing end quote",
+                                   file, linenum);
+                               xfree(tun);
+                               forced_tun_device = -1;
+                               goto bad_option;
+                       }
+                       tun[i] = '\0';
+                       forced_tun_device = a2tun(tun, NULL);
+                       xfree(tun);
+                       if (forced_tun_device == SSH_TUNID_ERR) {
+                               debug("%.100s, line %lu: invalid tun device",
+                                   file, linenum);
+                               auth_debug_add("%.100s, line %lu: invalid tun device",
+                                   file, linenum);
+                               forced_tun_device = -1;
+                               goto bad_option;
+                       }
+                       auth_debug_add("Forced tun device: %d", forced_tun_device);
+                       opts++;
+                       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:
+       logit("Bad options in %.100s file, line %lu: %.50s",
+           file, linenum, opts);
+       auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
+           file, linenum, opts);
+
+       /* deny access */
+       return 0;
+}
+
+#define OPTIONS_CRITICAL       1
+#define OPTIONS_EXTENSIONS     2
+static int
+parse_option_list(u_char *optblob, size_t optblob_len, struct passwd *pw,
+    u_int which, int crit,
+    int *cert_no_port_forwarding_flag,
+    int *cert_no_agent_forwarding_flag,
+    int *cert_no_x11_forwarding_flag,
+    int *cert_no_pty_flag,
+    int *cert_no_user_rc,
+    char **cert_forced_command,
+    int *cert_source_address_done)
+{
+       char *command, *allowed;
+       const char *remote_ip;
+       u_char *name = NULL, *data_blob = NULL;
+       u_int nlen, dlen, clen;
+       Buffer c, data;
+       int ret = -1, found;
+
+       buffer_init(&data);
+
+       /* Make copy to avoid altering original */
+       buffer_init(&c);
+       buffer_append(&c, optblob, optblob_len);
+
+       while (buffer_len(&c) > 0) {
+               if ((name = buffer_get_cstring_ret(&c, &nlen)) == NULL ||
+                   (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) {
+                       error("Certificate options corrupt");
+                       goto out;
+               }
+               buffer_append(&data, data_blob, dlen);
+               debug3("found certificate option \"%.100s\" len %u",
+                   name, dlen);
+               if (strlen(name) != nlen) {
+                       error("Certificate constraint name contains \\0");
+                       goto out;
+               }
+               found = 0;
+               if ((which & OPTIONS_EXTENSIONS) != 0) {
+                       if (strcmp(name, "permit-X11-forwarding") == 0) {
+                               *cert_no_x11_forwarding_flag = 0;
+                               found = 1;
+                       } else if (strcmp(name,
+                           "permit-agent-forwarding") == 0) {
+                               *cert_no_agent_forwarding_flag = 0;
+                               found = 1;
+                       } else if (strcmp(name,
+                           "permit-port-forwarding") == 0) {
+                               *cert_no_port_forwarding_flag = 0;
+                               found = 1;
+                       } else if (strcmp(name, "permit-pty") == 0) {
+                               *cert_no_pty_flag = 0;
+                               found = 1;
+                       } else if (strcmp(name, "permit-user-rc") == 0) {
+                               *cert_no_user_rc = 0;
+                               found = 1;
+                       }
+               }
+               if (!found && (which & OPTIONS_CRITICAL) != 0) {
+                       if (strcmp(name, "force-command") == 0) {
+                               if ((command = buffer_get_cstring_ret(&data,
+                                   &clen)) == NULL) {
+                                       error("Certificate constraint \"%s\" "
+                                           "corrupt", name);
+                                       goto out;
+                               }
+                               if (strlen(command) != clen) {
+                                       error("force-command constraint "
+                                           "contains \\0");
+                                       goto out;
+                               }
+                               if (*cert_forced_command != NULL) {
+                                       error("Certificate has multiple "
+                                           "force-command options");
+                                       xfree(command);
+                                       goto out;
+                               }
+                               *cert_forced_command = command;
+                               found = 1;
+                       }
+                       if (strcmp(name, "source-address") == 0) {
+                               if ((allowed = buffer_get_cstring_ret(&data,
+                                   &clen)) == NULL) {
+                                       error("Certificate constraint "
+                                           "\"%s\" corrupt", name);
+                                       goto out;
+                               }
+                               if (strlen(allowed) != clen) {
+                                       error("source-address constraint "
+                                           "contains \\0");
+                                       goto out;
+                               }
+                               if ((*cert_source_address_done)++) {
+                                       error("Certificate has multiple "
+                                           "source-address options");
+                                       xfree(allowed);
+                                       goto out;
+                               }
+                               remote_ip = get_remote_ipaddr();
+                               switch (addr_match_cidr_list(remote_ip,
+                                   allowed)) {
+                               case 1:
+                                       /* accepted */
+                                       xfree(allowed);
+                                       break;
+                               case 0:
+                                       /* no match */
+                                       logit("Authentication tried for %.100s "
+                                           "with valid certificate but not "
+                                           "from a permitted host "
+                                           "(ip=%.200s).", pw->pw_name,
+                                           remote_ip);
+                                       auth_debug_add("Your address '%.200s' "
+                                           "is not permitted to use this "
+                                           "certificate for login.",
+                                           remote_ip);
+                                       xfree(allowed);
+                                       goto out;
+                               case -1:
+                                       error("Certificate source-address "
+                                           "contents invalid");
+                                       xfree(allowed);
+                                       goto out;
+                               }
+                               found = 1;
+                       }
+               }
+
+               if (!found) {
+                       if (crit) {
+                               error("Certificate critical option \"%s\" "
+                                   "is not supported", name);
+                               goto out;
+                       } else {
+                               logit("Certificate extension \"%s\" "
+                                   "is not supported", name);
+                       }
+               } else if (buffer_len(&data) != 0) {
+                       error("Certificate option \"%s\" corrupt "
+                           "(extra data)", name);
+                       goto out;
+               }
+               buffer_clear(&data);
+               xfree(name);
+               xfree(data_blob);
+               name = data_blob = NULL;
+       }
+       /* successfully parsed all options */
+       ret = 0;
+
+ out:
+       if (ret != 0 &&
+           cert_forced_command != NULL &&
+           *cert_forced_command != NULL) {
+               xfree(*cert_forced_command);
+               *cert_forced_command = NULL;
+       }
+       if (name != NULL)
+               xfree(name);
+       if (data_blob != NULL)
+               xfree(data_blob);
+       buffer_free(&data);
+       buffer_free(&c);
+       return ret;
+}
+
+/*
+ * Set options from critical certificate options. These supersede user key
+ * options so this must be called after auth_parse_options().
+ */
+int
+auth_cert_options(Key *k, struct passwd *pw)
+{
+       int cert_no_port_forwarding_flag = 1;
+       int cert_no_agent_forwarding_flag = 1;
+       int cert_no_x11_forwarding_flag = 1;
+       int cert_no_pty_flag = 1;
+       int cert_no_user_rc = 1;
+       char *cert_forced_command = NULL;
+       int cert_source_address_done = 0;
+
+       if (key_cert_is_legacy(k)) {
+               /* All options are in the one field for v00 certs */
+               if (parse_option_list(buffer_ptr(&k->cert->critical),
+                   buffer_len(&k->cert->critical), pw,
+                   OPTIONS_CRITICAL|OPTIONS_EXTENSIONS, 1,
+                   &cert_no_port_forwarding_flag,
+                   &cert_no_agent_forwarding_flag,
+                   &cert_no_x11_forwarding_flag,
+                   &cert_no_pty_flag,
+                   &cert_no_user_rc,
+                   &cert_forced_command,
+                   &cert_source_address_done) == -1)
+                       return -1;
+       } else {
+               /* Separate options and extensions for v01 certs */
+               if (parse_option_list(buffer_ptr(&k->cert->critical),
+                   buffer_len(&k->cert->critical), pw,
+                   OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
+                   &cert_forced_command,
+                   &cert_source_address_done) == -1)
+                       return -1;
+               if (parse_option_list(buffer_ptr(&k->cert->extensions),
+                   buffer_len(&k->cert->extensions), pw,
+                   OPTIONS_EXTENSIONS, 1,
+                   &cert_no_port_forwarding_flag,
+                   &cert_no_agent_forwarding_flag,
+                   &cert_no_x11_forwarding_flag,
+                   &cert_no_pty_flag,
+                   &cert_no_user_rc,
+                   NULL, NULL) == -1)
+                       return -1;
+       }
+
+       no_port_forwarding_flag |= cert_no_port_forwarding_flag;
+       no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
+       no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
+       no_pty_flag |= cert_no_pty_flag;
+       no_user_rc |= cert_no_user_rc;
+       /* CA-specified forced command supersedes key option */
+       if (cert_forced_command != NULL) {
+               if (forced_command != NULL)
+                       xfree(forced_command);
+               forced_command = cert_forced_command;
+       }
+       return 0;
+}
+
diff --git a/auth-options.h b/auth-options.h
new file mode 100644 (file)
index 0000000..7455c94
--- /dev/null
@@ -0,0 +1,40 @@
+/* $OpenBSD: auth-options.h,v 1.20 2010/05/07 11:30:29 djm 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 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 int no_user_rc;
+extern char *forced_command;
+extern struct envstring *custom_environment;
+extern int forced_tun_device;
+extern int key_is_cert_authority;
+extern char *authorized_principals;
+
+int    auth_parse_options(struct passwd *, char *, char *, u_long);
+void   auth_clear_options(void);
+int    auth_cert_options(Key *, struct passwd *);
+
+#endif
diff --git a/auth-pam.c b/auth-pam.c
new file mode 100644 (file)
index 0000000..675006e
--- /dev/null
@@ -0,0 +1,1221 @@
+/*-
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * NAI Labs, the Security Research Division of Network Associates, Inc.
+ * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
+ * DARPA CHATS research program.
+ *
+ * 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 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 AUTHOR 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.
+ */
+/*
+ * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org>
+ * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF 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.
+ */
+
+/* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef USE_PAM
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined (HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+/* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
+#ifdef PAM_SUN_CODEBASE
+# define sshpam_const          /* Solaris, HP-UX, AIX */
+#else
+# define sshpam_const  const   /* LinuxPAM, OpenPAM */
+#endif
+
+/* Ambiguity in spec: is it an array of pointers or a pointer to an array? */
+#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
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-pam.h"
+#include "canohost.h"
+#include "log.h"
+#include "msg.h"
+#include "packet.h"
+#include "misc.h"
+#include "servconf.h"
+#include "ssh2.h"
+#include "auth-options.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+extern ServerOptions options;
+extern Buffer loginmsg;
+extern int compat20;
+extern u_int utmp_len;
+
+/* so we don't silently change behaviour */
+#ifdef USE_POSIX_THREADS
+# error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
+#endif
+
+/*
+ * Formerly known as USE_POSIX_THREADS, using this is completely unsupported
+ * and generally a bad idea.  Use at own risk and do not expect support if
+ * this breaks.
+ */
+#ifdef UNSUPPORTED_POSIX_THREADS_HACK
+#include <pthread.h>
+/*
+ * Avoid namespace clash when *not* using pthreads for systems *with*
+ * pthreads, which unconditionally define pthread_t via sys/types.h
+ * (e.g. Linux)
+ */
+typedef pthread_t sp_pthread_t;
+#else
+typedef pid_t sp_pthread_t;
+#endif
+
+struct pam_ctxt {
+       sp_pthread_t     pam_thread;
+       int              pam_psock;
+       int              pam_csock;
+       int              pam_done;
+};
+
+static void sshpam_free_ctx(void *);
+static struct pam_ctxt *cleanup_ctxt;
+
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
+/*
+ * Simulate threads with processes.
+ */
+
+static int sshpam_thread_status = -1;
+static mysig_t sshpam_oldsig;
+
+static void
+sshpam_sigchld_handler(int sig)
+{
+       signal(SIGCHLD, SIG_DFL);
+       if (cleanup_ctxt == NULL)
+               return; /* handler called after PAM cleanup, shouldn't happen */
+       if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
+           <= 0) {
+               /* PAM thread has not exitted, privsep slave must have */
+               kill(cleanup_ctxt->pam_thread, SIGTERM);
+               if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0)
+                   <= 0)
+                       return; /* could not wait */
+       }
+       if (WIFSIGNALED(sshpam_thread_status) &&
+           WTERMSIG(sshpam_thread_status) == SIGTERM)
+               return; /* terminated by pthread_cancel */
+       if (!WIFEXITED(sshpam_thread_status))
+               sigdie("PAM: authentication thread exited unexpectedly");
+       if (WEXITSTATUS(sshpam_thread_status) != 0)
+               sigdie("PAM: authentication thread exited uncleanly");
+}
+
+/* ARGSUSED */
+static void
+pthread_exit(void *value)
+{
+       _exit(0);
+}
+
+/* ARGSUSED */
+static int
+pthread_create(sp_pthread_t *thread, const void *attr,
+    void *(*thread_start)(void *), void *arg)
+{
+       pid_t pid;
+       struct pam_ctxt *ctx = arg;
+
+       sshpam_thread_status = -1;
+       switch ((pid = fork())) {
+       case -1:
+               error("fork(): %s", strerror(errno));
+               return (-1);
+       case 0:
+               close(ctx->pam_psock);
+               ctx->pam_psock = -1;
+               thread_start(arg);
+               _exit(1);
+       default:
+               *thread = pid;
+               close(ctx->pam_csock);
+               ctx->pam_csock = -1;
+               sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
+               return (0);
+       }
+}
+
+static int
+pthread_cancel(sp_pthread_t thread)
+{
+       signal(SIGCHLD, sshpam_oldsig);
+       return (kill(thread, SIGTERM));
+}
+
+/* ARGSUSED */
+static int
+pthread_join(sp_pthread_t thread, void **value)
+{
+       int status;
+
+       if (sshpam_thread_status != -1)
+               return (sshpam_thread_status);
+       signal(SIGCHLD, sshpam_oldsig);
+       waitpid(thread, &status, 0);
+       return (status);
+}
+#endif
+
+
+static pam_handle_t *sshpam_handle = NULL;
+static int sshpam_err = 0;
+static int sshpam_authenticated = 0;
+static int sshpam_session_open = 0;
+static int sshpam_cred_established = 0;
+static int sshpam_account_status = -1;
+static char **sshpam_env = NULL;
+static Authctxt *sshpam_authctxt = NULL;
+static const char *sshpam_password = NULL;
+static char badpw[] = "\b\n\r\177INCORRECT";
+
+/* Some PAM implementations don't implement this */
+#ifndef HAVE_PAM_GETENVLIST
+static char **
+pam_getenvlist(pam_handle_t *pamh)
+{
+       /*
+        * XXX - If necessary, we can still support envrionment passing
+        * for platforms without pam_getenvlist by searching for known
+        * env vars (e.g. KRB5CCNAME) from the PAM environment.
+        */
+        return NULL;
+}
+#endif
+
+/*
+ * Some platforms, notably Solaris, do not enforce password complexity
+ * rules during pam_chauthtok() if the real uid of the calling process
+ * is 0, on the assumption that it's being called by "passwd" run by root.
+ * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
+ * the right thing.
+ */
+#ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
+static int
+sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
+{
+       int result;
+
+       if (sshpam_authctxt == NULL)
+               fatal("PAM: sshpam_authctxt not initialized");
+       if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
+               fatal("%s: setreuid failed: %s", __func__, strerror(errno));
+       result = pam_chauthtok(pamh, flags);
+       if (setreuid(0, -1) == -1)
+               fatal("%s: setreuid failed: %s", __func__, strerror(errno));
+       return result;
+}
+# define pam_chauthtok(a,b)    (sshpam_chauthtok_ruid((a), (b)))
+#endif
+
+void
+sshpam_password_change_required(int reqd)
+{
+       debug3("%s %d", __func__, reqd);
+       if (sshpam_authctxt == NULL)
+               fatal("%s: PAM authctxt not initialized", __func__);
+       sshpam_authctxt->force_pwchange = reqd;
+       if (reqd) {
+               no_port_forwarding_flag |= 2;
+               no_agent_forwarding_flag |= 2;
+               no_x11_forwarding_flag |= 2;
+       } else {
+               no_port_forwarding_flag &= ~2;
+               no_agent_forwarding_flag &= ~2;
+               no_x11_forwarding_flag &= ~2;
+       }
+}
+
+/* Import regular and PAM environment from subprocess */
+static void
+import_environments(Buffer *b)
+{
+       char *env;
+       u_int i, num_env;
+       int err;
+
+       debug3("PAM: %s entering", __func__);
+
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
+       /* Import variables set by do_pam_account */
+       sshpam_account_status = buffer_get_int(b);
+       sshpam_password_change_required(buffer_get_int(b));
+
+       /* Import environment from subprocess */
+       num_env = buffer_get_int(b);
+       if (num_env > 1024)
+               fatal("%s: received %u environment variables, expected <= 1024",
+                   __func__, num_env);
+       sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
+       debug3("PAM: num env strings %d", num_env);
+       for(i = 0; i < num_env; i++)
+               sshpam_env[i] = buffer_get_string(b, NULL);
+
+       sshpam_env[num_env] = NULL;
+
+       /* Import PAM environment from subprocess */
+       num_env = buffer_get_int(b);
+       debug("PAM: num PAM env strings %d", num_env);
+       for(i = 0; i < num_env; i++) {
+               env = buffer_get_string(b, NULL);
+
+#ifdef HAVE_PAM_PUTENV
+               /* Errors are not fatal here */
+               if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
+                       error("PAM: pam_putenv: %s",
+                           pam_strerror(sshpam_handle, sshpam_err));
+               }
+#endif
+       }
+#endif
+}
+
+/*
+ * Conversation function for authentication thread.
+ */
+static int
+sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
+    struct pam_response **resp, void *data)
+{
+       Buffer buffer;
+       struct pam_ctxt *ctxt;
+       struct pam_response *reply;
+       int i;
+
+       debug3("PAM: %s entering, %d messages", __func__, n);
+       *resp = NULL;
+
+       if (data == NULL) {
+               error("PAM: conversation function passed a null context");
+               return (PAM_CONV_ERR);
+       }
+       ctxt = data;
+       if (n <= 0 || n > PAM_MAX_NUM_MSG)
+               return (PAM_CONV_ERR);
+
+       if ((reply = calloc(n, sizeof(*reply))) == NULL)
+               return (PAM_CONV_ERR);
+
+       buffer_init(&buffer);
+       for (i = 0; i < n; ++i) {
+               switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
+               case PAM_PROMPT_ECHO_OFF:
+                       buffer_put_cstring(&buffer,
+                           PAM_MSG_MEMBER(msg, i, msg));
+                       if (ssh_msg_send(ctxt->pam_csock,
+                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                               goto fail;
+                       if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
+                               goto fail;
+                       if (buffer_get_char(&buffer) != PAM_AUTHTOK)
+                               goto fail;
+                       reply[i].resp = buffer_get_string(&buffer, NULL);
+                       break;
+               case PAM_PROMPT_ECHO_ON:
+                       buffer_put_cstring(&buffer,
+                           PAM_MSG_MEMBER(msg, i, msg));
+                       if (ssh_msg_send(ctxt->pam_csock,
+                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                               goto fail;
+                       if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
+                               goto fail;
+                       if (buffer_get_char(&buffer) != PAM_AUTHTOK)
+                               goto fail;
+                       reply[i].resp = buffer_get_string(&buffer, NULL);
+                       break;
+               case PAM_ERROR_MSG:
+                       buffer_put_cstring(&buffer,
+                           PAM_MSG_MEMBER(msg, i, msg));
+                       if (ssh_msg_send(ctxt->pam_csock,
+                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                               goto fail;
+                       break;
+               case PAM_TEXT_INFO:
+                       buffer_put_cstring(&buffer,
+                           PAM_MSG_MEMBER(msg, i, msg));
+                       if (ssh_msg_send(ctxt->pam_csock,
+                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                               goto fail;
+                       break;
+               default:
+                       goto fail;
+               }
+               buffer_clear(&buffer);
+       }
+       buffer_free(&buffer);
+       *resp = reply;
+       return (PAM_SUCCESS);
+
+ fail:
+       for(i = 0; i < n; i++) {
+               if (reply[i].resp != NULL)
+                       xfree(reply[i].resp);
+       }
+       xfree(reply);
+       buffer_free(&buffer);
+       return (PAM_CONV_ERR);
+}
+
+/*
+ * Authentication thread.
+ */
+static void *
+sshpam_thread(void *ctxtp)
+{
+       struct pam_ctxt *ctxt = ctxtp;
+       Buffer buffer;
+       struct pam_conv sshpam_conv;
+       int flags = (options.permit_empty_passwd == 0 ?
+           PAM_DISALLOW_NULL_AUTHTOK : 0);
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
+       extern char **environ;
+       char **env_from_pam;
+       u_int i;
+       const char *pam_user;
+       const char **ptr_pam_user = &pam_user;
+       char *tz = getenv("TZ");
+
+       pam_get_item(sshpam_handle, PAM_USER,
+           (sshpam_const void **)ptr_pam_user);
+
+       environ[0] = NULL;
+       if (tz != NULL)
+               if (setenv("TZ", tz, 1) == -1)
+                       error("PAM: could not set TZ environment: %s",
+                           strerror(errno));
+
+       if (sshpam_authctxt != NULL) {
+               setproctitle("%s [pam]",
+                   sshpam_authctxt->valid ? pam_user : "unknown");
+       }
+#endif
+
+       sshpam_conv.conv = sshpam_thread_conv;
+       sshpam_conv.appdata_ptr = ctxt;
+
+       if (sshpam_authctxt == NULL)
+               fatal("%s: PAM authctxt not initialized", __func__);
+
+       buffer_init(&buffer);
+       sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
+           (const void *)&sshpam_conv);
+       if (sshpam_err != PAM_SUCCESS)
+               goto auth_fail;
+       sshpam_err = pam_authenticate(sshpam_handle, flags);
+       if (sshpam_err != PAM_SUCCESS)
+               goto auth_fail;
+
+       if (compat20) {
+               if (!do_pam_account()) {
+                       sshpam_err = PAM_ACCT_EXPIRED;
+                       goto auth_fail;
+               }
+               if (sshpam_authctxt->force_pwchange) {
+                       sshpam_err = pam_chauthtok(sshpam_handle,
+                           PAM_CHANGE_EXPIRED_AUTHTOK);
+                       if (sshpam_err != PAM_SUCCESS)
+                               goto auth_fail;
+                       sshpam_password_change_required(0);
+               }
+       }
+
+       buffer_put_cstring(&buffer, "OK");
+
+#ifndef UNSUPPORTED_POSIX_THREADS_HACK
+       /* Export variables set by do_pam_account */
+       buffer_put_int(&buffer, sshpam_account_status);
+       buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
+
+       /* Export any environment strings set in child */
+       for(i = 0; environ[i] != NULL; i++)
+               ; /* Count */
+       buffer_put_int(&buffer, i);
+       for(i = 0; environ[i] != NULL; i++)
+               buffer_put_cstring(&buffer, environ[i]);
+
+       /* Export any environment strings set by PAM in child */
+       env_from_pam = pam_getenvlist(sshpam_handle);
+       for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
+               ; /* Count */
+       buffer_put_int(&buffer, i);
+       for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
+               buffer_put_cstring(&buffer, env_from_pam[i]);
+#endif /* UNSUPPORTED_POSIX_THREADS_HACK */
+
+       /* XXX - can't do much about an error here */
+       ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
+       buffer_free(&buffer);
+       pthread_exit(NULL);
+
+ auth_fail:
+       buffer_put_cstring(&buffer,
+           pam_strerror(sshpam_handle, sshpam_err));
+       /* XXX - can't do much about an error here */
+       if (sshpam_err == PAM_ACCT_EXPIRED)
+               ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
+       else
+               ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
+       buffer_free(&buffer);
+       pthread_exit(NULL);
+
+       return (NULL); /* Avoid warning for non-pthread case */
+}
+
+void
+sshpam_thread_cleanup(void)
+{
+       struct pam_ctxt *ctxt = cleanup_ctxt;
+
+       debug3("PAM: %s entering", __func__);
+       if (ctxt != NULL && ctxt->pam_thread != 0) {
+               pthread_cancel(ctxt->pam_thread);
+               pthread_join(ctxt->pam_thread, NULL);
+               close(ctxt->pam_psock);
+               close(ctxt->pam_csock);
+               memset(ctxt, 0, sizeof(*ctxt));
+               cleanup_ctxt = NULL;
+       }
+}
+
+static int
+sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
+    struct pam_response **resp, void *data)
+{
+       debug3("PAM: %s entering, %d messages", __func__, n);
+       return (PAM_CONV_ERR);
+}
+
+static struct pam_conv null_conv = { sshpam_null_conv, NULL };
+
+static int
+sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
+    struct pam_response **resp, void *data)
+{
+       struct pam_response *reply;
+       int i;
+       size_t len;
+
+       debug3("PAM: %s called with %d messages", __func__, n);
+       *resp = NULL;
+
+       if (n <= 0 || n > PAM_MAX_NUM_MSG)
+               return (PAM_CONV_ERR);
+
+       if ((reply = calloc(n, sizeof(*reply))) == NULL)
+               return (PAM_CONV_ERR);
+
+       for (i = 0; i < n; ++i) {
+               switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
+               case PAM_ERROR_MSG:
+               case PAM_TEXT_INFO:
+                       len = strlen(PAM_MSG_MEMBER(msg, i, msg));
+                       buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
+                       buffer_append(&loginmsg, "\n", 1 );
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       *resp = reply;
+       return (PAM_SUCCESS);
+
+ fail:
+       for(i = 0; i < n; i++) {
+               if (reply[i].resp != NULL)
+                       xfree(reply[i].resp);
+       }
+       xfree(reply);
+       return (PAM_CONV_ERR);
+}
+
+static struct pam_conv store_conv = { sshpam_store_conv, NULL };
+
+void
+sshpam_cleanup(void)
+{
+       if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor()))
+               return;
+       debug("PAM: cleanup");
+       pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
+       if (sshpam_session_open) {
+               debug("PAM: closing session");
+               pam_close_session(sshpam_handle, PAM_SILENT);
+               sshpam_session_open = 0;
+       }
+       if (sshpam_cred_established) {
+               debug("PAM: deleting credentials");
+               pam_setcred(sshpam_handle, PAM_DELETE_CRED);
+               sshpam_cred_established = 0;
+       }
+       sshpam_authenticated = 0;
+       pam_end(sshpam_handle, sshpam_err);
+       sshpam_handle = NULL;
+}
+
+static int
+sshpam_init(Authctxt *authctxt)
+{
+       extern char *__progname;
+       const char *pam_rhost, *pam_user, *user = authctxt->user;
+       const char **ptr_pam_user = &pam_user;
+
+       if (sshpam_handle != NULL) {
+               /* We already have a PAM context; check if the user matches */
+               sshpam_err = pam_get_item(sshpam_handle,
+                   PAM_USER, (sshpam_const void **)ptr_pam_user);
+               if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
+                       return (0);
+               pam_end(sshpam_handle, sshpam_err);
+               sshpam_handle = NULL;
+       }
+       debug("PAM: initializing for \"%s\"", user);
+       sshpam_err =
+           pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
+       sshpam_authctxt = authctxt;
+
+       if (sshpam_err != PAM_SUCCESS) {
+               pam_end(sshpam_handle, sshpam_err);
+               sshpam_handle = NULL;
+               return (-1);
+       }
+       pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns);
+       debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
+       sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
+       if (sshpam_err != PAM_SUCCESS) {
+               pam_end(sshpam_handle, sshpam_err);
+               sshpam_handle = NULL;
+               return (-1);
+       }
+#ifdef PAM_TTY_KLUDGE
+       /*
+        * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
+        * sshd doesn't set the tty until too late in the auth process and
+        * may not even set one (for tty-less connections)
+        */
+       debug("PAM: setting PAM_TTY to \"ssh\"");
+       sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
+       if (sshpam_err != PAM_SUCCESS) {
+               pam_end(sshpam_handle, sshpam_err);
+               sshpam_handle = NULL;
+               return (-1);
+       }
+#endif
+       return (0);
+}
+
+static void *
+sshpam_init_ctx(Authctxt *authctxt)
+{
+       struct pam_ctxt *ctxt;
+       int socks[2];
+
+       debug3("PAM: %s entering", __func__);
+       /*
+        * Refuse to start if we don't have PAM enabled or do_pam_account
+        * has previously failed.
+        */
+       if (!options.use_pam || sshpam_account_status == 0)
+               return NULL;
+
+       /* Initialize PAM */
+       if (sshpam_init(authctxt) == -1) {
+               error("PAM: initialization failed");
+               return (NULL);
+       }
+
+       ctxt = xcalloc(1, sizeof *ctxt);
+
+       /* Start the authentication thread */
+       if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
+               error("PAM: failed create sockets: %s", strerror(errno));
+               xfree(ctxt);
+               return (NULL);
+       }
+       ctxt->pam_psock = socks[0];
+       ctxt->pam_csock = socks[1];
+       if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
+               error("PAM: failed to start authentication thread: %s",
+                   strerror(errno));
+               close(socks[0]);
+               close(socks[1]);
+               xfree(ctxt);
+               return (NULL);
+       }
+       cleanup_ctxt = ctxt;
+       return (ctxt);
+}
+
+static int
+sshpam_query(void *ctx, char **name, char **info,
+    u_int *num, char ***prompts, u_int **echo_on)
+{
+       Buffer buffer;
+       struct pam_ctxt *ctxt = ctx;
+       size_t plen;
+       u_char type;
+       char *msg;
+       size_t len, mlen;
+
+       debug3("PAM: %s entering", __func__);
+       buffer_init(&buffer);
+       *name = xstrdup("");
+       *info = xstrdup("");
+       *prompts = xmalloc(sizeof(char *));
+       **prompts = NULL;
+       plen = 0;
+       *echo_on = xmalloc(sizeof(u_int));
+       while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
+               type = buffer_get_char(&buffer);
+               msg = buffer_get_string(&buffer, NULL);
+               mlen = strlen(msg);
+               switch (type) {
+               case PAM_PROMPT_ECHO_ON:
+               case PAM_PROMPT_ECHO_OFF:
+                       *num = 1;
+                       len = plen + mlen + 1;
+                       **prompts = xrealloc(**prompts, 1, len);
+                       strlcpy(**prompts + plen, msg, len - plen);
+                       plen += mlen;
+                       **echo_on = (type == PAM_PROMPT_ECHO_ON);
+                       xfree(msg);
+                       return (0);
+               case PAM_ERROR_MSG:
+               case PAM_TEXT_INFO:
+                       /* accumulate messages */
+                       len = plen + mlen + 2;
+                       **prompts = xrealloc(**prompts, 1, len);
+                       strlcpy(**prompts + plen, msg, len - plen);
+                       plen += mlen;
+                       strlcat(**prompts + plen, "\n", len - plen);
+                       plen++;
+                       xfree(msg);
+                       break;
+               case PAM_ACCT_EXPIRED:
+                       sshpam_account_status = 0;
+                       /* FALLTHROUGH */
+               case PAM_AUTH_ERR:
+                       debug3("PAM: %s", pam_strerror(sshpam_handle, type));
+                       if (**prompts != NULL && strlen(**prompts) != 0) {
+                               *info = **prompts;
+                               **prompts = NULL;
+                               *num = 0;
+                               **echo_on = 0;
+                               ctxt->pam_done = -1;
+                               xfree(msg);
+                               return 0;
+                       }
+                       /* FALLTHROUGH */
+               case PAM_SUCCESS:
+                       if (**prompts != NULL) {
+                               /* drain any accumulated messages */
+                               debug("PAM: %s", **prompts);
+                               buffer_append(&loginmsg, **prompts,
+                                   strlen(**prompts));
+                               xfree(**prompts);
+                               **prompts = NULL;
+                       }
+                       if (type == PAM_SUCCESS) {
+                               if (!sshpam_authctxt->valid ||
+                                   (sshpam_authctxt->pw->pw_uid == 0 &&
+                                   options.permit_root_login != PERMIT_YES))
+                                       fatal("Internal error: PAM auth "
+                                           "succeeded when it should have "
+                                           "failed");
+                               import_environments(&buffer);
+                               *num = 0;
+                               **echo_on = 0;
+                               ctxt->pam_done = 1;
+                               xfree(msg);
+                               return (0);
+                       }
+                       error("PAM: %s for %s%.100s from %.100s", msg,
+                           sshpam_authctxt->valid ? "" : "illegal user ",
+                           sshpam_authctxt->user,
+                           get_remote_name_or_ip(utmp_len, options.use_dns));
+                       /* FALLTHROUGH */
+               default:
+                       *num = 0;
+                       **echo_on = 0;
+                       xfree(msg);
+                       ctxt->pam_done = -1;
+                       return (-1);
+               }
+       }
+       return (-1);
+}
+
+/* XXX - see also comment in auth-chall.c:verify_response */
+static int
+sshpam_respond(void *ctx, u_int num, char **resp)
+{
+       Buffer buffer;
+       struct pam_ctxt *ctxt = ctx;
+
+       debug2("PAM: %s entering, %u responses", __func__, num);
+       switch (ctxt->pam_done) {
+       case 1:
+               sshpam_authenticated = 1;
+               return (0);
+       case 0:
+               break;
+       default:
+               return (-1);
+       }
+       if (num != 1) {
+               error("PAM: expected one response, got %u", num);
+               return (-1);
+       }
+       buffer_init(&buffer);
+       if (sshpam_authctxt->valid &&
+           (sshpam_authctxt->pw->pw_uid != 0 ||
+           options.permit_root_login == PERMIT_YES))
+               buffer_put_cstring(&buffer, *resp);
+       else
+               buffer_put_cstring(&buffer, badpw);
+       if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
+               buffer_free(&buffer);
+               return (-1);
+       }
+       buffer_free(&buffer);
+       return (1);
+}
+
+static void
+sshpam_free_ctx(void *ctxtp)
+{
+       struct pam_ctxt *ctxt = ctxtp;
+
+       debug3("PAM: %s entering", __func__);
+       sshpam_thread_cleanup();
+       xfree(ctxt);
+       /*
+        * We don't call sshpam_cleanup() here because we may need the PAM
+        * handle at a later stage, e.g. when setting up a session.  It's
+        * still on the cleanup list, so pam_end() *will* be called before
+        * the server process terminates.
+        */
+}
+
+KbdintDevice sshpam_device = {
+       "pam",
+       sshpam_init_ctx,
+       sshpam_query,
+       sshpam_respond,
+       sshpam_free_ctx
+};
+
+KbdintDevice mm_sshpam_device = {
+       "pam",
+       mm_sshpam_init_ctx,
+       mm_sshpam_query,
+       mm_sshpam_respond,
+       mm_sshpam_free_ctx
+};
+
+/*
+ * This replaces auth-pam.c
+ */
+void
+start_pam(Authctxt *authctxt)
+{
+       if (!options.use_pam)
+               fatal("PAM: initialisation requested when UsePAM=no");
+
+       if (sshpam_init(authctxt) == -1)
+               fatal("PAM: initialisation failed");
+}
+
+void
+finish_pam(void)
+{
+       sshpam_cleanup();
+}
+
+u_int
+do_pam_account(void)
+{
+       debug("%s: called", __func__);
+       if (sshpam_account_status != -1)
+               return (sshpam_account_status);
+
+       sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
+       debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
+           pam_strerror(sshpam_handle, sshpam_err));
+
+       if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
+               sshpam_account_status = 0;
+               return (sshpam_account_status);
+       }
+
+       if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
+               sshpam_password_change_required(1);
+
+       sshpam_account_status = 1;
+       return (sshpam_account_status);
+}
+
+void
+do_pam_set_tty(const char *tty)
+{
+       if (tty != NULL) {
+               debug("PAM: setting PAM_TTY to \"%s\"", tty);
+               sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
+               if (sshpam_err != PAM_SUCCESS)
+                       fatal("PAM: failed to set PAM_TTY: %s",
+                           pam_strerror(sshpam_handle, sshpam_err));
+       }
+}
+
+void
+do_pam_setcred(int init)
+{
+       sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
+           (const void *)&store_conv);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: failed to set PAM_CONV: %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       if (init) {
+               debug("PAM: establishing credentials");
+               sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
+       } else {
+               debug("PAM: reinitializing credentials");
+               sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
+       }
+       if (sshpam_err == PAM_SUCCESS) {
+               sshpam_cred_established = 1;
+               return;
+       }
+       if (sshpam_authenticated)
+               fatal("PAM: pam_setcred(): %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       else
+               debug("PAM: pam_setcred(): %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+}
+
+static int
+sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
+    struct pam_response **resp, void *data)
+{
+       char input[PAM_MAX_MSG_SIZE];
+       struct pam_response *reply;
+       int i;
+
+       debug3("PAM: %s called with %d messages", __func__, n);
+
+       *resp = NULL;
+
+       if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
+               return (PAM_CONV_ERR);
+
+       if ((reply = calloc(n, sizeof(*reply))) == NULL)
+               return (PAM_CONV_ERR);
+
+       for (i = 0; i < n; ++i) {
+               switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
+               case PAM_PROMPT_ECHO_OFF:
+                       reply[i].resp =
+                           read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
+                           RP_ALLOW_STDIN);
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               case PAM_PROMPT_ECHO_ON:
+                       fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
+                       if (fgets(input, sizeof input, stdin) == NULL)
+                               input[0] = '\0';
+                       if ((reply[i].resp = strdup(input)) == NULL)
+                               goto fail;
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               case PAM_ERROR_MSG:
+               case PAM_TEXT_INFO:
+                       fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       *resp = reply;
+       return (PAM_SUCCESS);
+
+ fail:
+       for(i = 0; i < n; i++) {
+               if (reply[i].resp != NULL)
+                       xfree(reply[i].resp);
+       }
+       xfree(reply);
+       return (PAM_CONV_ERR);
+}
+
+static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
+
+/*
+ * XXX this should be done in the authentication phase, but ssh1 doesn't
+ * support that
+ */
+void
+do_pam_chauthtok(void)
+{
+       if (use_privsep)
+               fatal("Password expired (unable to change with privsep)");
+       sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
+           (const void *)&tty_conv);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: failed to set PAM_CONV: %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       debug("PAM: changing password");
+       sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: pam_chauthtok(): %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+}
+
+void
+do_pam_session(void)
+{
+       debug3("PAM: opening session");
+       sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
+           (const void *)&store_conv);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: failed to set PAM_CONV: %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       sshpam_err = pam_open_session(sshpam_handle, 0);
+       if (sshpam_err == PAM_SUCCESS)
+               sshpam_session_open = 1;
+       else {
+               sshpam_session_open = 0;
+               disable_forwarding();
+               error("PAM: pam_open_session(): %s",
+                   pam_strerror(sshpam_handle, sshpam_err));
+       }
+
+}
+
+int
+is_pam_session_open(void)
+{
+       return sshpam_session_open;
+}
+
+/*
+ * Set a PAM environment string. We need to do this so that the session
+ * modules can handle things like Kerberos/GSI credentials that appear
+ * during the ssh authentication process.
+ */
+int
+do_pam_putenv(char *name, char *value)
+{
+       int ret = 1;
+#ifdef HAVE_PAM_PUTENV
+       char *compound;
+       size_t len;
+
+       len = strlen(name) + strlen(value) + 2;
+       compound = xmalloc(len);
+
+       snprintf(compound, len, "%s=%s", name, value);
+       ret = pam_putenv(sshpam_handle, compound);
+       xfree(compound);
+#endif
+
+       return (ret);
+}
+
+char **
+fetch_pam_child_environment(void)
+{
+       return sshpam_env;
+}
+
+char **
+fetch_pam_environment(void)
+{
+       return (pam_getenvlist(sshpam_handle));
+}
+
+void
+free_pam_environment(char **env)
+{
+       char **envp;
+
+       if (env == NULL)
+               return;
+
+       for (envp = env; *envp; envp++)
+               xfree(*envp);
+       xfree(env);
+}
+
+/*
+ * "Blind" conversation function for password authentication.  Assumes that
+ * echo-off prompts are for the password and stores messages for later
+ * display.
+ */
+static int
+sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
+    struct pam_response **resp, void *data)
+{
+       struct pam_response *reply;
+       int i;
+       size_t len;
+
+       debug3("PAM: %s called with %d messages", __func__, n);
+
+       *resp = NULL;
+
+       if (n <= 0 || n > PAM_MAX_NUM_MSG)
+               return (PAM_CONV_ERR);
+
+       if ((reply = calloc(n, sizeof(*reply))) == NULL)
+               return (PAM_CONV_ERR);
+
+       for (i = 0; i < n; ++i) {
+               switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
+               case PAM_PROMPT_ECHO_OFF:
+                       if (sshpam_password == NULL)
+                               goto fail;
+                       if ((reply[i].resp = strdup(sshpam_password)) == NULL)
+                               goto fail;
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               case PAM_ERROR_MSG:
+               case PAM_TEXT_INFO:
+                       len = strlen(PAM_MSG_MEMBER(msg, i, msg));
+                       if (len > 0) {
+                               buffer_append(&loginmsg,
+                                   PAM_MSG_MEMBER(msg, i, msg), len);
+                               buffer_append(&loginmsg, "\n", 1);
+                       }
+                       if ((reply[i].resp = strdup("")) == NULL)
+                               goto fail;
+                       reply[i].resp_retcode = PAM_SUCCESS;
+                       break;
+               default:
+                       goto fail;
+               }
+       }
+       *resp = reply;
+       return (PAM_SUCCESS);
+
+ fail:
+       for(i = 0; i < n; i++) {
+               if (reply[i].resp != NULL)
+                       xfree(reply[i].resp);
+       }
+       xfree(reply);
+       return (PAM_CONV_ERR);
+}
+
+static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
+
+/*
+ * Attempt password authentication via PAM
+ */
+int
+sshpam_auth_passwd(Authctxt *authctxt, const char *password)
+{
+       int flags = (options.permit_empty_passwd == 0 ?
+           PAM_DISALLOW_NULL_AUTHTOK : 0);
+
+       if (!options.use_pam || sshpam_handle == NULL)
+               fatal("PAM: %s called when PAM disabled or failed to "
+                   "initialise.", __func__);
+
+       sshpam_password = password;
+       sshpam_authctxt = authctxt;
+
+       /*
+        * If the user logging in is invalid, or is root but is not permitted
+        * by PermitRootLogin, use an invalid password to prevent leaking
+        * information via timing (eg if the PAM config has a delay on fail).
+        */
+       if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
+           options.permit_root_login != PERMIT_YES))
+               sshpam_password = badpw;
+
+       sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
+           (const void *)&passwd_conv);
+       if (sshpam_err != PAM_SUCCESS)
+               fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
+                   pam_strerror(sshpam_handle, sshpam_err));
+
+       sshpam_err = pam_authenticate(sshpam_handle, flags);
+       sshpam_password = NULL;
+       if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
+               debug("PAM: password authentication accepted for %.100s",
+                   authctxt->user);
+               return 1;
+       } else {
+               debug("PAM: password authentication failed for %.100s: %s",
+                   authctxt->valid ? authctxt->user : "an illegal user",
+                   pam_strerror(sshpam_handle, sshpam_err));
+               return 0;
+       }
+}
+#endif /* USE_PAM */
diff --git a/auth-pam.h b/auth-pam.h
new file mode 100644 (file)
index 0000000..a1a2b52
--- /dev/null
@@ -0,0 +1,50 @@
+/* $Id: auth-pam.h,v 1.27 2004/09/11 12:17:26 dtucker Exp $ */
+
+/*
+ * 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
+
+#if !defined(SSHD_PAM_SERVICE)
+# define SSHD_PAM_SERVICE              __progname
+#endif
+
+void start_pam(Authctxt *);
+void finish_pam(void);
+u_int do_pam_account(void);
+void do_pam_session(void);
+void do_pam_set_tty(const char *);
+void do_pam_setcred(int );
+void do_pam_chauthtok(void);
+int do_pam_putenv(char *, char *);
+char ** fetch_pam_environment(void);
+char ** fetch_pam_child_environment(void);
+void free_pam_environment(char **);
+void sshpam_thread_cleanup(void);
+void sshpam_cleanup(void);
+int sshpam_auth_passwd(Authctxt *, const char *);
+int is_pam_session_open(void);
+
+#endif /* USE_PAM */
diff --git a/auth-passwd.c b/auth-passwd.c
new file mode 100644 (file)
index 0000000..b1c6ce0
--- /dev/null
@@ -0,0 +1,214 @@
+/* $OpenBSD: auth-passwd.c,v 1.43 2007/09/21 08:15:29 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+
+extern Buffer loginmsg;
+extern ServerOptions options;
+
+#ifdef HAVE_LOGIN_CAP
+extern login_cap_t *lc;
+#endif
+
+
+#define DAY            (24L * 60 * 60) /* 1 day in seconds */
+#define TWO_WEEKS      (2L * 7 * DAY)  /* 2 weeks in seconds */
+
+void
+disable_forwarding(void)
+{
+       no_port_forwarding_flag = 1;
+       no_agent_forwarding_flag = 1;
+       no_x11_forwarding_flag = 1;
+}
+
+/*
+ * 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;
+       int result, ok = authctxt->valid;
+#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
+       static int expire_checked = 0;
+#endif
+
+#ifndef HAVE_CYGWIN
+       if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
+               ok = 0;
+#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 && ok;
+               /* Fall back to ordinary passwd authentication. */
+       }
+#endif
+#ifdef HAVE_CYGWIN
+       {
+               HANDLE hToken = cygwin_logon_user(pw, password);
+
+               if (hToken == INVALID_HANDLE_VALUE)
+                       return 0;
+               cygwin_set_impersonation_token(hToken);
+               return ok;
+       }
+#endif
+#ifdef USE_PAM
+       if (options.use_pam)
+               return (sshpam_auth_passwd(authctxt, password) && ok);
+#endif
+#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
+       if (!expire_checked) {
+               expire_checked = 1;
+               if (auth_shadow_pwexpired(authctxt))
+                       authctxt->force_pwchange = 1;
+       }
+#endif
+       result = sys_auth_passwd(authctxt, password);
+       if (authctxt->force_pwchange)
+               disable_forwarding();
+       return (result && ok);
+}
+
+#ifdef BSD_AUTH
+static void
+warn_expiry(Authctxt *authctxt, auth_session_t *as)
+{
+       char buf[256];
+       quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime;
+
+       pwwarntime = acwarntime = TWO_WEEKS;
+
+       pwtimeleft = auth_check_change(as);
+       actimeleft = auth_check_expire(as);
+#ifdef HAVE_LOGIN_CAP
+       if (authctxt->valid) {
+               pwwarntime = login_getcaptime(lc, "password-warn", TWO_WEEKS,
+                   TWO_WEEKS);
+               acwarntime = login_getcaptime(lc, "expire-warn", TWO_WEEKS,
+                   TWO_WEEKS);
+       }
+#endif
+       if (pwtimeleft != 0 && pwtimeleft < pwwarntime) {
+               daysleft = pwtimeleft / DAY + 1;
+               snprintf(buf, sizeof(buf),
+                   "Your password will expire in %lld day%s.\n",
+                   daysleft, daysleft == 1 ? "" : "s");
+               buffer_append(&loginmsg, buf, strlen(buf));
+       }
+       if (actimeleft != 0 && actimeleft < acwarntime) {
+               daysleft = actimeleft / DAY + 1;
+               snprintf(buf, sizeof(buf),
+                   "Your account will expire in %lld day%s.\n",
+                   daysleft, daysleft == 1 ? "" : "s");
+               buffer_append(&loginmsg, buf, strlen(buf));
+       }
+}
+
+int
+sys_auth_passwd(Authctxt *authctxt, const char *password)
+{
+       struct passwd *pw = authctxt->pw;
+       auth_session_t *as;
+       static int expire_checked = 0;
+
+       as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
+           (char *)password);
+       if (as == NULL)
+               return (0);
+       if (auth_getstate(as) & AUTH_PWEXPIRED) {
+               auth_close(as);
+               disable_forwarding();
+               authctxt->force_pwchange = 1;
+               return (1);
+       } else {
+               if (!expire_checked) {
+                       expire_checked = 1;
+                       warn_expiry(authctxt, as);
+               }
+               return (auth_close(as));
+       }
+}
+#elif !defined(CUSTOM_SYS_AUTH_PASSWD)
+int
+sys_auth_passwd(Authctxt *authctxt, const char *password)
+{
+       struct passwd *pw = authctxt->pw;
+       char *encrypted_password;
+
+       /* Just use the supplied fake password if authctxt is invalid */
+       char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
+
+       /* Check for users with no password. */
+       if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
+               return (1);
+
+       /* Encrypt the candidate password using the proper salt. */
+       encrypted_password = xcrypt(password,
+           (pw_password[0] && pw_password[1]) ? pw_password : "xx");
+
+       /*
+        * Authentication is accepted if the encrypted passwords
+        * are identical.
+        */
+       return (strcmp(encrypted_password, pw_password) == 0);
+}
+#endif
diff --git a/auth-rh-rsa.c b/auth-rh-rsa.c
new file mode 100644 (file)
index 0000000..b21a0f4
--- /dev/null
@@ -0,0 +1,103 @@
+/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <stdarg.h>
+
+#include "packet.h"
+#include "uidswap.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "key.h"
+#include "hostfile.h"
+#include "pathnames.h"
+#include "auth.h"
+#include "canohost.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+/* import */
+extern ServerOptions options;
+
+int
+auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
+    Key *client_host_key)
+{
+       HostStatus host_status;
+
+       if (auth_key_is_revoked(client_host_key))
+               return 0;
+
+       /* Check if we would accept it using rhosts authentication. */
+       if (!auth_rhosts(pw, cuser))
+               return 0;
+
+       host_status = check_key_in_hostfiles(pw, client_host_key,
+           chost, _PATH_SSH_SYSTEM_HOSTFILE,
+           options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
+
+       return (host_status == HOST_OK);
+}
+
+/*
+ * 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(Authctxt *authctxt, char *cuser, Key *client_host_key)
+{
+       char *chost;
+       struct passwd *pw = authctxt->pw;
+
+       debug("Trying rhosts with RSA host authentication for client user %.100s",
+           cuser);
+
+       if (!authctxt->valid || client_host_key == NULL ||
+           client_host_key->rsa == NULL)
+               return 0;
+
+       chost = (char *)get_canonical_hostname(options.use_dns);
+       debug("Rhosts RSA authentication: canonical host %.900s", chost);
+
+       if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) {
+               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)) {
+               logit("Client on %.800s failed to respond correctly to host authentication.",
+                   chost);
+               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, cuser, chost);
+       packet_send_debug("Rhosts with RSA host authentication accepted.");
+       return 1;
+}
diff --git a/auth-rhosts.c b/auth-rhosts.c
new file mode 100644 (file)
index 0000000..06ae7f0
--- /dev/null
@@ -0,0 +1,321 @@
+/* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_NETGROUP_H
+# include <netgroup.h>
+#endif
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "packet.h"
+#include "buffer.h"
+#include "uidswap.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "misc.h"
+
+/* import */
+extern ServerOptions options;
+extern int use_privsep;
+
+/*
+ * 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. */
+       int fd;
+       struct stat st;
+
+       /* Open the .rhosts file, deny if unreadable */
+       if ((fd = open(filename, O_RDONLY|O_NONBLOCK)) == -1)
+               return 0;
+       if (fstat(fd, &st) == -1) {
+               close(fd);
+               return 0;
+       }
+       if (!S_ISREG(st.st_mode)) {
+               logit("User %s hosts file %s is not a regular file",
+                   server_user, filename);
+               close(fd);
+               return 0;
+       }
+       unset_nonblock(fd);
+       if ((f = fdopen(fd, "r")) == NULL) {
+               close(fd);
+               return 0;
+       }
+       while (fgets(buf, sizeof(buf), f)) {
+               /* All three must be at least as big as buf to avoid overflows. */
+               char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp;
+               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, "%1023s %1023s %1023s", hostbuf, userbuf,
+                   dummy)) {
+               case 0:
+                       auth_debug_add("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:
+                       auth_debug_add("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 '-'. */
+                       auth_debug_add("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) {
+                       auth_debug_add("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;
+
+       hostname = get_canonical_hostname(options.use_dns);
+       ipaddr = get_remote_ipaddr();
+       return auth_rhosts2(pw, client_user, hostname, ipaddr);
+}
+
+static int
+auth_rhosts2_raw(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);
+
+       /* 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)) {
+                       auth_debug_add("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)) {
+                       auth_debug_add("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) {
+               logit("Rhosts authentication refused for %.100s: "
+                   "no home directory %.200s", pw->pw_name, pw->pw_dir);
+               auth_debug_add("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)) {
+               logit("Rhosts authentication refused for %.100s: "
+                   "bad ownership or modes for home directory.", pw->pw_name);
+               auth_debug_add("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)) {
+                       logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
+                           pw->pw_name, buf);
+                       auth_debug_add("Bad file modes for %.200s", buf);
+                       continue;
+               }
+               /* Check if we have been configured to ignore .rhosts and .shosts files. */
+               if (options.ignore_rhosts) {
+                       auth_debug_add("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)) {
+                       auth_debug_add("Accepted by %.100s.",
+                           rhosts_files[rhosts_file_index]);
+                       /* Restore the privileged uid. */
+                       restore_uid();
+                       auth_debug_add("Accepted host %s ip %s client_user %s server_user %s",
+                               hostname, ipaddr, client_user, pw->pw_name);
+                       return 1;
+               }
+       }
+
+       /* Restore the privileged uid. */
+       restore_uid();
+       return 0;
+}
+
+int
+auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
+    const char *ipaddr)
+{
+       return auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
+}
diff --git a/auth-rsa.c b/auth-rsa.c
new file mode 100644 (file)
index 0000000..4edaab0
--- /dev/null
@@ -0,0 +1,329 @@
+/* $OpenBSD: auth-rsa.c,v 1.79 2010/12/03 23:55:27 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <openssl/rsa.h>
+#include <openssl/md5.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "packet.h"
+#include "ssh1.h"
+#include "uidswap.h"
+#include "match.h"
+#include "buffer.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "key.h"
+#include "auth-options.h"
+#include "hostfile.h"
+#include "auth.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "ssh.h"
+#include "misc.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 SSH_MAX_PUBKEY_BYTES characters.  See sshd(8) for a
+ * description of the options.
+ */
+
+BIGNUM *
+auth_rsa_generate_challenge(Key *key)
+{
+       BIGNUM *challenge;
+       BN_CTX *ctx;
+
+       if ((challenge = BN_new()) == NULL)
+               fatal("auth_rsa_generate_challenge: BN_new() failed");
+       /* Generate a random challenge. */
+       if (BN_rand(challenge, 256, 0, 0) == 0)
+               fatal("auth_rsa_generate_challenge: BN_rand failed");
+       if ((ctx = BN_CTX_new()) == NULL)
+               fatal("auth_rsa_generate_challenge: BN_CTX_new failed");
+       if (BN_mod(challenge, challenge, key->rsa->n, ctx) == 0)
+               fatal("auth_rsa_generate_challenge: BN_mod failed");
+       BN_CTX_free(ctx);
+
+       return challenge;
+}
+
+int
+auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
+{
+       u_char buf[32], mdbuf[16];
+       MD5_CTX md;
+       int len;
+
+       /* don't allow short keys */
+       if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+               error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits",
+                   BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
+               return (0);
+       }
+
+       /* The response is MD5 of decrypted challenge plus session id. */
+       len = BN_num_bytes(challenge);
+       if (len <= 0 || len > 32)
+               fatal("auth_rsa_verify_response: 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);
+
+       /* Verify that the response is the original challenge. */
+       if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
+               /* Wrong answer. */
+               return (0);
+       }
+       /* Correct answer. */
+       return (1);
+}
+
+/*
+ * 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(Key *key)
+{
+       BIGNUM *challenge, *encrypted_challenge;
+       u_char response[16];
+       int i, success;
+
+       if ((encrypted_challenge = BN_new()) == NULL)
+               fatal("auth_rsa_challenge_dialog: BN_new() failed");
+
+       challenge = PRIVSEP(auth_rsa_generate_challenge(key));
+
+       /* Encrypt the challenge with the public key. */
+       rsa_public_encrypt(encrypted_challenge, challenge, key->rsa);
+
+       /* 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(SSH_CMSG_AUTH_RSA_RESPONSE);
+       for (i = 0; i < 16; i++)
+               response[i] = (u_char)packet_get_char();
+       packet_check_eom();
+
+       success = PRIVSEP(auth_rsa_verify_response(key, challenge, response));
+       BN_clear_free(challenge);
+       return (success);
+}
+
+/*
+ * check if there's user key matching client_n,
+ * return key if login is allowed, NULL otherwise
+ */
+
+int
+auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
+{
+       char line[SSH_MAX_PUBKEY_BYTES], *file;
+       int allowed = 0;
+       u_int bits;
+       FILE *f;
+       u_long linenum = 0;
+       Key *key;
+
+       /* 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);
+       f = auth_openkeyfile(file, pw, options.strict_modes);
+       if (!f) {
+               xfree(file);
+               restore_uid();
+               return (0);
+       }
+
+       /* Flag indicating whether the key is allowed. */
+       allowed = 0;
+
+       key = key_new(KEY_RSA1);
+
+       /*
+        * 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 (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+               char *cp;
+               char *key_options;
+               int keybits;
+
+               /* 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;
+                       key_options = cp;
+                       for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
+                               if (*cp == '\\' && cp[1] == '"')
+                                       cp++;   /* Skip both */
+                               else if (*cp == '"')
+                                       quoted = !quoted;
+                       }
+               } else
+                       key_options = NULL;
+
+               /* Parse the key from the line. */
+               if (hostfile_read_key(&cp, &bits, key) == 0) {
+                       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(key->rsa->n, client_n) != 0)
+                       continue;
+
+               /* check the real bits  */
+               keybits = BN_num_bits(key->rsa->n);
+               if (keybits < 0 || bits != (u_int)keybits)
+                       logit("Warning: %s, line %lu: keysize mismatch: "
+                           "actual %d vs. announced %d.",
+                           file, linenum, BN_num_bits(key->rsa->n), bits);
+
+               /* Never accept a revoked key */
+               if (auth_key_is_revoked(key))
+                       break;
+
+               /* 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, key_options, file, linenum))
+                       continue;
+               if (key_is_cert_authority)
+                       continue;
+               /* break out, this key is allowed */
+               allowed = 1;
+               break;
+       }
+
+       /* Restore the privileged uid. */
+       restore_uid();
+
+       /* Close the file. */
+       xfree(file);
+       fclose(f);
+
+       /* return key if allowed */
+       if (allowed && rkey != NULL)
+               *rkey = key;
+       else
+               key_free(key);
+       return (allowed);
+}
+
+/*
+ * 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(Authctxt *authctxt, BIGNUM *client_n)
+{
+       Key *key;
+       char *fp;
+       struct passwd *pw = authctxt->pw;
+
+       /* no user given */
+       if (!authctxt->valid)
+               return 0;
+
+       if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) {
+               auth_clear_options();
+               return (0);
+       }
+
+       /* Perform the challenge-response dialog for this key. */
+       if (!auth_rsa_challenge_dialog(key)) {
+               /* Wrong response. */
+               verbose("Wrong response to RSA authentication challenge.");
+               packet_send_debug("Wrong response to RSA authentication challenge.");
+               /*
+                * Break out of the loop. Otherwise we might send
+                * another challenge and break the protocol.
+                */
+               key_free(key);
+               return (0);
+       }
+       /*
+        * 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.
+        */
+       fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+       verbose("Found matching %s key: %s",
+           key_type(key), fp);
+       xfree(fp);
+       key_free(key);
+
+       packet_send_debug("RSA authentication accepted.");
+       return (1);
+}
diff --git a/auth-shadow.c b/auth-shadow.c
new file mode 100644 (file)
index 0000000..2190916
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.  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"
+
+#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
+#include <shadow.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "buffer.h"
+#include "log.h"
+
+#ifdef DAY
+# undef DAY
+#endif
+#define DAY    (24L * 60 * 60) /* 1 day in seconds */
+
+extern Buffer loginmsg;
+
+/*
+ * For the account and password expiration functions, we assume the expiry
+ * occurs the day after the day specified.
+ */
+
+/*
+ * Check if specified account is expired.  Returns 1 if account is expired,
+ * 0 otherwise.
+ */
+int
+auth_shadow_acctexpired(struct spwd *spw)
+{
+       time_t today;
+       int daysleft;
+       char buf[256];
+
+       today = time(NULL) / DAY;
+       daysleft = spw->sp_expire - today;
+       debug3("%s: today %d sp_expire %d days left %d", __func__, (int)today,
+           (int)spw->sp_expire, daysleft);
+
+       if (spw->sp_expire == -1) {
+               debug3("account expiration disabled");
+       } else if (daysleft < 0) {
+               logit("Account %.100s has expired", spw->sp_namp);
+               return 1;
+       } else if (daysleft <= spw->sp_warn) {
+               debug3("account will expire in %d days", daysleft);
+               snprintf(buf, sizeof(buf),
+                   "Your account will expire in %d day%s.\n", daysleft,
+                   daysleft == 1 ? "" : "s");
+               buffer_append(&loginmsg, buf, strlen(buf));
+       }
+
+       return 0;
+}
+
+/*
+ * Checks password expiry for platforms that use shadow passwd files.
+ * Returns: 1 = password expired, 0 = password not expired
+ */
+int
+auth_shadow_pwexpired(Authctxt *ctxt)
+{
+       struct spwd *spw = NULL;
+       const char *user = ctxt->pw->pw_name;
+       char buf[256];
+       time_t today;
+       int daysleft, disabled = 0;
+
+       if ((spw = getspnam((char *)user)) == NULL) {
+               error("Could not get shadow information for %.100s", user);
+               return 0;
+       }
+
+       today = time(NULL) / DAY;
+       debug3("%s: today %d sp_lstchg %d sp_max %d", __func__, (int)today,
+           (int)spw->sp_lstchg, (int)spw->sp_max);
+
+#if defined(__hpux) && !defined(HAVE_SECUREWARE)
+       if (iscomsec()) {
+               struct pr_passwd *pr;
+
+               pr = getprpwnam((char *)user);
+
+               /* Test for Trusted Mode expiry disabled */
+               if (pr != NULL && pr->ufld.fd_min == 0 &&
+                   pr->ufld.fd_lifetime == 0 && pr->ufld.fd_expire == 0 &&
+                   pr->ufld.fd_pw_expire_warning == 0 &&
+                   pr->ufld.fd_schange != 0)
+                       disabled = 1;
+       }
+#endif
+
+       /* TODO: check sp_inact */
+       daysleft = spw->sp_lstchg + spw->sp_max - today;
+       if (disabled) {
+               debug3("password expiration disabled");
+       } else if (spw->sp_lstchg == 0) {
+               logit("User %.100s password has expired (root forced)", user);
+               return 1;
+       } else if (spw->sp_max == -1) {
+               debug3("password expiration disabled");
+       } else if (daysleft < 0) {
+               logit("User %.100s password has expired (password aged)", user);
+               return 1;
+       } else if (daysleft <= spw->sp_warn) {
+               debug3("password will expire in %d days", daysleft);
+               snprintf(buf, sizeof(buf),
+                   "Your password will expire in %d day%s.\n", daysleft,
+                   daysleft == 1 ? "" : "s");
+               buffer_append(&loginmsg, buf, strlen(buf));
+       }
+
+       return 0;
+}
+#endif /* USE_SHADOW && HAS_SHADOW_EXPIRE */
diff --git a/auth-sia.c b/auth-sia.c
new file mode 100644 (file)
index 0000000..a9e1c25
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002 Chris Adams.  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 HAVE_OSF_SIA
+#include <sia.h>
+#include <siad.h>
+#include <pwd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "ssh.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-sia.h"
+#include "log.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "uidswap.h"
+
+extern ServerOptions options;
+extern int saved_argc;
+extern char **saved_argv;
+
+int
+sys_auth_passwd(Authctxt *authctxt, const char *pass)
+{
+       int ret;
+       SIAENTITY *ent = NULL;
+       const char *host;
+
+       host = get_canonical_hostname(options.use_dns);
+
+       if (!authctxt->user || pass == NULL || pass[0] == '\0')
+               return (0);
+
+       if (sia_ses_init(&ent, saved_argc, saved_argv, host, authctxt->user,
+           NULL, 0, NULL) != SIASUCCESS)
+               return (0);
+
+       if ((ret = sia_ses_authent(NULL, pass, ent)) != SIASUCCESS) {
+               error("Couldn't authenticate %s from %s",
+                   authctxt->user, host);
+               if (ret & SIASTOP)
+                       sia_ses_release(&ent);
+
+               return (0);
+       }
+
+       sia_ses_release(&ent);
+
+       return (1);
+}
+
+void
+session_setup_sia(struct passwd *pw, char *tty)
+{
+       SIAENTITY *ent = NULL;
+       const char *host;
+
+       host = get_canonical_hostname(options.use_dns);
+
+       if (sia_ses_init(&ent, saved_argc, saved_argv, host, pw->pw_name,
+           tty, 0, NULL) != SIASUCCESS)
+               fatal("sia_ses_init failed");
+
+       if (sia_make_entity_pwd(pw, ent) != SIASUCCESS) {
+               sia_ses_release(&ent);
+               fatal("sia_make_entity_pwd failed");
+       }
+
+       ent->authtype = SIA_A_NONE;
+       if (sia_ses_estab(sia_collect_trm, ent) != SIASUCCESS)
+               fatal("Couldn't establish session for %s from %s",
+                   pw->pw_name, host);
+
+       if (sia_ses_launch(sia_collect_trm, ent) != SIASUCCESS)
+               fatal("Couldn't launch session for %s from %s",
+                   pw->pw_name, host);
+
+       sia_ses_release(&ent);
+
+       setuid(0);
+       permanently_set_uid(pw);
+}
+
+#endif /* HAVE_OSF_SIA */
diff --git a/auth-sia.h b/auth-sia.h
new file mode 100644 (file)
index 0000000..27cbb93
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002 Chris Adams.  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 HAVE_OSF_SIA
+
+void   session_setup_sia(struct passwd *, char *);
+
+#endif /* HAVE_OSF_SIA */
diff --git a/auth-skey.c b/auth-skey.c
new file mode 100644 (file)
index 0000000..cb43dba
--- /dev/null
@@ -0,0 +1,107 @@
+/* $OpenBSD: auth-skey.c,v 1.27 2007/01/21 01:41:54 stevesk 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.
+ */
+
+#include "includes.h"
+
+#ifdef SKEY
+
+#include <sys/types.h>
+
+#include <pwd.h>
+#include <stdio.h>
+
+#include <skey.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "ssh-gss.h"
+#include "monitor_wrap.h"
+
+static void *
+skey_init_ctx(Authctxt *authctxt)
+{
+       return authctxt;
+}
+
+int
+skey_query(void *ctx, char **name, char **infotxt,
+    u_int* numprompts, char ***prompts, u_int **echo_on)
+{
+       Authctxt *authctxt = ctx;
+       char challenge[1024];
+       struct skey skey;
+
+       if (_compat_skeychallenge(&skey, authctxt->user, challenge,
+           sizeof(challenge)) == -1)
+               return -1;
+
+       *name = xstrdup("");
+       *infotxt = xstrdup("");
+       *numprompts = 1;
+       *prompts = xcalloc(*numprompts, sizeof(char *));
+       *echo_on = xcalloc(*numprompts, sizeof(u_int));
+
+       xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
+
+       return 0;
+}
+
+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
+};
+
+KbdintDevice mm_skey_device = {
+       "skey",
+       skey_init_ctx,
+       mm_skey_query,
+       mm_skey_respond,
+       skey_free_ctx
+};
+#endif /* SKEY */
diff --git a/auth.c b/auth.c
new file mode 100644 (file)
index 0000000..33680b9
--- /dev/null
+++ b/auth.c
@@ -0,0 +1,710 @@
+/* $OpenBSD: auth.c,v 1.91 2010/11/29 23:45:51 djm 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <pwd.h>
+#ifdef HAVE_LOGIN_H
+#include <login.h>
+#endif
+#ifdef USE_SHADOW
+#include <shadow.h>
+#endif
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "match.h"
+#include "groupaccess.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "canohost.h"
+#include "uidswap.h"
+#include "misc.h"
+#include "packet.h"
+#include "loginrec.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "authfile.h"
+#include "monitor_wrap.h"
+
+/* import */
+extern ServerOptions options;
+extern int use_privsep;
+extern Buffer loginmsg;
+extern struct passwd *privsep_pw;
+
+/* Debugging messages */
+Buffer auth_debug;
+int auth_debug_init;
+
+/*
+ * 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, *passwd = NULL;
+       u_int i;
+#ifdef USE_SHADOW
+       struct spwd *spw = NULL;
+#endif
+
+       /* Shouldn't be called if pw is NULL, but better safe than sorry... */
+       if (!pw || !pw->pw_name)
+               return 0;
+
+#ifdef USE_SHADOW
+       if (!options.use_pam)
+               spw = getspnam(pw->pw_name);
+#ifdef HAS_SHADOW_EXPIRE
+       if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw))
+               return 0;
+#endif /* HAS_SHADOW_EXPIRE */
+#endif /* USE_SHADOW */
+
+       /* grab passwd field for locked account check */
+       passwd = pw->pw_passwd;
+#ifdef USE_SHADOW
+       if (spw != NULL)
+#ifdef USE_LIBIAF
+               passwd = get_iaf_password(pw);
+#else
+               passwd = spw->sp_pwdp;
+#endif /* USE_LIBIAF */
+#endif
+
+       /* check for locked account */
+       if (!options.use_pam && passwd && *passwd) {
+               int locked = 0;
+
+#ifdef LOCKED_PASSWD_STRING
+               if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0)
+                        locked = 1;
+#endif
+#ifdef LOCKED_PASSWD_PREFIX
+               if (strncmp(passwd, LOCKED_PASSWD_PREFIX,
+                   strlen(LOCKED_PASSWD_PREFIX)) == 0)
+                        locked = 1;
+#endif
+#ifdef LOCKED_PASSWD_SUBSTR
+               if (strstr(passwd, LOCKED_PASSWD_SUBSTR))
+                       locked = 1;
+#endif
+#ifdef USE_LIBIAF
+               free((void *) passwd);
+#endif /* USE_LIBIAF */
+               if (locked) {
+                       logit("User %.100s not allowed because account is locked",
+                           pw->pw_name);
+                       return 0;
+               }
+       }
+
+       /*
+        * Deny if shell does not exist or is not executable unless we
+        * are chrooting.
+        */
+       if (options.chroot_directory == NULL ||
+           strcasecmp(options.chroot_directory, "none") == 0) {
+               char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
+                   _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
+
+               if (stat(shell, &st) != 0) {
+                       logit("User %.100s not allowed because shell %.100s "
+                           "does not exist", pw->pw_name, shell);
+                       xfree(shell);
+                       return 0;
+               }
+               if (S_ISREG(st.st_mode) == 0 ||
+                   (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
+                       logit("User %.100s not allowed because shell %.100s "
+                           "is not executable", pw->pw_name, shell);
+                       xfree(shell);
+                       return 0;
+               }
+               xfree(shell);
+       }
+
+       if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
+           options.num_deny_groups > 0 || options.num_allow_groups > 0) {
+               hostname = get_canonical_hostname(options.use_dns);
+               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])) {
+                               logit("User %.100s from %.100s not allowed "
+                                   "because listed in DenyUsers",
+                                   pw->pw_name, hostname);
+                               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) {
+                       logit("User %.100s from %.100s not allowed because "
+                           "not listed in AllowUsers", pw->pw_name, hostname);
+                       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) {
+                       logit("User %.100s from %.100s not allowed because "
+                           "not in any group", pw->pw_name, hostname);
+                       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();
+                               logit("User %.100s from %.100s not allowed "
+                                   "because a group is listed in DenyGroups",
+                                   pw->pw_name, hostname);
+                               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();
+                               logit("User %.100s from %.100s not allowed "
+                                   "because none of user's groups are listed "
+                                   "in AllowGroups", pw->pw_name, hostname);
+                               return 0;
+                       }
+               ga_free();
+       }
+
+#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
+       if (!sys_auth_allowed_user(pw, &loginmsg))
+               return 0;
+#endif
+
+       /* We found no reason not to let this user try to log on... */
+       return 1;
+}
+
+void
+auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
+{
+       void (*authlog) (const char *fmt,...) = verbose;
+       char *authmsg;
+
+       if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
+               return;
+
+       /* Raise logging level */
+       if (authenticated == 1 ||
+           !authctxt->valid ||
+           authctxt->failures >= options.max_authtries / 2 ||
+           strcmp(method, "password") == 0)
+               authlog = logit;
+
+       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 ? "" : "invalid user ",
+           authctxt->user,
+           get_remote_ipaddr(),
+           get_remote_port(),
+           info);
+
+#ifdef CUSTOM_FAILED_LOGIN
+       if (authenticated == 0 && !authctxt->postponed &&
+           (strcmp(method, "password") == 0 ||
+           strncmp(method, "keyboard-interactive", 20) == 0 ||
+           strcmp(method, "challenge-response") == 0))
+               record_failed_login(authctxt->user,
+                   get_canonical_hostname(options.use_dns), "ssh");
+# ifdef WITH_AIXAUTHENTICATE
+       if (authenticated)
+               sys_auth_record_login(authctxt->user,
+                   get_canonical_hostname(options.use_dns), "ssh", &loginmsg);
+# endif
+#endif
+#ifdef SSH_AUDIT_EVENTS
+       if (authenticated == 0 && !authctxt->postponed)
+               audit_event(audit_classify_auth(method));
+#endif
+}
+
+/*
+ * Check whether root logins are disallowed.
+ */
+int
+auth_root_allowed(char *method)
+{
+       switch (options.permit_root_login) {
+       case PERMIT_YES:
+               return 1;
+       case PERMIT_NO_PASSWD:
+               if (strcmp(method, "password") != 0)
+                       return 1;
+               break;
+       case PERMIT_FORCED_ONLY:
+               if (forced_command) {
+                       logit("Root login accepted for forced command.");
+                       return 1;
+               }
+               break;
+       }
+       logit("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.
+ */
+static char *
+expand_authorized_keys(const char *filename, struct passwd *pw)
+{
+       char *file, ret[MAXPATHLEN];
+       int i;
+
+       file = percent_expand(filename, "h", pw->pw_dir,
+           "u", pw->pw_name, (char *)NULL);
+
+       /*
+        * Ensure that filename starts anchored. If not, be backward
+        * compatible and prepend the '%h/'
+        */
+       if (*file == '/')
+               return (file);
+
+       i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
+       if (i < 0 || (size_t)i >= sizeof(ret))
+               fatal("expand_authorized_keys: path too long");
+       xfree(file);
+       return (xstrdup(ret));
+}
+
+char *
+authorized_keys_file(struct passwd *pw)
+{
+       return expand_authorized_keys(options.authorized_keys_file, pw);
+}
+
+char *
+authorized_keys_file2(struct passwd *pw)
+{
+       return expand_authorized_keys(options.authorized_keys_file2, pw);
+}
+
+char *
+authorized_principals_file(struct passwd *pw)
+{
+       if (options.authorized_principals_file == NULL)
+               return NULL;
+       return expand_authorized_keys(options.authorized_principals_file, 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)
+{
+       char *user_hostfile;
+       struct stat st;
+       HostStatus host_status;
+       struct hostkeys *hostkeys;
+       const struct hostkey_entry *found;
+
+       hostkeys = init_hostkeys();
+       load_hostkeys(hostkeys, host, sysfile);
+       if (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)) {
+                       logit("Authentication refused for %.100s: "
+                           "bad owner or modes for %.200s",
+                           pw->pw_name, user_hostfile);
+                       auth_debug_add("Ignored %.200s: bad ownership or modes",
+                           user_hostfile);
+               } else {
+                       temporarily_use_uid(pw);
+                       load_hostkeys(hostkeys, host, user_hostfile);
+                       restore_uid();
+               }
+               xfree(user_hostfile);
+       }
+       host_status = check_key_in_hostkeys(hostkeys, key, &found);
+       if (host_status == HOST_REVOKED)
+               error("WARNING: revoked key for %s attempted authentication",
+                   found->host);
+       else if (host_status == HOST_OK)
+               debug("%s: key for %s found at %s:%ld", __func__,
+                   found->host, found->file, found->line);
+       else
+               debug("%s: key for host %s not found", __func__, host);
+
+       free_hostkeys(hostkeys);
+
+       return host_status;
+}
+
+
+/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must 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
+ */
+static 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;
+       int comparehome = 0;
+       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)
+               comparehome = 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 past the homedir then we can stop */
+               if (comparehome && 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;
+}
+
+static FILE *
+auth_openfile(const char *file, struct passwd *pw, int strict_modes,
+    int log_missing, char *file_type)
+{
+       char line[1024];
+       struct stat st;
+       int fd;
+       FILE *f;
+
+       if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
+               if (log_missing || errno != ENOENT)
+                       debug("Could not open %s '%s': %s", file_type, file,
+                          strerror(errno));
+               return NULL;
+       }
+
+       if (fstat(fd, &st) < 0) {
+               close(fd);
+               return NULL;
+       }
+       if (!S_ISREG(st.st_mode)) {
+               logit("User %s %s %s is not a regular file",
+                   pw->pw_name, file_type, file);
+               close(fd);
+               return NULL;
+       }
+       unset_nonblock(fd);
+       if ((f = fdopen(fd, "r")) == NULL) {
+               close(fd);
+               return NULL;
+       }
+       if (strict_modes &&
+           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+               fclose(f);
+               logit("Authentication refused: %s", line);
+               auth_debug_add("Ignored %s: %s", file_type, line);
+               return NULL;
+       }
+
+       return f;
+}
+
+
+FILE *
+auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
+{
+       return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
+}
+
+FILE *
+auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
+{
+       return auth_openfile(file, pw, strict_modes, 0,
+           "authorized principals");
+}
+
+struct passwd *
+getpwnamallow(const char *user)
+{
+#ifdef HAVE_LOGIN_CAP
+       extern login_cap_t *lc;
+#ifdef BSD_AUTH
+       auth_session_t *as;
+#endif
+#endif
+       struct passwd *pw;
+
+       parse_server_match_config(&options, user,
+           get_canonical_hostname(options.use_dns), get_remote_ipaddr());
+
+#if defined(_AIX) && defined(HAVE_SETAUTHDB)
+       aix_setauthdb(user);
+#endif
+
+       pw = getpwnam(user);
+
+#if defined(_AIX) && defined(HAVE_SETAUTHDB)
+       aix_restoreauthdb();
+#endif
+#ifdef HAVE_CYGWIN
+       /*
+        * Windows usernames are case-insensitive.  To avoid later problems
+        * when trying to match the username, the user is only allowed to
+        * login if the username is given in the same case as stored in the
+        * user database.
+        */
+       if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
+               logit("Login name %.100s does not match stored username %.100s",
+                   user, pw->pw_name);
+               pw = NULL;
+       }
+#endif
+       if (pw == NULL) {
+               logit("Invalid user %.100s from %.100s",
+                   user, get_remote_ipaddr());
+#ifdef CUSTOM_FAILED_LOGIN
+               record_failed_login(user,
+                   get_canonical_hostname(options.use_dns), "ssh");
+#endif
+#ifdef SSH_AUDIT_EVENTS
+               audit_event(SSH_INVALID_USER);
+#endif /* SSH_AUDIT_EVENTS */
+               return (NULL);
+       }
+       if (!allowed_user(pw))
+               return (NULL);
+#ifdef HAVE_LOGIN_CAP
+       if ((lc = login_getclass(pw->pw_class)) == NULL) {
+               debug("unable to get login class: %s", user);
+               return (NULL);
+       }
+#ifdef BSD_AUTH
+       if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
+           auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
+               debug("Approval failure for %s", user);
+               pw = NULL;
+       }
+       if (as != NULL)
+               auth_close(as);
+#endif
+#endif
+       if (pw != NULL)
+               return (pwcopy(pw));
+       return (NULL);
+}
+
+/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
+int
+auth_key_is_revoked(Key *key)
+{
+       char *key_fp;
+
+       if (options.revoked_keys_file == NULL)
+               return 0;
+
+       switch (key_in_file(key, options.revoked_keys_file, 0)) {
+       case 0:
+               /* key not revoked */
+               return 0;
+       case -1:
+               /* Error opening revoked_keys_file: refuse all keys */
+               error("Revoked keys file is unreadable: refusing public key "
+                   "authentication");
+               return 1;
+       case 1:
+               /* Key revoked */
+               key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+               error("WARNING: authentication attempt with a revoked "
+                   "%s key %s ", key_type(key), key_fp);
+               xfree(key_fp);
+               return 1;
+       }
+       fatal("key_in_file returned junk");
+}
+
+void
+auth_debug_add(const char *fmt,...)
+{
+       char buf[1024];
+       va_list args;
+
+       if (!auth_debug_init)
+               return;
+
+       va_start(args, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, args);
+       va_end(args);
+       buffer_put_cstring(&auth_debug, buf);
+}
+
+void
+auth_debug_send(void)
+{
+       char *msg;
+
+       if (!auth_debug_init)
+               return;
+       while (buffer_len(&auth_debug)) {
+               msg = buffer_get_string(&auth_debug, NULL);
+               packet_send_debug("%s", msg);
+               xfree(msg);
+       }
+}
+
+void
+auth_debug_reset(void)
+{
+       if (auth_debug_init)
+               buffer_clear(&auth_debug);
+       else {
+               buffer_init(&auth_debug);
+               auth_debug_init = 1;
+       }
+}
+
+struct passwd *
+fakepw(void)
+{
+       static struct passwd fake;
+
+       memset(&fake, 0, sizeof(fake));
+       fake.pw_name = "NOUSER";
+       fake.pw_passwd =
+           "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK";
+       fake.pw_gecos = "NOUSER";
+       fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
+       fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       fake.pw_class = "";
+#endif
+       fake.pw_dir = "/nonexist";
+       fake.pw_shell = "/nonexist";
+
+       return (&fake);
+}
diff --git a/auth.h b/auth.h
new file mode 100644 (file)
index 0000000..77317ae
--- /dev/null
+++ b/auth.h
@@ -0,0 +1,206 @@
+/* $OpenBSD: auth.h,v 1.66 2010/05/07 11:30:29 djm 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 AUTH_H
+#define AUTH_H
+
+#include <signal.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 Authmethod Authmethod;
+typedef struct KbdintDevice KbdintDevice;
+
+struct Authctxt {
+       sig_atomic_t     success;
+       int              authenticated; /* authenticated and alarms cancelled */
+       int              postponed;     /* authentication needs another step */
+       int              valid;         /* user exists and is allowed to login */
+       int              attempt;
+       int              failures;
+       int              force_pwchange;
+       char            *user;          /* username sent by the client */
+       char            *service;
+       struct passwd   *pw;            /* set if 'valid' */
+       char            *style;
+       void            *kbdintctxt;
+       void            *jpake_ctx;
+#ifdef BSD_AUTH
+       auth_session_t  *as;
+#endif
+#ifdef KRB5
+       krb5_context     krb5_ctx;
+       krb5_ccache      krb5_fwd_ccache;
+       krb5_principal   krb5_user;
+       char            *krb5_ticket_file;
+       char            *krb5_ccname;
+#endif
+       Buffer          *loginmsg;
+       void            *methoddata;
+};
+/*
+ * Every authentication method has to handle authentication requests for
+ * non-existing users, or for users that are not allowed to login. In this
+ * case 'valid' is set to 0, but 'user' points to the username requested by
+ * the client.
+ */
+
+struct Authmethod {
+       char    *name;
+       int     (*userauth)(Authctxt *authctxt);
+       int     *enabled;
+};
+
+/*
+ * 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)(Authctxt*);
+       int     (*query)(void *ctx, char **name, char **infotxt,
+                   u_int *numprompts, char ***prompts, u_int **echo_on);
+       int     (*respond)(void *ctx, u_int numresp, char **responses);
+       void    (*free_ctx)(void *ctx);
+};
+
+int      auth_rhosts(struct passwd *, const char *);
+int
+auth_rhosts2(struct passwd *, const char *, const char *, const char *);
+
+int     auth_rhosts_rsa(Authctxt *, char *, Key *);
+int      auth_password(Authctxt *, const char *);
+int      auth_rsa(Authctxt *, BIGNUM *);
+int      auth_rsa_challenge_dialog(Key *);
+BIGNUM *auth_rsa_generate_challenge(Key *);
+int     auth_rsa_verify_response(Key *, BIGNUM *, u_char[]);
+int     auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
+
+int     auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
+int     hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
+int     user_key_allowed(struct passwd *, Key *);
+
+#ifdef KRB5
+int    auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
+int    auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
+int    auth_krb5_password(Authctxt *authctxt, const char *password);
+void   krb5_cleanup_proc(Authctxt *authctxt);
+#endif /* KRB5 */
+
+#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
+#include <shadow.h>
+int auth_shadow_acctexpired(struct spwd *);
+int auth_shadow_pwexpired(Authctxt *);
+#endif
+
+#include "auth-pam.h"
+#include "audit.h"
+void remove_kbdint_device(const char *);
+
+void disable_forwarding(void);
+
+void   do_authentication(Authctxt *);
+void   do_authentication2(Authctxt *);
+
+void   auth_log(Authctxt *, int, char *, char *);
+void   userauth_finish(Authctxt *, int, char *);
+void   userauth_send_banner(const char *);
+int    auth_root_allowed(char *);
+
+char   *auth2_read_banner(void);
+
+void   privsep_challenge_enable(void);
+
+int    auth2_challenge(Authctxt *, char *);
+void   auth2_challenge_stop(Authctxt *);
+int    bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
+int    bsdauth_respond(void *, u_int, char **);
+int    skey_query(void *, char **, char **, u_int *, char ***, u_int **);
+int    skey_respond(void *, u_int, char **);
+
+void   auth2_jpake_get_pwdata(Authctxt *, BIGNUM **, char **, char **);
+void   auth2_jpake_stop(Authctxt *);
+
+int    allowed_user(struct passwd *);
+struct passwd * getpwnamallow(const char *user);
+
+char   *get_challenge(Authctxt *);
+int    verify_response(Authctxt *, const char *);
+void   abandon_challenge_response(Authctxt *);
+
+char   *authorized_keys_file(struct passwd *);
+char   *authorized_keys_file2(struct passwd *);
+char   *authorized_principals_file(struct passwd *);
+
+FILE   *auth_openkeyfile(const char *, struct passwd *, int);
+FILE   *auth_openprincipals(const char *, struct passwd *, int);
+int     auth_key_is_revoked(Key *);
+
+HostStatus
+check_key_in_hostfiles(struct passwd *, Key *, const char *,
+    const char *, const char *);
+
+/* hostkey handling */
+Key    *get_hostkey_by_index(int);
+Key    *get_hostkey_public_by_type(int);
+Key    *get_hostkey_private_by_type(int);
+int     get_hostkey_index(Key *);
+int     ssh1_session_key(BIGNUM *);
+
+/* debug messages during authentication */
+void    auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void    auth_debug_send(void);
+void    auth_debug_reset(void);
+
+struct passwd *fakepw(void);
+
+int     sys_auth_passwd(Authctxt *, const char *);
+
+#define AUTH_FAIL_MSG "Too many authentication failures for %.100s"
+
+#define SKEY_PROMPT "\nS/Key Password: "
+
+#if defined(KRB5) && !defined(HEIMDAL)
+#include <krb5.h>
+krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *);
+#endif
+#endif
diff --git a/auth1.c b/auth1.c
new file mode 100644 (file)
index 0000000..cc85aec
--- /dev/null
+++ b/auth1.c
@@ -0,0 +1,437 @@
+/* $OpenBSD: auth1.c,v 1.75 2010/08/31 09:58:37 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "rsa.h"
+#include "ssh1.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "compat.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "channels.h"
+#include "session.h"
+#include "uidswap.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "buffer.h"
+
+/* import */
+extern ServerOptions options;
+extern Buffer loginmsg;
+
+static int auth1_process_password(Authctxt *, char *, size_t);
+static int auth1_process_rsa(Authctxt *, char *, size_t);
+static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
+static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
+static int auth1_process_tis_response(Authctxt *, char *, size_t);
+
+static char *client_user = NULL;    /* Used to fill in remote user for PAM */
+
+struct AuthMethod1 {
+       int type;
+       char *name;
+       int *enabled;
+       int (*method)(Authctxt *, char *, size_t);
+};
+
+const struct AuthMethod1 auth1_methods[] = {
+       {
+               SSH_CMSG_AUTH_PASSWORD, "password",
+               &options.password_authentication, auth1_process_password
+       },
+       {
+               SSH_CMSG_AUTH_RSA, "rsa",
+               &options.rsa_authentication, auth1_process_rsa
+       },
+       {
+               SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
+               &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
+       },
+       {
+               SSH_CMSG_AUTH_TIS, "challenge-response",
+               &options.challenge_response_authentication,
+               auth1_process_tis_challenge
+       },
+       {
+               SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
+               &options.challenge_response_authentication,
+               auth1_process_tis_response
+       },
+       { -1, NULL, NULL, NULL}
+};
+
+static const struct AuthMethod1
+*lookup_authmethod1(int type)
+{
+       int i;
+
+       for (i = 0; auth1_methods[i].name != NULL; i++)
+               if (auth1_methods[i].type == type)
+                       return (&(auth1_methods[i]));
+
+       return (NULL);
+}
+
+static char *
+get_authname(int type)
+{
+       const struct AuthMethod1 *a;
+       static char buf[64];
+
+       if ((a = lookup_authmethod1(type)) != NULL)
+               return (a->name);
+       snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
+       return (buf);
+}
+
+/*ARGSUSED*/
+static int
+auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
+{
+       int authenticated = 0;
+       char *password;
+       u_int dlen;
+
+       /*
+        * 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_check_eom();
+
+       /* Try authentication with the password. */
+       authenticated = PRIVSEP(auth_password(authctxt, password));
+
+       memset(password, 0, dlen);
+       xfree(password);
+
+       return (authenticated);
+}
+
+/*ARGSUSED*/
+static int
+auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+       int authenticated = 0;
+       BIGNUM *n;
+
+       /* RSA authentication requested. */
+       if ((n = BN_new()) == NULL)
+               fatal("do_authloop: BN_new failed");
+       packet_get_bignum(n);
+       packet_check_eom();
+       authenticated = auth_rsa(authctxt, n);
+       BN_clear_free(n);
+
+       return (authenticated);
+}
+
+/*ARGSUSED*/
+static int
+auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
+{
+       int keybits, authenticated = 0;
+       u_int bits;
+       Key *client_host_key;
+       u_int ulen;
+
+       /*
+        * 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_cstring(&ulen);
+
+       /* Get the client host key. */
+       client_host_key = key_new(KEY_RSA1);
+       bits = packet_get_int();
+       packet_get_bignum(client_host_key->rsa->e);
+       packet_get_bignum(client_host_key->rsa->n);
+
+       keybits = BN_num_bits(client_host_key->rsa->n);
+       if (keybits < 0 || bits != (u_int)keybits) {
+               verbose("Warning: keysize mismatch for client_host_key: "
+                   "actual %d, announced %d",
+                   BN_num_bits(client_host_key->rsa->n), bits);
+       }
+       packet_check_eom();
+
+       authenticated = auth_rhosts_rsa(authctxt, client_user,
+           client_host_key);
+       key_free(client_host_key);
+
+       snprintf(info, infolen, " ruser %.100s", client_user);
+
+       return (authenticated);
+}
+
+/*ARGSUSED*/
+static int
+auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
+{
+       char *challenge;
+
+       if ((challenge = get_challenge(authctxt)) == NULL)
+               return (0);
+
+       debug("sending challenge '%s'", challenge);
+       packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+       packet_put_cstring(challenge);
+       xfree(challenge);
+       packet_send();
+       packet_write_wait();
+
+       return (-1);
+}
+
+/*ARGSUSED*/
+static int
+auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
+{
+       int authenticated = 0;
+       char *response;
+       u_int dlen;
+
+       response = packet_get_string(&dlen);
+       packet_check_eom();
+       authenticated = verify_response(authctxt, response);
+       memset(response, 'r', dlen);
+       xfree(response);
+
+       return (authenticated);
+}
+
+/*
+ * read packets, try to authenticate the user and
+ * return only if authentication is successful
+ */
+static void
+do_authloop(Authctxt *authctxt)
+{
+       int authenticated = 0;
+       char info[1024];
+       int prev = 0, type = 0;
+       const struct AuthMethod1 *meth;
+
+       debug("Attempting authentication for %s%.100s.",
+           authctxt->valid ? "" : "invalid user ", authctxt->user);
+
+       /* If the user has no password, accept authentication immediately. */
+       if (options.permit_empty_passwd && options.password_authentication &&
+#ifdef KRB5
+           (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
+#endif
+           PRIVSEP(auth_password(authctxt, ""))) {
+#ifdef USE_PAM
+               if (options.use_pam && (PRIVSEP(do_pam_account())))
+#endif
+               {
+                       auth_log(authctxt, 1, "without authentication", "");
+                       return;
+               }
+       }
+
+       /* Indicate that authentication is needed. */
+       packet_start(SSH_SMSG_FAILURE);
+       packet_send();
+       packet_write_wait();
+
+       for (;;) {
+               /* default to fail */
+               authenticated = 0;
+
+               info[0] = '\0';
+
+               /* Get a packet from the client. */
+               prev = type;
+               type = packet_read();
+
+               /*
+                * If we started challenge-response authentication but the
+                * next packet is not a response to our challenge, release
+                * the resources allocated by get_challenge() (which would
+                * normally have been released by verify_response() had we
+                * received such a response)
+                */
+               if (prev == SSH_CMSG_AUTH_TIS &&
+                   type != SSH_CMSG_AUTH_TIS_RESPONSE)
+                       abandon_challenge_response(authctxt);
+
+               if (authctxt->failures >= options.max_authtries)
+                       goto skip;
+               if ((meth = lookup_authmethod1(type)) == NULL) {
+                       logit("Unknown message during authentication: "
+                           "type %d", type);
+                       goto skip;
+               }
+
+               if (!*(meth->enabled)) {
+                       verbose("%s authentication disabled.", meth->name);
+                       goto skip;
+               }
+
+               authenticated = meth->method(authctxt, info, sizeof(info));
+               if (authenticated == -1)
+                       continue; /* "postponed" */
+
+#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 _UNICOS
+               if (authenticated && cray_access_denied(authctxt->user)) {
+                       authenticated = 0;
+                       fatal("Access denied for user %s.",authctxt->user);
+               }
+#endif /* _UNICOS */
+
+#ifndef HAVE_CYGWIN
+               /* Special handling for root */
+               if (authenticated && authctxt->pw->pw_uid == 0 &&
+                   !auth_root_allowed(meth->name)) {
+                       authenticated = 0;
+# ifdef SSH_AUDIT_EVENTS
+                       PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
+# endif
+               }
+#endif
+
+#ifdef USE_PAM
+               if (options.use_pam && authenticated &&
+                   !PRIVSEP(do_pam_account())) {
+                       char *msg;
+                       size_t len;
+
+                       error("Access denied for user %s by PAM account "
+                           "configuration", authctxt->user);
+                       len = buffer_len(&loginmsg);
+                       buffer_append(&loginmsg, "\0", 1);
+                       msg = buffer_ptr(&loginmsg);
+                       /* strip trailing newlines */
+                       if (len > 0)
+                               while (len > 0 && msg[--len] == '\n')
+                                       msg[len] = '\0';
+                       else
+                               msg = "Access denied.";
+                       packet_disconnect("%s", msg);
+               }
+#endif
+
+ skip:
+               /* 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 >= options.max_authtries) {
+#ifdef SSH_AUDIT_EVENTS
+                       PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
+#endif
+                       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)
+{
+       u_int ulen;
+       char *user, *style = NULL;
+
+       /* Get the name of the user that we wish to log in as. */
+       packet_read_expect(SSH_CMSG_USER);
+
+       /* Get the user name. */
+       user = packet_get_cstring(&ulen);
+       packet_check_eom();
+
+       if ((style = strchr(user, ':')) != NULL)
+               *style++ = '\0';
+
+       authctxt->user = user;
+       authctxt->style = style;
+
+       /* Verify that the user is a valid user. */
+       if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
+               authctxt->valid = 1;
+       else {
+               debug("do_authentication: invalid user %s", user);
+               authctxt->pw = fakepw();
+       }
+
+       setproctitle("%s%s", authctxt->valid ? user : "unknown",
+           use_privsep ? " [net]" : "");
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               PRIVSEP(start_pam(authctxt));
+#endif
+
+       /*
+        * If we are not running as root, the user must have the same uid as
+        * the server.
+        */
+#ifndef HAVE_CYGWIN
+       if (!use_privsep && getuid() != 0 && authctxt->pw &&
+           authctxt->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();
+}
diff --git a/auth2-chall.c b/auth2-chall.c
new file mode 100644 (file)
index 0000000..e6dbffe
--- /dev/null
@@ -0,0 +1,374 @@
+/* $OpenBSD: auth2-chall.c,v 1.34 2008/12/09 04:32:22 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "buffer.h"
+#include "packet.h"
+#include "dispatch.h"
+#include "log.h"
+#include "servconf.h"
+
+/* import */
+extern ServerOptions options;
+
+static int auth2_challenge_start(Authctxt *);
+static int send_userauth_info_request(Authctxt *);
+static void input_userauth_info_response(int, u_int32_t, void *);
+
+#ifdef BSD_AUTH
+extern KbdintDevice bsdauth_device;
+#else
+#ifdef USE_PAM
+extern KbdintDevice sshpam_device;
+#endif
+#ifdef SKEY
+extern KbdintDevice skey_device;
+#endif
+#endif
+
+KbdintDevice *devices[] = {
+#ifdef BSD_AUTH
+       &bsdauth_device,
+#else
+#ifdef USE_PAM
+       &sshpam_device,
+#endif
+#ifdef SKEY
+       &skey_device,
+#endif
+#endif
+       NULL
+};
+
+typedef struct KbdintAuthctxt KbdintAuthctxt;
+struct KbdintAuthctxt
+{
+       char *devices;
+       void *ctxt;
+       KbdintDevice *device;
+       u_int nreq;
+};
+
+#ifdef USE_PAM
+void
+remove_kbdint_device(const char *devname)
+{
+       int i, j;
+
+       for (i = 0; devices[i] != NULL; i++)
+               if (strcmp(devices[i]->name, devname) == 0) {
+                       for (j = i; devices[j] != NULL; j++)
+                               devices[j] = devices[j+1];
+                       i--;
+               }
+}
+#endif
+
+static KbdintAuthctxt *
+kbdint_alloc(const char *devs)
+{
+       KbdintAuthctxt *kbdintctxt;
+       Buffer b;
+       int i;
+
+#ifdef USE_PAM
+       if (!options.use_pam)
+               remove_kbdint_device("pam");
+#endif
+
+       kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));
+       if (strcmp(devs, "") == 0) {
+               buffer_init(&b);
+               for (i = 0; devices[i]; i++) {
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       buffer_append(&b, devices[i]->name,
+                           strlen(devices[i]->name));
+               }
+               buffer_append(&b, "\0", 1);
+               kbdintctxt->devices = xstrdup(buffer_ptr(&b));
+               buffer_free(&b);
+       } else {
+               kbdintctxt->devices = xstrdup(devs);
+       }
+       debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
+       kbdintctxt->ctxt = NULL;
+       kbdintctxt->device = NULL;
+       kbdintctxt->nreq = 0;
+
+       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);
+}
+
+/* unregister kbd-int callbacks and context */
+void
+auth2_challenge_stop(Authctxt *authctxt)
+{
+       /* unregister callback */
+       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+       if (authctxt->kbdintctxt != NULL) {
+               kbdint_free(authctxt->kbdintctxt);
+               authctxt->kbdintctxt = NULL;
+       }
+}
+
+/* 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) {
+               auth2_challenge_stop(authctxt);
+               return 0;
+       }
+       debug("auth2_challenge_start: trying authentication method '%s'",
+           kbdintctxt->device->name);
+
+       if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
+               auth2_challenge_stop(authctxt);
+               return 0;
+       }
+       if (send_userauth_info_request(authctxt) == 0) {
+               auth2_challenge_stop(authctxt);
+               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;
+       u_int i, *echo_on;
+
+       kbdintctxt = authctxt->kbdintctxt;
+       if (kbdintctxt->device->query(kbdintctxt->ctxt,
+           &name, &instr, &kbdintctxt->nreq, &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(kbdintctxt->nreq);
+       for (i = 0; i < kbdintctxt->nreq; i++) {
+               packet_put_cstring(prompts[i]);
+               packet_put_char(echo_on[i]);
+       }
+       packet_send();
+       packet_write_wait();
+
+       for (i = 0; i < kbdintctxt->nreq; i++)
+               xfree(prompts[i]);
+       xfree(prompts);
+       xfree(echo_on);
+       xfree(name);
+       xfree(instr);
+       return 1;
+}
+
+static void
+input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       KbdintAuthctxt *kbdintctxt;
+       int authenticated = 0, res;
+       u_int i, 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 != kbdintctxt->nreq)
+               fatal("input_userauth_info_response: wrong number of replies");
+       if (nresp > 100)
+               fatal("input_userauth_info_response: too many replies");
+       if (nresp > 0) {
+               response = xcalloc(nresp, sizeof(char *));
+               for (i = 0; i < nresp; i++)
+                       response[i] = packet_get_string(NULL);
+       }
+       packet_check_eom();
+
+       res = kbdintctxt->device->respond(kbdintctxt->ctxt, nresp, response);
+
+       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 = authctxt->valid ? 1 : 0;
+               break;
+       case 1:
+               /* Authentication needs further interaction */
+               if (send_userauth_info_request(authctxt) == 1)
+                       authctxt->postponed = 1;
+               break;
+       default:
+               /* Failure! */
+               break;
+       }
+
+       xasprintf(&method, "keyboard-interactive/%s", kbdintctxt->device->name);
+
+       if (!authctxt->postponed) {
+               if (authenticated) {
+                       auth2_challenge_stop(authctxt);
+               } else {
+                       /* start next device */
+                       /* may set authctxt->postponed */
+                       auth2_challenge_start(authctxt);
+               }
+       }
+       userauth_finish(authctxt, authenticated, method);
+       xfree(method);
+}
+
+void
+privsep_challenge_enable(void)
+{
+#if defined(BSD_AUTH) || defined(USE_PAM) || defined(SKEY)
+       int n = 0;
+#endif
+#ifdef BSD_AUTH
+       extern KbdintDevice mm_bsdauth_device;
+#endif
+#ifdef USE_PAM
+       extern KbdintDevice mm_sshpam_device;
+#endif
+#ifdef SKEY
+       extern KbdintDevice mm_skey_device;
+#endif
+
+#ifdef BSD_AUTH
+       devices[n++] = &mm_bsdauth_device;
+#else
+#ifdef USE_PAM
+       devices[n++] = &mm_sshpam_device;
+#endif
+#ifdef SKEY
+       devices[n++] = &mm_skey_device;
+#endif
+#endif
+}
diff --git a/auth2-gss.c b/auth2-gss.c
new file mode 100644 (file)
index 0000000..0e08d88
--- /dev/null
@@ -0,0 +1,301 @@
+/* $OpenBSD: auth2-gss.c,v 1.16 2007/10/29 00:52:45 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. 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 GSSAPI
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "ssh2.h"
+#include "log.h"
+#include "dispatch.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "packet.h"
+#include "ssh-gss.h"
+#include "monitor_wrap.h"
+
+extern ServerOptions options;
+
+static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_errtok(int, u_int32_t, void *);
+
+/*
+ * We only support those mechanisms that we know about (ie ones that we know
+ * how to check local user kuserok and the like)
+ */
+static int
+userauth_gssapi(Authctxt *authctxt)
+{
+       gss_OID_desc goid = {0, NULL};
+       Gssctxt *ctxt = NULL;
+       int mechs;
+       gss_OID_set supported;
+       int present;
+       OM_uint32 ms;
+       u_int len;
+       u_char *doid = NULL;
+
+       if (!authctxt->valid || authctxt->user == NULL)
+               return (0);
+
+       mechs = packet_get_int();
+       if (mechs == 0) {
+               debug("Mechanism negotiation is not supported");
+               return (0);
+       }
+
+       ssh_gssapi_supported_oids(&supported);
+       do {
+               mechs--;
+
+               if (doid)
+                       xfree(doid);
+
+               present = 0;
+               doid = packet_get_string(&len);
+
+               if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
+                   doid[1] == len - 2) {
+                       goid.elements = doid + 2;
+                       goid.length   = len - 2;
+                       gss_test_oid_set_member(&ms, &goid, supported,
+                           &present);
+               } else {
+                       logit("Badly formed OID received");
+               }
+       } while (mechs > 0 && !present);
+
+       gss_release_oid_set(&ms, &supported);
+
+       if (!present) {
+               xfree(doid);
+               return (0);
+       }
+
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
+               if (ctxt != NULL)
+                       ssh_gssapi_delete_ctx(&ctxt);
+               xfree(doid);
+               return (0);
+       }
+
+       authctxt->methoddata = (void *)ctxt;
+
+       packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
+
+       /* Return the OID that we received */
+       packet_put_string(doid, len);
+
+       packet_send();
+       xfree(doid);
+
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+       authctxt->postponed = 1;
+
+       return (0);
+}
+
+static void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc recv_tok;
+       OM_uint32 maj_status, min_status, flags;
+       u_int len;
+
+       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+               fatal("No authentication or GSSAPI context");
+
+       gssctxt = authctxt->methoddata;
+       recv_tok.value = packet_get_string(&len);
+       recv_tok.length = len; /* u_int vs. size_t */
+
+       packet_check_eom();
+
+       maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
+           &send_tok, &flags));
+
+       xfree(recv_tok.value);
+
+       if (GSS_ERROR(maj_status)) {
+               if (send_tok.length != 0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value, send_tok.length);
+                       packet_send();
+               }
+               authctxt->postponed = 0;
+               dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+               userauth_finish(authctxt, 0, "gssapi-with-mic");
+       } else {
+               if (send_tok.length != 0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+                       packet_put_string(send_tok.value, send_tok.length);
+                       packet_send();
+               }
+               if (maj_status == GSS_S_COMPLETE) {
+                       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+                       if (flags & GSS_C_INTEG_FLAG)
+                               dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
+                                   &input_gssapi_mic);
+                       else
+                               dispatch_set(
+                                   SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+                                   &input_gssapi_exchange_complete);
+               }
+       }
+
+       gss_release_buffer(&min_status, &send_tok);
+}
+
+static void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc recv_tok;
+       OM_uint32 maj_status;
+       u_int len;
+
+       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+               fatal("No authentication or GSSAPI context");
+
+       gssctxt = authctxt->methoddata;
+       recv_tok.value = packet_get_string(&len);
+       recv_tok.length = len;
+
+       packet_check_eom();
+
+       /* Push the error token into GSSAPI to see what it says */
+       maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
+           &send_tok, NULL));
+
+       xfree(recv_tok.value);
+
+       /* We can't return anything to the client, even if we wanted to */
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+
+       /* The client will have already moved on to the next auth */
+
+       gss_release_buffer(&maj_status, &send_tok);
+}
+
+/*
+ * This is called when the client thinks we've completed authentication.
+ * It should only be enabled in the dispatch handler by the function above,
+ * which only enables it once the GSSAPI exchange is complete.
+ */
+
+static void
+input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       int authenticated;
+
+       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+               fatal("No authentication or GSSAPI context");
+
+       gssctxt = authctxt->methoddata;
+
+       /*
+        * We don't need to check the status, because we're only enabled in
+        * the dispatcher once the exchange is complete
+        */
+
+       packet_check_eom();
+
+       authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+
+       authctxt->postponed = 0;
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+       userauth_finish(authctxt, authenticated, "gssapi-with-mic");
+}
+
+static void
+input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       int authenticated = 0;
+       Buffer b;
+       gss_buffer_desc mic, gssbuf;
+       u_int len;
+
+       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+               fatal("No authentication or GSSAPI context");
+
+       gssctxt = authctxt->methoddata;
+
+       mic.value = packet_get_string(&len);
+       mic.length = len;
+
+       ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
+           "gssapi-with-mic");
+
+       gssbuf.value = buffer_ptr(&b);
+       gssbuf.length = buffer_len(&b);
+
+       if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
+               authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+       else
+               logit("GSSAPI MIC check failed");
+
+       buffer_free(&b);
+       xfree(mic.value);
+
+       authctxt->postponed = 0;
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+       userauth_finish(authctxt, authenticated, "gssapi-with-mic");
+}
+
+Authmethod method_gssapi = {
+       "gssapi-with-mic",
+       userauth_gssapi,
+       &options.gss_authentication
+};
+
+#endif /* GSSAPI */
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
new file mode 100644 (file)
index 0000000..cdf442f
--- /dev/null
@@ -0,0 +1,220 @@
+/* $OpenBSD: auth2-hostbased.c,v 1.14 2010/08/04 05:42:47 djm 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 <sys/types.h>
+
+#include <pwd.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "compat.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "canohost.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "pathnames.h"
+
+/* import */
+extern ServerOptions options;
+extern u_char *session_id2;
+extern u_int session_id2_len;
+
+static int
+userauth_hostbased(Authctxt *authctxt)
+{
+       Buffer b;
+       Key *key = NULL;
+       char *pkalg, *cuser, *chost, *service;
+       u_char *pkblob, *sig;
+       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 */
+               logit("userauth_hostbased: unsupported "
+                   "public key algorithm: %s", pkalg);
+               goto done;
+       }
+       key = key_from_blob(pkblob, blen);
+       if (key == NULL) {
+               error("userauth_hostbased: cannot decode key: %s", pkalg);
+               goto done;
+       }
+       if (key->type != pktype) {
+               error("userauth_hostbased: type mismatch for decoded key "
+                   "(received %d, expected %d)", key->type, pktype);
+               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 */
+       authenticated = 0;
+       if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
+           PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
+                       buffer_len(&b))) == 1)
+               authenticated = 1;
+
+       buffer_free(&b);
+done:
+       debug2("userauth_hostbased: authenticated %d", authenticated);
+       if (key != NULL)
+               key_free(key);
+       xfree(pkalg);
+       xfree(pkblob);
+       xfree(cuser);
+       xfree(chost);
+       xfree(sig);
+       return authenticated;
+}
+
+/* return 1 if given hostkey is allowed */
+int
+hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
+    Key *key)
+{
+       const char *resolvedname, *ipaddr, *lookup, *reason;
+       HostStatus host_status;
+       int len;
+       char *fp;
+
+       if (auth_key_is_revoked(key))
+               return 0;
+
+       resolvedname = get_canonical_hostname(options.use_dns);
+       ipaddr = get_remote_ipaddr();
+
+       debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s",
+           chost, resolvedname, ipaddr);
+
+       if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') {
+               debug2("stripping trailing dot from chost %s", chost);
+               chost[len - 1] = '\0';
+       }
+
+       if (options.hostbased_uses_name_from_packet_only) {
+               if (auth_rhosts2(pw, cuser, chost, chost) == 0)
+                       return 0;
+               lookup = chost;
+       } else {
+               if (strcasecmp(resolvedname, chost) != 0)
+                       logit("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");
+
+       if (key_is_cert(key) && 
+           key_cert_check_authority(key, 1, 0, lookup, &reason)) {
+               error("%s", reason);
+               auth_debug_add("%s", reason);
+               return 0;
+       }
+
+       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);
+       }
+
+       if (host_status == HOST_OK) {
+               if (key_is_cert(key)) {
+                       fp = key_fingerprint(key->cert->signature_key,
+                           SSH_FP_MD5, SSH_FP_HEX);
+                       verbose("Accepted certificate ID \"%s\" signed by "
+                           "%s CA %s from %s@%s", key->cert->key_id,
+                           key_type(key->cert->signature_key), fp,
+                           cuser, lookup);
+               } else {
+                       fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+                       verbose("Accepted %s public key %s from %s@%s",
+                           key_type(key), fp, cuser, lookup);
+               }
+               xfree(fp);
+       }
+
+       return (host_status == HOST_OK);
+}
+
+Authmethod method_hostbased = {
+       "hostbased",
+       userauth_hostbased,
+       &options.hostbased_authentication
+};
diff --git a/auth2-jpake.c b/auth2-jpake.c
new file mode 100644 (file)
index 0000000..a460e82
--- /dev/null
@@ -0,0 +1,563 @@
+/* $OpenBSD: auth2-jpake.c,v 1.4 2010/08/31 11:54:45 djm Exp $ */
+/*
+ * Copyright (c) 2008 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Server side of zero-knowledge password auth using J-PAKE protocol
+ * as described in:
+ *
+ * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling",
+ * 16th Workshop on Security Protocols, Cambridge, April 2008
+ *
+ * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
+ */
+
+#ifdef JPAKE
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <login_cap.h>
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "buffer.h"
+#include "packet.h"
+#include "dispatch.h"
+#include "log.h"
+#include "servconf.h"
+#include "auth-options.h"
+#include "canohost.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+#include "schnorr.h"
+#include "jpake.h"
+
+/*
+ * XXX options->permit_empty_passwd (at the moment, they will be refused
+ * anyway because they will mismatch on fake salt.
+ */
+
+/* Dispatch handlers */
+static void input_userauth_jpake_client_step1(int, u_int32_t, void *);
+static void input_userauth_jpake_client_step2(int, u_int32_t, void *);
+static void input_userauth_jpake_client_confirm(int, u_int32_t, void *);
+
+static int auth2_jpake_start(Authctxt *);
+
+/* import */
+extern ServerOptions options;
+extern u_char *session_id2;
+extern u_int session_id2_len;
+
+/*
+ * Attempt J-PAKE authentication.
+ */
+static int
+userauth_jpake(Authctxt *authctxt)
+{
+       int authenticated = 0;
+
+       packet_check_eom();
+
+       debug("jpake-01@openssh.com requested");
+
+       if (authctxt->user != NULL) {
+               if (authctxt->jpake_ctx == NULL)
+                       authctxt->jpake_ctx = jpake_new();
+               if (options.zero_knowledge_password_authentication)
+                       authenticated = auth2_jpake_start(authctxt);
+       }
+
+       return authenticated;
+}
+
+Authmethod method_jpake = {
+       "jpake-01@openssh.com",
+       userauth_jpake,
+       &options.zero_knowledge_password_authentication
+};
+
+/* Clear context and callbacks */
+void
+auth2_jpake_stop(Authctxt *authctxt)
+{
+       /* unregister callbacks */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL);
+       if (authctxt->jpake_ctx != NULL) {
+               jpake_free(authctxt->jpake_ctx);
+               authctxt->jpake_ctx = NULL;
+       }
+}
+
+/* Returns 1 if 'c' is a valid crypt(3) salt character, 0 otherwise */
+static int
+valid_crypt_salt(int c)
+{
+       if (c >= 'A' && c <= 'Z')
+               return 1;
+       if (c >= 'a' && c <= 'z')
+               return 1;
+       if (c >= '.' && c <= '9')
+               return 1;
+       return 0;
+}
+
+/*
+ * Derive fake salt as H(username || first_private_host_key)
+ * This provides relatively stable fake salts for non-existent
+ * users and avoids the jpake method becoming an account validity
+ * oracle.
+ */
+static void
+derive_rawsalt(const char *username, u_char *rawsalt, u_int len)
+{
+       u_char *digest;
+       u_int digest_len;
+       Buffer b;
+       Key *k;
+
+       buffer_init(&b);
+       buffer_put_cstring(&b, username);
+       if ((k = get_hostkey_by_index(0)) == NULL ||
+           (k->flags & KEY_FLAG_EXT))
+               fatal("%s: no hostkeys", __func__);
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+               if (k->rsa->p == NULL || k->rsa->q == NULL)
+                       fatal("%s: RSA key missing p and/or q", __func__);
+               buffer_put_bignum2(&b, k->rsa->p);
+               buffer_put_bignum2(&b, k->rsa->q);
+               break;
+       case KEY_DSA:
+               if (k->dsa->priv_key == NULL)
+                       fatal("%s: DSA key missing priv_key", __func__);
+               buffer_put_bignum2(&b, k->dsa->priv_key);
+               break;
+       case KEY_ECDSA:
+               if (EC_KEY_get0_private_key(k->ecdsa) == NULL)
+                       fatal("%s: ECDSA key missing priv_key", __func__);
+               buffer_put_bignum2(&b, EC_KEY_get0_private_key(k->ecdsa));
+               break;
+       default:
+               fatal("%s: unknown key type %d", __func__, k->type);
+       }
+       if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(),
+           &digest, &digest_len) != 0)
+               fatal("%s: hash_buffer", __func__);
+       buffer_free(&b);
+       if (len > digest_len)
+               fatal("%s: not enough bytes for rawsalt (want %u have %u)",
+                   __func__, len, digest_len);
+       memcpy(rawsalt, digest, len);
+       bzero(digest, digest_len);
+       xfree(digest);
+}
+
+/* ASCII an integer [0, 64) for inclusion in a password/salt */
+static char
+pw_encode64(u_int i64)
+{
+       const u_char e64[] =
+           "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+       return e64[i64 % 64];
+}
+
+/* Generate ASCII salt bytes for user */
+static char *
+makesalt(u_int want, const char *user)
+{
+       u_char rawsalt[32];
+       static char ret[33];
+       u_int i;
+
+       if (want > sizeof(ret) - 1)
+               fatal("%s: want %u", __func__, want);
+
+       derive_rawsalt(user, rawsalt, sizeof(rawsalt));
+       bzero(ret, sizeof(ret));
+       for (i = 0; i < want; i++)
+               ret[i] = pw_encode64(rawsalt[i]);
+       bzero(rawsalt, sizeof(rawsalt));
+
+       return ret;
+}
+
+/*
+ * Select the system's default password hashing scheme and generate
+ * a stable fake salt under it for use by a non-existent account.
+ * Prevents jpake method being used to infer the validity of accounts.
+ */
+static void
+fake_salt_and_scheme(Authctxt *authctxt, char **salt, char **scheme)
+{
+       char *rounds_s, *style;
+       long long rounds;
+       login_cap_t *lc;
+
+
+       if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL &&
+           (lc = login_getclass(NULL)) == NULL)
+               fatal("%s: login_getclass failed", __func__);
+       style = login_getcapstr(lc, "localcipher", NULL, NULL);
+       if (style == NULL)
+               style = xstrdup("blowfish,6");
+       login_close(lc);
+       
+       if ((rounds_s = strchr(style, ',')) != NULL)
+               *rounds_s++ = '\0';
+       rounds = strtonum(rounds_s, 1, 1<<31, NULL);
+       
+       if (strcmp(style, "md5") == 0) {
+               xasprintf(salt, "$1$%s$", makesalt(8, authctxt->user));
+               *scheme = xstrdup("md5");
+       } else if (strcmp(style, "old") == 0) {
+               *salt = xstrdup(makesalt(2, authctxt->user));
+               *scheme = xstrdup("crypt");
+       } else if (strcmp(style, "newsalt") == 0) {
+               rounds = MAX(rounds, 7250);
+               rounds = MIN(rounds, (1<<24) - 1);
+               xasprintf(salt, "_%c%c%c%c%s",
+                   pw_encode64(rounds), pw_encode64(rounds >> 6),
+                   pw_encode64(rounds >> 12), pw_encode64(rounds >> 18),
+                   makesalt(4, authctxt->user));
+               *scheme = xstrdup("crypt-extended");
+       } else {
+               /* Default to blowfish */
+               rounds = MAX(rounds, 3);
+               rounds = MIN(rounds, 31);
+               xasprintf(salt, "$2a$%02lld$%s", rounds,
+                   makesalt(22, authctxt->user));
+               *scheme = xstrdup("bcrypt");
+       }
+       xfree(style);
+       debug3("%s: fake %s salt for user %s: %s",
+           __func__, *scheme, authctxt->user, *salt);
+}
+
+/*
+ * Fetch password hashing scheme, password salt and derive shared secret
+ * for user. If user does not exist, a fake but stable and user-unique
+ * salt will be returned.
+ */
+void
+auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
+    char **hash_scheme, char **salt)
+{
+       char *cp;
+       u_char *secret;
+       u_int secret_len, salt_len;
+
+#ifdef JPAKE_DEBUG
+       debug3("%s: valid %d pw %.5s...", __func__,
+           authctxt->valid, authctxt->pw->pw_passwd);
+#endif
+
+       *salt = NULL;
+       *hash_scheme = NULL;
+       if (authctxt->valid) {
+               if (strncmp(authctxt->pw->pw_passwd, "$2$", 3) == 0 &&
+                   strlen(authctxt->pw->pw_passwd) > 28) {
+                       /*
+                        * old-variant bcrypt:
+                        *     "$2$", 2 digit rounds, "$", 22 bytes salt
+                        */
+                       salt_len = 3 + 2 + 1 + 22 + 1;
+                       *salt = xmalloc(salt_len);
+                       strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
+                       *hash_scheme = xstrdup("bcrypt");
+               } else if (strncmp(authctxt->pw->pw_passwd, "$2a$", 4) == 0 &&
+                   strlen(authctxt->pw->pw_passwd) > 29) {
+                       /*
+                        * current-variant bcrypt:
+                        *     "$2a$", 2 digit rounds, "$", 22 bytes salt
+                        */
+                       salt_len = 4 + 2 + 1 + 22 + 1;
+                       *salt = xmalloc(salt_len);
+                       strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
+                       *hash_scheme = xstrdup("bcrypt");
+               } else if (strncmp(authctxt->pw->pw_passwd, "$1$", 3) == 0 &&
+                   strlen(authctxt->pw->pw_passwd) > 5) {
+                       /*
+                        * md5crypt:
+                        *     "$1$", salt until "$"
+                        */
+                       cp = strchr(authctxt->pw->pw_passwd + 3, '$');
+                       if (cp != NULL) {
+                               salt_len = (cp - authctxt->pw->pw_passwd) + 1;
+                               *salt = xmalloc(salt_len);
+                               strlcpy(*salt, authctxt->pw->pw_passwd,
+                                   salt_len);
+                               *hash_scheme = xstrdup("md5crypt");
+                       }
+               } else if (strncmp(authctxt->pw->pw_passwd, "_", 1) == 0 &&
+                   strlen(authctxt->pw->pw_passwd) > 9) {
+                       /*
+                        * BSDI extended crypt:
+                        *     "_", 4 digits count, 4 chars salt
+                        */
+                       salt_len = 1 + 4 + 4 + 1;
+                       *salt = xmalloc(salt_len);
+                       strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
+                       *hash_scheme = xstrdup("crypt-extended");
+               } else if (strlen(authctxt->pw->pw_passwd) == 13  &&
+                   valid_crypt_salt(authctxt->pw->pw_passwd[0]) &&
+                   valid_crypt_salt(authctxt->pw->pw_passwd[1])) {
+                       /*
+                        * traditional crypt:
+                        *     2 chars salt
+                        */
+                       salt_len = 2 + 1;
+                       *salt = xmalloc(salt_len);
+                       strlcpy(*salt, authctxt->pw->pw_passwd, salt_len);
+                       *hash_scheme = xstrdup("crypt");
+               }
+               if (*salt == NULL) {
+                       debug("%s: unrecognised crypt scheme for user %s",
+                           __func__, authctxt->pw->pw_name);
+               }
+       }
+       if (*salt == NULL)
+               fake_salt_and_scheme(authctxt, salt, hash_scheme);
+
+       if (hash_buffer(authctxt->pw->pw_passwd,
+           strlen(authctxt->pw->pw_passwd), EVP_sha256(),
+           &secret, &secret_len) != 0)
+               fatal("%s: hash_buffer", __func__);
+       if ((*s = BN_bin2bn(secret, secret_len, NULL)) == NULL)
+               fatal("%s: BN_bin2bn (secret)", __func__);
+#ifdef JPAKE_DEBUG
+       debug3("%s: salt = %s (len %u)", __func__,
+           *salt, (u_int)strlen(*salt));
+       debug3("%s: scheme = %s", __func__, *hash_scheme);
+       JPAKE_DEBUG_BN((*s, "%s: s = ", __func__));
+#endif
+       bzero(secret, secret_len);
+       xfree(secret);
+}
+
+/*
+ * Begin authentication attempt.
+ * Note, sets authctxt->postponed while in subprotocol
+ */
+static int
+auth2_jpake_start(Authctxt *authctxt)
+{
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       u_char *x3_proof, *x4_proof;
+       u_int x3_proof_len, x4_proof_len;
+       char *salt, *hash_scheme;
+
+       debug("%s: start", __func__);
+
+       PRIVSEP(jpake_step1(pctx->grp,
+           &pctx->server_id, &pctx->server_id_len,
+           &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4,
+           &x3_proof, &x3_proof_len,
+           &x4_proof, &x4_proof_len));
+
+       PRIVSEP(auth2_jpake_get_pwdata(authctxt, &pctx->s,
+           &hash_scheme, &salt));
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
+
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1);
+       packet_put_cstring(hash_scheme);
+       packet_put_cstring(salt);
+       packet_put_string(pctx->server_id, pctx->server_id_len);
+       packet_put_bignum2(pctx->g_x3);
+       packet_put_bignum2(pctx->g_x4);
+       packet_put_string(x3_proof, x3_proof_len);
+       packet_put_string(x4_proof, x4_proof_len);
+       packet_send();
+       packet_write_wait();
+
+       bzero(hash_scheme, strlen(hash_scheme));
+       bzero(salt, strlen(salt));
+       xfree(hash_scheme);
+       xfree(salt);
+       bzero(x3_proof, x3_proof_len);
+       bzero(x4_proof, x4_proof_len);
+       xfree(x3_proof);
+       xfree(x4_proof);
+
+       /* Expect step 1 packet from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1,
+           input_userauth_jpake_client_step1);
+
+       authctxt->postponed = 1;
+       return 0;
+}
+
+/* ARGSUSED */
+static void
+input_userauth_jpake_client_step1(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       u_char *x1_proof, *x2_proof, *x4_s_proof;
+       u_int x1_proof_len, x2_proof_len, x4_s_proof_len;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1, NULL);
+
+       /* Fetch step 1 values */
+       if ((pctx->g_x1 = BN_new()) == NULL ||
+           (pctx->g_x2 = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       pctx->client_id = packet_get_string(&pctx->client_id_len);
+       packet_get_bignum2(pctx->g_x1);
+       packet_get_bignum2(pctx->g_x2);
+       x1_proof = packet_get_string(&x1_proof_len);
+       x2_proof = packet_get_string(&x2_proof_len);
+       packet_check_eom();
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
+
+       PRIVSEP(jpake_step2(pctx->grp, pctx->s, pctx->g_x3,
+           pctx->g_x1, pctx->g_x2, pctx->x4,
+           pctx->client_id, pctx->client_id_len,
+           pctx->server_id, pctx->server_id_len,
+           x1_proof, x1_proof_len,
+           x2_proof, x2_proof_len,
+           &pctx->b,
+           &x4_s_proof, &x4_s_proof_len));
+
+       bzero(x1_proof, x1_proof_len);
+       bzero(x2_proof, x2_proof_len);
+       xfree(x1_proof);
+       xfree(x2_proof);
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
+
+       /* Send values for step 2 */
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2);
+       packet_put_bignum2(pctx->b);
+       packet_put_string(x4_s_proof, x4_s_proof_len);
+       packet_send();
+       packet_write_wait();
+
+       bzero(x4_s_proof, x4_s_proof_len);
+       xfree(x4_s_proof);
+
+       /* Expect step 2 packet from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2,
+           input_userauth_jpake_client_step2);
+}
+
+/* ARGSUSED */
+static void
+input_userauth_jpake_client_step2(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       u_char *x2_s_proof;
+       u_int x2_s_proof_len;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2, NULL);
+
+       if ((pctx->a = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       /* Fetch step 2 values */
+       packet_get_bignum2(pctx->a);
+       x2_s_proof = packet_get_string(&x2_s_proof_len);
+       packet_check_eom();
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
+
+       /* Derive shared key and calculate confirmation hash */
+       PRIVSEP(jpake_key_confirm(pctx->grp, pctx->s, pctx->a,
+           pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2,
+           pctx->server_id, pctx->server_id_len,
+           pctx->client_id, pctx->client_id_len,
+           session_id2, session_id2_len,
+           x2_s_proof, x2_s_proof_len,
+           &pctx->k,
+           &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len));
+
+       bzero(x2_s_proof, x2_s_proof_len);
+       xfree(x2_s_proof);
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
+
+       /* Send key confirmation proof */
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM);
+       packet_put_string(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
+       packet_send();
+       packet_write_wait();
+
+       /* Expect confirmation from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM,
+           input_userauth_jpake_client_confirm);
+}
+
+/* ARGSUSED */
+static void
+input_userauth_jpake_client_confirm(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       int authenticated = 0;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM, NULL);
+
+       pctx->h_k_cid_sessid = packet_get_string(&pctx->h_k_cid_sessid_len);
+       packet_check_eom();
+
+       if (!use_privsep)
+               JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
+
+       /* Verify expected confirmation hash */
+       if (PRIVSEP(jpake_check_confirm(pctx->k,
+           pctx->client_id, pctx->client_id_len,
+           session_id2, session_id2_len,
+           pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len)) == 1)
+               authenticated = authctxt->valid ? 1 : 0;
+       else
+               debug("%s: confirmation mismatch", __func__);
+               
+       /* done */
+       authctxt->postponed = 0;
+       jpake_free(authctxt->jpake_ctx);
+       authctxt->jpake_ctx = NULL;
+       userauth_finish(authctxt, authenticated, method_jpake.name);
+}
+
+#endif /* JPAKE */
+
diff --git a/auth2-kbdint.c b/auth2-kbdint.c
new file mode 100644 (file)
index 0000000..fae67da
--- /dev/null
@@ -0,0 +1,68 @@
+/* $OpenBSD: auth2-kbdint.c,v 1.5 2006/08/03 03:34:41 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 <sys/types.h>
+
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "packet.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+
+/* import */
+extern ServerOptions options;
+
+static int
+userauth_kbdint(Authctxt *authctxt)
+{
+       int authenticated = 0;
+       char *lang, *devs;
+
+       lang = packet_get_string(NULL);
+       devs = packet_get_string(NULL);
+       packet_check_eom();
+
+       debug("keyboard-interactive devs %s", devs);
+
+       if (options.challenge_response_authentication)
+               authenticated = auth2_challenge(authctxt, devs);
+
+       xfree(devs);
+       xfree(lang);
+       return authenticated;
+}
+
+Authmethod method_kbdint = {
+       "keyboard-interactive",
+       userauth_kbdint,
+       &options.kbd_interactive_authentication
+};
diff --git a/auth2-none.c b/auth2-none.c
new file mode 100644 (file)
index 0000000..c8c6c74
--- /dev/null
@@ -0,0 +1,73 @@
+/* $OpenBSD: auth2-none.c,v 1.16 2010/06/25 08:46:17 djm 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "packet.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "compat.h"
+#include "ssh2.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+/* import */
+extern ServerOptions options;
+
+/* "none" is allowed only one time */
+static int none_enabled = 1;
+
+static int
+userauth_none(Authctxt *authctxt)
+{
+       none_enabled = 0;
+       packet_check_eom();
+       if (options.permit_empty_passwd && options.password_authentication)
+               return (PRIVSEP(auth_password(authctxt, "")));
+       return (0);
+}
+
+Authmethod method_none = {
+       "none",
+       userauth_none,
+       &none_enabled
+};
diff --git a/auth2-passwd.c b/auth2-passwd.c
new file mode 100644 (file)
index 0000000..5f1f363
--- /dev/null
@@ -0,0 +1,80 @@
+/* $OpenBSD: auth2-passwd.c,v 1.9 2006/08/03 03:34:41 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 <sys/types.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "packet.h"
+#include "log.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "buffer.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "servconf.h"
+
+/* import */
+extern ServerOptions options;
+
+static int
+userauth_passwd(Authctxt *authctxt)
+{
+       char *password, *newpass;
+       int authenticated = 0;
+       int change;
+       u_int len, newlen;
+
+       change = packet_get_char();
+       password = packet_get_string(&len);
+       if (change) {
+               /* discard new password from packet */
+               newpass = packet_get_string(&newlen);
+               memset(newpass, 0, newlen);
+               xfree(newpass);
+       }
+       packet_check_eom();
+
+       if (change)
+               logit("password change not supported");
+       else if (PRIVSEP(auth_password(authctxt, password)) == 1)
+               authenticated = 1;
+       memset(password, 0, len);
+       xfree(password);
+       return authenticated;
+}
+
+Authmethod method_passwd = {
+       "password",
+       userauth_passwd,
+       &options.password_authentication
+};
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
new file mode 100644 (file)
index 0000000..7d21413
--- /dev/null
@@ -0,0 +1,468 @@
+/* $OpenBSD: auth2-pubkey.c,v 1.27 2010/11/20 05:12:38 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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "compat.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "pathnames.h"
+#include "uidswap.h"
+#include "auth-options.h"
+#include "canohost.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "misc.h"
+#include "authfile.h"
+#include "match.h"
+
+/* import */
+extern ServerOptions options;
+extern u_char *session_id2;
+extern u_int session_id2_len;
+
+static int
+userauth_pubkey(Authctxt *authctxt)
+{
+       Buffer b;
+       Key *key = NULL;
+       char *pkalg;
+       u_char *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 */
+               logit("userauth_pubkey: unsupported public key algorithm: %s",
+                   pkalg);
+               goto done;
+       }
+       key = key_from_blob(pkblob, blen);
+       if (key == NULL) {
+               error("userauth_pubkey: cannot decode key: %s", pkalg);
+               goto done;
+       }
+       if (key->type != pktype) {
+               error("userauth_pubkey: type mismatch for decoded key "
+                   "(received %d, expected %d)", key->type, pktype);
+               goto done;
+       }
+       if (have_sig) {
+               sig = packet_get_string(&slen);
+               packet_check_eom();
+               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 */
+               authenticated = 0;
+               if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
+                   PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
+                   buffer_len(&b))) == 1)
+                       authenticated = 1;
+               buffer_free(&b);
+               xfree(sig);
+       } else {
+               debug("test whether pkalg/pkblob are acceptable");
+               packet_check_eom();
+
+               /* 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 (PRIVSEP(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();
+done:
+       debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
+       if (key != NULL)
+               key_free(key);
+       xfree(pkalg);
+       xfree(pkblob);
+       return authenticated;
+}
+
+static int
+match_principals_option(const char *principal_list, struct KeyCert *cert)
+{
+       char *result;
+       u_int i;
+
+       /* XXX percent_expand() sequences for authorized_principals? */
+
+       for (i = 0; i < cert->nprincipals; i++) {
+               if ((result = match_list(cert->principals[i],
+                   principal_list, NULL)) != NULL) {
+                       debug3("matched principal from key options \"%.100s\"",
+                           result);
+                       xfree(result);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int
+match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
+{
+       FILE *f;
+       char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
+       u_long linenum = 0;
+       u_int i;
+
+       temporarily_use_uid(pw);
+       debug("trying authorized principals file %s", file);
+       if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
+               restore_uid();
+               return 0;
+       }
+       while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+               /* Skip leading whitespace. */
+               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               /* Skip blank and comment lines. */
+               if ((ep = strchr(cp, '#')) != NULL)
+                       *ep = '\0';
+               if (!*cp || *cp == '\n')
+                       continue;
+               /* Trim trailing whitespace. */
+               ep = cp + strlen(cp) - 1;
+               while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
+                       *ep-- = '\0';
+               /*
+                * If the line has internal whitespace then assume it has
+                * key options.
+                */
+               line_opts = NULL;
+               if ((ep = strrchr(cp, ' ')) != NULL ||
+                   (ep = strrchr(cp, '\t')) != NULL) {
+                       for (; *ep == ' ' || *ep == '\t'; ep++)
+                               ;
+                       line_opts = cp;
+                       cp = ep;
+               }
+               for (i = 0; i < cert->nprincipals; i++) {
+                       if (strcmp(cp, cert->principals[i]) == 0) {
+                               debug3("matched principal from file \"%.100s\"",
+                                   cert->principals[i]);
+                               if (auth_parse_options(pw, line_opts,
+                                   file, linenum) != 1)
+                                       continue;
+                               fclose(f);
+                               restore_uid();
+                               return 1;
+                       }
+               }
+       }
+       fclose(f);
+       restore_uid();
+       return 0;
+}      
+
+/* return 1 if user allows given key */
+static int
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
+{
+       char line[SSH_MAX_PUBKEY_BYTES];
+       const char *reason;
+       int found_key = 0;
+       FILE *f;
+       u_long linenum = 0;
+       Key *found;
+       char *fp;
+
+       /* Temporarily use the user's uid. */
+       temporarily_use_uid(pw);
+
+       debug("trying public key file %s", file);
+       f = auth_openkeyfile(file, pw, options.strict_modes);
+
+       if (!f) {
+               restore_uid();
+               return 0;
+       }
+
+       found_key = 0;
+       found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
+
+       while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+               char *cp, *key_options = NULL;
+
+               auth_clear_options();
+
+               /* 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);
+                       key_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_is_cert(key)) {
+                       if (!key_equal(found, key->cert->signature_key))
+                               continue;
+                       if (auth_parse_options(pw, key_options, file,
+                           linenum) != 1)
+                               continue;
+                       if (!key_is_cert_authority)
+                               continue;
+                       fp = key_fingerprint(found, SSH_FP_MD5,
+                           SSH_FP_HEX);
+                       debug("matching CA found: file %s, line %lu, %s %s",
+                           file, linenum, key_type(found), fp);
+                       /*
+                        * If the user has specified a list of principals as
+                        * a key option, then prefer that list to matching
+                        * their username in the certificate principals list.
+                        */
+                       if (authorized_principals != NULL &&
+                           !match_principals_option(authorized_principals,
+                           key->cert)) {
+                               reason = "Certificate does not contain an "
+                                   "authorized principal";
+ fail_reason:
+                               xfree(fp);
+                               error("%s", reason);
+                               auth_debug_add("%s", reason);
+                               continue;
+                       }
+                       if (key_cert_check_authority(key, 0, 0,
+                           authorized_principals == NULL ? pw->pw_name : NULL,
+                           &reason) != 0)
+                               goto fail_reason;
+                       if (auth_cert_options(key, pw) != 0) {
+                               xfree(fp);
+                               continue;
+                       }
+                       verbose("Accepted certificate ID \"%s\" "
+                           "signed by %s CA %s via %s", key->cert->key_id,
+                           key_type(found), fp, file);
+                       xfree(fp);
+                       found_key = 1;
+                       break;
+               } else if (key_equal(found, key)) {
+                       if (auth_parse_options(pw, key_options, file,
+                           linenum) != 1)
+                               continue;
+                       if (key_is_cert_authority)
+                               continue;
+                       found_key = 1;
+                       debug("matching key found: file %s, line %lu",
+                           file, linenum);
+                       fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+                       verbose("Found matching %s key: %s",
+                           key_type(found), fp);
+                       xfree(fp);
+                       break;
+               }
+       }
+       restore_uid();
+       fclose(f);
+       key_free(found);
+       if (!found_key)
+               debug2("key not found");
+       return found_key;
+}
+
+/* Authenticate a certificate key against TrustedUserCAKeys */
+static int
+user_cert_trusted_ca(struct passwd *pw, Key *key)
+{
+       char *ca_fp, *principals_file = NULL;
+       const char *reason;
+       int ret = 0;
+
+       if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
+               return 0;
+
+       ca_fp = key_fingerprint(key->cert->signature_key,
+           SSH_FP_MD5, SSH_FP_HEX);
+
+       if (key_in_file(key->cert->signature_key,
+           options.trusted_user_ca_keys, 1) != 1) {
+               debug2("%s: CA %s %s is not listed in %s", __func__,
+                   key_type(key->cert->signature_key), ca_fp,
+                   options.trusted_user_ca_keys);
+               goto out;
+       }
+       /*
+        * If AuthorizedPrincipals is in use, then compare the certificate
+        * principals against the names in that file rather than matching
+        * against the username.
+        */
+       if ((principals_file = authorized_principals_file(pw)) != NULL) {
+               if (!match_principals_file(principals_file, pw, key->cert)) {
+                       reason = "Certificate does not contain an "
+                           "authorized principal";
+ fail_reason:
+                       error("%s", reason);
+                       auth_debug_add("%s", reason);
+                       goto out;
+               }
+       }
+       if (key_cert_check_authority(key, 0, 1,
+           principals_file == NULL ? pw->pw_name : NULL, &reason) != 0)
+               goto fail_reason;
+       if (auth_cert_options(key, pw) != 0)
+               goto out;
+
+       verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",
+           key->cert->key_id, key_type(key->cert->signature_key), ca_fp,
+           options.trusted_user_ca_keys);
+       ret = 1;
+
+ out:
+       if (principals_file != NULL)
+               xfree(principals_file);
+       if (ca_fp != NULL)
+               xfree(ca_fp);
+       return ret;
+}
+
+/* check whether given key is in .ssh/authorized_keys* */
+int
+user_key_allowed(struct passwd *pw, Key *key)
+{
+       int success;
+       char *file;
+
+       if (auth_key_is_revoked(key))
+               return 0;
+       if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
+               return 0;
+
+       success = user_cert_trusted_ca(pw, key);
+       if (success)
+               return success;
+
+       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;
+}
+
+Authmethod method_pubkey = {
+       "publickey",
+       userauth_pubkey,
+       &options.pubkey_authentication
+};
diff --git a/auth2.c b/auth2.c
new file mode 100644 (file)
index 0000000..95820f9
--- /dev/null
+++ b/auth2.c
@@ -0,0 +1,407 @@
+/* $OpenBSD: auth2.c,v 1.122 2010/08/31 09:58:37 djm 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "compat.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "dispatch.h"
+#include "pathnames.h"
+#include "buffer.h"
+
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+/* import */
+extern ServerOptions options;
+extern u_char *session_id2;
+extern u_int session_id2_len;
+extern Buffer loginmsg;
+
+/* methods */
+
+extern Authmethod method_none;
+extern Authmethod method_pubkey;
+extern Authmethod method_passwd;
+extern Authmethod method_kbdint;
+extern Authmethod method_hostbased;
+#ifdef GSSAPI
+extern Authmethod method_gssapi;
+#endif
+#ifdef JPAKE
+extern Authmethod method_jpake;
+#endif
+
+Authmethod *authmethods[] = {
+       &method_none,
+       &method_pubkey,
+#ifdef GSSAPI
+       &method_gssapi,
+#endif
+#ifdef JPAKE
+       &method_jpake,
+#endif
+       &method_passwd,
+       &method_kbdint,
+       &method_hostbased,
+       NULL
+};
+
+/* protocol */
+
+static void input_service_request(int, u_int32_t, void *);
+static void input_userauth_request(int, u_int32_t, void *);
+
+/* helper */
+static Authmethod *authmethod_lookup(const char *);
+static char *authmethods_get(void);
+
+char *
+auth2_read_banner(void)
+{
+       struct stat st;
+       char *banner = NULL;
+       size_t len, n;
+       int fd;
+
+       if ((fd = open(options.banner, O_RDONLY)) == -1)
+               return (NULL);
+       if (fstat(fd, &st) == -1) {
+               close(fd);
+               return (NULL);
+       }
+       if (st.st_size > 1*1024*1024) {
+               close(fd);
+               return (NULL);
+       }
+
+       len = (size_t)st.st_size;               /* truncate */
+       banner = xmalloc(len + 1);
+       n = atomicio(read, fd, banner, len);
+       close(fd);
+
+       if (n != len) {
+               xfree(banner);
+               return (NULL);
+       }
+       banner[n] = '\0';
+
+       return (banner);
+}
+
+void
+userauth_send_banner(const char *msg)
+{
+       if (datafellows & SSH_BUG_BANNER)
+               return;
+
+       packet_start(SSH2_MSG_USERAUTH_BANNER);
+       packet_put_cstring(msg);
+       packet_put_cstring("");         /* language, unused */
+       packet_send();
+       debug("%s: sent", __func__);
+}
+
+static void
+userauth_banner(void)
+{
+       char *banner = NULL;
+
+       if (options.banner == NULL ||
+           strcasecmp(options.banner, "none") == 0 ||
+           (datafellows & SSH_BUG_BANNER) != 0)
+               return;
+
+       if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
+               goto done;
+       userauth_send_banner(banner);
+
+done:
+       if (banner)
+               xfree(banner);
+}
+
+/*
+ * loop until authctxt->success == TRUE
+ */
+void
+do_authentication2(Authctxt *authctxt)
+{
+       dispatch_init(&dispatch_protocol_error);
+       dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+       dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
+}
+
+/*ARGSUSED*/
+static void
+input_service_request(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       u_int len;
+       int acceptit = 0;
+       char *service = packet_get_cstring(&len);
+       packet_check_eom();
+
+       if (authctxt == NULL)
+               fatal("input_service_request: no authctxt");
+
+       if (strcmp(service, "ssh-userauth") == 0) {
+               if (!authctxt->success) {
+                       acceptit = 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 (acceptit) {
+               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);
+}
+
+/*ARGSUSED*/
+static void
+input_userauth_request(int type, u_int32_t seq, 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_cstring(NULL);
+       service = packet_get_cstring(NULL);
+       method = packet_get_cstring(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 */
+               authctxt->pw = PRIVSEP(getpwnamallow(user));
+               authctxt->user = xstrdup(user);
+               if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
+                       authctxt->valid = 1;
+                       debug2("input_userauth_request: setting up authctxt for %s", user);
+               } else {
+                       logit("input_userauth_request: invalid user %s", user);
+                       authctxt->pw = fakepw();
+#ifdef SSH_AUDIT_EVENTS
+                       PRIVSEP(audit_event(SSH_INVALID_USER));
+#endif
+               }
+#ifdef USE_PAM
+               if (options.use_pam)
+                       PRIVSEP(start_pam(authctxt));
+#endif
+               setproctitle("%s%s", authctxt->valid ? user : "unknown",
+                   use_privsep ? " [net]" : "");
+               authctxt->service = xstrdup(service);
+               authctxt->style = style ? xstrdup(style) : NULL;
+               if (use_privsep)
+                       mm_inform_authserv(service, style);
+               userauth_banner();
+       } else if (strcmp(user, authctxt->user) != 0 ||
+           strcmp(service, authctxt->service) != 0) {
+               packet_disconnect("Change of username or service not allowed: "
+                   "(%s,%s) -> (%s,%s)",
+                   authctxt->user, authctxt->service, user, service);
+       }
+       /* reset state */
+       auth2_challenge_stop(authctxt);
+#ifdef JPAKE
+       auth2_jpake_stop(authctxt);
+#endif
+
+#ifdef GSSAPI
+       /* XXX move to auth2_gssapi_stop() */
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+#endif
+
+       authctxt->postponed = 0;
+
+       /* try to authenticate user */
+       m = authmethod_lookup(method);
+       if (m != NULL && authctxt->failures < options.max_authtries) {
+               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 SSH_AUDIT_EVENTS
+               PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
+#endif
+       }
+
+#ifdef USE_PAM
+       if (options.use_pam && authenticated) {
+               if (!PRIVSEP(do_pam_account())) {
+                       /* if PAM returned a message, send it to the user */
+                       if (buffer_len(&loginmsg) > 0) {
+                               buffer_append(&loginmsg, "\0", 1);
+                               userauth_send_banner(buffer_ptr(&loginmsg));
+                               packet_write_wait();
+                       }
+                       fatal("Access denied for user %s by PAM account "
+                           "configuration", authctxt->user);
+               }
+       }
+#endif
+
+#ifdef _UNICOS
+       if (authenticated && cray_access_denied(authctxt->user)) {
+               authenticated = 0;
+               fatal("Access denied for user %s.",authctxt->user);
+       }
+#endif /* _UNICOS */
+
+       /* 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, &dispatch_protocol_ignore);
+               packet_start(SSH2_MSG_USERAUTH_SUCCESS);
+               packet_send();
+               packet_write_wait();
+               /* now we can break out */
+               authctxt->success = 1;
+       } else {
+
+               /* Allow initial try of "none" auth without failure penalty */
+               if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
+                       authctxt->failures++;
+               if (authctxt->failures >= options.max_authtries) {
+#ifdef SSH_AUDIT_EVENTS
+                       PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
+#endif
+                       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 char *
+authmethods_get(void)
+{
+       Buffer b;
+       char *list;
+       int i;
+
+       buffer_init(&b);
+       for (i = 0; authmethods[i] != NULL; i++) {
+               if (strcmp(authmethods[i]->name, "none") == 0)
+                       continue;
+               if (authmethods[i]->enabled != NULL &&
+                   *(authmethods[i]->enabled) != 0) {
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       buffer_append(&b, authmethods[i]->name,
+                           strlen(authmethods[i]->name));
+               }
+       }
+       buffer_append(&b, "\0", 1);
+       list = xstrdup(buffer_ptr(&b));
+       buffer_free(&b);
+       return list;
+}
+
+static Authmethod *
+authmethod_lookup(const char *name)
+{
+       int i;
+
+       if (name != NULL)
+               for (i = 0; authmethods[i] != NULL; i++)
+                       if (authmethods[i]->enabled != NULL &&
+                           *(authmethods[i]->enabled) != 0 &&
+                           strcmp(name, authmethods[i]->name) == 0)
+                               return authmethods[i];
+       debug2("Unrecognized authentication method name: %s",
+           name ? name : "NULL");
+       return NULL;
+}
+
diff --git a/authfd.c b/authfd.c
new file mode 100644 (file)
index 0000000..c11c3f5
--- /dev/null
+++ b/authfd.c
@@ -0,0 +1,707 @@
+/* $OpenBSD: authfd.c,v 1.84 2010/08/31 11:54:45 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+
+#include <openssl/evp.h>
+
+#include <openssl/crypto.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "key.h"
+#include "authfd.h"
+#include "cipher.h"
+#include "kex.h"
+#include "compat.h"
+#include "log.h"
+#include "atomicio.h"
+#include "misc.h"
+
+static int agent_present = 0;
+
+/* 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))
+
+int
+ssh_agent_present(void)
+{
+       int authfd;
+
+       if (agent_present)
+               return 1;
+       if ((authfd = ssh_get_authentication_socket()) == -1)
+               return 0;
+       else {
+               ssh_close_authentication_socket(authfd);
+               return 1;
+       }
+}
+
+/* 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;
+       }
+       agent_present = 1;
+       return sock;
+}
+
+static int
+ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply)
+{
+       u_int l, len;
+       char buf[1024];
+
+       /* Get the length of the message, and format it in the buffer. */
+       len = buffer_len(request);
+       put_u32(buf, len);
+
+       /* Send the length and then the packet to the agent. */
+       if (atomicio(vwrite, auth->fd, buf, 4) != 4 ||
+           atomicio(vwrite, 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.
+        */
+       if (atomicio(read, auth->fd, buf, 4) != 4) {
+           error("Error reading response length from authentication socket.");
+           return 0;
+       }
+
+       /* Extract the length, and check it for sanity. */
+       len = get_u32(buf);
+       if (len > 256 * 1024)
+               fatal("Authentication response too long: %u", 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);
+               if (atomicio(read, auth->fd, buf, l) != l) {
+                       error("Error reading response from authentication socket.");
+                       return 0;
+               }
+               buffer_append(reply, 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);
+}
+
+/* Lock/unlock agent */
+int
+ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password)
+{
+       int type;
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK);
+       buffer_put_cstring(&msg, password);
+
+       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);
+}
+
+/*
+ * 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 ((u_int)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)
+{
+       int keybits;
+       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);
+               keybits = BN_num_bits(key->rsa->n);
+               if (keybits < 0 || bits != (u_int)keybits)
+                       logit("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;
+       }
+       /* 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) {
+               logit("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, 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)) {
+               logit("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] = (u_char)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, u_int *lenp,
+    u_char *data, u_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)) {
+               logit("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_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_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_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
+                       fatal("%s: no cert/certblob", __func__);
+               buffer_put_string(b, buffer_ptr(&key->cert->certblob),
+                   buffer_len(&key->cert->certblob));
+               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;
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
+                       fatal("%s: no cert/certblob", __func__);
+               buffer_put_string(b, buffer_ptr(&key->cert->certblob),
+                   buffer_len(&key->cert->certblob));
+               buffer_put_bignum2(b, key->dsa->priv_key);
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               buffer_put_cstring(b, key_curve_nid_to_name(key->ecdsa_nid));
+               buffer_put_ecpoint(b, EC_KEY_get0_group(key->ecdsa),
+                   EC_KEY_get0_public_key(key->ecdsa));
+               buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
+               break;
+       case KEY_ECDSA_CERT:
+               if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0)
+                       fatal("%s: no cert/certblob", __func__);
+               buffer_put_string(b, buffer_ptr(&key->cert->certblob),
+                   buffer_len(&key->cert->certblob));
+               buffer_put_bignum2(b, EC_KEY_get0_private_key(key->ecdsa));
+               break;
+#endif
+       }
+       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_constrained(AuthenticationConnection *auth, Key *key,
+    const char *comment, u_int life, u_int confirm)
+{
+       Buffer msg;
+       int type, constrained = (life || confirm);
+
+       buffer_init(&msg);
+
+       switch (key->type) {
+       case KEY_RSA1:
+               type = constrained ?
+                   SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
+                   SSH_AGENTC_ADD_RSA_IDENTITY;
+               buffer_put_char(&msg, type);
+               ssh_encode_identity_rsa1(&msg, key->rsa, comment);
+               break;
+       case KEY_RSA:
+       case KEY_RSA_CERT:
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA:
+       case KEY_DSA_CERT:
+       case KEY_DSA_CERT_V00:
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               type = constrained ?
+                   SSH2_AGENTC_ADD_ID_CONSTRAINED :
+                   SSH2_AGENTC_ADD_IDENTITY;
+               buffer_put_char(&msg, type);
+               ssh_encode_identity_ssh2(&msg, key, comment);
+               break;
+       default:
+               buffer_free(&msg);
+               return 0;
+       }
+       if (constrained) {
+               if (life != 0) {
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
+                       buffer_put_int(&msg, life);
+               }
+               if (confirm != 0)
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);
+       }
+       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_plain(key->type) == KEY_DSA ||
+           key_type_plain(key->type) == KEY_RSA ||
+           key_type_plain(key->type) == KEY_ECDSA) {
+               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, const char *pin, u_int life, u_int confirm)
+{
+       Buffer msg;
+       int type, constrained = (life || confirm);
+
+       if (add) {
+               type = constrained ?
+                   SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED :
+                   SSH_AGENTC_ADD_SMARTCARD_KEY;
+       } else
+               type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, type);
+       buffer_put_cstring(&msg, reader_id);
+       buffer_put_cstring(&msg, pin);
+
+       if (constrained) {
+               if (life != 0) {
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME);
+                       buffer_put_int(&msg, life);
+               }
+               if (confirm != 0)
+                       buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM);
+       }
+
+       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:
+               logit("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/authfd.h b/authfd.h
new file mode 100644 (file)
index 0000000..2582a27
--- /dev/null
+++ b/authfd.h
@@ -0,0 +1,94 @@
+/* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#ifndef AUTHFD_H
+#define AUTHFD_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
+
+/* lock/unlock the agent */
+#define SSH_AGENTC_LOCK                                22
+#define SSH_AGENTC_UNLOCK                      23
+
+/* add key with constraints */
+#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED      24
+#define SSH2_AGENTC_ADD_ID_CONSTRAINED         25
+#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
+
+#define        SSH_AGENT_CONSTRAIN_LIFETIME            1
+#define        SSH_AGENT_CONSTRAIN_CONFIRM             2
+
+/* 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_agent_present(void);
+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_constrained(AuthenticationConnection *, Key *,
+    const char *, u_int, u_int);
+int     ssh_remove_identity(AuthenticationConnection *, Key *);
+int     ssh_remove_all_identities(AuthenticationConnection *, int);
+int     ssh_lock_agent(AuthenticationConnection *, int, const char *);
+int     ssh_update_card(AuthenticationConnection *, int, const char *,
+    const char *, u_int, u_int);
+
+int
+ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16],
+    u_int, u_char[16]);
+
+int
+ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *,
+    u_int);
+
+#endif                         /* AUTHFD_H */
diff --git a/authfile.c b/authfile.c
new file mode 100644 (file)
index 0000000..f2aec26
--- /dev/null
@@ -0,0 +1,908 @@
+/* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 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 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"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/uio.h>
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "cipher.h"
+#include "buffer.h"
+#include "key.h"
+#include "ssh.h"
+#include "log.h"
+#include "authfile.h"
+#include "rsa.h"
+#include "misc.h"
+#include "atomicio.h"
+
+/* Version identification string for SSH v1 identity files. */
+static const char authfile_id_string[] =
+    "SSH PRIVATE KEY FILE FORMAT 1.1\n";
+
+/*
+ * Serialises the authentication (private) key to a blob, encrypting it with
+ * passphrase.  The identification of the blob (lowest 64 bits of n) will
+ * precede the key to provide identification of the key without needing a
+ * passphrase.
+ */
+static int
+key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
+    const char *comment)
+{
+       Buffer buffer, encrypted;
+       u_char buf[100], *cp;
+       int i, cipher_num;
+       CipherContext ciphercontext;
+       Cipher *cipher;
+       u_int32_t rnd;
+
+       /*
+        * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
+        * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
+        */
+       cipher_num = (strcmp(passphrase, "") == 0) ?
+           SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
+       if ((cipher = cipher_by_number(cipher_num)) == 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. */
+       rnd = arc4random();
+       buf[0] = rnd & 0xff;
+       buf[1] = (rnd >> 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_num);
+       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. */
+       cp = buffer_append_space(&encrypted, buffer_len(&buffer));
+
+       cipher_set_key_string(&ciphercontext, cipher, passphrase,
+           CIPHER_ENCRYPT);
+       cipher_crypt(&ciphercontext, cp,
+           buffer_ptr(&buffer), buffer_len(&buffer));
+       cipher_cleanup(&ciphercontext);
+       memset(&ciphercontext, 0, sizeof(ciphercontext));
+
+       /* Destroy temporary data. */
+       memset(buf, 0, sizeof(buf));
+       buffer_free(&buffer);
+
+       buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
+       buffer_free(&encrypted);
+
+       return 1;
+}
+
+/* convert SSH v2 key in OpenSSL PEM format */
+static int
+key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
+    const char *comment)
+{
+       int success = 0;
+       int blen, len = strlen(_passphrase);
+       u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
+#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
+       const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
+#else
+       const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
+#endif
+       const u_char *bptr;
+       BIO *bio;
+
+       if (len > 0 && len <= 4) {
+               error("passphrase too short: have %d bytes, need > 4", len);
+               return 0;
+       }
+       if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+               error("%s: BIO_new failed", __func__);
+               return 0;
+       }
+       switch (key->type) {
+       case KEY_DSA:
+               success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
+                   cipher, passphrase, len, NULL, NULL);
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
+                   cipher, passphrase, len, NULL, NULL);
+               break;
+#endif
+       case KEY_RSA:
+               success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
+                   cipher, passphrase, len, NULL, NULL);
+               break;
+       }
+       if (success) {
+               if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
+                       success = 0;
+               else
+                       buffer_append(blob, bptr, blen);
+       }
+       BIO_free(bio);
+       return success;
+}
+
+/* Save a key blob to a file */
+static int
+key_save_private_blob(Buffer *keybuf, const char *filename)
+{
+       int fd;
+
+       if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
+               error("open %s failed: %s.", filename, strerror(errno));
+               return 0;
+       }
+       if (atomicio(vwrite, fd, buffer_ptr(keybuf),
+           buffer_len(keybuf)) != buffer_len(keybuf)) {
+               error("write to key file %s failed: %s", filename,
+                   strerror(errno));
+               close(fd);
+               unlink(filename);
+               return 0;
+       }
+       close(fd);
+       return 1;
+}
+
+/* Serialise "key" to buffer "blob" */
+static int
+key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
+    const char *comment)
+{
+       switch (key->type) {
+       case KEY_RSA1:
+               return key_private_rsa1_to_blob(key, blob, passphrase, comment);
+       case KEY_DSA:
+       case KEY_ECDSA:
+       case KEY_RSA:
+               return key_private_pem_to_blob(key, blob, passphrase, comment);
+       default:
+               error("%s: cannot save key type %d", __func__, key->type);
+               return 0;
+       }
+}
+
+int
+key_save_private(Key *key, const char *filename, const char *passphrase,
+    const char *comment)
+{
+       Buffer keyblob;
+       int success = 0;
+
+       buffer_init(&keyblob);
+       if (!key_private_to_blob(key, &keyblob, passphrase, comment))
+               goto out;
+       if (!key_save_private_blob(&keyblob, filename))
+               goto out;
+       success = 1;
+ out:
+       buffer_free(&keyblob);
+       return success;
+}
+
+/*
+ * Parse the public, unencrypted portion of a RSA1 key.
+ */
+static Key *
+key_parse_public_rsa1(Buffer *blob, char **commentp)
+{
+       Key *pub;
+
+       /* Check that it is at least big enough to contain the ID string. */
+       if (buffer_len(blob) < sizeof(authfile_id_string)) {
+               debug3("Truncated RSA1 identifier");
+               return NULL;
+       }
+
+       /*
+        * Make sure it begins with the id string.  Consume the id string
+        * from the buffer.
+        */
+       if (memcmp(buffer_ptr(blob), authfile_id_string,
+           sizeof(authfile_id_string)) != 0) {
+               debug3("Incorrect RSA1 identifier");
+               return NULL;
+       }
+       buffer_consume(blob, sizeof(authfile_id_string));
+
+       /* Skip cipher type and reserved data. */
+       (void) buffer_get_char(blob);   /* cipher type */
+       (void) buffer_get_int(blob);            /* reserved */
+
+       /* Read the public key from the buffer. */
+       (void) buffer_get_int(blob);
+       pub = key_new(KEY_RSA1);
+       buffer_get_bignum(blob, pub->rsa->n);
+       buffer_get_bignum(blob, pub->rsa->e);
+       if (commentp)
+               *commentp = buffer_get_string(blob, NULL);
+       /* The encrypted private part is not parsed by this function. */
+       buffer_clear(blob);
+
+       return pub;
+}
+
+/* Load the contents of a key file into a buffer */
+static int
+key_load_file(int fd, const char *filename, Buffer *blob)
+{
+       size_t len;
+       u_char *cp;
+       struct stat st;
+
+       if (fstat(fd, &st) < 0) {
+               error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
+                   filename == NULL ? "" : filename,
+                   filename == NULL ? "" : " ",
+                   strerror(errno));
+               close(fd);
+               return 0;
+       }
+       if (st.st_size > 1*1024*1024) {
+               error("%s: key file %.200s%stoo large", __func__,
+                   filename == NULL ? "" : filename,
+                   filename == NULL ? "" : " ");
+               close(fd);
+               return 0;
+       }
+       len = (size_t)st.st_size;               /* truncated */
+
+       buffer_init(blob);
+       cp = buffer_append_space(blob, len);
+
+       if (atomicio(read, fd, cp, len) != len) {
+               debug("%s: read from key file %.200s%sfailed: %.100s", __func__,
+                   filename == NULL ? "" : filename,
+                   filename == NULL ? "" : " ",
+                   strerror(errno));
+               buffer_clear(blob);
+               close(fd);
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * 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;
+
+       buffer_init(&buffer);
+       if (!key_load_file(fd, filename, &buffer)) {
+               buffer_free(&buffer);
+               return NULL;
+       }
+
+       pub = key_parse_public_rsa1(&buffer, commentp);
+       if (pub == NULL)
+               debug3("Could not load \"%s\" as a RSA1 public key", filename);
+       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;
+}
+
+static Key *
+key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
+{
+       int check1, check2, cipher_type;
+       Buffer decrypted;
+       u_char *cp;
+       CipherContext ciphercontext;
+       Cipher *cipher;
+       Key *prv = NULL;
+
+       /* Check that it is at least big enough to contain the ID string. */
+       if (buffer_len(blob) < sizeof(authfile_id_string)) {
+               debug3("Truncated RSA1 identifier");
+               return NULL;
+       }
+
+       /*
+        * Make sure it begins with the id string.  Consume the id string
+        * from the buffer.
+        */
+       if (memcmp(buffer_ptr(blob), authfile_id_string,
+           sizeof(authfile_id_string)) != 0) {
+               debug3("Incorrect RSA1 identifier");
+               return NULL;
+       }
+       buffer_consume(blob, sizeof(authfile_id_string));
+
+       /* Read cipher type. */
+       cipher_type = buffer_get_char(blob);
+       (void) buffer_get_int(blob);    /* Reserved data. */
+
+       /* Read the public key from the buffer. */
+       (void) buffer_get_int(blob);
+       prv = key_new_private(KEY_RSA1);
+
+       buffer_get_bignum(blob, prv->rsa->n);
+       buffer_get_bignum(blob, prv->rsa->e);
+       if (commentp)
+               *commentp = buffer_get_string(blob, NULL);
+       else
+               (void)buffer_get_string_ptr(blob, NULL);
+
+       /* Check that it is a supported cipher. */
+       cipher = cipher_by_number(cipher_type);
+       if (cipher == NULL) {
+               debug("Unsupported RSA1 cipher %d", cipher_type);
+               goto fail;
+       }
+       /* Initialize space for decrypted data. */
+       buffer_init(&decrypted);
+       cp = buffer_append_space(&decrypted, buffer_len(blob));
+
+       /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
+       cipher_set_key_string(&ciphercontext, cipher, passphrase,
+           CIPHER_DECRYPT);
+       cipher_crypt(&ciphercontext, cp,
+           buffer_ptr(blob), buffer_len(blob));
+       cipher_cleanup(&ciphercontext);
+       memset(&ciphercontext, 0, sizeof(ciphercontext));
+       buffer_clear(blob);
+
+       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 RSA1 key");
+               /* 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 */
+       rsa_generate_additional_parameters(prv->rsa);
+
+       buffer_free(&decrypted);
+
+       /* enable blinding */
+       if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+               error("%s: RSA_blinding_on failed", __func__);
+               goto fail;
+       }
+       return prv;
+
+fail:
+       if (commentp)
+               xfree(*commentp);
+       key_free(prv);
+       return NULL;
+}
+
+static Key *
+key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
+    char **commentp)
+{
+       EVP_PKEY *pk = NULL;
+       Key *prv = NULL;
+       char *name = "<no key>";
+       BIO *bio;
+
+       if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
+           buffer_len(blob))) == NULL) {
+               error("%s: BIO_new_mem_buf failed", __func__);
+               return NULL;
+       }
+       
+       pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
+       BIO_free(bio);
+       if (pk == NULL) {
+               debug("%s: PEM_read_PrivateKey failed", __func__);
+               (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
+               if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+                       error("%s: RSA_blinding_on failed", __func__);
+                       key_free(prv);
+                       prv = NULL;
+               }
+       } 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
+#ifdef OPENSSL_HAS_ECC
+       } else if (pk->type == EVP_PKEY_EC &&
+           (type == KEY_UNSPEC||type==KEY_ECDSA)) {
+               prv = key_new(KEY_UNSPEC);
+               prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
+               prv->type = KEY_ECDSA;
+               if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
+                   key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
+                   key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
+                   EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
+                   key_ec_validate_private(prv->ecdsa) != 0) {
+                       error("%s: bad ECDSA key", __func__);
+                       key_free(prv);
+                       prv = NULL;
+               }
+               name = "ecdsa w/o comment";
+#ifdef DEBUG_PK
+               if (prv != NULL && prv->ecdsa != NULL)
+                       key_dump_ec_key(prv->ecdsa);
+#endif
+#endif /* OPENSSL_HAS_ECC */
+       } else {
+               error("%s: PEM_read_PrivateKey: mismatch or "
+                   "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
+       }
+       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;
+}
+
+Key *
+key_load_private_pem(int fd, int type, const char *passphrase,
+    char **commentp)
+{
+       Buffer buffer;
+       Key *prv;
+
+       buffer_init(&buffer);
+       if (!key_load_file(fd, NULL, &buffer)) {
+               buffer_free(&buffer);
+               return NULL;
+       }
+       prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
+       buffer_free(&buffer);
+       return prv;
+}
+
+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.",
+                   (u_int)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;
+}
+
+static Key *
+key_parse_private_type(Buffer *blob, int type, const char *passphrase,
+    char **commentp)
+{
+       switch (type) {
+       case KEY_RSA1:
+               return key_parse_private_rsa1(blob, passphrase, commentp);
+       case KEY_DSA:
+       case KEY_ECDSA:
+       case KEY_RSA:
+       case KEY_UNSPEC:
+               return key_parse_private_pem(blob, type, passphrase, commentp);
+       default:
+               break;
+       }
+       return NULL;
+}
+
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+    char **commentp, int *perm_ok)
+{
+       int fd;
+       Key *ret;
+       Buffer buffer;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               debug("could not open key file '%s': %s", filename,
+                   strerror(errno));
+               if (perm_ok != NULL)
+                       *perm_ok = 0;
+               return NULL;
+       }
+       if (!key_perm_ok(fd, filename)) {
+               if (perm_ok != NULL)
+                       *perm_ok = 0;
+               error("bad permissions: ignore key: %s", filename);
+               close(fd);
+               return NULL;
+       }
+       if (perm_ok != NULL)
+               *perm_ok = 1;
+
+       buffer_init(&buffer);
+       if (!key_load_file(fd, filename, &buffer)) {
+               buffer_free(&buffer);
+               close(fd);
+               return NULL;
+       }
+       close(fd);
+       ret = key_parse_private_type(&buffer, type, passphrase, commentp);
+       buffer_free(&buffer);
+       return ret;
+}
+
+Key *
+key_load_private(const char *filename, const char *passphrase,
+    char **commentp)
+{
+       Key *pub, *prv;
+       Buffer buffer, pubcopy;
+       int fd;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               debug("could not open key file '%s': %s", filename,
+                   strerror(errno));
+               return NULL;
+       }
+       if (!key_perm_ok(fd, filename)) {
+               error("bad permissions: ignore key: %s", filename);
+               close(fd);
+               return NULL;
+       }
+
+       buffer_init(&buffer);
+       if (!key_load_file(fd, filename, &buffer)) {
+               buffer_free(&buffer);
+               close(fd);
+               return NULL;
+       }
+       close(fd);
+
+       buffer_init(&pubcopy);
+       buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer));
+       /* it's a SSH v1 key if the public key part is readable */
+       pub = key_parse_public_rsa1(&pubcopy, commentp);
+       buffer_free(&pubcopy);
+       if (pub == NULL) {
+               prv = key_parse_private_type(&buffer, KEY_UNSPEC,
+                   passphrase, NULL);
+               /* use the filename as a comment for PEM */
+               if (commentp && prv)
+                       *commentp = xstrdup(filename);
+       } else {
+               key_free(pub);
+               /* key_parse_public_rsa1() has already loaded the comment */
+               prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase,
+                   NULL);
+       }
+       buffer_free(&buffer);
+       return prv;
+}
+
+static int
+key_try_load_public(Key *k, const char *filename, char **commentp)
+{
+       FILE *f;
+       char line[SSH_MAX_PUBKEY_BYTES];
+       char *cp;
+       u_long linenum = 0;
+
+       f = fopen(filename, "r");
+       if (f != NULL) {
+               while (read_keyfile_line(f, filename, line, sizeof(line),
+                           &linenum) != -1) {
+                       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];
+
+       /* try rsa1 private key */
+       pub = key_load_public_type(KEY_RSA1, filename, commentp);
+       if (pub != NULL)
+               return pub;
+
+       /* try rsa1 public key */
+       pub = key_new(KEY_RSA1);
+       if (key_try_load_public(pub, filename, commentp) == 1)
+               return pub;
+       key_free(pub);
+
+       /* try ssh2 public key */
+       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;
+}
+
+/* Load the certificate associated with the named private key */
+Key *
+key_load_cert(const char *filename)
+{
+       Key *pub;
+       char *file;
+
+       pub = key_new(KEY_UNSPEC);
+       xasprintf(&file, "%s-cert.pub", filename);
+       if (key_try_load_public(pub, file, NULL) == 1) {
+               xfree(file);
+               return pub;
+       }
+       xfree(file);
+       key_free(pub);
+       return NULL;
+}
+
+/* Load private key and certificate */
+Key *
+key_load_private_cert(int type, const char *filename, const char *passphrase,
+    int *perm_ok)
+{
+       Key *key, *pub;
+
+       switch (type) {
+       case KEY_RSA:
+       case KEY_DSA:
+       case KEY_ECDSA:
+               break;
+       default:
+               error("%s: unsupported key type", __func__);
+               return NULL;
+       }
+
+       if ((key = key_load_private_type(type, filename, 
+           passphrase, NULL, perm_ok)) == NULL)
+               return NULL;
+
+       if ((pub = key_load_cert(filename)) == NULL) {
+               key_free(key);
+               return NULL;
+       }
+
+       /* Make sure the private key matches the certificate */
+       if (key_equal_public(key, pub) == 0) {
+               error("%s: certificate does not match private key %s",
+                   __func__, filename);
+       } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
+               error("%s: key_to_certified failed", __func__);
+       } else {
+               key_cert_copy(pub, key);
+               key_free(pub);
+               return key;
+       }
+
+       key_free(key);
+       key_free(pub);
+       return NULL;
+}
+
+/*
+ * Returns 1 if the specified "key" is listed in the file "filename",
+ * 0 if the key is not listed or -1 on error.
+ * If strict_type is set then the key type must match exactly,
+ * otherwise a comparison that ignores certficiate data is performed.
+ */
+int
+key_in_file(Key *key, const char *filename, int strict_type)
+{
+       FILE *f;
+       char line[SSH_MAX_PUBKEY_BYTES];
+       char *cp;
+       u_long linenum = 0;
+       int ret = 0;
+       Key *pub;
+       int (*key_compare)(const Key *, const Key *) = strict_type ?
+           key_equal : key_equal_public;
+
+       if ((f = fopen(filename, "r")) == NULL) {
+               if (errno == ENOENT) {
+                       debug("%s: keyfile \"%s\" missing", __func__, filename);
+                       return 0;
+               } else {
+                       error("%s: could not open keyfile \"%s\": %s", __func__,
+                           filename, strerror(errno));
+                       return -1;
+               }
+       }
+
+       while (read_keyfile_line(f, filename, line, sizeof(line),
+                   &linenum) != -1) {
+               cp = line;
+
+               /* Skip leading whitespace. */
+               for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
+                       ;
+
+               /* Skip comments and empty lines */
+               switch (*cp) {
+               case '#':
+               case '\n':
+               case '\0':
+                       continue;
+               }
+
+               pub = key_new(KEY_UNSPEC);
+               if (key_read(pub, &cp) != 1) {
+                       key_free(pub);
+                       continue;
+               }
+               if (key_compare(key, pub)) {
+                       ret = 1;
+                       key_free(pub);
+                       break;
+               }
+               key_free(pub);
+       }
+       fclose(f);
+       return ret;
+}
+
diff --git a/authfile.h b/authfile.h
new file mode 100644 (file)
index 0000000..6745dc0
--- /dev/null
@@ -0,0 +1,29 @@
+/* $OpenBSD: authfile.h,v 1.15 2010/08/04 05:42:47 djm 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 AUTHFILE_H
+#define AUTHFILE_H
+
+int     key_save_private(Key *, const char *, const char *, const char *);
+Key    *key_load_cert(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_cert(int, const char *, const char *, int *);
+Key    *key_load_private_type(int, const char *, const char *, char **, int *);
+Key    *key_load_private_pem(int, int, const char *, char **);
+int     key_perm_ok(int, const char *);
+int     key_in_file(Key *, const char *, int);
+
+#endif
diff --git a/bufaux.c b/bufaux.c
new file mode 100644 (file)
index 0000000..00208ca
--- /dev/null
+++ b/bufaux.c
@@ -0,0 +1,316 @@
+/* $OpenBSD: bufaux.c,v 1.50 2010/08/31 09:58:37 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+
+/*
+ * Returns integers from the buffer (msb first).
+ */
+
+int
+buffer_get_short_ret(u_short *ret, Buffer *buffer)
+{
+       u_char buf[2];
+
+       if (buffer_get_ret(buffer, (char *) buf, 2) == -1)
+               return (-1);
+       *ret = get_u16(buf);
+       return (0);
+}
+
+u_short
+buffer_get_short(Buffer *buffer)
+{
+       u_short ret;
+
+       if (buffer_get_short_ret(&ret, buffer) == -1)
+               fatal("buffer_get_short: buffer error");
+
+       return (ret);
+}
+
+int
+buffer_get_int_ret(u_int *ret, Buffer *buffer)
+{
+       u_char buf[4];
+
+       if (buffer_get_ret(buffer, (char *) buf, 4) == -1)
+               return (-1);
+       if (ret != NULL)
+               *ret = get_u32(buf);
+       return (0);
+}
+
+u_int
+buffer_get_int(Buffer *buffer)
+{
+       u_int ret;
+
+       if (buffer_get_int_ret(&ret, buffer) == -1)
+               fatal("buffer_get_int: buffer error");
+
+       return (ret);
+}
+
+int
+buffer_get_int64_ret(u_int64_t *ret, Buffer *buffer)
+{
+       u_char buf[8];
+
+       if (buffer_get_ret(buffer, (char *) buf, 8) == -1)
+               return (-1);
+       if (ret != NULL)
+               *ret = get_u64(buf);
+       return (0);
+}
+
+u_int64_t
+buffer_get_int64(Buffer *buffer)
+{
+       u_int64_t ret;
+
+       if (buffer_get_int64_ret(&ret, buffer) == -1)
+               fatal("buffer_get_int: buffer error");
+
+       return (ret);
+}
+
+/*
+ * Stores integers in the buffer, msb first.
+ */
+void
+buffer_put_short(Buffer *buffer, u_short value)
+{
+       char buf[2];
+
+       put_u16(buf, value);
+       buffer_append(buffer, buf, 2);
+}
+
+void
+buffer_put_int(Buffer *buffer, u_int value)
+{
+       char buf[4];
+
+       put_u32(buf, value);
+       buffer_append(buffer, buf, 4);
+}
+
+void
+buffer_put_int64(Buffer *buffer, u_int64_t value)
+{
+       char buf[8];
+
+       put_u64(buf, value);
+       buffer_append(buffer, buf, 8);
+}
+
+/*
+ * 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.
+ */
+void *
+buffer_get_string_ret(Buffer *buffer, u_int *length_ptr)
+{
+       u_char *value;
+       u_int len;
+
+       /* Get the length. */
+       if (buffer_get_int_ret(&len, buffer) != 0) {
+               error("buffer_get_string_ret: cannot extract length");
+               return (NULL);
+       }
+       if (len > 256 * 1024) {
+               error("buffer_get_string_ret: bad string length %u", len);
+               return (NULL);
+       }
+       /* Allocate space for the string.  Add one byte for a null character. */
+       value = xmalloc(len + 1);
+       /* Get the string. */
+       if (buffer_get_ret(buffer, value, len) == -1) {
+               error("buffer_get_string_ret: buffer_get failed");
+               xfree(value);
+               return (NULL);
+       }
+       /* 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);
+}
+
+void *
+buffer_get_string(Buffer *buffer, u_int *length_ptr)
+{
+       void *ret;
+
+       if ((ret = buffer_get_string_ret(buffer, length_ptr)) == NULL)
+               fatal("buffer_get_string: buffer error");
+       return (ret);
+}
+
+char *
+buffer_get_cstring_ret(Buffer *buffer, u_int *length_ptr)
+{
+       u_int length;
+       char *cp, *ret = buffer_get_string_ret(buffer, &length);
+
+       if (ret == NULL)
+               return NULL;
+       if ((cp = memchr(ret, '\0', length)) != NULL) {
+               /* XXX allow \0 at end-of-string for a while, remove later */
+               if (cp == ret + length - 1)
+                       error("buffer_get_cstring_ret: string contains \\0");
+               else {
+                       bzero(ret, length);
+                       xfree(ret);
+                       return NULL;
+               }
+       }
+       if (length_ptr != NULL)
+               *length_ptr = length;
+       return ret;
+}
+
+char *
+buffer_get_cstring(Buffer *buffer, u_int *length_ptr)
+{
+       char *ret;
+
+       if ((ret = buffer_get_cstring_ret(buffer, length_ptr)) == NULL)
+               fatal("buffer_get_cstring: buffer error");
+       return ret;
+}
+
+void *
+buffer_get_string_ptr_ret(Buffer *buffer, u_int *length_ptr)
+{
+       void *ptr;
+       u_int len;
+
+       if (buffer_get_int_ret(&len, buffer) != 0)
+               return NULL;
+       if (len > 256 * 1024) {
+               error("buffer_get_string_ptr: bad string length %u", len);
+               return NULL;
+       }
+       ptr = buffer_ptr(buffer);
+       buffer_consume(buffer, len);
+       if (length_ptr)
+               *length_ptr = len;
+       return (ptr);
+}
+
+void *
+buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
+{
+       void *ret;
+
+       if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL)
+               fatal("buffer_get_string_ptr: buffer error");
+       return (ret);
+}
+
+/*
+ * 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)
+{
+       if (s == NULL)
+               fatal("buffer_put_cstring: s == NULL");
+       buffer_put_string(buffer, s, strlen(s));
+}
+
+/*
+ * Returns a character from the buffer (0 - 255).
+ */
+int
+buffer_get_char_ret(char *ret, Buffer *buffer)
+{
+       if (buffer_get_ret(buffer, ret, 1) == -1) {
+               error("buffer_get_char_ret: buffer_get_ret failed");
+               return (-1);
+       }
+       return (0);
+}
+
+int
+buffer_get_char(Buffer *buffer)
+{
+       char ch;
+
+       if (buffer_get_char_ret(&ch, buffer) == -1)
+               fatal("buffer_get_char: buffer error");
+       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/bufbn.c b/bufbn.c
new file mode 100644 (file)
index 0000000..251cd09
--- /dev/null
+++ b/bufbn.c
@@ -0,0 +1,223 @@
+/* $OpenBSD: bufbn.c,v 1.6 2007/06/02 09:04:58 djm Exp $*/
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.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.
+ */
+int
+buffer_put_bignum_ret(Buffer *buffer, const 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) {
+               error("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d",
+                   oi, bin_size);
+               xfree(buf);
+               return (-1);
+       }
+
+       /* Store the number of bits in the buffer in two bytes, msb first. */
+       put_u16(msg, bits);
+       buffer_append(buffer, msg, 2);
+       /* Store the binary data. */
+       buffer_append(buffer, buf, oi);
+
+       memset(buf, 0, bin_size);
+       xfree(buf);
+
+       return (0);
+}
+
+void
+buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
+{
+       if (buffer_put_bignum_ret(buffer, value) == -1)
+               fatal("buffer_put_bignum: buffer error");
+}
+
+/*
+ * Retrieves a BIGNUM from the buffer.
+ */
+int
+buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
+{
+       u_int bits, bytes;
+       u_char buf[2], *bin;
+
+       /* Get the number of bits. */
+       if (buffer_get_ret(buffer, (char *) buf, 2) == -1) {
+               error("buffer_get_bignum_ret: invalid length");
+               return (-1);
+       }
+       bits = get_u16(buf);
+       /* Compute the number of binary bytes that follow. */
+       bytes = (bits + 7) / 8;
+       if (bytes > 8 * 1024) {
+               error("buffer_get_bignum_ret: cannot handle BN of size %d", bytes);
+               return (-1);
+       }
+       if (buffer_len(buffer) < bytes) {
+               error("buffer_get_bignum_ret: input buffer too small");
+               return (-1);
+       }
+       bin = buffer_ptr(buffer);
+       if (BN_bin2bn(bin, bytes, value) == NULL) {
+               error("buffer_get_bignum_ret: BN_bin2bn failed");
+               return (-1);
+       }
+       if (buffer_consume_ret(buffer, bytes) == -1) {
+               error("buffer_get_bignum_ret: buffer_consume failed");
+               return (-1);
+       }
+       return (0);
+}
+
+void
+buffer_get_bignum(Buffer *buffer, BIGNUM *value)
+{
+       if (buffer_get_bignum_ret(buffer, value) == -1)
+               fatal("buffer_get_bignum: buffer error");
+}
+
+/*
+ * Stores a BIGNUM in the buffer in SSH2 format.
+ */
+int
+buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
+{
+       u_int bytes;
+       u_char *buf;
+       int oi;
+       u_int hasnohigh = 0;
+
+       if (BN_is_zero(value)) {
+               buffer_put_int(buffer, 0);
+               return 0;
+       }
+       if (value->neg) {
+               error("buffer_put_bignum2_ret: negative numbers not supported");
+               return (-1);
+       }
+       bytes = BN_num_bytes(value) + 1; /* extra padding byte */
+       if (bytes < 2) {
+               error("buffer_put_bignum2_ret: BN too small");
+               return (-1);
+       }
+       buf = xmalloc(bytes);
+       buf[0] = 0x00;
+       /* Get the value of in binary */
+       oi = BN_bn2bin(value, buf+1);
+       if (oi < 0 || (u_int)oi != bytes - 1) {
+               error("buffer_put_bignum2_ret: BN_bn2bin() failed: "
+                   "oi %d != bin_size %d", oi, bytes);
+               xfree(buf);
+               return (-1);
+       }
+       hasnohigh = (buf[1] & 0x80) ? 0 : 1;
+       buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh);
+       memset(buf, 0, bytes);
+       xfree(buf);
+       return (0);
+}
+
+void
+buffer_put_bignum2(Buffer *buffer, const BIGNUM *value)
+{
+       if (buffer_put_bignum2_ret(buffer, value) == -1)
+               fatal("buffer_put_bignum2: buffer error");
+}
+
+int
+buffer_get_bignum2_ret(Buffer *buffer, BIGNUM *value)
+{
+       u_int len;
+       u_char *bin;
+
+       if ((bin = buffer_get_string_ret(buffer, &len)) == NULL) {
+               error("buffer_get_bignum2_ret: invalid bignum");
+               return (-1);
+       }
+
+       if (len > 0 && (bin[0] & 0x80)) {
+               error("buffer_get_bignum2_ret: negative numbers not supported");
+               xfree(bin);
+               return (-1);
+       }
+       if (len > 8 * 1024) {
+               error("buffer_get_bignum2_ret: cannot handle BN of size %d",
+                   len);
+               xfree(bin);
+               return (-1);
+       }
+       if (BN_bin2bn(bin, len, value) == NULL) {
+               error("buffer_get_bignum2_ret: BN_bin2bn failed");
+               xfree(bin);
+               return (-1);
+       }
+       xfree(bin);
+       return (0);
+}
+
+void
+buffer_get_bignum2(Buffer *buffer, BIGNUM *value)
+{
+       if (buffer_get_bignum2_ret(buffer, value) == -1)
+               fatal("buffer_get_bignum2: buffer error");
+}
diff --git a/bufec.c b/bufec.c
new file mode 100644 (file)
index 0000000..3dcb494
--- /dev/null
+++ b/bufec.c
@@ -0,0 +1,146 @@
+/* $OpenBSD: bufec.c,v 1.1 2010/08/31 11:54:45 djm Exp $ */
+/*
+ * Copyright (c) 2010 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifdef OPENSSL_HAS_ECC
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+
+/*
+ * Maximum supported EC GFp field length is 528 bits. SEC1 uncompressed
+ * encoding represents this as two bitstring points that should each
+ * be no longer than the field length, SEC1 specifies a 1 byte
+ * point type header.
+ * Being paranoid here may insulate us to parsing problems in
+ * EC_POINT_oct2point.
+ */
+#define BUFFER_MAX_ECPOINT_LEN ((528*2 / 8) + 1)
+
+/*
+ * Append an EC_POINT to the buffer as a string containing a SEC1 encoded
+ * uncompressed point. Fortunately OpenSSL handles the gory details for us.
+ */
+int
+buffer_put_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
+    const EC_POINT *point)
+{
+       u_char *buf = NULL;
+       size_t len;
+       BN_CTX *bnctx;
+       int ret = -1;
+
+       /* Determine length */
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new failed", __func__);
+       len = EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
+           NULL, 0, bnctx);
+       if (len > BUFFER_MAX_ECPOINT_LEN) {
+               error("%s: giant EC point: len = %lu (max %u)",
+                   __func__, (u_long)len, BUFFER_MAX_ECPOINT_LEN);
+               goto out;
+       }
+       /* Convert */
+       buf = xmalloc(len);
+       if (EC_POINT_point2oct(curve, point, POINT_CONVERSION_UNCOMPRESSED,
+           buf, len, bnctx) != len) {
+               error("%s: EC_POINT_point2oct length mismatch", __func__);
+               goto out;
+       }
+       /* Append */
+       buffer_put_string(buffer, buf, len);
+       ret = 0;
+ out:
+       if (buf != NULL) {
+               bzero(buf, len);
+               xfree(buf);
+       }
+       BN_CTX_free(bnctx);
+       return ret;
+}
+
+void
+buffer_put_ecpoint(Buffer *buffer, const EC_GROUP *curve,
+    const EC_POINT *point)
+{
+       if (buffer_put_ecpoint_ret(buffer, curve, point) == -1)
+               fatal("%s: buffer error", __func__);
+}
+
+int
+buffer_get_ecpoint_ret(Buffer *buffer, const EC_GROUP *curve,
+    EC_POINT *point)
+{
+       u_char *buf;
+       u_int len;
+       BN_CTX *bnctx;
+       int ret = -1;
+
+       if ((buf = buffer_get_string_ret(buffer, &len)) == NULL) {
+               error("%s: invalid point", __func__);
+               return -1;
+       }
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new failed", __func__);
+       if (len > BUFFER_MAX_ECPOINT_LEN) {
+               error("%s: EC_POINT too long: %u > max %u", __func__,
+                   len, BUFFER_MAX_ECPOINT_LEN);
+               goto out;
+       }
+       if (len == 0) {
+               error("%s: EC_POINT buffer is empty", __func__);
+               goto out;
+       }
+       if (buf[0] != POINT_CONVERSION_UNCOMPRESSED) {
+               error("%s: EC_POINT is in an incorrect form: "
+                   "0x%02x (want 0x%02x)", __func__, buf[0],
+                   POINT_CONVERSION_UNCOMPRESSED);
+               goto out;
+       }
+       if (EC_POINT_oct2point(curve, point, buf, len, bnctx) != 1) {
+               error("buffer_get_bignum2_ret: BN_bin2bn failed");
+               goto out;
+       }
+       /* EC_POINT_oct2point verifies that the point is on the curve for us */
+       ret = 0;
+ out:
+       BN_CTX_free(bnctx);
+       bzero(buf, len);
+       xfree(buf);
+       return ret;
+}
+
+void
+buffer_get_ecpoint(Buffer *buffer, const EC_GROUP *curve,
+    EC_POINT *point)
+{
+       if (buffer_get_ecpoint_ret(buffer, curve, point) == -1)
+               fatal("%s: buffer error", __func__);
+}
+
+#endif /* OPENSSL_HAS_ECC */
diff --git a/buffer.c b/buffer.c
new file mode 100644 (file)
index 0000000..ae97003
--- /dev/null
+++ b/buffer.c
@@ -0,0 +1,252 @@
+/* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+
+#define        BUFFER_MAX_CHUNK        0x100000
+#define        BUFFER_MAX_LEN          0xa00000
+#define        BUFFER_ALLOCSZ          0x008000
+
+/* Initializes the buffer structure. */
+
+void
+buffer_init(Buffer *buffer)
+{
+       const u_int len = 4096;
+
+       buffer->alloc = 0;
+       buffer->buf = xmalloc(len);
+       buffer->alloc = len;
+       buffer->offset = 0;
+       buffer->end = 0;
+}
+
+/* Frees any memory used for the buffer. */
+
+void
+buffer_free(Buffer *buffer)
+{
+       if (buffer->alloc > 0) {
+               memset(buffer->buf, 0, buffer->alloc);
+               buffer->alloc = 0;
+               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 void *data, u_int len)
+{
+       void *p;
+       p = buffer_append_space(buffer, len);
+       memcpy(p, data, len);
+}
+
+static int
+buffer_compact(Buffer *buffer)
+{
+       /*
+        * If the buffer is quite empty, but all data is at the end, move the
+        * data to the beginning.
+        */
+       if (buffer->offset > MIN(buffer->alloc, BUFFER_MAX_CHUNK)) {
+               memmove(buffer->buf, buffer->buf + buffer->offset,
+                       buffer->end - buffer->offset);
+               buffer->end -= buffer->offset;
+               buffer->offset = 0;
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * 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, u_int len)
+{
+       u_int newlen;
+       void *p;
+
+       if (len > BUFFER_MAX_CHUNK)
+               fatal("buffer_append_space: len %u not supported", 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) {
+               p = buffer->buf + buffer->end;
+               buffer->end += len;
+               return p;
+       }
+
+       /* Compact data back to the start of the buffer if necessary */
+       if (buffer_compact(buffer))
+               goto restart;
+
+       /* Increase the size of the buffer and retry. */
+       newlen = roundup(buffer->alloc + len, BUFFER_ALLOCSZ);
+       if (newlen > BUFFER_MAX_LEN)
+               fatal("buffer_append_space: alloc %u not supported",
+                   newlen);
+       buffer->buf = xrealloc(buffer->buf, 1, newlen);
+       buffer->alloc = newlen;
+       goto restart;
+       /* NOTREACHED */
+}
+
+/*
+ * Check whether an allocation of 'len' will fit in the buffer
+ * This must follow the same math as buffer_append_space
+ */
+int
+buffer_check_alloc(Buffer *buffer, u_int len)
+{
+       if (buffer->offset == buffer->end) {
+               buffer->offset = 0;
+               buffer->end = 0;
+       }
+ restart:
+       if (buffer->end + len < buffer->alloc)
+               return (1);
+       if (buffer_compact(buffer))
+               goto restart;
+       if (roundup(buffer->alloc + len, BUFFER_ALLOCSZ) <= BUFFER_MAX_LEN)
+               return (1);
+       return (0);
+}
+
+/* Returns the number of bytes of data in the buffer. */
+
+u_int
+buffer_len(const Buffer *buffer)
+{
+       return buffer->end - buffer->offset;
+}
+
+/* Gets data from the beginning of the buffer. */
+
+int
+buffer_get_ret(Buffer *buffer, void *buf, u_int len)
+{
+       if (len > buffer->end - buffer->offset) {
+               error("buffer_get_ret: trying to get more bytes %d than in buffer %d",
+                   len, buffer->end - buffer->offset);
+               return (-1);
+       }
+       memcpy(buf, buffer->buf + buffer->offset, len);
+       buffer->offset += len;
+       return (0);
+}
+
+void
+buffer_get(Buffer *buffer, void *buf, u_int len)
+{
+       if (buffer_get_ret(buffer, buf, len) == -1)
+               fatal("buffer_get: buffer error");
+}
+
+/* Consumes the given number of bytes from the beginning of the buffer. */
+
+int
+buffer_consume_ret(Buffer *buffer, u_int bytes)
+{
+       if (bytes > buffer->end - buffer->offset) {
+               error("buffer_consume_ret: trying to get more bytes than in buffer");
+               return (-1);
+       }
+       buffer->offset += bytes;
+       return (0);
+}
+
+void
+buffer_consume(Buffer *buffer, u_int bytes)
+{
+       if (buffer_consume_ret(buffer, bytes) == -1)
+               fatal("buffer_consume: buffer error");
+}
+
+/* Consumes the given number of bytes from the end of the buffer. */
+
+int
+buffer_consume_end_ret(Buffer *buffer, u_int bytes)
+{
+       if (bytes > buffer->end - buffer->offset)
+               return (-1);
+       buffer->end -= bytes;
+       return (0);
+}
+
+void
+buffer_consume_end(Buffer *buffer, u_int bytes)
+{
+       if (buffer_consume_end_ret(buffer, bytes) == -1)
+               fatal("buffer_consume_end: trying to get more bytes than in buffer");
+}
+
+/* Returns a pointer to the first used byte in the buffer. */
+
+void *
+buffer_ptr(const Buffer *buffer)
+{
+       return buffer->buf + buffer->offset;
+}
+
+/* Dumps the contents of the buffer to stderr. */
+
+void
+buffer_dump(const Buffer *buffer)
+{
+       u_int i;
+       u_char *ucp = 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/buffer.h b/buffer.h
new file mode 100644 (file)
index 0000000..e2a9dd1
--- /dev/null
+++ b/buffer.h
@@ -0,0 +1,98 @@
+/* $OpenBSD: buffer.h,v 1.21 2010/08/31 11:54:45 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#ifndef BUFFER_H
+#define BUFFER_H
+
+typedef struct {
+       u_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(const Buffer *);
+void   *buffer_ptr(const Buffer *);
+
+void    buffer_append(Buffer *, const void *, u_int);
+void   *buffer_append_space(Buffer *, u_int);
+
+int     buffer_check_alloc(Buffer *, u_int);
+
+void    buffer_get(Buffer *, void *, u_int);
+
+void    buffer_consume(Buffer *, u_int);
+void    buffer_consume_end(Buffer *, u_int);
+
+void     buffer_dump(const Buffer *);
+
+int     buffer_get_ret(Buffer *, void *, u_int);
+int     buffer_consume_ret(Buffer *, u_int);
+int     buffer_consume_end_ret(Buffer *, u_int);
+
+#include <openssl/bn.h>
+
+void    buffer_put_bignum(Buffer *, const BIGNUM *);
+void    buffer_put_bignum2(Buffer *, const BIGNUM *);
+void   buffer_get_bignum(Buffer *, BIGNUM *);
+void   buffer_get_bignum2(Buffer *, BIGNUM *);
+
+u_short        buffer_get_short(Buffer *);
+void   buffer_put_short(Buffer *, u_short);
+
+u_int  buffer_get_int(Buffer *);
+void    buffer_put_int(Buffer *, u_int);
+
+u_int64_t buffer_get_int64(Buffer *);
+void   buffer_put_int64(Buffer *, u_int64_t);
+
+int     buffer_get_char(Buffer *);
+void    buffer_put_char(Buffer *, int);
+
+void   *buffer_get_string(Buffer *, u_int *);
+void   *buffer_get_string_ptr(Buffer *, u_int *);
+void    buffer_put_string(Buffer *, const void *, u_int);
+char   *buffer_get_cstring(Buffer *, u_int *);
+void   buffer_put_cstring(Buffer *, const char *);
+
+#define buffer_skip_string(b) \
+    do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while (0)
+
+int    buffer_put_bignum_ret(Buffer *, const BIGNUM *);
+int    buffer_get_bignum_ret(Buffer *, BIGNUM *);
+int    buffer_put_bignum2_ret(Buffer *, const BIGNUM *);
+int    buffer_get_bignum2_ret(Buffer *, BIGNUM *);
+int    buffer_get_short_ret(u_short *, Buffer *);
+int    buffer_get_int_ret(u_int *, Buffer *);
+int    buffer_get_int64_ret(u_int64_t *, Buffer *);
+void   *buffer_get_string_ret(Buffer *, u_int *);
+char   *buffer_get_cstring_ret(Buffer *, u_int *);
+void   *buffer_get_string_ptr_ret(Buffer *, u_int *);
+int    buffer_get_char_ret(char *, Buffer *);
+
+#ifdef OPENSSL_HAS_ECC
+#include <openssl/ec.h>
+
+int    buffer_put_ecpoint_ret(Buffer *, const EC_GROUP *, const EC_POINT *);
+void   buffer_put_ecpoint(Buffer *, const EC_GROUP *, const EC_POINT *);
+int    buffer_get_ecpoint_ret(Buffer *, const EC_GROUP *, EC_POINT *);
+void   buffer_get_ecpoint(Buffer *, const EC_GROUP *, EC_POINT *);
+#endif
+
+#endif                         /* BUFFER_H */
diff --git a/buildpkg.sh.in b/buildpkg.sh.in
new file mode 100644 (file)
index 0000000..22c66fb
--- /dev/null
@@ -0,0 +1,684 @@
+#!/bin/sh
+#
+# Fake Root Solaris/SVR4/SVR5 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
+#
+# Options for building the package
+# You can create a openssh-config.local with your customized options
+#
+REMOVE_FAKE_ROOT_WHEN_DONE=yes
+#
+# uncommenting TEST_DIR and using
+# configure --prefix=/var/tmp --with-privsep-path=/var/tmp/empty
+# and
+# PKGNAME=tOpenSSH should allow testing a package without interfering
+# with a real OpenSSH package on a system. This is not needed on systems
+# that support the -R option to pkgadd.
+#TEST_DIR=/var/tmp     # leave commented out for production build
+PKGNAME=OpenSSH
+# revisions within the same version (REV=a)
+#REV=
+SYSVINIT_NAME=opensshd
+AWK=${AWK:="nawk"}
+MAKE=${MAKE:="make"}
+SSHDUID=67     # Default privsep uid
+SSHDGID=67     # Default privsep gid
+# uncomment these next three as needed
+#PERMIT_ROOT_LOGIN=no
+#X11_FORWARDING=yes
+#USR_LOCAL_IS_SYMLINK=yes
+# System V init run levels
+SYSVINITSTART=S98
+SYSVINITSTOPT=K30
+# We will source these if they exist
+POST_MAKE_INSTALL_FIXES=./pkg-post-make-install-fixes.sh
+POST_PROTOTYPE_EDITS=./pkg-post-prototype-edit.sh
+# We'll be one level deeper looking for these
+PKG_PREINSTALL_LOCAL=../pkg-preinstall.local
+PKG_POSTINSTALL_LOCAL=../pkg-postinstall.local
+PKG_PREREMOVE_LOCAL=../pkg-preremove.local
+PKG_POSTREMOVE_LOCAL=../pkg-postremove.local
+PKG_REQUEST_LOCAL=../pkg-request.local
+# end of sourced files
+#
+OPENSSHD=opensshd.init
+OPENSSH_MANIFEST=openssh.xml
+OPENSSH_FMRI=svc:/site/${SYSVINIT_NAME}:default
+SMF_METHOD_DIR=/lib/svc/method/site
+SMF_MANIFEST_DIR=/var/svc/manifest/site
+
+PATH_GROUPADD_PROG=@PATH_GROUPADD_PROG@
+PATH_USERADD_PROG=@PATH_USERADD_PROG@
+PATH_PASSWD_PROG=@PATH_PASSWD_PROG@
+#
+# list of system directories we do NOT want to change owner/group/perms
+# when installing our package
+SYSTEM_DIR="/etc       \
+/etc/init.d            \
+/etc/rcS.d             \
+/etc/rc0.d             \
+/etc/rc1.d             \
+/etc/rc2.d             \
+/etc/opt               \
+/lib                   \
+/lib/svc               \
+/lib/svc/method                \
+/lib/svc/method/site   \
+/opt                   \
+/opt/bin               \
+/usr                   \
+/usr/bin               \
+/usr/lib               \
+/usr/sbin              \
+/usr/share             \
+/usr/share/man         \
+/usr/share/man/man1    \
+/usr/share/man/man8    \
+/usr/local             \
+/usr/local/bin         \
+/usr/local/etc         \
+/usr/local/libexec     \
+/usr/local/man         \
+/usr/local/man/man1    \
+/usr/local/man/man8    \
+/usr/local/sbin                \
+/usr/local/share       \
+/var                   \
+/var/opt               \
+/var/run               \
+/var/svc               \
+/var/svc/manifest      \
+/var/svc/manifest/site  \
+/var/tmp               \
+/tmp"
+
+# We may need to build as root so we make sure PATH is set up
+# only set the path if it's not set already
+[ -d /opt/bin ]  &&  {
+       echo $PATH | grep ":/opt/bin"  > /dev/null 2>&1
+       [ $? -ne 0 ] && PATH=$PATH:/opt/bin
+}
+[ -d /usr/local/bin ]  &&  {
+       echo $PATH | grep ":/usr/local/bin"  > /dev/null 2>&1
+       [ $? -ne 0 ] && PATH=$PATH:/usr/local/bin
+}
+[ -d /usr/ccs/bin ]  &&  {
+       echo $PATH | grep ":/usr/ccs/bin"  > /dev/null 2>&1
+       [ $? -ne 0 ] && PATH=$PATH:/usr/ccs/bin
+}
+export PATH
+#
+
+[ -f Makefile ]  ||  {
+       echo "Please run this script from your build directory"
+       exit 1
+}
+
+# we will look for openssh-config.local to override the above options
+[ -s ./openssh-config.local ]  &&  . ./openssh-config.local
+
+START=`pwd`
+FAKE_ROOT=$START/pkg
+
+## Fill in some details, like prefix and sysconfdir
+for confvar in prefix exec_prefix bindir sbindir libexecdir datadir mandir sysconfdir piddir srcdir
+do
+       eval $confvar=`grep "^$confvar=" Makefile | cut -d = -f 2`
+done
+
+## Are we using Solaris' SMF?
+DO_SMF=0
+if egrep "^#define USE_SOLARIS_PROCESS_CONTRACTS" config.h > /dev/null 2>&1
+then
+       DO_SMF=1
+fi
+
+## Collect value of privsep user
+for confvar in SSH_PRIVSEP_USER
+do
+       eval $confvar=`awk '/#define[ \t]'$confvar'/{print $3}' config.h`
+done
+
+## Set privsep defaults if not defined
+if [ -z "$SSH_PRIVSEP_USER" ]
+then
+       SSH_PRIVSEP_USER=sshd
+fi
+
+## Extract common info requires for the 'info' part of the package.
+VERSION=`./ssh -V 2>&1 | sed -e 's/,.*//'`
+
+ARCH=`uname -m`
+DEF_MSG="\n"
+OS_VER=`uname -v`
+SCRIPT_SHELL=/sbin/sh
+UNAME_R=`uname -r`
+UNAME_S=`uname -s`
+case ${UNAME_S} in
+       SunOS)  UNAME_S=Solaris
+               OS_VER=${UNAME_R}
+               ARCH=`uname -p`
+               RCS_D=yes
+               DEF_MSG="(default: n)"
+               ;;
+       SCO_SV) case ${UNAME_R} in
+                       3.2)    UNAME_S=OpenServer5
+               OS_VER=`uname -X | grep Release | sed -e 's/^Rel.*3.2v//'`
+                               ;;
+                       5)      UNAME_S=OpenServer6
+                               ;;
+               esac
+               SCRIPT_SHELL=/bin/sh
+               RC1_D=no
+               DEF_MSG="(default: n)"
+               ;;
+esac
+
+case `basename $0` in
+       buildpkg.sh)
+## Start by faking root install
+echo "Faking root install..."
+[ -d $FAKE_ROOT ]  &&  rm -fr $FAKE_ROOT
+mkdir $FAKE_ROOT
+${MAKE} install-nokeys DESTDIR=$FAKE_ROOT
+if [ $? -gt 0 ]
+then
+       echo "Fake root install failed, stopping."
+       exit 1
+fi
+
+## Setup our run level stuff while we are at it.
+if [ $DO_SMF -eq 1 ]
+then
+       # For Solaris' SMF, /lib/svc/method/site is the preferred place
+       # for start/stop scripts that aren't supplied with the OS, and
+       # similarly /var/svc/manifest/site for manifests.
+       mkdir -p $FAKE_ROOT${TEST_DIR}${SMF_METHOD_DIR}
+       mkdir -p $FAKE_ROOT${TEST_DIR}${SMF_MANIFEST_DIR}
+
+       cp ${OPENSSHD} $FAKE_ROOT${TEST_DIR}${SMF_METHOD_DIR}/${SYSVINIT_NAME}
+       chmod 744 $FAKE_ROOT${TEST_DIR}${SMF_METHOD_DIR}/${SYSVINIT_NAME}
+
+       cat ${OPENSSH_MANIFEST} | \
+           sed -e "s|__SYSVINIT_NAME__|${SYSVINIT_NAME}|" \
+           -e "s|__SMF_METHOD_DIR__|${SMF_METHOD_DIR}|" \
+           > $FAKE_ROOT${TEST_DIR}${SMF_MANIFEST_DIR}/${SYSVINIT_NAME}.xml
+       chmod 644 $FAKE_ROOT${TEST_DIR}${SMF_MANIFEST_DIR}/${SYSVINIT_NAME}.xml
+else
+       mkdir -p $FAKE_ROOT${TEST_DIR}/etc/init.d
+
+       cp ${OPENSSHD} $FAKE_ROOT${TEST_DIR}/etc/init.d/${SYSVINIT_NAME}
+       chmod 744 $FAKE_ROOT${TEST_DIR}/etc/init.d/${SYSVINIT_NAME}
+fi
+
+[ "${PERMIT_ROOT_LOGIN}" = no ]  &&  \
+       perl -p -i -e "s/#PermitRootLogin yes/PermitRootLogin no/" \
+               $FAKE_ROOT${sysconfdir}/sshd_config
+[ "${X11_FORWARDING}" = yes ]  &&  \
+       perl -p -i -e "s/#X11Forwarding no/X11Forwarding yes/" \
+               $FAKE_ROOT${sysconfdir}/sshd_config
+# fix PrintMotd
+perl -p -i -e "s/#PrintMotd yes/PrintMotd no/" \
+       $FAKE_ROOT${sysconfdir}/sshd_config
+
+# We don't want to overwrite config files on multiple installs
+mv $FAKE_ROOT${sysconfdir}/ssh_config $FAKE_ROOT${sysconfdir}/ssh_config.default
+mv $FAKE_ROOT${sysconfdir}/sshd_config $FAKE_ROOT${sysconfdir}/sshd_config.default
+[ -f $FAKE_ROOT${sysconfdir}/ssh_prng_cmds ]  &&  \
+mv $FAKE_ROOT${sysconfdir}/ssh_prng_cmds $FAKE_ROOT${sysconfdir}/ssh_prng_cmds.default
+
+# local tweeks here
+[ -s "${POST_MAKE_INSTALL_FIXES}" ]  &&  . ${POST_MAKE_INSTALL_FIXES}
+
+cd $FAKE_ROOT
+
+## 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 ${UNAME_S}"
+DESC="Secure Shell remote access utility; replaces telnet and rlogin/rsh."
+VENDOR="OpenSSH Portable Team - http://www.openssh.com/portable.html"
+ARCH=$ARCH
+VERSION=$VERSION$REV
+CATEGORY="Security,application"
+BASEDIR=/
+CLASSES="none"
+PSTAMP="${UNAME_S} ${OS_VER} ${ARCH} `date '+%d%b%Y %H:%M'`"
+_EOF
+
+## Build empty depend file that may get updated by $POST_PROTOTYPE_EDITS
+echo "Building depend file..."
+touch depend
+
+## Build space file
+echo "Building space file..."
+if [ $DO_SMF -eq 1 ]
+then
+       # XXX Is this necessary?  If not, remove space line from mk-proto.awk.
+       touch space
+else
+       cat > space << _EOF
+# extra space required by start/stop links added by installf 
+# in postinstall
+$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1
+$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME} 0 1
+_EOF
+       [ "$RC1_D" = no ]  ||  \
+       echo "$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1" >> space
+       [ "$RCS_D" = yes ]  &&  \
+       echo "$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1" >> space
+fi
+
+## Build preinstall file
+echo "Building preinstall file..."
+cat > preinstall << _EOF
+#! ${SCRIPT_SHELL}
+#
+_EOF
+
+# local preinstall changes here
+[ -s "${PKG_PREINSTALL_LOCAL}" ]  &&  . ${PKG_PREINSTALL_LOCAL}
+
+cat >> preinstall << _EOF
+#
+if [ "\${PRE_INS_STOP}" = "yes" ]
+then
+       if [ $DO_SMF -eq 1 ] 
+       then
+               svcadm disable $OPENSSH_FMRI
+       else
+               ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} stop
+       fi
+fi
+
+exit 0
+_EOF
+
+## Build postinstall file
+echo "Building postinstall file..."
+cat > postinstall << _EOF
+#! ${SCRIPT_SHELL}
+#
+[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config ]  ||  \\
+       cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config.default \\
+               \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config
+[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config ]  ||  \\
+       cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config.default \\
+               \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config
+[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds.default ]  &&  {
+       [ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds ]  ||  \\
+       cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds.default \\
+               \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds
+}
+
+# make rc?.d dirs only if we are doing a test install
+[ -n "${TEST_DIR}" ]  &&  [ $DO_SMF -ne 1 ] && {
+       [ "$RCS_D" = yes ]  &&  mkdir -p ${TEST_DIR}/etc/rcS.d
+       mkdir -p ${TEST_DIR}/etc/rc0.d
+       [ "$RC1_D" = no ]  ||  mkdir -p ${TEST_DIR}/etc/rc1.d
+       mkdir -p ${TEST_DIR}/etc/rc2.d
+}
+
+if [ $DO_SMF -eq 1 ]
+then
+       # Delete the existing service, if it exists, then import the 
+       # new one.
+       if svcs $OPENSSH_FMRI > /dev/null 2>&1
+       then
+               svccfg delete -f $OPENSSH_FMRI
+       fi
+       # NOTE, The manifest disables sshd by default.
+       svccfg import ${TEST_DIR}${SMF_MANIFEST_DIR}/${SYSVINIT_NAME}.xml
+else
+       if [ "\${USE_SYM_LINKS}" = yes ]
+       then
+               [ "$RCS_D" = yes ]  &&  \
+       installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s
+               [ "$RC1_D" = no ]  ||  \
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s
+       else
+               [ "$RCS_D" = yes ]  &&  \
+       installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=\${PKG_INSTALL_ROOT}$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=\${PKG_INSTALL_ROOT}$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l
+               [ "$RC1_D" = no ]  ||  \
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=\${PKG_INSTALL_ROOT}$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l
+               installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME}=\${PKG_INSTALL_ROOT}$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l
+       fi
+fi
+
+# If piddir doesn't exist we add it. (Ie. --with-pid-dir=/var/opt/ssh)
+[ -d $piddir ]  ||  installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR$piddir d 0755 root sys
+
+_EOF
+
+# local postinstall changes here
+[ -s "${PKG_POSTINSTALL_LOCAL}" ]  &&  . ${PKG_POSTINSTALL_LOCAL}
+
+cat >> postinstall << _EOF
+installf -f ${PKGNAME}
+
+# Use chroot to handle PKG_INSTALL_ROOT
+if [ ! -z "\${PKG_INSTALL_ROOT}" ]
+then
+       chroot="chroot \${PKG_INSTALL_ROOT}"
+fi
+# If this is a test build, we will skip the groupadd/useradd/passwd commands
+if [ ! -z "${TEST_DIR}" ]
+then
+       chroot=echo
+fi
+
+       echo "PrivilegeSeparation user always required."
+       if cut -f1 -d: \${PKG_INSTALL_ROOT}/etc/passwd | egrep '^'$SSH_PRIVSEP_USER'\$' >/dev/null
+       then
+               echo "PrivSep user $SSH_PRIVSEP_USER already exists."
+               SSH_PRIVSEP_GROUP=\`grep "^$SSH_PRIVSEP_USER:" \${PKG_INSTALL_ROOT}/etc/passwd | awk -F: '{print \$4}'\`
+               SSH_PRIVSEP_GROUP=\`grep ":\$SSH_PRIVSEP_GROUP:" \${PKG_INSTALL_ROOT}/etc/group | awk -F: '{print \$1}'\`
+       else
+               DO_PASSWD=yes
+       fi
+       [ -z "\$SSH_PRIVSEP_GROUP" ]  &&  SSH_PRIVSEP_GROUP=$SSH_PRIVSEP_USER
+
+       # group required?
+       if cut -f1 -d: \${PKG_INSTALL_ROOT}/etc/group | egrep '^'\$SSH_PRIVSEP_GROUP'\$' >/dev/null
+       then
+               echo "PrivSep group \$SSH_PRIVSEP_GROUP already exists."
+       else
+               DO_GROUP=yes
+       fi
+
+       # create group if required
+       [ "\$DO_GROUP" = yes ]  &&  {
+               # Use gid of 67 if possible
+               if cut -f3 -d: \${PKG_INSTALL_ROOT}/etc/group | egrep '^'$SSHDGID'\$' >/dev/null
+               then
+                       :
+               else
+                       sshdgid="-g $SSHDGID"
+               fi
+               echo "Creating PrivSep group \$SSH_PRIVSEP_GROUP."
+               \$chroot ${PATH_GROUPADD_PROG} \$sshdgid \$SSH_PRIVSEP_GROUP
+       }
+
+       # Create user if required
+       [ "\$DO_PASSWD" = yes ]  &&  {
+               # Use uid of 67 if possible
+               if cut -f3 -d: \${PKG_INSTALL_ROOT}/etc/passwd | egrep '^'$SSHDUID'\$' >/dev/null
+               then
+                       :
+               else
+                       sshduid="-u $SSHDUID"
+               fi
+               echo "Creating PrivSep user $SSH_PRIVSEP_USER."
+               \$chroot ${PATH_USERADD_PROG} -c 'SSHD PrivSep User' -s /bin/false -g $SSH_PRIVSEP_USER \$sshduid $SSH_PRIVSEP_USER
+               \$chroot ${PATH_PASSWD_PROG} -l $SSH_PRIVSEP_USER
+       }
+
+if [ "\${POST_INS_START}" = "yes" ]
+then
+       if [ $DO_SMF -eq 1 ]
+       then
+               svcadm enable $OPENSSH_FMRI
+       else
+               ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} start
+       fi
+fi
+exit 0
+_EOF
+
+## Build preremove file
+echo "Building preremove file..."
+cat > preremove << _EOF
+#! ${SCRIPT_SHELL}
+#
+if [ $DO_SMF -eq 1 ] 
+then
+       svcadm disable $OPENSSH_FMRI
+else
+       ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} stop
+fi
+_EOF
+
+# local preremove changes here
+[ -s "${PKG_PREREMOVE_LOCAL}" ]  &&  . ${PKG_PREREMOVE_LOCAL}
+
+cat >> preremove << _EOF
+exit 0
+_EOF
+
+## Build postremove file
+echo "Building postremove file..."
+cat > postremove << _EOF
+#! ${SCRIPT_SHELL}
+#
+if [ $DO_SMF -eq 1 ]
+then
+       if svcs $OPENSSH_FMRI > /dev/null 2>&1
+       then
+               svccfg delete -f $OPENSSH_FMRI
+       fi
+fi
+_EOF
+
+# local postremove changes here
+[ -s "${PKG_POSTREMOVE_LOCAL}" ]  &&  . ${PKG_POSTREMOVE_LOCAL}
+
+cat >> postremove << _EOF
+exit 0
+_EOF
+
+## Build request file
+echo "Building request file..."
+cat > request << _EOF
+trap 'exit 3' 15
+
+_EOF
+
+[ -x /usr/bin/ckyorn ]  ||  cat >> request << _EOF
+
+ckyorn() {
+# for some strange reason OpenServer5 has no ckyorn
+# We build a striped down version here
+
+DEFAULT=n
+PROMPT="Yes or No [yes,no,?,quit]"
+HELP_PROMPT="        Enter y or yes if your answer is yes; n or no if your answer is no."
+USAGE="usage: ckyorn [options]
+where options may include:
+        -d default
+        -h help
+        -p prompt
+"
+
+if [ \$# != 0 ]
+then
+       while getopts d:p:h: c
+       do
+               case \$c in
+                       h)      HELP_PROMPT="\$OPTARG" ;;
+                       d)      DEFAULT=\$OPTARG ;;
+                       p)      PROMPT=\$OPTARG ;;
+                       \\?)    echo "\$USAGE" 1>&2
+                               exit 1 ;;
+               esac
+       done
+       shift \`expr \$OPTIND - 1\`
+fi
+
+while true
+do
+       echo "\${PROMPT}\\c " 1>&2
+       read key
+       [ -z "\$key" ]  &&  key=\$DEFAULT
+       case \$key in
+               [n,N]|[n,N][o,O]|[y,Y]|[y,Y][e,E][s,S]) echo "\${key}\\c"
+                       exit 0 ;;
+               \\?)    echo \$HELP_PROMPT 1>&2 ;;
+               q|quit) echo "q\\c" 1>&2
+                       exit 3 ;;
+       esac
+done
+
+}
+
+_EOF
+
+if [ $DO_SMF -eq 1 ]
+then
+       # This could get hairy, as the running sshd may not be under SMF.
+       # We'll assume an earlier version of OpenSSH started via SMF.
+       cat >> request << _EOF
+PRE_INS_STOP=no
+POST_INS_START=no
+# determine if should restart the daemon
+if [ -s ${piddir}/sshd.pid  ] && \
+    /usr/bin/svcs -H $OPENSSH_FMRI 2>&1 | egrep "^online" > /dev/null 2>&1
+then
+       ans=\`ckyorn -d n \
+-p "Should the running sshd daemon be restarted? ${DEF_MSG}"\` || exit \$?
+       case \$ans in
+               [y,Y]*) PRE_INS_STOP=yes
+                       POST_INS_START=yes
+                       ;;
+       esac
+
+else
+
+# determine if we should start sshd
+       ans=\`ckyorn -d n \
+-p "Start the sshd daemon after installing this package? ${DEF_MSG}"\` || exit \$?
+       case \$ans in
+               [y,Y]*) POST_INS_START=yes ;;
+       esac
+fi
+
+# make parameters available to installation service,
+# and so to any other packaging scripts
+cat >\$1 <<!
+PRE_INS_STOP='\$PRE_INS_STOP'
+POST_INS_START='\$POST_INS_START'
+!
+
+_EOF
+else
+       cat >> request << _EOF
+USE_SYM_LINKS=no
+PRE_INS_STOP=no
+POST_INS_START=no
+# Use symbolic links?
+ans=\`ckyorn -d n \
+-p "Do you want symbolic links for the start/stop scripts? ${DEF_MSG}"\` || exit \$?
+case \$ans in
+       [y,Y]*) USE_SYM_LINKS=yes ;;
+esac
+
+# determine if should restart the daemon
+if [ -s ${piddir}/sshd.pid  -a  -f ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} ]
+then
+       ans=\`ckyorn -d n \
+-p "Should the running sshd daemon be restarted? ${DEF_MSG}"\` || exit \$?
+       case \$ans in
+               [y,Y]*) PRE_INS_STOP=yes
+                       POST_INS_START=yes
+                       ;;
+       esac
+
+else
+
+# determine if we should start sshd
+       ans=\`ckyorn -d n \
+-p "Start the sshd daemon after installing this package? ${DEF_MSG}"\` || exit \$?
+       case \$ans in
+               [y,Y]*) POST_INS_START=yes ;;
+       esac
+fi
+
+# make parameters available to installation service,
+# and so to any other packaging scripts
+cat >\$1 <<!
+USE_SYM_LINKS='\$USE_SYM_LINKS'
+PRE_INS_STOP='\$PRE_INS_STOP'
+POST_INS_START='\$POST_INS_START'
+!
+
+_EOF
+fi
+
+# local request changes here
+[ -s "${PKG_REQUEST_LOCAL}" ]  &&  . ${PKG_REQUEST_LOCAL}
+
+cat >> request << _EOF
+exit 0
+
+_EOF
+
+## Next Build our prototype
+echo "Building prototype file..."
+cat >mk-proto.awk << _EOF
+           BEGIN { print "i pkginfo"; print "i depend"; \\
+                   print "i preinstall"; print "i postinstall"; \\
+                   print "i preremove"; print "i postremove"; \\
+                   print "i request"; print "i space"; \\
+                   split("$SYSTEM_DIR",sys_files); }
+           {
+            for (dir in sys_files) { if ( \$3 != sys_files[dir] )
+                    { if ( \$1 == "s" )
+                       { \$5=""; \$6=""; }
+                    else
+                       { \$5="root"; \$6="sys"; }
+                    }
+               else
+                    { \$4="?"; \$5="?"; \$6="?"; break;}
+           } }
+           { print; }
+_EOF
+
+find . | egrep -v "prototype|pkginfo|mk-proto.awk" | sort | \
+       pkgproto $PROTO_ARGS | ${AWK} -f mk-proto.awk > prototype
+
+# /usr/local is a symlink on some systems
+[ "${USR_LOCAL_IS_SYMLINK}" = yes ]  &&  {
+       grep -v "^d none /usr/local ? ? ?$" prototype > prototype.new
+       mv prototype.new prototype
+}
+
+## Step back a directory and now build the package.
+cd ..
+# local prototype tweeks here
+[ -s "${POST_PROTOTYPE_EDITS}" ]  &&  . ${POST_PROTOTYPE_EDITS}
+
+echo "Building package.."
+pkgmk -d ${FAKE_ROOT} -f $FAKE_ROOT/prototype -o
+echo | pkgtrans -os ${FAKE_ROOT} ${START}/$PKGNAME-$VERSION$REV-$UNAME_S-$ARCH.pkg
+       ;;
+
+       justpkg.sh)
+rm -fr ${FAKE_ROOT}/${PKGNAME}
+grep -v "^PSTAMP=" $FAKE_ROOT/pkginfo > $$tmp
+mv $$tmp $FAKE_ROOT/pkginfo
+cat >> $FAKE_ROOT/pkginfo << _EOF
+PSTAMP="${UNAME_S} ${OS_VER} ${ARCH} `date '+%d%b%Y %H:%M'`"
+_EOF
+pkgmk -d ${FAKE_ROOT} -f $FAKE_ROOT/prototype -o
+echo | pkgtrans -os ${FAKE_ROOT} ${START}/$PKGNAME-$VERSION$REV-$UNAME_S-$ARCH.pkg
+       ;;
+
+esac
+
+[ "${REMOVE_FAKE_ROOT_WHEN_DONE}" = yes ]  &&  rm -rf $FAKE_ROOT
+exit 0
+
diff --git a/canohost.c b/canohost.c
new file mode 100644 (file)
index 0000000..dabd8a3
--- /dev/null
@@ -0,0 +1,440 @@
+/* $OpenBSD: canohost.c,v 1.66 2010/01/13 01:20:20 dtucker Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "packet.h"
+#include "log.h"
+#include "canohost.h"
+#include "misc.h"
+
+static void check_ip_options(int, char *);
+static char *canonical_host_ip = NULL;
+static int cached_port = -1;
+
+/*
+ * 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 sock, int use_dns)
+{
+       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(sock, (struct sockaddr *)&from, &fromlen) < 0) {
+               debug("getpeername failed: %.100s", strerror(errno));
+               cleanup_exit(255);
+       }
+
+       if (from.ss_family == AF_INET)
+               check_ip_options(sock, ntop);
+
+       ipv64_normalise_mapped(&from, &fromlen);
+
+       if (from.ss_family == AF_INET6)
+               fromlen = sizeof(struct sockaddr_in6);
+
+       if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
+           NULL, 0, NI_NUMERICHOST) != 0)
+               fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
+
+       if (!use_dns)
+               return xstrdup(ntop);
+
+       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. */
+               return xstrdup(ntop);
+       }
+
+       /*
+        * if reverse lookup result looks like a numeric hostname,
+        * someone is trying to trick us by PTR record like following:
+        *      1.1.1.10.in-addr.arpa.  IN PTR  2.3.4.5
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+       hints.ai_flags = AI_NUMERICHOST;
+       if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
+               logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
+                   name, ntop);
+               freeaddrinfo(ai);
+               return xstrdup(ntop);
+       }
+
+       /*
+        * 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] = (char)tolower(name[i]);
+       /*
+        * 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) {
+               logit("reverse mapping checking getaddrinfo for %.700s "
+                   "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop);
+               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. */
+               logit("Address %.100s maps to %.600s, but this does not "
+                   "map back to the address - POSSIBLE BREAK-IN 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 sock, char *ipaddr)
+{
+#ifdef IP_OPTIONS
+       u_char options[200];
+       char text[sizeof(options) * 3 + 1];
+       socklen_t option_size;
+       u_int i;
+       int ipproto;
+       struct protoent *ip;
+
+       if ((ip = getprotobyname("ip")) != NULL)
+               ipproto = ip->p_proto;
+       else
+               ipproto = IPPROTO_IP;
+       option_size = sizeof(options);
+       if (getsockopt(sock, ipproto, IP_OPTIONS, 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]);
+               fatal("Connection from %.100s with IP options:%.800s",
+                   ipaddr, text);
+       }
+#endif /* IP_OPTIONS */
+}
+
+void
+ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
+{
+       struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
+       struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
+       struct in_addr inaddr;
+       u_int16_t port;
+
+       if (addr->ss_family != AF_INET6 ||
+           !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
+               return;
+
+       debug3("Normalising mapped IPv4 in IPv6 address");
+
+       memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
+       port = a6->sin6_port;
+
+       bzero(a4, sizeof(*a4));
+
+       a4->sin_family = AF_INET;
+       *len = sizeof(*a4);
+       memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
+       a4->sin_port = port;
+}
+
+/*
+ * 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 use_dns)
+{
+       char *host;
+       static char *canonical_host_name = NULL;
+       static char *remote_ip = NULL;
+
+       /* Check if we have previously retrieved name with same option. */
+       if (use_dns && canonical_host_name != NULL)
+               return canonical_host_name;
+       if (!use_dns && remote_ip != NULL)
+               return remote_ip;
+
+       /* Get the real hostname if socket; otherwise return UNKNOWN. */
+       if (packet_connection_is_on_socket())
+               host = get_remote_hostname(packet_get_connection_in(), use_dns);
+       else
+               host = "UNKNOWN";
+
+       if (use_dns)
+               canonical_host_name = host;
+       else
+               remote_ip = host;
+       return host;
+}
+
+/*
+ * Returns the local/remote IP-address/hostname of socket as a string.
+ * The returned string must be freed.
+ */
+static char *
+get_socket_address(int sock, int remote, int flags)
+{
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       char ntop[NI_MAXHOST];
+       int r;
+
+       /* Get IP address of client. */
+       addrlen = sizeof(addr);
+       memset(&addr, 0, sizeof(addr));
+
+       if (remote) {
+               if (getpeername(sock, (struct sockaddr *)&addr, &addrlen)
+                   < 0)
+                       return NULL;
+       } else {
+               if (getsockname(sock, (struct sockaddr *)&addr, &addrlen)
+                   < 0)
+                       return NULL;
+       }
+
+       /* Work around Linux IPv6 weirdness */
+       if (addr.ss_family == AF_INET6)
+               addrlen = sizeof(struct sockaddr_in6);
+
+       ipv64_normalise_mapped(&addr, &addrlen);
+
+       /* Get the address in ascii. */
+       if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
+           sizeof(ntop), NULL, 0, flags)) != 0) {
+               error("get_socket_address: getnameinfo %d failed: %s", flags,
+                   ssh_gai_strerror(r));
+               return NULL;
+       }
+       return xstrdup(ntop);
+}
+
+char *
+get_peer_ipaddr(int sock)
+{
+       char *p;
+
+       if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
+               return p;
+       return xstrdup("UNKNOWN");
+}
+
+char *
+get_local_ipaddr(int sock)
+{
+       char *p;
+
+       if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
+               return p;
+       return xstrdup("UNKNOWN");
+}
+
+char *
+get_local_name(int fd)
+{
+       char *host, myname[NI_MAXHOST];
+
+       /* Assume we were passed a socket */
+       if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
+               return host;
+
+       /* Handle the case where we were passed a pipe */
+       if (gethostname(myname, sizeof(myname)) == -1) {
+               verbose("get_local_name: gethostname: %s", strerror(errno));
+       } else {
+               host = xstrdup(myname);
+       }
+
+       return host;
+}
+
+void
+clear_cached_addr(void)
+{
+       if (canonical_host_ip != NULL) {
+               xfree(canonical_host_ip);
+               canonical_host_ip = NULL;
+       }
+       cached_port = -1;
+}
+
+/*
+ * Returns the IP-address of the remote host as a string.  The returned
+ * string must not be freed.
+ */
+
+const char *
+get_remote_ipaddr(void)
+{
+       /* 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)
+                               cleanup_exit(255);
+               } 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 use_dns)
+{
+       static const char *remote = "";
+       if (utmp_len > 0)
+               remote = get_canonical_hostname(use_dns);
+       if (utmp_len == 0 || strlen(remote) > utmp_len)
+               remote = get_remote_ipaddr();
+       return remote;
+}
+
+/* Returns the local/remote port for the socket. */
+
+int
+get_sock_port(int sock, int local)
+{
+       struct sockaddr_storage from;
+       socklen_t fromlen;
+       char strport[NI_MAXSERV];
+       int r;
+
+       /* 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));
+                       return -1;
+               }
+       }
+
+       /* Work around Linux IPv6 weirdness */
+       if (from.ss_family == AF_INET6)
+               fromlen = sizeof(struct sockaddr_in6);
+
+       /* Return port number. */
+       if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
+           strport, sizeof(strport), NI_NUMERICSERV)) != 0)
+               fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s",
+                   ssh_gai_strerror(r));
+       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(void)
+{
+       /* Cache to avoid getpeername() on a dead connection */
+       if (cached_port == -1)
+               cached_port = get_port(0);
+
+       return cached_port;
+}
+
+int
+get_local_port(void)
+{
+       return get_port(1);
+}
diff --git a/canohost.h b/canohost.h
new file mode 100644 (file)
index 0000000..4c8636f
--- /dev/null
@@ -0,0 +1,29 @@
+/* $OpenBSD: canohost.h,v 1.11 2009/05/27 06:31:25 andreas 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);
+int             get_sock_port(int, int);
+void            clear_cached_addr(void);
+
+void            ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
diff --git a/channels.c b/channels.c
new file mode 100644 (file)
index 0000000..6abe2d0
--- /dev/null
@@ -0,0 +1,3642 @@
+/* $OpenBSD: channels.c,v 1.310 2010/11/24 01:24:14 djm Exp $ */
+/*
+ * 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, 2002 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"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "log.h"
+#include "misc.h"
+#include "buffer.h"
+#include "channels.h"
+#include "compat.h"
+#include "canohost.h"
+#include "key.h"
+#include "authfd.h"
+#include "pathnames.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 u_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 by the user. */
+static ForwardPermission *permitted_opens = NULL;
+
+/* List of all permitted host/port pairs to connect by the admin. */
+static ForwardPermission *permitted_adm_opens = NULL;
+
+/* Number of permitted host/port pairs in the array permitted by the user. */
+static int num_permitted_opens = 0;
+
+/* Number of permitted host/port pair in the array permitted by the admin. */
+static int num_adm_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 local (client) display. */
+static char *x11_saved_display = NULL;
+
+/* 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 u_char *x11_fake_data = NULL;
+static u_int x11_fake_data_len;
+
+
+/* -- agent forwarding */
+
+#define        NUM_SOCKS       10
+
+/* AF_UNSPEC or AF_INET or AF_INET6 */
+static int IPv4or6 = AF_UNSPEC;
+
+/* helper */
+static void port_open_helper(Channel *c, char *rtype);
+
+/* non-blocking connect helpers */
+static int connect_next(struct channel_connect *);
+static void channel_connect_ctx_free(struct channel_connect *);
+
+/* -- channel core */
+
+Channel *
+channel_by_id(int id)
+{
+       Channel *c;
+
+       if (id < 0 || (u_int)id >= channels_alloc) {
+               logit("channel_by_id: %d: bad id", id);
+               return NULL;
+       }
+       c = channels[id];
+       if (c == NULL) {
+               logit("channel_by_id: %d: bad id: channel free", id);
+               return NULL;
+       }
+       return c;
+}
+
+/*
+ * Returns the channel if it is allowed to receive protocol messages.
+ * Private channels, like listening sockets, may not receive messages.
+ */
+Channel *
+channel_lookup(int id)
+{
+       Channel *c;
+
+       if ((c = channel_by_id(id)) == NULL)
+               return (NULL);
+
+       switch (c->type) {
+       case SSH_CHANNEL_X11_OPEN:
+       case SSH_CHANNEL_LARVAL:
+       case SSH_CHANNEL_CONNECTING:
+       case SSH_CHANNEL_DYNAMIC:
+       case SSH_CHANNEL_OPENING:
+       case SSH_CHANNEL_OPEN:
+       case SSH_CHANNEL_INPUT_DRAINING:
+       case SSH_CHANNEL_OUTPUT_DRAINING:
+               return (c);
+       }
+       logit("Non-public channel %d, type %d.", id, c->type);
+       return (NULL);
+}
+
+/*
+ * 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, int is_tty)
+{
+       /* 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);
+
+       if (rfd != -1)
+               fcntl(rfd, F_SETFD, FD_CLOEXEC);
+       if (wfd != -1 && wfd != rfd)
+               fcntl(wfd, F_SETFD, FD_CLOEXEC);
+       if (efd != -1 && efd != rfd && efd != wfd)
+               fcntl(efd, F_SETFD, FD_CLOEXEC);
+
+       c->rfd = rfd;
+       c->wfd = wfd;
+       c->sock = (rfd == wfd) ? rfd : -1;
+       c->efd = efd;
+       c->extended_usage = extusage;
+
+       if ((c->isatty = is_tty) != 0)
+               debug2("channel %d: rfd %d isatty", c->self, c->rfd);
+       c->wfd_isatty = is_tty || isatty(c->wfd);
+
+       /* 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,
+    u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
+{
+       int found;
+       u_int i;
+       Channel *c;
+
+       /* Do initial allocation if this is the first call. */
+       if (channels_alloc == 0) {
+               channels_alloc = 10;
+               channels = xcalloc(channels_alloc, sizeof(Channel *));
+               for (i = 0; i < channels_alloc; i++)
+                       channels[i] = 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 = (int)i;
+                       break;
+               }
+       if (found < 0) {
+               /* There are no free slots.  Take last+1 slot and expand the array.  */
+               found = channels_alloc;
+               if (channels_alloc > 10000)
+                       fatal("channel_new: internal error: channels_alloc %d "
+                           "too big.", channels_alloc);
+               channels = xrealloc(channels, channels_alloc + 10,
+                   sizeof(Channel *));
+               channels_alloc += 10;
+               debug2("channel: expanding %d", channels_alloc);
+               for (i = found; i < channels_alloc; i++)
+                       channels[i] = NULL;
+       }
+       /* Initialize and return new channel. */
+       c = channels[found] = xcalloc(1, sizeof(Channel));
+       buffer_init(&c->input);
+       buffer_init(&c->output);
+       buffer_init(&c->extended);
+       c->path = NULL;
+       c->ostate = CHAN_OUTPUT_OPEN;
+       c->istate = CHAN_INPUT_OPEN;
+       c->flags = 0;
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
+       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 = xstrdup(remote_name);
+       c->remote_window = 0;
+       c->remote_maxpacket = 0;
+       c->force_drain = 0;
+       c->single_connection = 0;
+       c->detach_user = NULL;
+       c->detach_close = 0;
+       c->open_confirm = NULL;
+       c->open_confirm_ctx = NULL;
+       c->input_filter = NULL;
+       c->output_filter = NULL;
+       c->filter_ctx = NULL;
+       c->filter_cleanup = NULL;
+       c->ctl_chan = -1;
+       c->mux_rcb = NULL;
+       c->mux_ctx = NULL;
+       c->mux_pause = 0;
+       c->delayed = 1;         /* prevent call to channel_post handler */
+       TAILQ_INIT(&c->status_confirms);
+       debug("channel %d: new [%s]", found, remote_name);
+       return c;
+}
+
+static int
+channel_find_maxfd(void)
+{
+       u_int i;
+       int 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)
+{
+       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;
+       u_int i, n;
+       struct channel_confirm *cc;
+
+       for (n = 0, i = 0; i < channels_alloc; i++)
+               if (channels[i])
+                       n++;
+       debug("channel %d: free: %s, nchannels %u", c->self,
+           c->remote_name ? c->remote_name : "???", n);
+
+       s = channel_open_message();
+       debug3("channel %d: status: %s", c->self, 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;
+       }
+       if (c->path) {
+               xfree(c->path);
+               c->path = NULL;
+       }
+       while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
+               if (cc->abandon_cb != NULL)
+                       cc->abandon_cb(c, cc->ctx);
+               TAILQ_REMOVE(&c->status_confirms, cc, entry);
+               bzero(cc, sizeof(*cc));
+               xfree(cc);
+       }
+       if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
+               c->filter_cleanup(c->self, c->filter_ctx);
+       channels[c->self] = NULL;
+       xfree(c);
+}
+
+void
+channel_free_all(void)
+{
+       u_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(void)
+{
+       u_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)
+{
+       u_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(void)
+{
+       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()) {
+                               debug2("channel %d: big input buffer %d",
+                                   c->self, buffer_len(&c->input));
+                               return 0;
+                       }
+#endif
+                       if (buffer_len(&c->output) > packet_get_maxsize()) {
+                               debug2("channel %d: big output buffer %u > %u",
+                                   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(void)
+{
+       u_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_MUX_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:
+               case SSH_CHANNEL_MUX_CLIENT:
+                       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(void)
+{
+       u_int i;
+       Channel *c;
+
+       for (i = 0; i < channels_alloc; i++) {
+               c = channels[i];
+               if (c == NULL || c->remote_id < 0)
+                       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_MUX_LISTENER:
+               case SSH_CHANNEL_MUX_CLIENT:
+               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(void)
+{
+       Buffer buffer;
+       Channel *c;
+       char buf[1024], *cp;
+       u_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:
+               case SSH_CHANNEL_MUX_CLIENT:
+               case SSH_CHANNEL_MUX_LISTENER:
+                       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 cc %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, c->ctl_chan);
+                       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) {
+               logit("channel_send_open: %d: bad id", id);
+               return;
+       }
+       debug2("channel %d: send open", 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_start(int id, char *service, int wantconfirm)
+{
+       Channel *c = channel_lookup(id);
+
+       if (c == NULL) {
+               logit("channel_request_start: %d: unknown channel id", id);
+               return;
+       }
+       debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
+       packet_start(SSH2_MSG_CHANNEL_REQUEST);
+       packet_put_int(c->remote_id);
+       packet_put_cstring(service);
+       packet_put_char(wantconfirm);
+}
+
+void
+channel_register_status_confirm(int id, channel_confirm_cb *cb,
+    channel_confirm_abandon_cb *abandon_cb, void *ctx)
+{
+       struct channel_confirm *cc;
+       Channel *c;
+
+       if ((c = channel_lookup(id)) == NULL)
+               fatal("channel_register_expect: %d: bad id", id);
+
+       cc = xmalloc(sizeof(*cc));
+       cc->cb = cb;
+       cc->abandon_cb = abandon_cb;
+       cc->ctx = ctx;
+       TAILQ_INSERT_TAIL(&c->status_confirms, cc, entry);
+}
+
+void
+channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
+{
+       Channel *c = channel_lookup(id);
+
+       if (c == NULL) {
+               logit("channel_register_open_confirm: %d: bad id", id);
+               return;
+       }
+       c->open_confirm = fn;
+       c->open_confirm_ctx = ctx;
+}
+
+void
+channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
+{
+       Channel *c = channel_by_id(id);
+
+       if (c == NULL) {
+               logit("channel_register_cleanup: %d: bad id", id);
+               return;
+       }
+       c->detach_user = fn;
+       c->detach_close = do_close;
+}
+
+void
+channel_cancel_cleanup(int id)
+{
+       Channel *c = channel_by_id(id);
+
+       if (c == NULL) {
+               logit("channel_cancel_cleanup: %d: bad id", id);
+               return;
+       }
+       c->detach_user = NULL;
+       c->detach_close = 0;
+}
+
+void
+channel_register_filter(int id, channel_infilter_fn *ifn,
+    channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
+{
+       Channel *c = channel_lookup(id);
+
+       if (c == NULL) {
+               logit("channel_register_filter: %d: bad id", id);
+               return;
+       }
+       c->input_filter = ifn;
+       c->output_filter = ofn;
+       c->filter_ctx = ctx;
+       c->filter_cleanup = cfn;
+}
+
+void
+channel_set_fds(int id, int rfd, int wfd, int efd,
+    int extusage, int nonblock, int is_tty, u_int window_max)
+{
+       Channel *c = channel_lookup(id);
+
+       if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
+               fatal("channel_activate for non-larval channel %d.", id);
+       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
+       c->type = SSH_CHANNEL_OPEN;
+       c->local_window = c->local_window_max = window_max;
+       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];
+
+/* ARGSUSED */
+static void
+channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       FD_SET(c->sock, readset);
+}
+
+/* ARGSUSED */
+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(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
+
+       if (c->istate == CHAN_INPUT_OPEN &&
+           limit > 0 &&
+           buffer_len(&c->input) < limit &&
+           buffer_check_alloc(&c->input, CHAN_RBUF))
+               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) {
+                       if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
+                               debug2("channel %d: obuf_empty delayed efd %d/(%d)",
+                                   c->self, c->efd, buffer_len(&c->extended));
+                       else
+                               chan_obuf_empty(c);
+               }
+       }
+       /** XXX check close conditions, too */
+       if (compat20 && c->efd != -1 && 
+           !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
+               if (c->extended_usage == CHAN_EXTENDED_WRITE &&
+                   buffer_len(&c->extended) > 0)
+                       FD_SET(c->efd, writeset);
+               else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
+                   (c->extended_usage == CHAN_EXTENDED_READ ||
+                   c->extended_usage == CHAN_EXTENDED_IGNORE) &&
+                   buffer_len(&c->extended) < c->remote_window)
+                       FD_SET(c->efd, readset);
+       }
+       /* XXX: What about efd? races? */
+}
+
+/* ARGSUSED */
+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;
+               debug2("channel %d: closing after input drain.", c->self);
+       }
+}
+
+/* ARGSUSED */
+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 = 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 {
+               debug2("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) {
+               debug2("X11 connection uses different authentication protocol.");
+               return -1;
+       }
+       /* Check if authentication data matches our fake data. */
+       if (data_len != x11_fake_data_len ||
+           timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
+               x11_fake_data, x11_fake_data_len) != 0) {
+               debug2("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.
+                */
+               logit("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;
+               channel_pre_open(c, readset, writeset);
+       } else if (ret == -1) {
+               logit("X11 connection rejected because of wrong authentication.");
+               debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
+               chan_read_failed(c);
+               buffer_clear(&c->input);
+               chan_ibuf_empty(c);
+               buffer_clear(&c->output);
+               /* for proto v1, the peer will send an IEOF */
+               if (compat20)
+                       chan_write_failed(c);
+               else
+                       c->type = SSH_CHANNEL_OPEN;
+               debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
+       }
+}
+
+static void
+channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
+           buffer_check_alloc(&c->input, CHAN_RBUF))
+               FD_SET(c->rfd, readset);
+       if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
+               /* clear buffer immediately (discard any partial packet) */
+               buffer_clear(&c->input);
+               chan_ibuf_empty(c);
+               /* Start output drain. XXX just kill chan? */
+               chan_rcvd_oclose(c);
+       }
+       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);
+       }
+}
+
+/* try to decode a socks4 header */
+/* ARGSUSED */
+static int
+channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       char *p, *host;
+       u_int len, have, i, found, need;
+       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);
+
+       need = 1;
+       /* SOCKS4A uses an invalid IP address 0.0.0.x */
+       if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) {
+               debug2("channel %d: socks4a request", c->self);
+               /* ... and needs an extra string (the hostname) */
+               need = 2;
+       }
+       /* Check for terminating NUL on the string(s) */
+       for (found = 0, i = len; i < have; i++) {
+               if (p[i] == '\0') {
+                       found++;
+                       if (found == need)
+                               break;
+               }
+               if (i > 1024) {
+                       /* the peer is probably sending garbage */
+                       debug("channel %d: decode socks4: too long",
+                           c->self);
+                       return -1;
+               }
+       }
+       if (found < need)
+               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);
+       len++;                                  /* trailing '\0' */
+       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);
+
+       if (c->path != NULL) {
+               xfree(c->path);
+               c->path = NULL;
+       }
+       if (need == 1) {                        /* SOCKS4: one string */
+               host = inet_ntoa(s4_req.dest_addr);
+               c->path = xstrdup(host);
+       } else {                                /* SOCKS4A: two strings */
+               have = buffer_len(&c->input);
+               p = buffer_ptr(&c->input);
+               len = strlen(p);
+               debug2("channel %d: decode socks4a: host %s/%d",
+                   c->self, p, len);
+               len++;                          /* trailing '\0' */
+               if (len > have)
+                       fatal("channel %d: decode socks4a: len %d > have %d",
+                           c->self, len, have);
+               if (len > NI_MAXHOST) {
+                       error("channel %d: hostname \"%.100s\" too long",
+                           c->self, p);
+                       return -1;
+               }
+               c->path = xstrdup(p);
+               buffer_consume(&c->input, len);
+       }
+       c->host_port = ntohs(s4_req.dest_port);
+
+       debug2("channel %d: dynamic request: socks4 host %s port %u command %u",
+           c->self, c->path, c->host_port, s4_req.command);
+
+       if (s4_req.command != 1) {
+               debug("channel %d: cannot handle: %s cn %d",
+                   c->self, need == 1 ? "SOCKS4" : "SOCKS4A", 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, &s4_rsp, sizeof(s4_rsp));
+       return 1;
+}
+
+/* try to decode a socks5 header */
+#define SSH_SOCKS5_AUTHDONE    0x1000
+#define SSH_SOCKS5_NOAUTH      0x00
+#define SSH_SOCKS5_IPV4                0x01
+#define SSH_SOCKS5_DOMAIN      0x03
+#define SSH_SOCKS5_IPV6                0x04
+#define SSH_SOCKS5_CONNECT     0x01
+#define SSH_SOCKS5_SUCCESS     0x00
+
+/* ARGSUSED */
+static int
+channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       struct {
+               u_int8_t version;
+               u_int8_t command;
+               u_int8_t reserved;
+               u_int8_t atyp;
+       } s5_req, s5_rsp;
+       u_int16_t dest_port;
+       u_char *p, dest_addr[255+1], ntop[INET6_ADDRSTRLEN];
+       u_int have, need, i, found, nmethods, addrlen, af;
+
+       debug2("channel %d: decode socks5", c->self);
+       p = buffer_ptr(&c->input);
+       if (p[0] != 0x05)
+               return -1;
+       have = buffer_len(&c->input);
+       if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
+               /* format: ver | nmethods | methods */
+               if (have < 2)
+                       return 0;
+               nmethods = p[1];
+               if (have < nmethods + 2)
+                       return 0;
+               /* look for method: "NO AUTHENTICATION REQUIRED" */
+               for (found = 0, i = 2; i < nmethods + 2; i++) {
+                       if (p[i] == SSH_SOCKS5_NOAUTH) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
+                           c->self);
+                       return -1;
+               }
+               buffer_consume(&c->input, nmethods + 2);
+               buffer_put_char(&c->output, 0x05);              /* version */
+               buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */
+               FD_SET(c->sock, writeset);
+               c->flags |= SSH_SOCKS5_AUTHDONE;
+               debug2("channel %d: socks5 auth done", c->self);
+               return 0;                               /* need more */
+       }
+       debug2("channel %d: socks5 post auth", c->self);
+       if (have < sizeof(s5_req)+1)
+               return 0;                       /* need more */
+       memcpy(&s5_req, p, sizeof(s5_req));
+       if (s5_req.version != 0x05 ||
+           s5_req.command != SSH_SOCKS5_CONNECT ||
+           s5_req.reserved != 0x00) {
+               debug2("channel %d: only socks5 connect supported", c->self);
+               return -1;
+       }
+       switch (s5_req.atyp){
+       case SSH_SOCKS5_IPV4:
+               addrlen = 4;
+               af = AF_INET;
+               break;
+       case SSH_SOCKS5_DOMAIN:
+               addrlen = p[sizeof(s5_req)];
+               af = -1;
+               break;
+       case SSH_SOCKS5_IPV6:
+               addrlen = 16;
+               af = AF_INET6;
+               break;
+       default:
+               debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
+               return -1;
+       }
+       need = sizeof(s5_req) + addrlen + 2;
+       if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
+               need++;
+       if (have < need)
+               return 0;
+       buffer_consume(&c->input, sizeof(s5_req));
+       if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
+               buffer_consume(&c->input, 1);    /* host string length */
+       buffer_get(&c->input, (char *)&dest_addr, addrlen);
+       buffer_get(&c->input, (char *)&dest_port, 2);
+       dest_addr[addrlen] = '\0';
+       if (c->path != NULL) {
+               xfree(c->path);
+               c->path = NULL;
+       }
+       if (s5_req.atyp == SSH_SOCKS5_DOMAIN) {
+               if (addrlen >= NI_MAXHOST) {
+                       error("channel %d: dynamic request: socks5 hostname "
+                           "\"%.100s\" too long", c->self, dest_addr);
+                       return -1;
+               }
+               c->path = xstrdup(dest_addr);
+       } else {
+               if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL)
+                       return -1;
+               c->path = xstrdup(ntop);
+       }
+       c->host_port = ntohs(dest_port);
+
+       debug2("channel %d: dynamic request: socks5 host %s port %u command %u",
+           c->self, c->path, c->host_port, s5_req.command);
+
+       s5_rsp.version = 0x05;
+       s5_rsp.command = SSH_SOCKS5_SUCCESS;
+       s5_rsp.reserved = 0;                    /* ignored */
+       s5_rsp.atyp = SSH_SOCKS5_IPV4;
+       ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
+       dest_port = 0;                          /* ignored */
+
+       buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp));
+       buffer_append(&c->output, &dest_addr, sizeof(struct in_addr));
+       buffer_append(&c->output, &dest_port, sizeof(dest_port));
+       return 1;
+}
+
+Channel *
+channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect,
+    int in, int out)
+{
+       Channel *c;
+
+       debug("channel_connect_stdio_fwd %s:%d", host_to_connect,
+           port_to_connect);
+
+       c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out,
+           -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+           0, "stdio-forward", /*nonblock*/0);
+
+       c->path = xstrdup(host_to_connect);
+       c->host_port = port_to_connect;
+       c->listening_port = 0;
+       c->force_drain = 1;
+
+       channel_register_fds(c, in, out, -1, 0, 1, 0);
+       port_open_helper(c, "direct-tcpip");
+
+       return c;
+}
+
+/* dynamic port forwarding */
+static void
+channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       u_char *p;
+       u_int have;
+       int ret;
+
+       have = buffer_len(&c->input);
+       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 < 3) {
+               /* 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;
+       case 0x05:
+               ret = channel_decode_socks5(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. */
+/* ARGSUSED */
+static void
+channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       Channel *nc;
+       struct sockaddr_storage 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, (struct sockaddr *)&addr, &addrlen);
+               if (c->single_connection) {
+                       debug2("single_connection: closing X11 listener.");
+                       channel_close_fd(&c->sock);
+                       chan_mark_dead(c);
+               }
+               if (newsock < 0) {
+                       error("accept: %.100s", strerror(errno));
+                       return;
+               }
+               set_nodelay(newsock);
+               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, buf, 1);
+               if (compat20) {
+                       packet_start(SSH2_MSG_CHANNEL_OPEN);
+                       packet_put_cstring("x11");
+                       packet_put_int(nc->self);
+                       packet_put_int(nc->local_window_max);
+                       packet_put_int(nc->local_maxpacket);
+                       /* originator ipaddr and port */
+                       packet_put_cstring(remote_ipaddr);
+                       if (datafellows & SSH_BUG_X11FWD) {
+                               debug2("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);
+       int remote_port = get_peer_port(c->sock);
+
+       if (remote_port == -1) {
+               /* Fake addr/port to appease peers that validate it (Tectia) */
+               xfree(remote_ipaddr);
+               remote_ipaddr = xstrdup("127.0.0.1");
+               remote_port = 65535;
+       }
+
+       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((u_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);
+}
+
+static void
+channel_set_reuseaddr(int fd)
+{
+       int on = 1;
+
+       /*
+        * Set socket options.
+        * Allow local port reuse in TIME_WAIT.
+        */
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
+               error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
+}
+
+/*
+ * This socket is listening for connections to a forwarded TCP/IP port.
+ */
+/* ARGSUSED */
+static void
+channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       Channel *nc;
+       struct sockaddr_storage 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, (struct sockaddr *)&addr, &addrlen);
+               if (newsock < 0) {
+                       error("accept: %.100s", strerror(errno));
+                       return;
+               }
+               set_nodelay(newsock);
+               nc = channel_new(rtype, nextstate, newsock, newsock, -1,
+                   c->local_window_max, c->local_maxpacket, 0, rtype, 1);
+               nc->listening_port = c->listening_port;
+               nc->host_port = c->host_port;
+               if (c->path != NULL)
+                       nc->path = xstrdup(c->path);
+
+               if (nextstate != SSH_CHANNEL_DYNAMIC)
+                       port_open_helper(nc, rtype);
+       }
+}
+
+/*
+ * This is the authentication agent socket listening for connections from
+ * clients.
+ */
+/* ARGSUSED */
+static void
+channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       Channel *nc;
+       int newsock;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+
+       if (FD_ISSET(c->sock, readset)) {
+               addrlen = sizeof(addr);
+               newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
+               if (newsock < 0) {
+                       error("accept from auth socket: %.100s", strerror(errno));
+                       return;
+               }
+               nc = channel_new("accepted auth socket",
+                   SSH_CHANNEL_OPENING, newsock, newsock, -1,
+                   c->local_window_max, c->local_maxpacket,
+                   0, "accepted auth socket", 1);
+               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();
+       }
+}
+
+/* ARGSUSED */
+static void
+channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       int err = 0, sock;
+       socklen_t sz = sizeof(err);
+
+       if (FD_ISSET(c->sock, writeset)) {
+               if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {
+                       err = errno;
+                       error("getsockopt SO_ERROR failed");
+               }
+               if (err == 0) {
+                       debug("channel %d: connected to %s port %d",
+                           c->self, c->connect_ctx.host, c->connect_ctx.port);
+                       channel_connect_ctx_free(&c->connect_ctx);
+                       c->type = SSH_CHANNEL_OPEN;
+                       if (compat20) {
+                               packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
+                               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: connection failed: %s",
+                           c->self, strerror(err));
+                       /* Try next address, if any */
+                       if ((sock = connect_next(&c->connect_ctx)) > 0) {
+                               close(c->sock);
+                               c->sock = c->rfd = c->wfd = sock;
+                               channel_max_fd = channel_find_maxfd();
+                               return;
+                       }
+                       /* Exhausted all addresses */
+                       error("connect_to %.100s port %d: failed.",
+                           c->connect_ctx.host, c->connect_ctx.port);
+                       channel_connect_ctx_free(&c->connect_ctx);
+                       if (compat20) {
+                               packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
+                               packet_put_int(c->remote_id);
+                               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();
+       }
+}
+
+/* ARGSUSED */
+static int
+channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       char buf[CHAN_RBUF];
+       int len, force;
+
+       force = c->isatty && c->detach_close && c->istate != CHAN_INPUT_CLOSED;
+       if (c->rfd != -1 && (force || FD_ISSET(c->rfd, readset))) {
+               errno = 0;
+               len = read(c->rfd, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR ||
+                   ((errno == EAGAIN || errno == EWOULDBLOCK) && !force)))
+                       return 1;
+#ifndef PTY_ZEROREAD
+               if (len <= 0) {
+#else
+               if ((!c->isatty && len <= 0) ||
+                   (c->isatty && (len < 0 || (len == 0 && errno != 0)))) {
+#endif
+                       debug2("channel %d: read<=0 rfd %d len %d",
+                           c->self, c->rfd, len);
+                       if (c->type != SSH_CHANNEL_OPEN) {
+                               debug2("channel %d: not open", c->self);
+                               chan_mark_dead(c);
+                               return -1;
+                       } else if (compat13) {
+                               buffer_clear(&c->output);
+                               c->type = SSH_CHANNEL_INPUT_DRAINING;
+                               debug2("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) {
+                               debug2("channel %d: filter stops", c->self);
+                               chan_read_failed(c);
+                       }
+               } else if (c->datagram) {
+                       buffer_put_string(&c->input, buf, len);
+               } else {
+                       buffer_append(&c->input, buf, len);
+               }
+       }
+       return 1;
+}
+
+/* ARGSUSED */
+static int
+channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       struct termios tio;
+       u_char *data = NULL, *buf;
+       u_int dlen, olen = 0;
+       int len;
+
+       /* Send buffered output data to the socket. */
+       if (c->wfd != -1 &&
+           FD_ISSET(c->wfd, writeset) &&
+           buffer_len(&c->output) > 0) {
+               olen = buffer_len(&c->output);
+               if (c->output_filter != NULL) {
+                       if ((buf = c->output_filter(c, &data, &dlen)) == NULL) {
+                               debug2("channel %d: filter stops", c->self);
+                               if (c->type != SSH_CHANNEL_OPEN)
+                                       chan_mark_dead(c);
+                               else
+                                       chan_write_failed(c);
+                               return -1;
+                       }
+               } else if (c->datagram) {
+                       buf = data = buffer_get_string(&c->output, &dlen);
+               } else {
+                       buf = data = buffer_ptr(&c->output);
+                       dlen = buffer_len(&c->output);
+               }
+
+               if (c->datagram) {
+                       /* ignore truncated writes, datagrams might get lost */
+                       len = write(c->wfd, buf, dlen);
+                       xfree(data);
+                       if (len < 0 && (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK))
+                               return 1;
+                       if (len <= 0) {
+                               if (c->type != SSH_CHANNEL_OPEN)
+                                       chan_mark_dead(c);
+                               else
+                                       chan_write_failed(c);
+                               return -1;
+                       }
+                       goto out;
+               }
+#ifdef _AIX
+               /* XXX: Later AIX versions can't push as much data to tty */
+               if (compat20 && c->wfd_isatty)
+                       dlen = MIN(dlen, 8*1024);
+#endif
+
+               len = write(c->wfd, buf, dlen);
+               if (len < 0 &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
+                       return 1;
+               if (len <= 0) {
+                       if (c->type != SSH_CHANNEL_OPEN) {
+                               debug2("channel %d: not open", c->self);
+                               chan_mark_dead(c);
+                               return -1;
+                       } else if (compat13) {
+                               buffer_clear(&c->output);
+                               debug2("channel %d: input draining.", c->self);
+                               c->type = SSH_CHANNEL_INPUT_DRAINING;
+                       } else {
+                               chan_write_failed(c);
+                       }
+                       return -1;
+               }
+#ifndef BROKEN_TCGETATTR_ICANON
+               if (compat20 && c->isatty && dlen >= 1 && buf[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 + buf)
+                                */
+                               packet_send_ignore(4 + len);
+                               packet_send();
+                       }
+               }
+#endif
+               buffer_consume(&c->output, len);
+       }
+ out:
+       if (compat20 && olen > 0)
+               c->local_consumed += olen - buffer_len(&c->output);
+       return 1;
+}
+
+static int
+channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       char buf[CHAN_RBUF];
+       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 ||
+                           errno == EWOULDBLOCK))
+                               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->efd != -1 &&
+                   (c->extended_usage == CHAN_EXTENDED_READ ||
+                   c->extended_usage == CHAN_EXTENDED_IGNORE) &&
+                   (c->detach_close || 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 ||
+                           errno == EWOULDBLOCK) && !c->detach_close)))
+                               return 1;
+                       if (len <= 0) {
+                               debug2("channel %d: closing read-efd %d",
+                                   c->self, c->efd);
+                               channel_close_fd(&c->efd);
+                       } else {
+                               if (c->extended_usage == CHAN_EXTENDED_IGNORE) {
+                                       debug3("channel %d: discard efd",
+                                           c->self);
+                               } 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_max - c->local_window >
+           c->local_maxpacket*3) ||
+           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(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       channel_handle_rfd(c, readset, writeset);
+       channel_handle_wfd(c, readset, writeset);
+       if (!compat20)
+               return;
+       channel_handle_efd(c, readset, writeset);
+       channel_check_window(c);
+}
+
+static u_int
+read_mux(Channel *c, u_int need)
+{
+       char buf[CHAN_RBUF];
+       int len;
+       u_int rlen;
+
+       if (buffer_len(&c->input) < need) {
+               rlen = need - buffer_len(&c->input);
+               len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF));
+               if (len <= 0) {
+                       if (errno != EINTR && errno != EAGAIN) {
+                               debug2("channel %d: ctl read<=0 rfd %d len %d",
+                                   c->self, c->rfd, len);
+                               chan_read_failed(c);
+                               return 0;
+                       }
+               } else
+                       buffer_append(&c->input, buf, len);
+       }
+       return buffer_len(&c->input);
+}
+
+static void
+channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       u_int need;
+       ssize_t len;
+
+       if (!compat20)
+               fatal("%s: entered with !compat20", __func__);
+
+       if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
+           (c->istate == CHAN_INPUT_OPEN ||
+           c->istate == CHAN_INPUT_WAIT_DRAIN)) {
+               /*
+                * Don't not read past the precise end of packets to
+                * avoid disrupting fd passing.
+                */
+               if (read_mux(c, 4) < 4) /* read header */
+                       return;
+               need = get_u32(buffer_ptr(&c->input));
+#define CHANNEL_MUX_MAX_PACKET (256 * 1024)
+               if (need > CHANNEL_MUX_MAX_PACKET) {
+                       debug2("channel %d: packet too big %u > %u",
+                           c->self, CHANNEL_MUX_MAX_PACKET, need);
+                       chan_rcvd_oclose(c);
+                       return;
+               }
+               if (read_mux(c, need + 4) < need + 4) /* read body */
+                       return;
+               if (c->mux_rcb(c) != 0) {
+                       debug("channel %d: mux_rcb failed", c->self);
+                       chan_mark_dead(c);
+                       return;
+               }
+       }
+
+       if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) &&
+           buffer_len(&c->output) > 0) {
+               len = write(c->wfd, buffer_ptr(&c->output),
+                   buffer_len(&c->output));
+               if (len < 0 && (errno == EINTR || errno == EAGAIN))
+                       return;
+               if (len <= 0) {
+                       chan_mark_dead(c);
+                       return;
+               }
+               buffer_consume(&c->output, len);
+       }
+}
+
+static void
+channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
+{
+       Channel *nc;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int newsock;
+       uid_t euid;
+       gid_t egid;
+
+       if (!FD_ISSET(c->sock, readset))
+               return;
+
+       debug("multiplexing control connection");
+
+       /*
+        * Accept connection on control socket
+        */
+       memset(&addr, 0, sizeof(addr));
+       addrlen = sizeof(addr);
+       if ((newsock = accept(c->sock, (struct sockaddr*)&addr,
+           &addrlen)) == -1) {
+               error("%s accept: %s", __func__, strerror(errno));
+               return;
+       }
+
+       if (getpeereid(newsock, &euid, &egid) < 0) {
+               error("%s getpeereid failed: %s", __func__,
+                   strerror(errno));
+               close(newsock);
+               return;
+       }
+       if ((euid != 0) && (getuid() != euid)) {
+               error("multiplex uid mismatch: peer euid %u != uid %u",
+                   (u_int)euid, (u_int)getuid());
+               close(newsock);
+               return;
+       }
+       nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT,
+           newsock, newsock, -1, c->local_window_max,
+           c->local_maxpacket, 0, "mux-control", 1);
+       nc->mux_rcb = c->mux_rcb;
+       debug3("%s: new mux channel %d fd %d", __func__,
+           nc->self, nc->sock);
+       /* establish state */
+       nc->mux_rcb(nc);
+       /* mux state transitions must not elicit protocol messages */
+       nc->flags |= CHAN_LOCAL;
+}
+
+/* ARGSUSED */
+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_clear(&c->output);
+               else
+                       buffer_consume(&c->output, len);
+       }
+}
+
+static void
+channel_handler_init_20(void)
+{
+       channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open;
+       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_pre[SSH_CHANNEL_MUX_LISTENER] =         &channel_pre_listener;
+       channel_pre[SSH_CHANNEL_MUX_CLIENT] =           &channel_pre_mux_client;
+
+       channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open;
+       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;
+       channel_post[SSH_CHANNEL_MUX_LISTENER] =        &channel_post_mux_listener;
+       channel_post[SSH_CHANNEL_MUX_CLIENT] =          &channel_post_mux_client;
+}
+
+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;
+       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;
+}
+
+static void
+channel_handler_init_15(void)
+{
+       channel_pre[SSH_CHANNEL_OPEN] =                 &channel_pre_open;
+       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;
+       channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_open;
+}
+
+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, c->detach_close))
+                       return;
+               debug2("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;
+               debug2("channel %d: gc: user detached", c->self);
+       }
+       if (!chan_is_dead(c, 1))
+               return;
+       debug2("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;
+       u_int i, oalloc;
+       Channel *c;
+
+       if (!did_init) {
+               channel_handler_init();
+               did_init = 1;
+       }
+       for (i = 0, oalloc = channels_alloc; i < oalloc; i++) {
+               c = channels[i];
+               if (c == NULL)
+                       continue;
+               if (c->delayed) {
+                       if (ftab == channel_pre)
+                               c->delayed = 0;
+                       else
+                               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,
+    u_int *nallocp, int rekeying)
+{
+       u_int n, sz, nfdset;
+
+       n = MAX(*maxfdp, channel_max_fd);
+
+       nfdset = howmany(n+1, NFDBITS);
+       /* Explicitly test here, because xrealloc isn't always called */
+       if (nfdset && SIZE_T_MAX / nfdset < sizeof(fd_mask))
+               fatal("channel_prepare_select: max_fd (%d) is too large", n);
+       sz = nfdset * sizeof(fd_mask);
+
+       /* perhaps check sz < nalloc/2 and shrink? */
+       if (*readsetp == NULL || sz > *nallocp) {
+               *readsetp = xrealloc(*readsetp, nfdset, sizeof(fd_mask));
+               *writesetp = xrealloc(*writesetp, nfdset, sizeof(fd_mask));
+               *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(void)
+{
+       Channel *c;
+       u_int i, len;
+
+       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) {
+                       if (c->datagram) {
+                               if (len > 0) {
+                                       u_char *data;
+                                       u_int dlen;
+
+                                       data = buffer_get_string(&c->input,
+                                           &dlen);
+                                       if (dlen > c->remote_window ||
+                                           dlen > c->remote_maxpacket) {
+                                               debug("channel %d: datagram "
+                                                   "too big for channel",
+                                                   c->self);
+                                               xfree(data);
+                                               continue;
+                                       }
+                                       packet_start(SSH2_MSG_CHANNEL_DATA);
+                                       packet_put_int(c->remote_id);
+                                       packet_put_string(data, dlen);
+                                       packet_send();
+                                       c->remote_window -= dlen + 4;
+                                       xfree(data);
+                               }
+                               continue;
+                       }
+                       /*
+                        * 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.
+                        * hack for extended data: delay EOF if EFD still in use.
+                        */
+                       if (CHANNEL_EFD_INPUT_ACTIVE(c))
+                               debug2("channel %d: ibuf_empty delayed efd %d/(%d)",
+                                   c->self, c->efd, buffer_len(&c->extended));
+                       else
+                               chan_ibuf_empty(c);
+               }
+               /* Send extended data, i.e. stderr */
+               if (compat20 &&
+                   !(c->flags & CHAN_EOF_SENT) &&
+                   c->remote_window > 0 &&
+                   (len = buffer_len(&c->extended)) > 0 &&
+                   c->extended_usage == CHAN_EXTENDED_READ) {
+                       debug2("channel %d: rwin %u elen %u 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 */
+
+/* ARGSUSED */
+void
+channel_input_data(int type, u_int32_t seq, void *ctxt)
+{
+       int id;
+       char *data;
+       u_int data_len, win_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;
+
+       /* Get the data. */
+       data = packet_get_string_ptr(&data_len);
+       win_len = data_len;
+       if (c->datagram)
+               win_len += 4;  /* string length header */
+
+       /*
+        * Ignore data for protocol > 1.3 if output end is no longer open.
+        * For protocol 2 the sending side is reducing its window as it sends
+        * data, so we must 'fake' consumption of the data in order to ensure
+        * that window updates are sent back.  Otherwise the connection might
+        * deadlock.
+        */
+       if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
+               if (compat20) {
+                       c->local_window -= win_len;
+                       c->local_consumed += win_len;
+               }
+               return;
+       }
+
+       if (compat20) {
+               if (win_len > c->local_maxpacket) {
+                       logit("channel %d: rcvd big packet %d, maxpack %d",
+                           c->self, win_len, c->local_maxpacket);
+               }
+               if (win_len > c->local_window) {
+                       logit("channel %d: rcvd too much data %d, win %d",
+                           c->self, win_len, c->local_window);
+                       return;
+               }
+               c->local_window -= win_len;
+       }
+       if (c->datagram)
+               buffer_put_string(&c->output, data, data_len);
+       else
+               buffer_append(&c->output, data, data_len);
+       packet_check_eom();
+}
+
+/* ARGSUSED */
+void
+channel_input_extended_data(int type, u_int32_t seq, void *ctxt)
+{
+       int id;
+       char *data;
+       u_int data_len, tcode;
+       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) {
+               logit("channel %d: ext data for non open", id);
+               return;
+       }
+       if (c->flags & CHAN_EOF_RCVD) {
+               if (datafellows & SSH_BUG_EXTEOF)
+                       debug("channel %d: accepting ext data after eof", id);
+               else
+                       packet_disconnect("Received extended_data after EOF "
+                           "on channel %d.", id);
+       }
+       tcode = packet_get_int();
+       if (c->efd == -1 ||
+           c->extended_usage != CHAN_EXTENDED_WRITE ||
+           tcode != SSH2_EXTENDED_DATA_STDERR) {
+               logit("channel %d: bad ext data", c->self);
+               return;
+       }
+       data = packet_get_string(&data_len);
+       packet_check_eom();
+       if (data_len > c->local_window) {
+               logit("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);
+}
+
+/* ARGSUSED */
+void
+channel_input_ieof(int type, u_int32_t seq, void *ctxt)
+{
+       int id;
+       Channel *c;
+
+       id = packet_get_int();
+       packet_check_eom();
+       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 && c->istate == CHAN_INPUT_OPEN) {
+               debug("channel %d: FORCE input drain", c->self);
+               c->istate = CHAN_INPUT_WAIT_DRAIN;
+               if (buffer_len(&c->input) == 0)
+                       chan_ibuf_empty(c);
+       }
+
+}
+
+/* ARGSUSED */
+void
+channel_input_close(int type, u_int32_t seq, void *ctxt)
+{
+       int id;
+       Channel *c;
+
+       id = packet_get_int();
+       packet_check_eom();
+       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_clear(&c->input);
+               c->type = SSH_CHANNEL_OUTPUT_DRAINING;
+       }
+}
+
+/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */
+/* ARGSUSED */
+void
+channel_input_oclose(int type, u_int32_t seq, void *ctxt)
+{
+       int id = packet_get_int();
+       Channel *c = channel_lookup(id);
+
+       packet_check_eom();
+       if (c == NULL)
+               packet_disconnect("Received oclose for nonexistent channel %d.", id);
+       chan_rcvd_oclose(c);
+}
+
+/* ARGSUSED */
+void
+channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt)
+{
+       int id = packet_get_int();
+       Channel *c = channel_lookup(id);
+
+       packet_check_eom();
+       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);
+}
+
+/* ARGSUSED */
+void
+channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
+{
+       int id, remote_id;
+       Channel *c;
+
+       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();
+               if (c->open_confirm) {
+                       debug2("callback start");
+                       c->open_confirm(c->self, 1, c->open_confirm_ctx);
+                       debug2("callback done");
+               }
+               debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
+                   c->remote_window, c->remote_maxpacket);
+       }
+       packet_check_eom();
+}
+
+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";
+}
+
+/* ARGSUSED */
+void
+channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
+{
+       int id, reason;
+       char *msg = NULL, *lang = NULL;
+       Channel *c;
+
+       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);
+               }
+               logit("channel %d: open failed: %s%s%s", id,
+                   reason2txt(reason), msg ? ": ": "", msg ? msg : "");
+               if (msg != NULL)
+                       xfree(msg);
+               if (lang != NULL)
+                       xfree(lang);
+               if (c->open_confirm) {
+                       debug2("callback start");
+                       c->open_confirm(c->self, 0, c->open_confirm_ctx);
+                       debug2("callback done");
+               }
+       }
+       packet_check_eom();
+       /* Schedule the channel for cleanup/deletion. */
+       chan_mark_dead(c);
+}
+
+/* ARGSUSED */
+void
+channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c;
+       int id;
+       u_int adjust;
+
+       if (!compat20)
+               return;
+
+       /* Get the channel number and verify it. */
+       id = packet_get_int();
+       c = channel_lookup(id);
+
+       if (c == NULL) {
+               logit("Received window adjust for non-open channel %d.", id);
+               return;
+       }
+       adjust = packet_get_int();
+       packet_check_eom();
+       debug2("channel %d: rcvd adjust %u", id, adjust);
+       c->remote_window += adjust;
+}
+
+/* ARGSUSED */
+void
+channel_input_port_open(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c = NULL;
+       u_short host_port;
+       char *host, *originator_string;
+       int remote_id;
+
+       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_check_eom();
+       c = channel_connect_to(host, host_port,
+           "connected socket", originator_string);
+       xfree(originator_string);
+       xfree(host);
+       if (c == NULL) {
+               packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+               packet_put_int(remote_id);
+               packet_send();
+       } else
+               c->remote_id = remote_id;
+}
+
+/* ARGSUSED */
+void
+channel_input_status_confirm(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c;
+       struct channel_confirm *cc;
+       int id;
+
+       /* Reset keepalive timeout */
+       packet_set_alive_timeouts(0);
+
+       id = packet_get_int();
+       packet_check_eom();
+
+       debug2("channel_input_status_confirm: type %d id %d", type, id);
+
+       if ((c = channel_lookup(id)) == NULL) {
+               logit("channel_input_status_confirm: %d: unknown", id);
+               return;
+       }       
+       ;
+       if ((cc = TAILQ_FIRST(&c->status_confirms)) == NULL)
+               return;
+       cc->cb(type, c, cc->ctx);
+       TAILQ_REMOVE(&c->status_confirms, cc, entry);
+       bzero(cc, sizeof(*cc));
+       xfree(cc);
+}
+
+/* -- tcp forwarding */
+
+void
+channel_set_af(int af)
+{
+       IPv4or6 = af;
+}
+
+static int
+channel_setup_fwd_listener(int type, const char *listen_addr,
+    u_short listen_port, int *allocated_listen_port,
+    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+{
+       Channel *c;
+       int sock, r, success = 0, wildcard = 0, is_client;
+       struct addrinfo hints, *ai, *aitop;
+       const char *host, *addr;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+       in_port_t *lport_p;
+
+       host = (type == SSH_CHANNEL_RPORT_LISTENER) ?
+           listen_addr : host_to_connect;
+       is_client = (type == SSH_CHANNEL_PORT_LISTENER);
+
+       if (host == NULL) {
+               error("No forward host name.");
+               return 0;
+       }
+       if (strlen(host) >= NI_MAXHOST) {
+               error("Forward host name too long.");
+               return 0;
+       }
+
+       /*
+        * Determine whether or not a port forward listens to loopback,
+        * specified address or wildcard. On the client, a specified bind
+        * address will always override gateway_ports. On the server, a
+        * gateway_ports of 1 (``yes'') will override the client's
+        * specification and force a wildcard bind, whereas a value of 2
+        * (``clientspecified'') will bind to whatever address the client
+        * asked for.
+        *
+        * Special-case listen_addrs are:
+        *
+        * "0.0.0.0"               -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
+        * "" (empty string), "*"  -> wildcard v4/v6
+        * "localhost"             -> loopback v4/v6
+        */
+       addr = NULL;
+       if (listen_addr == NULL) {
+               /* No address specified: default to gateway_ports setting */
+               if (gateway_ports)
+                       wildcard = 1;
+       } else if (gateway_ports || is_client) {
+               if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
+                   strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
+                   *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
+                   (!is_client && gateway_ports == 1))
+                       wildcard = 1;
+               else if (strcmp(listen_addr, "localhost") != 0)
+                       addr = listen_addr;
+       }
+
+       debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
+           type, wildcard, (addr == NULL) ? "NULL" : addr);
+
+       /*
+        * 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 = wildcard ? AI_PASSIVE : 0;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", listen_port);
+       if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) {
+               if (addr == NULL) {
+                       /* This really shouldn't happen */
+                       packet_disconnect("getaddrinfo: fatal error: %s",
+                           ssh_gai_strerror(r));
+               } else {
+                       error("channel_setup_fwd_listener: "
+                           "getaddrinfo(%.64s): %s", addr,
+                           ssh_gai_strerror(r));
+               }
+               return 0;
+       }
+       if (allocated_listen_port != NULL)
+               *allocated_listen_port = 0;
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               switch (ai->ai_family) {
+               case AF_INET:
+                       lport_p = &((struct sockaddr_in *)ai->ai_addr)->
+                           sin_port;
+                       break;
+               case AF_INET6:
+                       lport_p = &((struct sockaddr_in6 *)ai->ai_addr)->
+                           sin6_port;
+                       break;
+               default:
+                       continue;
+               }
+               /*
+                * If allocating a port for -R forwards, then use the
+                * same port for all address families.
+                */
+               if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+                   allocated_listen_port != NULL && *allocated_listen_port > 0)
+                       *lport_p = htons(*allocated_listen_port);
+
+               if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
+                   strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                       error("channel_setup_fwd_listener: getnameinfo failed");
+                       continue;
+               }
+               /* Create a port to listen for the host. */
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) {
+                       /* this is no error since kernel may not support ipv6 */
+                       verbose("socket: %.100s", strerror(errno));
+                       continue;
+               }
+
+               channel_set_reuseaddr(sock);
+               if (ai->ai_family == AF_INET6)
+                       sock_set_v6only(sock);
+
+               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, SSH_LISTEN_BACKLOG) < 0) {
+                       error("listen: %.100s", strerror(errno));
+                       close(sock);
+                       continue;
+               }
+
+               /*
+                * listen_port == 0 requests a dynamically allocated port -
+                * record what we got.
+                */
+               if (type == SSH_CHANNEL_RPORT_LISTENER && listen_port == 0 &&
+                   allocated_listen_port != NULL &&
+                   *allocated_listen_port == 0) {
+                       *allocated_listen_port = get_sock_port(sock, 1);
+                       debug("Allocated listen port %d",
+                           *allocated_listen_port);
+               }
+
+               /* 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, "port listener", 1);
+               c->path = xstrdup(host);
+               c->host_port = port_to_connect;
+               c->listening_port = listen_port;
+               success = 1;
+       }
+       if (success == 0)
+               error("channel_setup_fwd_listener: cannot listen to port: %d",
+                   listen_port);
+       freeaddrinfo(aitop);
+       return success;
+}
+
+int
+channel_cancel_rport_listener(const char *host, u_short port)
+{
+       u_int i;
+       int found = 0;
+
+       for (i = 0; i < channels_alloc; i++) {
+               Channel *c = channels[i];
+
+               if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER &&
+                   strcmp(c->path, host) == 0 && c->listening_port == port) {
+                       debug2("%s: close channel %d", __func__, i);
+                       channel_free(c);
+                       found = 1;
+               }
+       }
+
+       return (found);
+}
+
+/* protocol local port fwd, used by ssh (and sshd in v1) */
+int
+channel_setup_local_fwd_listener(const char *listen_host, u_short listen_port,
+    const char *host_to_connect, u_short port_to_connect, int gateway_ports)
+{
+       return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER,
+           listen_host, listen_port, NULL, host_to_connect, port_to_connect,
+           gateway_ports);
+}
+
+/* protocol v2 remote port fwd, used by sshd */
+int
+channel_setup_remote_fwd_listener(const char *listen_address,
+    u_short listen_port, int *allocated_listen_port, int gateway_ports)
+{
+       return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER,
+           listen_address, listen_port, allocated_listen_port,
+           NULL, 0, gateway_ports);
+}
+
+/*
+ * Initiate forwarding of connections to port "port" on remote host through
+ * the secure channel to host:port from local side.
+ */
+
+int
+channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
+    const char *host_to_connect, u_short port_to_connect)
+{
+       int type, success = 0;
+
+       /* Send the forward request to the remote side. */
+       if (compat20) {
+               const char *address_to_bind;
+               if (listen_host == NULL) {
+                       if (datafellows & SSH_BUG_RFWD_ADDR)
+                               address_to_bind = "127.0.0.1";
+                       else
+                               address_to_bind = "localhost";
+               } else if (*listen_host == '\0' ||
+                          strcmp(listen_host, "*") == 0) {
+                       if (datafellows & SSH_BUG_RFWD_ADDR)
+                               address_to_bind = "0.0.0.0";
+                       else
+                               address_to_bind = "";
+               } else
+                       address_to_bind = listen_host;
+
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("tcpip-forward");
+               packet_put_char(1);                     /* 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();
+               switch (type) {
+               case SSH_SMSG_SUCCESS:
+                       success = 1;
+                       break;
+               case SSH_SMSG_FAILURE:
+                       break;
+               default:
+                       /* Unknown packet */
+                       packet_disconnect("Protocol error for port forward request:"
+                           "received packet type %d.", type);
+               }
+       }
+       if (success) {
+               /* Record that connection to this host/port is permitted. */
+               permitted_opens = xrealloc(permitted_opens,
+                   num_permitted_opens + 1, sizeof(*permitted_opens));
+               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++;
+       }
+       return (success ? 0 : -1);
+}
+
+/*
+ * Request cancellation of remote forwarding of connection host:port from
+ * local side.
+ */
+void
+channel_request_rforward_cancel(const char *host, u_short port)
+{
+       int i;
+
+       if (!compat20)
+               return;
+
+       for (i = 0; i < num_permitted_opens; i++) {
+               if (permitted_opens[i].host_to_connect != NULL &&
+                   permitted_opens[i].listen_port == port)
+                       break;
+       }
+       if (i >= num_permitted_opens) {
+               debug("%s: requested forward not found", __func__);
+               return;
+       }
+       packet_start(SSH2_MSG_GLOBAL_REQUEST);
+       packet_put_cstring("cancel-tcpip-forward");
+       packet_put_char(0);
+       packet_put_cstring(host == NULL ? "" : host);
+       packet_put_int(port);
+       packet_send();
+
+       permitted_opens[i].listen_port = 0;
+       permitted_opens[i].port_to_connect = 0;
+       xfree(permitted_opens[i].host_to_connect);
+       permitted_opens[i].host_to_connect = NULL;
+}
+
+/*
+ * 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).
+ */
+int
+channel_input_port_forward_request(int is_root, int gateway_ports)
+{
+       u_short port, host_port;
+       int success = 0;
+       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);
+       if (host_port == 0)
+               packet_disconnect("Dynamic forwarding denied.");
+#endif
+
+       /* Initiate forwarding */
+       success = channel_setup_local_fwd_listener(NULL, port, hostname,
+           host_port, gateway_ports);
+
+       /* Free the argument string. */
+       xfree(hostname);
+
+       return (success ? 0 : -1);
+}
+
+/*
+ * 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(void)
+{
+       if (num_permitted_opens == 0)
+               all_opens_permitted = 1;
+}
+
+void
+channel_add_permitted_opens(char *host, int port)
+{
+       debug("allow port forwarding to host %s port %d", host, port);
+
+       permitted_opens = xrealloc(permitted_opens,
+           num_permitted_opens + 1, sizeof(*permitted_opens));
+       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;
+}
+
+int
+channel_add_adm_permitted_opens(char *host, int port)
+{
+       debug("config allows port forwarding to host %s port %d", host, port);
+
+       permitted_adm_opens = xrealloc(permitted_adm_opens,
+           num_adm_permitted_opens + 1, sizeof(*permitted_adm_opens));
+       permitted_adm_opens[num_adm_permitted_opens].host_to_connect
+            = xstrdup(host);
+       permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port;
+       return ++num_adm_permitted_opens;
+}
+
+void
+channel_clear_permitted_opens(void)
+{
+       int i;
+
+       for (i = 0; i < num_permitted_opens; i++)
+               if (permitted_opens[i].host_to_connect != NULL)
+                       xfree(permitted_opens[i].host_to_connect);
+       if (num_permitted_opens > 0) {
+               xfree(permitted_opens);
+               permitted_opens = NULL;
+       }
+       num_permitted_opens = 0;
+}
+
+void
+channel_clear_adm_permitted_opens(void)
+{
+       int i;
+
+       for (i = 0; i < num_adm_permitted_opens; i++)
+               if (permitted_adm_opens[i].host_to_connect != NULL)
+                       xfree(permitted_adm_opens[i].host_to_connect);
+       if (num_adm_permitted_opens > 0) {
+               xfree(permitted_adm_opens);
+               permitted_adm_opens = NULL;
+       }
+       num_adm_permitted_opens = 0;
+}
+
+void
+channel_print_adm_permitted_opens(void)
+{
+       int i;
+
+       printf("permitopen");
+       if (num_adm_permitted_opens == 0) {
+               printf(" any\n");
+               return;
+       }
+       for (i = 0; i < num_adm_permitted_opens; i++)
+               if (permitted_adm_opens[i].host_to_connect != NULL)
+                       printf(" %s:%d", permitted_adm_opens[i].host_to_connect,
+                           permitted_adm_opens[i].port_to_connect);
+       printf("\n");
+}
+
+/* Try to start non-blocking connect to next host in cctx list */
+static int
+connect_next(struct channel_connect *cctx)
+{
+       int sock, saved_errno;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+
+       for (; cctx->ai; cctx->ai = cctx->ai->ai_next) {
+               if (cctx->ai->ai_family != AF_INET &&
+                   cctx->ai->ai_family != AF_INET6)
+                       continue;
+               if (getnameinfo(cctx->ai->ai_addr, cctx->ai->ai_addrlen,
+                   ntop, sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
+                       error("connect_next: getnameinfo failed");
+                       continue;
+               }
+               if ((sock = socket(cctx->ai->ai_family, cctx->ai->ai_socktype,
+                   cctx->ai->ai_protocol)) == -1) {
+                       if (cctx->ai->ai_next == NULL)
+                               error("socket: %.100s", strerror(errno));
+                       else
+                               verbose("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               if (set_nonblock(sock) == -1)
+                       fatal("%s: set_nonblock(%d)", __func__, sock);
+               if (connect(sock, cctx->ai->ai_addr,
+                   cctx->ai->ai_addrlen) == -1 && errno != EINPROGRESS) {
+                       debug("connect_next: host %.100s ([%.100s]:%s): "
+                           "%.100s", cctx->host, ntop, strport,
+                           strerror(errno));
+                       saved_errno = errno;
+                       close(sock);
+                       errno = saved_errno;
+                       continue;       /* fail -- try next */
+               }
+               debug("connect_next: host %.100s ([%.100s]:%s) "
+                   "in progress, fd=%d", cctx->host, ntop, strport, sock);
+               cctx->ai = cctx->ai->ai_next;
+               set_nodelay(sock);
+               return sock;
+       }
+       return -1;
+}
+
+static void
+channel_connect_ctx_free(struct channel_connect *cctx)
+{
+       xfree(cctx->host);
+       if (cctx->aitop)
+               freeaddrinfo(cctx->aitop);
+       bzero(cctx, sizeof(*cctx));
+       cctx->host = NULL;
+       cctx->ai = cctx->aitop = NULL;
+}
+
+/* Return CONNECTING channel to remote host, port */
+static Channel *
+connect_to(const char *host, u_short port, char *ctype, char *rname)
+{
+       struct addrinfo hints;
+       int gaierr;
+       int sock = -1;
+       char strport[NI_MAXSERV];
+       struct channel_connect cctx;
+       Channel *c;
+
+       memset(&cctx, 0, sizeof(cctx));
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = IPv4or6;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%d", port);
+       if ((gaierr = getaddrinfo(host, strport, &hints, &cctx.aitop)) != 0) {
+               error("connect_to %.100s: unknown host (%s)", host,
+                   ssh_gai_strerror(gaierr));
+               return NULL;
+       }
+
+       cctx.host = xstrdup(host);
+       cctx.port = port;
+       cctx.ai = cctx.aitop;
+
+       if ((sock = connect_next(&cctx)) == -1) {
+               error("connect to %.100s port %d failed: %s",
+                   host, port, strerror(errno));
+               channel_connect_ctx_free(&cctx);
+               return NULL;
+       }
+       c = channel_new(ctype, SSH_CHANNEL_CONNECTING, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, rname, 1);
+       c->connect_ctx = cctx;
+       return c;
+}
+
+Channel *
+channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
+{
+       int i;
+
+       for (i = 0; i < num_permitted_opens; i++) {
+               if (permitted_opens[i].host_to_connect != NULL &&
+                   permitted_opens[i].listen_port == listen_port) {
+                       return connect_to(
+                           permitted_opens[i].host_to_connect,
+                           permitted_opens[i].port_to_connect, ctype, rname);
+               }
+       }
+       error("WARNING: Server requests forwarding for unknown listen_port %d",
+           listen_port);
+       return NULL;
+}
+
+/* Check if connecting to that port is permitted and connect. */
+Channel *
+channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
+{
+       int i, permit, permit_adm = 1;
+
+       permit = all_opens_permitted;
+       if (!permit) {
+               for (i = 0; i < num_permitted_opens; i++)
+                       if (permitted_opens[i].host_to_connect != NULL &&
+                           permitted_opens[i].port_to_connect == port &&
+                           strcmp(permitted_opens[i].host_to_connect, host) == 0)
+                               permit = 1;
+       }
+
+       if (num_adm_permitted_opens > 0) {
+               permit_adm = 0;
+               for (i = 0; i < num_adm_permitted_opens; i++)
+                       if (permitted_adm_opens[i].host_to_connect != NULL &&
+                           permitted_adm_opens[i].port_to_connect == port &&
+                           strcmp(permitted_adm_opens[i].host_to_connect, host)
+                           == 0)
+                               permit_adm = 1;
+       }
+
+       if (!permit || !permit_adm) {
+               logit("Received request to connect to host %.100s port %d, "
+                   "but the request was denied.", host, port);
+               return NULL;
+       }
+       return connect_to(host, port, ctype, rname);
+}
+
+void
+channel_send_window_changes(void)
+{
+       u_int i;
+       struct winsize ws;
+
+       for (i = 0; i < channels_alloc; i++) {
+               if (channels[i] == NULL || !channels[i]->client_tty ||
+                   channels[i]->type != SSH_CHANNEL_OPEN)
+                       continue;
+               if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0)
+                       continue;
+               channel_request_start(i, "window-change", 0);
+               packet_put_int((u_int)ws.ws_col);
+               packet_put_int((u_int)ws.ws_row);
+               packet_put_int((u_int)ws.ws_xpixel);
+               packet_put_int((u_int)ws.ws_ypixel);
+               packet_send();
+       }
+}
+
+/* -- X11 forwarding */
+
+/*
+ * Creates an internet domain socket for listening for X11 connections.
+ * Returns 0 and a suitable display number for the DISPLAY variable
+ * stored in display_numberp , or -1 if an error occurs.
+ */
+int
+x11_create_display_inet(int x11_display_offset, int x11_use_localhost,
+    int single_connection, u_int *display_numberp, int **chanids)
+{
+       Channel *nc = NULL;
+       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];
+
+       if (chanids == NULL)
+               return -1;
+
+       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 = x11_use_localhost ? 0: AI_PASSIVE;
+               hints.ai_socktype = SOCK_STREAM;
+               snprintf(strport, sizeof strport, "%d", port);
+               if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) {
+                       error("getaddrinfo: %.100s", ssh_gai_strerror(gaierr));
+                       return -1;
+               }
+               for (ai = aitop; ai; ai = ai->ai_next) {
+                       if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                               continue;
+                       sock = socket(ai->ai_family, ai->ai_socktype,
+                           ai->ai_protocol);
+                       if (sock < 0) {
+                               if ((errno != EINVAL) && (errno != EAFNOSUPPORT)
+#ifdef EPFNOSUPPORT
+                                   && (errno != EPFNOSUPPORT)
+#endif 
+                                   ) {
+                                       error("socket: %.100s", strerror(errno));
+                                       freeaddrinfo(aitop);
+                                       return -1;
+                               } else {
+                                       debug("x11_create_display_inet: Socket family %d not supported",
+                                                ai->ai_family);
+                                       continue;
+                               }
+                       }
+                       if (ai->ai_family == AF_INET6)
+                               sock_set_v6only(sock);
+                       if (x11_use_localhost)
+                               channel_set_reuseaddr(sock);
+                       if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                               debug2("bind port %d: %.100s", port, strerror(errno));
+                               close(sock);
+
+                               for (n = 0; n < num_socks; n++) {
+                                       close(socks[n]);
+                               }
+                               num_socks = 0;
+                               break;
+                       }
+                       socks[num_socks++] = sock;
+                       if (num_socks == NUM_SOCKS)
+                               break;
+               }
+               freeaddrinfo(aitop);
+               if (num_socks > 0)
+                       break;
+       }
+       if (display_number >= MAX_DISPLAYS) {
+               error("Failed to allocate internet-domain X11 display socket.");
+               return -1;
+       }
+       /* Start listening for connections on the socket. */
+       for (n = 0; n < num_socks; n++) {
+               sock = socks[n];
+               if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
+                       error("listen: %.100s", strerror(errno));
+                       close(sock);
+                       return -1;
+               }
+       }
+
+       /* Allocate a channel for each socket. */
+       *chanids = xcalloc(num_socks + 1, sizeof(**chanids));
+       for (n = 0; n < num_socks; n++) {
+               sock = socks[n];
+               nc = channel_new("x11 listener",
+                   SSH_CHANNEL_X11_LISTENER, sock, sock, -1,
+                   CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
+                   0, "X11 inet listener", 1);
+               nc->single_connection = single_connection;
+               (*chanids)[n] = nc->self;
+       }
+       (*chanids)[n] = -1;
+
+       /* Return the display number for the DISPLAY environment variable. */
+       *display_numberp = display_number;
+       return (0);
+}
+
+static int
+connect_local_xsocket_path(const char *pathname)
+{
+       int sock;
+       struct sockaddr_un addr;
+
+       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;
+       strlcpy(addr.sun_path, pathname, sizeof addr.sun_path);
+       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0)
+               return sock;
+       close(sock);
+       error("connect %.100s: %.100s", addr.sun_path, strerror(errno));
+       return -1;
+}
+
+static int
+connect_local_xsocket(u_int dnr)
+{
+       char buf[1024];
+       snprintf(buf, sizeof buf, _PATH_UNIX_X, dnr);
+       return connect_local_xsocket_path(buf);
+}
+
+int
+x11_connect_display(void)
+{
+       u_int display_number;
+       const char *display;
+       char buf[1024], *cp;
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr, sock = 0;
+
+       /* 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 the display is from launchd. */
+#ifdef __APPLE__
+       if (strncmp(display, "/tmp/launch", 11) == 0) {
+               sock = connect_local_xsocket_path(display);
+               if (sock < 0)
+                       return -1;
+
+               /* OK, we now have a connection to the display. */
+               return sock;
+       }
+#endif
+       /*
+        * 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, "%u", &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.
+        */
+       strlcpy(buf, display, sizeof(buf));
+       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, "%u", &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, "%u", 6000 + display_number);
+       if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) {
+               error("%.100s: unknown host. (%s)", buf,
+               ssh_gai_strerror(gaierr));
+               return -1;
+       }
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               /* Create a socket. */
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) {
+                       debug2("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               /* Connect it to the display. */
+               if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       debug2("connect %.100s port %u: %.100s", buf,
+                           6000 + display_number, strerror(errno));
+                       close(sock);
+                       continue;
+               }
+               /* Success */
+               break;
+       }
+       freeaddrinfo(aitop);
+       if (!ai) {
+               error("connect %.100s port %u: %.100s", buf, 6000 + display_number,
+                   strerror(errno));
+               return -1;
+       }
+       set_nodelay(sock);
+       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.
+ */
+
+/* ARGSUSED */
+void
+x11_input_open(int type, u_int32_t seq, 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_check_eom();
+
+       /* 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);
+               c->remote_id = remote_id;
+               c->force_drain = 1;
+       }
+       xfree(remote_host);
+       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) */
+/* ARGSUSED */
+void
+deny_input_open(int type, u_int32_t seq, 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", type);
+               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 *disp,
+    const char *proto, const char *data)
+{
+       u_int data_len = (u_int) strlen(data) / 2;
+       u_int i, value;
+       char *new_data;
+       int screen_number;
+       const char *cp;
+       u_int32_t rnd = 0;
+
+       if (x11_saved_display == NULL)
+               x11_saved_display = xstrdup(disp);
+       else if (strcmp(disp, x11_saved_display) != 0) {
+               error("x11_request_forwarding_with_spoofing: different "
+                   "$DISPLAY already forwarded");
+               return;
+       }
+
+       cp = strchr(disp, ':');
+       if (cp)
+               cp = strchr(cp, '.');
+       if (cp)
+               screen_number = (u_int)strtonum(cp + 1, 0, 400, NULL);
+       else
+               screen_number = 0;
+
+       if (x11_saved_proto == NULL) {
+               /* 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)
+                               rnd = arc4random();
+                       x11_saved_data[i] = value;
+                       x11_fake_data[i] = rnd & 0xff;
+                       rnd >>= 8;
+               }
+               x11_saved_data_len = data_len;
+               x11_fake_data_len = data_len;
+       }
+
+       /* Convert the fake data into hex. */
+       new_data = tohex(x11_fake_data, data_len);
+
+       /* 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(void)
+{
+       packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING);
+       packet_send();
+       packet_write_wait();
+}
diff --git a/channels.h b/channels.h
new file mode 100644 (file)
index 0000000..0680ed0
--- /dev/null
@@ -0,0 +1,297 @@
+/* $OpenBSD: channels.h,v 1.104 2010/05/14 23:29:23 djm 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, 2001, 2002 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 CHANNEL_H
+#define CHANNEL_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_MUX_LISTENER       15      /* Listener for mux conn. */
+#define SSH_CHANNEL_MUX_CLIENT         16      /* Conn. to mux slave */
+#define SSH_CHANNEL_MAX_TYPE           17
+
+struct Channel;
+typedef struct Channel Channel;
+
+typedef void channel_open_fn(int, int, void *);
+typedef void channel_callback_fn(int, void *);
+typedef int channel_infilter_fn(struct Channel *, char *, int);
+typedef void channel_filter_cleanup_fn(int, void *);
+typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
+
+/* Channel success/failure callbacks */
+typedef void channel_confirm_cb(int, struct Channel *, void *);
+typedef void channel_confirm_abandon_cb(struct Channel *, void *);
+struct channel_confirm {
+       TAILQ_ENTRY(channel_confirm) entry;
+       channel_confirm_cb *cb;
+       channel_confirm_abandon_cb *abandon_cb;
+       void *ctx;
+};
+TAILQ_HEAD(channel_confirms, channel_confirm);
+
+/* Context for non-blocking connects */
+struct channel_connect {
+       char *host;
+       int port;
+       struct addrinfo *ai, *aitop;
+};
+
+/* Callbacks for mux channels back into client-specific code */
+typedef int mux_callback_fn(struct Channel *);
+
+struct Channel {
+       int     type;           /* channel type/state */
+       int     self;           /* my own channel identifier */
+       int     remote_id;      /* channel identifier for remote peer */
+       u_int   istate;         /* input from channel (state of receive half) */
+       u_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     ctl_chan;       /* control channel (multiplexed connections) */
+       int     isatty;         /* rfd is a tty */
+       int     wfd_isatty;     /* wfd is a tty */
+       int     client_tty;     /* (client) TTY has been requested */
+       int     force_drain;    /* force close on iEOF */
+       int     delayed;        /* post-select handlers for newly created
+                                * channels are delayed until the first call
+                                * to a matching pre-select handler. 
+                                * this way post-select handlers are not
+                                * accidenly called if a FD gets reused */
+       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;
+               /* 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 */
+
+       u_int   remote_window;
+       u_int   remote_maxpacket;
+       u_int   local_window;
+       u_int   local_window_max;
+       u_int   local_consumed;
+       u_int   local_maxpacket;
+       int     extended_usage;
+       int     single_connection;
+
+       char   *ctype;          /* type */
+
+       /* callback */
+       channel_open_fn         *open_confirm;
+       void                    *open_confirm_ctx;
+       channel_callback_fn     *detach_user;
+       int                     detach_close;
+       struct channel_confirms status_confirms;
+
+       /* filter */
+       channel_infilter_fn     *input_filter;
+       channel_outfilter_fn    *output_filter;
+       void                    *filter_ctx;
+       channel_filter_cleanup_fn *filter_cleanup;
+
+       /* keep boundaries */
+       int                     datagram;
+
+       /* non-blocking connect */
+       struct channel_connect  connect_ctx;
+
+       /* multiplexing protocol hook, called for each packet received */
+       mux_callback_fn         *mux_rcb;
+       void                    *mux_ctx;
+       int                     mux_pause;
+};
+
+#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_PACKET_DEFAULT        (32*1024)
+#define CHAN_SES_WINDOW_DEFAULT        (64*CHAN_SES_PACKET_DEFAULT)
+#define CHAN_TCP_PACKET_DEFAULT        (32*1024)
+#define CHAN_TCP_WINDOW_DEFAULT        (64*CHAN_TCP_PACKET_DEFAULT)
+#define CHAN_X11_PACKET_DEFAULT        (16*1024)
+#define CHAN_X11_WINDOW_DEFAULT        (4*CHAN_X11_PACKET_DEFAULT)
+
+/* possible input states */
+#define CHAN_INPUT_OPEN                        0
+#define CHAN_INPUT_WAIT_DRAIN          1
+#define CHAN_INPUT_WAIT_OCLOSE         2
+#define CHAN_INPUT_CLOSED              3
+
+/* possible output states */
+#define CHAN_OUTPUT_OPEN               0
+#define CHAN_OUTPUT_WAIT_DRAIN         1
+#define CHAN_OUTPUT_WAIT_IEOF          2
+#define CHAN_OUTPUT_CLOSED             3
+
+#define CHAN_CLOSE_SENT                        0x01
+#define CHAN_CLOSE_RCVD                        0x02
+#define CHAN_EOF_SENT                  0x04
+#define CHAN_EOF_RCVD                  0x08
+#define CHAN_LOCAL                     0x10
+
+#define CHAN_RBUF      16*1024
+
+/* check whether 'efd' is still in use */
+#define CHANNEL_EFD_INPUT_ACTIVE(c) \
+       (compat20 && c->extended_usage == CHAN_EXTENDED_READ && \
+       (c->efd != -1 || \
+       buffer_len(&c->extended) > 0))
+#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
+       (compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \
+       c->efd != -1 && (!(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD)) || \
+       buffer_len(&c->extended) > 0))
+
+/* channel management */
+
+Channel        *channel_by_id(int);
+Channel        *channel_lookup(int);
+Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
+void    channel_set_fds(int, int, int, int, int, int, int, u_int);
+void    channel_free(Channel *);
+void    channel_free_all(void);
+void    channel_stop_listening(void);
+
+void    channel_send_open(int);
+void    channel_request_start(int, char *, int);
+void    channel_register_cleanup(int, channel_callback_fn *, int);
+void    channel_register_open_confirm(int, channel_open_fn *, void *);
+void    channel_register_filter(int, channel_infilter_fn *,
+    channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
+void    channel_register_status_confirm(int, channel_confirm_cb *,
+    channel_confirm_abandon_cb *, void *);
+void    channel_cancel_cleanup(int);
+int     channel_close_fd(int *);
+void    channel_send_window_changes(void);
+
+/* protocol handler */
+
+void    channel_input_close(int, u_int32_t, void *);
+void    channel_input_close_confirmation(int, u_int32_t, void *);
+void    channel_input_data(int, u_int32_t, void *);
+void    channel_input_extended_data(int, u_int32_t, void *);
+void    channel_input_ieof(int, u_int32_t, void *);
+void    channel_input_oclose(int, u_int32_t, void *);
+void    channel_input_open_confirmation(int, u_int32_t, void *);
+void    channel_input_open_failure(int, u_int32_t, void *);
+void    channel_input_port_open(int, u_int32_t, void *);
+void    channel_input_window_adjust(int, u_int32_t, void *);
+void    channel_input_status_confirm(int, u_int32_t, void *);
+
+/* file descriptor handling (read/write) */
+
+void    channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int);
+void     channel_after_select(fd_set *, fd_set *);
+void     channel_output_poll(void);
+
+int      channel_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);
+int     channel_add_adm_permitted_opens(char *, int);
+void    channel_clear_permitted_opens(void);
+void    channel_clear_adm_permitted_opens(void);
+void    channel_print_adm_permitted_opens(void);
+int      channel_input_port_forward_request(int, int);
+Channel        *channel_connect_to(const char *, u_short, char *, char *);
+Channel        *channel_connect_stdio_fwd(const char*, u_short, int, int);
+Channel        *channel_connect_by_listen_address(u_short, char *, char *);
+int     channel_request_remote_forwarding(const char *, u_short,
+            const char *, u_short);
+int     channel_setup_local_fwd_listener(const char *, u_short,
+            const char *, u_short, int);
+void    channel_request_rforward_cancel(const char *host, u_short port);
+int     channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
+int     channel_cancel_rport_listener(const char *, u_short);
+
+/* x11 forwarding */
+
+int     x11_connect_display(void);
+int     x11_create_display_inet(int, int, int, u_int *, int **);
+void     x11_input_open(int, u_int32_t, void *);
+void    x11_request_forwarding_with_spoofing(int, const char *, const char *,
+            const char *);
+void    deny_input_open(int, u_int32_t, void *);
+
+/* agent forwarding */
+
+void    auth_request_forwarding(void);
+
+/* channel close */
+
+int     chan_is_dead(Channel *, int);
+void    chan_mark_dead(Channel *);
+
+/* channel events */
+
+void    chan_rcvd_oclose(Channel *);
+void    chan_rcvd_eow(Channel *);      /* SSH2-only */
+void    chan_read_failed(Channel *);
+void    chan_ibuf_empty(Channel *);
+
+void    chan_rcvd_ieof(Channel *);
+void    chan_write_failed(Channel *);
+void    chan_obuf_empty(Channel *);
+
+#endif
diff --git a/cipher-3des1.c b/cipher-3des1.c
new file mode 100644 (file)
index 0000000..b7aa588
--- /dev/null
@@ -0,0 +1,183 @@
+/* $OpenBSD: cipher-3des1.c,v 1.7 2010/10/01 23:05:32 djm Exp $ */
+/*
+ * Copyright (c) 2003 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 <sys/types.h>
+
+#include <openssl/evp.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+#include "openbsd-compat/openssl-compat.h"
+
+/*
+ * 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.
+ */
+struct ssh1_3des_ctx
+{
+       EVP_CIPHER_CTX  k1, k2, k3;
+};
+
+const EVP_CIPHER * evp_ssh1_3des(void);
+void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+
+static int
+ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+    int enc)
+{
+       struct ssh1_3des_ctx *c;
+       u_char *k1, *k2, *k3;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+               c = xmalloc(sizeof(*c));
+               EVP_CIPHER_CTX_set_app_data(ctx, c);
+       }
+       if (key == NULL)
+               return (1);
+       if (enc == -1)
+               enc = ctx->encrypt;
+       k1 = k2 = k3 = (u_char *) key;
+       k2 += 8;
+       if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
+               if (enc)
+                       k3 += 16;
+               else
+                       k1 += 16;
+       }
+       EVP_CIPHER_CTX_init(&c->k1);
+       EVP_CIPHER_CTX_init(&c->k2);
+       EVP_CIPHER_CTX_init(&c->k3);
+#ifdef SSH_OLD_EVP
+       EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc);
+       EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc);
+       EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc);
+#else
+       if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
+           EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
+           EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
+               memset(c, 0, sizeof(*c));
+               xfree(c);
+               EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+               return (0);
+       }
+#endif
+       return (1);
+}
+
+static int
+ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
+    LIBCRYPTO_EVP_INL_TYPE len)
+{
+       struct ssh1_3des_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+               error("ssh1_3des_cbc: no context");
+               return (0);
+       }
+#ifdef SSH_OLD_EVP
+       EVP_Cipher(&c->k1, dest, (u_char *)src, len);
+       EVP_Cipher(&c->k2, dest, dest, len);
+       EVP_Cipher(&c->k3, dest, dest, len);
+#else
+       if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
+           EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
+           EVP_Cipher(&c->k3, dest, dest, len) == 0)
+               return (0);
+#endif
+       return (1);
+}
+
+static int
+ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
+{
+       struct ssh1_3des_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+               EVP_CIPHER_CTX_cleanup(&c->k1);
+               EVP_CIPHER_CTX_cleanup(&c->k2);
+               EVP_CIPHER_CTX_cleanup(&c->k3);
+               memset(c, 0, sizeof(*c));
+               xfree(c);
+               EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+       }
+       return (1);
+}
+
+void
+ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
+{
+       struct ssh1_3des_ctx *c;
+
+       if (len != 24)
+               fatal("%s: bad 3des iv length: %d", __func__, len);
+       if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
+               fatal("%s: no 3des context", __func__);
+       if (doset) {
+               debug3("%s: Installed 3DES IV", __func__);
+               memcpy(c->k1.iv, iv, 8);
+               memcpy(c->k2.iv, iv + 8, 8);
+               memcpy(c->k3.iv, iv + 16, 8);
+       } else {
+               debug3("%s: Copying 3DES IV", __func__);
+               memcpy(iv, c->k1.iv, 8);
+               memcpy(iv + 8, c->k2.iv, 8);
+               memcpy(iv + 16, c->k3.iv, 8);
+       }
+}
+
+const EVP_CIPHER *
+evp_ssh1_3des(void)
+{
+       static EVP_CIPHER ssh1_3des;
+
+       memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
+       ssh1_3des.nid = NID_undef;
+       ssh1_3des.block_size = 8;
+       ssh1_3des.iv_len = 0;
+       ssh1_3des.key_len = 16;
+       ssh1_3des.init = ssh1_3des_init;
+       ssh1_3des.cleanup = ssh1_3des_cleanup;
+       ssh1_3des.do_cipher = ssh1_3des_cbc;
+#ifndef SSH_OLD_EVP
+       ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
+#endif
+       return (&ssh1_3des);
+}
diff --git a/cipher-acss.c b/cipher-acss.c
new file mode 100644 (file)
index 0000000..e755f92
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2004 The OpenBSD project
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <openssl/evp.h>
+
+#include <string.h>
+
+#if !defined(EVP_CTRL_SET_ACSS_MODE) && (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+
+#include "acss.h"
+#include "openbsd-compat/openssl-compat.h"
+
+#define data(ctx) ((EVP_ACSS_KEY *)(ctx)->cipher_data)
+
+typedef struct {
+       ACSS_KEY ks;
+} EVP_ACSS_KEY;
+
+#define EVP_CTRL_SET_ACSS_MODE          0xff06
+#define EVP_CTRL_SET_ACSS_SUBKEY        0xff07
+
+static int
+acss_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+    const unsigned char *iv, int enc)
+{
+       acss_setkey(&data(ctx)->ks,key,enc,ACSS_DATA);
+       return 1;
+}
+
+static int
+acss_ciph(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in,
+    LIBCRYPTO_EVP_INL_TYPE inl)
+{
+       acss(&data(ctx)->ks,inl,in,out);
+       return 1;
+}
+
+static int
+acss_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr)
+{
+       switch(type) {
+       case EVP_CTRL_SET_ACSS_MODE:
+               data(ctx)->ks.mode = arg;
+               return 1;
+       case EVP_CTRL_SET_ACSS_SUBKEY:
+               acss_setsubkey(&data(ctx)->ks,(unsigned char *)ptr);
+               return 1;
+       default:
+               return -1;
+       }
+}
+
+const EVP_CIPHER *
+evp_acss(void)
+{
+       static EVP_CIPHER acss_cipher;
+
+       memset(&acss_cipher, 0, sizeof(EVP_CIPHER));
+
+       acss_cipher.nid = NID_undef;
+       acss_cipher.block_size = 1;
+       acss_cipher.key_len = 5;
+       acss_cipher.init = acss_init_key;
+       acss_cipher.do_cipher = acss_ciph;
+       acss_cipher.ctx_size = sizeof(EVP_ACSS_KEY);
+       acss_cipher.ctrl = acss_ctrl;
+
+       return (&acss_cipher);
+}
+#endif
+
diff --git a/cipher-aes.c b/cipher-aes.c
new file mode 100644 (file)
index 0000000..bfda6d2
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003 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"
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+#ifdef USE_BUILTIN_RIJNDAEL
+#include <sys/types.h>
+
+#include <openssl/evp.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "rijndael.h"
+#include "xmalloc.h"
+#include "log.h"
+
+#define RIJNDAEL_BLOCKSIZE 16
+struct ssh_rijndael_ctx
+{
+       rijndael_ctx    r_ctx;
+       u_char          r_iv[RIJNDAEL_BLOCKSIZE];
+};
+
+const EVP_CIPHER * evp_rijndael(void);
+void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
+
+static int
+ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+    int enc)
+{
+       struct ssh_rijndael_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+               c = xmalloc(sizeof(*c));
+               EVP_CIPHER_CTX_set_app_data(ctx, c);
+       }
+       if (key != NULL) {
+               if (enc == -1)
+                       enc = ctx->encrypt;
+               rijndael_set_key(&c->r_ctx, (u_char *)key,
+                   8*EVP_CIPHER_CTX_key_length(ctx), enc);
+       }
+       if (iv != NULL)
+               memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE);
+       return (1);
+}
+
+static int
+ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
+    LIBCRYPTO_EVP_INL_TYPE len)
+{
+       struct ssh_rijndael_ctx *c;
+       u_char buf[RIJNDAEL_BLOCKSIZE];
+       u_char *cprev, *cnow, *plain, *ivp;
+       int i, j, blocks = len / RIJNDAEL_BLOCKSIZE;
+
+       if (len == 0)
+               return (1);
+       if (len % RIJNDAEL_BLOCKSIZE)
+               fatal("ssh_rijndael_cbc: bad len %d", len);
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+               error("ssh_rijndael_cbc: no context");
+               return (0);
+       }
+       if (ctx->encrypt) {
+               cnow  = dest;
+               plain = (u_char *)src;
+               cprev = c->r_iv;
+               for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE,
+                   cnow+=RIJNDAEL_BLOCKSIZE) {
+                       for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+                               buf[j] = plain[j] ^ cprev[j];
+                       rijndael_encrypt(&c->r_ctx, buf, cnow);
+                       cprev = cnow;
+               }
+               memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE);
+       } else {
+               cnow  = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE);
+               plain = dest+len-RIJNDAEL_BLOCKSIZE;
+
+               memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE);
+               for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE,
+                   plain-=RIJNDAEL_BLOCKSIZE) {
+                       rijndael_decrypt(&c->r_ctx, cnow, plain);
+                       ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE;
+                       for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++)
+                               plain[j] ^= ivp[j];
+               }
+               memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE);
+       }
+       return (1);
+}
+
+static int
+ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx)
+{
+       struct ssh_rijndael_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+               memset(c, 0, sizeof(*c));
+               xfree(c);
+               EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+       }
+       return (1);
+}
+
+void
+ssh_rijndael_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len)
+{
+       struct ssh_rijndael_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
+               fatal("ssh_rijndael_iv: no context");
+       if (doset)
+               memcpy(c->r_iv, iv, len);
+       else
+               memcpy(iv, c->r_iv, len);
+}
+
+const EVP_CIPHER *
+evp_rijndael(void)
+{
+       static EVP_CIPHER rijndal_cbc;
+
+       memset(&rijndal_cbc, 0, sizeof(EVP_CIPHER));
+       rijndal_cbc.nid = NID_undef;
+       rijndal_cbc.block_size = RIJNDAEL_BLOCKSIZE;
+       rijndal_cbc.iv_len = RIJNDAEL_BLOCKSIZE;
+       rijndal_cbc.key_len = 16;
+       rijndal_cbc.init = ssh_rijndael_init;
+       rijndal_cbc.cleanup = ssh_rijndael_cleanup;
+       rijndal_cbc.do_cipher = ssh_rijndael_cbc;
+#ifndef SSH_OLD_EVP
+       rijndal_cbc.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
+           EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+#endif
+       return (&rijndal_cbc);
+}
+#endif /* USE_BUILTIN_RIJNDAEL */
diff --git a/cipher-bf1.c b/cipher-bf1.c
new file mode 100644 (file)
index 0000000..309509d
--- /dev/null
@@ -0,0 +1,108 @@
+/* $OpenBSD: cipher-bf1.c,v 1.6 2010/10/01 23:05:32 djm Exp $ */
+/*
+ * Copyright (c) 2003 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 <sys/types.h>
+
+#include <openssl/evp.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+#include "openbsd-compat/openssl-compat.h"
+
+/*
+ * SSH1 uses a variation on Blowfish, all bytes must be swapped before
+ * and after encryption/decryption. Thus the swap_bytes stuff (yuk).
+ */
+
+const EVP_CIPHER * evp_ssh1_bf(void);
+
+static void
+swap_bytes(const u_char *src, u_char *dst, int n)
+{
+       u_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];
+       }
+}
+
+#ifdef SSH_OLD_EVP
+static void bf_ssh1_init (EVP_CIPHER_CTX * ctx, const unsigned char *key,
+                         const unsigned char *iv, int enc)
+{
+       if (iv != NULL)
+               memcpy (&(ctx->oiv[0]), iv, 8);
+       memcpy (&(ctx->iv[0]), &(ctx->oiv[0]), 8);
+       if (key != NULL)
+               BF_set_key (&(ctx->c.bf_ks), EVP_CIPHER_CTX_key_length (ctx),
+                           key);
+}
+#endif
+
+static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *,
+    const u_char *, LIBCRYPTO_EVP_INL_TYPE) = NULL;
+
+static int
+bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in,
+    LIBCRYPTO_EVP_INL_TYPE len)
+{
+       int ret;
+
+       swap_bytes(in, out, len);
+       ret = (*orig_bf)(ctx, out, out, len);
+       swap_bytes(out, out, len);
+       return (ret);
+}
+
+const EVP_CIPHER *
+evp_ssh1_bf(void)
+{
+       static EVP_CIPHER ssh1_bf;
+
+       memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
+       orig_bf = ssh1_bf.do_cipher;
+       ssh1_bf.nid = NID_undef;
+#ifdef SSH_OLD_EVP
+       ssh1_bf.init = bf_ssh1_init;
+#endif
+       ssh1_bf.do_cipher = bf_ssh1_cipher;
+       ssh1_bf.key_len = 32;
+       return (&ssh1_bf);
+}
diff --git a/cipher-ctr.c b/cipher-ctr.c
new file mode 100644 (file)
index 0000000..04975b4
--- /dev/null
@@ -0,0 +1,146 @@
+/* $OpenBSD: cipher-ctr.c,v 1.11 2010/10/01 23:05:32 djm Exp $ */
+/*
+ * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "log.h"
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+#ifndef USE_BUILTIN_RIJNDAEL
+#include <openssl/aes.h>
+#endif
+
+const EVP_CIPHER *evp_aes_128_ctr(void);
+void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, size_t);
+
+struct ssh_aes_ctr_ctx
+{
+       AES_KEY         aes_ctx;
+       u_char          aes_counter[AES_BLOCK_SIZE];
+};
+
+/*
+ * increment counter 'ctr',
+ * the counter is of size 'len' bytes and stored in network-byte-order.
+ * (LSB at ctr[len-1], MSB at ctr[0])
+ */
+static void
+ssh_ctr_inc(u_char *ctr, size_t len)
+{
+       int i;
+
+       for (i = len - 1; i >= 0; i--)
+               if (++ctr[i])   /* continue on overflow */
+                       return;
+}
+
+static int
+ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src,
+    LIBCRYPTO_EVP_INL_TYPE len)
+{
+       struct ssh_aes_ctr_ctx *c;
+       size_t n = 0;
+       u_char buf[AES_BLOCK_SIZE];
+
+       if (len == 0)
+               return (1);
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
+               return (0);
+
+       while ((len--) > 0) {
+               if (n == 0) {
+                       AES_encrypt(c->aes_counter, buf, &c->aes_ctx);
+                       ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE);
+               }
+               *(dest++) = *(src++) ^ buf[n];
+               n = (n + 1) % AES_BLOCK_SIZE;
+       }
+       return (1);
+}
+
+static int
+ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
+    int enc)
+{
+       struct ssh_aes_ctr_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
+               c = xmalloc(sizeof(*c));
+               EVP_CIPHER_CTX_set_app_data(ctx, c);
+       }
+       if (key != NULL)
+               AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8,
+                   &c->aes_ctx);
+       if (iv != NULL)
+               memcpy(c->aes_counter, iv, AES_BLOCK_SIZE);
+       return (1);
+}
+
+static int
+ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx)
+{
+       struct ssh_aes_ctr_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
+               memset(c, 0, sizeof(*c));
+               xfree(c);
+               EVP_CIPHER_CTX_set_app_data(ctx, NULL);
+       }
+       return (1);
+}
+
+void
+ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, size_t len)
+{
+       struct ssh_aes_ctr_ctx *c;
+
+       if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
+               fatal("ssh_aes_ctr_iv: no context");
+       if (doset)
+               memcpy(c->aes_counter, iv, len);
+       else
+               memcpy(iv, c->aes_counter, len);
+}
+
+const EVP_CIPHER *
+evp_aes_128_ctr(void)
+{
+       static EVP_CIPHER aes_ctr;
+
+       memset(&aes_ctr, 0, sizeof(EVP_CIPHER));
+       aes_ctr.nid = NID_undef;
+       aes_ctr.block_size = AES_BLOCK_SIZE;
+       aes_ctr.iv_len = AES_BLOCK_SIZE;
+       aes_ctr.key_len = 16;
+       aes_ctr.init = ssh_aes_ctr_init;
+       aes_ctr.cleanup = ssh_aes_ctr_cleanup;
+       aes_ctr.do_cipher = ssh_aes_ctr;
+#ifndef SSH_OLD_EVP
+       aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
+           EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+#endif
+       return (&aes_ctr);
+}
diff --git a/cipher.c b/cipher.c
new file mode 100644 (file)
index 0000000..bb5c0ac
--- /dev/null
+++ b/cipher.c
@@ -0,0 +1,431 @@
+/* $OpenBSD: cipher.c,v 1.82 2009/01/26 09:58:15 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) 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"
+
+#include <sys/types.h>
+
+#include <openssl/md5.h>
+
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "cipher.h"
+
+/* compatibility with old or broken OpenSSL versions */
+#include "openbsd-compat/openssl-compat.h"
+
+extern const EVP_CIPHER *evp_ssh1_bf(void);
+extern const EVP_CIPHER *evp_ssh1_3des(void);
+extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
+extern const EVP_CIPHER *evp_aes_128_ctr(void);
+extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
+
+struct Cipher {
+       char    *name;
+       int     number;         /* for ssh1 only */
+       u_int   block_size;
+       u_int   key_len;
+       u_int   discard_len;
+       u_int   cbc_mode;
+       const EVP_CIPHER        *(*evptype)(void);
+} ciphers[] = {
+       { "none",               SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null },
+       { "des",                SSH_CIPHER_DES, 8, 8, 0, 1, EVP_des_cbc },
+       { "3des",               SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des },
+       { "blowfish",           SSH_CIPHER_BLOWFISH, 8, 32, 0, 1, evp_ssh1_bf },
+
+       { "3des-cbc",           SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc },
+       { "blowfish-cbc",       SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_bf_cbc },
+       { "cast128-cbc",        SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_cast5_cbc },
+       { "arcfour",            SSH_CIPHER_SSH2, 8, 16, 0, 0, EVP_rc4 },
+       { "arcfour128",         SSH_CIPHER_SSH2, 8, 16, 1536, 0, EVP_rc4 },
+       { "arcfour256",         SSH_CIPHER_SSH2, 8, 32, 1536, 0, EVP_rc4 },
+       { "aes128-cbc",         SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc },
+       { "aes192-cbc",         SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc },
+       { "aes256-cbc",         SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
+       { "rijndael-cbc@lysator.liu.se",
+                               SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc },
+       { "aes128-ctr",         SSH_CIPHER_SSH2, 16, 16, 0, 0, evp_aes_128_ctr },
+       { "aes192-ctr",         SSH_CIPHER_SSH2, 16, 24, 0, 0, evp_aes_128_ctr },
+       { "aes256-ctr",         SSH_CIPHER_SSH2, 16, 32, 0, 0, evp_aes_128_ctr },
+#ifdef USE_CIPHER_ACSS
+       { "acss@openssh.org",   SSH_CIPHER_SSH2, 16, 5, 0, 0, EVP_acss },
+#endif
+       { NULL,                 SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL }
+};
+
+/*--*/
+
+u_int
+cipher_blocksize(const Cipher *c)
+{
+       return (c->block_size);
+}
+
+u_int
+cipher_keylen(const Cipher *c)
+{
+       return (c->key_len);
+}
+
+u_int
+cipher_get_number(const Cipher *c)
+{
+       return (c->number);
+}
+
+u_int
+cipher_is_cbc(const Cipher *c)
+{
+       return (c->cbc_mode);
+}
+
+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 (strcmp(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 *cipher_list, *cp;
+       char *p;
+
+       if (names == NULL || strcmp(names, "") == 0)
+               return 0;
+       cipher_list = 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(cipher_list);
+                       return 0;
+               } else {
+                       debug3("cipher ok: %s [%s]", p, names);
+               }
+       }
+       debug3("ciphers ok: [%s]", names);
+       xfree(cipher_list);
+       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;
+       for (c = ciphers; c->name != NULL; c++)
+               if (strcasecmp(c->name, name) == 0)
+                       return c->number;
+       return -1;
+}
+
+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,
+    int do_encrypt)
+{
+       static int dowarn = 1;
+#ifdef SSH_OLD_EVP
+       EVP_CIPHER *type;
+#else
+       const EVP_CIPHER *type;
+       int klen;
+#endif
+       u_char *junk, *discard;
+
+       if (cipher->number == SSH_CIPHER_DES) {
+               if (dowarn) {
+                       error("Warning: use of DES is strongly discouraged "
+                           "due to cryptographic weaknesses");
+                       dowarn = 0;
+               }
+               if (keylen > 8)
+                       keylen = 8;
+       }
+       cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
+
+       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;
+
+       type = (*cipher->evptype)();
+
+       EVP_CIPHER_CTX_init(&cc->evp);
+#ifdef SSH_OLD_EVP
+       if (type->key_len > 0 && type->key_len != keylen) {
+               debug("cipher_init: set keylen (%d -> %d)",
+                   type->key_len, keylen);
+               type->key_len = keylen;
+       }
+       EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv,
+           (do_encrypt == CIPHER_ENCRYPT));
+#else
+       if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv,
+           (do_encrypt == CIPHER_ENCRYPT)) == 0)
+               fatal("cipher_init: EVP_CipherInit failed for %s",
+                   cipher->name);
+       klen = EVP_CIPHER_CTX_key_length(&cc->evp);
+       if (klen > 0 && keylen != (u_int)klen) {
+               debug2("cipher_init: set keylen (%d -> %d)", klen, keylen);
+               if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0)
+                       fatal("cipher_init: set keylen failed (%d -> %d)",
+                           klen, keylen);
+       }
+       if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0)
+               fatal("cipher_init: EVP_CipherInit: set key failed for %s",
+                   cipher->name);
+#endif
+
+       if (cipher->discard_len > 0) {
+               junk = xmalloc(cipher->discard_len);
+               discard = xmalloc(cipher->discard_len);
+               if (EVP_Cipher(&cc->evp, discard, junk,
+                   cipher->discard_len) == 0)
+                       fatal("evp_crypt: EVP_Cipher failed during discard");
+               memset(discard, 0, cipher->discard_len);
+               xfree(junk);
+               xfree(discard);
+       }
+}
+
+void
+cipher_crypt(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);
+       if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0)
+               fatal("evp_crypt: EVP_Cipher failed");
+}
+
+void
+cipher_cleanup(CipherContext *cc)
+{
+       if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0)
+               error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed");
+}
+
+/*
+ * 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, int do_encrypt)
+{
+       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, do_encrypt);
+
+       memset(digest, 0, sizeof(digest));
+       memset(&md, 0, sizeof(md));
+}
+
+/*
+ * Exports an IV from the CipherContext required to export the key
+ * state back from the unprivileged child to the privileged parent
+ * process.
+ */
+
+int
+cipher_get_keyiv_len(const CipherContext *cc)
+{
+       Cipher *c = cc->cipher;
+       int ivlen;
+
+       if (c->number == SSH_CIPHER_3DES)
+               ivlen = 24;
+       else
+               ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+       return (ivlen);
+}
+
+void
+cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
+{
+       Cipher *c = cc->cipher;
+       int evplen;
+
+       switch (c->number) {
+       case SSH_CIPHER_SSH2:
+       case SSH_CIPHER_DES:
+       case SSH_CIPHER_BLOWFISH:
+               evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+               if (evplen <= 0)
+                       return;
+               if ((u_int)evplen != len)
+                       fatal("%s: wrong iv length %d != %d", __func__,
+                           evplen, len);
+#ifdef USE_BUILTIN_RIJNDAEL
+               if (c->evptype == evp_rijndael)
+                       ssh_rijndael_iv(&cc->evp, 0, iv, len);
+               else
+#endif
+               if (c->evptype == evp_aes_128_ctr)
+                       ssh_aes_ctr_iv(&cc->evp, 0, iv, len);
+               else
+                       memcpy(iv, cc->evp.iv, len);
+               break;
+       case SSH_CIPHER_3DES:
+               ssh1_3des_iv(&cc->evp, 0, iv, 24);
+               break;
+       default:
+               fatal("%s: bad cipher %d", __func__, c->number);
+       }
+}
+
+void
+cipher_set_keyiv(CipherContext *cc, u_char *iv)
+{
+       Cipher *c = cc->cipher;
+       int evplen = 0;
+
+       switch (c->number) {
+       case SSH_CIPHER_SSH2:
+       case SSH_CIPHER_DES:
+       case SSH_CIPHER_BLOWFISH:
+               evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
+               if (evplen == 0)
+                       return;
+#ifdef USE_BUILTIN_RIJNDAEL
+               if (c->evptype == evp_rijndael)
+                       ssh_rijndael_iv(&cc->evp, 1, iv, evplen);
+               else
+#endif
+               if (c->evptype == evp_aes_128_ctr)
+                       ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen);
+               else
+                       memcpy(cc->evp.iv, iv, evplen);
+               break;
+       case SSH_CIPHER_3DES:
+               ssh1_3des_iv(&cc->evp, 1, iv, 24);
+               break;
+       default:
+               fatal("%s: bad cipher %d", __func__, c->number);
+       }
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#define EVP_X_STATE(evp)       &(evp).c
+#define EVP_X_STATE_LEN(evp)   sizeof((evp).c)
+#else
+#define EVP_X_STATE(evp)       (evp).cipher_data
+#define EVP_X_STATE_LEN(evp)   (evp).cipher->ctx_size
+#endif
+
+int
+cipher_get_keycontext(const CipherContext *cc, u_char *dat)
+{
+       Cipher *c = cc->cipher;
+       int plen = 0;
+
+       if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) {
+               plen = EVP_X_STATE_LEN(cc->evp);
+               if (dat == NULL)
+                       return (plen);
+               memcpy(dat, EVP_X_STATE(cc->evp), plen);
+       }
+       return (plen);
+}
+
+void
+cipher_set_keycontext(CipherContext *cc, u_char *dat)
+{
+       Cipher *c = cc->cipher;
+       int plen;
+
+       if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) {
+               plen = EVP_X_STATE_LEN(cc->evp);
+               memcpy(EVP_X_STATE(cc->evp), dat, plen);
+       }
+}
diff --git a/cipher.h b/cipher.h
new file mode 100644 (file)
index 0000000..3dd2270
--- /dev/null
+++ b/cipher.h
@@ -0,0 +1,92 @@
+/* $OpenBSD: cipher.h,v 1.37 2009/01/26 09:58:15 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) 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 CIPHER_H
+#define CIPHER_H
+
+#include <openssl/evp.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_INVALID     -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
+
+#define CIPHER_ENCRYPT         1
+#define CIPHER_DECRYPT         0
+
+typedef struct Cipher Cipher;
+typedef struct CipherContext CipherContext;
+
+struct Cipher;
+struct CipherContext {
+       int     plaintext;
+       EVP_CIPHER_CTX evp;
+       Cipher *cipher;
+};
+
+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, int);
+void    cipher_crypt(CipherContext *, u_char *, const u_char *, u_int);
+void    cipher_cleanup(CipherContext *);
+void    cipher_set_key_string(CipherContext *, Cipher *, const char *, int);
+u_int   cipher_blocksize(const Cipher *);
+u_int   cipher_keylen(const Cipher *);
+u_int   cipher_is_cbc(const Cipher *);
+
+u_int   cipher_get_number(const Cipher *);
+void    cipher_get_keyiv(CipherContext *, u_char *, u_int);
+void    cipher_set_keyiv(CipherContext *, u_char *);
+int     cipher_get_keyiv_len(const CipherContext *);
+int     cipher_get_keycontext(const CipherContext *, u_char *);
+void    cipher_set_keycontext(CipherContext *, u_char *);
+#endif                         /* CIPHER_H */
diff --git a/cleanup.c b/cleanup.c
new file mode 100644 (file)
index 0000000..238f965
--- /dev/null
+++ b/cleanup.c
@@ -0,0 +1,32 @@
+/* $OpenBSD: cleanup.c,v 1.5 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "log.h"
+
+/* default implementation */
+void
+cleanup_exit(int i)
+{
+       _exit(i);
+}
diff --git a/clientloop.c b/clientloop.c
new file mode 100644 (file)
index 0000000..f6c1444
--- /dev/null
@@ -0,0 +1,2135 @@
+/* $OpenBSD: clientloop.c,v 1.231 2011/01/16 12:05:59 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <errno.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "packet.h"
+#include "buffer.h"
+#include "compat.h"
+#include "channels.h"
+#include "dispatch.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "readconf.h"
+#include "clientloop.h"
+#include "sshconnect.h"
+#include "authfd.h"
+#include "atomicio.h"
+#include "sshpty.h"
+#include "misc.h"
+#include "match.h"
+#include "msg.h"
+#include "roaming.h"
+
+/* import options */
+extern Options options;
+
+/* Flag indicating that stdin should be redirected from /dev/null. */
+extern int stdin_null_flag;
+
+/* Flag indicating that no shell has been requested */
+extern int no_shell_flag;
+
+/* Control socket */
+extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */
+
+/*
+ * 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;
+
+/* Force TTY allocation */
+extern int force_tty_flag;
+
+/*
+ * 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 sig_atomic_t received_window_change_signal = 0;
+static volatile sig_atomic_t received_signal = 0;
+
+/* Flag indicating whether the user's terminal is in non-blocking mode. */
+static int in_non_blocking_mode = 0;
+
+/* Time when backgrounded control master using ControlPersist should exit */
+static time_t control_persist_exit_time = 0;
+
+/* Common data for the client loop code. */
+volatile sig_atomic_t quit_pending; /* Set non-zero to quit the loop. */
+static int escape_char1;       /* Escape character. (proto1 only) */
+static int escape_pending1;    /* Last character was an escape (proto1 only) */
+static int last_was_cr;                /* Last character was a newline. */
+static int exit_status;                /* Used to store the command exit status. */
+static int stdin_eof;          /* EOF has been encountered on stderr. */
+static Buffer stdin_buffer;    /* Buffer for stdin data. */
+static Buffer stdout_buffer;   /* Buffer for stdout data. */
+static Buffer stderr_buffer;   /* Buffer for stderr data. */
+static u_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;     /* In SSH2: login session closed. */
+static int x11_refuse_time;    /* If >0, refuse x11 opens after this time. */
+
+static void client_init_dispatch(void);
+int    session_ident = -1;
+
+int    session_resumed = 0;
+
+/* Track escape per proto2 channel */
+struct escape_filter_ctx {
+       int escape_pending;
+       int escape_char;
+};
+
+/* Context for channel confirmation replies */
+struct channel_reply_ctx {
+       const char *request_type;
+       int id, do_close;
+};
+
+/* Global request success/failure callbacks */
+struct global_confirm {
+       TAILQ_ENTRY(global_confirm) entry;
+       global_confirm_cb *cb;
+       void *ctx;
+       int ref_count;
+};
+TAILQ_HEAD(global_confirms, global_confirm);
+static struct global_confirms global_confirms =
+    TAILQ_HEAD_INITIALIZER(global_confirms);
+
+/*XXX*/
+extern Kex *xxx_kex;
+
+void ssh_process_session2_setup(int, int, int, Buffer *);
+
+/* Restores stdin to blocking mode. */
+
+static void
+leave_non_blocking(void)
+{
+       if (in_non_blocking_mode) {
+               unset_nonblock(fileno(stdin));
+               in_non_blocking_mode = 0;
+       }
+}
+
+/* Puts stdin terminal in non-blocking mode. */
+
+static void
+enter_non_blocking(void)
+{
+       in_non_blocking_mode = 1;
+       set_nonblock(fileno(stdin));
+}
+
+/*
+ * Signal handler for the window change signal (SIGWINCH).  This just sets a
+ * flag indicating that the window has changed.
+ */
+/*ARGSUSED */
+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.
+ */
+/*ARGSUSED */
+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;
+}
+
+/*
+ * Sets control_persist_exit_time to the absolute time when the
+ * backgrounded control master should exit due to expiry of the
+ * ControlPersist timeout.  Sets it to 0 if we are not a backgrounded
+ * control master process, or if there is no ControlPersist timeout.
+ */
+static void
+set_control_persist_exit_time(void)
+{
+       if (muxserver_sock == -1 || !options.control_persist
+           || options.control_persist_timeout == 0)
+               /* not using a ControlPersist timeout */
+               control_persist_exit_time = 0;
+       else if (channel_still_open()) {
+               /* some client connections are still open */
+               if (control_persist_exit_time > 0)
+                       debug2("%s: cancel scheduled exit", __func__);
+               control_persist_exit_time = 0;
+       } else if (control_persist_exit_time <= 0) {
+               /* a client connection has recently closed */
+               control_persist_exit_time = time(NULL) +
+                       (time_t)options.control_persist_timeout;
+               debug2("%s: schedule exit in %d seconds", __func__,
+                   options.control_persist_timeout);
+       }
+       /* else we are already counting down to the timeout */
+}
+
+#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
+void
+client_x11_get_proto(const char *display, const char *xauth_path,
+    u_int trusted, u_int timeout, char **_proto, char **_data)
+{
+       char cmd[1024];
+       char line[512];
+       char xdisplay[512];
+       static char proto[512], data[512];
+       FILE *f;
+       int got_data = 0, generated = 0, do_unlink = 0, i;
+       char *xauthdir, *xauthfile;
+       struct stat st;
+       u_int now;
+
+       xauthdir = xauthfile = NULL;
+       *_proto = proto;
+       *_data = data;
+       proto[0] = data[0] = '\0';
+
+       if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) {
+               debug("No xauth program.");
+       } else {
+               if (display == NULL) {
+                       debug("x11_get_proto: DISPLAY not set");
+                       return;
+               }
+               /*
+                * Handle FamilyLocal case where $DISPLAY does
+                * not match an authorization entry.  For this we
+                * just try "xauth list unix:displaynum.screennum".
+                * XXX: "localhost" match to determine FamilyLocal
+                *      is not perfect.
+                */
+               if (strncmp(display, "localhost:", 10) == 0) {
+                       snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
+                           display + 10);
+                       display = xdisplay;
+               }
+               if (trusted == 0) {
+                       xauthdir = xmalloc(MAXPATHLEN);
+                       xauthfile = xmalloc(MAXPATHLEN);
+                       mktemp_proto(xauthdir, MAXPATHLEN);
+                       if (mkdtemp(xauthdir) != NULL) {
+                               do_unlink = 1;
+                               snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
+                                   xauthdir);
+                               snprintf(cmd, sizeof(cmd),
+                                   "%s -f %s generate %s " SSH_X11_PROTO
+                                   " untrusted timeout %u 2>" _PATH_DEVNULL,
+                                   xauth_path, xauthfile, display, timeout);
+                               debug2("x11_get_proto: %s", cmd);
+                               if (system(cmd) == 0)
+                                       generated = 1;
+                               if (x11_refuse_time == 0) {
+                                       now = time(NULL) + 1;
+                                       if (UINT_MAX - timeout < now)
+                                               x11_refuse_time = UINT_MAX;
+                                       else
+                                               x11_refuse_time = now + timeout;
+                               }
+                       }
+               }
+
+               /*
+                * When in untrusted mode, we read the cookie only if it was
+                * successfully generated as an untrusted one in the step
+                * above.
+                */
+               if (trusted || generated) {
+                       snprintf(cmd, sizeof(cmd),
+                           "%s %s%s list %s 2>" _PATH_DEVNULL,
+                           xauth_path,
+                           generated ? "-f " : "" ,
+                           generated ? xauthfile : "",
+                           display);
+                       debug2("x11_get_proto: %s", cmd);
+                       f = popen(cmd, "r");
+                       if (f && fgets(line, sizeof(line), f) &&
+                           sscanf(line, "%*s %511s %511s", proto, data) == 2)
+                               got_data = 1;
+                       if (f)
+                               pclose(f);
+               } else
+                       error("Warning: untrusted X11 forwarding setup failed: "
+                           "xauth key data not generated");
+       }
+
+       if (do_unlink) {
+               unlink(xauthfile);
+               rmdir(xauthdir);
+       }
+       if (xauthdir)
+               xfree(xauthdir);
+       if (xauthfile)
+               xfree(xauthfile);
+
+       /*
+        * 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 rnd = 0;
+
+               logit("Warning: No xauth data; "
+                   "using fake authentication data for X11 forwarding.");
+               strlcpy(proto, SSH_X11_PROTO, sizeof proto);
+               for (i = 0; i < 16; i++) {
+                       if (i % 4 == 0)
+                               rnd = arc4random();
+                       snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
+                           rnd & 0xff);
+                       rnd >>= 8;
+               }
+       }
+}
+
+/*
+ * 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_char1)
+                               escape_pending1 = 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);
+               /* 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;
+
+       debug2("client_check_window_change: changed");
+
+       if (compat20) {
+               channel_send_window_changes();
+       } else {
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
+                       return;
+               packet_start(SSH_CMSG_WINDOW_SIZE);
+               packet_put_int((u_int)ws.ws_row);
+               packet_put_int((u_int)ws.ws_col);
+               packet_put_int((u_int)ws.ws_xpixel);
+               packet_put_int((u_int)ws.ws_ypixel);
+               packet_send();
+       }
+}
+
+static void
+client_global_request_reply(int type, u_int32_t seq, void *ctxt)
+{
+       struct global_confirm *gc;
+
+       if ((gc = TAILQ_FIRST(&global_confirms)) == NULL)
+               return;
+       if (gc->cb != NULL)
+               gc->cb(type, seq, gc->ctx);
+       if (--gc->ref_count <= 0) {
+               TAILQ_REMOVE(&global_confirms, gc, entry);
+               bzero(gc, sizeof(*gc));
+               xfree(gc);
+       }
+
+       packet_set_alive_timeouts(0);
+}
+
+static void
+server_alive_check(void)
+{
+       if (packet_inc_alive_timeouts() > options.server_alive_count_max) {
+               logit("Timeout, server %s not responding.", host);
+               cleanup_exit(255);
+       }
+       packet_start(SSH2_MSG_GLOBAL_REQUEST);
+       packet_put_cstring("keepalive@openssh.com");
+       packet_put_char(1);     /* boolean: want reply */
+       packet_send();
+       /* Insert an empty placeholder to maintain ordering */
+       client_register_global_confirm(NULL, NULL);
+}
+
+/*
+ * 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, u_int *nallocp, int rekeying)
+{
+       struct timeval tv, *tvp;
+       int timeout_secs;
+       int ret;
+
+       /* 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, or a timeout expires.
+        */
+
+       timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
+       if (options.server_alive_interval > 0 && compat20)
+               timeout_secs = options.server_alive_interval;
+       set_control_persist_exit_time();
+       if (control_persist_exit_time > 0) {
+               timeout_secs = MIN(timeout_secs,
+                       control_persist_exit_time - time(NULL));
+               if (timeout_secs < 0)
+                       timeout_secs = 0;
+       }
+       if (timeout_secs == INT_MAX)
+               tvp = NULL;
+       else {
+               tv.tv_sec = timeout_secs;
+               tv.tv_usec = 0;
+               tvp = &tv;
+       }
+
+       ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp);
+       if (ret < 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;
+       } else if (ret == 0)
+               server_alive_check();
+}
+
+static void
+client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
+{
+       /* Flush stdout and stderr buffers. */
+       if (buffer_len(bout) > 0)
+               atomicio(vwrite, fileno(stdout), buffer_ptr(bout),
+                   buffer_len(bout));
+       if (buffer_len(berr) > 0)
+               atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
+                   buffer_len(berr));
+
+       leave_raw_mode(force_tty_flag);
+
+       /*
+        * 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);
+
+       /* Send the suspend signal to the program itself. */
+       kill(getpid(), SIGTSTP);
+
+       /* Reset window sizes in case they have changed */
+       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(force_tty_flag);
+}
+
+static void
+client_process_net_input(fd_set *readset)
+{
+       int len, cont = 0;
+       char buf[SSH_IOBUFSZ];
+
+       /*
+        * 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 = roaming_read(connection_in, buf, sizeof(buf), &cont);
+               if (len == 0 && cont == 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 || errno == EWOULDBLOCK))
+                       len = 0;
+
+               if (len < 0) {
+                       /*
+                        * An error has encountered.  Perhaps there is a
+                        * network problem.
+                        */
+                       snprintf(buf, sizeof buf,
+                           "Read from remote host %.300s: %.100s\r\n",
+                           host, strerror(errno));
+                       buffer_append(&stderr_buffer, buf, strlen(buf));
+                       quit_pending = 1;
+                       return;
+               }
+               packet_process_incoming(buf, len);
+       }
+}
+
+static void
+client_status_confirm(int type, Channel *c, void *ctx)
+{
+       struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ctx;
+       char errmsg[256];
+       int tochan;
+
+       /* XXX supress on mux _client_ quietmode */
+       tochan = options.log_level >= SYSLOG_LEVEL_ERROR &&
+           c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
+
+       if (type == SSH2_MSG_CHANNEL_SUCCESS) {
+               debug2("%s request accepted on channel %d",
+                   cr->request_type, c->self);
+       } else if (type == SSH2_MSG_CHANNEL_FAILURE) {
+               if (tochan) {
+                       snprintf(errmsg, sizeof(errmsg),
+                           "%s request failed\r\n", cr->request_type);
+               } else {
+                       snprintf(errmsg, sizeof(errmsg),
+                           "%s request failed on channel %d",
+                           cr->request_type, c->self);
+               }
+               /* If error occurred on primary session channel, then exit */
+               if (cr->do_close && c->self == session_ident)
+                       fatal("%s", errmsg);
+               /* If error occurred on mux client, append to their stderr */
+               if (tochan)
+                       buffer_append(&c->extended, errmsg, strlen(errmsg));
+               else
+                       error("%s", errmsg);
+               if (cr->do_close) {
+                       chan_read_failed(c);
+                       chan_write_failed(c);
+               }
+       }
+       xfree(cr);
+}
+
+static void
+client_abandon_status_confirm(Channel *c, void *ctx)
+{
+       xfree(ctx);
+}
+
+static void
+client_expect_confirm(int id, const char *request, int do_close)
+{
+       struct channel_reply_ctx *cr = xmalloc(sizeof(*cr));
+
+       cr->request_type = request;
+       cr->do_close = do_close;
+
+       channel_register_status_confirm(id, client_status_confirm,
+           client_abandon_status_confirm, cr);
+}
+
+void
+client_register_global_confirm(global_confirm_cb *cb, void *ctx)
+{
+       struct global_confirm *gc, *last_gc;
+
+       /* Coalesce identical callbacks */
+       last_gc = TAILQ_LAST(&global_confirms, global_confirms);
+       if (last_gc && last_gc->cb == cb && last_gc->ctx == ctx) {
+               if (++last_gc->ref_count >= INT_MAX)
+                       fatal("%s: last_gc->ref_count = %d",
+                           __func__, last_gc->ref_count);
+               return;
+       }
+
+       gc = xmalloc(sizeof(*gc));
+       gc->cb = cb;
+       gc->ctx = ctx;
+       gc->ref_count = 1;
+       TAILQ_INSERT_TAIL(&global_confirms, gc, entry);
+}
+
+static void
+process_cmdline(void)
+{
+       void (*handler)(int);
+       char *s, *cmd, *cancel_host;
+       int delete = 0;
+       int local = 0, remote = 0, dynamic = 0;
+       int cancel_port;
+       Forward fwd;
+
+       bzero(&fwd, sizeof(fwd));
+       fwd.listen_host = fwd.connect_host = NULL;
+
+       leave_raw_mode(force_tty_flag);
+       handler = signal(SIGINT, SIG_IGN);
+       cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);
+       if (s == NULL)
+               goto out;
+       while (isspace(*s))
+               s++;
+       if (*s == '-')
+               s++;    /* Skip cmdline '-', if any */
+       if (*s == '\0')
+               goto out;
+
+       if (*s == 'h' || *s == 'H' || *s == '?') {
+               logit("Commands:");
+               logit("      -L[bind_address:]port:host:hostport    "
+                   "Request local forward");
+               logit("      -R[bind_address:]port:host:hostport    "
+                   "Request remote forward");
+               logit("      -D[bind_address:]port                  "
+                   "Request dynamic forward");
+               logit("      -KR[bind_address:]port                 "
+                   "Cancel remote forward");
+               if (!options.permit_local_command)
+                       goto out;
+               logit("      !args                                  "
+                   "Execute local command");
+               goto out;
+       }
+
+       if (*s == '!' && options.permit_local_command) {
+               s++;
+               ssh_local_cmd(s);
+               goto out;
+       }
+
+       if (*s == 'K') {
+               delete = 1;
+               s++;
+       }
+       if (*s == 'L')
+               local = 1;
+       else if (*s == 'R')
+               remote = 1;
+       else if (*s == 'D')
+               dynamic = 1;
+       else {
+               logit("Invalid command.");
+               goto out;
+       }
+
+       if ((local || dynamic) && delete) {
+               logit("Not supported.");
+               goto out;
+       }
+       if (remote && delete && !compat20) {
+               logit("Not supported for SSH protocol version 1.");
+               goto out;
+       }
+
+       while (isspace(*++s))
+               ;
+
+       /* XXX update list of forwards in options */
+       if (delete) {
+               cancel_port = 0;
+               cancel_host = hpdelim(&s);      /* may be NULL */
+               if (s != NULL) {
+                       cancel_port = a2port(s);
+                       cancel_host = cleanhostname(cancel_host);
+               } else {
+                       cancel_port = a2port(cancel_host);
+                       cancel_host = NULL;
+               }
+               if (cancel_port <= 0) {
+                       logit("Bad forwarding close port");
+                       goto out;
+               }
+               channel_request_rforward_cancel(cancel_host, cancel_port);
+       } else {
+               if (!parse_forward(&fwd, s, dynamic, remote)) {
+                       logit("Bad forwarding specification.");
+                       goto out;
+               }
+               if (local || dynamic) {
+                       if (channel_setup_local_fwd_listener(fwd.listen_host,
+                           fwd.listen_port, fwd.connect_host,
+                           fwd.connect_port, options.gateway_ports) < 0) {
+                               logit("Port forwarding failed.");
+                               goto out;
+                       }
+               } else {
+                       if (channel_request_remote_forwarding(fwd.listen_host,
+                           fwd.listen_port, fwd.connect_host,
+                           fwd.connect_port) < 0) {
+                               logit("Port forwarding failed.");
+                               goto out;
+                       }
+               }
+
+               logit("Forwarding port.");
+       }
+
+out:
+       signal(SIGINT, handler);
+       enter_raw_mode(force_tty_flag);
+       if (cmd)
+               xfree(cmd);
+       if (fwd.listen_host != NULL)
+               xfree(fwd.listen_host);
+       if (fwd.connect_host != NULL)
+               xfree(fwd.connect_host);
+}
+
+/* 
+ * Process the characters one by one, call with c==NULL for proto1 case.
+ */
+static int
+process_escapes(Channel *c, 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;
+       int *escape_pendingp, escape_char;
+       struct escape_filter_ctx *efc;
+
+       if (c == NULL) {
+               escape_pendingp = &escape_pending1;
+               escape_char = escape_char1;
+       } else {
+               if (c->filter_ctx == NULL)
+                       return 0;
+               efc = (struct escape_filter_ctx *)c->filter_ctx;
+               escape_pendingp = &efc->escape_pending;
+               escape_char = efc->escape_char;
+       }
+       
+       if (len <= 0)
+               return (0);
+
+       for (i = 0; i < (u_int)len; i++) {
+               /* Get one character at a time. */
+               ch = buf[i];
+
+               if (*escape_pendingp) {
+                       /* We have previously seen an escape character. */
+                       /* Clear the flag now. */
+                       *escape_pendingp = 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));
+
+                               if (c && c->ctl_chan != -1) {
+                                       chan_read_failed(c);
+                                       chan_write_failed(c);
+                                       return 0;
+                               } else
+                                       quit_pending = 1;
+                               return -1;
+
+                       case 'Z' - 64:
+                               /* XXX support this for mux clients */
+                               if (c && c->ctl_chan != -1) {
+ noescape:
+                                       snprintf(string, sizeof string,
+                                           "%c%c escape not available to "
+                                           "multiplexed sessions\r\n",
+                                           escape_char, ch);
+                                       buffer_append(berr, string,
+                                           strlen(string));
+                                       continue;
+                               }
+                               /* Suspend the program. Inform the user */
+                               snprintf(string, sizeof string,
+                                   "%c^Z [suspend ssh]\r\n", escape_char);
+                               buffer_append(berr, string, strlen(string));
+
+                               /* Restore terminal modes and suspend. */
+                               client_suspend_self(bin, bout, berr);
+
+                               /* We have been continued. */
+                               continue;
+
+                       case 'B':
+                               if (compat20) {
+                                       snprintf(string, sizeof string,
+                                           "%cB\r\n", escape_char);
+                                       buffer_append(berr, string,
+                                           strlen(string));
+                                       channel_request_start(session_ident,
+                                           "break", 0);
+                                       packet_put_int(1000);
+                                       packet_send();
+                               }
+                               continue;
+
+                       case 'R':
+                               if (compat20) {
+                                       if (datafellows & SSH_BUG_NOREKEY)
+                                               logit("Server does not "
+                                                   "support re-keying");
+                                       else
+                                               need_rekeying = 1;
+                               }
+                               continue;
+
+                       case '&':
+                               if (c && c->ctl_chan != -1)
+                                       goto noescape;
+                               /*
+                                * Detach the program (continue to serve
+                                * connections, but put in background and no
+                                * more new connections).
+                                */
+                               /* Restore tty modes. */
+                               leave_raw_mode(force_tty_flag);
+
+                               /* 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 '?':
+                               if (c && c->ctl_chan != -1) {
+                                       snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+  %c.  - terminate session\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
+(Note that escapes are only recognized immediately after newline.)\r\n",
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char);
+                               } else {
+                                       snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+  %c.  - terminate connection (and any multiplexed sessions)\r\n\
+  %cB  - send a BREAK to the remote system\r\n\
+  %cC  - open a command line\r\n\
+  %cR  - Request rekey (SSH protocol 2 only)\r\n\
+  %c^Z - suspend ssh\r\n\
+  %c#  - list forwarded connections\r\n\
+  %c&  - background ssh (when waiting for connections to terminate)\r\n\
+  %c?  - this message\r\n\
+  %c%c  - send the escape character by typing it twice\r\n\
+(Note that escapes are only recognized immediately after newline.)\r\n",
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char, escape_char,
+                                           escape_char);
+                               }
+                               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;
+
+                       case 'C':
+                               if (c && c->ctl_chan != -1)
+                                       goto noescape;
+                               process_cmdline();
+                               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_pendingp = 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[SSH_IOBUFSZ];
+
+       /* 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 || errno == EWOULDBLOCK))
+                       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_char1 == 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(NULL, &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 ||
+                           errno == EWOULDBLOCK)
+                               len = 0;
+                       else {
+                               /*
+                                * An error or EOF was encountered.  Put an
+                                * error message to stderr buffer.
+                                */
+                               snprintf(buf, sizeof buf,
+                                   "write stdout: %.50s\r\n", strerror(errno));
+                               buffer_append(&stderr_buffer, buf, strlen(buf));
+                               quit_pending = 1;
+                               return;
+                       }
+               }
+               /* Consume printed data from the buffer. */
+               buffer_consume(&stdout_buffer, 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 ||
+                           errno == EWOULDBLOCK)
+                               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);
+       }
+}
+
+/*
+ * 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 */
+
+/* Helper: allocate a new escape_filter_ctx and fill in its escape char */
+void *
+client_new_escape_filter_ctx(int escape_char)
+{
+       struct escape_filter_ctx *ret;
+
+       ret = xmalloc(sizeof(*ret));
+       ret->escape_pending = 0;
+       ret->escape_char = escape_char;
+       return (void *)ret;
+}
+
+/* Free the escape filter context on channel free */
+void
+client_filter_cleanup(int cid, void *ctx)
+{
+       xfree(ctx);
+}
+
+int
+client_simple_escape_filter(Channel *c, char *buf, int len)
+{
+       if (c->extended_usage != CHAN_EXTENDED_WRITE)
+               return 0;
+
+       return process_escapes(c, &c->input, &c->output, &c->extended,
+           buf, len);
+}
+
+static void
+client_channel_closed(int id, void *arg)
+{
+       channel_cancel_cleanup(id);
+       session_closed = 1;
+       leave_raw_mode(force_tty_flag);
+}
+
+/*
+ * 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;
+       u_int64_t ibytes, obytes;
+       u_int nalloc = 0;
+       char buf[100];
+
+       debug("Entering interactive session.");
+
+       start_time = get_current_time();
+
+       /* Initialize variables. */
+       escape_pending1 = 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));
+       }
+       quit_pending = 0;
+       escape_char1 = escape_char_arg;
+
+       /* Initialize buffers. */
+       buffer_init(&stdin_buffer);
+       buffer_init(&stdout_buffer);
+       buffer_init(&stderr_buffer);
+
+       client_init_dispatch();
+
+       /*
+        * Set signal handlers, (e.g. to restore non-blocking mode)
+        * but don't overwrite SIG_IGN, matches behaviour from rsh(1)
+        */
+       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+               signal(SIGHUP, signal_handler);
+       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+               signal(SIGINT, signal_handler);
+       if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+               signal(SIGQUIT, signal_handler);
+       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+               signal(SIGTERM, signal_handler);
+       signal(SIGWINCH, window_change_handler);
+
+       if (have_pty)
+               enter_raw_mode(force_tty_flag);
+
+       if (compat20) {
+               session_ident = ssh2_chan_id;
+               if (escape_char_arg != SSH_ESCAPECHAR_NONE)
+                       channel_register_filter(session_ident,
+                           client_simple_escape_filter, NULL,
+                           client_filter_cleanup,
+                           client_new_escape_filter_ctx(escape_char_arg));
+               if (session_ident != -1)
+                       channel_register_cleanup(session_ident,
+                           client_channel_closed, 0);
+       } 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 || packet_need_rekeying()) {
+                               debug("need 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);
+               }
+
+               if (session_resumed) {
+                       connection_in = packet_get_connection_in();
+                       connection_out = packet_get_connection_out();
+                       max_fd = MAX(max_fd, connection_out);
+                       max_fd = MAX(max_fd, connection_in);
+                       session_resumed = 0;
+               }
+
+               /*
+                * Send as much buffered packet data as possible to the
+                * sender.
+                */
+               if (FD_ISSET(connection_out, writeset))
+                       packet_write_poll();
+
+               /*
+                * If we are a backgrounded control master, and the
+                * timeout has expired without any active client
+                * connections, then quit.
+                */
+               if (control_persist_exit_time > 0) {
+                       if (time(NULL) >= control_persist_exit_time) {
+                               debug("ControlPersist timeout expired");
+                               break;
+                       }
+               }
+       }
+       if (readset)
+               xfree(readset);
+       if (writeset)
+               xfree(writeset);
+
+       /* Terminate the session. */
+
+       /* Stop watching for window change. */
+       signal(SIGWINCH, SIG_DFL);
+
+       if (compat20) {
+               packet_start(SSH2_MSG_DISCONNECT);
+               packet_put_int(SSH2_DISCONNECT_BY_APPLICATION);
+               packet_put_cstring("disconnected by user");
+               packet_put_cstring(""); /* language tag */
+               packet_send();
+               packet_write_wait();
+       }
+
+       channel_free_all();
+
+       if (have_pty)
+               leave_raw_mode(force_tty_flag);
+
+       /* 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 there was no shell or command requested, there will be no remote
+        * exit status to be returned.  In that case, clear error code if the
+        * connection was deliberately terminated at this end.
+        */
+       if (no_shell_flag && received_signal == SIGTERM) {
+               received_signal = 0;
+               exit_status = 0;
+       }
+
+       if (received_signal)
+               fatal("Killed by signal %d.", (int) 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. */
+       if (buffer_len(&stdout_buffer) > 0) {
+               len = atomicio(vwrite, fileno(stdout),
+                   buffer_ptr(&stdout_buffer), buffer_len(&stdout_buffer));
+               if (len < 0 || (u_int)len != buffer_len(&stdout_buffer))
+                       error("Write failed flushing stdout buffer.");
+               else
+                       buffer_consume(&stdout_buffer, len);
+       }
+
+       /* Output any buffered data for stderr. */
+       if (buffer_len(&stderr_buffer) > 0) {
+               len = atomicio(vwrite, fileno(stderr),
+                   buffer_ptr(&stderr_buffer), buffer_len(&stderr_buffer));
+               if (len < 0 || (u_int)len != buffer_len(&stderr_buffer))
+                       error("Write failed flushing stderr buffer.");
+               else
+                       buffer_consume(&stderr_buffer, 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;
+       packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+       packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+       verbose("Transferred: sent %llu, received %llu bytes, in %.1f seconds",
+           (unsigned long long)obytes, (unsigned long long)ibytes, total_time);
+       if (total_time > 0)
+               verbose("Bytes per second: sent %.1f, received %.1f",
+                   obytes / total_time, ibytes / total_time);
+       /* Return the exit status of the program. */
+       debug("Exit status %d", exit_status);
+       return exit_status;
+}
+
+/*********/
+
+static void
+client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
+{
+       u_int data_len;
+       char *data = packet_get_string(&data_len);
+       packet_check_eom();
+       buffer_append(&stdout_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+static void
+client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
+{
+       u_int data_len;
+       char *data = packet_get_string(&data_len);
+       packet_check_eom();
+       buffer_append(&stderr_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+static void
+client_input_exit_status(int type, u_int32_t seq, void *ctxt)
+{
+       exit_status = packet_get_int();
+       packet_check_eom();
+       /* 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 void
+client_input_agent_open(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c = NULL;
+       int remote_id, sock;
+
+       /* Read the remote channel number from the message. */
+       remote_id = packet_get_int();
+       packet_check_eom();
+
+       /*
+        * 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) {
+               c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
+                   -1, 0, 0, 0, "authentication agent connection", 1);
+               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();
+}
+
+static Channel *
+client_request_forwarded_tcpip(const char *request_type, int rchan)
+{
+       Channel *c = NULL;
+       char *listen_address, *originator_address;
+       u_short listen_port, originator_port;
+
+       /* 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_check_eom();
+
+       debug("client_request_forwarded_tcpip: listen %s port %d, "
+           "originator %s port %d", listen_address, listen_port,
+           originator_address, originator_port);
+
+       c = channel_connect_by_listen_address(listen_port,
+           "forwarded-tcpip", originator_address);
+
+       xfree(originator_address);
+       xfree(listen_address);
+       return c;
+}
+
+static Channel *
+client_request_x11(const char *request_type, int rchan)
+{
+       Channel *c = NULL;
+       char *originator;
+       u_short 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;
+       }
+       if (x11_refuse_time != 0 && time(NULL) >= x11_refuse_time) {
+               verbose("Rejected X11 connection after ForwardX11Timeout "
+                   "expired");
+               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_check_eom();
+       /* 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, "x11", 1);
+       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_PACKET_DEFAULT, 0,
+           "authentication agent connection", 1);
+       c->force_drain = 1;
+       return c;
+}
+
+int
+client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
+{
+       Channel *c;
+       int fd;
+
+       if (tun_mode == SSH_TUNMODE_NO)
+               return 0;
+
+       if (!compat20) {
+               error("Tunnel forwarding is not supported for protocol 1");
+               return -1;
+       }
+
+       debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
+
+       /* Open local tunnel device */
+       if ((fd = tun_open(local_tun, tun_mode)) == -1) {
+               error("Tunnel device open failed.");
+               return -1;
+       }
+
+       c = channel_new("tun", SSH_CHANNEL_OPENING, fd, fd, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
+       c->datagram = 1;
+
+#if defined(SSH_TUN_FILTER)
+       if (options.tun_open == SSH_TUNMODE_POINTOPOINT)
+               channel_register_filter(c->self, sys_tun_infilter,
+                   sys_tun_outfilter, NULL, NULL);
+#endif
+
+       packet_start(SSH2_MSG_CHANNEL_OPEN);
+       packet_put_cstring("tun@openssh.com");
+       packet_put_int(c->self);
+       packet_put_int(c->local_window_max);
+       packet_put_int(c->local_maxpacket);
+       packet_put_int(tun_mode);
+       packet_put_int(remote_tun);
+       packet_send();
+
+       return 0;
+}
+
+/* XXXX move to generic input handler */
+static void
+client_input_channel_open(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c = NULL;
+       char *ctype;
+       int rchan;
+       u_int rmaxpack, rwindow, len;
+
+       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, u_int32_t seq, void *ctxt)
+{
+       Channel *c = NULL;
+       int exitval, 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 (id == -1) {
+               error("client_input_channel_req: request for channel -1");
+       } else if ((c = channel_lookup(id)) == NULL) {
+               error("client_input_channel_req: channel %d: "
+                   "unknown channel", id);
+       } else if (strcmp(rtype, "eow@openssh.com") == 0) {
+               packet_check_eom();
+               chan_rcvd_eow(c);
+       } else if (strcmp(rtype, "exit-status") == 0) {
+               exitval = packet_get_int();
+               if (c->ctl_chan != -1) {
+                       mux_exit_message(c, exitval);
+                       success = 1;
+               } else if (id == session_ident) {
+                       /* Record exit value of local session */
+                       success = 1;
+                       exit_status = exitval;
+               } else {
+                       /* Probably for a mux channel that has already closed */
+                       debug("%s: no sink for exit-status on channel %d",
+                           __func__, id);
+               }
+               packet_check_eom();
+       }
+       if (reply && c != NULL) {
+               packet_start(success ?
+                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+               packet_put_int(c->remote_id);
+               packet_send();
+       }
+       xfree(rtype);
+}
+static void
+client_input_global_request(int type, u_int32_t seq, void *ctxt)
+{
+       char *rtype;
+       int want_reply;
+       int success = 0;
+
+       rtype = packet_get_string(NULL);
+       want_reply = packet_get_char();
+       debug("client_input_global_request: rtype %s want_reply %d",
+           rtype, want_reply);
+       if (want_reply) {
+               packet_start(success ?
+                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+               packet_send();
+               packet_write_wait();
+       }
+       xfree(rtype);
+}
+
+void
+client_session2_setup(int id, int want_tty, int want_subsystem,
+    const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env)
+{
+       int len;
+       Channel *c = NULL;
+
+       debug2("%s: id %d", __func__, id);
+
+       if ((c = channel_lookup(id)) == NULL)
+               fatal("client_session2_setup: channel %d: unknown channel", id);
+
+       packet_set_interactive(want_tty,
+           options.ip_qos_interactive, options.ip_qos_bulk);
+
+       if (want_tty) {
+               struct winsize ws;
+
+               /* Store window size in the packet. */
+               if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0)
+                       memset(&ws, 0, sizeof(ws));
+
+               channel_request_start(id, "pty-req", 1);
+               client_expect_confirm(id, "PTY allocation", 1);
+               packet_put_cstring(term != NULL ? term : "");
+               packet_put_int((u_int)ws.ws_col);
+               packet_put_int((u_int)ws.ws_row);
+               packet_put_int((u_int)ws.ws_xpixel);
+               packet_put_int((u_int)ws.ws_ypixel);
+               if (tiop == NULL)
+                       tiop = get_saved_tio();
+               tty_make_modes(-1, tiop);
+               packet_send();
+               /* XXX wait for reply */
+               c->client_tty = 1;
+       }
+
+       /* Transfer any environment variables from client to server */
+       if (options.num_send_env != 0 && env != NULL) {
+               int i, j, matched;
+               char *name, *val;
+
+               debug("Sending environment.");
+               for (i = 0; env[i] != NULL; i++) {
+                       /* Split */
+                       name = xstrdup(env[i]);
+                       if ((val = strchr(name, '=')) == NULL) {
+                               xfree(name);
+                               continue;
+                       }
+                       *val++ = '\0';
+
+                       matched = 0;
+                       for (j = 0; j < options.num_send_env; j++) {
+                               if (match_pattern(name, options.send_env[j])) {
+                                       matched = 1;
+                                       break;
+                               }
+                       }
+                       if (!matched) {
+                               debug3("Ignored env %s", name);
+                               xfree(name);
+                               continue;
+                       }
+
+                       debug("Sending env %s = %s", name, val);
+                       channel_request_start(id, "env", 0);
+                       packet_put_cstring(name);
+                       packet_put_cstring(val);
+                       packet_send();
+                       xfree(name);
+               }
+       }
+
+       len = buffer_len(cmd);
+       if (len > 0) {
+               if (len > 900)
+                       len = 900;
+               if (want_subsystem) {
+                       debug("Sending subsystem: %.*s",
+                           len, (u_char*)buffer_ptr(cmd));
+                       channel_request_start(id, "subsystem", 1);
+                       client_expect_confirm(id, "subsystem", 1);
+               } else {
+                       debug("Sending command: %.*s",
+                           len, (u_char*)buffer_ptr(cmd));
+                       channel_request_start(id, "exec", 1);
+                       client_expect_confirm(id, "exec", 1);
+               }
+               packet_put_string(buffer_ptr(cmd), buffer_len(cmd));
+               packet_send();
+       } else {
+               channel_request_start(id, "shell", 1);
+               client_expect_confirm(id, "shell", 1);
+               packet_send();
+       }
+}
+
+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);
+       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &channel_input_status_confirm);
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &channel_input_status_confirm);
+       dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request);
+
+       /* rekeying */
+       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+
+       /* global request reply messages */
+       dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply);
+       dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
+}
+
+static void
+client_init_dispatch_13(void)
+{
+       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 ?
+           &client_input_agent_open : &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();
+}
+
+/* client specific fatal cleanup */
+void
+cleanup_exit(int i)
+{
+       leave_raw_mode(force_tty_flag);
+       leave_non_blocking();
+       if (options.control_path != NULL && muxserver_sock != -1)
+               unlink(options.control_path);
+       ssh_kill_proxy_command();
+       _exit(i);
+}
diff --git a/clientloop.h b/clientloop.h
new file mode 100644 (file)
index 0000000..52115db
--- /dev/null
@@ -0,0 +1,70 @@
+/* $OpenBSD: clientloop.h,v 1.25 2010/06/25 23:15:36 djm 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.
+ */
+
+#include <termios.h>
+
+/* Client side main loop for the interactive session. */
+int     client_loop(int, int, int);
+void    client_x11_get_proto(const char *, const char *, u_int, u_int,
+           char **, char **);
+void    client_global_request_reply_fwd(int, u_int32_t, void *);
+void    client_session2_setup(int, int, int, const char *, struct termios *,
+           int, Buffer *, char **);
+int     client_request_tun_fwd(int, int, int);
+
+/* Escape filter for protocol 2 sessions */
+void   *client_new_escape_filter_ctx(int);
+void    client_filter_cleanup(int, void *);
+int     client_simple_escape_filter(Channel *, char *, int);
+
+/* Global request confirmation callbacks */
+typedef void global_confirm_cb(int, u_int32_t seq, void *);
+void    client_register_global_confirm(global_confirm_cb *, void *);
+
+/* Multiplexing protocol version */
+#define SSHMUX_VER                     4
+
+/* Multiplexing control protocol flags */
+#define SSHMUX_COMMAND_OPEN            1       /* Open new connection */
+#define SSHMUX_COMMAND_ALIVE_CHECK     2       /* Check master is alive */
+#define SSHMUX_COMMAND_TERMINATE       3       /* Ask master to exit */
+#define SSHMUX_COMMAND_STDIO_FWD       4       /* Open stdio fwd (ssh -W) */
+#define SSHMUX_COMMAND_FORWARD         5       /* Forward only, no command */
+
+void   muxserver_listen(void);
+void   muxclient(const char *);
+void   mux_exit_message(Channel *, int);
diff --git a/compat.c b/compat.c
new file mode 100644 (file)
index 0000000..df3541d
--- /dev/null
+++ b/compat.c
@@ -0,0 +1,237 @@
+/* $OpenBSD: compat.c,v 1.78 2008/09/11 14:22:37 markus Exp $ */
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 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 <sys/types.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "packet.h"
+#include "compat.h"
+#include "log.h"
+#include "match.h"
+
+int compat13 = 0;
+int compat20 = 0;
+int datafellows = 0;
+
+void
+enable_compat20(void)
+{
+       debug("Enabling compatibility mode for protocol 2.0");
+       compat20 = 1;
+}
+void
+enable_compat13(void)
+{
+       debug("Enabling compatibility mode for protocol 1.3");
+       compat13 = 1;
+}
+/* datafellows bug compatibility */
+void
+compat_datafellows(const char *version)
+{
+       int i;
+       static struct {
+               char    *pat;
+               int     bugs;
+       } check[] = {
+               { "OpenSSH-2.0*,"
+                 "OpenSSH-2.1*,"
+                 "OpenSSH_2.1*,"
+                 "OpenSSH_2.2*",       SSH_OLD_SESSIONID|SSH_BUG_BANNER|
+                                       SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+                                       SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.3.0*",     SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES|
+                                       SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+                                       SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.3.*",      SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
+                                       SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+                                       SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.5.0p1*,"
+                 "OpenSSH_2.5.1p1*",
+                                       SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
+                                       SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+                                       SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.5.0*,"
+                 "OpenSSH_2.5.1*,"
+                 "OpenSSH_2.5.2*",     SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
+                                       SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.5.3*",     SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+                                       SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_2.*,"
+                 "OpenSSH_3.0*,"
+                 "OpenSSH_3.1*",       SSH_BUG_EXTEOF|SSH_OLD_FORWARD_ADDR},
+               { "OpenSSH_3.*",        SSH_OLD_FORWARD_ADDR },
+               { "Sun_SSH_1.0*",       SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+               { "OpenSSH_4*",         0 },
+               { "OpenSSH*",           SSH_NEW_OPENSSH },
+               { "*MindTerm*",         0 },
+               { "2.1.0*",             SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE|
+                                       SSH_BUG_FIRSTKEX },
+               { "2.1 *",              SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
+                                       SSH_OLD_SESSIONID|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE|
+                                       SSH_BUG_FIRSTKEX },
+               { "2.0.13*,"
+                 "2.0.14*,"
+                 "2.0.15*,"
+                 "2.0.16*,"
+                 "2.0.17*,"
+                 "2.0.18*,"
+                 "2.0.19*",            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|SSH_BUG_FIRSTKEX },
+               { "2.0.11*,"
+                 "2.0.12*",            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|SSH_BUG_FIRSTKEX },
+               { "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|
+                                       SSH_BUG_FIRSTKEX },
+               { "2.2.0*,"
+                 "2.3.0*",             SSH_BUG_HMAC|SSH_BUG_DEBUG|
+                                       SSH_BUG_RSASIGMD5|SSH_BUG_FIRSTKEX },
+               { "2.3.*",              SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5|
+                                       SSH_BUG_FIRSTKEX },
+               { "2.4",                SSH_OLD_SESSIONID },    /* Van Dyke */
+               { "2.*",                SSH_BUG_DEBUG|SSH_BUG_FIRSTKEX|
+                                       SSH_BUG_RFWD_ADDR },
+               { "3.0.*",              SSH_BUG_DEBUG },
+               { "3.0 SecureCRT*",     SSH_OLD_SESSIONID },
+               { "1.7 SecureFX*",      SSH_OLD_SESSIONID },
+               { "1.2.18*,"
+                 "1.2.19*,"
+                 "1.2.20*,"
+                 "1.2.21*,"
+                 "1.2.22*",            SSH_BUG_IGNOREMSG },
+               { "1.3.2*",             /* F-Secure */
+                                       SSH_BUG_IGNOREMSG },
+               { "*SSH Compatible Server*",                    /* Netscreen */
+                                       SSH_BUG_PASSWORDPAD },
+               { "*OSU_0*,"
+                 "OSU_1.0*,"
+                 "OSU_1.1*,"
+                 "OSU_1.2*,"
+                 "OSU_1.3*,"
+                 "OSU_1.4*,"
+                 "OSU_1.5alpha1*,"
+                 "OSU_1.5alpha2*,"
+                 "OSU_1.5alpha3*",     SSH_BUG_PASSWORDPAD },
+               { "*SSH_Version_Mapper*",
+                                       SSH_BUG_SCANNER },
+               { "Probe-*",
+                                       SSH_BUG_PROBE },
+               { NULL,                 0 }
+       };
+
+       /* process table, return first match */
+       for (i = 0; check[i].pat; i++) {
+               if (match_pattern_list(version, check[i].pat,
+                   strlen(check[i].pat), 0) == 1) {
+                       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:
+                       logit("ignoring bad proto spec: '%s'.", p);
+                       break;
+               }
+       }
+       xfree(s);
+       return ret;
+}
+
+char *
+compat_cipher_proposal(char *cipher_prop)
+{
+       Buffer b;
+       char *orig_prop, *fix_ciphers;
+       char *cp, *tmp;
+
+       if (!(datafellows & SSH_BUG_BIGENDIANAES))
+               return(cipher_prop);
+
+       buffer_init(&b);
+       tmp = orig_prop = xstrdup(cipher_prop);
+       while ((cp = strsep(&tmp, ",")) != NULL) {
+               if (strncmp(cp, "aes", 3) != 0) {
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       buffer_append(&b, cp, strlen(cp));
+               }
+       }
+       buffer_append(&b, "\0", 1);
+       fix_ciphers = xstrdup(buffer_ptr(&b));
+       buffer_free(&b);
+       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/compat.h b/compat.h
new file mode 100644 (file)
index 0000000..16cf282
--- /dev/null
+++ b/compat.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: compat.h,v 1.42 2008/09/11 14:22:37 markus Exp $ */
+
+/*
+ * 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.
+ */
+
+#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
+#define SSH_BUG_EXTEOF         0x00200000
+#define SSH_BUG_PROBE          0x00400000
+#define SSH_BUG_FIRSTKEX       0x00800000
+#define SSH_OLD_FORWARD_ADDR   0x01000000
+#define SSH_BUG_RFWD_ADDR      0x02000000
+#define SSH_NEW_OPENSSH                0x04000000
+
+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/compress.c b/compress.c
new file mode 100644 (file)
index 0000000..24778e5
--- /dev/null
@@ -0,0 +1,167 @@
+/* $OpenBSD: compress.c,v 1.26 2010/09/08 04:13:31 deraadt Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+
+#include "log.h"
+#include "buffer.h"
+#include "compress.h"
+
+#include <zlib.h>
+
+z_stream incoming_stream;
+z_stream outgoing_stream;
+static int compress_init_send_called = 0;
+static int compress_init_recv_called = 0;
+static int inflate_failed = 0;
+static int deflate_failed = 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 %llu, compressed %llu, factor %.2f",
+           (unsigned long long)outgoing_stream.total_in,
+           (unsigned long long)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 %llu, compressed %llu, factor %.2f",
+           (unsigned long long)incoming_stream.total_out,
+           (unsigned long long)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 && inflate_failed == 0)
+               inflateEnd(&incoming_stream);
+       if (compress_init_send_called == 1 && deflate_failed == 0)
+               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)
+{
+       u_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 = 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 = 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:
+                       deflate_failed = 1;
+                       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)
+{
+       u_char buf[4096];
+       int status;
+
+       incoming_stream.next_in = buffer_ptr(input_buffer);
+       incoming_stream.avail_in = buffer_len(input_buffer);
+
+       for (;;) {
+               /* Set up fixed-size output buffer. */
+               incoming_stream.next_out = 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:
+                       inflate_failed = 1;
+                       fatal("buffer_uncompress: inflate returned %d", status);
+                       /* NOTREACHED */
+               }
+       }
+}
diff --git a/compress.h b/compress.h
new file mode 100644 (file)
index 0000000..418d6fd
--- /dev/null
@@ -0,0 +1,25 @@
+/* $OpenBSD: compress.h,v 1.12 2006/03/25 22:22:43 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#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/config.guess b/config.guess
new file mode 100755 (executable)
index 0000000..c2246a4
--- /dev/null
@@ -0,0 +1,1502 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2009-12-30'
+
+# 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., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, 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.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# 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.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+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, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # 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
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       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 ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+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.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep -q __ELF__
+               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
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # 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 ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # 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.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit ;;
+    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 ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    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 ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    s390x:SunOS:*:*)
+       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+       echo i386-pc-auroraux${UNAME_RELEASE}
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       eval $set_cc_for_build
+       SUN_ARCH="i386"
+       # If there is a compiler, see if it is configured for 64-bit objects.
+       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+       # This test works for both compilers.
+       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               grep IS_64BIT_ARCH >/dev/null
+           then
+               SUN_ARCH="x86_64"
+           fi
+       fi
+       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    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 ;;
+    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 ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /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 ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # 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 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       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 -o $dummy $dummy.c &&
+         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+         SYSTEM_NAME=`$dummy $dummyarg` &&
+           { echo "$SYSTEM_NAME"; exit; }
+       echo mips-mips-riscos${UNAME_RELEASE}
+       exit ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+       echo powerpc-harris-powerunix
+       exit ;;
+    m88k:CX/UX:7*:*)
+       echo m88k-harris-cxux7
+       exit ;;
+    m88k:*:4*:R4*)
+       echo m88k-motorola-sysv4
+       exit ;;
+    m88k:*:3*:R3*)
+       echo m88k-motorola-sysv3
+       exit ;;
+    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 ;;
+    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
+       echo m88k-dolphin-sysv3
+       exit ;;
+    M88*:*:R3*:*)
+       # Delta 88k system running SVR3
+       echo m88k-motorola-sysv3
+       exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+       echo m88k-tektronix-sysv3
+       exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+       echo m68k-tektronix-bsd
+       exit ;;
+    *:IRIX*:*:*)
+       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+       exit ;;
+    ????????: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 ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+       echo i386-ibm-aix
+       exit ;;
+    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 ;;
+    *:AIX:2:3)
+       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
+               sed 's/^                //' << EOF >$dummy.c
+               #include <sys/systemcfg.h>
+
+               main()
+                       {
+                       if (!__power_pc())
+                               exit(1);
+                       puts("powerpc-ibm-aix3.2.5");
+                       exit(0);
+                       }
+EOF
+               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+               then
+                       echo "$SYSTEM_NAME"
+               else
+                       echo rs6000-ibm-aix3.2.5
+               fi
+       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 ;;
+    *:AIX:*:[456])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | 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 ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    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])
+               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" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   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 -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
+       esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           eval $set_cc_for_build
+
+           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+           # generating 64-bit code.  GNU and HP use different nomenclature:
+           #
+           # $ CC_FOR_BUILD=cc ./config.guess
+           # => hppa2.0w-hp-hpux11.23
+           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+           # => hppa64-hp-hpux11.23
+
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+               grep -q __LP64__
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       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 -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+               { echo "$SYSTEM_NAME"; exit; }
+       echo unknown-hitachi-hiuxwe2
+       exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+       echo hppa1.1-hp-bsd
+       exit ;;
+    9000/8??:4.3bsd:*:*)
+       echo hppa1.0-hp-bsd
+       exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+       echo hppa1.0-hp-mpeix
+       exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+       echo hppa1.1-hp-osf
+       exit ;;
+    hp8??:OSF1:*:*)
+       echo hppa1.0-hp-osf
+       exit ;;
+    i*86:OSF1:*:*)
+       if [ -x /usr/sbin/sysversion ] ; then
+           echo ${UNAME_MACHINE}-unknown-osf1mk
+       else
+           echo ${UNAME_MACHINE}-unknown-osf1
+       fi
+       exit ;;
+    parisc*:Lites*:*:*)
+       echo hppa1.1-hp-lites
+       exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+       echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+       echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+       echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+       echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*[A-Z]90:*:*:*)
+       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*TS:*:*:*)
+       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*T3E:*:*:*)
+       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    CRAY*SV1:*:*:*)
+       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit ;;
+    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 ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+       exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+       exit ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:BSD/OS:*:*)
+       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+       exit ;;
+    *:FreeBSD:*:*)
+       case ${UNAME_MACHINE} in
+           pc98)
+               echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           amd64)
+               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           authenticamd | genuineintel | EM64T)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    8664:Windows_NT:*)
+       echo x86_64-pc-mks
+       exit ;;
+    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 i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep -q ld.so.1
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-gnu
+       else
+           echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    cris:Linux:*:*)
+       echo cris-axis-linux-gnu
+       exit ;;
+    crisv32:Linux:*:*)
+       echo crisv32-axis-linux-gnu
+       exit ;;
+    frv:Linux:*:*)
+       echo frv-unknown-linux-gnu
+       exit ;;
+    i*86:Linux:*:*)
+       LIBC=gnu
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+       echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef ${UNAME_MACHINE}
+       #undef ${UNAME_MACHINE}el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=${UNAME_MACHINE}el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=${UNAME_MACHINE}
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    or32:Linux:*:*)
+       echo or32-unknown-linux-gnu
+       exit ;;
+    padre:Linux:*:*)
+       echo sparc-unknown-linux-gnu
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit ;;
+    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 ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-gnu
+       exit ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    i*86:DYNIX/ptx:4*:*)
+       # 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.
+       echo i386-sequent-sysv4
+       exit ;;
+    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 ;;
+    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 ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    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 ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    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|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+                       && UNAME_MACHINE=i586
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+       else
+               echo ${UNAME_MACHINE}-pc-sysv32
+       fi
+       exit ;;
+    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 i586.
+       # Note: whatever this is, it MUST be the same as what config.sub
+       # prints for the "djgpp" host, or else GDB configury will decide that
+       # this is a cross-build.
+       echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    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 ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*: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; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+       OS_REL='.3'
+       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; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *: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 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+       # From Gerald Hewes <hewes@openmarket.com>.
+       # How about differentiating between stratus architectures? -djm
+       echo hppa1.1-stratus-sysv4
+       exit ;;
+    *:*:*:FTX*)
+       # From seanf@swdc.stratus.com.
+       echo i860-stratus-sysv4
+       exit ;;
+    i*86:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo ${UNAME_MACHINE}-stratus-vos
+       exit ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit ;;
+    mc68*:A/UX:*:*)
+       echo m68k-apple-aux${UNAME_RELEASE}
+       exit ;;
+    news*:NEWS-OS:6*:*)
+       echo mips-sony-newsos6
+       exit ;;
+    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 ;;
+    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
+       echo powerpc-be-beos
+       exit ;;
+    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
+       echo powerpc-apple-beos
+       exit ;;
+    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
+       echo i586-pc-beos
+       exit ;;
+    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
+       echo i586-pc-haiku
+       exit ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       case $UNAME_PROCESSOR in
+           i386)
+               eval $set_cc_for_build
+               if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+                 if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+                     (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                     grep IS_64BIT_ARCH >/dev/null
+                 then
+                     UNAME_PROCESSOR="x86_64"
+                 fi
+               fi ;;
+           unknown) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *: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 ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+    i*86:AROS:*:*)
+       echo ${UNAME_MACHINE}-pc-aros
+       exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+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\n"); 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 -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+       { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# 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 ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    c34*)
+       echo c34-convex-bsd
+       exit ;;
+    c38*)
+       echo c38-convex-bsd
+       exit ;;
+    c4*)
+       echo c4-convex-bsd
+       exit ;;
+    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
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+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/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..e5c9379
--- /dev/null
@@ -0,0 +1,1495 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if you have a getaddrinfo that fails for the all-zeros IPv6 address
+   */
+#undef AIX_GETNAMEINFO_HACK
+
+/* Define if your AIX loginfailed() function takes 4 arguments (AIX >= 5.2) */
+#undef AIX_LOGINFAILED_4ARG
+
+/* System only supports IPv4 audit records */
+#undef AU_IPv4
+
+/* Define if your resolver libs need this for getrrsetbyname */
+#undef BIND_8_COMPAT
+
+/* Define if cmsg_type is not passed correctly */
+#undef BROKEN_CMSG_TYPE
+
+/* getaddrinfo is broken (if present) */
+#undef BROKEN_GETADDRINFO
+
+/* getgroups(0,NULL) will return -1 */
+#undef BROKEN_GETGROUPS
+
+/* FreeBSD glob does not do what we need */
+#undef BROKEN_GLOB
+
+/* Define if you system's inet_ntoa is busted (e.g. Irix gcc issue) */
+#undef BROKEN_INET_NTOA
+
+/* ia_uinfo routines not supported by OS yet */
+#undef BROKEN_LIBIAF
+
+/* Ultrix mmap can't map files */
+#undef BROKEN_MMAP
+
+/* Define if your struct dirent expects you to allocate extra space for d_name
+   */
+#undef BROKEN_ONE_BYTE_DIRENT_D_NAME
+
+/* Can't do comparisons on readv */
+#undef BROKEN_READV_COMPARISON
+
+/* Define if you have a broken realpath. */
+#undef BROKEN_REALPATH
+
+/* Needed for NeXT */
+#undef BROKEN_SAVED_UIDS
+
+/* Define if your setregid() is broken */
+#undef BROKEN_SETREGID
+
+/* Define if your setresgid() is broken */
+#undef BROKEN_SETRESGID
+
+/* Define if your setresuid() is broken */
+#undef BROKEN_SETRESUID
+
+/* Define if your setreuid() is broken */
+#undef BROKEN_SETREUID
+
+/* LynxOS has broken setvbuf() implementation */
+#undef BROKEN_SETVBUF
+
+/* QNX shadow support is broken */
+#undef BROKEN_SHADOW_EXPIRE
+
+/* Define if your snprintf is busted */
+#undef BROKEN_SNPRINTF
+
+/* tcgetattr with ICANON may hang */
+#undef BROKEN_TCGETATTR_ICANON
+
+/* updwtmpx is broken (if present) */
+#undef BROKEN_UPDWTMPX
+
+/* Define if you have BSD auth support */
+#undef BSD_AUTH
+
+/* 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 wtmpx file */
+#undef CONF_WTMPX_FILE
+
+/* Define if you want to specify the path to your wtmp file */
+#undef CONF_WTMP_FILE
+
+/* Define if your platform needs to skip post auth file descriptor passing */
+#undef DISABLE_FD_PASSING
+
+/* Define if you don't want to use lastlog */
+#undef DISABLE_LASTLOG
+
+/* 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 want to disable shadow passwords */
+#undef DISABLE_SHADOW
+
+/* 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
+
+/* Enable for PKCS#11 support */
+#undef ENABLE_PKCS11
+
+/* Builtin PRNG command timeout */
+#undef ENTROPY_TIMEOUT_MSEC
+
+/* File names may not contain backslash characters */
+#undef FILESYSTEM_NO_BACKSLASH
+
+/* fsid_t has member val */
+#undef FSID_HAS_VAL
+
+/* fsid_t has member __val */
+#undef FSID_HAS___VAL
+
+/* Define to 1 if the `getpgrp' function requires zero arguments. */
+#undef GETPGRP_VOID
+
+/* Conflicting defs for getspnam */
+#undef GETSPNAM_CONFLICTING_DEFS
+
+/* 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 if your system glob() function has gl_statv options in glob_t */
+#undef GLOB_HAS_GL_STATV
+
+/* Define this if you want GSSAPI support in the version 2 protocol */
+#undef GSSAPI
+
+/* Define if you want to use shadow password expire field */
+#undef HAS_SHADOW_EXPIRE
+
+/* Define if your system uses access rights style file descriptor passing */
+#undef HAVE_ACCRIGHTS_IN_MSGHDR
+
+/* Define if you have ut_addr in utmp.h */
+#undef HAVE_ADDR_IN_UTMP
+
+/* Define if you have ut_addr in utmpx.h */
+#undef HAVE_ADDR_IN_UTMPX
+
+/* Define if you have ut_addr_v6 in utmp.h */
+#undef HAVE_ADDR_V6_IN_UTMP
+
+/* Define if you have ut_addr_v6 in utmpx.h */
+#undef HAVE_ADDR_V6_IN_UTMPX
+
+/* Define to 1 if you have the `arc4random' function. */
+#undef HAVE_ARC4RANDOM
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#undef HAVE_ARC4RANDOM_BUF
+
+/* Define to 1 if you have the `arc4random_uniform' function. */
+#undef HAVE_ARC4RANDOM_UNIFORM
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* OpenBSD's gcc has bounded */
+#undef HAVE_ATTRIBUTE__BOUNDED__
+
+/* Have attribute nonnull */
+#undef HAVE_ATTRIBUTE__NONNULL__
+
+/* OpenBSD's gcc has sentinel */
+#undef HAVE_ATTRIBUTE__SENTINEL__
+
+/* Define to 1 if you have the `aug_get_machine' function. */
+#undef HAVE_AUG_GET_MACHINE
+
+/* Define to 1 if you have the `b64_ntop' function. */
+#undef HAVE_B64_NTOP
+
+/* Define to 1 if you have the `b64_pton' function. */
+#undef HAVE_B64_PTON
+
+/* Define if you have the basename function. */
+#undef HAVE_BASENAME
+
+/* Define to 1 if you have the `bcopy' function. */
+#undef HAVE_BCOPY
+
+/* Define to 1 if you have the `bindresvport_sa' function. */
+#undef HAVE_BINDRESVPORT_SA
+
+/* Define to 1 if you have the `BN_is_prime_ex' function. */
+#undef HAVE_BN_IS_PRIME_EX
+
+/* Define to 1 if you have the <bsm/audit.h> header file. */
+#undef HAVE_BSM_AUDIT_H
+
+/* Define to 1 if you have the <bstring.h> header file. */
+#undef HAVE_BSTRING_H
+
+/* Define to 1 if you have the `clock' function. */
+#undef HAVE_CLOCK
+
+/* define if you have clock_t data type */
+#undef HAVE_CLOCK_T
+
+/* Define to 1 if you have the `closefrom' function. */
+#undef HAVE_CLOSEFROM
+
+/* Define if gai_strerror() returns const char * */
+#undef HAVE_CONST_GAI_STRERROR_PROTO
+
+/* Define if your system uses ancillary data style file descriptor passing */
+#undef HAVE_CONTROL_IN_MSGHDR
+
+/* Define to 1 if you have the <crypto/sha2.h> header file. */
+#undef HAVE_CRYPTO_SHA2_H
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Define if you are on Cygwin */
+#undef HAVE_CYGWIN
+
+/* Define if your libraries define daemon() */
+#undef HAVE_DAEMON
+
+/* Define to 1 if you have the declaration of `authenticate', and to 0 if you
+   don't. */
+#undef HAVE_DECL_AUTHENTICATE
+
+/* Define to 1 if you have the declaration of `GLOB_NOMATCH', and to 0 if you
+   don't. */
+#undef HAVE_DECL_GLOB_NOMATCH
+
+/* Define to 1 if you have the declaration of `h_errno', and to 0 if you
+   don't. */
+#undef HAVE_DECL_H_ERRNO
+
+/* Define to 1 if you have the declaration of `loginfailed', and to 0 if you
+   don't. */
+#undef HAVE_DECL_LOGINFAILED
+
+/* Define to 1 if you have the declaration of `loginrestrictions', and to 0 if
+   you don't. */
+#undef HAVE_DECL_LOGINRESTRICTIONS
+
+/* Define to 1 if you have the declaration of `loginsuccess', and to 0 if you
+   don't. */
+#undef HAVE_DECL_LOGINSUCCESS
+
+/* Define to 1 if you have the declaration of `MAXSYMLINKS', and to 0 if you
+   don't. */
+#undef HAVE_DECL_MAXSYMLINKS
+
+/* Define to 1 if you have the declaration of `offsetof', and to 0 if you
+   don't. */
+#undef HAVE_DECL_OFFSETOF
+
+/* Define to 1 if you have the declaration of `O_NONBLOCK', and to 0 if you
+   don't. */
+#undef HAVE_DECL_O_NONBLOCK
+
+/* Define to 1 if you have the declaration of `passwdexpired', and to 0 if you
+   don't. */
+#undef HAVE_DECL_PASSWDEXPIRED
+
+/* Define to 1 if you have the declaration of `setauthdb', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SETAUTHDB
+
+/* Define to 1 if you have the declaration of `SHUT_RD', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SHUT_RD
+
+/* Define to 1 if you have the declaration of `writev', and to 0 if you don't.
+   */
+#undef HAVE_DECL_WRITEV
+
+/* Define to 1 if you have the declaration of `_getlong', and to 0 if you
+   don't. */
+#undef HAVE_DECL__GETLONG
+
+/* Define to 1 if you have the declaration of `_getshort', and to 0 if you
+   don't. */
+#undef HAVE_DECL__GETSHORT
+
+/* Define if you have /dev/ptmx */
+#undef HAVE_DEV_PTMX
+
+/* Define if you have /dev/ptc */
+#undef HAVE_DEV_PTS_AND_PTC
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the `dirfd' function. */
+#undef HAVE_DIRFD
+
+/* Define to 1 if you have the `dirname' function. */
+#undef HAVE_DIRNAME
+
+/* Define to 1 if you have the `DSA_generate_parameters_ex' function. */
+#undef HAVE_DSA_GENERATE_PARAMETERS_EX
+
+/* Define to 1 if you have the <endian.h> header file. */
+#undef HAVE_ENDIAN_H
+
+/* Define to 1 if you have the `endutent' function. */
+#undef HAVE_ENDUTENT
+
+/* Define to 1 if you have the `endutxent' function. */
+#undef HAVE_ENDUTXENT
+
+/* Define if your system has /etc/default/login */
+#undef HAVE_ETC_DEFAULT_LOGIN
+
+/* Define to 1 if you have the `EVP_sha256' function. */
+#undef HAVE_EVP_SHA256
+
+/* Define if you have ut_exit in utmp.h */
+#undef HAVE_EXIT_IN_UTMP
+
+/* Define to 1 if you have the `fchmod' function. */
+#undef HAVE_FCHMOD
+
+/* Define to 1 if you have the `fchown' function. */
+#undef HAVE_FCHOWN
+
+/* Use F_CLOSEM fcntl for closefrom */
+#undef HAVE_FCNTL_CLOSEM
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <features.h> header file. */
+#undef HAVE_FEATURES_H
+
+/* Define to 1 if you have the <floatingpoint.h> header file. */
+#undef HAVE_FLOATINGPOINT_H
+
+/* Define to 1 if you have the `fmt_scaled' function. */
+#undef HAVE_FMT_SCALED
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if the system has the type `fsblkcnt_t'. */
+#undef HAVE_FSBLKCNT_T
+
+/* Define to 1 if the system has the type `fsfilcnt_t'. */
+#undef HAVE_FSFILCNT_T
+
+/* Define to 1 if you have the `fstatvfs' function. */
+#undef HAVE_FSTATVFS
+
+/* Define to 1 if you have the `futimes' function. */
+#undef HAVE_FUTIMES
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#undef HAVE_GAI_STRERROR
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if you have the `getaudit' function. */
+#undef HAVE_GETAUDIT
+
+/* Define to 1 if you have the `getaudit_addr' function. */
+#undef HAVE_GETAUDIT_ADDR
+
+/* Define to 1 if you have the `getcwd' function. */
+#undef HAVE_GETCWD
+
+/* Define to 1 if you have the `getgrouplist' function. */
+#undef HAVE_GETGROUPLIST
+
+/* Define to 1 if you have the `getgrset' function. */
+#undef HAVE_GETGRSET
+
+/* Define to 1 if you have the `getlastlogxbyname' function. */
+#undef HAVE_GETLASTLOGXBYNAME
+
+/* Define to 1 if you have the `getluid' function. */
+#undef HAVE_GETLUID
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if your getopt(3) defines and uses optreset */
+#undef HAVE_GETOPT_OPTRESET
+
+/* Define if your libraries define getpagesize() */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getpeereid' function. */
+#undef HAVE_GETPEEREID
+
+/* Define to 1 if you have the `getpeerucred' function. */
+#undef HAVE_GETPEERUCRED
+
+/* Define to 1 if you have the `getpwanam' function. */
+#undef HAVE_GETPWANAM
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define if getrrsetbyname() exists */
+#undef HAVE_GETRRSETBYNAME
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `getseuserbyname' function. */
+#undef HAVE_GETSEUSERBYNAME
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `getttyent' function. */
+#undef HAVE_GETTTYENT
+
+/* Define to 1 if you have the `getutent' function. */
+#undef HAVE_GETUTENT
+
+/* Define to 1 if you have the `getutid' function. */
+#undef HAVE_GETUTID
+
+/* Define to 1 if you have the `getutline' function. */
+#undef HAVE_GETUTLINE
+
+/* Define to 1 if you have the `getutxent' function. */
+#undef HAVE_GETUTXENT
+
+/* Define to 1 if you have the `getutxid' function. */
+#undef HAVE_GETUTXID
+
+/* Define to 1 if you have the `getutxline' function. */
+#undef HAVE_GETUTXLINE
+
+/* Define to 1 if you have the `getutxuser' function. */
+#undef HAVE_GETUTXUSER
+
+/* Define to 1 if you have the `get_default_context_with_level' function. */
+#undef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+
+/* Define to 1 if you have the `glob' function. */
+#undef HAVE_GLOB
+
+/* Define to 1 if you have the <glob.h> header file. */
+#undef HAVE_GLOB_H
+
+/* Define to 1 if you have the `group_from_gid' function. */
+#undef HAVE_GROUP_FROM_GID
+
+/* Define to 1 if you have the <gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_KRB5_H
+
+/* Define if HEADER.ad exists in arpa/nameser.h */
+#undef HAVE_HEADER_AD
+
+/* Define if you have ut_host in utmp.h */
+#undef HAVE_HOST_IN_UTMP
+
+/* Define if you have ut_host in utmpx.h */
+#undef HAVE_HOST_IN_UTMPX
+
+/* Define to 1 if you have the <iaf.h> header file. */
+#undef HAVE_IAF_H
+
+/* Define to 1 if you have the <ia.h> header file. */
+#undef HAVE_IA_H
+
+/* Define if you have ut_id in utmp.h */
+#undef HAVE_ID_IN_UTMP
+
+/* Define if you have ut_id in utmpx.h */
+#undef HAVE_ID_IN_UTMPX
+
+/* Define to 1 if you have the `inet_aton' function. */
+#undef HAVE_INET_ATON
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#undef HAVE_INET_NTOA
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have the `innetgr' function. */
+#undef HAVE_INNETGR
+
+/* define if you have int64_t data type */
+#undef HAVE_INT64_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* define if you have intxx_t data type */
+#undef HAVE_INTXX_T
+
+/* Define to 1 if the system has the type `in_addr_t'. */
+#undef HAVE_IN_ADDR_T
+
+/* Define to 1 if the system has the type `in_port_t'. */
+#undef HAVE_IN_PORT_T
+
+/* Define if you have isblank(3C). */
+#undef HAVE_ISBLANK
+
+/* Define to 1 if you have the <lastlog.h> header file. */
+#undef HAVE_LASTLOG_H
+
+/* Define to 1 if you have the <libaudit.h> header file. */
+#undef HAVE_LIBAUDIT_H
+
+/* Define to 1 if you have the `bsm' library (-lbsm). */
+#undef HAVE_LIBBSM
+
+/* Define to 1 if you have the `crypt' library (-lcrypt). */
+#undef HAVE_LIBCRYPT
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+#undef HAVE_LIBDL
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define if system has libiaf that supports set_id */
+#undef HAVE_LIBIAF
+
+/* Define to 1 if you have the `network' library (-lnetwork). */
+#undef HAVE_LIBNETWORK
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+#undef HAVE_LIBPAM
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <libutil.h> header file. */
+#undef HAVE_LIBUTIL_H
+
+/* Define to 1 if you have the `xnet' library (-lxnet). */
+#undef HAVE_LIBXNET
+
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <linux/if_tun.h> header file. */
+#undef HAVE_LINUX_IF_TUN_H
+
+/* Define if your libraries define login() */
+#undef HAVE_LOGIN
+
+/* Define to 1 if you have the <login_cap.h> header file. */
+#undef HAVE_LOGIN_CAP_H
+
+/* Define to 1 if you have the `login_getcapbool' function. */
+#undef HAVE_LOGIN_GETCAPBOOL
+
+/* Define to 1 if you have the <login.h> header file. */
+#undef HAVE_LOGIN_H
+
+/* Define to 1 if you have the `logout' function. */
+#undef HAVE_LOGOUT
+
+/* Define to 1 if you have the `logwtmp' function. */
+#undef HAVE_LOGWTMP
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the <maillock.h> header file. */
+#undef HAVE_MAILLOCK_H
+
+/* Define to 1 if you have the `md5_crypt' function. */
+#undef HAVE_MD5_CRYPT
+
+/* Define if you want to allow MD5 passwords */
+#undef HAVE_MD5_PASSWORDS
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#undef HAVE_MKDTEMP
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* define if you have mode_t data type */
+#undef HAVE_MODE_T
+
+/* Some systems put nanosleep outside of libc */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netgroup.h> header file. */
+#undef HAVE_NETGROUP_H
+
+/* Define to 1 if you have the <net/if_tun.h> header file. */
+#undef HAVE_NET_IF_TUN_H
+
+/* Define if you are on NeXT */
+#undef HAVE_NEXT
+
+/* Define to 1 if you have the `ngetaddrinfo' function. */
+#undef HAVE_NGETADDRINFO
+
+/* Define to 1 if you have the `nsleep' function. */
+#undef HAVE_NSLEEP
+
+/* Define to 1 if you have the `ogetaddrinfo' function. */
+#undef HAVE_OGETADDRINFO
+
+/* Define if you have an old version of PAM which takes only one argument to
+   pam_strerror */
+#undef HAVE_OLD_PAM
+
+/* Define to 1 if you have the `openlog_r' function. */
+#undef HAVE_OPENLOG_R
+
+/* Define to 1 if you have the `openpty' function. */
+#undef HAVE_OPENPTY
+
+/* Define if your ssl headers are included with #include <openssl/header.h> */
+#undef HAVE_OPENSSL
+
+/* Define if you have Digital Unix Security Integration Architecture */
+#undef HAVE_OSF_SIA
+
+/* Define to 1 if you have the `pam_getenvlist' function. */
+#undef HAVE_PAM_GETENVLIST
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+#undef HAVE_PAM_PAM_APPL_H
+
+/* Define to 1 if you have the `pam_putenv' function. */
+#undef HAVE_PAM_PUTENV
+
+/* Define to 1 if you have the <paths.h> header file. */
+#undef HAVE_PATHS_H
+
+/* Define if you have ut_pid in utmp.h */
+#undef HAVE_PID_IN_UTMP
+
+/* define if you have pid_t data type */
+#undef HAVE_PID_T
+
+/* Define to 1 if you have the `poll' function. */
+#undef HAVE_POLL
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if you have the `prctl' function. */
+#undef HAVE_PRCTL
+
+/* Define if you have /proc/$pid/fd */
+#undef HAVE_PROC_PID
+
+/* Define to 1 if you have the `pstat' function. */
+#undef HAVE_PSTAT
+
+/* Define to 1 if you have the <pty.h> header file. */
+#undef HAVE_PTY_H
+
+/* Define to 1 if you have the `pututline' function. */
+#undef HAVE_PUTUTLINE
+
+/* Define to 1 if you have the `pututxline' function. */
+#undef HAVE_PUTUTXLINE
+
+/* Define if your password has a pw_change field */
+#undef HAVE_PW_CHANGE_IN_PASSWD
+
+/* 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 to 1 if you have the `readpassphrase' function. */
+#undef HAVE_READPASSPHRASE
+
+/* Define to 1 if you have the <readpassphrase.h> header file. */
+#undef HAVE_READPASSPHRASE_H
+
+/* Define to 1 if you have the `realpath' function. */
+#undef HAVE_REALPATH
+
+/* Define to 1 if you have the `recvmsg' function. */
+#undef HAVE_RECVMSG
+
+/* Define to 1 if you have the <rpc/types.h> header file. */
+#undef HAVE_RPC_TYPES_H
+
+/* Define to 1 if you have the `rresvport_af' function. */
+#undef HAVE_RRESVPORT_AF
+
+/* Define to 1 if you have the `RSA_generate_key_ex' function. */
+#undef HAVE_RSA_GENERATE_KEY_EX
+
+/* Define to 1 if you have the `RSA_get_default_method' function. */
+#undef HAVE_RSA_GET_DEFAULT_METHOD
+
+/* define if you have sa_family_t data type */
+#undef HAVE_SA_FAMILY_T
+
+/* Define if you have SecureWare-based protected password database */
+#undef HAVE_SECUREWARE
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#undef HAVE_SECURITY_PAM_APPL_H
+
+/* Define to 1 if you have the `sendmsg' function. */
+#undef HAVE_SENDMSG
+
+/* Define to 1 if you have the `setauthdb' function. */
+#undef HAVE_SETAUTHDB
+
+/* Define to 1 if you have the `setdtablesize' function. */
+#undef HAVE_SETDTABLESIZE
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the `setgroupent' function. */
+#undef HAVE_SETGROUPENT
+
+/* Define to 1 if you have the `setgroups' function. */
+#undef HAVE_SETGROUPS
+
+/* Define to 1 if you have the `setlogin' function. */
+#undef HAVE_SETLOGIN
+
+/* Define to 1 if you have the `setluid' function. */
+#undef HAVE_SETLUID
+
+/* Define to 1 if you have the `setpassent' function. */
+#undef HAVE_SETPASSENT
+
+/* Define to 1 if you have the `setpcred' function. */
+#undef HAVE_SETPCRED
+
+/* Define to 1 if you have the `setproctitle' function. */
+#undef HAVE_SETPROCTITLE
+
+/* Define to 1 if you have the `setregid' function. */
+#undef HAVE_SETREGID
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the `setreuid' function. */
+#undef HAVE_SETREUID
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the `setsid' function. */
+#undef HAVE_SETSID
+
+/* Define to 1 if you have the `setutent' function. */
+#undef HAVE_SETUTENT
+
+/* Define to 1 if you have the `setutxdb' function. */
+#undef HAVE_SETUTXDB
+
+/* Define to 1 if you have the `setutxent' function. */
+#undef HAVE_SETUTXENT
+
+/* Define to 1 if you have the `setvbuf' function. */
+#undef HAVE_SETVBUF
+
+/* Define to 1 if you have the `set_id' function. */
+#undef HAVE_SET_ID
+
+/* Define to 1 if you have the `SHA256_Update' function. */
+#undef HAVE_SHA256_UPDATE
+
+/* Define to 1 if you have the <sha2.h> header file. */
+#undef HAVE_SHA2_H
+
+/* Define to 1 if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigvec' function. */
+#undef HAVE_SIGVEC
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#undef HAVE_SIG_ATOMIC_T
+
+/* define if you have size_t data type */
+#undef HAVE_SIZE_T
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `socketpair' function. */
+#undef HAVE_SOCKETPAIR
+
+/* Have PEERCRED socket option */
+#undef HAVE_SO_PEERCRED
+
+/* define if you have ssize_t data type */
+#undef HAVE_SSIZE_T
+
+/* Fields in struct sockaddr_storage */
+#undef HAVE_SS_FAMILY_IN_SS
+
+/* Define to 1 if you have the `statfs' function. */
+#undef HAVE_STATFS
+
+/* Define to 1 if you have the `statvfs' function. */
+#undef HAVE_STATVFS
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strftime' function. */
+#undef HAVE_STRFTIME
+
+/* Silly mkstemp() */
+#undef HAVE_STRICT_MKSTEMP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strmode' function. */
+#undef HAVE_STRMODE
+
+/* Define to 1 if you have the `strnvis' function. */
+#undef HAVE_STRNVIS
+
+/* Define to 1 if you have the `strptime' function. */
+#undef HAVE_STRPTIME
+
+/* Define to 1 if you have the `strsep' function. */
+#undef HAVE_STRSEP
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtonum' function. */
+#undef HAVE_STRTONUM
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* define if you have struct addrinfo data type */
+#undef HAVE_STRUCT_ADDRINFO
+
+/* define if you have struct in6_addr data type */
+#undef HAVE_STRUCT_IN6_ADDR
+
+/* define if you have struct sockaddr_in6 data type */
+#undef HAVE_STRUCT_SOCKADDR_IN6
+
+/* Define to 1 if `sin6_scope_id' is member of `struct sockaddr_in6'. */
+#undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+
+/* define if you have struct sockaddr_storage data type */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_BLKSIZE
+
+/* Define to 1 if the system has the type `struct timespec'. */
+#undef HAVE_STRUCT_TIMESPEC
+
+/* define if you have struct timeval */
+#undef HAVE_STRUCT_TIMEVAL
+
+/* Define to 1 if you have the `swap32' function. */
+#undef HAVE_SWAP32
+
+/* Define to 1 if you have the `sysconf' function. */
+#undef HAVE_SYSCONF
+
+/* Define if you have syslen in utmpx.h */
+#undef HAVE_SYSLEN_IN_UTMPX
+
+/* Define to 1 if you have the <sys/audit.h> header file. */
+#undef HAVE_SYS_AUDIT_H
+
+/* Define to 1 if you have the <sys/bitypes.h> header file. */
+#undef HAVE_SYS_BITYPES_H
+
+/* Define to 1 if you have the <sys/bsdtty.h> header file. */
+#undef HAVE_SYS_BSDTTY_H
+
+/* Define to 1 if you have the <sys/cdefs.h> header file. */
+#undef HAVE_SYS_CDEFS_H
+
+/* Define to 1 if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if your system defines sys_errlist[] */
+#undef HAVE_SYS_ERRLIST
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if your system defines sys_nerr */
+#undef HAVE_SYS_NERR
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#undef HAVE_SYS_PRCTL_H
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+#undef HAVE_SYS_PSTAT_H
+
+/* Define to 1 if you have the <sys/ptms.h> header file. */
+#undef HAVE_SYS_PTMS_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/statvfs.h> header file. */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/stream.h> header file. */
+#undef HAVE_SYS_STREAM_H
+
+/* Define to 1 if you have the <sys/stropts.h> header file. */
+#undef HAVE_SYS_STROPTS_H
+
+/* Define to 1 if you have the <sys/strtio.h> header file. */
+#undef HAVE_SYS_STRTIO_H
+
+/* Force use of sys/syslog.h on Ultrix */
+#undef HAVE_SYS_SYSLOG_H
+
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#undef HAVE_SYS_SYSMACROS_H
+
+/* Define to 1 if you have the <sys/timers.h> header file. */
+#undef HAVE_SYS_TIMERS_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the `tcgetpgrp' function. */
+#undef HAVE_TCGETPGRP
+
+/* Define to 1 if you have the `tcsendbreak' function. */
+#undef HAVE_TCSENDBREAK
+
+/* Define to 1 if you have the `time' function. */
+#undef HAVE_TIME
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define if you have ut_time in utmp.h */
+#undef HAVE_TIME_IN_UTMP
+
+/* Define if you have ut_time in utmpx.h */
+#undef HAVE_TIME_IN_UTMPX
+
+/* Define to 1 if you have the `timingsafe_bcmp' function. */
+#undef HAVE_TIMINGSAFE_BCMP
+
+/* Define to 1 if you have the <tmpdir.h> header file. */
+#undef HAVE_TMPDIR_H
+
+/* Define to 1 if you have the `truncate' function. */
+#undef HAVE_TRUNCATE
+
+/* Define to 1 if you have the <ttyent.h> header file. */
+#undef HAVE_TTYENT_H
+
+/* Define if you have ut_tv in utmp.h */
+#undef HAVE_TV_IN_UTMP
+
+/* Define if you have ut_tv in utmpx.h */
+#undef HAVE_TV_IN_UTMPX
+
+/* Define if you have ut_type in utmp.h */
+#undef HAVE_TYPE_IN_UTMP
+
+/* Define if you have ut_type in utmpx.h */
+#undef HAVE_TYPE_IN_UTMPX
+
+/* Define to 1 if you have the <ucred.h> header file. */
+#undef HAVE_UCRED_H
+
+/* define if you have uintxx_t data type */
+#undef HAVE_UINTXX_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `unsetenv' function. */
+#undef HAVE_UNSETENV
+
+/* Define to 1 if the system has the type `unsigned long long'. */
+#undef HAVE_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the `updwtmp' function. */
+#undef HAVE_UPDWTMP
+
+/* Define to 1 if you have the `updwtmpx' function. */
+#undef HAVE_UPDWTMPX
+
+/* Define to 1 if you have the <usersec.h> header file. */
+#undef HAVE_USERSEC_H
+
+/* Define to 1 if you have the `user_from_uid' function. */
+#undef HAVE_USER_FROM_UID
+
+/* Define to 1 if you have the <util.h> header file. */
+#undef HAVE_UTIL_H
+
+/* Define to 1 if you have the `utimes' function. */
+#undef HAVE_UTIMES
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the `utmpname' function. */
+#undef HAVE_UTMPNAME
+
+/* Define to 1 if you have the `utmpxname' function. */
+#undef HAVE_UTMPXNAME
+
+/* Define to 1 if you have the <utmpx.h> header file. */
+#undef HAVE_UTMPX_H
+
+/* Define to 1 if you have the <utmp.h> header file. */
+#undef HAVE_UTMP_H
+
+/* define if you have u_char data type */
+#undef HAVE_U_CHAR
+
+/* define if you have u_int data type */
+#undef HAVE_U_INT
+
+/* define if you have u_int64_t data type */
+#undef HAVE_U_INT64_T
+
+/* define if you have u_intxx_t data type */
+#undef HAVE_U_INTXX_T
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define if va_copy exists */
+#undef HAVE_VA_COPY
+
+/* Define to 1 if you have the `vhangup' function. */
+#undef HAVE_VHANGUP
+
+/* Define to 1 if you have the <vis.h> header file. */
+#undef HAVE_VIS_H
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 if you have the `waitpid' function. */
+#undef HAVE_WAITPID
+
+/* Define to 1 if you have the `_getlong' function. */
+#undef HAVE__GETLONG
+
+/* Define to 1 if you have the `_getpty' function. */
+#undef HAVE__GETPTY
+
+/* Define to 1 if you have the `_getshort' function. */
+#undef HAVE__GETSHORT
+
+/* Define if you have struct __res_state _res as an extern */
+#undef HAVE__RES_EXTERN
+
+/* Define to 1 if you have the `__b64_ntop' function. */
+#undef HAVE___B64_NTOP
+
+/* Define to 1 if you have the `__b64_pton' function. */
+#undef HAVE___B64_PTON
+
+/* Define if compiler implements __FUNCTION__ */
+#undef HAVE___FUNCTION__
+
+/* Define if libc defines __progname */
+#undef HAVE___PROGNAME
+
+/* Fields in struct sockaddr_storage */
+#undef HAVE___SS_FAMILY_IN_SS
+
+/* Define if __va_copy exists */
+#undef HAVE___VA_COPY
+
+/* Define if compiler implements __func__ */
+#undef HAVE___func__
+
+/* Define this if you are using the Heimdal version of Kerberos V5 */
+#undef HEIMDAL
+
+/* Define if you need to use IP address instead of hostname in $DISPLAY */
+#undef IPADDR_IN_DISPLAY
+
+/* Detect IPv4 in IPv6 mapped addresses and treat as IPv4 */
+#undef IPV4_IN_IPV6
+
+/* Define if your system choked on IP TOS setting */
+#undef IP_TOS_IS_BROKEN
+
+/* Define if you want Kerberos 5 support */
+#undef KRB5
+
+/* Define if pututxline updates lastlog too */
+#undef LASTLOG_WRITE_PUTUTXLINE
+
+/* Define if you want TCP Wrappers support */
+#undef LIBWRAP
+
+/* Define to whatever link() returns for "not supported" if it doesn't return
+   EOPNOTSUPP. */
+#undef LINK_OPNOTSUPP_ERRNO
+
+/* Adjust Linux out-of-memory killer */
+#undef LINUX_OOM_ADJUST
+
+/* max value of long long calculated by configure */
+#undef LLONG_MAX
+
+/* min value of long long calculated by configure */
+#undef LLONG_MIN
+
+/* Account locked with pw(1) */
+#undef LOCKED_PASSWD_PREFIX
+
+/* String used in /etc/passwd to denote locked account */
+#undef LOCKED_PASSWD_STRING
+
+/* String used in /etc/passwd to denote locked account */
+#undef LOCKED_PASSWD_SUBSTR
+
+/* Some versions of /bin/login need the TERM supplied on the commandline */
+#undef LOGIN_NEEDS_TERM
+
+/* Some systems need a utmpx entry for /bin/login to work */
+#undef LOGIN_NEEDS_UTMPX
+
+/* Define if your login program cannot handle end of options ("--") */
+#undef LOGIN_NO_ENDOPT
+
+/* If your header files don't define LOGIN_PROGRAM, then use this (detected)
+   from environment and PATH */
+#undef LOGIN_PROGRAM_FALLBACK
+
+/* Set this to your mail directory if you don't have maillock.h */
+#undef MAIL_DIRECTORY
+
+/* Define on *nto-qnx systems */
+#undef MISSING_FD_MASK
+
+/* Define on *nto-qnx systems */
+#undef MISSING_HOWMANY
+
+/* Define on *nto-qnx systems */
+#undef MISSING_NFDBITS
+
+/* Need setpgrp to acquire controlling tty */
+#undef NEED_SETPGRP
+
+/* Define if the concept of ports only accessible to superusers isn't known */
+#undef NO_IPPORT_RESERVED_CONCEPT
+
+/* Define if you don't want to use lastlog in session.c */
+#undef NO_SSH_LASTLOG
+
+/* Define if X11 doesn't support AF_UNIX sockets on that system */
+#undef NO_X11_UNIX_SOCKETS
+
+/* Define if EVP_DigestUpdate returns void */
+#undef OPENSSL_EVP_DIGESTUPDATE_VOID
+
+/* libcrypto includes complete ECC support */
+#undef OPENSSL_HAS_ECC
+
+/* libcrypto is missing AES 192 and 256 bit functions */
+#undef OPENSSL_LOBOTOMISED_AES
+
+/* Define if you want OpenSSL's internally seeded PRNG only */
+#undef OPENSSL_PRNG_ONLY
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* 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
+
+/* Work around problematic Linux PAM modules handling of PAM_TTY */
+#undef PAM_TTY_KLUDGE
+
+/* must supply username to passwd */
+#undef PASSWD_NEEDS_USERNAME
+
+/* Port number of PRNGD/EGD random number socket */
+#undef PRNGD_PORT
+
+/* Location of PRNGD/EGD random number socket */
+#undef PRNGD_SOCKET
+
+/* read(1) can return 0 for a non-closed fd */
+#undef PTY_ZEROREAD
+
+/* Define if your platform breaks doing a seteuid before a setuid */
+#undef SETEUID_BREAKS_SETUID
+
+/* The size of `char', as computed by sizeof. */
+#undef SIZEOF_CHAR
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long int', as computed by sizeof. */
+#undef SIZEOF_LONG_INT
+
+/* The size of `long long int', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG_INT
+
+/* The size of `short int', as computed by sizeof. */
+#undef SIZEOF_SHORT_INT
+
+/* Define if you want S/Key support */
+#undef SKEY
+
+/* Define if your skeychallenge() function takes 4 arguments (NetBSD) */
+#undef SKEYCHALLENGE_4ARG
+
+/* Define as const if snprintf() can declare const char *fmt */
+#undef SNPRINTF_CONST
+
+/* Define to a Set Process Title type if your system is supported by
+   bsd-setproctitle.c */
+#undef SPT_TYPE
+
+/* Define if sshd somehow reacquires a controlling TTY after setsid() */
+#undef SSHD_ACQUIRES_CTTY
+
+/* Define if pam_chauthtok wants real uid set to the unpriv'ed user */
+#undef SSHPAM_CHAUTHTOK_NEEDS_RUID
+
+/* Use audit debugging module */
+#undef SSH_AUDIT_EVENTS
+
+/* Windows is sensitive to read buffer size */
+#undef SSH_IOBUFSZ
+
+/* non-privileged user for privilege separation */
+#undef SSH_PRIVSEP_USER
+
+/* Use tunnel device compatibility to OpenBSD */
+#undef SSH_TUN_COMPAT_AF
+
+/* Open tunnel devices the FreeBSD way */
+#undef SSH_TUN_FREEBSD
+
+/* Open tunnel devices the Linux tun/tap way */
+#undef SSH_TUN_LINUX
+
+/* No layer 2 tunnel support */
+#undef SSH_TUN_NO_L2
+
+/* Open tunnel devices the OpenBSD way */
+#undef SSH_TUN_OPENBSD
+
+/* Prepend the address family to IP tunnel traffic */
+#undef SSH_TUN_PREPEND_AF
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you want a different $PATH for the superuser */
+#undef SUPERUSER_PATH
+
+/* syslog_r function is safe to use in in a signal handler */
+#undef SYSLOG_R_SAFE_IN_SIGHAND
+
+/* Support passwords > 8 chars */
+#undef UNIXWARE_LONG_PASSWORDS
+
+/* Specify default $PATH */
+#undef USER_PATH
+
+/* Define this if you want to use libkafs' AFS support */
+#undef USE_AFS
+
+/* Use BSM audit module */
+#undef USE_BSM_AUDIT
+
+/* Use btmp to log bad logins */
+#undef USE_BTMP
+
+/* Use libedit for sftp */
+#undef USE_LIBEDIT
+
+/* Use Linux audit module */
+#undef USE_LINUX_AUDIT
+
+/* Enable OpenSSL engine support */
+#undef USE_OPENSSL_ENGINE
+
+/* Define if you want to enable PAM support */
+#undef USE_PAM
+
+/* Use PIPES instead of a socketpair() */
+#undef USE_PIPES
+
+/* Define if you have Solaris process contracts */
+#undef USE_SOLARIS_PROCESS_CONTRACTS
+
+/* Define if you have Solaris projects */
+#undef USE_SOLARIS_PROJECTS
+
+/* Define if you shouldn't strip 'tty' from your ttyname in [uw]tmp */
+#undef WITH_ABBREV_NO_TTY
+
+/* 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 audit trails */
+#undef WITH_IRIX_AUDIT
+
+/* Define if you want IRIX kernel jobs */
+#undef WITH_IRIX_JOBS
+
+/* Define if you want IRIX project management */
+#undef WITH_IRIX_PROJECT
+
+/* Define if you want SELinux support. */
+#undef WITH_SELINUX
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define if xauth is found in your path */
+#undef XAUTH_PATH
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* log for bad login attempts */
+#undef _PATH_BTMP
+
+/* Full path of your "passwd" program */
+#undef _PATH_PASSWD_PROG
+
+/* Specify location of ssh.pid */
+#undef _PATH_SSH_PIDDIR
+
+/* Define if we don't have struct __res_state in resolv.h */
+#undef __res_state
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* type to use in place of socklen_t if not defined */
+#undef socklen_t
diff --git a/config.sub b/config.sub
new file mode 100755 (executable)
index 0000000..c2d1257
--- /dev/null
@@ -0,0 +1,1714 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+#   Free Software Foundation, Inc.
+
+timestamp='2010-01-22'
+
+# 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., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, 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>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# 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.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# 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, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # 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 ;;
+
+    * )
+       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* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    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 | -knuth | -cray | -microblaze)
+               os=
+               basic_machine=$1
+               ;;
+        -bluegene*)
+               os=-cnk
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -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/'`
+               ;;
+       -sco5v6*)
+               # 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.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+       | bfin \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fido | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | lm32 \
+       | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | mcore | mep | metag \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64octeon | mips64octeonel \
+       | mips64orion | mips64orionel \
+       | mips64r5900 | mips64r5900el \
+       | mips64vr | mips64vrel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | moxie \
+       | mt \
+       | msp430 \
+       | nios | nios2 \
+       | ns16k | ns32k \
+       | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | rx \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
+       | ubicom32 \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+       | z8k | z80)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       # 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.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+       | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | lm32-* \
+       | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64octeon-* | mips64octeonel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64r5900-* | mips64r5900el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nios-* | nios2-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* | rx-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tile-* | tilegx-* \
+       | tron-* \
+       | ubicom32-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-* | z80-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # 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
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       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
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       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
+               ;;
+       aros)
+               basic_machine=i386-pc
+               os=-aros
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       bluegene*)
+               basic_machine=powerpc-ibm
+               os=-cnk
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+        cegcc)
+               basic_machine=arm-unknown
+               os=-cegcc
+               ;;
+       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 | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       dicos)
+               basic_machine=i686-pc
+               os=-dicos
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       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
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+        microblaze)
+               basic_machine=microblaze-xilinx
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       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
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       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
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`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/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-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=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tic55x | c55x*)
+               basic_machine=tic55x-unknown
+               os=-coff
+               ;;
+       tic6x | c6x*)
+               basic_machine=tic6x-unknown
+               os=-coff
+               ;;
+        # This must be matched before tile*.
+        tilegx*)
+               basic_machine=tilegx-unknown
+               os=-linux-gnu
+               ;;
+       tile*)
+               basic_machine=tile-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       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
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       z80-*-coff)
+               basic_machine=z80-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
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       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
+               ;;
+       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               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
+               ;;
+       *-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.
+        -auroraux)
+               os=-auroraux
+               ;;
+       -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* | -cnk* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* | -aros* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -openbsd* | -solidbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* | -cegcc* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -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
+               ;;
+        -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+        -tpf*)
+               os=-tpf
+               ;;
+       -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
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -dicos*)
+               os=-dicos
+               ;;
+        -nacl*)
+               ;;
+       -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
+        score-*)
+               os=-elf
+               ;;
+        spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       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
+               ;;
+        mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-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
+                               ;;
+                       -cnk*|-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
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# 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/configure b/configure
new file mode 100755 (executable)
index 0000000..73040c5
--- /dev/null
+++ b/configure
@@ -0,0 +1,32039 @@
+#! /bin/sh
+# From configure.ac Revision: 1.469.4.1 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61 for OpenSSH Portable.
+#
+# Report bugs to <openssh-unix-dev@mindrot.org>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf@gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='OpenSSH'
+PACKAGE_TARNAME='openssh'
+PACKAGE_VERSION='Portable'
+PACKAGE_STRING='OpenSSH Portable'
+PACKAGE_BUGREPORT='openssh-unix-dev@mindrot.org'
+
+ac_unique_file="ssh.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+build
+build_cpu
+build_vendor
+build_os
+host
+host_cpu
+host_vendor
+host_os
+CPP
+GREP
+EGREP
+AWK
+RANLIB
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+AR
+CAT
+KILL
+PERL
+SED
+ENT
+TEST_MINUS_S_SH
+SH
+GROFF
+NROFF
+MANDOC
+TEST_SHELL
+MANFMT
+PATH_GROUPADD_PROG
+PATH_USERADD_PROG
+MAKE_PACKAGE_SUPPORTED
+STARTUP_SCRIPT_SHELL
+LOGIN_PROGRAM_FALLBACK
+PATH_PASSWD_PROG
+LD
+PKGCONFIG
+LIBEDIT
+TEST_SSH_SHA256
+TEST_SSH_ECC
+COMMENT_OUT_ECC
+INSTALL_SSH_RAND_HELPER
+SSH_PRIVSEP_USER
+PROG_LS
+PROG_NETSTAT
+PROG_ARP
+PROG_IFCONFIG
+PROG_JSTAT
+PROG_PS
+PROG_SAR
+PROG_W
+PROG_WHO
+PROG_LAST
+PROG_LASTLOG
+PROG_DF
+PROG_VMSTAT
+PROG_UPTIME
+PROG_IPCS
+PROG_TAIL
+INSTALL_SSH_PRNG_CMDS
+SSHLIBS
+SSHDLIBS
+KRB5CONF
+PRIVSEP_PATH
+xauth_path
+STRIP_OPT
+XAUTH_PATH
+MANTYPE
+mansubdir
+user_path
+piddir
+TEST_SSH_IPV6
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$0" : 'X\(//\)[^/]' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures OpenSSH Portable to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                         [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                         [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --datarootdir=DIR      read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR          read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR          info documentation [DATAROOTDIR/info]
+  --localedir=DIR        locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR           man documentation [DATAROOTDIR/man]
+  --docdir=DIR           documentation root [DATAROOTDIR/doc/openssh]
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of OpenSSH Portable:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-largefile     omit support for large files
+  --disable-strip         Disable calling strip(1) on install
+  --disable-etc-default-login Disable using PATH from /etc/default/login no
+  --disable-lastlog       disable use of lastlog even if detected no
+  --disable-utmp          disable use of utmp even if detected no
+  --disable-utmpx         disable use of utmpx even if detected no
+  --disable-wtmp          disable use of wtmp even if detected no
+  --disable-wtmpx         disable use of wtmpx even if detected no
+  --disable-libutil       disable use of libutil (login() etc.) no
+  --disable-pututline     disable use of pututline() etc. (uwtmp) no
+  --disable-pututxline    disable use of pututxline() etc. (uwtmpx) no
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --without-stackprotect  Don't use compiler's stack protection
+  --without-rpath         Disable auto-added -R linker paths
+  --with-cflags           Specify additional flags to pass to compiler
+  --with-cppflags         Specify additional flags to pass to preprocessor
+  --with-ldflags          Specify additional flags to pass to linker
+  --with-libs             Specify additional libraries to link with
+  --with-Werror           Build main code with -Werror
+  --with-solaris-contracts Enable Solaris process contracts (experimental)
+  --with-solaris-projects Enable Solaris projects (experimental)
+  --with-osfsia           Enable Digital Unix SIA
+  --with-zlib=PATH        Use zlib in PATH
+  --without-zlib-version-check Disable zlib version check
+  --with-skey[=PATH]      Enable S/Key support (optionally in PATH)
+  --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
+  --with-libedit[=PATH]   Enable libedit support for sftp
+  --with-audit=module     Enable audit support (modules=debug,bsm,linux)
+  --with-ssl-dir=PATH     Specify path to OpenSSL installation
+  --without-openssl-header-check Disable OpenSSL version consistency check
+  --with-ssl-engine       Enable OpenSSL (hardware) ENGINE support
+  --with-pam              Enable PAM support
+  --with-rand-helper      Use subprocess to gather strong randomness
+  --with-prngd-port=PORT  read entropy from PRNGD/EGD TCP localhost:PORT
+  --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)
+  --with-entropy-timeout  Specify entropy gathering command timeout (msec)
+  --with-privsep-user=user Specify non-privileged user for privilege separation
+  --with-selinux          Enable SELinux support
+  --with-kerberos5=PATH   Enable Kerberos 5 support
+  --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)
+  --with-xauth=PATH       Specify path to xauth program
+  --with-mantype=man|cat|doc  Set man page type
+  --with-md5-passwords    Enable use of MD5 passwords
+  --without-shadow        Disable shadow password support
+  --with-ipaddr-display   Use ip address instead of hostname in \$DISPLAY
+  --with-default-path=    Specify default \$PATH environment for server
+  --with-superuser-path=  Specify different path for super-user
+  --with-4in6             Check for and convert IPv4 in IPv6 mapped addresses
+  --with-bsd-auth         Enable BSD auth support
+  --with-pid-dir=PATH     Specify location of ssh.pid file
+  --with-lastlog=FILE|DIR specify lastlog location common locations
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <openssh-unix-dev@mindrot.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+OpenSSH configure Portable
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by OpenSSH $as_me Portable, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+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 || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+       "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+       { echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+       { echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+       ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+# local macros
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ echo "$as_me:$LINENO: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6; }
+if test "${ac_cv_build+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ echo "$as_me:$LINENO: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6; }
+if test "${ac_cv_host+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+    # Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_GREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if  ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \
+       && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN)
+ bogus endian macros
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_bigendian=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_bigendian=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       # It does not; compile a test program.
+if test "$cross_compiling" = yes; then
+  # try to guess the endianness by grepping values into an object file
+  ac_cv_c_bigendian=unknown
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; }
+short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; }
+int
+main ()
+{
+ _ascii (); _ebcdic ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then
+  ac_cv_c_bigendian=yes
+fi
+if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+  if test "$ac_cv_c_bigendian" = unknown; then
+    ac_cv_c_bigendian=no
+  else
+    # finding both strings is unlikely to happen, but who knows?
+    ac_cv_c_bigendian=unknown
+  fi
+fi
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+  /* Are we little or big endian?  From Harbison&Steele.  */
+  union
+  {
+    long int l;
+    char c[sizeof (long int)];
+  } u;
+  u.l = 1;
+  return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_bigendian=no
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6; }
+case $ac_cv_c_bigendian in
+  yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define WORDS_BIGENDIAN 1
+_ACEOF
+ ;;
+  no)
+     ;;
+  *)
+    { { echo "$as_me:$LINENO: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&5
+echo "$as_me: error: unknown endianness
+presetting ac_cv_c_bigendian=no (or yes) will help" >&2;}
+   { (exit 1); exit 1; }; } ;;
+esac
+
+
+# Checks for programs.
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { echo "$as_me:$LINENO: result: $AWK" >&5
+echo "${ECHO_T}$AWK" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { echo "$as_me:$LINENO: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+           break 3
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+  for ac_exec_ext in '' $ac_executable_extensions; do
+    ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+    { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+    # Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+    $ac_path_EGREP_found && break 3
+  done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_AR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $AR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_AR="$AR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+AR=$ac_cv_path_AR
+if test -n "$AR"; then
+  { echo "$as_me:$LINENO: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "cat", so it can be a program name with args.
+set dummy cat; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_CAT+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $CAT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_CAT="$CAT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_CAT="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+CAT=$ac_cv_path_CAT
+if test -n "$CAT"; then
+  { echo "$as_me:$LINENO: result: $CAT" >&5
+echo "${ECHO_T}$CAT" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "kill", so it can be a program name with args.
+set dummy kill; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_KILL+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $KILL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_KILL="$KILL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_KILL="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+KILL=$ac_cv_path_KILL
+if test -n "$KILL"; then
+  { echo "$as_me:$LINENO: result: $KILL" >&5
+echo "${ECHO_T}$KILL" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+for ac_prog in perl5 perl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PERL+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PERL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PERL="$PERL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PERL=$ac_cv_path_PERL
+if test -n "$PERL"; then
+  { echo "$as_me:$LINENO: result: $PERL" >&5
+echo "${ECHO_T}$PERL" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$PERL" && break
+done
+
+# Extract the first word of "sed", so it can be a program name with args.
+set dummy sed; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SED+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SED in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SED="$SED" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+SED=$ac_cv_path_SED
+if test -n "$SED"; then
+  { echo "$as_me:$LINENO: result: $SED" >&5
+echo "${ECHO_T}$SED" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+
+# Extract the first word of "ent", so it can be a program name with args.
+set dummy ent; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_ENT+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $ENT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ENT="$ENT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_ENT="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ENT=$ac_cv_path_ENT
+if test -n "$ENT"; then
+  { echo "$as_me:$LINENO: result: $ENT" >&5
+echo "${ECHO_T}$ENT" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+
+# Extract the first word of "bash", so it can be a program name with args.
+set dummy bash; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_TEST_MINUS_S_SH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $TEST_MINUS_S_SH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
+if test -n "$TEST_MINUS_S_SH"; then
+  { echo "$as_me:$LINENO: result: $TEST_MINUS_S_SH" >&5
+echo "${ECHO_T}$TEST_MINUS_S_SH" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "ksh", so it can be a program name with args.
+set dummy ksh; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_TEST_MINUS_S_SH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $TEST_MINUS_S_SH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
+if test -n "$TEST_MINUS_S_SH"; then
+  { echo "$as_me:$LINENO: result: $TEST_MINUS_S_SH" >&5
+echo "${ECHO_T}$TEST_MINUS_S_SH" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "sh", so it can be a program name with args.
+set dummy sh; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_TEST_MINUS_S_SH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $TEST_MINUS_S_SH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_TEST_MINUS_S_SH="$TEST_MINUS_S_SH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_TEST_MINUS_S_SH="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+TEST_MINUS_S_SH=$ac_cv_path_TEST_MINUS_S_SH
+if test -n "$TEST_MINUS_S_SH"; then
+  { echo "$as_me:$LINENO: result: $TEST_MINUS_S_SH" >&5
+echo "${ECHO_T}$TEST_MINUS_S_SH" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "sh", so it can be a program name with args.
+set dummy sh; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SH="$SH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SH="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+SH=$ac_cv_path_SH
+if test -n "$SH"; then
+  { echo "$as_me:$LINENO: result: $SH" >&5
+echo "${ECHO_T}$SH" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "groff", so it can be a program name with args.
+set dummy groff; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_GROFF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $GROFF in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GROFF="$GROFF" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_GROFF="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+GROFF=$ac_cv_path_GROFF
+if test -n "$GROFF"; then
+  { echo "$as_me:$LINENO: result: $GROFF" >&5
+echo "${ECHO_T}$GROFF" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "nroff", so it can be a program name with args.
+set dummy nroff; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_NROFF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $NROFF in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_NROFF="$NROFF" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_NROFF="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+NROFF=$ac_cv_path_NROFF
+if test -n "$NROFF"; then
+  { echo "$as_me:$LINENO: result: $NROFF" >&5
+echo "${ECHO_T}$NROFF" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "mandoc", so it can be a program name with args.
+set dummy mandoc; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_MANDOC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $MANDOC in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_MANDOC="$MANDOC" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_MANDOC="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+MANDOC=$ac_cv_path_MANDOC
+if test -n "$MANDOC"; then
+  { echo "$as_me:$LINENO: result: $MANDOC" >&5
+echo "${ECHO_T}$MANDOC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+TEST_SHELL=sh
+
+
+if test "x$MANDOC" != "x" ; then
+       MANFMT="$MANDOC"
+elif test "x$NROFF" != "x" ; then
+       MANFMT="$NROFF -mandoc"
+elif test "x$GROFF" != "x" ; then
+       MANFMT="$GROFF -mandoc -Tascii"
+else
+       { echo "$as_me:$LINENO: WARNING: no manpage formatted found" >&5
+echo "$as_me: WARNING: no manpage formatted found" >&2;}
+       MANFMT="false"
+fi
+
+
+# Extract the first word of "groupadd", so it can be a program name with args.
+set dummy groupadd; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PATH_GROUPADD_PROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PATH_GROUPADD_PROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATH_GROUPADD_PROG="$PATH_GROUPADD_PROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /usr/sbin${PATH_SEPARATOR}/etc
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PATH_GROUPADD_PROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PATH_GROUPADD_PROG" && ac_cv_path_PATH_GROUPADD_PROG="groupadd"
+  ;;
+esac
+fi
+PATH_GROUPADD_PROG=$ac_cv_path_PATH_GROUPADD_PROG
+if test -n "$PATH_GROUPADD_PROG"; then
+  { echo "$as_me:$LINENO: result: $PATH_GROUPADD_PROG" >&5
+echo "${ECHO_T}$PATH_GROUPADD_PROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "useradd", so it can be a program name with args.
+set dummy useradd; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PATH_USERADD_PROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PATH_USERADD_PROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATH_USERADD_PROG="$PATH_USERADD_PROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /usr/sbin${PATH_SEPARATOR}/etc
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PATH_USERADD_PROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PATH_USERADD_PROG" && ac_cv_path_PATH_USERADD_PROG="useradd"
+  ;;
+esac
+fi
+PATH_USERADD_PROG=$ac_cv_path_PATH_USERADD_PROG
+if test -n "$PATH_USERADD_PROG"; then
+  { echo "$as_me:$LINENO: result: $PATH_USERADD_PROG" >&5
+echo "${ECHO_T}$PATH_USERADD_PROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "pkgmk", so it can be a program name with args.
+set dummy pkgmk; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_MAKE_PACKAGE_SUPPORTED+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$MAKE_PACKAGE_SUPPORTED"; then
+  ac_cv_prog_MAKE_PACKAGE_SUPPORTED="$MAKE_PACKAGE_SUPPORTED" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_MAKE_PACKAGE_SUPPORTED="yes"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_MAKE_PACKAGE_SUPPORTED" && ac_cv_prog_MAKE_PACKAGE_SUPPORTED="no"
+fi
+fi
+MAKE_PACKAGE_SUPPORTED=$ac_cv_prog_MAKE_PACKAGE_SUPPORTED
+if test -n "$MAKE_PACKAGE_SUPPORTED"; then
+  { echo "$as_me:$LINENO: result: $MAKE_PACKAGE_SUPPORTED" >&5
+echo "${ECHO_T}$MAKE_PACKAGE_SUPPORTED" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+if test -x /sbin/sh; then
+       STARTUP_SCRIPT_SHELL=/sbin/sh
+
+else
+       STARTUP_SCRIPT_SHELL=/bin/sh
+
+fi
+
+# System features
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5
+echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_largefile_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+        # IRIX 6.2 and later do not support large files by default,
+        # so use the C compiler's -n32 option if that helps.
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+        rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+        CC="$CC -n32"
+        rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_sys_largefile_CC=' -n32'; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+        break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5
+echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  while :; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_sys_file_offset_bits=no; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_sys_file_offset_bits=64; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5
+echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -f conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5
+echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_large_files+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  while :; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_sys_large_files=no; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_sys_large_files=1; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5
+echo "${ECHO_T}$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -f conftest*
+  fi
+fi
+
+
+if test -z "$AR" ; then
+       { { echo "$as_me:$LINENO: error: *** 'ar' missing, please install or fix your \$PATH ***" >&5
+echo "$as_me: error: *** 'ar' missing, please install or fix your \$PATH ***" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# Use LOGIN_PROGRAM from environment if possible
+if test ! -z "$LOGIN_PROGRAM" ; then
+
+cat >>confdefs.h <<_ACEOF
+#define LOGIN_PROGRAM_FALLBACK "$LOGIN_PROGRAM"
+_ACEOF
+
+else
+       # Search for login
+       # Extract the first word of "login", so it can be a program name with args.
+set dummy login; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_LOGIN_PROGRAM_FALLBACK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $LOGIN_PROGRAM_FALLBACK in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LOGIN_PROGRAM_FALLBACK="$LOGIN_PROGRAM_FALLBACK" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_LOGIN_PROGRAM_FALLBACK="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+LOGIN_PROGRAM_FALLBACK=$ac_cv_path_LOGIN_PROGRAM_FALLBACK
+if test -n "$LOGIN_PROGRAM_FALLBACK"; then
+  { echo "$as_me:$LINENO: result: $LOGIN_PROGRAM_FALLBACK" >&5
+echo "${ECHO_T}$LOGIN_PROGRAM_FALLBACK" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test ! -z "$LOGIN_PROGRAM_FALLBACK" ; then
+               cat >>confdefs.h <<_ACEOF
+#define LOGIN_PROGRAM_FALLBACK "$LOGIN_PROGRAM_FALLBACK"
+_ACEOF
+
+       fi
+fi
+
+# Extract the first word of "passwd", so it can be a program name with args.
+set dummy passwd; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PATH_PASSWD_PROG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PATH_PASSWD_PROG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PATH_PASSWD_PROG="$PATH_PASSWD_PROG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PATH_PASSWD_PROG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PATH_PASSWD_PROG=$ac_cv_path_PATH_PASSWD_PROG
+if test -n "$PATH_PASSWD_PROG"; then
+  { echo "$as_me:$LINENO: result: $PATH_PASSWD_PROG" >&5
+echo "${ECHO_T}$PATH_PASSWD_PROG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+if test ! -z "$PATH_PASSWD_PROG" ; then
+
+cat >>confdefs.h <<_ACEOF
+#define _PATH_PASSWD_PROG "$PATH_PASSWD_PROG"
+_ACEOF
+
+fi
+
+if test -z "$LD" ; then
+       LD=$CC
+fi
+
+
+{ echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6; }
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_inline=$ac_kw
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6; }
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+{ echo "$as_me:$LINENO: checking whether LLONG_MAX is declared" >&5
+echo $ECHO_N "checking whether LLONG_MAX is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_LLONG_MAX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef LLONG_MAX
+  (void) LLONG_MAX;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_LLONG_MAX=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_LLONG_MAX=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_LLONG_MAX" >&5
+echo "${ECHO_T}$ac_cv_have_decl_LLONG_MAX" >&6; }
+if test $ac_cv_have_decl_LLONG_MAX = yes; then
+  have_llong_max=1
+fi
+
+
+use_stack_protector=1
+
+# Check whether --with-stackprotect was given.
+if test "${with_stackprotect+set}" = set; then
+  withval=$with_stackprotect;
+    if test "x$withval" = "xno"; then
+       use_stack_protector=0
+    fi
+fi
+
+
+
+if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wall" >&5
+echo $ECHO_N "checking if $CC supports -Wall... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wall"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wpointer-arith" >&5
+echo $ECHO_N "checking if $CC supports -Wpointer-arith... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wpointer-arith"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wuninitialized" >&5
+echo $ECHO_N "checking if $CC supports -Wuninitialized... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wuninitialized"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wsign-compare" >&5
+echo $ECHO_N "checking if $CC supports -Wsign-compare... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wsign-compare"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wformat-security" >&5
+echo $ECHO_N "checking if $CC supports -Wformat-security... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wformat-security"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wno-pointer-sign" >&5
+echo $ECHO_N "checking if $CC supports -Wno-pointer-sign... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wno-pointer-sign"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -Wno-unused-result" >&5
+echo $ECHO_N "checking if $CC supports -Wno-unused-result... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -Wno-unused-result"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       {
+       { echo "$as_me:$LINENO: checking if $CC supports -fno-strict-aliasing" >&5
+echo $ECHO_N "checking if $CC supports -fno-strict-aliasing... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -fno-strict-aliasing"
+       cat >conftest.$ac_ext <<_ACEOF
+void main(void) { return 0; }
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+}
+       { echo "$as_me:$LINENO: checking gcc version" >&5
+echo $ECHO_N "checking gcc version... $ECHO_C" >&6; }
+       GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'`
+       case $GCC_VER in
+               1.*) no_attrib_nonnull=1 ;;
+               2.8* | 2.9*)
+                    no_attrib_nonnull=1
+                    ;;
+               2.*) no_attrib_nonnull=1 ;;
+               *) ;;
+       esac
+       { echo "$as_me:$LINENO: result: $GCC_VER" >&5
+echo "${ECHO_T}$GCC_VER" >&6; }
+
+       { echo "$as_me:$LINENO: checking if $CC accepts -fno-builtin-memset" >&5
+echo $ECHO_N "checking if $CC accepts -fno-builtin-memset... $ECHO_C" >&6; }
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -fno-builtin-memset"
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <string.h>
+int main(void){char b[10]; memset(b, 0, sizeof(b));}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                 CFLAGS="$saved_CFLAGS"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+       # -fstack-protector-all doesn't always work for some GCC versions
+       # and/or platforms, so we test if we can.  If it's not supported
+       # on a given platform gcc will emit a warning so we use -Werror.
+       if test "x$use_stack_protector" = "x1"; then
+           for t in -fstack-protector-all -fstack-protector; do
+               { echo "$as_me:$LINENO: checking if $CC supports $t" >&5
+echo $ECHO_N "checking if $CC supports $t... $ECHO_C" >&6; }
+               saved_CFLAGS="$CFLAGS"
+               saved_LDFLAGS="$LDFLAGS"
+               CFLAGS="$CFLAGS $t -Werror"
+               LDFLAGS="$LDFLAGS $t -Werror"
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+int main(void){char x[256]; snprintf(x, sizeof(x), "XXX"); return 0;}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+                     CFLAGS="$saved_CFLAGS $t"
+                     LDFLAGS="$saved_LDFLAGS $t"
+                     { echo "$as_me:$LINENO: checking if $t works" >&5
+echo $ECHO_N "checking if $t works... $ECHO_C" >&6; }
+                     if test "$cross_compiling" = yes; then
+   { echo "$as_me:$LINENO: WARNING: cross compiling: cannot test" >&5
+echo "$as_me: WARNING: cross compiling: cannot test" >&2;}
+                         break
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+int main(void){char x[256]; snprintf(x, sizeof(x), "XXX"); return 0;}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+                         break
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+               CFLAGS="$saved_CFLAGS"
+               LDFLAGS="$saved_LDFLAGS"
+           done
+       fi
+
+       if test -z "$have_llong_max"; then
+               # retry LLONG_MAX with -std=gnu99, needed on some Linuxes
+               unset ac_cv_have_decl_LLONG_MAX
+               saved_CFLAGS="$CFLAGS"
+               CFLAGS="$CFLAGS -std=gnu99"
+               { echo "$as_me:$LINENO: checking whether LLONG_MAX is declared" >&5
+echo $ECHO_N "checking whether LLONG_MAX is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_LLONG_MAX+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <limits.h>
+
+
+int
+main ()
+{
+#ifndef LLONG_MAX
+  (void) LLONG_MAX;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_LLONG_MAX=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_LLONG_MAX=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_LLONG_MAX" >&5
+echo "${ECHO_T}$ac_cv_have_decl_LLONG_MAX" >&6; }
+if test $ac_cv_have_decl_LLONG_MAX = yes; then
+  have_llong_max=1
+else
+  CFLAGS="$saved_CFLAGS"
+fi
+
+       fi
+fi
+
+if test "x$no_attrib_nonnull" != "x1" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ATTRIBUTE__NONNULL__ 1
+_ACEOF
+
+fi
+
+
+# Check whether --with-rpath was given.
+if test "${with_rpath+set}" = set; then
+  withval=$with_rpath;
+               if test "x$withval" = "xno" ; then
+                       need_dash_r=""
+               fi
+               if test "x$withval" = "xyes" ; then
+                       need_dash_r=1
+               fi
+
+
+fi
+
+
+# Allow user to specify flags
+
+# Check whether --with-cflags was given.
+if test "${with_cflags+set}" = set; then
+  withval=$with_cflags;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       CFLAGS="$CFLAGS $withval"
+               fi
+
+
+fi
+
+
+# Check whether --with-cppflags was given.
+if test "${with_cppflags+set}" = set; then
+  withval=$with_cppflags;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       CPPFLAGS="$CPPFLAGS $withval"
+               fi
+
+
+fi
+
+
+# Check whether --with-ldflags was given.
+if test "${with_ldflags+set}" = set; then
+  withval=$with_ldflags;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       LDFLAGS="$LDFLAGS $withval"
+               fi
+
+
+fi
+
+
+# Check whether --with-libs was given.
+if test "${with_libs+set}" = set; then
+  withval=$with_libs;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       LIBS="$LIBS $withval"
+               fi
+
+
+fi
+
+
+# Check whether --with-Werror was given.
+if test "${with_Werror+set}" = set; then
+  withval=$with_Werror;
+               if test -n "$withval"  &&  test "x$withval" != "xno"; then
+                       werror_flags="-Werror"
+                       if test "x${withval}" != "xyes"; then
+                               werror_flags="$withval"
+                       fi
+               fi
+
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in \
+       bstring.h \
+       crypt.h \
+       crypto/sha2.h \
+       dirent.h \
+       endian.h \
+       features.h \
+       fcntl.h \
+       floatingpoint.h \
+       getopt.h \
+       glob.h \
+       ia.h \
+       iaf.h \
+       limits.h \
+       login.h \
+       maillock.h \
+       ndir.h \
+       net/if_tun.h \
+       netdb.h \
+       netgroup.h \
+       pam/pam_appl.h \
+       paths.h \
+       poll.h \
+       pty.h \
+       readpassphrase.h \
+       rpc/types.h \
+       security/pam_appl.h \
+       sha2.h \
+       shadow.h \
+       stddef.h \
+       stdint.h \
+       string.h \
+       strings.h \
+       sys/audit.h \
+       sys/bitypes.h \
+       sys/bsdtty.h \
+       sys/cdefs.h \
+       sys/dir.h \
+       sys/mman.h \
+       sys/ndir.h \
+       sys/poll.h \
+       sys/prctl.h \
+       sys/pstat.h \
+       sys/select.h \
+       sys/stat.h \
+       sys/stream.h \
+       sys/stropts.h \
+       sys/strtio.h \
+       sys/statvfs.h \
+       sys/sysmacros.h \
+       sys/time.h \
+       sys/timers.h \
+       sys/un.h \
+       time.h \
+       tmpdir.h \
+       ttyent.h \
+       ucred.h \
+       unistd.h \
+       usersec.h \
+       util.h \
+       utime.h \
+       utmp.h \
+       utmpx.h \
+       vis.h \
+
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# lastlog.h requires sys/time.h to be included first on Solaris
+
+for ac_header in lastlog.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# sys/ptms.h requires sys/stream.h to be included first on Solaris
+
+for ac_header in sys/ptms.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# login_cap.h requires sys/types.h on NetBSD
+
+for ac_header in login_cap.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# older BSDs need sys/param.h before sys/mount.h
+
+for ac_header in sys/mount.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/param.h>
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# Messages for features tested for in target-specific section
+SIA_MSG="no"
+SPC_MSG="no"
+SP_MSG="no"
+
+# Check for some target-specific stuff
+case "$host" in
+*-*-aix*)
+       # Some versions of VAC won't allow macro redefinitions at
+       # -qlanglevel=ansi, and autoconf 2.60 sometimes insists on using that
+       # particularly with older versions of vac or xlc.
+       # It also throws errors about null macro argments, but these are
+       # not fatal.
+       { echo "$as_me:$LINENO: checking if compiler allows macro redefinitions" >&5
+echo $ECHO_N "checking if compiler allows macro redefinitions... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#define testmacro foo
+#define testmacro bar
+int main(void) { exit(0); }
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+             CC="`echo $CC | sed 's/-qlanglvl\=ansi//g'`"
+             LD="`echo $LD | sed 's/-qlanglvl\=ansi//g'`"
+             CFLAGS="`echo $CFLAGS | sed 's/-qlanglvl\=ansi//g'`"
+             CPPFLAGS="`echo $CPPFLAGS | sed 's/-qlanglvl\=ansi//g'`"
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+       { echo "$as_me:$LINENO: checking how to specify blibpath for linker ($LD)" >&5
+echo $ECHO_N "checking how to specify blibpath for linker ($LD)... $ECHO_C" >&6; }
+       if (test -z "$blibpath"); then
+               blibpath="/usr/lib:/lib"
+       fi
+       saved_LDFLAGS="$LDFLAGS"
+       if test "$GCC" = "yes"; then
+               flags="-Wl,-blibpath: -Wl,-rpath, -blibpath:"
+       else
+               flags="-blibpath: -Wl,-blibpath: -Wl,-rpath,"
+       fi
+       for tryflags in $flags ;do
+               if (test -z "$blibflags"); then
+                       LDFLAGS="$saved_LDFLAGS $tryflags$blibpath"
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  blibflags=$tryflags
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+               fi
+       done
+       if (test -z "$blibflags"); then
+               { echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6; }
+               { { echo "$as_me:$LINENO: error: *** must be able to specify blibpath on AIX - check config.log" >&5
+echo "$as_me: error: *** must be able to specify blibpath on AIX - check config.log" >&2;}
+   { (exit 1); exit 1; }; }
+       else
+               { echo "$as_me:$LINENO: result: $blibflags" >&5
+echo "${ECHO_T}$blibflags" >&6; }
+       fi
+       LDFLAGS="$saved_LDFLAGS"
+               { echo "$as_me:$LINENO: checking for authenticate" >&5
+echo $ECHO_N "checking for authenticate... $ECHO_C" >&6; }
+if test "${ac_cv_func_authenticate+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define authenticate to an innocuous variant, in case <limits.h> declares authenticate.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define authenticate innocuous_authenticate
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char authenticate (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef authenticate
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char authenticate ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_authenticate || defined __stub___authenticate
+choke me
+#endif
+
+int
+main ()
+{
+return authenticate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_authenticate=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_authenticate=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_authenticate" >&5
+echo "${ECHO_T}$ac_cv_func_authenticate" >&6; }
+if test $ac_cv_func_authenticate = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_AIXAUTHENTICATE 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: checking for authenticate in -ls" >&5
+echo $ECHO_N "checking for authenticate in -ls... $ECHO_C" >&6; }
+if test "${ac_cv_lib_s_authenticate+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ls  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char authenticate ();
+int
+main ()
+{
+return authenticate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_s_authenticate=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_s_authenticate=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_s_authenticate" >&5
+echo "${ECHO_T}$ac_cv_lib_s_authenticate" >&6; }
+if test $ac_cv_lib_s_authenticate = yes; then
+   cat >>confdefs.h <<\_ACEOF
+#define WITH_AIXAUTHENTICATE 1
+_ACEOF
+
+                               LIBS="$LIBS -ls"
+
+fi
+
+
+fi
+
+               { echo "$as_me:$LINENO: checking whether authenticate is declared" >&5
+echo $ECHO_N "checking whether authenticate is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_authenticate+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+int
+main ()
+{
+#ifndef authenticate
+  (void) authenticate;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_authenticate=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_authenticate=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_authenticate" >&5
+echo "${ECHO_T}$ac_cv_have_decl_authenticate" >&6; }
+if test $ac_cv_have_decl_authenticate = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_AUTHENTICATE 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_AUTHENTICATE 0
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking whether loginrestrictions is declared" >&5
+echo $ECHO_N "checking whether loginrestrictions is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_loginrestrictions+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+int
+main ()
+{
+#ifndef loginrestrictions
+  (void) loginrestrictions;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_loginrestrictions=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_loginrestrictions=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_loginrestrictions" >&5
+echo "${ECHO_T}$ac_cv_have_decl_loginrestrictions" >&6; }
+if test $ac_cv_have_decl_loginrestrictions = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINRESTRICTIONS 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINRESTRICTIONS 0
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking whether loginsuccess is declared" >&5
+echo $ECHO_N "checking whether loginsuccess is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_loginsuccess+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+int
+main ()
+{
+#ifndef loginsuccess
+  (void) loginsuccess;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_loginsuccess=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_loginsuccess=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_loginsuccess" >&5
+echo "${ECHO_T}$ac_cv_have_decl_loginsuccess" >&6; }
+if test $ac_cv_have_decl_loginsuccess = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINSUCCESS 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINSUCCESS 0
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking whether passwdexpired is declared" >&5
+echo $ECHO_N "checking whether passwdexpired is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_passwdexpired+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+int
+main ()
+{
+#ifndef passwdexpired
+  (void) passwdexpired;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_passwdexpired=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_passwdexpired=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_passwdexpired" >&5
+echo "${ECHO_T}$ac_cv_have_decl_passwdexpired" >&6; }
+if test $ac_cv_have_decl_passwdexpired = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PASSWDEXPIRED 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_PASSWDEXPIRED 0
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking whether setauthdb is declared" >&5
+echo $ECHO_N "checking whether setauthdb is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_setauthdb+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+int
+main ()
+{
+#ifndef setauthdb
+  (void) setauthdb;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_setauthdb=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_setauthdb=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_setauthdb" >&5
+echo "${ECHO_T}$ac_cv_have_decl_setauthdb" >&6; }
+if test $ac_cv_have_decl_setauthdb = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SETAUTHDB 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SETAUTHDB 0
+_ACEOF
+
+
+fi
+
+
+               { echo "$as_me:$LINENO: checking whether loginfailed is declared" >&5
+echo $ECHO_N "checking whether loginfailed is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_loginfailed+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+
+
+int
+main ()
+{
+#ifndef loginfailed
+  (void) loginfailed;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_loginfailed=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_loginfailed=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_loginfailed" >&5
+echo "${ECHO_T}$ac_cv_have_decl_loginfailed" >&6; }
+if test $ac_cv_have_decl_loginfailed = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINFAILED 1
+_ACEOF
+
+{ echo "$as_me:$LINENO: checking if loginfailed takes 4 arguments" >&5
+echo $ECHO_N "checking if loginfailed takes 4 arguments... $ECHO_C" >&6; }
+                 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usersec.h>
+int
+main ()
+{
+(void)loginfailed("user","host","tty",0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define AIX_LOGINFAILED_4ARG 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_LOGINFAILED 0
+_ACEOF
+
+
+fi
+
+
+
+
+for ac_func in getgrset setauthdb
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+       { echo "$as_me:$LINENO: checking whether F_CLOSEM is declared" >&5
+echo $ECHO_N "checking whether F_CLOSEM is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_F_CLOSEM+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <limits.h>
+             #include <fcntl.h>
+
+
+int
+main ()
+{
+#ifndef F_CLOSEM
+  (void) F_CLOSEM;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_F_CLOSEM=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_F_CLOSEM=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_F_CLOSEM" >&5
+echo "${ECHO_T}$ac_cv_have_decl_F_CLOSEM" >&6; }
+if test $ac_cv_have_decl_F_CLOSEM = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_FCNTL_CLOSEM 1
+_ACEOF
+
+fi
+
+       check_for_aix_broken_getaddrinfo=1
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_REALPATH 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LASTLOG 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LOGIN_NEEDS_UTMPX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SPT_TYPE SPT_REUSEARGV
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PTY_ZEROREAD 1
+_ACEOF
+
+       ;;
+*-*-cygwin*)
+       check_for_libcrypt_later=1
+       LIBS="$LIBS /usr/lib/textreadmode.o"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CYGWIN 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_SHADOW 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_X11_UNIX_SOCKETS 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_IPPORT_RESERVED_CONCEPT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_IOBUFSZ 65535
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define FILESYSTEM_NO_BACKSLASH 1
+_ACEOF
+
+       ;;
+*-*-dgux*)
+
+cat >>confdefs.h <<\_ACEOF
+#define IP_TOS_IS_BROKEN 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       ;;
+*-*-darwin*)
+       { echo "$as_me:$LINENO: checking if we have working getaddrinfo" >&5
+echo $ECHO_N "checking if we have working getaddrinfo... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+  { echo "$as_me:$LINENO: result: assume it is working" >&5
+echo "${ECHO_T}assume it is working" >&6; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <mach-o/dyld.h>
+main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
+               exit(0);
+       else
+               exit(1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: working" >&5
+echo "${ECHO_T}working" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+{ echo "$as_me:$LINENO: result: buggy" >&5
+echo "${ECHO_T}buggy" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GLOB 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define BIND_8_COMPAT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_FREEBSD 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_COMPAT_AF 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_PREPEND_AF 1
+_ACEOF
+
+
+       { echo "$as_me:$LINENO: checking whether AU_IPv4 is declared" >&5
+echo $ECHO_N "checking whether AU_IPv4 is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_AU_IPv4+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+#ifndef AU_IPv4
+  (void) AU_IPv4;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_AU_IPv4=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_AU_IPv4=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_AU_IPv4" >&5
+echo "${ECHO_T}$ac_cv_have_decl_AU_IPv4" >&6; }
+if test $ac_cv_have_decl_AU_IPv4 = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define AU_IPv4 0
+_ACEOF
+
+           #include <bsm/audit.h>
+
+cat >>confdefs.h <<\_ACEOF
+#define LASTLOG_WRITE_PUTUTXLINE 1
+_ACEOF
+
+
+fi
+
+       ;;
+*-*-dragonfly*)
+       SSHDLIBS="$SSHDLIBS -lcrypt"
+       ;;
+*-*-haiku*)
+    LIBS="$LIBS -lbsd "
+
+{ echo "$as_me:$LINENO: checking for socket in -lnetwork" >&5
+echo $ECHO_N "checking for socket in -lnetwork... $ECHO_C" >&6; }
+if test "${ac_cv_lib_network_socket+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnetwork  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_network_socket=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_network_socket=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_network_socket" >&5
+echo "${ECHO_T}$ac_cv_lib_network_socket" >&6; }
+if test $ac_cv_lib_network_socket = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNETWORK 1
+_ACEOF
+
+  LIBS="-lnetwork $LIBS"
+
+fi
+
+    cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INT64_T 1
+_ACEOF
+
+    MANTYPE=man
+    ;;
+*-*-hpux*)
+       # first we define all of the options common to all HP-UX releases
+       CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
+       IPADDR_IN_DISPLAY=yes
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LOGIN_NO_ENDOPT 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOGIN_NEEDS_UTMPX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*"
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SPT_TYPE SPT_PSTAT
+_ACEOF
+
+       MAIL="/var/mail/username"
+       LIBS="$LIBS -lsec"
+
+{ echo "$as_me:$LINENO: checking for t_error in -lxnet" >&5
+echo $ECHO_N "checking for t_error in -lxnet... $ECHO_C" >&6; }
+if test "${ac_cv_lib_xnet_t_error+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxnet  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char t_error ();
+int
+main ()
+{
+return t_error ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_xnet_t_error=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_xnet_t_error=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_xnet_t_error" >&5
+echo "${ECHO_T}$ac_cv_lib_xnet_t_error" >&6; }
+if test $ac_cv_lib_xnet_t_error = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBXNET 1
+_ACEOF
+
+  LIBS="-lxnet $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: *** -lxnet needed on HP-UX - check config.log ***" >&5
+echo "$as_me: error: *** -lxnet needed on HP-UX - check config.log ***" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+       # next, we define all of the options specific to major releases
+       case "$host" in
+       *-*-hpux10*)
+               if test -z "$GCC"; then
+                       CFLAGS="$CFLAGS -Ae"
+               fi
+               ;;
+       *-*-hpux11*)
+
+cat >>confdefs.h <<\_ACEOF
+#define PAM_SUN_CODEBASE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_UTMP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_BTMP 1
+_ACEOF
+
+               check_for_hpux_broken_getaddrinfo=1
+               check_for_conflicting_getspnam=1
+               ;;
+       esac
+
+       # lastly, we define options specific to minor releases
+       case "$host" in
+       *-*-hpux10.26)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SECUREWARE 1
+_ACEOF
+
+               disable_ptmx_check=yes
+               LIBS="$LIBS -lsecpw"
+               ;;
+       esac
+       ;;
+*-*-irix5*)
+       PATH="$PATH:/usr/etc"
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_INET_NTOA 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_ABBREV_NO_TTY 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*LK*"
+_ACEOF
+
+       ;;
+*-*-irix6*)
+       PATH="$PATH:/usr/etc"
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_IRIX_ARRAY 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_IRIX_PROJECT 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_IRIX_AUDIT 1
+_ACEOF
+
+       { echo "$as_me:$LINENO: checking for jlimit_startjob" >&5
+echo $ECHO_N "checking for jlimit_startjob... $ECHO_C" >&6; }
+if test "${ac_cv_func_jlimit_startjob+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define jlimit_startjob to an innocuous variant, in case <limits.h> declares jlimit_startjob.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define jlimit_startjob innocuous_jlimit_startjob
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char jlimit_startjob (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef jlimit_startjob
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jlimit_startjob ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_jlimit_startjob || defined __stub___jlimit_startjob
+choke me
+#endif
+
+int
+main ()
+{
+return jlimit_startjob ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_jlimit_startjob=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_jlimit_startjob=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_jlimit_startjob" >&5
+echo "${ECHO_T}$ac_cv_func_jlimit_startjob" >&6; }
+if test $ac_cv_func_jlimit_startjob = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_IRIX_JOBS 1
+_ACEOF
+
+fi
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_INET_NTOA 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_UPDWTMPX 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define WITH_ABBREV_NO_TTY 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*LK*"
+_ACEOF
+
+       ;;
+*-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
+       check_for_libcrypt_later=1
+       cat >>confdefs.h <<\_ACEOF
+#define PAM_TTY_KLUDGE 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_PREFIX "!"
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SPT_TYPE SPT_REUSEARGV
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _PATH_BTMP "/var/log/btmp"
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_BTMP 1
+_ACEOF
+
+       ;;
+*-*-linux*)
+       no_dev_ptmx=1
+       check_for_libcrypt_later=1
+       check_for_openpty_ctty_bug=1
+
+cat >>confdefs.h <<\_ACEOF
+#define PAM_TTY_KLUDGE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_PREFIX "!"
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SPT_TYPE SPT_REUSEARGV
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINK_OPNOTSUPP_ERRNO EPERM
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _PATH_BTMP "/var/log/btmp"
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_BTMP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LINUX_OOM_ADJUST 1
+_ACEOF
+
+       inet6_default_4in6=yes
+       case `uname -r` in
+       1.*|2.0.*)
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_CMSG_TYPE 1
+_ACEOF
+
+               ;;
+       esac
+       # tun(4) forwarding compat code
+
+for ac_header in linux/if_tun.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+       if test "x$ac_cv_header_linux_if_tun_h" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_LINUX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_COMPAT_AF 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_PREPEND_AF 1
+_ACEOF
+
+       fi
+       ;;
+mips-sony-bsd|mips-sony-newsos4)
+
+cat >>confdefs.h <<\_ACEOF
+#define NEED_SETPGRP 1
+_ACEOF
+
+       SONY=1
+       ;;
+*-*-netbsd*)
+       check_for_libcrypt_before=1
+       if test "x$withval" != "xno" ; then
+               need_dash_r=1
+       fi
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_FREEBSD 1
+_ACEOF
+
+       if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for net/if_tap.h" >&5
+echo $ECHO_N "checking for net/if_tap.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_net_if_tap_h" >&5
+echo "${ECHO_T}$ac_cv_header_net_if_tap_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking net/if_tap.h usability" >&5
+echo $ECHO_N "checking net/if_tap.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <net/if_tap.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking net/if_tap.h presence" >&5
+echo $ECHO_N "checking net/if_tap.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <net/if_tap.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: net/if_tap.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: net/if_tap.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: net/if_tap.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: net/if_tap.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: net/if_tap.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: net/if_tap.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: net/if_tap.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: net/if_tap.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for net/if_tap.h" >&5
+echo $ECHO_N "checking for net/if_tap.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_net_if_tap_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_net_if_tap_h" >&5
+echo "${ECHO_T}$ac_cv_header_net_if_tap_h" >&6; }
+
+fi
+if test $ac_cv_header_net_if_tap_h = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_NO_L2 1
+_ACEOF
+
+fi
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_PREPEND_AF 1
+_ACEOF
+
+       ;;
+*-*-freebsd*)
+       check_for_libcrypt_later=1
+
+cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_PREFIX "*LOCKED*"
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_FREEBSD 1
+_ACEOF
+
+       if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for net/if_tap.h" >&5
+echo $ECHO_N "checking for net/if_tap.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_net_if_tap_h" >&5
+echo "${ECHO_T}$ac_cv_header_net_if_tap_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking net/if_tap.h usability" >&5
+echo $ECHO_N "checking net/if_tap.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <net/if_tap.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking net/if_tap.h presence" >&5
+echo $ECHO_N "checking net/if_tap.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <net/if_tap.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: net/if_tap.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: net/if_tap.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: net/if_tap.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: net/if_tap.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: net/if_tap.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: net/if_tap.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: net/if_tap.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: net/if_tap.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: net/if_tap.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for net/if_tap.h" >&5
+echo $ECHO_N "checking for net/if_tap.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_net_if_tap_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_net_if_tap_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_net_if_tap_h" >&5
+echo "${ECHO_T}$ac_cv_header_net_if_tap_h" >&6; }
+
+fi
+if test $ac_cv_header_net_if_tap_h = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_NO_L2 1
+_ACEOF
+
+fi
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GLOB 1
+_ACEOF
+
+       ;;
+*-*-bsdi*)
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       ;;
+*-next-*)
+       conf_lastlog_location="/usr/adm/lastlog"
+       conf_utmp_location=/etc/utmp
+       conf_wtmp_location=/usr/adm/wtmp
+       MAIL=/usr/spool/mail
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NEXT 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_REALPATH 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SAVED_UIDS 1
+_ACEOF
+
+       ;;
+*-*-openbsd*)
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ATTRIBUTE__SENTINEL__ 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ATTRIBUTE__BOUNDED__ 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_TUN_OPENBSD 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SYSLOG_R_SAFE_IN_SIGHAND 1
+_ACEOF
+
+       ;;
+*-*-solaris*)
+       if test "x$withval" != "xno" ; then
+               need_dash_r=1
+       fi
+       cat >>confdefs.h <<\_ACEOF
+#define PAM_SUN_CODEBASE 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOGIN_NEEDS_UTMPX 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define LOGIN_NEEDS_TERM 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define PAM_TTY_KLUDGE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SSHPAM_CHAUTHTOK_NEEDS_RUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*LK*"
+_ACEOF
+
+       # Pushing STREAMS modules will cause sshd to acquire a controlling tty.
+
+cat >>confdefs.h <<\_ACEOF
+#define SSHD_ACQUIRES_CTTY 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PASSWD_NEEDS_USERNAME 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_TCGETATTR_ICANON 1
+_ACEOF
+
+       external_path_file=/etc/default/login
+       # hardwire lastlog location (can't detect it on some versions)
+       conf_lastlog_location="/var/adm/lastlog"
+       { echo "$as_me:$LINENO: checking for obsolete utmp and wtmp in solaris2.x" >&5
+echo $ECHO_N "checking for obsolete utmp and wtmp in solaris2.x... $ECHO_C" >&6; }
+       sol2ver=`echo "$host"| sed -e 's/.*[0-9]\.//'`
+       if test "$sol2ver" -ge 8; then
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+               cat >>confdefs.h <<\_ACEOF
+#define DISABLE_UTMP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_WTMP 1
+_ACEOF
+
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+# Check whether --with-solaris-contracts was given.
+if test "${with_solaris_contracts+set}" = set; then
+  withval=$with_solaris_contracts;
+               { echo "$as_me:$LINENO: checking for ct_tmpl_activate in -lcontract" >&5
+echo $ECHO_N "checking for ct_tmpl_activate in -lcontract... $ECHO_C" >&6; }
+if test "${ac_cv_lib_contract_ct_tmpl_activate+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcontract  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ct_tmpl_activate ();
+int
+main ()
+{
+return ct_tmpl_activate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_contract_ct_tmpl_activate=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_contract_ct_tmpl_activate=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_contract_ct_tmpl_activate" >&5
+echo "${ECHO_T}$ac_cv_lib_contract_ct_tmpl_activate" >&6; }
+if test $ac_cv_lib_contract_ct_tmpl_activate = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_SOLARIS_PROCESS_CONTRACTS 1
+_ACEOF
+
+                         SSHDLIBS="$SSHDLIBS -lcontract"
+                         SPC_MSG="yes"
+fi
+
+
+fi
+
+
+# Check whether --with-solaris-projects was given.
+if test "${with_solaris_projects+set}" = set; then
+  withval=$with_solaris_projects;
+               { echo "$as_me:$LINENO: checking for setproject in -lproject" >&5
+echo $ECHO_N "checking for setproject in -lproject... $ECHO_C" >&6; }
+if test "${ac_cv_lib_project_setproject+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lproject  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setproject ();
+int
+main ()
+{
+return setproject ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_project_setproject=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_project_setproject=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_project_setproject" >&5
+echo "${ECHO_T}$ac_cv_lib_project_setproject" >&6; }
+if test $ac_cv_lib_project_setproject = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_SOLARIS_PROJECTS 1
+_ACEOF
+
+                       SSHDLIBS="$SSHDLIBS -lproject"
+                       SP_MSG="yes"
+fi
+
+
+fi
+
+       ;;
+*-*-sunos4*)
+       CPPFLAGS="$CPPFLAGS -DSUNOS4"
+
+for ac_func in getpwanam
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+       cat >>confdefs.h <<\_ACEOF
+#define PAM_SUN_CODEBASE 1
+_ACEOF
+
+       conf_utmp_location=/etc/utmp
+       conf_wtmp_location=/var/adm/wtmp
+       conf_lastlog_location=/var/adm/lastlog
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       ;;
+*-ncr-sysv*)
+       LIBS="$LIBS -lc89"
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SSHD_ACQUIRES_CTTY 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       ;;
+*-sni-sysv*)
+       # /usr/ucblib MUST NOT be searched on ReliantUNIX
+
+{ echo "$as_me:$LINENO: checking for dlsym in -ldl" >&5
+echo $ECHO_N "checking for dlsym in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_dlsym+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlsym ();
+int
+main ()
+{
+return dlsym ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_dl_dlsym=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dl_dlsym=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlsym" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlsym" >&6; }
+if test $ac_cv_lib_dl_dlsym = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+  LIBS="-ldl $LIBS"
+
+fi
+
+       # -lresolv needs to be at the end of LIBS or DNS lookups break
+       { echo "$as_me:$LINENO: checking for res_query in -lresolv" >&5
+echo $ECHO_N "checking for res_query in -lresolv... $ECHO_C" >&6; }
+if test "${ac_cv_lib_resolv_res_query+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char res_query ();
+int
+main ()
+{
+return res_query ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_resolv_res_query=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_resolv_res_query=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_res_query" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_res_query" >&6; }
+if test $ac_cv_lib_resolv_res_query = yes; then
+   LIBS="$LIBS -lresolv"
+fi
+
+       IPADDR_IN_DISPLAY=yes
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define IP_TOS_IS_BROKEN 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SSHD_ACQUIRES_CTTY 1
+_ACEOF
+
+       external_path_file=/etc/default/login
+       # /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
+       ;;
+# UnixWare 1.x, UnixWare 2.x, and others based on code from Univel.
+*-*-sysv4.2*)
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PASSWD_NEEDS_USERNAME 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*LK*"
+_ACEOF
+
+       ;;
+# UnixWare 7.x, OpenUNIX 8
+*-*-sysv5*)
+       CPPFLAGS="$CPPFLAGS -Dvsnprintf=_xvsnprintf -Dsnprintf=_xsnprintf"
+
+cat >>confdefs.h <<\_ACEOF
+#define UNIXWARE_LONG_PASSWORDS 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define PASSWD_NEEDS_USERNAME 1
+_ACEOF
+
+       case "$host" in
+       *-*-sysv5SCO_SV*)       # SCO OpenServer 6.x
+               TEST_SHELL=/u95/bin/sh
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_LIBIAF 1
+_ACEOF
+
+               cat >>confdefs.h <<\_ACEOF
+#define BROKEN_UPDWTMPX 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: checking for getluid in -lprot" >&5
+echo $ECHO_N "checking for getluid in -lprot... $ECHO_C" >&6; }
+if test "${ac_cv_lib_prot_getluid+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lprot  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getluid ();
+int
+main ()
+{
+return getluid ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_prot_getluid=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_prot_getluid=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_prot_getluid" >&5
+echo "${ECHO_T}$ac_cv_lib_prot_getluid" >&6; }
+if test $ac_cv_lib_prot_getluid = yes; then
+   LIBS="$LIBS -lprot"
+
+
+for ac_func in getluid setluid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_SECUREWARE 1
+_ACEOF
+
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_SHADOW 1
+_ACEOF
+
+
+fi
+
+               ;;
+       *)      cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_STRING "*LK*"
+_ACEOF
+
+               check_for_libcrypt_later=1
+               ;;
+       esac
+       ;;
+*-*-sysv*)
+       ;;
+# SCO UNIX and OEM versions of SCO UNIX
+*-*-sco3.2v4*)
+       { { echo "$as_me:$LINENO: error: \"This Platform is no longer supported.\"" >&5
+echo "$as_me: error: \"This Platform is no longer supported.\"" >&2;}
+   { (exit 1); exit 1; }; }
+       ;;
+# SCO OpenServer 5.x
+*-*-sco3.2v5*)
+       if test -z "$GCC"; then
+               CFLAGS="$CFLAGS -belf"
+       fi
+       LIBS="$LIBS -lprot -lx -ltinfo -lm"
+       no_dev_ptmx=1
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE_SECUREWARE 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_SHADOW 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define WITH_ABBREV_NO_TTY 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_UPDWTMPX 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define PASSWD_NEEDS_USERNAME 1
+_ACEOF
+
+
+
+for ac_func in getluid setluid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+       MANTYPE=man
+       TEST_SHELL=ksh
+       ;;
+*-*-unicosmk*)
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_SSH_LASTLOG 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+       LDFLAGS="$LDFLAGS"
+       LIBS="$LIBS -lgen -lrsc -lshare -luex -lacm"
+       MANTYPE=cat
+       ;;
+*-*-unicosmp*)
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define WITH_ABBREV_NO_TTY 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+       LDFLAGS="$LDFLAGS"
+       LIBS="$LIBS -lgen -lacid -ldb"
+       MANTYPE=cat
+       ;;
+*-*-unicos*)
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define NO_SSH_LASTLOG 1
+_ACEOF
+
+       LDFLAGS="$LDFLAGS -Wl,-Dmsglevel=334:fatal"
+       LIBS="$LIBS -lgen -lrsc -lshare -luex -lacm"
+       MANTYPE=cat
+       ;;
+*-dec-osf*)
+       { echo "$as_me:$LINENO: checking for Digital Unix SIA" >&5
+echo $ECHO_N "checking for Digital Unix SIA... $ECHO_C" >&6; }
+       no_osfsia=""
+
+# Check whether --with-osfsia was given.
+if test "${with_osfsia+set}" = set; then
+  withval=$with_osfsia;
+                       if test "x$withval" = "xno" ; then
+                               { echo "$as_me:$LINENO: result: disabled" >&5
+echo "${ECHO_T}disabled" >&6; }
+                               no_osfsia=1
+                       fi
+
+fi
+
+       if test -z "$no_osfsia" ; then
+               if test -f /etc/sia/matrix.conf; then
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OSF_SIA 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LOGIN 1
+_ACEOF
+
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+                       LIBS="$LIBS -lsecurity -ldb -lm -laud"
+                       SIA_MSG="yes"
+               else
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define LOCKED_PASSWD_SUBSTR "Nologin"
+_ACEOF
+
+               fi
+       fi
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SETEUID_BREAKS_SETUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREUID 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETREGID 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_READV_COMPARISON 1
+_ACEOF
+
+       ;;
+
+*-*-nto-qnx*)
+       cat >>confdefs.h <<\_ACEOF
+#define USE_PIPES 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define NO_X11_UNIX_SOCKETS 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MISSING_NFDBITS 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MISSING_HOWMANY 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define MISSING_FD_MASK 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LASTLOG 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define SSHD_ACQUIRES_CTTY 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SHADOW_EXPIRE 1
+_ACEOF
+
+       enable_etc_default_login=no     # has incompatible /etc/default/login
+       case "$host" in
+       *-*-nto-qnx6*)
+               cat >>confdefs.h <<\_ACEOF
+#define DISABLE_FD_PASSING 1
+_ACEOF
+
+               ;;
+       esac
+       ;;
+
+*-*-ultrix*)
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETGROUPS 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_MMAP 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define NEED_SETPGRP 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_SYSLOG_H 1
+_ACEOF
+
+       ;;
+
+*-*-lynxos)
+        CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"
+       cat >>confdefs.h <<\_ACEOF
+#define MISSING_HOWMANY 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETVBUF 1
+_ACEOF
+
+        ;;
+esac
+
+{ echo "$as_me:$LINENO: checking compiler and flags for sanity" >&5
+echo $ECHO_N "checking compiler and flags for sanity... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+       { echo "$as_me:$LINENO: WARNING: cross compiling: not checking compiler sanity" >&5
+echo "$as_me: WARNING: cross compiling: not checking compiler sanity" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+int main(){exit(0);}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               { { echo "$as_me:$LINENO: error: *** compiler cannot create working executables, check config.log ***" >&5
+echo "$as_me: error: *** compiler cannot create working executables, check config.log ***" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+# Checks for libraries.
+{ echo "$as_me:$LINENO: checking for yp_match" >&5
+echo $ECHO_N "checking for yp_match... $ECHO_C" >&6; }
+if test "${ac_cv_func_yp_match+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define yp_match to an innocuous variant, in case <limits.h> declares yp_match.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define yp_match innocuous_yp_match
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char yp_match (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef yp_match
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char yp_match ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_yp_match || defined __stub___yp_match
+choke me
+#endif
+
+int
+main ()
+{
+return yp_match ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_yp_match=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_yp_match=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_yp_match" >&5
+echo "${ECHO_T}$ac_cv_func_yp_match" >&6; }
+if test $ac_cv_func_yp_match = yes; then
+  :
+else
+
+{ echo "$as_me:$LINENO: checking for yp_match in -lnsl" >&5
+echo $ECHO_N "checking for yp_match in -lnsl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_nsl_yp_match+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char yp_match ();
+int
+main ()
+{
+return yp_match ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_nsl_yp_match=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_yp_match=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_yp_match" >&5
+echo "${ECHO_T}$ac_cv_lib_nsl_yp_match" >&6; }
+if test $ac_cv_lib_nsl_yp_match = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+  LIBS="-lnsl $LIBS"
+
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: checking for setsockopt" >&5
+echo $ECHO_N "checking for setsockopt... $ECHO_C" >&6; }
+if test "${ac_cv_func_setsockopt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define setsockopt to an innocuous variant, in case <limits.h> declares setsockopt.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define setsockopt innocuous_setsockopt
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char setsockopt (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef setsockopt
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setsockopt ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_setsockopt || defined __stub___setsockopt
+choke me
+#endif
+
+int
+main ()
+{
+return setsockopt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_setsockopt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_setsockopt=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_setsockopt" >&5
+echo "${ECHO_T}$ac_cv_func_setsockopt" >&6; }
+if test $ac_cv_func_setsockopt = yes; then
+  :
+else
+
+{ echo "$as_me:$LINENO: checking for setsockopt in -lsocket" >&5
+echo $ECHO_N "checking for setsockopt in -lsocket... $ECHO_C" >&6; }
+if test "${ac_cv_lib_socket_setsockopt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setsockopt ();
+int
+main ()
+{
+return setsockopt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_socket_setsockopt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_setsockopt=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_setsockopt" >&5
+echo "${ECHO_T}$ac_cv_lib_socket_setsockopt" >&6; }
+if test $ac_cv_lib_socket_setsockopt = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+fi
+
+fi
+
+
+
+for ac_func in dirname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+for ac_header in libgen.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+else
+
+       { echo "$as_me:$LINENO: checking for dirname in -lgen" >&5
+echo $ECHO_N "checking for dirname in -lgen... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gen_dirname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgen  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dirname ();
+int
+main ()
+{
+return dirname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gen_dirname=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gen_dirname=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gen_dirname" >&5
+echo "${ECHO_T}$ac_cv_lib_gen_dirname" >&6; }
+if test $ac_cv_lib_gen_dirname = yes; then
+
+               { echo "$as_me:$LINENO: checking for broken dirname" >&5
+echo $ECHO_N "checking for broken dirname... $ECHO_C" >&6; }
+if test "${ac_cv_have_broken_dirname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+                       save_LIBS="$LIBS"
+                       LIBS="$LIBS -lgen"
+                       if test "$cross_compiling" = yes; then
+   ac_cv_have_broken_dirname="no"
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#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);
+    }
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   ac_cv_have_broken_dirname="no"
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ ac_cv_have_broken_dirname="yes"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+                       LIBS="$save_LIBS"
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_broken_dirname" >&5
+echo "${ECHO_T}$ac_cv_have_broken_dirname" >&6; }
+               if test "x$ac_cv_have_broken_dirname" = "xno" ; then
+                       LIBS="$LIBS -lgen"
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_DIRNAME 1
+_ACEOF
+
+
+for ac_header in libgen.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+               fi
+
+fi
+
+
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for getspnam" >&5
+echo $ECHO_N "checking for getspnam... $ECHO_C" >&6; }
+if test "${ac_cv_func_getspnam+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define getspnam to an innocuous variant, in case <limits.h> declares getspnam.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define getspnam innocuous_getspnam
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getspnam (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getspnam
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getspnam ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_getspnam || defined __stub___getspnam
+choke me
+#endif
+
+int
+main ()
+{
+return getspnam ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_getspnam=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_getspnam=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_getspnam" >&5
+echo "${ECHO_T}$ac_cv_func_getspnam" >&6; }
+if test $ac_cv_func_getspnam = yes; then
+  :
+else
+  { echo "$as_me:$LINENO: checking for getspnam in -lgen" >&5
+echo $ECHO_N "checking for getspnam in -lgen... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gen_getspnam+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgen  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getspnam ();
+int
+main ()
+{
+return getspnam ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gen_getspnam=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gen_getspnam=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gen_getspnam" >&5
+echo "${ECHO_T}$ac_cv_lib_gen_getspnam" >&6; }
+if test $ac_cv_lib_gen_getspnam = yes; then
+  LIBS="$LIBS -lgen"
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: checking for library containing basename" >&5
+echo $ECHO_N "checking for library containing basename... $ECHO_C" >&6; }
+if test "${ac_cv_search_basename+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char basename ();
+int
+main ()
+{
+return basename ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' gen; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_basename=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_basename+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_basename+set}" = set; then
+  :
+else
+  ac_cv_search_basename=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_basename" >&5
+echo "${ECHO_T}$ac_cv_search_basename" >&6; }
+ac_res=$ac_cv_search_basename
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_BASENAME 1
+_ACEOF
+
+fi
+
+
+
+# Check whether --with-zlib was given.
+if test "${with_zlib+set}" = set; then
+  withval=$with_zlib;  if test "x$withval" = "xno" ; then
+               { { echo "$as_me:$LINENO: error: *** zlib is required ***" >&5
+echo "$as_me: error: *** zlib is required ***" >&2;}
+   { (exit 1); exit 1; }; }
+         elif 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
+
+fi
+
+
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking zlib.h usability" >&5
+echo $ECHO_N "checking zlib.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <zlib.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking zlib.h presence" >&5
+echo $ECHO_N "checking zlib.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <zlib.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: zlib.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: zlib.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: zlib.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: zlib.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: zlib.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: zlib.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: zlib.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: zlib.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: zlib.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for zlib.h" >&5
+echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_zlib_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_zlib_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5
+echo "${ECHO_T}$ac_cv_header_zlib_h" >&6; }
+
+fi
+if test $ac_cv_header_zlib_h = yes; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: *** zlib.h missing - please install first or check config.log ***" >&5
+echo "$as_me: error: *** zlib.h missing - please install first or check config.log ***" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking for deflate in -lz" >&5
+echo $ECHO_N "checking for deflate in -lz... $ECHO_C" >&6; }
+if test "${ac_cv_lib_z_deflate+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char deflate ();
+int
+main ()
+{
+return deflate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_z_deflate=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_z_deflate=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_z_deflate" >&5
+echo "${ECHO_T}$ac_cv_lib_z_deflate" >&6; }
+if test $ac_cv_lib_z_deflate = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+  LIBS="-lz $LIBS"
+
+else
+
+               saved_CPPFLAGS="$CPPFLAGS"
+               saved_LDFLAGS="$LDFLAGS"
+               save_LIBS="$LIBS"
+                               if test -n "${need_dash_r}"; then
+                       LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}"
+               else
+                       LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}"
+               fi
+               CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}"
+               LIBS="$LIBS -lz"
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char deflate ();
+int
+main ()
+{
+return deflate ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                               { { echo "$as_me:$LINENO: error: *** zlib missing - please install first or check config.log ***" >&5
+echo "$as_me: error: *** zlib missing - please install first or check config.log ***" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+
+
+# Check whether --with-zlib-version-check was given.
+if test "${with_zlib_version_check+set}" = set; then
+  withval=$with_zlib_version_check;   if test "x$withval" = "xno" ; then
+               zlib_check_nonfatal=1
+          fi
+
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for possibly buggy zlib" >&5
+echo $ECHO_N "checking for possibly buggy zlib... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+       { echo "$as_me:$LINENO: WARNING: cross compiling: not checking zlib version" >&5
+echo "$as_me: WARNING: cross compiling: not checking zlib version" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <zlib.h>
+int main()
+{
+       int a=0, b=0, c=0, d=0, n, v;
+       n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
+       if (n != 3 && n != 4)
+               exit(1);
+       v = a*1000000 + b*10000 + c*100 + d;
+       fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);
+
+       /* 1.1.4 is OK */
+       if (a == 1 && b == 1 && c >= 4)
+               exit(0);
+
+       /* 1.2.3 and up are OK */
+       if (v >= 1020300)
+               exit(0);
+
+       exit(2);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+         if test -z "$zlib_check_nonfatal" ; then
+               { { echo "$as_me:$LINENO: error: *** zlib too old - check config.log ***
+Your reported zlib version has known security problems.  It's possible your
+vendor has fixed these problems without changing the version number.  If you
+are sure this is the case, you can disable the check by running
+\"./configure --without-zlib-version-check\".
+If you are in doubt, upgrade zlib to version 1.2.3 or greater.
+See http://www.gzip.org/zlib/ for details." >&5
+echo "$as_me: error: *** zlib too old - check config.log ***
+Your reported zlib version has known security problems.  It's possible your
+vendor has fixed these problems without changing the version number.  If you
+are sure this is the case, you can disable the check by running
+\"./configure --without-zlib-version-check\".
+If you are in doubt, upgrade zlib to version 1.2.3 or greater.
+See http://www.gzip.org/zlib/ for details." >&2;}
+   { (exit 1); exit 1; }; }
+         else
+               { echo "$as_me:$LINENO: WARNING: zlib version may have security problems" >&5
+echo "$as_me: WARNING: zlib version may have security problems" >&2;}
+         fi
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking for strcasecmp" >&5
+echo $ECHO_N "checking for strcasecmp... $ECHO_C" >&6; }
+if test "${ac_cv_func_strcasecmp+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define strcasecmp to an innocuous variant, in case <limits.h> declares strcasecmp.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define strcasecmp innocuous_strcasecmp
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strcasecmp (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef strcasecmp
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strcasecmp ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_strcasecmp || defined __stub___strcasecmp
+choke me
+#endif
+
+int
+main ()
+{
+return strcasecmp ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_strcasecmp=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_strcasecmp=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_strcasecmp" >&5
+echo "${ECHO_T}$ac_cv_func_strcasecmp" >&6; }
+if test $ac_cv_func_strcasecmp = yes; then
+  :
+else
+   { echo "$as_me:$LINENO: checking for strcasecmp in -lresolv" >&5
+echo $ECHO_N "checking for strcasecmp in -lresolv... $ECHO_C" >&6; }
+if test "${ac_cv_lib_resolv_strcasecmp+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lresolv  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strcasecmp ();
+int
+main ()
+{
+return strcasecmp ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_resolv_strcasecmp=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_resolv_strcasecmp=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_strcasecmp" >&5
+echo "${ECHO_T}$ac_cv_lib_resolv_strcasecmp" >&6; }
+if test $ac_cv_lib_resolv_strcasecmp = yes; then
+  LIBS="$LIBS -lresolv"
+fi
+
+
+fi
+
+
+for ac_func in utimes
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+   { echo "$as_me:$LINENO: checking for utimes in -lc89" >&5
+echo $ECHO_N "checking for utimes in -lc89... $ECHO_C" >&6; }
+if test "${ac_cv_lib_c89_utimes+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc89  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char utimes ();
+int
+main ()
+{
+return utimes ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_c89_utimes=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_c89_utimes=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_c89_utimes" >&5
+echo "${ECHO_T}$ac_cv_lib_c89_utimes" >&6; }
+if test $ac_cv_lib_c89_utimes = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_UTIMES 1
+_ACEOF
+
+                                       LIBS="$LIBS -lc89"
+fi
+
+
+fi
+done
+
+
+
+for ac_header in libutil.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ echo "$as_me:$LINENO: checking for library containing login" >&5
+echo $ECHO_N "checking for library containing login... $ECHO_C" >&6; }
+if test "${ac_cv_search_login+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char login ();
+int
+main ()
+{
+return login ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' util bsd; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_login=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_login+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_login+set}" = set; then
+  :
+else
+  ac_cv_search_login=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_login" >&5
+echo "${ECHO_T}$ac_cv_search_login" >&6; }
+ac_res=$ac_cv_search_login
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LOGIN 1
+_ACEOF
+
+fi
+
+
+
+
+
+for ac_func in fmt_scaled logout updwtmp logwtmp
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+for ac_func in strftime
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  # strftime is in -lintl on SCO UNIX.
+{ echo "$as_me:$LINENO: checking for strftime in -lintl" >&5
+echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_intl_strftime+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lintl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char strftime ();
+int
+main ()
+{
+return strftime ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_intl_strftime=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_intl_strftime=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5
+echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6; }
+if test $ac_cv_lib_intl_strftime = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRFTIME 1
+_ACEOF
+
+LIBS="-lintl $LIBS"
+fi
+
+fi
+done
+
+
+# Check for ALTDIRFUNC glob() extension
+{ echo "$as_me:$LINENO: checking for GLOB_ALTDIRFUNC support" >&5
+echo $ECHO_N "checking for GLOB_ALTDIRFUNC support... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+               #include <glob.h>
+               #ifdef GLOB_ALTDIRFUNC
+               FOUNDIT
+               #endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "FOUNDIT" >/dev/null 2>&1; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define GLOB_HAS_ALTDIRFUNC 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+
+fi
+rm -f conftest*
+
+
+# Check for g.gl_matchc glob() extension
+{ echo "$as_me:$LINENO: checking for gl_matchc field in glob_t" >&5
+echo $ECHO_N "checking for gl_matchc field in glob_t... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <glob.h>
+int
+main ()
+{
+glob_t g; g.gl_matchc = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define GLOB_HAS_GL_MATCHC 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Check for g.gl_statv glob() extension
+{ echo "$as_me:$LINENO: checking for gl_statv and GLOB_KEEPSTAT extensions for glob" >&5
+echo $ECHO_N "checking for gl_statv and GLOB_KEEPSTAT extensions for glob... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <glob.h>
+int
+main ()
+{
+
+#ifndef GLOB_KEEPSTAT
+#error "glob does not support GLOB_KEEPSTAT extension"
+#endif
+glob_t g;
+g.gl_statv = NULL;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define GLOB_HAS_GL_STATV 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ echo "$as_me:$LINENO: checking whether GLOB_NOMATCH is declared" >&5
+echo $ECHO_N "checking whether GLOB_NOMATCH is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_GLOB_NOMATCH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <glob.h>
+
+int
+main ()
+{
+#ifndef GLOB_NOMATCH
+  (void) GLOB_NOMATCH;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_GLOB_NOMATCH=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_GLOB_NOMATCH=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_GLOB_NOMATCH" >&5
+echo "${ECHO_T}$ac_cv_have_decl_GLOB_NOMATCH" >&6; }
+if test $ac_cv_have_decl_GLOB_NOMATCH = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GLOB_NOMATCH 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GLOB_NOMATCH 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether struct dirent allocates space for d_name" >&5
+echo $ECHO_N "checking whether struct dirent allocates space for d_name... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&5
+echo "$as_me: WARNING: cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME" >&2;}
+               cat >>confdefs.h <<\_ACEOF
+#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1
+_ACEOF
+
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <dirent.h>
+int main(void){struct dirent d;exit(sizeof(d.d_name)<=sizeof(char));}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_ONE_BYTE_DIRENT_D_NAME 1
+_ACEOF
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking for /proc/pid/fd directory" >&5
+echo $ECHO_N "checking for /proc/pid/fd directory... $ECHO_C" >&6; }
+if test -d "/proc/$$/fd" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PROC_PID 1
+_ACEOF
+
+       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+# Check whether user wants S/Key support
+SKEY_MSG="no"
+
+# Check whether --with-skey was given.
+if test "${with_skey+set}" = set; then
+  withval=$with_skey;
+               if test "x$withval" != "xno" ; then
+
+                       if test "x$withval" != "xyes" ; then
+                               CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                               LDFLAGS="$LDFLAGS -L${withval}/lib"
+                       fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define SKEY 1
+_ACEOF
+
+                       LIBS="-lskey $LIBS"
+                       SKEY_MSG="yes"
+
+                       { echo "$as_me:$LINENO: checking for s/key support" >&5
+echo $ECHO_N "checking for s/key support... $ECHO_C" >&6; }
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <skey.h>
+int main() { char *ff = skey_keyinfo(""); ff=""; exit(0); }
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                                       { { echo "$as_me:$LINENO: error: ** Incomplete or missing s/key libraries." >&5
+echo "$as_me: error: ** Incomplete or missing s/key libraries." >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+                       { echo "$as_me:$LINENO: checking if skeychallenge takes 4 arguments" >&5
+echo $ECHO_N "checking if skeychallenge takes 4 arguments... $ECHO_C" >&6; }
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+                                #include <skey.h>
+int
+main ()
+{
+(void)skeychallenge(NULL,"name","",0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define SKEYCHALLENGE_4ARG 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+               fi
+
+
+fi
+
+
+# Check whether user wants TCP wrappers support
+TCPW_MSG="no"
+
+# Check whether --with-tcp-wrappers was given.
+if test "${with_tcp_wrappers+set}" = set; then
+  withval=$with_tcp_wrappers;
+               if test "x$withval" != "xno" ; then
+                       saved_LIBS="$LIBS"
+                       saved_LDFLAGS="$LDFLAGS"
+                       saved_CPPFLAGS="$CPPFLAGS"
+                       if test -n "${withval}" && \
+                           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
+                       LIBS="-lwrap $LIBS"
+                       { echo "$as_me:$LINENO: checking for libwrap" >&5
+echo $ECHO_N "checking for libwrap... $ECHO_C" >&6; }
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <tcpd.h>
+                                       int deny_severity = 0, allow_severity = 0;
+
+int
+main ()
+{
+hosts_access(0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+                                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define LIBWRAP 1
+_ACEOF
+
+                                       SSHDLIBS="$SSHDLIBS -lwrap"
+                                       TCPW_MSG="yes"
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                                       { { echo "$as_me:$LINENO: error: *** libwrap missing" >&5
+echo "$as_me: error: *** libwrap missing" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+                       LIBS="$saved_LIBS"
+               fi
+
+
+fi
+
+
+# Check whether user wants libedit support
+LIBEDIT_MSG="no"
+
+# Check whether --with-libedit was given.
+if test "${with_libedit+set}" = set; then
+  withval=$with_libedit;  if test "x$withval" != "xno" ; then
+               if test "x$withval" = "xyes" ; then
+                       # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PKGCONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PKGCONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKGCONFIG="$PKGCONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_PKGCONFIG" && ac_cv_path_PKGCONFIG="no"
+  ;;
+esac
+fi
+PKGCONFIG=$ac_cv_path_PKGCONFIG
+if test -n "$PKGCONFIG"; then
+  { echo "$as_me:$LINENO: result: $PKGCONFIG" >&5
+echo "${ECHO_T}$PKGCONFIG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+                       if test "x$PKGCONFIG" != "xno"; then
+                               { echo "$as_me:$LINENO: checking if $PKGCONFIG knows about libedit" >&5
+echo $ECHO_N "checking if $PKGCONFIG knows about libedit... $ECHO_C" >&6; }
+                               if "$PKGCONFIG" libedit; then
+                                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+                                       use_pkgconfig_for_libedit=yes
+                               else
+                                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                               fi
+                       fi
+               else
+                       CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                       if test -n "${need_dash_r}"; then
+                               LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
+                       else
+                               LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+                       fi
+               fi
+               if test "x$use_pkgconfig_for_libedit" = "xyes"; then
+                       LIBEDIT=`$PKGCONFIG --libs-only-l libedit`
+                       CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libedit`"
+               else
+                       LIBEDIT="-ledit -lcurses"
+               fi
+               OTHERLIBS=`echo $LIBEDIT | sed 's/-ledit//'`
+               { echo "$as_me:$LINENO: checking for el_init in -ledit" >&5
+echo $ECHO_N "checking for el_init in -ledit... $ECHO_C" >&6; }
+if test "${ac_cv_lib_edit_el_init+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ledit  $OTHERLIBS
+                $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char el_init ();
+int
+main ()
+{
+return el_init ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_edit_el_init=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_edit_el_init=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_edit_el_init" >&5
+echo "${ECHO_T}$ac_cv_lib_edit_el_init" >&6; }
+if test $ac_cv_lib_edit_el_init = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_LIBEDIT 1
+_ACEOF
+
+                         LIBEDIT_MSG="yes"
+
+
+else
+   { { echo "$as_me:$LINENO: error: libedit not found" >&5
+echo "$as_me: error: libedit not found" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+               { echo "$as_me:$LINENO: checking if libedit version is compatible" >&5
+echo $ECHO_N "checking if libedit version is compatible... $ECHO_C" >&6; }
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <histedit.h>
+int main(void)
+{
+       int i = H_SETSIZE;
+       el_init("", NULL, NULL, NULL);
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                     { { echo "$as_me:$LINENO: error: libedit version is not compatible" >&5
+echo "$as_me: error: libedit version is not compatible" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       fi
+
+fi
+
+
+AUDIT_MODULE=none
+
+# Check whether --with-audit was given.
+if test "${with_audit+set}" = set; then
+  withval=$with_audit;
+         { echo "$as_me:$LINENO: checking for supported audit module" >&5
+echo $ECHO_N "checking for supported audit module... $ECHO_C" >&6; }
+         case "$withval" in
+         bsm)
+               { echo "$as_me:$LINENO: result: bsm" >&5
+echo "${ECHO_T}bsm" >&6; }
+               AUDIT_MODULE=bsm
+
+for ac_header in bsm/audit.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
+
+
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: BSM enabled and bsm/audit.h not found" >&5
+echo "$as_me: error: BSM enabled and bsm/audit.h not found" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+done
+
+
+{ echo "$as_me:$LINENO: checking for getaudit in -lbsm" >&5
+echo $ECHO_N "checking for getaudit in -lbsm... $ECHO_C" >&6; }
+if test "${ac_cv_lib_bsm_getaudit+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsm  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getaudit ();
+int
+main ()
+{
+return getaudit ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_bsm_getaudit=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_bsm_getaudit=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_bsm_getaudit" >&5
+echo "${ECHO_T}$ac_cv_lib_bsm_getaudit" >&6; }
+if test $ac_cv_lib_bsm_getaudit = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBSM 1
+_ACEOF
+
+  LIBS="-lbsm $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: BSM enabled and required library not found" >&5
+echo "$as_me: error: BSM enabled and required library not found" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+for ac_func in getaudit
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { { echo "$as_me:$LINENO: error: BSM enabled and required function not found" >&5
+echo "$as_me: error: BSM enabled and required function not found" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+done
+
+               # These are optional
+
+
+for ac_func in getaudit_addr aug_get_machine
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_BSM_AUDIT 1
+_ACEOF
+
+               ;;
+         linux)
+               { echo "$as_me:$LINENO: result: linux" >&5
+echo "${ECHO_T}linux" >&6; }
+               AUDIT_MODULE=linux
+
+for ac_header in libaudit.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+               SSHDLIBS="$SSHDLIBS -laudit"
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_LINUX_AUDIT 1
+_ACEOF
+
+               ;;
+         debug)
+               AUDIT_MODULE=debug
+               { echo "$as_me:$LINENO: result: debug" >&5
+echo "${ECHO_T}debug" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define SSH_AUDIT_EVENTS 1
+_ACEOF
+
+               ;;
+         no)
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               ;;
+         *)
+               { { echo "$as_me:$LINENO: error: Unknown audit module $withval" >&5
+echo "$as_me: error: Unknown audit module $withval" >&2;}
+   { (exit 1); exit 1; }; }
+               ;;
+       esac
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in \
+       arc4random \
+       arc4random_buf \
+       arc4random_uniform \
+       asprintf \
+       b64_ntop \
+       __b64_ntop \
+       b64_pton \
+       __b64_pton \
+       bcopy \
+       bindresvport_sa \
+       clock \
+       closefrom \
+       dirfd \
+       fchmod \
+       fchown \
+       freeaddrinfo \
+       fstatvfs \
+       futimes \
+       getaddrinfo \
+       getcwd \
+       getgrouplist \
+       getnameinfo \
+       getopt \
+       getpeereid \
+       getpeerucred \
+       _getpty \
+       getrlimit \
+       getttyent \
+       glob \
+       group_from_gid \
+       inet_aton \
+       inet_ntoa \
+       inet_ntop \
+       innetgr \
+       login_getcapbool \
+       md5_crypt \
+       memmove \
+       mkdtemp \
+       mmap \
+       ngetaddrinfo \
+       nsleep \
+       ogetaddrinfo \
+       openlog_r \
+       openpty \
+       poll \
+       prctl \
+       pstat \
+       readpassphrase \
+       realpath \
+       recvmsg \
+       rresvport_af \
+       sendmsg \
+       setdtablesize \
+       setegid \
+       setenv \
+       seteuid \
+       setgroupent \
+       setgroups \
+       setlogin \
+       setpassent\
+       setpcred \
+       setproctitle \
+       setregid \
+       setreuid \
+       setrlimit \
+       setsid \
+       setvbuf \
+       sigaction \
+       sigvec \
+       snprintf \
+       socketpair \
+       statfs \
+       statvfs \
+       strdup \
+       strerror \
+       strlcat \
+       strlcpy \
+       strmode \
+       strnvis \
+       strptime \
+       strtonum \
+       strtoll \
+       strtoul \
+       swap32 \
+       sysconf \
+       tcgetpgrp \
+       timingsafe_bcmp \
+       truncate \
+       unsetenv \
+       updwtmpx \
+       user_from_uid \
+       vasprintf \
+       vhangup \
+       vsnprintf \
+       waitpid \
+
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+cat >conftest.$ac_ext <<_ACEOF
+
+#include <ctype.h>
+int main(void)
+{
+       return (isblank('a'));
+}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ISBLANK 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+# PKCS#11 support requires dlopen() and co
+{ echo "$as_me:$LINENO: checking for library containing dlopen" >&5
+echo $ECHO_N "checking for library containing dlopen... $ECHO_C" >&6; }
+if test "${ac_cv_search_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' dl; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_dlopen=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_dlopen+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_dlopen+set}" = set; then
+  :
+else
+  ac_cv_search_dlopen=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_dlopen" >&5
+echo "${ECHO_T}$ac_cv_search_dlopen" >&6; }
+ac_res=$ac_cv_search_dlopen
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_PKCS11
+_ACEOF
+
+
+fi
+
+
+# IRIX has a const char return value for gai_strerror()
+
+for ac_func in gai_strerror
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+       cat >>confdefs.h <<\_ACEOF
+#define HAVE_GAI_STRERROR 1
+_ACEOF
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+const char *gai_strerror(int);
+int
+main ()
+{
+
+char *str;
+
+str = gai_strerror(0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CONST_GAI_STRERROR_PROTO 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for library containing nanosleep" >&5
+echo $ECHO_N "checking for library containing nanosleep... $ECHO_C" >&6; }
+if test "${ac_cv_search_nanosleep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char nanosleep ();
+int
+main ()
+{
+return nanosleep ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' rt posix4; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_nanosleep=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_nanosleep+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_nanosleep+set}" = set; then
+  :
+else
+  ac_cv_search_nanosleep=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_nanosleep" >&5
+echo "${ECHO_T}$ac_cv_search_nanosleep" >&6; }
+ac_res=$ac_cv_search_nanosleep
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_NANOSLEEP 1
+_ACEOF
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether getrusage is declared" >&5
+echo $ECHO_N "checking whether getrusage is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_getrusage+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+#ifndef getrusage
+  (void) getrusage;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_getrusage=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_getrusage=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_getrusage" >&5
+echo "${ECHO_T}$ac_cv_have_decl_getrusage" >&6; }
+if test $ac_cv_have_decl_getrusage = yes; then
+
+for ac_func in getrusage
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether strsep is declared" >&5
+echo $ECHO_N "checking whether strsep is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_strsep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+
+int
+main ()
+{
+#ifndef strsep
+  (void) strsep;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_strsep=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_strsep=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_strsep" >&5
+echo "${ECHO_T}$ac_cv_have_decl_strsep" >&6; }
+if test $ac_cv_have_decl_strsep = yes; then
+
+for ac_func in strsep
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether tcsendbreak is declared" >&5
+echo $ECHO_N "checking whether tcsendbreak is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_tcsendbreak+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <termios.h>
+
+
+int
+main ()
+{
+#ifndef tcsendbreak
+  (void) tcsendbreak;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_tcsendbreak=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_tcsendbreak=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_tcsendbreak" >&5
+echo "${ECHO_T}$ac_cv_have_decl_tcsendbreak" >&6; }
+if test $ac_cv_have_decl_tcsendbreak = yes; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_TCSENDBREAK 1
+_ACEOF
+
+else
+
+for ac_func in tcsendbreak
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether h_errno is declared" >&5
+echo $ECHO_N "checking whether h_errno is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_h_errno+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <netdb.h>
+
+int
+main ()
+{
+#ifndef h_errno
+  (void) h_errno;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_h_errno=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_h_errno=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_h_errno" >&5
+echo "${ECHO_T}$ac_cv_have_decl_h_errno" >&6; }
+if test $ac_cv_have_decl_h_errno = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_H_ERRNO 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_H_ERRNO 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether SHUT_RD is declared" >&5
+echo $ECHO_N "checking whether SHUT_RD is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_SHUT_RD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+int
+main ()
+{
+#ifndef SHUT_RD
+  (void) SHUT_RD;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_SHUT_RD=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_SHUT_RD=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_SHUT_RD" >&5
+echo "${ECHO_T}$ac_cv_have_decl_SHUT_RD" >&6; }
+if test $ac_cv_have_decl_SHUT_RD = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SHUT_RD 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SHUT_RD 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether O_NONBLOCK is declared" >&5
+echo $ECHO_N "checking whether O_NONBLOCK is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_O_NONBLOCK+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+
+int
+main ()
+{
+#ifndef O_NONBLOCK
+  (void) O_NONBLOCK;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_O_NONBLOCK=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_O_NONBLOCK=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_O_NONBLOCK" >&5
+echo "${ECHO_T}$ac_cv_have_decl_O_NONBLOCK" >&6; }
+if test $ac_cv_have_decl_O_NONBLOCK = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_O_NONBLOCK 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_O_NONBLOCK 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether writev is declared" >&5
+echo $ECHO_N "checking whether writev is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_writev+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+
+int
+main ()
+{
+#ifndef writev
+  (void) writev;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_writev=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_writev=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_writev" >&5
+echo "${ECHO_T}$ac_cv_have_decl_writev" >&6; }
+if test $ac_cv_have_decl_writev = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_WRITEV 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_WRITEV 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether MAXSYMLINKS is declared" >&5
+echo $ECHO_N "checking whether MAXSYMLINKS is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_MAXSYMLINKS+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/param.h>
+
+
+int
+main ()
+{
+#ifndef MAXSYMLINKS
+  (void) MAXSYMLINKS;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_MAXSYMLINKS=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_MAXSYMLINKS=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_MAXSYMLINKS" >&5
+echo "${ECHO_T}$ac_cv_have_decl_MAXSYMLINKS" >&6; }
+if test $ac_cv_have_decl_MAXSYMLINKS = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MAXSYMLINKS 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_MAXSYMLINKS 0
+_ACEOF
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking whether offsetof is declared" >&5
+echo $ECHO_N "checking whether offsetof is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_offsetof+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stddef.h>
+
+
+int
+main ()
+{
+#ifndef offsetof
+  (void) offsetof;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_offsetof=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_offsetof=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_offsetof" >&5
+echo "${ECHO_T}$ac_cv_have_decl_offsetof" >&6; }
+if test $ac_cv_have_decl_offsetof = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OFFSETOF 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OFFSETOF 0
+_ACEOF
+
+
+fi
+
+
+
+
+for ac_func in setresuid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: checking if setresuid seems to work" >&5
+echo $ECHO_N "checking if setresuid seems to work... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+  { echo "$as_me:$LINENO: WARNING: cross compiling: not checking setresuid" >&5
+echo "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdlib.h>
+#include <errno.h>
+int main(){errno=0; setresuid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETRESUID 1
+_ACEOF
+
+                { echo "$as_me:$LINENO: result: not implemented" >&5
+echo "${ECHO_T}not implemented" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+fi
+done
+
+
+
+for ac_func in setresgid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+               { echo "$as_me:$LINENO: checking if setresgid seems to work" >&5
+echo $ECHO_N "checking if setresgid seems to work... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+  { echo "$as_me:$LINENO: WARNING: cross compiling: not checking setresuid" >&5
+echo "$as_me: WARNING: cross compiling: not checking setresuid" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdlib.h>
+#include <errno.h>
+int main(){errno=0; setresgid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SETRESGID 1
+_ACEOF
+
+                { echo "$as_me:$LINENO: result: not implemented" >&5
+echo "${ECHO_T}not implemented" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+fi
+done
+
+
+
+
+for ac_func in gettimeofday time
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+for ac_func in endutent getutent getutid getutline pututline setutent
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in utmpname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+for ac_func in endutxent getutxent getutxid getutxline getutxuser pututxline
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+for ac_func in setutxdb setutxent utmpxname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in getlastlogxbyname
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+{ echo "$as_me:$LINENO: checking for daemon" >&5
+echo $ECHO_N "checking for daemon... $ECHO_C" >&6; }
+if test "${ac_cv_func_daemon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define daemon to an innocuous variant, in case <limits.h> declares daemon.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define daemon innocuous_daemon
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char daemon (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef daemon
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char daemon ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_daemon || defined __stub___daemon
+choke me
+#endif
+
+int
+main ()
+{
+return daemon ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_daemon=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_daemon=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_daemon" >&5
+echo "${ECHO_T}$ac_cv_func_daemon" >&6; }
+if test $ac_cv_func_daemon = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAEMON 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: checking for daemon in -lbsd" >&5
+echo $ECHO_N "checking for daemon in -lbsd... $ECHO_C" >&6; }
+if test "${ac_cv_lib_bsd_daemon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char daemon ();
+int
+main ()
+{
+return daemon ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_bsd_daemon=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_bsd_daemon=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_daemon" >&5
+echo "${ECHO_T}$ac_cv_lib_bsd_daemon" >&6; }
+if test $ac_cv_lib_bsd_daemon = yes; then
+  LIBS="$LIBS -lbsd"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAEMON 1
+_ACEOF
+
+fi
+
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for getpagesize" >&5
+echo $ECHO_N "checking for getpagesize... $ECHO_C" >&6; }
+if test "${ac_cv_func_getpagesize+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define getpagesize to an innocuous variant, in case <limits.h> declares getpagesize.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define getpagesize innocuous_getpagesize
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char getpagesize (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef getpagesize
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getpagesize ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_getpagesize || defined __stub___getpagesize
+choke me
+#endif
+
+int
+main ()
+{
+return getpagesize ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_func_getpagesize=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_getpagesize=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_getpagesize" >&5
+echo "${ECHO_T}$ac_cv_func_getpagesize" >&6; }
+if test $ac_cv_func_getpagesize = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETPAGESIZE 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: checking for getpagesize in -lucb" >&5
+echo $ECHO_N "checking for getpagesize in -lucb... $ECHO_C" >&6; }
+if test "${ac_cv_lib_ucb_getpagesize+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lucb  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getpagesize ();
+int
+main ()
+{
+return getpagesize ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_ucb_getpagesize=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ucb_getpagesize=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_ucb_getpagesize" >&5
+echo "${ECHO_T}$ac_cv_lib_ucb_getpagesize" >&6; }
+if test $ac_cv_lib_ucb_getpagesize = yes; then
+  LIBS="$LIBS -lucb"; cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETPAGESIZE 1
+_ACEOF
+
+fi
+
+
+fi
+
+
+# Check for broken snprintf
+if test "x$ac_cv_func_snprintf" = "xyes" ; then
+       { echo "$as_me:$LINENO: checking whether snprintf correctly terminates long strings" >&5
+echo $ECHO_N "checking whether snprintf correctly terminates long strings... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+   { echo "$as_me:$LINENO: WARNING: cross compiling: Assuming working snprintf()" >&5
+echo "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+int main(void){char b[5];snprintf(b,5,"123456789");exit(b[4]!='\0');}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SNPRINTF 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&5
+echo "$as_me: WARNING: ****** Your snprintf() function is broken, complain to your vendor" >&2;}
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+# If we don't have a working asprintf, then we strongly depend on vsnprintf
+# returning the right thing on overflow: the number of characters it tried to
+# create (as per SUSv3)
+if test "x$ac_cv_func_asprintf" != "xyes" && \
+   test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+       { echo "$as_me:$LINENO: checking whether vsnprintf returns correct values on overflow" >&5
+echo $ECHO_N "checking whether vsnprintf returns correct values on overflow... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+   { echo "$as_me:$LINENO: WARNING: cross compiling: Assuming working vsnprintf()" >&5
+echo "$as_me: WARNING: cross compiling: Assuming working vsnprintf()" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+int x_snprintf(char *str,size_t count,const char *fmt,...)
+{
+       size_t ret; va_list ap;
+       va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+       return ret;
+}
+int main(void)
+{
+       char x[1];
+       exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SNPRINTF 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&5
+echo "$as_me: WARNING: ****** Your vsnprintf() function is broken, complain to your vendor" >&2;}
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+# On systems where [v]snprintf is broken, but is declared in stdio,
+# check that the fmt argument is const char * or just char *.
+# This is only useful for when BROKEN_SNPRINTF
+{ echo "$as_me:$LINENO: checking whether snprintf can declare const char *fmt" >&5
+echo $ECHO_N "checking whether snprintf can declare const char *fmt... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdio.h>
+          int snprintf(char *a, size_t b, const char *c, ...) { return 0; }
+          int main(void) { snprintf(0, 0, 0); }
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define SNPRINTF_CONST const
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+    cat >>confdefs.h <<\_ACEOF
+#define SNPRINTF_CONST /* not const */
+_ACEOF
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Check for missing getpeereid (or equiv) support
+NO_PEERCHECK=""
+if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then
+       { echo "$as_me:$LINENO: checking whether system supports SO_PEERCRED getsockopt" >&5
+echo $ECHO_N "checking whether system supports SO_PEERCRED getsockopt... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+                #include <sys/socket.h>
+int
+main ()
+{
+int i = SO_PEERCRED;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SO_PEERCRED 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               NO_PEERCHECK=1
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x$ac_cv_func_mkdtemp" = "xyes" ; then
+{ echo "$as_me:$LINENO: checking for (overly) strict mkstemp" >&5
+echo $ECHO_N "checking for (overly) strict mkstemp... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+               cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRICT_MKSTEMP 1
+_ACEOF
+
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdlib.h>
+main() { char template[]="conftest.mkstemp-test";
+if (mkstemp(template) == -1)
+       exit(1);
+unlink(template); exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRICT_MKSTEMP 1
+_ACEOF
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+if test ! -z "$check_for_openpty_ctty_bug"; then
+       { echo "$as_me:$LINENO: checking if openpty correctly handles controlling tty" >&5
+echo $ECHO_N "checking if openpty correctly handles controlling tty... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+
+                       { echo "$as_me:$LINENO: result: cross-compiling" >&5
+echo "${ECHO_T}cross-compiling" >&6; }
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int
+main()
+{
+       pid_t pid;
+       int fd, ptyfd, ttyfd, status;
+
+       pid = fork();
+       if (pid < 0) {          /* failed */
+               exit(1);
+       } else if (pid > 0) {   /* parent */
+               waitpid(pid, &status, 0);
+               if (WIFEXITED(status))
+                       exit(WEXITSTATUS(status));
+               else
+                       exit(2);
+       } else {                /* child */
+               close(0); close(1); close(2);
+               setsid();
+               openpty(&ptyfd, &ttyfd, NULL, NULL, NULL);
+               fd = open("/dev/tty", O_RDWR | O_NOCTTY);
+               if (fd >= 0)
+                       exit(3);        /* Acquired ctty: broken */
+               else
+                       exit(0);        /* Did not acquire ctty: OK */
+       }
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                       cat >>confdefs.h <<\_ACEOF
+#define SSHD_ACQUIRES_CTTY 1
+_ACEOF
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+    test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then
+       { echo "$as_me:$LINENO: checking if getaddrinfo seems to work" >&5
+echo $ECHO_N "checking if getaddrinfo seems to work... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+
+                       { echo "$as_me:$LINENO: result: cross-compiling" >&5
+echo "${ECHO_T}cross-compiling" >&6; }
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+
+int
+main(void)
+{
+       int err, sock;
+       struct addrinfo *gai_ai, *ai, hints;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+       if (err != 0) {
+               fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+               exit(1);
+       }
+
+       for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET6)
+                       continue;
+
+               err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+                   sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+               if (err != 0) {
+                       if (err == EAI_SYSTEM)
+                               perror("getnameinfo EAI_SYSTEM");
+                       else
+                               fprintf(stderr, "getnameinfo failed: %s\n",
+                                   gai_strerror(err));
+                       exit(2);
+               }
+
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0)
+                       perror("socket");
+               if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       if (errno == EBADF)
+                               exit(3);
+               }
+       }
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+    test "x$check_for_aix_broken_getaddrinfo" = "x1"; then
+       { echo "$as_me:$LINENO: checking if getaddrinfo seems to work" >&5
+echo $ECHO_N "checking if getaddrinfo seems to work... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+
+                       { echo "$as_me:$LINENO: result: cross-compiling" >&5
+echo "${ECHO_T}cross-compiling" >&6; }
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+
+int
+main(void)
+{
+       int err, sock;
+       struct addrinfo *gai_ai, *ai, hints;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+       if (err != 0) {
+               fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+               exit(1);
+       }
+
+       for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                       continue;
+
+               err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+                   sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+               if (ai->ai_family == AF_INET && err != 0) {
+                       perror("getnameinfo");
+                       exit(2);
+               }
+       }
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define AIX_GETNAMEINFO_HACK 1
+_ACEOF
+
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                       cat >>confdefs.h <<\_ACEOF
+#define BROKEN_GETADDRINFO 1
+_ACEOF
+
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+if test "x$check_for_conflicting_getspnam" = "x1"; then
+       { echo "$as_me:$LINENO: checking for conflicting getspnam in shadow.h" >&5
+echo $ECHO_N "checking for conflicting getspnam in shadow.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+
+#include <shadow.h>
+int main(void) {exit(0);}
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define GETSPNAM_CONFLICTING_DEFS 1
+_ACEOF
+
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ echo "$as_me:$LINENO: checking whether getpgrp requires zero arguments" >&5
+echo $ECHO_N "checking whether getpgrp requires zero arguments... $ECHO_C" >&6; }
+if test "${ac_cv_func_getpgrp_void+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Use it with a single arg.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+getpgrp (0);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_func_getpgrp_void=no
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_getpgrp_void=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_getpgrp_void" >&5
+echo "${ECHO_T}$ac_cv_func_getpgrp_void" >&6; }
+if test $ac_cv_func_getpgrp_void = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define GETPGRP_VOID 1
+_ACEOF
+
+fi
+
+
+# Search for OpenSSL
+saved_CPPFLAGS="$CPPFLAGS"
+saved_LDFLAGS="$LDFLAGS"
+
+# Check whether --with-ssl-dir was given.
+if test "${with_ssl_dir+set}" = set; then
+  withval=$with_ssl_dir;
+               if test "x$withval" != "xno" ; then
+                       case "$withval" in
+                               # Relative paths
+                               ./*|../*)       withval="`pwd`/$withval"
+                       esac
+                       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
+                       elif test -d "$withval/lib64"; then
+                               if test -n "${need_dash_r}"; then
+                                       LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}"
+                               else
+                                       LDFLAGS="-L${withval}/lib64 ${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
+
+
+fi
+
+LIBS="-lcrypto $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char RAND_add ();
+int
+main ()
+{
+return RAND_add ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                               if test -n "${need_dash_r}"; then
+                       LDFLAGS="-L/usr/local/ssl/lib -R/usr/local/ssl/lib ${saved_LDFLAGS}"
+               else
+                       LDFLAGS="-L/usr/local/ssl/lib ${saved_LDFLAGS}"
+               fi
+               CPPFLAGS="-I/usr/local/ssl/include ${saved_CPPFLAGS}"
+               if test "${ac_cv_header_openssl_opensslv_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for openssl/opensslv.h" >&5
+echo $ECHO_N "checking for openssl/opensslv.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_openssl_opensslv_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_openssl_opensslv_h" >&5
+echo "${ECHO_T}$ac_cv_header_openssl_opensslv_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking openssl/opensslv.h usability" >&5
+echo $ECHO_N "checking openssl/opensslv.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <openssl/opensslv.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking openssl/opensslv.h presence" >&5
+echo $ECHO_N "checking openssl/opensslv.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <openssl/opensslv.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: openssl/opensslv.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: openssl/opensslv.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: openssl/opensslv.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: openssl/opensslv.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for openssl/opensslv.h" >&5
+echo $ECHO_N "checking for openssl/opensslv.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_openssl_opensslv_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_openssl_opensslv_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_openssl_opensslv_h" >&5
+echo "${ECHO_T}$ac_cv_header_openssl_opensslv_h" >&6; }
+
+fi
+if test $ac_cv_header_openssl_opensslv_h = yes; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: *** OpenSSL headers missing - please install first or check config.log ***" >&5
+echo "$as_me: error: *** OpenSSL headers missing - please install first or check config.log ***" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char RAND_add ();
+int
+main ()
+{
+return RAND_add ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENSSL 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                               { { echo "$as_me:$LINENO: error: *** Can't find recent OpenSSL libcrypto (see config.log for details) ***" >&5
+echo "$as_me: error: *** Can't find recent OpenSSL libcrypto (see config.log for details) ***" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+# Determine OpenSSL header version
+{ echo "$as_me:$LINENO: checking OpenSSL header version" >&5
+echo $ECHO_N "checking OpenSSL header version... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: WARNING: cross compiling: not checking" >&5
+echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#define DATA "conftest.sslincver"
+int main(void) {
+       FILE *fd;
+       int rc;
+
+       fd = fopen(DATA,"w");
+       if(fd == NULL)
+               exit(1);
+
+       if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
+               exit(1);
+
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               ssl_header_ver=`cat conftest.sslincver`
+               { echo "$as_me:$LINENO: result: $ssl_header_ver" >&5
+echo "${ECHO_T}$ssl_header_ver" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6; }
+               { { echo "$as_me:$LINENO: error: OpenSSL version header not found." >&5
+echo "$as_me: error: OpenSSL version header not found." >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+# Determine OpenSSL library version
+{ echo "$as_me:$LINENO: checking OpenSSL library version" >&5
+echo $ECHO_N "checking OpenSSL library version... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: WARNING: cross compiling: not checking" >&5
+echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/crypto.h>
+#define DATA "conftest.ssllibver"
+int main(void) {
+       FILE *fd;
+       int rc;
+
+       fd = fopen(DATA,"w");
+       if(fd == NULL)
+               exit(1);
+
+       if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0)
+               exit(1);
+
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               ssl_library_ver=`cat conftest.ssllibver`
+               { echo "$as_me:$LINENO: result: $ssl_library_ver" >&5
+echo "${ECHO_T}$ssl_library_ver" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6; }
+               { { echo "$as_me:$LINENO: error: OpenSSL library not found." >&5
+echo "$as_me: error: OpenSSL library not found." >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+
+# Check whether --with-openssl-header-check was given.
+if test "${with_openssl_header_check+set}" = set; then
+  withval=$with_openssl_header_check;   if test "x$withval" = "xno" ; then
+               openssl_check_nonfatal=1
+          fi
+
+
+fi
+
+
+# Sanity check OpenSSL headers
+{ echo "$as_me:$LINENO: checking whether OpenSSL's headers match the library" >&5
+echo $ECHO_N "checking whether OpenSSL's headers match the library... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: WARNING: cross compiling: not checking" >&5
+echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <string.h>
+#include <openssl/opensslv.h>
+int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               if test "x$openssl_check_nonfatal" = "x"; then
+                       { { echo "$as_me:$LINENO: error: Your OpenSSL headers do not match your
+library. Check config.log for details.
+If you are sure your installation is consistent, you can disable the check
+by running \"./configure --without-openssl-header-check\".
+Also see contrib/findssl.sh for help identifying header/library mismatches.
+" >&5
+echo "$as_me: error: Your OpenSSL headers do not match your
+library. Check config.log for details.
+If you are sure your installation is consistent, you can disable the check
+by running \"./configure --without-openssl-header-check\".
+Also see contrib/findssl.sh for help identifying header/library mismatches.
+" >&2;}
+   { (exit 1); exit 1; }; }
+               else
+                       { echo "$as_me:$LINENO: WARNING: Your OpenSSL headers do not match your
+library. Check config.log for details.
+Also see contrib/findssl.sh for help identifying header/library mismatches." >&5
+echo "$as_me: WARNING: Your OpenSSL headers do not match your
+library. Check config.log for details.
+Also see contrib/findssl.sh for help identifying header/library mismatches." >&2;}
+               fi
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking if programs using OpenSSL functions will link" >&5
+echo $ECHO_N "checking if programs using OpenSSL functions will link... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <openssl/evp.h>
+int main(void) { SSLeay_add_all_algorithms(); }
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               saved_LIBS="$LIBS"
+               LIBS="$LIBS -ldl"
+               { echo "$as_me:$LINENO: checking if programs using OpenSSL need -ldl" >&5
+echo $ECHO_N "checking if programs using OpenSSL need -ldl... $ECHO_C" >&6; }
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <openssl/evp.h>
+int main(void) { SSLeay_add_all_algorithms(); }
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+                               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                               LIBS="$saved_LIBS"
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+
+
+
+for ac_func in RSA_generate_key_ex DSA_generate_parameters_ex BN_is_prime_ex RSA_get_default_method
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+# Check whether --with-ssl-engine was given.
+if test "${with_ssl_engine+set}" = set; then
+  withval=$with_ssl_engine;  if test "x$withval" != "xno" ; then
+               { echo "$as_me:$LINENO: checking for OpenSSL ENGINE support" >&5
+echo $ECHO_N "checking for OpenSSL ENGINE support... $ECHO_C" >&6; }
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <openssl/engine.h>
+int
+main ()
+{
+
+ENGINE_load_builtin_engines();ENGINE_register_all_complete();
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_OPENSSL_ENGINE 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { { echo "$as_me:$LINENO: error: OpenSSL ENGINE support not found" >&5
+echo "$as_me: error: OpenSSL ENGINE support not found" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+         fi
+
+fi
+
+
+# Check for OpenSSL without EVP_aes_{192,256}_cbc
+{ echo "$as_me:$LINENO: checking whether OpenSSL has crippled AES support" >&5
+echo $ECHO_N "checking whether OpenSSL has crippled AES support... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <string.h>
+#include <openssl/evp.h>
+int main(void) { exit(EVP_aes_192_cbc() == NULL || EVP_aes_256_cbc() == NULL);}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define OPENSSL_LOBOTOMISED_AES 1
+_ACEOF
+
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+{ echo "$as_me:$LINENO: checking if EVP_DigestUpdate returns an int" >&5
+echo $ECHO_N "checking if EVP_DigestUpdate returns an int... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <string.h>
+#include <openssl/evp.h>
+int main(void) { if(EVP_DigestUpdate(NULL, NULL,0)) exit(0); }
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define OPENSSL_EVP_DIGESTUPDATE_VOID 1
+_ACEOF
+
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+# Some systems want crypt() from libcrypt, *not* the version in OpenSSL,
+# because the system crypt() is more featureful.
+if test "x$check_for_libcrypt_before" = "x1"; then
+
+{ echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5
+echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6; }
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_crypt_crypt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_crypt_crypt=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6; }
+if test $ac_cv_lib_crypt_crypt = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCRYPT 1
+_ACEOF
+
+  LIBS="-lcrypt $LIBS"
+
+fi
+
+fi
+
+# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
+# version in OpenSSL.
+if test "x$check_for_libcrypt_later" = "x1"; then
+       { echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5
+echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6; }
+if test "${ac_cv_lib_crypt_crypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcrypt  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char crypt ();
+int
+main ()
+{
+return crypt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_crypt_crypt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_crypt_crypt=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_crypt_crypt" >&5
+echo "${ECHO_T}$ac_cv_lib_crypt_crypt" >&6; }
+if test $ac_cv_lib_crypt_crypt = yes; then
+  LIBS="$LIBS -lcrypt"
+fi
+
+fi
+
+# Search for SHA256 support in libc and/or OpenSSL
+
+
+for ac_func in SHA256_Update EVP_sha256
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ TEST_SSH_SHA256=yes
+else
+  TEST_SSH_SHA256=no
+fi
+done
+
+
+
+# Check complete ECC support in OpenSSL
+{ echo "$as_me:$LINENO: checking whether OpenSSL has complete ECC support" >&5
+echo $ECHO_N "checking whether OpenSSL has complete ECC support... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
+# error "OpenSSL < 0.9.8g has unreliable ECC code"
+#endif
+int main(void) {
+       EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
+       const EVP_MD *m = EVP_sha512(); /* We need this too */
+}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define OPENSSL_HAS_ECC 1
+_ACEOF
+
+               TEST_SSH_ECC=yes
+               COMMENT_OUT_ECC=""
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               TEST_SSH_ECC=no
+               COMMENT_OUT_ECC="#no ecc#"
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+
+saved_LIBS="$LIBS"
+{ echo "$as_me:$LINENO: checking for ia_openinfo in -liaf" >&5
+echo $ECHO_N "checking for ia_openinfo in -liaf... $ECHO_C" >&6; }
+if test "${ac_cv_lib_iaf_ia_openinfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-liaf  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ia_openinfo ();
+int
+main ()
+{
+return ia_openinfo ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_iaf_ia_openinfo=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_iaf_ia_openinfo=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_iaf_ia_openinfo" >&5
+echo "${ECHO_T}$ac_cv_lib_iaf_ia_openinfo" >&6; }
+if test $ac_cv_lib_iaf_ia_openinfo = yes; then
+
+       LIBS="$LIBS -liaf"
+
+for ac_func in set_id
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ SSHDLIBS="$SSHDLIBS -liaf"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBIAF 1
+_ACEOF
+
+
+fi
+done
+
+
+fi
+
+LIBS="$saved_LIBS"
+
+### Configure cryptographic random number support
+
+# Check wheter OpenSSL seeds itself
+{ echo "$as_me:$LINENO: checking whether OpenSSL's PRNG is internally seeded" >&5
+echo $ECHO_N "checking whether OpenSSL's PRNG is internally seeded... $ECHO_C" >&6; }
+if test "$cross_compiling" = yes; then
+
+               { echo "$as_me:$LINENO: WARNING: cross compiling: assuming yes" >&5
+echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
+               # This is safe, since all recent OpenSSL versions will
+               # complain at runtime if not seeded correctly.
+               OPENSSL_SEEDS_ITSELF=yes
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <string.h>
+#include <openssl/rand.h>
+int main(void) { exit(RAND_status() == 1 ? 0 : 1); }
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+               OPENSSL_SEEDS_ITSELF=yes
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               # Default to use of the rand helper if OpenSSL doesn't
+               # seed itself
+               USE_RAND_HELPER=yes
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+
+# Check for PAM libs
+PAM_MSG="no"
+
+# Check whether --with-pam was given.
+if test "${with_pam+set}" = set; then
+  withval=$with_pam;
+               if test "x$withval" != "xno" ; then
+                       if test "x$ac_cv_header_security_pam_appl_h" != "xyes" && \
+                          test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then
+                               { { echo "$as_me:$LINENO: error: PAM headers not found" >&5
+echo "$as_me: error: PAM headers not found" >&2;}
+   { (exit 1); exit 1; }; }
+                       fi
+
+                       saved_LIBS="$LIBS"
+
+{ echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dl_dlopen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6; }
+if test $ac_cv_lib_dl_dlopen = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+  LIBS="-ldl $LIBS"
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for pam_set_item in -lpam" >&5
+echo $ECHO_N "checking for pam_set_item in -lpam... $ECHO_C" >&6; }
+if test "${ac_cv_lib_pam_pam_set_item+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpam  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pam_set_item ();
+int
+main ()
+{
+return pam_set_item ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_pam_pam_set_item=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_pam_pam_set_item=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_set_item" >&5
+echo "${ECHO_T}$ac_cv_lib_pam_pam_set_item" >&6; }
+if test $ac_cv_lib_pam_pam_set_item = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPAM 1
+_ACEOF
+
+  LIBS="-lpam $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: *** libpam missing" >&5
+echo "$as_me: error: *** libpam missing" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+for ac_func in pam_getenvlist
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in pam_putenv
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+                       LIBS="$saved_LIBS"
+
+                       PAM_MSG="yes"
+
+                       SSHDLIBS="$SSHDLIBS -lpam"
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_PAM 1
+_ACEOF
+
+
+                       if test $ac_cv_lib_dl_dlopen = yes; then
+                               case "$LIBS" in
+                               *-ldl*)
+                                       # libdl already in LIBS
+                                       ;;
+                               *)
+                                       SSHDLIBS="$SSHDLIBS -ldl"
+                                       ;;
+                               esac
+                       fi
+               fi
+
+
+fi
+
+
+# Check for older PAM
+if test "x$PAM_MSG" = "xyes" ; then
+       # Check PAM strerror arguments (old PAM)
+       { echo "$as_me:$LINENO: checking whether pam_strerror takes only one argument" >&5
+echo $ECHO_N "checking whether pam_strerror takes only one argument... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdlib.h>
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined (HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+
+int
+main ()
+{
+(void)pam_strerror((pam_handle_t *)NULL, -1);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OLD_PAM 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+                       PAM_MSG="yes (old library)"
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+# Do we want to force the use of the rand helper?
+
+# Check whether --with-rand-helper was given.
+if test "${with_rand_helper+set}" = set; then
+  withval=$with_rand_helper;
+               if test "x$withval" = "xno" ; then
+                       # Force use of OpenSSL's internal RNG, even if
+                       # the previous test showed it to be unseeded.
+                       if test -z "$OPENSSL_SEEDS_ITSELF" ; then
+                               { echo "$as_me:$LINENO: WARNING: *** Forcing use of OpenSSL's non-self-seeding PRNG" >&5
+echo "$as_me: WARNING: *** Forcing use of OpenSSL's non-self-seeding PRNG" >&2;}
+                               OPENSSL_SEEDS_ITSELF=yes
+                               USE_RAND_HELPER=""
+                       fi
+               else
+                       USE_RAND_HELPER=yes
+               fi
+
+fi
+
+
+# Which randomness source do we use?
+if test ! -z "$OPENSSL_SEEDS_ITSELF" && test -z "$USE_RAND_HELPER" ; then
+       # OpenSSL only
+
+cat >>confdefs.h <<\_ACEOF
+#define OPENSSL_PRNG_ONLY 1
+_ACEOF
+
+       RAND_MSG="OpenSSL internal ONLY"
+       INSTALL_SSH_RAND_HELPER=""
+elif test ! -z "$USE_RAND_HELPER" ; then
+       # install rand helper
+       RAND_MSG="ssh-rand-helper"
+       INSTALL_SSH_RAND_HELPER="yes"
+fi
+
+
+### Configuration of ssh-rand-helper
+
+# PRNGD TCP socket
+
+# Check whether --with-prngd-port was given.
+if test "${with_prngd_port+set}" = set; then
+  withval=$with_prngd_port;
+               case "$withval" in
+               no)
+                       withval=""
+                       ;;
+               [0-9]*)
+                       ;;
+               *)
+                       { { echo "$as_me:$LINENO: error: You must specify a numeric port number for --with-prngd-port" >&5
+echo "$as_me: error: You must specify a numeric port number for --with-prngd-port" >&2;}
+   { (exit 1); exit 1; }; }
+                       ;;
+               esac
+               if test ! -z "$withval" ; then
+                       PRNGD_PORT="$withval"
+
+cat >>confdefs.h <<_ACEOF
+#define PRNGD_PORT $PRNGD_PORT
+_ACEOF
+
+               fi
+
+
+fi
+
+
+# PRNGD Unix domain socket
+
+# Check whether --with-prngd-socket was given.
+if test "${with_prngd_socket+set}" = set; then
+  withval=$with_prngd_socket;
+               case "$withval" in
+               yes)
+                       withval="/var/run/egd-pool"
+                       ;;
+               no)
+                       withval=""
+                       ;;
+               /*)
+                       ;;
+               *)
+                       { { echo "$as_me:$LINENO: error: You must specify an absolute path to the entropy socket" >&5
+echo "$as_me: error: You must specify an absolute path to the entropy socket" >&2;}
+   { (exit 1); exit 1; }; }
+                       ;;
+               esac
+
+               if test ! -z "$withval" ; then
+                       if test ! -z "$PRNGD_PORT" ; then
+                               { { echo "$as_me:$LINENO: error: You may not specify both a PRNGD/EGD port and socket" >&5
+echo "$as_me: error: You may not specify both a PRNGD/EGD port and socket" >&2;}
+   { (exit 1); exit 1; }; }
+                       fi
+                       if test ! -r "$withval" ; then
+                               { echo "$as_me:$LINENO: WARNING: Entropy socket is not readable" >&5
+echo "$as_me: WARNING: Entropy socket is not readable" >&2;}
+                       fi
+                       PRNGD_SOCKET="$withval"
+
+cat >>confdefs.h <<_ACEOF
+#define PRNGD_SOCKET "$PRNGD_SOCKET"
+_ACEOF
+
+               fi
+
+else
+
+               # Check for existing socket only if we don't have a random device already
+               if test "$USE_RAND_HELPER" = yes ; then
+                       { echo "$as_me:$LINENO: checking for PRNGD/EGD socket" >&5
+echo $ECHO_N "checking for PRNGD/EGD socket... $ECHO_C" >&6; }
+                       # 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"
+                                       cat >>confdefs.h <<_ACEOF
+#define PRNGD_SOCKET "$PRNGD_SOCKET"
+_ACEOF
+
+                                       break;
+                               fi
+                       done
+                       if test ! -z "$PRNGD_SOCKET" ; then
+                               { echo "$as_me:$LINENO: result: $PRNGD_SOCKET" >&5
+echo "${ECHO_T}$PRNGD_SOCKET" >&6; }
+                       else
+                               { echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6; }
+                       fi
+               fi
+
+
+fi
+
+
+# Change default command timeout for hashing entropy source
+entropy_timeout=200
+
+# Check whether --with-entropy-timeout was given.
+if test "${with_entropy_timeout+set}" = set; then
+  withval=$with_entropy_timeout;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       entropy_timeout=$withval
+               fi
+
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define ENTROPY_TIMEOUT_MSEC $entropy_timeout
+_ACEOF
+
+
+SSH_PRIVSEP_USER=sshd
+
+# Check whether --with-privsep-user was given.
+if test "${with_privsep_user+set}" = set; then
+  withval=$with_privsep_user;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       SSH_PRIVSEP_USER=$withval
+               fi
+
+
+fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define SSH_PRIVSEP_USER "$SSH_PRIVSEP_USER"
+_ACEOF
+
+
+
+# We do this little dance with the search path to insure
+# that programs that we select for use by installed programs
+# (which may be run by the super-user) come from trusted
+# locations before they come from the user's private area.
+# This should help avoid accidentally configuring some
+# random version of a program in someone's personal bin.
+
+OPATH=$PATH
+PATH=/bin:/usr/bin
+test -h /bin 2> /dev/null && PATH=/usr/bin
+test -d /sbin && PATH=$PATH:/sbin
+test -d /usr/sbin && PATH=$PATH:/usr/sbin
+PATH=$PATH:/etc:$OPATH
+
+# These programs are used by the command hashing source to gather entropy
+
+       # Extract the first word of "ls", so it can be a program name with args.
+set dummy ls; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_LS+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_LS in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_LS="$PROG_LS" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_LS="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_LS=$ac_cv_path_PROG_LS
+if test -n "$PROG_LS"; then
+  { echo "$as_me:$LINENO: result: $PROG_LS" >&5
+echo "${ECHO_T}$PROG_LS" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_LS" ; then
+               PROG_LS="undef"
+       fi
+
+
+
+       # Extract the first word of "netstat", so it can be a program name with args.
+set dummy netstat; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_NETSTAT+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_NETSTAT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_NETSTAT="$PROG_NETSTAT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_NETSTAT="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_NETSTAT=$ac_cv_path_PROG_NETSTAT
+if test -n "$PROG_NETSTAT"; then
+  { echo "$as_me:$LINENO: result: $PROG_NETSTAT" >&5
+echo "${ECHO_T}$PROG_NETSTAT" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_NETSTAT" ; then
+               PROG_NETSTAT="undef"
+       fi
+
+
+
+       # Extract the first word of "arp", so it can be a program name with args.
+set dummy arp; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_ARP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_ARP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_ARP="$PROG_ARP" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_ARP="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_ARP=$ac_cv_path_PROG_ARP
+if test -n "$PROG_ARP"; then
+  { echo "$as_me:$LINENO: result: $PROG_ARP" >&5
+echo "${ECHO_T}$PROG_ARP" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_ARP" ; then
+               PROG_ARP="undef"
+       fi
+
+
+
+       # Extract the first word of "ifconfig", so it can be a program name with args.
+set dummy ifconfig; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_IFCONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_IFCONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_IFCONFIG="$PROG_IFCONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_IFCONFIG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_IFCONFIG=$ac_cv_path_PROG_IFCONFIG
+if test -n "$PROG_IFCONFIG"; then
+  { echo "$as_me:$LINENO: result: $PROG_IFCONFIG" >&5
+echo "${ECHO_T}$PROG_IFCONFIG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_IFCONFIG" ; then
+               PROG_IFCONFIG="undef"
+       fi
+
+
+
+       # Extract the first word of "jstat", so it can be a program name with args.
+set dummy jstat; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_JSTAT+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_JSTAT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_JSTAT="$PROG_JSTAT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_JSTAT="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_JSTAT=$ac_cv_path_PROG_JSTAT
+if test -n "$PROG_JSTAT"; then
+  { echo "$as_me:$LINENO: result: $PROG_JSTAT" >&5
+echo "${ECHO_T}$PROG_JSTAT" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_JSTAT" ; then
+               PROG_JSTAT="undef"
+       fi
+
+
+
+       # Extract the first word of "ps", so it can be a program name with args.
+set dummy ps; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_PS+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_PS in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_PS="$PROG_PS" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_PS="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_PS=$ac_cv_path_PROG_PS
+if test -n "$PROG_PS"; then
+  { echo "$as_me:$LINENO: result: $PROG_PS" >&5
+echo "${ECHO_T}$PROG_PS" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_PS" ; then
+               PROG_PS="undef"
+       fi
+
+
+
+       # Extract the first word of "sar", so it can be a program name with args.
+set dummy sar; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_SAR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_SAR in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_SAR="$PROG_SAR" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_SAR="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_SAR=$ac_cv_path_PROG_SAR
+if test -n "$PROG_SAR"; then
+  { echo "$as_me:$LINENO: result: $PROG_SAR" >&5
+echo "${ECHO_T}$PROG_SAR" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_SAR" ; then
+               PROG_SAR="undef"
+       fi
+
+
+
+       # Extract the first word of "w", so it can be a program name with args.
+set dummy w; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_W+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_W in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_W="$PROG_W" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_W="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_W=$ac_cv_path_PROG_W
+if test -n "$PROG_W"; then
+  { echo "$as_me:$LINENO: result: $PROG_W" >&5
+echo "${ECHO_T}$PROG_W" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_W" ; then
+               PROG_W="undef"
+       fi
+
+
+
+       # Extract the first word of "who", so it can be a program name with args.
+set dummy who; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_WHO+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_WHO in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_WHO="$PROG_WHO" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_WHO="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_WHO=$ac_cv_path_PROG_WHO
+if test -n "$PROG_WHO"; then
+  { echo "$as_me:$LINENO: result: $PROG_WHO" >&5
+echo "${ECHO_T}$PROG_WHO" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_WHO" ; then
+               PROG_WHO="undef"
+       fi
+
+
+
+       # Extract the first word of "last", so it can be a program name with args.
+set dummy last; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_LAST+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_LAST in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_LAST="$PROG_LAST" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_LAST="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_LAST=$ac_cv_path_PROG_LAST
+if test -n "$PROG_LAST"; then
+  { echo "$as_me:$LINENO: result: $PROG_LAST" >&5
+echo "${ECHO_T}$PROG_LAST" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_LAST" ; then
+               PROG_LAST="undef"
+       fi
+
+
+
+       # Extract the first word of "lastlog", so it can be a program name with args.
+set dummy lastlog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_LASTLOG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_LASTLOG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_LASTLOG="$PROG_LASTLOG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_LASTLOG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_LASTLOG=$ac_cv_path_PROG_LASTLOG
+if test -n "$PROG_LASTLOG"; then
+  { echo "$as_me:$LINENO: result: $PROG_LASTLOG" >&5
+echo "${ECHO_T}$PROG_LASTLOG" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_LASTLOG" ; then
+               PROG_LASTLOG="undef"
+       fi
+
+
+
+       # Extract the first word of "df", so it can be a program name with args.
+set dummy df; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_DF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_DF in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_DF="$PROG_DF" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_DF="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_DF=$ac_cv_path_PROG_DF
+if test -n "$PROG_DF"; then
+  { echo "$as_me:$LINENO: result: $PROG_DF" >&5
+echo "${ECHO_T}$PROG_DF" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_DF" ; then
+               PROG_DF="undef"
+       fi
+
+
+
+       # Extract the first word of "vmstat", so it can be a program name with args.
+set dummy vmstat; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_VMSTAT+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_VMSTAT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_VMSTAT="$PROG_VMSTAT" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_VMSTAT="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_VMSTAT=$ac_cv_path_PROG_VMSTAT
+if test -n "$PROG_VMSTAT"; then
+  { echo "$as_me:$LINENO: result: $PROG_VMSTAT" >&5
+echo "${ECHO_T}$PROG_VMSTAT" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_VMSTAT" ; then
+               PROG_VMSTAT="undef"
+       fi
+
+
+
+       # Extract the first word of "uptime", so it can be a program name with args.
+set dummy uptime; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_UPTIME+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_UPTIME in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_UPTIME="$PROG_UPTIME" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_UPTIME="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_UPTIME=$ac_cv_path_PROG_UPTIME
+if test -n "$PROG_UPTIME"; then
+  { echo "$as_me:$LINENO: result: $PROG_UPTIME" >&5
+echo "${ECHO_T}$PROG_UPTIME" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_UPTIME" ; then
+               PROG_UPTIME="undef"
+       fi
+
+
+
+       # Extract the first word of "ipcs", so it can be a program name with args.
+set dummy ipcs; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_IPCS+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_IPCS in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_IPCS="$PROG_IPCS" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_IPCS="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_IPCS=$ac_cv_path_PROG_IPCS
+if test -n "$PROG_IPCS"; then
+  { echo "$as_me:$LINENO: result: $PROG_IPCS" >&5
+echo "${ECHO_T}$PROG_IPCS" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_IPCS" ; then
+               PROG_IPCS="undef"
+       fi
+
+
+
+       # Extract the first word of "tail", so it can be a program name with args.
+set dummy tail; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_PROG_TAIL+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $PROG_TAIL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PROG_TAIL="$PROG_TAIL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_PROG_TAIL="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PROG_TAIL=$ac_cv_path_PROG_TAIL
+if test -n "$PROG_TAIL"; then
+  { echo "$as_me:$LINENO: result: $PROG_TAIL" >&5
+echo "${ECHO_T}$PROG_TAIL" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+       if test -z "$PROG_TAIL" ; then
+               PROG_TAIL="undef"
+       fi
+
+
+# restore PATH
+PATH=$OPATH
+
+# Where does ssh-rand-helper get its randomness from?
+INSTALL_SSH_PRNG_CMDS=""
+if test ! -z "$INSTALL_SSH_RAND_HELPER" ; then
+       if test ! -z "$PRNGD_PORT" ; then
+               RAND_HELPER_MSG="TCP localhost:$PRNGD_PORT"
+       elif test ! -z "$PRNGD_SOCKET" ; then
+               RAND_HELPER_MSG="Unix domain socket \"$PRNGD_SOCKET\""
+       else
+               RAND_HELPER_MSG="Command hashing (timeout $entropy_timeout)"
+               RAND_HELPER_CMDHASH=yes
+               INSTALL_SSH_PRNG_CMDS="yes"
+       fi
+fi
+
+
+
+# Cheap hack to ensure NEWS-OS libraries are arranged right.
+if test ! -z "$SONY" ; then
+  LIBS="$LIBS -liberty";
+fi
+
+# Check for  long long datatypes
+{ echo "$as_me:$LINENO: checking for long long" >&5
+echo $ECHO_N "checking for long long... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_long_long" >&6; }
+if test $ac_cv_type_long_long = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking for unsigned long long" >&5
+echo $ECHO_N "checking for unsigned long long... $ECHO_C" >&6; }
+if test "${ac_cv_type_unsigned_long_long+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef unsigned long long ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_unsigned_long_long=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_unsigned_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_long_long" >&5
+echo "${ECHO_T}$ac_cv_type_unsigned_long_long" >&6; }
+if test $ac_cv_type_unsigned_long_long = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UNSIGNED_LONG_LONG 1
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking for long double" >&5
+echo $ECHO_N "checking for long double... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_double+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long double ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_double=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_double=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_double" >&5
+echo "${ECHO_T}$ac_cv_type_long_double" >&6; }
+if test $ac_cv_type_long_double = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_DOUBLE 1
+_ACEOF
+
+
+fi
+
+
+# Check datatype sizes
+{ echo "$as_me:$LINENO: checking for char" >&5
+echo $ECHO_N "checking for char... $ECHO_C" >&6; }
+if test "${ac_cv_type_char+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef char ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_char=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_char=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_char" >&5
+echo "${ECHO_T}$ac_cv_type_char" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of char" >&5
+echo $ECHO_N "checking size of char... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_char+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_char=$ac_lo;;
+'') if test "$ac_cv_type_char" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (char)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (char)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_char=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef char ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_char=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_char" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (char)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (char)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_char=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_char" >&5
+echo "${ECHO_T}$ac_cv_sizeof_char" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_CHAR $ac_cv_sizeof_char
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for short int" >&5
+echo $ECHO_N "checking for short int... $ECHO_C" >&6; }
+if test "${ac_cv_type_short_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef short int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_short_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_short_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_short_int" >&5
+echo "${ECHO_T}$ac_cv_type_short_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of short int" >&5
+echo $ECHO_N "checking size of short int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_short_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_short_int=$ac_lo;;
+'') if test "$ac_cv_type_short_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef short int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_short_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_short_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (short int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (short int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_short_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_short_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_short_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SHORT_INT $ac_cv_sizeof_short_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for int" >&5
+echo $ECHO_N "checking for int... $ECHO_C" >&6; }
+if test "${ac_cv_type_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5
+echo "${ECHO_T}$ac_cv_type_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of int" >&5
+echo $ECHO_N "checking size of int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_int=$ac_lo;;
+'') if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long int" >&5
+echo $ECHO_N "checking for long int... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_int" >&5
+echo "${ECHO_T}$ac_cv_type_long_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long int" >&5
+echo $ECHO_N "checking size of long int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_int=$ac_lo;;
+'') if test "$ac_cv_type_long_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_INT $ac_cv_sizeof_long_int
+_ACEOF
+
+
+{ echo "$as_me:$LINENO: checking for long long int" >&5
+echo $ECHO_N "checking for long long int... $ECHO_C" >&6; }
+if test "${ac_cv_type_long_long_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef long long int ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_long_long_int=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_long_long_int=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long_int" >&5
+echo "${ECHO_T}$ac_cv_type_long_long_int" >&6; }
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ echo "$as_me:$LINENO: checking size of long long int" >&5
+echo $ECHO_N "checking size of long long int... $ECHO_C" >&6; }
+if test "${ac_cv_sizeof_long_long_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test "$cross_compiling" = yes; then
+  # Depending upon the size, compute the lo and hi bounds.
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr $ac_mid + 1`
+                       if test $ac_lo -le $ac_mid; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_lo=$ac_mid; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_hi=`expr '(' $ac_mid ')' - 1`
+                       if test $ac_mid -le $ac_hi; then
+                         ac_lo= ac_hi=
+                         break
+                       fi
+                       ac_mid=`expr 2 '*' $ac_mid`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo= ac_hi=
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo`
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+int
+main ()
+{
+static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)];
+test_array [0] = 0
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_hi=$ac_mid
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_lo=`expr '(' $ac_mid ')' + 1`
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in
+?*) ac_cv_sizeof_long_long_int=$ac_lo;;
+'') if test "$ac_cv_type_long_long_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long_int=0
+   fi ;;
+esac
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+   typedef long long int ac__type_sizeof_;
+static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); }
+static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (((long int) (sizeof (ac__type_sizeof_))) < 0)
+    {
+      long int i = longval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%ld\n", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ((long int) (sizeof (ac__type_sizeof_))))
+       return 1;
+      fprintf (f, "%lu\n", i);
+    }
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_sizeof_long_long_int=`cat conftest.val`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+if test "$ac_cv_type_long_long_int" = yes; then
+     { { echo "$as_me:$LINENO: error: cannot compute sizeof (long long int)
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute sizeof (long long int)
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+   else
+     ac_cv_sizeof_long_long_int=0
+   fi
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f conftest.val
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_long_int" >&5
+echo "${ECHO_T}$ac_cv_sizeof_long_long_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG_INT $ac_cv_sizeof_long_long_int
+_ACEOF
+
+
+
+# Sanity check long long for some platforms (AIX)
+if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then
+       ac_cv_sizeof_long_long_int=0
+fi
+
+# compute LLONG_MIN and LLONG_MAX if we don't know them.
+if test -z "$have_llong_max"; then
+       { echo "$as_me:$LINENO: checking for max value of long long" >&5
+echo $ECHO_N "checking for max value of long long... $ECHO_C" >&6; }
+       if test "$cross_compiling" = yes; then
+
+                       { echo "$as_me:$LINENO: WARNING: cross compiling: not checking" >&5
+echo "$as_me: WARNING: cross compiling: not checking" >&2;}
+
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+/* Why is this so damn hard? */
+#ifdef __GNUC__
+# undef __GNUC__
+#endif
+#define __USE_ISOC99
+#include <limits.h>
+#define DATA "conftest.llminmax"
+#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a))
+
+/*
+ * printf in libc on some platforms (eg old Tru64) does not understand %lld so
+ * we do this the hard way.
+ */
+static int
+fprint_ll(FILE *f, long long n)
+{
+       unsigned int i;
+       int l[sizeof(long long) * 8];
+
+       if (n < 0)
+               if (fprintf(f, "-") < 0)
+                       return -1;
+       for (i = 0; n != 0; i++) {
+               l[i] = my_abs(n % 10);
+               n /= 10;
+       }
+       do {
+               if (fprintf(f, "%d", l[--i]) < 0)
+                       return -1;
+       } while (i != 0);
+       if (fprintf(f, " ") < 0)
+               return -1;
+       return 0;
+}
+
+int main(void) {
+       FILE *f;
+       long long i, llmin, llmax = 0;
+
+       if((f = fopen(DATA,"w")) == NULL)
+               exit(1);
+
+#if defined(LLONG_MIN) && defined(LLONG_MAX)
+       fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n");
+       llmin = LLONG_MIN;
+       llmax = LLONG_MAX;
+#else
+       fprintf(stderr, "Calculating  LLONG_MIN and LLONG_MAX\n");
+       /* This will work on one's complement and two's complement */
+       for (i = 1; i > llmax; i <<= 1, i++)
+               llmax = i;
+       llmin = llmax + 1LL;    /* wrap */
+#endif
+
+       /* Sanity check */
+       if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax
+           || llmax - 1 > llmax || llmin == llmax || llmin == 0
+           || llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) {
+               fprintf(f, "unknown unknown\n");
+               exit(2);
+       }
+
+       if (fprint_ll(f, llmin) < 0)
+               exit(3);
+       if (fprint_ll(f, llmax) < 0)
+               exit(4);
+       if (fclose(f) < 0)
+               exit(5);
+       exit(0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+                       llong_min=`$AWK '{print $1}' conftest.llminmax`
+                       llong_max=`$AWK '{print $2}' conftest.llminmax`
+
+                       { echo "$as_me:$LINENO: result: $llong_max" >&5
+echo "${ECHO_T}$llong_max" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define LLONG_MAX ${llong_max}LL
+_ACEOF
+
+                       { echo "$as_me:$LINENO: checking for min value of long long" >&5
+echo $ECHO_N "checking for min value of long long... $ECHO_C" >&6; }
+                       { echo "$as_me:$LINENO: result: $llong_min" >&5
+echo "${ECHO_T}$llong_min" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define LLONG_MIN ${llong_min}LL
+_ACEOF
+
+
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+
+                       { echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+
+# More checks for data types
+{ echo "$as_me:$LINENO: checking for u_int type" >&5
+echo $ECHO_N "checking for u_int type... $ECHO_C" >&6; }
+if test "${ac_cv_have_u_int+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/types.h>
+int
+main ()
+{
+ u_int a; a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_u_int="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_u_int="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_u_int" >&5
+echo "${ECHO_T}$ac_cv_have_u_int" >&6; }
+if test "x$ac_cv_have_u_int" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INT 1
+_ACEOF
+
+       have_u_int=1
+fi
+
+{ echo "$as_me:$LINENO: checking for intXX_t types" >&5
+echo $ECHO_N "checking for intXX_t types... $ECHO_C" >&6; }
+if test "${ac_cv_have_intxx_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/types.h>
+int
+main ()
+{
+ int8_t a; int16_t b; int32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_intxx_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_intxx_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_intxx_t" >&5
+echo "${ECHO_T}$ac_cv_have_intxx_t" >&6; }
+if test "x$ac_cv_have_intxx_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTXX_T 1
+_ACEOF
+
+       have_intxx_t=1
+fi
+
+if (test -z "$have_intxx_t" && \
+          test "x$ac_cv_header_stdint_h" = "xyes")
+then
+    { echo "$as_me:$LINENO: checking for intXX_t types in stdint.h" >&5
+echo $ECHO_N "checking for intXX_t types in stdint.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <stdint.h>
+int
+main ()
+{
+ int8_t a; int16_t b; int32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTXX_T 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ echo "$as_me:$LINENO: checking for int64_t type" >&5
+echo $ECHO_N "checking for int64_t type... $ECHO_C" >&6; }
+if test "${ac_cv_have_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+
+int
+main ()
+{
+ int64_t a; a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_int64_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_int64_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_int64_t" >&5
+echo "${ECHO_T}$ac_cv_have_int64_t" >&6; }
+if test "x$ac_cv_have_int64_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_INT64_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for u_intXX_t types" >&5
+echo $ECHO_N "checking for u_intXX_t types... $ECHO_C" >&6; }
+if test "${ac_cv_have_u_intxx_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/types.h>
+int
+main ()
+{
+ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_u_intxx_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_u_intxx_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_u_intxx_t" >&5
+echo "${ECHO_T}$ac_cv_have_u_intxx_t" >&6; }
+if test "x$ac_cv_have_u_intxx_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INTXX_T 1
+_ACEOF
+
+       have_u_intxx_t=1
+fi
+
+if test -z "$have_u_intxx_t" ; then
+    { echo "$as_me:$LINENO: checking for u_intXX_t types in sys/socket.h" >&5
+echo $ECHO_N "checking for u_intXX_t types in sys/socket.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/socket.h>
+int
+main ()
+{
+ u_int8_t a; u_int16_t b; u_int32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INTXX_T 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ echo "$as_me:$LINENO: checking for u_int64_t types" >&5
+echo $ECHO_N "checking for u_int64_t types... $ECHO_C" >&6; }
+if test "${ac_cv_have_u_int64_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/types.h>
+int
+main ()
+{
+ u_int64_t a; a = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_u_int64_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_u_int64_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_u_int64_t" >&5
+echo "${ECHO_T}$ac_cv_have_u_int64_t" >&6; }
+if test "x$ac_cv_have_u_int64_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INT64_T 1
+_ACEOF
+
+       have_u_int64_t=1
+fi
+
+if test -z "$have_u_int64_t" ; then
+    { echo "$as_me:$LINENO: checking for u_int64_t type in sys/bitypes.h" >&5
+echo $ECHO_N "checking for u_int64_t type in sys/bitypes.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/bitypes.h>
+int
+main ()
+{
+ u_int64_t a; a = 1
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INT64_T 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test -z "$have_u_intxx_t" ; then
+       { echo "$as_me:$LINENO: checking for uintXX_t types" >&5
+echo $ECHO_N "checking for uintXX_t types... $ECHO_C" >&6; }
+if test "${ac_cv_have_uintxx_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_uintxx_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_uintxx_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_uintxx_t" >&5
+echo "${ECHO_T}$ac_cv_have_uintxx_t" >&6; }
+       if test "x$ac_cv_have_uintxx_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_UINTXX_T 1
+_ACEOF
+
+       fi
+fi
+
+if test -z "$have_uintxx_t" ; then
+    { echo "$as_me:$LINENO: checking for uintXX_t types in stdint.h" >&5
+echo $ECHO_N "checking for uintXX_t types in stdint.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <stdint.h>
+int
+main ()
+{
+ uint8_t a; uint16_t b; uint32_t c; a = b = c = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_UINTXX_T 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if (test -z "$have_u_intxx_t" || test -z "$have_intxx_t" && \
+          test "x$ac_cv_header_sys_bitypes_h" = "xyes")
+then
+       { echo "$as_me:$LINENO: checking for intXX_t and u_intXX_t types in sys/bitypes.h" >&5
+echo $ECHO_N "checking for intXX_t and u_intXX_t types in sys/bitypes.h... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/bitypes.h>
+
+int
+main ()
+{
+
+                       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;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_INTXX_T 1
+_ACEOF
+
+                       cat >>confdefs.h <<\_ACEOF
+#define HAVE_INTXX_T 1
+_ACEOF
+
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+{ echo "$as_me:$LINENO: checking for u_char" >&5
+echo $ECHO_N "checking for u_char... $ECHO_C" >&6; }
+if test "${ac_cv_have_u_char+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ u_char foo; foo = 125;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_u_char="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_u_char="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_u_char" >&5
+echo "${ECHO_T}$ac_cv_have_u_char" >&6; }
+if test "x$ac_cv_have_u_char" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_U_CHAR 1
+_ACEOF
+
+fi
+
+
+   { echo "$as_me:$LINENO: checking for socklen_t" >&5
+echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_socklen_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+typedef socklen_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_socklen_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_socklen_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5
+echo "${ECHO_T}$ac_cv_type_socklen_t" >&6; }
+if test $ac_cv_type_socklen_t = yes; then
+  :
+else
+
+      { echo "$as_me:$LINENO: checking for socklen_t equivalent" >&5
+echo $ECHO_N "checking for socklen_t equivalent... $ECHO_C" >&6; }
+      if test "${curl_cv_socklen_t_equiv+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+        # 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
+              cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+                 #include <sys/types.h>
+                 #include <sys/socket.h>
+
+                 int getpeername (int, $arg2 *, $t *);
+
+int
+main ()
+{
+
+                 $t len;
+                 getpeername(0,0,&len);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+                 curl_cv_socklen_t_equiv="$t"
+                 break
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+           done
+        done
+
+        if test "x$curl_cv_socklen_t_equiv" = x; then
+           { { echo "$as_me:$LINENO: error: Cannot find a type to use in place of socklen_t" >&5
+echo "$as_me: error: Cannot find a type to use in place of socklen_t" >&2;}
+   { (exit 1); exit 1; }; }
+        fi
+
+fi
+
+      { echo "$as_me:$LINENO: result: $curl_cv_socklen_t_equiv" >&5
+echo "${ECHO_T}$curl_cv_socklen_t_equiv" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define socklen_t $curl_cv_socklen_t_equiv
+_ACEOF
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking for sig_atomic_t" >&5
+echo $ECHO_N "checking for sig_atomic_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_sig_atomic_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <signal.h>
+
+typedef sig_atomic_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_sig_atomic_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_sig_atomic_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_sig_atomic_t" >&5
+echo "${ECHO_T}$ac_cv_type_sig_atomic_t" >&6; }
+if test $ac_cv_type_sig_atomic_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SIG_ATOMIC_T 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for fsblkcnt_t" >&5
+echo $ECHO_N "checking for fsblkcnt_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_fsblkcnt_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+
+typedef fsblkcnt_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_fsblkcnt_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_fsblkcnt_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_fsblkcnt_t" >&5
+echo "${ECHO_T}$ac_cv_type_fsblkcnt_t" >&6; }
+if test $ac_cv_type_fsblkcnt_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FSBLKCNT_T 1
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking for fsfilcnt_t" >&5
+echo $ECHO_N "checking for fsfilcnt_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_fsfilcnt_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+
+typedef fsfilcnt_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_fsfilcnt_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_fsfilcnt_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_fsfilcnt_t" >&5
+echo "${ECHO_T}$ac_cv_type_fsfilcnt_t" >&6; }
+if test $ac_cv_type_fsfilcnt_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FSFILCNT_T 1
+_ACEOF
+
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for in_addr_t" >&5
+echo $ECHO_N "checking for in_addr_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_in_addr_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef in_addr_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_in_addr_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_in_addr_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_in_addr_t" >&5
+echo "${ECHO_T}$ac_cv_type_in_addr_t" >&6; }
+if test $ac_cv_type_in_addr_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_IN_ADDR_T 1
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking for in_port_t" >&5
+echo $ECHO_N "checking for in_port_t... $ECHO_C" >&6; }
+if test "${ac_cv_type_in_port_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+typedef in_port_t ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_in_port_t=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_in_port_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_in_port_t" >&5
+echo "${ECHO_T}$ac_cv_type_in_port_t" >&6; }
+if test $ac_cv_type_in_port_t = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_IN_PORT_T 1
+_ACEOF
+
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_size_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ size_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_size_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_size_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_size_t" >&5
+echo "${ECHO_T}$ac_cv_have_size_t" >&6; }
+if test "x$ac_cv_have_size_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SIZE_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for ssize_t" >&5
+echo $ECHO_N "checking for ssize_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_ssize_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ ssize_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_ssize_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_ssize_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_ssize_t" >&5
+echo "${ECHO_T}$ac_cv_have_ssize_t" >&6; }
+if test "x$ac_cv_have_ssize_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SSIZE_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for clock_t" >&5
+echo $ECHO_N "checking for clock_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_clock_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <time.h>
+
+int
+main ()
+{
+ clock_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_clock_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_clock_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_clock_t" >&5
+echo "${ECHO_T}$ac_cv_have_clock_t" >&6; }
+if test "x$ac_cv_have_clock_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CLOCK_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for sa_family_t" >&5
+echo $ECHO_N "checking for sa_family_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_sa_family_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+ sa_family_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_sa_family_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+ sa_family_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_sa_family_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_sa_family_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_sa_family_t" >&5
+echo "${ECHO_T}$ac_cv_have_sa_family_t" >&6; }
+if test "x$ac_cv_have_sa_family_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SA_FAMILY_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for pid_t" >&5
+echo $ECHO_N "checking for pid_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_pid_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ pid_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_pid_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_pid_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_pid_t" >&5
+echo "${ECHO_T}$ac_cv_have_pid_t" >&6; }
+if test "x$ac_cv_have_pid_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PID_T 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for mode_t" >&5
+echo $ECHO_N "checking for mode_t... $ECHO_C" >&6; }
+if test "${ac_cv_have_mode_t+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+
+int
+main ()
+{
+ mode_t foo; foo = 1235;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_mode_t="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_mode_t="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_mode_t" >&5
+echo "${ECHO_T}$ac_cv_have_mode_t" >&6; }
+if test "x$ac_cv_have_mode_t" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MODE_T 1
+_ACEOF
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for struct sockaddr_storage" >&5
+echo $ECHO_N "checking for struct sockaddr_storage... $ECHO_C" >&6; }
+if test "${ac_cv_have_struct_sockaddr_storage+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+ struct sockaddr_storage s;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_struct_sockaddr_storage="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_struct_sockaddr_storage="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_struct_sockaddr_storage" >&5
+echo "${ECHO_T}$ac_cv_have_struct_sockaddr_storage" >&6; }
+if test "x$ac_cv_have_struct_sockaddr_storage" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5
+echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6; }
+if test "${ac_cv_have_struct_sockaddr_in6+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+ struct sockaddr_in6 s; s.sin6_family = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_struct_sockaddr_in6="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_struct_sockaddr_in6="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_struct_sockaddr_in6" >&5
+echo "${ECHO_T}$ac_cv_have_struct_sockaddr_in6" >&6; }
+if test "x$ac_cv_have_struct_sockaddr_in6" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_SOCKADDR_IN6 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct in6_addr" >&5
+echo $ECHO_N "checking for struct in6_addr... $ECHO_C" >&6; }
+if test "${ac_cv_have_struct_in6_addr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+ struct in6_addr s; s.s6_addr[0] = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_struct_in6_addr="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_struct_in6_addr="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_struct_in6_addr" >&5
+echo "${ECHO_T}$ac_cv_have_struct_in6_addr" >&6; }
+if test "x$ac_cv_have_struct_in6_addr" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_IN6_ADDR 1
+_ACEOF
+
+
+       { echo "$as_me:$LINENO: checking for struct sockaddr_in6.sin6_scope_id" >&5
+echo $ECHO_N "checking for struct sockaddr_in6.sin6_scope_id... $ECHO_C" >&6; }
+if test "${ac_cv_member_struct_sockaddr_in6_sin6_scope_id+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+
+
+int
+main ()
+{
+static struct sockaddr_in6 ac_aggr;
+if (ac_aggr.sin6_scope_id)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct_sockaddr_in6_sin6_scope_id=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+
+
+int
+main ()
+{
+static struct sockaddr_in6 ac_aggr;
+if (sizeof ac_aggr.sin6_scope_id)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct_sockaddr_in6_sin6_scope_id=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_member_struct_sockaddr_in6_sin6_scope_id=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_sockaddr_in6_sin6_scope_id" >&5
+echo "${ECHO_T}$ac_cv_member_struct_sockaddr_in6_sin6_scope_id" >&6; }
+if test $ac_cv_member_struct_sockaddr_in6_sin6_scope_id = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+_ACEOF
+
+
+fi
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct addrinfo" >&5
+echo $ECHO_N "checking for struct addrinfo... $ECHO_C" >&6; }
+if test "${ac_cv_have_struct_addrinfo+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+int
+main ()
+{
+ struct addrinfo s; s.ai_flags = AI_PASSIVE;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_struct_addrinfo="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_struct_addrinfo="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_struct_addrinfo" >&5
+echo "${ECHO_T}$ac_cv_have_struct_addrinfo" >&6; }
+if test "x$ac_cv_have_struct_addrinfo" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_ADDRINFO 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct timeval" >&5
+echo $ECHO_N "checking for struct timeval... $ECHO_C" >&6; }
+if test "${ac_cv_have_struct_timeval+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <sys/time.h>
+int
+main ()
+{
+ struct timeval tv; tv.tv_sec = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_struct_timeval="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_struct_timeval="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_struct_timeval" >&5
+echo "${ECHO_T}$ac_cv_have_struct_timeval" >&6; }
+if test "x$ac_cv_have_struct_timeval" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_STRUCT_TIMEVAL 1
+_ACEOF
+
+       have_struct_timeval=1
+fi
+
+{ echo "$as_me:$LINENO: checking for struct timespec" >&5
+echo $ECHO_N "checking for struct timespec... $ECHO_C" >&6; }
+if test "${ac_cv_type_struct_timespec+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+typedef struct timespec ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+  return 0;
+if (sizeof (ac__type_new_))
+  return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_struct_timespec=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_struct_timespec=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_struct_timespec" >&5
+echo "${ECHO_T}$ac_cv_type_struct_timespec" >&6; }
+if test $ac_cv_type_struct_timespec = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_TIMESPEC 1
+_ACEOF
+
+
+fi
+
+
+# We need int64_t or else certian parts of the compile will fail.
+if test "x$ac_cv_have_int64_t" = "xno" && \
+       test "x$ac_cv_sizeof_long_int" != "x8" && \
+       test "x$ac_cv_sizeof_long_long_int" = "x0" ; then
+       echo "OpenSSH requires int64_t support.  Contact your vendor or install"
+       echo "an alternative compiler (I.E., GCC) before continuing."
+       echo ""
+       exit 1;
+else
+       if test "$cross_compiling" = yes; then
+  { echo "$as_me:$LINENO: WARNING: cross compiling: Assuming working snprintf()" >&5
+echo "$as_me: WARNING: cross compiling: Assuming working snprintf()" >&2;}
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#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
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   true
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ cat >>confdefs.h <<\_ACEOF
+#define BROKEN_SNPRINTF 1
+_ACEOF
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+
+
+# look for field 'ut_host' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_host
+       { echo "$as_me:$LINENO: checking for ut_host field in utmp.h" >&5
+echo $ECHO_N "checking for ut_host field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_host" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_HOST_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_host' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_host
+       { echo "$as_me:$LINENO: checking for ut_host field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_host field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_host" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_HOST_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'syslen' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"syslen
+       { echo "$as_me:$LINENO: checking for syslen field in utmpx.h" >&5
+echo $ECHO_N "checking for syslen field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "syslen" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYSLEN_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_pid' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_pid
+       { echo "$as_me:$LINENO: checking for ut_pid field in utmp.h" >&5
+echo $ECHO_N "checking for ut_pid field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_pid" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PID_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_type' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_type
+       { echo "$as_me:$LINENO: checking for ut_type field in utmp.h" >&5
+echo $ECHO_N "checking for ut_type field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_type" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TYPE_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_type' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_type
+       { echo "$as_me:$LINENO: checking for ut_type field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_type field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_type" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TYPE_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_tv' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_tv
+       { echo "$as_me:$LINENO: checking for ut_tv field in utmp.h" >&5
+echo $ECHO_N "checking for ut_tv field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_tv" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TV_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_id' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_id
+       { echo "$as_me:$LINENO: checking for ut_id field in utmp.h" >&5
+echo $ECHO_N "checking for ut_id field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_id" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ID_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_id' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_id
+       { echo "$as_me:$LINENO: checking for ut_id field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_id field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_id" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ID_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_addr' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr
+       { echo "$as_me:$LINENO: checking for ut_addr field in utmp.h" >&5
+echo $ECHO_N "checking for ut_addr field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_addr" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDR_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_addr' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr
+       { echo "$as_me:$LINENO: checking for ut_addr field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_addr field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_addr" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDR_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_addr_v6' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr_v6
+       { echo "$as_me:$LINENO: checking for ut_addr_v6 field in utmp.h" >&5
+echo $ECHO_N "checking for ut_addr_v6 field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_addr_v6" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDR_V6_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_addr_v6' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_addr_v6
+       { echo "$as_me:$LINENO: checking for ut_addr_v6 field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_addr_v6 field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_addr_v6" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ADDR_V6_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_exit' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_exit
+       { echo "$as_me:$LINENO: checking for ut_exit field in utmp.h" >&5
+echo $ECHO_N "checking for ut_exit field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_exit" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_EXIT_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_time' in header 'utmp.h'
+               ossh_safe=`echo "utmp.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_time
+       { echo "$as_me:$LINENO: checking for ut_time field in utmp.h" >&5
+echo $ECHO_N "checking for ut_time field in utmp.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmp.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_time" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TIME_IN_UTMP 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_time' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_time
+       { echo "$as_me:$LINENO: checking for ut_time field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_time field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_time" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TIME_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+# look for field 'ut_tv' in header 'utmpx.h'
+               ossh_safe=`echo "utmpx.h" | sed 'y%./+-%__p_%'`
+               ossh_varname="ossh_cv_$ossh_safe""_has_"ut_tv
+       { echo "$as_me:$LINENO: checking for ut_tv field in utmpx.h" >&5
+echo $ECHO_N "checking for ut_tv field in utmpx.h... $ECHO_C" >&6; }
+       if { as_var=$ossh_varname; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <utmpx.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "ut_tv" >/dev/null 2>&1; then
+                       eval "$ossh_varname=yes"
+else
+                       eval "$ossh_varname=no"
+fi
+rm -f conftest*
+
+fi
+
+       ossh_result=`eval 'echo $'"$ossh_varname"`
+       if test -n "`echo $ossh_varname`"; then
+               { echo "$as_me:$LINENO: result: $ossh_result" >&5
+echo "${ECHO_T}$ossh_result" >&6; }
+               if test "x$ossh_result" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_TV_IN_UTMPX 1
+_ACEOF
+
+               fi
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+
+
+{ echo "$as_me:$LINENO: checking for struct stat.st_blksize" >&5
+echo $ECHO_N "checking for struct stat.st_blksize... $ECHO_C" >&6; }
+if test "${ac_cv_member_struct_stat_st_blksize+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_blksize)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct_stat_st_blksize=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_blksize)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct_stat_st_blksize=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_member_struct_stat_st_blksize=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_blksize" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_blksize" >&6; }
+if test $ac_cv_member_struct_stat_st_blksize = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct __res_state.retrans" >&5
+echo $ECHO_N "checking for struct __res_state.retrans... $ECHO_C" >&6; }
+if test "${ac_cv_member_struct___res_state_retrans+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+
+int
+main ()
+{
+static struct __res_state ac_aggr;
+if (ac_aggr.retrans)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct___res_state_retrans=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+
+int
+main ()
+{
+static struct __res_state ac_aggr;
+if (sizeof ac_aggr.retrans)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_struct___res_state_retrans=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_member_struct___res_state_retrans=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_struct___res_state_retrans" >&5
+echo "${ECHO_T}$ac_cv_member_struct___res_state_retrans" >&6; }
+if test $ac_cv_member_struct___res_state_retrans = yes; then
+  :
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define __res_state state
+_ACEOF
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking for ss_family field in struct sockaddr_storage" >&5
+echo $ECHO_N "checking for ss_family field in struct sockaddr_storage... $ECHO_C" >&6; }
+if test "${ac_cv_have_ss_family_in_struct_ss+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+ struct sockaddr_storage s; s.ss_family = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_ss_family_in_struct_ss="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_ss_family_in_struct_ss="no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_ss_family_in_struct_ss" >&5
+echo "${ECHO_T}$ac_cv_have_ss_family_in_struct_ss" >&6; }
+if test "x$ac_cv_have_ss_family_in_struct_ss" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SS_FAMILY_IN_SS 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for __ss_family field in struct sockaddr_storage" >&5
+echo $ECHO_N "checking for __ss_family field in struct sockaddr_storage... $ECHO_C" >&6; }
+if test "${ac_cv_have___ss_family_in_struct_ss+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+ struct sockaddr_storage s; s.__ss_family = 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have___ss_family_in_struct_ss="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have___ss_family_in_struct_ss="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have___ss_family_in_struct_ss" >&5
+echo "${ECHO_T}$ac_cv_have___ss_family_in_struct_ss" >&6; }
+if test "x$ac_cv_have___ss_family_in_struct_ss" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___SS_FAMILY_IN_SS 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for pw_class field in struct passwd" >&5
+echo $ECHO_N "checking for pw_class field in struct passwd... $ECHO_C" >&6; }
+if test "${ac_cv_have_pw_class_in_struct_passwd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <pwd.h>
+
+int
+main ()
+{
+ struct passwd p; p.pw_class = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_pw_class_in_struct_passwd="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_pw_class_in_struct_passwd="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_pw_class_in_struct_passwd" >&5
+echo "${ECHO_T}$ac_cv_have_pw_class_in_struct_passwd" >&6; }
+if test "x$ac_cv_have_pw_class_in_struct_passwd" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PW_CLASS_IN_PASSWD 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for pw_expire field in struct passwd" >&5
+echo $ECHO_N "checking for pw_expire field in struct passwd... $ECHO_C" >&6; }
+if test "${ac_cv_have_pw_expire_in_struct_passwd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <pwd.h>
+
+int
+main ()
+{
+ struct passwd p; p.pw_expire = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_pw_expire_in_struct_passwd="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_pw_expire_in_struct_passwd="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_pw_expire_in_struct_passwd" >&5
+echo "${ECHO_T}$ac_cv_have_pw_expire_in_struct_passwd" >&6; }
+if test "x$ac_cv_have_pw_expire_in_struct_passwd" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PW_EXPIRE_IN_PASSWD 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for pw_change field in struct passwd" >&5
+echo $ECHO_N "checking for pw_change field in struct passwd... $ECHO_C" >&6; }
+if test "${ac_cv_have_pw_change_in_struct_passwd+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <pwd.h>
+
+int
+main ()
+{
+ struct passwd p; p.pw_change = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_pw_change_in_struct_passwd="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_pw_change_in_struct_passwd="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_pw_change_in_struct_passwd" >&5
+echo "${ECHO_T}$ac_cv_have_pw_change_in_struct_passwd" >&6; }
+if test "x$ac_cv_have_pw_change_in_struct_passwd" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PW_CHANGE_IN_PASSWD 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking for msg_accrights field in struct msghdr" >&5
+echo $ECHO_N "checking for msg_accrights field in struct msghdr... $ECHO_C" >&6; }
+if test "${ac_cv_have_accrights_in_msghdr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+int main() {
+#ifdef msg_accrights
+#error "msg_accrights is a macro"
+exit(1);
+#endif
+struct msghdr m;
+m.msg_accrights = 0;
+exit(0);
+}
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_accrights_in_msghdr="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_accrights_in_msghdr="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_accrights_in_msghdr" >&5
+echo "${ECHO_T}$ac_cv_have_accrights_in_msghdr" >&6; }
+if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ACCRIGHTS_IN_MSGHDR 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking if struct statvfs.f_fsid is integral type" >&5
+echo $ECHO_N "checking if struct statvfs.f_fsid is integral type... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+int
+main ()
+{
+struct statvfs s; s.f_fsid = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+       { echo "$as_me:$LINENO: checking if fsid_t has member val" >&5
+echo $ECHO_N "checking if fsid_t has member val... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/statvfs.h>
+int
+main ()
+{
+fsid_t t; t.val[0] = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define FSID_HAS_VAL 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+       { echo "$as_me:$LINENO: checking if f_fsid has member __val" >&5
+echo $ECHO_N "checking if f_fsid has member __val... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/statvfs.h>
+int
+main ()
+{
+fsid_t t; t.__val[0] = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define FSID_HAS___VAL 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ echo "$as_me:$LINENO: checking for msg_control field in struct msghdr" >&5
+echo $ECHO_N "checking for msg_control field in struct msghdr... $ECHO_C" >&6; }
+if test "${ac_cv_have_control_in_msghdr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+int main() {
+#ifdef msg_control
+#error "msg_control is a macro"
+exit(1);
+#endif
+struct msghdr m;
+m.msg_control = 0;
+exit(0);
+}
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   ac_cv_have_control_in_msghdr="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_control_in_msghdr="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_control_in_msghdr" >&5
+echo "${ECHO_T}$ac_cv_have_control_in_msghdr" >&6; }
+if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_CONTROL_IN_MSGHDR 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking if libc defines __progname" >&5
+echo $ECHO_N "checking if libc defines __progname... $ECHO_C" >&6; }
+if test "${ac_cv_libc_defines___progname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ extern char *__progname; printf("%s", __progname);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_libc_defines___progname="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_libc_defines___progname="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_libc_defines___progname" >&5
+echo "${ECHO_T}$ac_cv_libc_defines___progname" >&6; }
+if test "x$ac_cv_libc_defines___progname" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___PROGNAME 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether $CC implements __FUNCTION__" >&5
+echo $ECHO_N "checking whether $CC implements __FUNCTION__... $ECHO_C" >&6; }
+if test "${ac_cv_cc_implements___FUNCTION__+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+
+int
+main ()
+{
+ printf("%s", __FUNCTION__);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_cc_implements___FUNCTION__="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_cc_implements___FUNCTION__="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_cc_implements___FUNCTION__" >&5
+echo "${ECHO_T}$ac_cv_cc_implements___FUNCTION__" >&6; }
+if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___FUNCTION__ 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether $CC implements __func__" >&5
+echo $ECHO_N "checking whether $CC implements __func__... $ECHO_C" >&6; }
+if test "${ac_cv_cc_implements___func__+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+
+int
+main ()
+{
+ printf("%s", __func__);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_cc_implements___func__="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_cc_implements___func__="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_cc_implements___func__" >&5
+echo "${ECHO_T}$ac_cv_cc_implements___func__" >&6; }
+if test "x$ac_cv_cc_implements___func__" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___func__ 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether va_copy exists" >&5
+echo $ECHO_N "checking whether va_copy exists... $ECHO_C" >&6; }
+if test "${ac_cv_have_va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+                va_list x,y;
+int
+main ()
+{
+va_copy(x,y);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_have_va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_va_copy" >&5
+echo "${ECHO_T}$ac_cv_have_va_copy" >&6; }
+if test "x$ac_cv_have_va_copy" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether __va_copy exists" >&5
+echo $ECHO_N "checking whether __va_copy exists... $ECHO_C" >&6; }
+if test "${ac_cv_have___va_copy+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+                va_list x,y;
+int
+main ()
+{
+__va_copy(x,y);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_have___va_copy="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have___va_copy="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have___va_copy" >&5
+echo "${ECHO_T}$ac_cv_have___va_copy" >&6; }
+if test "x$ac_cv_have___va_copy" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE___VA_COPY 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking whether getopt has optreset support" >&5
+echo $ECHO_N "checking whether getopt has optreset support... $ECHO_C" >&6; }
+if test "${ac_cv_have_getopt_optreset+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <getopt.h>
+
+int
+main ()
+{
+ extern int optreset; optreset = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_have_getopt_optreset="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_have_getopt_optreset="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_getopt_optreset" >&5
+echo "${ECHO_T}$ac_cv_have_getopt_optreset" >&6; }
+if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETOPT_OPTRESET 1
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking if libc defines sys_errlist" >&5
+echo $ECHO_N "checking if libc defines sys_errlist... $ECHO_C" >&6; }
+if test "${ac_cv_libc_defines_sys_errlist+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_libc_defines_sys_errlist="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_libc_defines_sys_errlist="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_libc_defines_sys_errlist" >&5
+echo "${ECHO_T}$ac_cv_libc_defines_sys_errlist" >&6; }
+if test "x$ac_cv_libc_defines_sys_errlist" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_ERRLIST 1
+_ACEOF
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking if libc defines sys_nerr" >&5
+echo $ECHO_N "checking if libc defines sys_nerr... $ECHO_C" >&6; }
+if test "${ac_cv_libc_defines_sys_nerr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+ extern int sys_nerr; printf("%i", sys_nerr);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+   ac_cv_libc_defines_sys_nerr="yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        ac_cv_libc_defines_sys_nerr="no"
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_libc_defines_sys_nerr" >&5
+echo "${ECHO_T}$ac_cv_libc_defines_sys_nerr" >&6; }
+if test "x$ac_cv_libc_defines_sys_nerr" = "xyes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_NERR 1
+_ACEOF
+
+fi
+
+# Check libraries needed by DNS fingerprint support
+{ echo "$as_me:$LINENO: checking for library containing getrrsetbyname" >&5
+echo $ECHO_N "checking for library containing getrrsetbyname... $ECHO_C" >&6; }
+if test "${ac_cv_search_getrrsetbyname+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getrrsetbyname ();
+int
+main ()
+{
+return getrrsetbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_getrrsetbyname=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_getrrsetbyname+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_getrrsetbyname+set}" = set; then
+  :
+else
+  ac_cv_search_getrrsetbyname=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_getrrsetbyname" >&5
+echo "${ECHO_T}$ac_cv_search_getrrsetbyname" >&6; }
+ac_res=$ac_cv_search_getrrsetbyname
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_GETRRSETBYNAME 1
+_ACEOF
+
+else
+
+               # Needed by our getrrsetbyname()
+               { echo "$as_me:$LINENO: checking for library containing res_query" >&5
+echo $ECHO_N "checking for library containing res_query... $ECHO_C" >&6; }
+if test "${ac_cv_search_res_query+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char res_query ();
+int
+main ()
+{
+return res_query ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_res_query=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_res_query+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_res_query+set}" = set; then
+  :
+else
+  ac_cv_search_res_query=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_res_query" >&5
+echo "${ECHO_T}$ac_cv_search_res_query" >&6; }
+ac_res=$ac_cv_search_res_query
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+               { echo "$as_me:$LINENO: checking for library containing dn_expand" >&5
+echo $ECHO_N "checking for library containing dn_expand... $ECHO_C" >&6; }
+if test "${ac_cv_search_dn_expand+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dn_expand ();
+int
+main ()
+{
+return dn_expand ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_dn_expand=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_dn_expand+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_dn_expand+set}" = set; then
+  :
+else
+  ac_cv_search_dn_expand=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_dn_expand" >&5
+echo "${ECHO_T}$ac_cv_search_dn_expand" >&6; }
+ac_res=$ac_cv_search_dn_expand
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+               { echo "$as_me:$LINENO: checking if res_query will link" >&5
+echo $ECHO_N "checking if res_query will link... $ECHO_C" >&6; }
+               cat >conftest.$ac_ext <<_ACEOF
+
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+int main()
+{
+       res_query (0, 0, 0, 0, 0);
+       return 0;
+}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                   saved_LIBS="$LIBS"
+                   LIBS="$LIBS -lresolv"
+                   { echo "$as_me:$LINENO: checking for res_query in -lresolv" >&5
+echo $ECHO_N "checking for res_query in -lresolv... $ECHO_C" >&6; }
+                   cat >conftest.$ac_ext <<_ACEOF
+
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+int main()
+{
+       res_query (0, 0, 0, 0, 0);
+       return 0;
+}
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       LIBS="$saved_LIBS"
+                        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+
+for ac_func in _getshort _getlong
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+               { echo "$as_me:$LINENO: checking whether _getshort is declared" >&5
+echo $ECHO_N "checking whether _getshort is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl__getshort+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+                   #include <arpa/nameser.h>
+
+int
+main ()
+{
+#ifndef _getshort
+  (void) _getshort;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl__getshort=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl__getshort=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl__getshort" >&5
+echo "${ECHO_T}$ac_cv_have_decl__getshort" >&6; }
+if test $ac_cv_have_decl__getshort = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__GETSHORT 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__GETSHORT 0
+_ACEOF
+
+
+fi
+{ echo "$as_me:$LINENO: checking whether _getlong is declared" >&5
+echo $ECHO_N "checking whether _getlong is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl__getlong+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+                   #include <arpa/nameser.h>
+
+int
+main ()
+{
+#ifndef _getlong
+  (void) _getlong;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl__getlong=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl__getlong=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl__getlong" >&5
+echo "${ECHO_T}$ac_cv_have_decl__getlong" >&6; }
+if test $ac_cv_have_decl__getlong = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__GETLONG 1
+_ACEOF
+
+
+else
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL__GETLONG 0
+_ACEOF
+
+
+fi
+
+
+               { echo "$as_me:$LINENO: checking for HEADER.ad" >&5
+echo $ECHO_N "checking for HEADER.ad... $ECHO_C" >&6; }
+if test "${ac_cv_member_HEADER_ad+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <arpa/nameser.h>
+
+int
+main ()
+{
+static HEADER ac_aggr;
+if (ac_aggr.ad)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_HEADER_ad=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <arpa/nameser.h>
+
+int
+main ()
+{
+static HEADER ac_aggr;
+if (sizeof ac_aggr.ad)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_member_HEADER_ad=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_member_HEADER_ad=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_HEADER_ad" >&5
+echo "${ECHO_T}$ac_cv_member_HEADER_ad" >&6; }
+if test $ac_cv_member_HEADER_ad = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_HEADER_AD 1
+_ACEOF
+
+fi
+
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking if struct __res_state _res is an extern" >&5
+echo $ECHO_N "checking if struct __res_state _res is an extern... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+extern struct __res_state _res;
+int main() { return 0; }
+
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE__RES_EXTERN 1
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+
+# Check whether user wants SELinux support
+SELINUX_MSG="no"
+LIBSELINUX=""
+
+# Check whether --with-selinux was given.
+if test "${with_selinux+set}" = set; then
+  withval=$with_selinux;  if test "x$withval" != "xno" ; then
+               save_LIBS="$LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define WITH_SELINUX 1
+_ACEOF
+
+               SELINUX_MSG="yes"
+               if test "${ac_cv_header_selinux_selinux_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for selinux/selinux.h" >&5
+echo $ECHO_N "checking for selinux/selinux.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_selinux_selinux_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_selinux_selinux_h" >&5
+echo "${ECHO_T}$ac_cv_header_selinux_selinux_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking selinux/selinux.h usability" >&5
+echo $ECHO_N "checking selinux/selinux.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <selinux/selinux.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking selinux/selinux.h presence" >&5
+echo $ECHO_N "checking selinux/selinux.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <selinux/selinux.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: selinux/selinux.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: selinux/selinux.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: selinux/selinux.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: selinux/selinux.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: selinux/selinux.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: selinux/selinux.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: selinux/selinux.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: selinux/selinux.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for selinux/selinux.h" >&5
+echo $ECHO_N "checking for selinux/selinux.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_selinux_selinux_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_selinux_selinux_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_selinux_selinux_h" >&5
+echo "${ECHO_T}$ac_cv_header_selinux_selinux_h" >&6; }
+
+fi
+if test $ac_cv_header_selinux_selinux_h = yes; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: SELinux support requires selinux.h header" >&5
+echo "$as_me: error: SELinux support requires selinux.h header" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+               { echo "$as_me:$LINENO: checking for setexeccon in -lselinux" >&5
+echo $ECHO_N "checking for setexeccon in -lselinux... $ECHO_C" >&6; }
+if test "${ac_cv_lib_selinux_setexeccon+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lselinux  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char setexeccon ();
+int
+main ()
+{
+return setexeccon ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_selinux_setexeccon=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_selinux_setexeccon=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_setexeccon" >&5
+echo "${ECHO_T}$ac_cv_lib_selinux_setexeccon" >&6; }
+if test $ac_cv_lib_selinux_setexeccon = yes; then
+   LIBSELINUX="-lselinux"
+                         LIBS="$LIBS -lselinux"
+
+else
+  { { echo "$as_me:$LINENO: error: SELinux support requires libselinux library" >&5
+echo "$as_me: error: SELinux support requires libselinux library" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+               SSHLIBS="$SSHLIBS $LIBSELINUX"
+               SSHDLIBS="$SSHDLIBS $LIBSELINUX"
+
+
+for ac_func in getseuserbyname get_default_context_with_level
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+               LIBS="$save_LIBS"
+       fi
+
+fi
+
+
+
+
+# Check whether user wants Kerberos 5 support
+KRB5_MSG="no"
+
+# Check whether --with-kerberos5 was given.
+if test "${with_kerberos5+set}" = set; then
+  withval=$with_kerberos5;  if test "x$withval" != "xno" ; then
+               if test "x$withval" = "xyes" ; then
+                       KRB5ROOT="/usr/local"
+               else
+                       KRB5ROOT=${withval}
+               fi
+
+
+cat >>confdefs.h <<\_ACEOF
+#define KRB5 1
+_ACEOF
+
+               KRB5_MSG="yes"
+
+               # Extract the first word of "krb5-config", so it can be a program name with args.
+set dummy krb5-config; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_KRB5CONF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $KRB5CONF in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_KRB5CONF="$KRB5CONF" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_dummy="$KRB5ROOT/bin:$PATH"
+for as_dir in $as_dummy
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_KRB5CONF="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_KRB5CONF" && ac_cv_path_KRB5CONF="$KRB5ROOT/bin/krb5-config"
+  ;;
+esac
+fi
+KRB5CONF=$ac_cv_path_KRB5CONF
+if test -n "$KRB5CONF"; then
+  { echo "$as_me:$LINENO: result: $KRB5CONF" >&5
+echo "${ECHO_T}$KRB5CONF" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+               if test -x $KRB5CONF ; then
+
+                       { echo "$as_me:$LINENO: checking for gssapi support" >&5
+echo $ECHO_N "checking for gssapi support... $ECHO_C" >&6; }
+                       if $KRB5CONF | grep gssapi >/dev/null ; then
+                               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+                               k5confopts=gssapi
+                       else
+                               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                               k5confopts=""
+                       fi
+                       K5CFLAGS="`$KRB5CONF --cflags $k5confopts`"
+                       K5LIBS="`$KRB5CONF --libs $k5confopts`"
+                       CPPFLAGS="$CPPFLAGS $K5CFLAGS"
+                       { echo "$as_me:$LINENO: checking whether we are using Heimdal" >&5
+echo $ECHO_N "checking whether we are using Heimdal... $ECHO_C" >&6; }
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <krb5.h>
+int
+main ()
+{
+ char *tmp = heimdal_version;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HEIMDAL 1
+_ACEOF
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+               else
+                       CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include"
+                       LDFLAGS="$LDFLAGS -L${KRB5ROOT}/lib"
+                       { echo "$as_me:$LINENO: checking whether we are using Heimdal" >&5
+echo $ECHO_N "checking whether we are using Heimdal... $ECHO_C" >&6; }
+                       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+ #include <krb5.h>
+int
+main ()
+{
+ char *tmp = heimdal_version;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+                                        cat >>confdefs.h <<\_ACEOF
+#define HEIMDAL 1
+_ACEOF
+
+                                        K5LIBS="-lkrb5"
+                                        K5LIBS="$K5LIBS -lcom_err -lasn1"
+                                        { echo "$as_me:$LINENO: checking for net_write in -lroken" >&5
+echo $ECHO_N "checking for net_write in -lroken... $ECHO_C" >&6; }
+if test "${ac_cv_lib_roken_net_write+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lroken  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char net_write ();
+int
+main ()
+{
+return net_write ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_roken_net_write=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_roken_net_write=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_roken_net_write" >&5
+echo "${ECHO_T}$ac_cv_lib_roken_net_write" >&6; }
+if test $ac_cv_lib_roken_net_write = yes; then
+  K5LIBS="$K5LIBS -lroken"
+fi
+
+                                        { echo "$as_me:$LINENO: checking for des_cbc_encrypt in -ldes" >&5
+echo $ECHO_N "checking for des_cbc_encrypt in -ldes... $ECHO_C" >&6; }
+if test "${ac_cv_lib_des_des_cbc_encrypt+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldes  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char des_cbc_encrypt ();
+int
+main ()
+{
+return des_cbc_encrypt ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_des_des_cbc_encrypt=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_des_des_cbc_encrypt=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_des_des_cbc_encrypt" >&5
+echo "${ECHO_T}$ac_cv_lib_des_des_cbc_encrypt" >&6; }
+if test $ac_cv_lib_des_des_cbc_encrypt = yes; then
+  K5LIBS="$K5LIBS -ldes"
+fi
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                                        K5LIBS="-lkrb5 -lk5crypto -lcom_err"
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+                       { echo "$as_me:$LINENO: checking for library containing dn_expand" >&5
+echo $ECHO_N "checking for library containing dn_expand... $ECHO_C" >&6; }
+if test "${ac_cv_search_dn_expand+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dn_expand ();
+int
+main ()
+{
+return dn_expand ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_dn_expand=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_dn_expand+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_dn_expand+set}" = set; then
+  :
+else
+  ac_cv_search_dn_expand=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_dn_expand" >&5
+echo "${ECHO_T}$ac_cv_search_dn_expand" >&6; }
+ac_res=$ac_cv_search_dn_expand
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+                       { echo "$as_me:$LINENO: checking for gss_init_sec_context in -lgssapi_krb5" >&5
+echo $ECHO_N "checking for gss_init_sec_context in -lgssapi_krb5... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gssapi_krb5_gss_init_sec_context+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi_krb5 $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gss_init_sec_context ();
+int
+main ()
+{
+return gss_init_sec_context ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gssapi_krb5_gss_init_sec_context=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gssapi_krb5_gss_init_sec_context=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&6; }
+if test $ac_cv_lib_gssapi_krb5_gss_init_sec_context = yes; then
+   cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+                                 K5LIBS="-lgssapi_krb5 $K5LIBS"
+else
+   { echo "$as_me:$LINENO: checking for gss_init_sec_context in -lgssapi" >&5
+echo $ECHO_N "checking for gss_init_sec_context in -lgssapi... $ECHO_C" >&6; }
+if test "${ac_cv_lib_gssapi_gss_init_sec_context+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gss_init_sec_context ();
+int
+main ()
+{
+return gss_init_sec_context ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_lib_gssapi_gss_init_sec_context=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_gssapi_gss_init_sec_context=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_gss_init_sec_context" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_gss_init_sec_context" >&6; }
+if test $ac_cv_lib_gssapi_gss_init_sec_context = yes; then
+   cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+                                         K5LIBS="-lgssapi $K5LIBS"
+else
+  { echo "$as_me:$LINENO: WARNING: Cannot find any suitable gss-api library - build may fail" >&5
+echo "$as_me: WARNING: Cannot find any suitable gss-api library - build may fail" >&2;}
+fi
+
+
+fi
+
+
+                       if test "${ac_cv_header_gssapi_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for gssapi.h" >&5
+echo $ECHO_N "checking for gssapi.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_gssapi_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking gssapi.h usability" >&5
+echo $ECHO_N "checking gssapi.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <gssapi.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking gssapi.h presence" >&5
+echo $ECHO_N "checking gssapi.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <gssapi.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: gssapi.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: gssapi.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: gssapi.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: gssapi.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: gssapi.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: gssapi.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for gssapi.h" >&5
+echo $ECHO_N "checking for gssapi.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_gssapi_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_gssapi_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_h" >&6; }
+
+fi
+if test $ac_cv_header_gssapi_h = yes; then
+  :
+else
+   unset ac_cv_header_gssapi_h
+                                 CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+
+for ac_header in gssapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: WARNING: Cannot find any suitable gss-api header - build may fail" >&5
+echo "$as_me: WARNING: Cannot find any suitable gss-api header - build may fail" >&2;}
+
+fi
+
+done
+
+
+
+fi
+
+
+
+                       oldCPP="$CPPFLAGS"
+                       CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+                       if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for gssapi_krb5.h" >&5
+echo $ECHO_N "checking for gssapi_krb5.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_krb5_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_krb5_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking gssapi_krb5.h usability" >&5
+echo $ECHO_N "checking gssapi_krb5.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <gssapi_krb5.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking gssapi_krb5.h presence" >&5
+echo $ECHO_N "checking gssapi_krb5.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <gssapi_krb5.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: gssapi_krb5.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: gssapi_krb5.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for gssapi_krb5.h" >&5
+echo $ECHO_N "checking for gssapi_krb5.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_gssapi_krb5_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_krb5_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_krb5_h" >&6; }
+
+fi
+if test $ac_cv_header_gssapi_krb5_h = yes; then
+  :
+else
+   CPPFLAGS="$oldCPP"
+fi
+
+
+
+               fi
+               if test ! -z "$need_dash_r" ; then
+                       LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
+               fi
+               if test ! -z "$blibpath" ; then
+                       blibpath="$blibpath:${KRB5ROOT}/lib"
+               fi
+
+
+
+for ac_header in gssapi.h gssapi/gssapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in gssapi_krb5.h gssapi/gssapi_krb5.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in gssapi_generic.h gssapi/gssapi_generic.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    ( cat <<\_ASBOX
+## ------------------------------------------- ##
+## Report this to openssh-unix-dev@mindrot.org ##
+## ------------------------------------------- ##
+_ASBOX
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+               LIBS="$LIBS $K5LIBS"
+               { echo "$as_me:$LINENO: checking for library containing k_hasafs" >&5
+echo $ECHO_N "checking for library containing k_hasafs... $ECHO_C" >&6; }
+if test "${ac_cv_search_k_hasafs+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char k_hasafs ();
+int
+main ()
+{
+return k_hasafs ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' kafs; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  ac_cv_search_k_hasafs=$ac_res
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext
+  if test "${ac_cv_search_k_hasafs+set}" = set; then
+  break
+fi
+done
+if test "${ac_cv_search_k_hasafs+set}" = set; then
+  :
+else
+  ac_cv_search_k_hasafs=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_k_hasafs" >&5
+echo "${ECHO_T}$ac_cv_search_k_hasafs" >&6; }
+ac_res=$ac_cv_search_k_hasafs
+if test "$ac_res" != no; then
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_AFS 1
+_ACEOF
+
+fi
+
+       fi
+
+
+fi
+
+
+# Looking for programs, paths and files
+
+PRIVSEP_PATH=/var/empty
+
+# Check whether --with-privsep-path was given.
+if test "${with_privsep_path+set}" = set; then
+  withval=$with_privsep_path;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       PRIVSEP_PATH=$withval
+               fi
+
+
+fi
+
+
+
+
+# Check whether --with-xauth was given.
+if test "${with_xauth+set}" = set; then
+  withval=$with_xauth;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       xauth_path=$withval
+               fi
+
+else
+
+               TestPath="$PATH"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/X/bin"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/bin/X11"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/X11R6/bin"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/openwin/bin"
+               # Extract the first word of "xauth", so it can be a program name with args.
+set dummy xauth; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_xauth_path+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $xauth_path in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_xauth_path="$xauth_path" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $TestPath
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_xauth_path="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+xauth_path=$ac_cv_path_xauth_path
+if test -n "$xauth_path"; then
+  { echo "$as_me:$LINENO: result: $xauth_path" >&5
+echo "${ECHO_T}$xauth_path" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+               if (test ! -z "$xauth_path" && test -x "/usr/openwin/bin/xauth") ; then
+                       xauth_path="/usr/openwin/bin/xauth"
+               fi
+
+
+fi
+
+
+STRIP_OPT=-s
+# Check whether --enable-strip was given.
+if test "${enable_strip+set}" = set; then
+  enableval=$enable_strip;
+               if test "x$enableval" = "xno" ; then
+                       STRIP_OPT=
+               fi
+
+
+fi
+
+
+
+if test -z "$xauth_path" ; then
+       XAUTH_PATH="undefined"
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define XAUTH_PATH "$xauth_path"
+_ACEOF
+
+       XAUTH_PATH=$xauth_path
+
+fi
+
+# Check for mail directory (last resort if we cannot get it from headers)
+if test ! -z "$MAIL" ; then
+       maildir=`dirname $MAIL`
+
+cat >>confdefs.h <<_ACEOF
+#define MAIL_DIRECTORY "$maildir"
+_ACEOF
+
+fi
+
+if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes"; then
+       { echo "$as_me:$LINENO: WARNING: cross compiling: Disabling /dev/ptmx test" >&5
+echo "$as_me: WARNING: cross compiling: Disabling /dev/ptmx test" >&2;}
+       disable_ptmx_check=yes
+fi
+if test -z "$no_dev_ptmx" ; then
+       if test "x$disable_ptmx_check" != "xyes" ; then
+               { echo "$as_me:$LINENO: checking for \"/dev/ptmx\"" >&5
+echo $ECHO_N "checking for \"/dev/ptmx\"... $ECHO_C" >&6; }
+if test "${ac_cv_file___dev_ptmx_+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r ""/dev/ptmx""; then
+  ac_cv_file___dev_ptmx_=yes
+else
+  ac_cv_file___dev_ptmx_=no
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_file___dev_ptmx_" >&5
+echo "${ECHO_T}$ac_cv_file___dev_ptmx_" >&6; }
+if test $ac_cv_file___dev_ptmx_ = yes; then
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DEV_PTMX 1
+_ACEOF
+
+                               have_dev_ptmx=1
+
+
+fi
+
+       fi
+fi
+
+if test ! -z "$cross_compiling" && test "x$cross_compiling" != "xyes"; then
+       { echo "$as_me:$LINENO: checking for \"/dev/ptc\"" >&5
+echo $ECHO_N "checking for \"/dev/ptc\"... $ECHO_C" >&6; }
+if test "${ac_cv_file___dev_ptc_+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r ""/dev/ptc""; then
+  ac_cv_file___dev_ptc_=yes
+else
+  ac_cv_file___dev_ptc_=no
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_file___dev_ptc_" >&5
+echo "${ECHO_T}$ac_cv_file___dev_ptc_" >&6; }
+if test $ac_cv_file___dev_ptc_ = yes; then
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DEV_PTS_AND_PTC 1
+_ACEOF
+
+                       have_dev_ptc=1
+
+
+fi
+
+else
+       { echo "$as_me:$LINENO: WARNING: cross compiling: Disabling /dev/ptc test" >&5
+echo "$as_me: WARNING: cross compiling: Disabling /dev/ptc test" >&2;}
+fi
+
+# Options from here on. Some of these are preset by platform above
+
+# Check whether --with-mantype was given.
+if test "${with_mantype+set}" = set; then
+  withval=$with_mantype;
+               case "$withval" in
+               man|cat|doc)
+                       MANTYPE=$withval
+                       ;;
+               *)
+                       { { echo "$as_me:$LINENO: error: invalid man type: $withval" >&5
+echo "$as_me: error: invalid man type: $withval" >&2;}
+   { (exit 1); exit 1; }; }
+                       ;;
+               esac
+
+
+fi
+
+if test -z "$MANTYPE"; then
+       TestPath="/usr/bin${PATH_SEPARATOR}/usr/ucb"
+       for ac_prog in nroff awf
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_NROFF+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $NROFF in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_NROFF="$NROFF" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $TestPath
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_NROFF="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+NROFF=$ac_cv_path_NROFF
+if test -n "$NROFF"; then
+  { echo "$as_me:$LINENO: result: $NROFF" >&5
+echo "${ECHO_T}$NROFF" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  test -n "$NROFF" && break
+done
+test -n "$NROFF" || NROFF="/bin/false"
+
+       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
+
+if test "$MANTYPE" = "doc"; then
+       mansubdir=man;
+else
+       mansubdir=$MANTYPE;
+fi
+
+
+# Check whether to enable MD5 passwords
+MD5_MSG="no"
+
+# Check whether --with-md5-passwords was given.
+if test "${with_md5_passwords+set}" = set; then
+  withval=$with_md5_passwords;
+               if test "x$withval" != "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MD5_PASSWORDS 1
+_ACEOF
+
+                       MD5_MSG="yes"
+               fi
+
+
+fi
+
+
+# Whether to disable shadow password support
+
+# Check whether --with-shadow was given.
+if test "${with_shadow+set}" = set; then
+  withval=$with_shadow;
+               if test "x$withval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_SHADOW 1
+_ACEOF
+
+                       disable_shadow=yes
+               fi
+
+
+fi
+
+
+if test -z "$disable_shadow" ; then
+       { echo "$as_me:$LINENO: checking if the systems has expire shadow information" >&5
+echo $ECHO_N "checking if the systems has expire shadow information... $ECHO_C" >&6; }
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <shadow.h>
+       struct spwd sp;
+
+int
+main ()
+{
+ sp.sp_expire = sp.sp_lstchg = sp.sp_inact = 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   sp_expire_available=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+       if test "x$sp_expire_available" = "xyes" ; then
+               { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define HAS_SHADOW_EXPIRE 1
+_ACEOF
+
+       else
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+       fi
+fi
+
+# Use ip address instead of hostname in $DISPLAY
+if test ! -z "$IPADDR_IN_DISPLAY" ; then
+       DISPLAY_HACK_MSG="yes"
+
+cat >>confdefs.h <<\_ACEOF
+#define IPADDR_IN_DISPLAY 1
+_ACEOF
+
+else
+       DISPLAY_HACK_MSG="no"
+
+# Check whether --with-ipaddr-display was given.
+if test "${with_ipaddr_display+set}" = set; then
+  withval=$with_ipaddr_display;
+                       if test "x$withval" != "xno" ; then
+                               cat >>confdefs.h <<\_ACEOF
+#define IPADDR_IN_DISPLAY 1
+_ACEOF
+
+                               DISPLAY_HACK_MSG="yes"
+                       fi
+
+
+fi
+
+fi
+
+# check for /etc/default/login and use it if present.
+# Check whether --enable-etc-default-login was given.
+if test "${enable_etc_default_login+set}" = set; then
+  enableval=$enable_etc_default_login;  if test "x$enableval" = "xno"; then
+               { echo "$as_me:$LINENO: /etc/default/login handling disabled" >&5
+echo "$as_me: /etc/default/login handling disabled" >&6;}
+               etc_default_login=no
+         else
+               etc_default_login=yes
+         fi
+else
+   if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes";
+         then
+               { echo "$as_me:$LINENO: WARNING: cross compiling: not checking /etc/default/login" >&5
+echo "$as_me: WARNING: cross compiling: not checking /etc/default/login" >&2;}
+               etc_default_login=no
+         else
+               etc_default_login=yes
+         fi
+
+fi
+
+
+if test "x$etc_default_login" != "xno"; then
+       { echo "$as_me:$LINENO: checking for \"/etc/default/login\"" >&5
+echo $ECHO_N "checking for \"/etc/default/login\"... $ECHO_C" >&6; }
+if test "${ac_cv_file___etc_default_login_+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  test "$cross_compiling" = yes &&
+  { { echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r ""/etc/default/login""; then
+  ac_cv_file___etc_default_login_=yes
+else
+  ac_cv_file___etc_default_login_=no
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_file___etc_default_login_" >&5
+echo "${ECHO_T}$ac_cv_file___etc_default_login_" >&6; }
+if test $ac_cv_file___etc_default_login_ = yes; then
+   external_path_file=/etc/default/login
+fi
+
+       if test "x$external_path_file" = "x/etc/default/login"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_ETC_DEFAULT_LOGIN 1
+_ACEOF
+
+       fi
+fi
+
+if test $ac_cv_func_login_getcapbool = "yes" && \
+       test $ac_cv_header_login_cap_h = "yes" ; then
+       external_path_file=/etc/login.conf
+fi
+
+# Whether to mess with the default path
+SERVER_PATH_MSG="(default)"
+
+# Check whether --with-default-path was given.
+if test "${with_default_path+set}" = set; then
+  withval=$with_default_path;
+               if test "x$external_path_file" = "x/etc/login.conf" ; then
+                       { echo "$as_me:$LINENO: WARNING:
+--with-default-path=PATH has no effect on this system.
+Edit /etc/login.conf instead." >&5
+echo "$as_me: WARNING:
+--with-default-path=PATH has no effect on this system.
+Edit /etc/login.conf instead." >&2;}
+               elif test "x$withval" != "xno" ; then
+                       if test ! -z "$external_path_file" ; then
+                               { echo "$as_me:$LINENO: WARNING:
+--with-default-path=PATH will only be used if PATH is not defined in
+$external_path_file ." >&5
+echo "$as_me: WARNING:
+--with-default-path=PATH will only be used if PATH is not defined in
+$external_path_file ." >&2;}
+                       fi
+                       user_path="$withval"
+                       SERVER_PATH_MSG="$withval"
+               fi
+
+else
+   if test "x$external_path_file" = "x/etc/login.conf" ; then
+               { echo "$as_me:$LINENO: WARNING: Make sure the path to scp is in /etc/login.conf" >&5
+echo "$as_me: WARNING: Make sure the path to scp is in /etc/login.conf" >&2;}
+       else
+               if test ! -z "$external_path_file" ; then
+                       { echo "$as_me:$LINENO: WARNING:
+If PATH is defined in $external_path_file, ensure the path to scp is included,
+otherwise scp will not work." >&5
+echo "$as_me: WARNING:
+If PATH is defined in $external_path_file, ensure the path to scp is included,
+otherwise scp will not work." >&2;}
+               fi
+               if test "$cross_compiling" = yes; then
+   user_path="/usr/bin:/bin:/usr/sbin:/sbin"
+
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* find out what STDPATH is */
+#include <stdio.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#ifndef _PATH_STDPATH
+# ifdef _PATH_USERPATH /* Irix */
+#  define _PATH_STDPATH _PATH_USERPATH
+# else
+#  define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
+# endif
+#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);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+   user_path=`cat conftest.stdpath`
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ user_path="/usr/bin:/bin:/usr/sbin:/sbin"
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+# 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
+                               { echo "$as_me:$LINENO: result: Adding $t_bindir to USER_PATH so scp will work" >&5
+echo "${ECHO_T}Adding $t_bindir to USER_PATH so scp will work" >&6; }
+                       fi
+               fi
+       fi
+
+fi
+
+if test "x$external_path_file" != "x/etc/login.conf" ; then
+
+cat >>confdefs.h <<_ACEOF
+#define USER_PATH "$user_path"
+_ACEOF
+
+
+fi
+
+# Set superuser path separately to user path
+
+# Check whether --with-superuser-path was given.
+if test "${with_superuser_path+set}" = set; then
+  withval=$with_superuser_path;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+
+cat >>confdefs.h <<_ACEOF
+#define SUPERUSER_PATH "$withval"
+_ACEOF
+
+                       superuser_path=$withval
+               fi
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking if we need to convert IPv4 in IPv6-mapped addresses" >&5
+echo $ECHO_N "checking if we need to convert IPv4 in IPv6-mapped addresses... $ECHO_C" >&6; }
+IPV4_IN6_HACK_MSG="no"
+
+# Check whether --with-4in6 was given.
+if test "${with_4in6+set}" = set; then
+  withval=$with_4in6;
+               if test "x$withval" != "xno" ; then
+                       { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define IPV4_IN_IPV6 1
+_ACEOF
+
+                       IPV4_IN6_HACK_MSG="yes"
+               else
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               fi
+
+else
+
+               if test "x$inet6_default_4in6" = "xyes"; then
+                       { echo "$as_me:$LINENO: result: yes (default)" >&5
+echo "${ECHO_T}yes (default)" >&6; }
+                       cat >>confdefs.h <<\_ACEOF
+#define IPV4_IN_IPV6 1
+_ACEOF
+
+                       IPV4_IN6_HACK_MSG="yes"
+               else
+                       { echo "$as_me:$LINENO: result: no (default)" >&5
+echo "${ECHO_T}no (default)" >&6; }
+               fi
+
+
+fi
+
+
+# Whether to enable BSD auth support
+BSD_AUTH_MSG=no
+
+# Check whether --with-bsd-auth was given.
+if test "${with_bsd_auth+set}" = set; then
+  withval=$with_bsd_auth;
+               if test "x$withval" != "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define BSD_AUTH 1
+_ACEOF
+
+                       BSD_AUTH_MSG=yes
+               fi
+
+
+fi
+
+
+# Where to place sshd.pid
+piddir=/var/run
+# 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
+
+
+# Check whether --with-pid-dir was given.
+if test "${with_pid_dir+set}" = set; then
+  withval=$with_pid_dir;
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       piddir=$withval
+                       if test ! -d $piddir ; then
+                       { echo "$as_me:$LINENO: WARNING: ** no $piddir directory on this system **" >&5
+echo "$as_me: WARNING: ** no $piddir directory on this system **" >&2;}
+                       fi
+               fi
+
+
+fi
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define _PATH_SSH_PIDDIR "$piddir"
+_ACEOF
+
+
+
+# Check whether --enable-lastlog was given.
+if test "${enable_lastlog+set}" = set; then
+  enableval=$enable_lastlog;
+               if test "x$enableval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LASTLOG 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-utmp was given.
+if test "${enable_utmp+set}" = set; then
+  enableval=$enable_utmp;
+               if test "x$enableval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_UTMP 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-utmpx was given.
+if test "${enable_utmpx+set}" = set; then
+  enableval=$enable_utmpx;
+               if test "x$enableval" = "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_UTMPX 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-wtmp was given.
+if test "${enable_wtmp+set}" = set; then
+  enableval=$enable_wtmp;
+               if test "x$enableval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_WTMP 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-wtmpx was given.
+if test "${enable_wtmpx+set}" = set; then
+  enableval=$enable_wtmpx;
+               if test "x$enableval" = "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_WTMPX 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-libutil was given.
+if test "${enable_libutil+set}" = set; then
+  enableval=$enable_libutil;
+               if test "x$enableval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LOGIN 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-pututline was given.
+if test "${enable_pututline+set}" = set; then
+  enableval=$enable_pututline;
+               if test "x$enableval" = "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_PUTUTLINE 1
+_ACEOF
+
+               fi
+
+
+fi
+
+# Check whether --enable-pututxline was given.
+if test "${enable_pututxline+set}" = set; then
+  enableval=$enable_pututxline;
+               if test "x$enableval" = "xno" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DISABLE_PUTUTXLINE 1
+_ACEOF
+
+               fi
+
+
+fi
+
+
+# Check whether --with-lastlog was given.
+if test "${with_lastlog+set}" = set; then
+  withval=$with_lastlog;
+               if test "x$withval" = "xno" ; then
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_LASTLOG 1
+_ACEOF
+
+               elif test -n "$withval"  &&  test "x${withval}" != "xyes"; then
+                       conf_lastlog_location=$withval
+               fi
+
+
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking if your system defines LASTLOG_FILE" >&5
+echo $ECHO_N "checking if your system defines LASTLOG_FILE... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#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
+
+int
+main ()
+{
+ char *lastlog = LASTLOG_FILE;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+               { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+               { echo "$as_me:$LINENO: checking if your system defines _PATH_LASTLOG" >&5
+echo $ECHO_N "checking if your system defines _PATH_LASTLOG... $ECHO_C" >&6; }
+               cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+
+int
+main ()
+{
+ char *lastlog = _PATH_LASTLOG;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+                       { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+                       system_lastlog_path=no
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+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
+                       { echo "$as_me:$LINENO: WARNING: ** Cannot find lastlog **" >&5
+echo "$as_me: WARNING: ** Cannot find lastlog **" >&2;}
+                                       fi
+       fi
+fi
+
+if test -n "$conf_lastlog_location"; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONF_LASTLOG_FILE "$conf_lastlog_location"
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking if your system defines UTMP_FILE" >&5
+echo $ECHO_N "checking if your system defines UTMP_FILE... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+
+int
+main ()
+{
+ char *utmp = UTMP_FILE;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+         system_utmp_path=no
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+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
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_UTMP 1
+_ACEOF
+
+               fi
+       fi
+fi
+if test -n "$conf_utmp_location"; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONF_UTMP_FILE "$conf_utmp_location"
+_ACEOF
+
+fi
+
+{ echo "$as_me:$LINENO: checking if your system defines WTMP_FILE" >&5
+echo $ECHO_N "checking if your system defines WTMP_FILE... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+
+int
+main ()
+{
+ char *wtmp = WTMP_FILE;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+         system_wtmp_path=no
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+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
+                       cat >>confdefs.h <<\_ACEOF
+#define DISABLE_WTMP 1
+_ACEOF
+
+               fi
+       fi
+fi
+if test -n "$conf_wtmp_location"; then
+
+cat >>confdefs.h <<_ACEOF
+#define CONF_WTMP_FILE "$conf_wtmp_location"
+_ACEOF
+
+fi
+
+
+{ echo "$as_me:$LINENO: checking if your system defines WTMPX_FILE" >&5
+echo $ECHO_N "checking if your system defines WTMPX_FILE... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+#ifdef HAVE_PATHS_H
+#  include <paths.h>
+#endif
+
+int
+main ()
+{
+ char *wtmpx = WTMPX_FILE;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+   { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+        { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+         system_wtmpx_path=no
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test -z "$conf_wtmpx_location"; then
+       if test x"$system_wtmpx_path" = x"no" ; then
+               cat >>confdefs.h <<\_ACEOF
+#define DISABLE_WTMPX 1
+_ACEOF
+
+       fi
+else
+
+cat >>confdefs.h <<_ACEOF
+#define CONF_WTMPX_FILE "$conf_wtmpx_location"
+_ACEOF
+
+fi
+
+
+if test ! -z "$blibpath" ; then
+       LDFLAGS="$LDFLAGS $blibflags$blibpath"
+       { echo "$as_me:$LINENO: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&5
+echo "$as_me: WARNING: Please check and edit blibpath in LDFLAGS in Makefile" >&2;}
+fi
+
+CFLAGS="$CFLAGS $werror_flags"
+
+if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
+       TEST_SSH_IPV6=no
+else
+       TEST_SSH_IPV6=yes
+fi
+{ echo "$as_me:$LINENO: checking whether BROKEN_GETADDRINFO is declared" >&5
+echo $ECHO_N "checking whether BROKEN_GETADDRINFO is declared... $ECHO_C" >&6; }
+if test "${ac_cv_have_decl_BROKEN_GETADDRINFO+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+#ifndef BROKEN_GETADDRINFO
+  (void) BROKEN_GETADDRINFO;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_have_decl_BROKEN_GETADDRINFO=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_have_decl_BROKEN_GETADDRINFO=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_BROKEN_GETADDRINFO" >&5
+echo "${ECHO_T}$ac_cv_have_decl_BROKEN_GETADDRINFO" >&6; }
+if test $ac_cv_have_decl_BROKEN_GETADDRINFO = yes; then
+  TEST_SSH_IPV6=no
+fi
+
+TEST_SSH_IPV6=$TEST_SSH_IPV6
+
+
+
+ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openssh.xml openbsd-compat/Makefile openbsd-compat/regress/Makefile ssh_prng_cmds survey.sh"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s='ln -s'
+  # ... but there are two gotchas:
+  # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+  # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+  # In both cases, we have to default to `cp -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+       case $1 in
+        -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by OpenSSH $as_me Portable, which was
+generated by GNU Autoconf 2.61.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --file=FILE[:TEMPLATE]
+                  instantiate the configuration file FILE
+  --header=FILE[:TEMPLATE]
+                  instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+OpenSSH config.status Portable
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "buildpkg.sh") CONFIG_FILES="$CONFIG_FILES buildpkg.sh" ;;
+    "opensshd.init") CONFIG_FILES="$CONFIG_FILES opensshd.init" ;;
+    "openssh.xml") CONFIG_FILES="$CONFIG_FILES openssh.xml" ;;
+    "openbsd-compat/Makefile") CONFIG_FILES="$CONFIG_FILES openbsd-compat/Makefile" ;;
+    "openbsd-compat/regress/Makefile") CONFIG_FILES="$CONFIG_FILES openbsd-compat/regress/Makefile" ;;
+    "ssh_prng_cmds") CONFIG_FILES="$CONFIG_FILES ssh_prng_cmds" ;;
+    "survey.sh") CONFIG_FILES="$CONFIG_FILES survey.sh" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+build!$build$ac_delim
+build_cpu!$build_cpu$ac_delim
+build_vendor!$build_vendor$ac_delim
+build_os!$build_os$ac_delim
+host!$host$ac_delim
+host_cpu!$host_cpu$ac_delim
+host_vendor!$host_vendor$ac_delim
+host_os!$host_os$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+AWK!$AWK$ac_delim
+RANLIB!$RANLIB$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+AR!$AR$ac_delim
+CAT!$CAT$ac_delim
+KILL!$KILL$ac_delim
+PERL!$PERL$ac_delim
+SED!$SED$ac_delim
+ENT!$ENT$ac_delim
+TEST_MINUS_S_SH!$TEST_MINUS_S_SH$ac_delim
+SH!$SH$ac_delim
+GROFF!$GROFF$ac_delim
+NROFF!$NROFF$ac_delim
+MANDOC!$MANDOC$ac_delim
+TEST_SHELL!$TEST_SHELL$ac_delim
+MANFMT!$MANFMT$ac_delim
+PATH_GROUPADD_PROG!$PATH_GROUPADD_PROG$ac_delim
+PATH_USERADD_PROG!$PATH_USERADD_PROG$ac_delim
+MAKE_PACKAGE_SUPPORTED!$MAKE_PACKAGE_SUPPORTED$ac_delim
+STARTUP_SCRIPT_SHELL!$STARTUP_SCRIPT_SHELL$ac_delim
+LOGIN_PROGRAM_FALLBACK!$LOGIN_PROGRAM_FALLBACK$ac_delim
+PATH_PASSWD_PROG!$PATH_PASSWD_PROG$ac_delim
+LD!$LD$ac_delim
+PKGCONFIG!$PKGCONFIG$ac_delim
+LIBEDIT!$LIBEDIT$ac_delim
+TEST_SSH_SHA256!$TEST_SSH_SHA256$ac_delim
+TEST_SSH_ECC!$TEST_SSH_ECC$ac_delim
+COMMENT_OUT_ECC!$COMMENT_OUT_ECC$ac_delim
+INSTALL_SSH_RAND_HELPER!$INSTALL_SSH_RAND_HELPER$ac_delim
+SSH_PRIVSEP_USER!$SSH_PRIVSEP_USER$ac_delim
+PROG_LS!$PROG_LS$ac_delim
+PROG_NETSTAT!$PROG_NETSTAT$ac_delim
+PROG_ARP!$PROG_ARP$ac_delim
+PROG_IFCONFIG!$PROG_IFCONFIG$ac_delim
+PROG_JSTAT!$PROG_JSTAT$ac_delim
+PROG_PS!$PROG_PS$ac_delim
+PROG_SAR!$PROG_SAR$ac_delim
+PROG_W!$PROG_W$ac_delim
+PROG_WHO!$PROG_WHO$ac_delim
+PROG_LAST!$PROG_LAST$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+CEOF$ac_eof
+_ACEOF
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+PROG_LASTLOG!$PROG_LASTLOG$ac_delim
+PROG_DF!$PROG_DF$ac_delim
+PROG_VMSTAT!$PROG_VMSTAT$ac_delim
+PROG_UPTIME!$PROG_UPTIME$ac_delim
+PROG_IPCS!$PROG_IPCS$ac_delim
+PROG_TAIL!$PROG_TAIL$ac_delim
+INSTALL_SSH_PRNG_CMDS!$INSTALL_SSH_PRNG_CMDS$ac_delim
+SSHLIBS!$SSHLIBS$ac_delim
+SSHDLIBS!$SSHDLIBS$ac_delim
+KRB5CONF!$KRB5CONF$ac_delim
+PRIVSEP_PATH!$PRIVSEP_PATH$ac_delim
+xauth_path!$xauth_path$ac_delim
+STRIP_OPT!$STRIP_OPT$ac_delim
+XAUTH_PATH!$XAUTH_PATH$ac_delim
+MANTYPE!$MANTYPE$ac_delim
+mansubdir!$mansubdir$ac_delim
+user_path!$user_path$ac_delim
+piddir!$piddir$ac_delim
+TEST_SSH_IPV6!$TEST_SSH_IPV6$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 21; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[    ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$ac_file_inputs $ac_f"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input="Generated from "`IFS=:
+         echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([  #]*\\)[^        ]*\\([  ]*'
+ac_dB='\\)[     (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+       t rset
+       :rset
+       s/^[     ]*#[    ]*define[       ][      ]*//
+       t ok
+       d
+       :ok
+       s/[\\&,]/\\&/g
+       s/^\('"$ac_word_re"'\)\(([^()]*)\)[      ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+       s/^\('"$ac_word_re"'\)[  ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[    #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:         sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:        sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:    sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[     ]*#[    ]*undef[        ][      ]*$ac_word_re[  ]*\$/b def
+/^[     ]*#[    ]*define[       ][      ]*$ac_word_re[(         ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
+
+# Print summary of options
+
+# 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 ${PRIVSEP_PATH}` ; H=`eval echo ${H}`
+I=`eval echo ${user_path}` ; I=`eval echo ${I}`
+J=`eval echo ${superuser_path}` ; J=`eval echo ${J}`
+
+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 "  Privilege separation chroot path: $H"
+if test "x$external_path_file" = "x/etc/login.conf" ; then
+echo "   At runtime, sshd will use the path defined in $external_path_file"
+echo "   Make sure the path to scp is present, otherwise scp will not work"
+else
+echo "            sshd default user PATH: $I"
+       if test ! -z "$external_path_file"; then
+echo "   (If PATH is set in $external_path_file it will be used instead. If"
+echo "   used, ensure the path to scp is present, otherwise scp will not work.)"
+       fi
+fi
+if test ! -z "$superuser_path" ; then
+echo "          sshd superuser user PATH: $J"
+fi
+echo "                    Manpage format: $MANTYPE"
+echo "                       PAM support: $PAM_MSG"
+echo "                   OSF SIA support: $SIA_MSG"
+echo "                 KerberosV support: $KRB5_MSG"
+echo "                   SELinux support: $SELINUX_MSG"
+echo "                 Smartcard support: $SCARD_MSG"
+echo "                     S/KEY support: $SKEY_MSG"
+echo "              TCP Wrappers support: $TCPW_MSG"
+echo "              MD5 password support: $MD5_MSG"
+echo "                   libedit support: $LIBEDIT_MSG"
+echo "  Solaris process contract support: $SPC_MSG"
+echo "           Solaris project support: $SP_MSG"
+echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
+echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+echo "                  BSD Auth support: $BSD_AUTH_MSG"
+echo "              Random number source: $RAND_MSG"
+if test ! -z "$USE_RAND_HELPER" ; then
+echo "     ssh-rand-helper collects from: $RAND_HELPER_MSG"
+fi
+
+echo ""
+
+echo "              Host: ${host}"
+echo "          Compiler: ${CC}"
+echo "    Compiler flags: ${CFLAGS}"
+echo "Preprocessor flags: ${CPPFLAGS}"
+echo "      Linker flags: ${LDFLAGS}"
+echo "         Libraries: ${LIBS}"
+if test ! -z "${SSHDLIBS}"; then
+echo "         +for sshd: ${SSHDLIBS}"
+fi
+if test ! -z "${SSHLIBS}"; then
+echo "          +for ssh: ${SSHLIBS}"
+fi
+
+echo ""
+
+if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then
+       echo "SVR4 style packages are supported with \"make package\""
+       echo ""
+fi
+
+if test "x$PAM_MSG" = "xyes" ; then
+       echo "PAM is enabled. You may need to install a PAM control file "
+       echo "for sshd, otherwise password authentication may fail. "
+       echo "Example PAM control files can be found in the contrib/ "
+       echo "subdirectory"
+       echo ""
+fi
+
+if test ! -z "$RAND_HELPER_CMDHASH" ; then
+       echo "WARNING: you are using the builtin random number collection "
+       echo "service. Please read WARNING.RNG and request that your OS "
+       echo "vendor includes kernel-based random number collection in "
+       echo "future versions of your OS."
+       echo ""
+fi
+
+if test ! -z "$NO_PEERCHECK" ; then
+       echo "WARNING: the operating system that you are using does not"
+       echo "appear to support getpeereid(), getpeerucred() or the"
+       echo "SO_PEERCRED getsockopt() option. These facilities are used to"
+       echo "enforce security checks to prevent unauthorised connections to"
+       echo "ssh-agent. Their absence increases the risk that a malicious"
+       echo "user can connect to your agent."
+       echo ""
+fi
+
+if test "$AUDIT_MODULE" = "bsm" ; then
+       echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
+       echo "See the Solaris section in README.platform for details."
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..f23784d
--- /dev/null
@@ -0,0 +1,4385 @@
+# $Id: configure.ac,v 1.469.4.1 2011/02/04 00:42:14 djm Exp $
+#
+# Copyright (c) 1999-2004 Damien Miller
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org)
+AC_REVISION($Revision: 1.469.4.1 $)
+AC_CONFIG_SRCDIR([ssh.c])
+
+# local macros
+AC_DEFUN([OPENSSH_CHECK_CFLAG_COMPILE], [{
+       AC_MSG_CHECKING([if $CC supports $1])
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS $1"
+       AC_COMPILE_IFELSE([void main(void) { return 0; }],
+               [ AC_MSG_RESULT(yes) ],
+               [ AC_MSG_RESULT(no)
+                 CFLAGS="$saved_CFLAGS" ]
+       )
+}])
+
+AC_CONFIG_HEADER(config.h)
+AC_PROG_CC
+AC_CANONICAL_HOST
+AC_C_BIGENDIAN
+
+# Checks for programs.
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PROG_EGREP
+AC_PATH_PROG(AR, ar)
+AC_PATH_PROG(CAT, cat)
+AC_PATH_PROG(KILL, kill)
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_PATH_PROG(SED, sed)
+AC_SUBST(PERL)
+AC_PATH_PROG(ENT, ent)
+AC_SUBST(ENT)
+AC_PATH_PROG(TEST_MINUS_S_SH, bash)
+AC_PATH_PROG(TEST_MINUS_S_SH, ksh)
+AC_PATH_PROG(TEST_MINUS_S_SH, sh)
+AC_PATH_PROG(SH, sh)
+AC_PATH_PROG(GROFF, groff)
+AC_PATH_PROG(NROFF, nroff)
+AC_PATH_PROG(MANDOC, mandoc)
+AC_SUBST(TEST_SHELL,sh)
+
+dnl select manpage formatter
+if test "x$MANDOC" != "x" ; then
+       MANFMT="$MANDOC"
+elif test "x$NROFF" != "x" ; then
+       MANFMT="$NROFF -mandoc"
+elif test "x$GROFF" != "x" ; then
+       MANFMT="$GROFF -mandoc -Tascii"
+else
+       AC_MSG_WARN([no manpage formatted found])
+       MANFMT="false"
+fi
+AC_SUBST(MANFMT)
+
+dnl for buildpkg.sh
+AC_PATH_PROG(PATH_GROUPADD_PROG, groupadd, groupadd,
+       [/usr/sbin${PATH_SEPARATOR}/etc])
+AC_PATH_PROG(PATH_USERADD_PROG, useradd, useradd,
+       [/usr/sbin${PATH_SEPARATOR}/etc])
+AC_CHECK_PROG(MAKE_PACKAGE_SUPPORTED, pkgmk, yes, no)
+if test -x /sbin/sh; then
+       AC_SUBST(STARTUP_SCRIPT_SHELL,/sbin/sh)
+else
+       AC_SUBST(STARTUP_SCRIPT_SHELL,/bin/sh)
+fi
+
+# 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",
+               [If your header files don't define LOGIN_PROGRAM,
+               then use this (detected) from environment and PATH])
+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
+
+AC_PATH_PROG(PATH_PASSWD_PROG, passwd)
+if test ! -z "$PATH_PASSWD_PROG" ; then
+       AC_DEFINE_UNQUOTED(_PATH_PASSWD_PROG, "$PATH_PASSWD_PROG",
+               [Full path of your "passwd" program])
+fi
+
+if test -z "$LD" ; then
+       LD=$CC
+fi
+AC_SUBST(LD)
+
+AC_C_INLINE
+
+AC_CHECK_DECL(LLONG_MAX, have_llong_max=1, , [#include <limits.h>])
+
+use_stack_protector=1
+AC_ARG_WITH(stackprotect,
+    [  --without-stackprotect  Don't use compiler's stack protection], [
+    if test "x$withval" = "xno"; then
+       use_stack_protector=0
+    fi ])
+
+
+if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wall])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wpointer-arith])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wuninitialized])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wsign-compare])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wformat-security])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wno-pointer-sign])
+       OPENSSH_CHECK_CFLAG_COMPILE([-Wno-unused-result])
+       OPENSSH_CHECK_CFLAG_COMPILE([-fno-strict-aliasing])
+       AC_MSG_CHECKING(gcc version)
+       GCC_VER=`$CC -v 2>&1 | $AWK '/gcc version /{print $3}'`
+       case $GCC_VER in
+               1.*) no_attrib_nonnull=1 ;;
+               2.8* | 2.9*)
+                    no_attrib_nonnull=1
+                    ;;
+               2.*) no_attrib_nonnull=1 ;;
+               *) ;;
+       esac
+       AC_MSG_RESULT($GCC_VER)
+
+       AC_MSG_CHECKING(if $CC accepts -fno-builtin-memset)
+       saved_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS -fno-builtin-memset"
+       AC_LINK_IFELSE( [AC_LANG_SOURCE([[
+#include <string.h>
+int main(void){char b[10]; memset(b, 0, sizeof(b));}
+               ]])],
+               [ AC_MSG_RESULT(yes) ],
+               [ AC_MSG_RESULT(no)
+                 CFLAGS="$saved_CFLAGS" ]
+)
+
+       # -fstack-protector-all doesn't always work for some GCC versions
+       # and/or platforms, so we test if we can.  If it's not supported
+       # on a given platform gcc will emit a warning so we use -Werror.
+       if test "x$use_stack_protector" = "x1"; then
+           for t in -fstack-protector-all -fstack-protector; do
+               AC_MSG_CHECKING(if $CC supports $t)
+               saved_CFLAGS="$CFLAGS"
+               saved_LDFLAGS="$LDFLAGS"
+               CFLAGS="$CFLAGS $t -Werror"
+               LDFLAGS="$LDFLAGS $t -Werror"
+               AC_LINK_IFELSE(
+                       [AC_LANG_SOURCE([
+#include <stdio.h>
+int main(void){char x[[256]]; snprintf(x, sizeof(x), "XXX"); return 0;}
+                        ])],
+                   [ AC_MSG_RESULT(yes)
+                     CFLAGS="$saved_CFLAGS $t"
+                     LDFLAGS="$saved_LDFLAGS $t"
+                     AC_MSG_CHECKING(if $t works)
+                     AC_RUN_IFELSE(
+                       [AC_LANG_SOURCE([
+#include <stdio.h>
+int main(void){char x[[256]]; snprintf(x, sizeof(x), "XXX"); return 0;}
+                       ])],
+                       [ AC_MSG_RESULT(yes)
+                         break ],
+                       [ AC_MSG_RESULT(no) ],
+                       [ AC_MSG_WARN([cross compiling: cannot test])
+                         break ]
+                     )
+                   ],
+                   [ AC_MSG_RESULT(no) ]
+               )
+               CFLAGS="$saved_CFLAGS"
+               LDFLAGS="$saved_LDFLAGS"
+           done
+       fi
+
+       if test -z "$have_llong_max"; then
+               # retry LLONG_MAX with -std=gnu99, needed on some Linuxes
+               unset ac_cv_have_decl_LLONG_MAX
+               saved_CFLAGS="$CFLAGS"
+               CFLAGS="$CFLAGS -std=gnu99"
+               AC_CHECK_DECL(LLONG_MAX,
+                   [have_llong_max=1],
+                   [CFLAGS="$saved_CFLAGS"],
+                   [#include <limits.h>]
+               )
+       fi
+fi
+
+if test "x$no_attrib_nonnull" != "x1" ; then
+       AC_DEFINE(HAVE_ATTRIBUTE__NONNULL__, 1, [Have attribute nonnull])
+fi
+
+AC_ARG_WITH(rpath,
+       [  --without-rpath         Disable auto-added -R linker paths],
+       [
+               if test "x$withval" = "xno" ; then
+                       need_dash_r=""
+               fi
+               if test "x$withval" = "xyes" ; then
+                       need_dash_r=1
+               fi
+       ]
+)
+
+# Allow user to specify flags
+AC_ARG_WITH(cflags,
+       [  --with-cflags           Specify additional flags to pass to compiler],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       CFLAGS="$CFLAGS $withval"
+               fi
+       ]
+)
+AC_ARG_WITH(cppflags,
+       [  --with-cppflags         Specify additional flags to pass to preprocessor] ,
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       CPPFLAGS="$CPPFLAGS $withval"
+               fi
+       ]
+)
+AC_ARG_WITH(ldflags,
+       [  --with-ldflags          Specify additional flags to pass to linker],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       LDFLAGS="$LDFLAGS $withval"
+               fi
+       ]
+)
+AC_ARG_WITH(libs,
+       [  --with-libs             Specify additional libraries to link with],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       LIBS="$LIBS $withval"
+               fi
+       ]
+)
+AC_ARG_WITH(Werror,
+       [  --with-Werror           Build main code with -Werror],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"; then
+                       werror_flags="-Werror"
+                       if test "x${withval}" != "xyes"; then
+                               werror_flags="$withval"
+                       fi
+               fi
+       ]
+)
+
+AC_CHECK_HEADERS( \
+       bstring.h \
+       crypt.h \
+       crypto/sha2.h \
+       dirent.h \
+       endian.h \
+       features.h \
+       fcntl.h \
+       floatingpoint.h \
+       getopt.h \
+       glob.h \
+       ia.h \
+       iaf.h \
+       limits.h \
+       login.h \
+       maillock.h \
+       ndir.h \
+       net/if_tun.h \
+       netdb.h \
+       netgroup.h \
+       pam/pam_appl.h \
+       paths.h \
+       poll.h \
+       pty.h \
+       readpassphrase.h \
+       rpc/types.h \
+       security/pam_appl.h \
+       sha2.h \
+       shadow.h \
+       stddef.h \
+       stdint.h \
+       string.h \
+       strings.h \
+       sys/audit.h \
+       sys/bitypes.h \
+       sys/bsdtty.h \
+       sys/cdefs.h \
+       sys/dir.h \
+       sys/mman.h \
+       sys/ndir.h \
+       sys/poll.h \
+       sys/prctl.h \
+       sys/pstat.h \
+       sys/select.h \
+       sys/stat.h \
+       sys/stream.h \
+       sys/stropts.h \
+       sys/strtio.h \
+       sys/statvfs.h \
+       sys/sysmacros.h \
+       sys/time.h \
+       sys/timers.h \
+       sys/un.h \
+       time.h \
+       tmpdir.h \
+       ttyent.h \
+       ucred.h \
+       unistd.h \
+       usersec.h \
+       util.h \
+       utime.h \
+       utmp.h \
+       utmpx.h \
+       vis.h \
+)
+
+# lastlog.h requires sys/time.h to be included first on Solaris
+AC_CHECK_HEADERS(lastlog.h, [], [], [
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+])
+
+# sys/ptms.h requires sys/stream.h to be included first on Solaris
+AC_CHECK_HEADERS(sys/ptms.h, [], [], [
+#ifdef HAVE_SYS_STREAM_H
+# include <sys/stream.h>
+#endif
+])
+
+# login_cap.h requires sys/types.h on NetBSD
+AC_CHECK_HEADERS(login_cap.h, [], [], [
+#include <sys/types.h>
+])
+
+# older BSDs need sys/param.h before sys/mount.h
+AC_CHECK_HEADERS(sys/mount.h, [], [], [
+#include <sys/param.h>
+])
+
+# Messages for features tested for in target-specific section
+SIA_MSG="no"
+SPC_MSG="no"
+SP_MSG="no"
+
+# Check for some target-specific stuff
+case "$host" in
+*-*-aix*)
+       # Some versions of VAC won't allow macro redefinitions at
+       # -qlanglevel=ansi, and autoconf 2.60 sometimes insists on using that
+       # particularly with older versions of vac or xlc.
+       # It also throws errors about null macro argments, but these are
+       # not fatal.
+       AC_MSG_CHECKING(if compiler allows macro redefinitions)
+       AC_COMPILE_IFELSE(
+           [AC_LANG_SOURCE([[
+#define testmacro foo
+#define testmacro bar
+int main(void) { exit(0); }
+           ]])],
+           [ AC_MSG_RESULT(yes) ],
+           [ AC_MSG_RESULT(no)
+             CC="`echo $CC | sed 's/-qlanglvl\=ansi//g'`"
+             LD="`echo $LD | sed 's/-qlanglvl\=ansi//g'`"
+             CFLAGS="`echo $CFLAGS | sed 's/-qlanglvl\=ansi//g'`"
+             CPPFLAGS="`echo $CPPFLAGS | sed 's/-qlanglvl\=ansi//g'`"
+           ]
+       )
+
+       AC_MSG_CHECKING([how to specify blibpath for linker ($LD)])
+       if (test -z "$blibpath"); then
+               blibpath="/usr/lib:/lib"
+       fi
+       saved_LDFLAGS="$LDFLAGS"
+       if test "$GCC" = "yes"; then
+               flags="-Wl,-blibpath: -Wl,-rpath, -blibpath:"
+       else
+               flags="-blibpath: -Wl,-blibpath: -Wl,-rpath,"
+       fi
+       for tryflags in $flags ;do
+               if (test -z "$blibflags"); then
+                       LDFLAGS="$saved_LDFLAGS $tryflags$blibpath"
+                       AC_TRY_LINK([], [], [blibflags=$tryflags])
+               fi
+       done
+       if (test -z "$blibflags"); then
+               AC_MSG_RESULT(not found)
+               AC_MSG_ERROR([*** must be able to specify blibpath on AIX - check config.log])
+       else
+               AC_MSG_RESULT($blibflags)
+       fi
+       LDFLAGS="$saved_LDFLAGS"
+       dnl Check for authenticate.  Might be in libs.a on older AIXes
+       AC_CHECK_FUNC(authenticate, [AC_DEFINE(WITH_AIXAUTHENTICATE, 1,
+               [Define if you want to enable AIX4's authenticate function])],
+               [AC_CHECK_LIB(s,authenticate,
+                       [ AC_DEFINE(WITH_AIXAUTHENTICATE)
+                               LIBS="$LIBS -ls"
+                       ])
+               ])
+       dnl Check for various auth function declarations in headers.
+       AC_CHECK_DECLS([authenticate, loginrestrictions, loginsuccess,
+           passwdexpired, setauthdb], , , [#include <usersec.h>])
+       dnl Check if loginfailed is declared and takes 4 arguments (AIX >= 5.2)
+       AC_CHECK_DECLS(loginfailed,
+                [AC_MSG_CHECKING(if loginfailed takes 4 arguments)
+                 AC_TRY_COMPILE(
+                       [#include <usersec.h>],
+                       [(void)loginfailed("user","host","tty",0);],
+                       [AC_MSG_RESULT(yes)
+                        AC_DEFINE(AIX_LOGINFAILED_4ARG, 1,
+                               [Define if your AIX loginfailed() function
+                               takes 4 arguments (AIX >= 5.2)])],
+                       [AC_MSG_RESULT(no)]
+               )],
+               [],
+               [#include <usersec.h>]
+       )
+       AC_CHECK_FUNCS(getgrset setauthdb)
+       AC_CHECK_DECL(F_CLOSEM,
+           AC_DEFINE(HAVE_FCNTL_CLOSEM, 1, [Use F_CLOSEM fcntl for closefrom]),
+           [],
+           [ #include <limits.h>
+             #include <fcntl.h> ]
+       )
+       check_for_aix_broken_getaddrinfo=1
+       AC_DEFINE(BROKEN_REALPATH, 1, [Define if you have a broken realpath.])
+       AC_DEFINE(SETEUID_BREAKS_SETUID, 1,
+           [Define if your platform breaks doing a seteuid before a setuid])
+       AC_DEFINE(BROKEN_SETREUID, 1, [Define if your setreuid() is broken])
+       AC_DEFINE(BROKEN_SETREGID, 1, [Define if your setregid() is broken])
+       dnl AIX handles lastlog as part of its login message
+       AC_DEFINE(DISABLE_LASTLOG, 1, [Define if you don't want to use lastlog])
+       AC_DEFINE(LOGIN_NEEDS_UTMPX, 1,
+               [Some systems need a utmpx entry for /bin/login to work])
+       AC_DEFINE(SPT_TYPE,SPT_REUSEARGV,
+               [Define to a Set Process Title type if your system is
+               supported by bsd-setproctitle.c])
+       AC_DEFINE(SSHPAM_CHAUTHTOK_NEEDS_RUID, 1,
+           [AIX 5.2 and 5.3 (and presumably newer) require this])
+       AC_DEFINE(PTY_ZEROREAD, 1, [read(1) can return 0 for a non-closed fd])
+       ;;
+*-*-cygwin*)
+       check_for_libcrypt_later=1
+       LIBS="$LIBS /usr/lib/textreadmode.o"
+       AC_DEFINE(HAVE_CYGWIN, 1, [Define if you are on Cygwin])
+       AC_DEFINE(USE_PIPES, 1, [Use PIPES instead of a socketpair()])
+       AC_DEFINE(DISABLE_SHADOW, 1,
+               [Define if you want to disable shadow passwords])
+       AC_DEFINE(NO_X11_UNIX_SOCKETS, 1,
+               [Define if X11 doesn't support AF_UNIX sockets on that system])
+       AC_DEFINE(NO_IPPORT_RESERVED_CONCEPT, 1,
+               [Define if the concept of ports only accessible to
+               superusers isn't known])
+       AC_DEFINE(DISABLE_FD_PASSING, 1,
+               [Define if your platform needs to skip post auth
+               file descriptor passing])
+       AC_DEFINE(SSH_IOBUFSZ, 65535, [Windows is sensitive to read buffer size])
+       AC_DEFINE(FILESYSTEM_NO_BACKSLASH, 1, [File names may not contain backslash characters]) 
+       ;;
+*-*-dgux*)
+       AC_DEFINE(IP_TOS_IS_BROKEN, 1,
+               [Define if your system choked on IP TOS setting])
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       ;;
+*-*-darwin*)
+       AC_MSG_CHECKING(if we have working getaddrinfo)
+       AC_TRY_RUN([#include <mach-o/dyld.h>
+main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
+               exit(0);
+       else
+               exit(1);
+}], [AC_MSG_RESULT(working)],
+       [AC_MSG_RESULT(buggy)
+       AC_DEFINE(BROKEN_GETADDRINFO, 1, [getaddrinfo is broken (if present)])],
+       [AC_MSG_RESULT(assume it is working)])
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(BROKEN_GLOB, 1, [OS X glob does not do what we expect])
+       AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1,
+               [Define if your resolver libs need this for getrrsetbyname])
+       AC_DEFINE(SSH_TUN_FREEBSD, 1, [Open tunnel devices the FreeBSD way])
+       AC_DEFINE(SSH_TUN_COMPAT_AF, 1,
+           [Use tunnel device compatibility to OpenBSD])
+       AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
+           [Prepend the address family to IP tunnel traffic])
+       m4_pattern_allow(AU_IPv)
+       AC_CHECK_DECL(AU_IPv4, [], 
+           AC_DEFINE(AU_IPv4, 0, [System only supports IPv4 audit records])
+           [#include <bsm/audit.h>]
+       AC_DEFINE(LASTLOG_WRITE_PUTUTXLINE, 1,
+           [Define if pututxline updates lastlog too])
+       )
+       ;;
+*-*-dragonfly*)
+       SSHDLIBS="$SSHDLIBS -lcrypt"
+       ;;
+*-*-haiku*) 
+    LIBS="$LIBS -lbsd "
+    AC_CHECK_LIB(network, socket)
+    AC_DEFINE(HAVE_U_INT64_T)
+    MANTYPE=man 
+    ;; 
+*-*-hpux*)
+       # first we define all of the options common to all HP-UX releases
+       CPPFLAGS="$CPPFLAGS -D_HPUX_SOURCE -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1"
+       IPADDR_IN_DISPLAY=yes
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(LOGIN_NO_ENDOPT, 1,
+           [Define if your login program cannot handle end of options ("--")])
+       AC_DEFINE(LOGIN_NEEDS_UTMPX)
+       AC_DEFINE(LOCKED_PASSWD_STRING, "*",
+               [String used in /etc/passwd to denote locked account])
+       AC_DEFINE(SPT_TYPE,SPT_PSTAT)
+       MAIL="/var/mail/username"
+       LIBS="$LIBS -lsec"
+       AC_CHECK_LIB(xnet, t_error, ,
+           AC_MSG_ERROR([*** -lxnet needed on HP-UX - check config.log ***]))
+
+       # next, we define all of the options specific to major releases
+       case "$host" in
+       *-*-hpux10*)
+               if test -z "$GCC"; then
+                       CFLAGS="$CFLAGS -Ae"
+               fi
+               ;;
+       *-*-hpux11*)
+               AC_DEFINE(PAM_SUN_CODEBASE, 1,
+                       [Define if you are using Solaris-derived PAM which
+                       passes pam_messages to the conversation function
+                       with an extra level of indirection])
+               AC_DEFINE(DISABLE_UTMP, 1,
+                       [Define if you don't want to use utmp])
+               AC_DEFINE(USE_BTMP, 1, [Use btmp to log bad logins])
+               check_for_hpux_broken_getaddrinfo=1
+               check_for_conflicting_getspnam=1
+               ;;
+       esac
+
+       # lastly, we define options specific to minor releases
+       case "$host" in
+       *-*-hpux10.26)
+               AC_DEFINE(HAVE_SECUREWARE, 1,
+                       [Define if you have SecureWare-based
+                       protected password database])
+               disable_ptmx_check=yes
+               LIBS="$LIBS -lsecpw"
+               ;;
+       esac
+       ;;
+*-*-irix5*)
+       PATH="$PATH:/usr/etc"
+       AC_DEFINE(BROKEN_INET_NTOA, 1,
+               [Define if you system's inet_ntoa is busted
+               (e.g. Irix gcc issue)])
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(WITH_ABBREV_NO_TTY, 1,
+               [Define if you shouldn't strip 'tty' from your
+               ttyname in [uw]tmp])
+       AC_DEFINE(LOCKED_PASSWD_STRING, "*LK*")
+       ;;
+*-*-irix6*)
+       PATH="$PATH:/usr/etc"
+       AC_DEFINE(WITH_IRIX_ARRAY, 1,
+               [Define if you have/want arrays
+               (cluster-wide session managment, not C arrays)])
+       AC_DEFINE(WITH_IRIX_PROJECT, 1,
+               [Define if you want IRIX project management])
+       AC_DEFINE(WITH_IRIX_AUDIT, 1,
+               [Define if you want IRIX audit trails])
+       AC_CHECK_FUNC(jlimit_startjob, [AC_DEFINE(WITH_IRIX_JOBS, 1,
+               [Define if you want IRIX kernel jobs])])
+       AC_DEFINE(BROKEN_INET_NTOA)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(BROKEN_UPDWTMPX, 1, [updwtmpx is broken (if present)])
+       AC_DEFINE(WITH_ABBREV_NO_TTY)
+       AC_DEFINE(LOCKED_PASSWD_STRING, "*LK*")
+       ;;
+*-*-k*bsd*-gnu | *-*-kopensolaris*-gnu)
+       check_for_libcrypt_later=1
+       AC_DEFINE(PAM_TTY_KLUDGE)
+       AC_DEFINE(LOCKED_PASSWD_PREFIX, "!")
+       AC_DEFINE(SPT_TYPE,SPT_REUSEARGV)
+       AC_DEFINE(_PATH_BTMP, "/var/log/btmp", [log for bad login attempts])
+       AC_DEFINE(USE_BTMP, 1, [Use btmp to log bad logins])
+       ;;
+*-*-linux*)
+       no_dev_ptmx=1
+       check_for_libcrypt_later=1
+       check_for_openpty_ctty_bug=1
+       AC_DEFINE(PAM_TTY_KLUDGE, 1,
+               [Work around problematic Linux PAM modules handling of PAM_TTY])
+       AC_DEFINE(LOCKED_PASSWD_PREFIX, "!",
+               [String used in /etc/passwd to denote locked account])
+       AC_DEFINE(SPT_TYPE,SPT_REUSEARGV)
+       AC_DEFINE(LINK_OPNOTSUPP_ERRNO, EPERM,
+               [Define to whatever link() returns for "not supported"
+               if it doesn't return EOPNOTSUPP.])
+       AC_DEFINE(_PATH_BTMP, "/var/log/btmp", [log for bad login attempts])
+       AC_DEFINE(USE_BTMP)
+       AC_DEFINE(LINUX_OOM_ADJUST, 1, [Adjust Linux out-of-memory killer])
+       inet6_default_4in6=yes
+       case `uname -r` in
+       1.*|2.0.*)
+               AC_DEFINE(BROKEN_CMSG_TYPE, 1,
+                       [Define if cmsg_type is not passed correctly])
+               ;;
+       esac
+       # tun(4) forwarding compat code
+       AC_CHECK_HEADERS(linux/if_tun.h)
+       if test "x$ac_cv_header_linux_if_tun_h" = "xyes" ; then
+               AC_DEFINE(SSH_TUN_LINUX, 1,
+                   [Open tunnel devices the Linux tun/tap way])
+               AC_DEFINE(SSH_TUN_COMPAT_AF, 1,
+                   [Use tunnel device compatibility to OpenBSD])
+               AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
+                   [Prepend the address family to IP tunnel traffic])
+       fi
+       ;;
+mips-sony-bsd|mips-sony-newsos4)
+       AC_DEFINE(NEED_SETPGRP, 1, [Need setpgrp to acquire controlling tty])
+       SONY=1
+       ;;
+*-*-netbsd*)
+       check_for_libcrypt_before=1
+       if test "x$withval" != "xno" ; then
+               need_dash_r=1
+       fi
+       AC_DEFINE(SSH_TUN_FREEBSD, 1, [Open tunnel devices the FreeBSD way])
+       AC_CHECK_HEADER([net/if_tap.h], ,
+           AC_DEFINE(SSH_TUN_NO_L2, 1, [No layer 2 tunnel support]))
+       AC_DEFINE(SSH_TUN_PREPEND_AF, 1,
+           [Prepend the address family to IP tunnel traffic])
+       ;;
+*-*-freebsd*)
+       check_for_libcrypt_later=1
+       AC_DEFINE(LOCKED_PASSWD_PREFIX, "*LOCKED*", [Account locked with pw(1)])
+       AC_DEFINE(SSH_TUN_FREEBSD, 1, [Open tunnel devices the FreeBSD way])
+       AC_CHECK_HEADER([net/if_tap.h], ,
+           AC_DEFINE(SSH_TUN_NO_L2, 1, [No layer 2 tunnel support]))
+       AC_DEFINE(BROKEN_GLOB, 1, [FreeBSD glob does not do what we need])
+       ;;
+*-*-bsdi*)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       ;;
+*-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, 1, [Define if you are on NeXT])
+       AC_DEFINE(BROKEN_REALPATH)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(BROKEN_SAVED_UIDS, 1, [Needed for NeXT])
+       ;;
+*-*-openbsd*)
+       AC_DEFINE(HAVE_ATTRIBUTE__SENTINEL__, 1, [OpenBSD's gcc has sentinel])
+       AC_DEFINE(HAVE_ATTRIBUTE__BOUNDED__, 1, [OpenBSD's gcc has bounded])
+       AC_DEFINE(SSH_TUN_OPENBSD, 1, [Open tunnel devices the OpenBSD way])
+       AC_DEFINE(SYSLOG_R_SAFE_IN_SIGHAND, 1,
+           [syslog_r function is safe to use in in a signal handler])
+       ;;
+*-*-solaris*)
+       if test "x$withval" != "xno" ; then
+               need_dash_r=1
+       fi
+       AC_DEFINE(PAM_SUN_CODEBASE)
+       AC_DEFINE(LOGIN_NEEDS_UTMPX)
+       AC_DEFINE(LOGIN_NEEDS_TERM, 1,
+               [Some versions of /bin/login need the TERM supplied
+               on the commandline])
+       AC_DEFINE(PAM_TTY_KLUDGE)
+       AC_DEFINE(SSHPAM_CHAUTHTOK_NEEDS_RUID, 1,
+               [Define if pam_chauthtok wants real uid set
+               to the unpriv'ed user])
+       AC_DEFINE(LOCKED_PASSWD_STRING, "*LK*")
+       # Pushing STREAMS modules will cause sshd to acquire a controlling tty.
+       AC_DEFINE(SSHD_ACQUIRES_CTTY, 1,
+               [Define if sshd somehow reacquires a controlling TTY
+               after setsid()])
+       AC_DEFINE(PASSWD_NEEDS_USERNAME, 1, [must supply username to passwd
+               in case the name is longer than 8 chars])
+       AC_DEFINE(BROKEN_TCGETATTR_ICANON, 1, [tcgetattr with ICANON may hang])
+       external_path_file=/etc/default/login
+       # 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, 1,
+                       [Define if you don't want to use wtmp])
+       else
+               AC_MSG_RESULT(no)
+       fi
+       AC_ARG_WITH(solaris-contracts,
+               [  --with-solaris-contracts Enable Solaris process contracts (experimental)],
+               [
+               AC_CHECK_LIB(contract, ct_tmpl_activate,
+                       [ AC_DEFINE(USE_SOLARIS_PROCESS_CONTRACTS, 1,
+                               [Define if you have Solaris process contracts])
+                         SSHDLIBS="$SSHDLIBS -lcontract"
+                         SPC_MSG="yes" ], )
+               ],
+       )
+       AC_ARG_WITH(solaris-projects,
+               [  --with-solaris-projects Enable Solaris projects (experimental)],
+               [
+               AC_CHECK_LIB(project, setproject,
+                       [ AC_DEFINE(USE_SOLARIS_PROJECTS, 1,
+                               [Define if you have Solaris projects])
+                       SSHDLIBS="$SSHDLIBS -lproject"
+                       SP_MSG="yes" ], )
+               ],
+       )
+       ;;
+*-*-sunos4*)
+       CPPFLAGS="$CPPFLAGS -DSUNOS4"
+       AC_CHECK_FUNCS(getpwanam)
+       AC_DEFINE(PAM_SUN_CODEBASE)
+       conf_utmp_location=/etc/utmp
+       conf_wtmp_location=/var/adm/wtmp
+       conf_lastlog_location=/var/adm/lastlog
+       AC_DEFINE(USE_PIPES)
+       ;;
+*-ncr-sysv*)
+       LIBS="$LIBS -lc89"
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(SSHD_ACQUIRES_CTTY)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       ;;
+*-sni-sysv*)
+       # /usr/ucblib MUST NOT be searched on ReliantUNIX
+       AC_CHECK_LIB(dl, dlsym, ,)
+       # -lresolv needs to be at the end of LIBS or DNS lookups break
+       AC_CHECK_LIB(resolv, res_query, [ LIBS="$LIBS -lresolv" ])
+       IPADDR_IN_DISPLAY=yes
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(IP_TOS_IS_BROKEN)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(SSHD_ACQUIRES_CTTY)
+       external_path_file=/etc/default/login
+       # /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
+       ;;
+# UnixWare 1.x, UnixWare 2.x, and others based on code from Univel.
+*-*-sysv4.2*)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(PASSWD_NEEDS_USERNAME, 1, [must supply username to passwd])
+       AC_DEFINE(LOCKED_PASSWD_STRING, "*LK*")
+       ;;
+# UnixWare 7.x, OpenUNIX 8
+*-*-sysv5*)
+       CPPFLAGS="$CPPFLAGS -Dvsnprintf=_xvsnprintf -Dsnprintf=_xsnprintf"
+       AC_DEFINE(UNIXWARE_LONG_PASSWORDS, 1, [Support passwords > 8 chars])
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_GETADDRINFO)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(PASSWD_NEEDS_USERNAME)
+       case "$host" in
+       *-*-sysv5SCO_SV*)       # SCO OpenServer 6.x
+               TEST_SHELL=/u95/bin/sh
+               AC_DEFINE(BROKEN_LIBIAF, 1,
+                       [ia_uinfo routines not supported by OS yet])
+               AC_DEFINE(BROKEN_UPDWTMPX)
+               AC_CHECK_LIB(prot, getluid,[ LIBS="$LIBS -lprot"
+                       AC_CHECK_FUNCS(getluid setluid,,,-lprot)
+                       AC_DEFINE(HAVE_SECUREWARE)
+                       AC_DEFINE(DISABLE_SHADOW)
+                       ],,)
+               ;;
+       *)      AC_DEFINE(LOCKED_PASSWD_STRING, "*LK*")
+               check_for_libcrypt_later=1
+               ;;
+       esac
+       ;;
+*-*-sysv*)
+       ;;
+# SCO UNIX and OEM versions of SCO UNIX
+*-*-sco3.2v4*)
+       AC_MSG_ERROR("This Platform is no longer supported.")
+       ;;
+# SCO OpenServer 5.x
+*-*-sco3.2v5*)
+       if test -z "$GCC"; then
+               CFLAGS="$CFLAGS -belf"
+       fi
+       LIBS="$LIBS -lprot -lx -ltinfo -lm"
+       no_dev_ptmx=1
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(HAVE_SECUREWARE)
+       AC_DEFINE(DISABLE_SHADOW)
+       AC_DEFINE(DISABLE_FD_PASSING)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_GETADDRINFO)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(WITH_ABBREV_NO_TTY)
+       AC_DEFINE(BROKEN_UPDWTMPX)
+       AC_DEFINE(PASSWD_NEEDS_USERNAME)
+       AC_CHECK_FUNCS(getluid setluid)
+       MANTYPE=man
+       TEST_SHELL=ksh
+       ;;
+*-*-unicosmk*)
+       AC_DEFINE(NO_SSH_LASTLOG, 1,
+               [Define if you don't want to use lastlog in session.c])
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_FD_PASSING)
+       LDFLAGS="$LDFLAGS"
+       LIBS="$LIBS -lgen -lrsc -lshare -luex -lacm"
+       MANTYPE=cat
+       ;;
+*-*-unicosmp*)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(WITH_ABBREV_NO_TTY)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_FD_PASSING)
+       LDFLAGS="$LDFLAGS"
+       LIBS="$LIBS -lgen -lacid -ldb"
+       MANTYPE=cat
+       ;;
+*-*-unicos*)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(DISABLE_FD_PASSING)
+       AC_DEFINE(NO_SSH_LASTLOG)
+       LDFLAGS="$LDFLAGS -Wl,-Dmsglevel=334:fatal"
+       LIBS="$LIBS -lgen -lrsc -lshare -luex -lacm"
+       MANTYPE=cat
+       ;;
+*-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, 1,
+                               [Define if you have Digital Unix Security
+                               Integration Architecture])
+                       AC_DEFINE(DISABLE_LOGIN, 1,
+                               [Define if you don't want to use your
+                               system's login() call])
+                       AC_DEFINE(DISABLE_FD_PASSING)
+                       LIBS="$LIBS -lsecurity -ldb -lm -laud"
+                       SIA_MSG="yes"
+               else
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(LOCKED_PASSWD_SUBSTR, "Nologin",
+                         [String used in /etc/passwd to denote locked account])
+               fi
+       fi
+       AC_DEFINE(BROKEN_GETADDRINFO)
+       AC_DEFINE(SETEUID_BREAKS_SETUID)
+       AC_DEFINE(BROKEN_SETREUID)
+       AC_DEFINE(BROKEN_SETREGID)
+       AC_DEFINE(BROKEN_READV_COMPARISON, 1, [Can't do comparisons on readv])
+       ;;
+
+*-*-nto-qnx*)
+       AC_DEFINE(USE_PIPES)
+       AC_DEFINE(NO_X11_UNIX_SOCKETS)
+       AC_DEFINE(MISSING_NFDBITS, 1, [Define on *nto-qnx systems])
+       AC_DEFINE(MISSING_HOWMANY, 1, [Define on *nto-qnx systems])
+       AC_DEFINE(MISSING_FD_MASK, 1, [Define on *nto-qnx systems])
+       AC_DEFINE(DISABLE_LASTLOG)
+       AC_DEFINE(SSHD_ACQUIRES_CTTY)
+       AC_DEFINE(BROKEN_SHADOW_EXPIRE, 1, [QNX shadow support is broken])
+       enable_etc_default_login=no     # has incompatible /etc/default/login
+       case "$host" in
+       *-*-nto-qnx6*)
+               AC_DEFINE(DISABLE_FD_PASSING)
+               ;;
+       esac
+       ;;
+
+*-*-ultrix*)
+       AC_DEFINE(BROKEN_GETGROUPS, 1, [getgroups(0,NULL) will return -1])
+       AC_DEFINE(BROKEN_MMAP, 1, [Ultrix mmap can't map files])
+       AC_DEFINE(NEED_SETPGRP)
+       AC_DEFINE(HAVE_SYS_SYSLOG_H, 1, [Force use of sys/syslog.h on Ultrix])
+       ;;
+
+*-*-lynxos)
+        CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__"
+       AC_DEFINE(MISSING_HOWMANY)
+        AC_DEFINE(BROKEN_SETVBUF, 1, [LynxOS has broken setvbuf() implementation])
+        ;;
+esac
+
+AC_MSG_CHECKING(compiler and flags for sanity)
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([
+#include <stdio.h>
+int main(){exit(0);}
+       ])],
+       [       AC_MSG_RESULT(yes) ],
+       [
+               AC_MSG_RESULT(no)
+               AC_MSG_ERROR([*** compiler cannot create working executables, check config.log ***])
+       ],
+       [       AC_MSG_WARN([cross compiling: not checking compiler sanity]) ]
+)
+
+dnl Checks for header files.
+# Checks for libraries.
+AC_CHECK_FUNC(yp_match, , AC_CHECK_LIB(nsl, yp_match))
+AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
+
+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_RUN_IFELSE(
+                               [AC_LANG_SOURCE([[
+#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" ],
+                               [ ac_cv_have_broken_dirname="no" ],
+                       )
+                       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
+       ])
+])
+
+AC_CHECK_FUNC(getspnam, ,
+       AC_CHECK_LIB(gen, getspnam, LIBS="$LIBS -lgen"))
+AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME, 1,
+       [Define if you have the basename function.]))
+
+dnl zlib is required
+AC_ARG_WITH(zlib,
+       [  --with-zlib=PATH        Use zlib in PATH],
+       [ if test "x$withval" = "xno" ; then
+               AC_MSG_ERROR([*** zlib is required ***])
+         elif 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([zlib.h], ,AC_MSG_ERROR([*** zlib.h missing - please install first or check config.log ***]))
+AC_CHECK_LIB(z, deflate, ,
+       [
+               saved_CPPFLAGS="$CPPFLAGS"
+               saved_LDFLAGS="$LDFLAGS"
+               save_LIBS="$LIBS"
+               dnl Check default zlib install dir
+               if test -n "${need_dash_r}"; then
+                       LDFLAGS="-L/usr/local/lib -R/usr/local/lib ${saved_LDFLAGS}"
+               else
+                       LDFLAGS="-L/usr/local/lib ${saved_LDFLAGS}"
+               fi
+               CPPFLAGS="-I/usr/local/include ${saved_CPPFLAGS}"
+               LIBS="$LIBS -lz"
+               AC_TRY_LINK_FUNC(deflate, AC_DEFINE(HAVE_LIBZ),
+                       [
+                               AC_MSG_ERROR([*** zlib missing - please install first or check config.log ***])
+                       ]
+               )
+       ]
+)
+
+AC_ARG_WITH(zlib-version-check,
+       [  --without-zlib-version-check Disable zlib version check],
+       [  if test "x$withval" = "xno" ; then
+               zlib_check_nonfatal=1
+          fi
+       ]
+)
+
+AC_MSG_CHECKING(for possibly buggy zlib)
+AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <zlib.h>
+int main()
+{
+       int a=0, b=0, c=0, d=0, n, v;
+       n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
+       if (n != 3 && n != 4)
+               exit(1);
+       v = a*1000000 + b*10000 + c*100 + d;
+       fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);
+
+       /* 1.1.4 is OK */
+       if (a == 1 && b == 1 && c >= 4)
+               exit(0);
+
+       /* 1.2.3 and up are OK */
+       if (v >= 1020300)
+               exit(0);
+
+       exit(2);
+}
+       ]])],
+       AC_MSG_RESULT(no),
+       [ AC_MSG_RESULT(yes)
+         if test -z "$zlib_check_nonfatal" ; then
+               AC_MSG_ERROR([*** zlib too old - check config.log ***
+Your reported zlib version has known security problems.  It's possible your
+vendor has fixed these problems without changing the version number.  If you
+are sure this is the case, you can disable the check by running
+"./configure --without-zlib-version-check".
+If you are in doubt, upgrade zlib to version 1.2.3 or greater.
+See http://www.gzip.org/zlib/ for details.])
+         else
+               AC_MSG_WARN([zlib version may have security problems])
+         fi
+       ],
+       [       AC_MSG_WARN([cross compiling: not checking zlib version]) ]
+)
+
+dnl UnixWare 2.x
+AC_CHECK_FUNC(strcasecmp,
+       [], [ AC_CHECK_LIB(resolv, strcasecmp, LIBS="$LIBS -lresolv") ]
+)
+AC_CHECK_FUNCS(utimes,
+       [], [ AC_CHECK_LIB(c89, utimes, [AC_DEFINE(HAVE_UTIMES)
+                                       LIBS="$LIBS -lc89"]) ]
+)
+
+dnl    Checks for libutil functions
+AC_CHECK_HEADERS(libutil.h)
+AC_SEARCH_LIBS(login, util bsd, [AC_DEFINE(HAVE_LOGIN, 1,
+       [Define if your libraries define login()])])
+AC_CHECK_FUNCS(fmt_scaled logout updwtmp logwtmp)
+
+AC_FUNC_STRFTIME
+
+# 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, 1,
+                       [Define if your system glob() function has
+                       the GLOB_ALTDIRFUNC extension])
+               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_TRY_COMPILE(
+       [ #include <glob.h> ],
+       [glob_t g; g.gl_matchc = 1;],
+       [
+               AC_DEFINE(GLOB_HAS_GL_MATCHC, 1,
+                       [Define if your system glob() function has
+                       gl_matchc options in glob_t])
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+       ]
+)
+
+# Check for g.gl_statv glob() extension
+AC_MSG_CHECKING(for gl_statv and GLOB_KEEPSTAT extensions for glob)
+AC_TRY_COMPILE(
+       [ #include <glob.h> ],
+       [
+#ifndef GLOB_KEEPSTAT
+#error "glob does not support GLOB_KEEPSTAT extension"
+#endif
+glob_t g;
+g.gl_statv = NULL;
+],
+       [
+               AC_DEFINE(GLOB_HAS_GL_STATV, 1,
+                       [Define if your system glob() function has
+                       gl_statv options in glob_t])
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+       ]
+)
+
+AC_CHECK_DECLS(GLOB_NOMATCH, , , [#include <glob.h>])
+
+AC_MSG_CHECKING([whether struct dirent allocates space for d_name])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <sys/types.h>
+#include <dirent.h>
+int main(void){struct dirent d;exit(sizeof(d.d_name)<=sizeof(char));}
+       ]])],
+       [AC_MSG_RESULT(yes)],
+       [
+               AC_MSG_RESULT(no)
+               AC_DEFINE(BROKEN_ONE_BYTE_DIRENT_D_NAME, 1,
+                       [Define if your struct dirent expects you to
+                       allocate extra space for d_name])
+       ],
+       [
+               AC_MSG_WARN([cross compiling: assuming BROKEN_ONE_BYTE_DIRENT_D_NAME])
+               AC_DEFINE(BROKEN_ONE_BYTE_DIRENT_D_NAME)
+       ]
+)
+
+AC_MSG_CHECKING([for /proc/pid/fd directory])
+if test -d "/proc/$$/fd" ; then
+       AC_DEFINE(HAVE_PROC_PID, 1, [Define if you have /proc/$pid/fd])
+       AC_MSG_RESULT(yes)
+else
+       AC_MSG_RESULT(no)
+fi
+
+# 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, 1, [Define if you want S/Key support])
+                       LIBS="-lskey $LIBS"
+                       SKEY_MSG="yes"
+
+                       AC_MSG_CHECKING([for s/key support])
+                       AC_LINK_IFELSE(
+                               [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <skey.h>
+int main() { char *ff = skey_keyinfo(""); ff=""; exit(0); }
+                               ]])],
+                               [AC_MSG_RESULT(yes)],
+                               [
+                                       AC_MSG_RESULT(no)
+                                       AC_MSG_ERROR([** Incomplete or missing s/key libraries.])
+                               ])
+                       AC_MSG_CHECKING(if skeychallenge takes 4 arguments)
+                       AC_TRY_COMPILE(
+                               [#include <stdio.h>
+                                #include <skey.h>],
+                               [(void)skeychallenge(NULL,"name","",0);],
+                               [AC_MSG_RESULT(yes)
+                                AC_DEFINE(SKEYCHALLENGE_4ARG, 1,
+                                       [Define if your skeychallenge()
+                                       function takes 4 arguments (NetBSD)])],
+                               [AC_MSG_RESULT(no)]
+                       )
+               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}" && \
+                           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
+                       LIBS="-lwrap $LIBS"
+                       AC_MSG_CHECKING(for libwrap)
+                       AC_TRY_LINK(
+                               [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <tcpd.h>
+                                       int deny_severity = 0, allow_severity = 0;
+                               ],
+                               [hosts_access(0);],
+                               [
+                                       AC_MSG_RESULT(yes)
+                                       AC_DEFINE(LIBWRAP, 1,
+                                               [Define if you want
+                                               TCP Wrappers support])
+                                       SSHDLIBS="$SSHDLIBS -lwrap"
+                                       TCPW_MSG="yes"
+                               ],
+                               [
+                                       AC_MSG_ERROR([*** libwrap missing])
+                               ]
+                       )
+                       LIBS="$saved_LIBS"
+               fi
+       ]
+)
+
+# Check whether user wants libedit support
+LIBEDIT_MSG="no"
+AC_ARG_WITH(libedit,
+       [  --with-libedit[[=PATH]]   Enable libedit support for sftp],
+       [ if test "x$withval" != "xno" ; then
+               if test "x$withval" = "xyes" ; then
+                       AC_PATH_PROG(PKGCONFIG, pkg-config, no)
+                       if test "x$PKGCONFIG" != "xno"; then
+                               AC_MSG_CHECKING(if $PKGCONFIG knows about libedit)
+                               if "$PKGCONFIG" libedit; then
+                                       AC_MSG_RESULT(yes)
+                                       use_pkgconfig_for_libedit=yes
+                               else
+                                       AC_MSG_RESULT(no)
+                               fi
+                       fi
+               else
+                       CPPFLAGS="$CPPFLAGS -I${withval}/include"
+                       if test -n "${need_dash_r}"; then
+                               LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}"
+                       else
+                               LDFLAGS="-L${withval}/lib ${LDFLAGS}"
+                       fi
+               fi
+               if test "x$use_pkgconfig_for_libedit" = "xyes"; then
+                       LIBEDIT=`$PKGCONFIG --libs-only-l libedit`
+                       CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags libedit`"
+               else
+                       LIBEDIT="-ledit -lcurses"
+               fi
+               OTHERLIBS=`echo $LIBEDIT | sed 's/-ledit//'`
+               AC_CHECK_LIB(edit, el_init,
+                       [ AC_DEFINE(USE_LIBEDIT, 1, [Use libedit for sftp])
+                         LIBEDIT_MSG="yes"
+                         AC_SUBST(LIBEDIT)
+                       ],
+                       [ AC_MSG_ERROR(libedit not found) ],
+                       [ $OTHERLIBS ]
+               )
+               AC_MSG_CHECKING(if libedit version is compatible)
+               AC_COMPILE_IFELSE(
+                   [AC_LANG_SOURCE([[
+#include <histedit.h>
+int main(void)
+{
+       int i = H_SETSIZE;
+       el_init("", NULL, NULL, NULL);
+       exit(0);
+}
+                   ]])],
+                   [ AC_MSG_RESULT(yes) ],
+                   [ AC_MSG_RESULT(no)
+                     AC_MSG_ERROR(libedit version is not compatible) ]
+               )
+       fi ]
+)
+
+AUDIT_MODULE=none
+AC_ARG_WITH(audit,
+       [  --with-audit=module     Enable audit support (modules=debug,bsm,linux)],
+       [
+         AC_MSG_CHECKING(for supported audit module)
+         case "$withval" in
+         bsm)
+               AC_MSG_RESULT(bsm)
+               AUDIT_MODULE=bsm
+               dnl    Checks for headers, libs and functions
+               AC_CHECK_HEADERS(bsm/audit.h, [],
+                   [AC_MSG_ERROR(BSM enabled and bsm/audit.h not found)],
+                   [
+#ifdef HAVE_TIME_H
+# include <time.h>
+#endif
+                   ]
+)
+               AC_CHECK_LIB(bsm, getaudit, [],
+                   [AC_MSG_ERROR(BSM enabled and required library not found)])
+               AC_CHECK_FUNCS(getaudit, [],
+                   [AC_MSG_ERROR(BSM enabled and required function not found)])
+               # These are optional
+               AC_CHECK_FUNCS(getaudit_addr aug_get_machine)
+               AC_DEFINE(USE_BSM_AUDIT, 1, [Use BSM audit module])
+               ;;
+         linux)
+               AC_MSG_RESULT(linux)
+               AUDIT_MODULE=linux
+               dnl    Checks for headers, libs and functions
+               AC_CHECK_HEADERS(libaudit.h)
+               SSHDLIBS="$SSHDLIBS -laudit"
+               AC_DEFINE(USE_LINUX_AUDIT, 1, [Use Linux audit module])
+               ;;
+         debug)
+               AUDIT_MODULE=debug
+               AC_MSG_RESULT(debug)
+               AC_DEFINE(SSH_AUDIT_EVENTS, 1, [Use audit debugging module])
+               ;;
+         no)
+               AC_MSG_RESULT(no)
+               ;;
+         *)
+               AC_MSG_ERROR([Unknown audit module $withval])
+               ;;
+       esac ]
+)
+
+dnl    Checks for library functions. Please keep in alphabetical order
+AC_CHECK_FUNCS( \
+       arc4random \
+       arc4random_buf \
+       arc4random_uniform \
+       asprintf \
+       b64_ntop \
+       __b64_ntop \
+       b64_pton \
+       __b64_pton \
+       bcopy \
+       bindresvport_sa \
+       clock \
+       closefrom \
+       dirfd \
+       fchmod \
+       fchown \
+       freeaddrinfo \
+       fstatvfs \
+       futimes \
+       getaddrinfo \
+       getcwd \
+       getgrouplist \
+       getnameinfo \
+       getopt \
+       getpeereid \
+       getpeerucred \
+       _getpty \
+       getrlimit \
+       getttyent \
+       glob \
+       group_from_gid \
+       inet_aton \
+       inet_ntoa \
+       inet_ntop \
+       innetgr \
+       login_getcapbool \
+       md5_crypt \
+       memmove \
+       mkdtemp \
+       mmap \
+       ngetaddrinfo \
+       nsleep \
+       ogetaddrinfo \
+       openlog_r \
+       openpty \
+       poll \
+       prctl \
+       pstat \
+       readpassphrase \
+       realpath \
+       recvmsg \
+       rresvport_af \
+       sendmsg \
+       setdtablesize \
+       setegid \
+       setenv \
+       seteuid \
+       setgroupent \
+       setgroups \
+       setlogin \
+       setpassent\
+       setpcred \
+       setproctitle \
+       setregid \
+       setreuid \
+       setrlimit \
+       setsid \
+       setvbuf \
+       sigaction \
+       sigvec \
+       snprintf \
+       socketpair \
+       statfs \
+       statvfs \
+       strdup \
+       strerror \
+       strlcat \
+       strlcpy \
+       strmode \
+       strnvis \
+       strptime \
+       strtonum \
+       strtoll \
+       strtoul \
+       swap32 \
+       sysconf \
+       tcgetpgrp \
+       timingsafe_bcmp \
+       truncate \
+       unsetenv \
+       updwtmpx \
+       user_from_uid \
+       vasprintf \
+       vhangup \
+       vsnprintf \
+       waitpid \
+)
+
+AC_LINK_IFELSE(
+[
+#include <ctype.h>
+int main(void)
+{
+       return (isblank('a'));
+}
+],
+       [AC_DEFINE(HAVE_ISBLANK, 1, [Define if you have isblank(3C).])
+])
+
+# PKCS#11 support requires dlopen() and co
+AC_SEARCH_LIBS(dlopen, dl,
+    AC_DEFINE([ENABLE_PKCS11], [], [Enable for PKCS#11 support])
+)
+
+# IRIX has a const char return value for gai_strerror()
+AC_CHECK_FUNCS(gai_strerror,[
+       AC_DEFINE(HAVE_GAI_STRERROR)
+       AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+const char *gai_strerror(int);],[
+char *str;
+
+str = gai_strerror(0);],[
+               AC_DEFINE(HAVE_CONST_GAI_STRERROR_PROTO, 1,
+               [Define if gai_strerror() returns const char *])])])
+
+AC_SEARCH_LIBS(nanosleep, rt posix4, AC_DEFINE(HAVE_NANOSLEEP, 1,
+       [Some systems put nanosleep outside of libc]))
+
+dnl Make sure prototypes are defined for these before using them.
+AC_CHECK_DECL(getrusage, [AC_CHECK_FUNCS(getrusage)])
+AC_CHECK_DECL(strsep,
+       [AC_CHECK_FUNCS(strsep)],
+       [],
+       [
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+       ])
+
+dnl tcsendbreak might be a macro
+AC_CHECK_DECL(tcsendbreak,
+       [AC_DEFINE(HAVE_TCSENDBREAK)],
+       [AC_CHECK_FUNCS(tcsendbreak)],
+       [#include <termios.h>]
+)
+
+AC_CHECK_DECLS(h_errno, , ,[#include <netdb.h>])
+
+AC_CHECK_DECLS(SHUT_RD, , ,
+       [
+#include <sys/types.h>
+#include <sys/socket.h>
+       ])
+
+AC_CHECK_DECLS(O_NONBLOCK, , ,
+       [
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+       ])
+
+AC_CHECK_DECLS(writev, , , [
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+       ])
+
+AC_CHECK_DECLS(MAXSYMLINKS, , , [
+#include <sys/param.h>
+       ])
+
+AC_CHECK_DECLS(offsetof, , , [
+#include <stddef.h>
+       ])
+
+AC_CHECK_FUNCS(setresuid, [
+       dnl Some platorms have setresuid that isn't implemented, test for this
+       AC_MSG_CHECKING(if setresuid seems to work)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdlib.h>
+#include <errno.h>
+int main(){errno=0; setresuid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);}
+               ]])],
+               [AC_MSG_RESULT(yes)],
+               [AC_DEFINE(BROKEN_SETRESUID, 1,
+                       [Define if your setresuid() is broken])
+                AC_MSG_RESULT(not implemented)],
+               [AC_MSG_WARN([cross compiling: not checking setresuid])]
+       )
+])
+
+AC_CHECK_FUNCS(setresgid, [
+       dnl Some platorms have setresgid that isn't implemented, test for this
+       AC_MSG_CHECKING(if setresgid seems to work)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdlib.h>
+#include <errno.h>
+int main(){errno=0; setresgid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);}
+               ]])],
+               [AC_MSG_RESULT(yes)],
+               [AC_DEFINE(BROKEN_SETRESGID, 1,
+                       [Define if your setresgid() is broken])
+                AC_MSG_RESULT(not implemented)],
+               [AC_MSG_WARN([cross compiling: not checking setresuid])]
+       )
+])
+
+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 getutxuser pututxline)
+AC_CHECK_FUNCS(setutxdb setutxent utmpxname)
+dnl    Checks for lastlog functions
+AC_CHECK_FUNCS(getlastlogxbyname)
+
+AC_CHECK_FUNC(daemon,
+       [AC_DEFINE(HAVE_DAEMON, 1, [Define if your libraries define daemon()])],
+       [AC_CHECK_LIB(bsd, daemon,
+               [LIBS="$LIBS -lbsd"; AC_DEFINE(HAVE_DAEMON)])]
+)
+
+AC_CHECK_FUNC(getpagesize,
+       [AC_DEFINE(HAVE_GETPAGESIZE, 1,
+               [Define if your libraries define 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_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdio.h>
+int main(void){char b[5];snprintf(b,5,"123456789");exit(b[4]!='\0');}
+               ]])],
+               [AC_MSG_RESULT(yes)],
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(BROKEN_SNPRINTF, 1,
+                               [Define if your snprintf is busted])
+                       AC_MSG_WARN([****** Your snprintf() function is broken, complain to your vendor])
+               ],
+               [ AC_MSG_WARN([cross compiling: Assuming working snprintf()]) ]
+       )
+fi
+
+# If we don't have a working asprintf, then we strongly depend on vsnprintf
+# returning the right thing on overflow: the number of characters it tried to
+# create (as per SUSv3)
+if test "x$ac_cv_func_asprintf" != "xyes" && \
+   test "x$ac_cv_func_vsnprintf" = "xyes" ; then
+       AC_MSG_CHECKING([whether vsnprintf returns correct values on overflow])
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+int x_snprintf(char *str,size_t count,const char *fmt,...)
+{
+       size_t ret; va_list ap;
+       va_start(ap, fmt); ret = vsnprintf(str, count, fmt, ap); va_end(ap);
+       return ret;
+}
+int main(void)
+{
+       char x[1];
+       exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1);
+} ]])],
+               [AC_MSG_RESULT(yes)],
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(BROKEN_SNPRINTF, 1,
+                               [Define if your snprintf is busted])
+                       AC_MSG_WARN([****** Your vsnprintf() function is broken, complain to your vendor])
+               ],
+               [ AC_MSG_WARN([cross compiling: Assuming working vsnprintf()]) ]
+       )
+fi
+
+# On systems where [v]snprintf is broken, but is declared in stdio,
+# check that the fmt argument is const char * or just char *.
+# This is only useful for when BROKEN_SNPRINTF
+AC_MSG_CHECKING([whether snprintf can declare const char *fmt])
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#include <stdio.h>
+          int snprintf(char *a, size_t b, const char *c, ...) { return 0; }
+          int main(void) { snprintf(0, 0, 0); } 
+    ]])],
+   [AC_MSG_RESULT(yes)
+    AC_DEFINE(SNPRINTF_CONST, [const],
+              [Define as const if snprintf() can declare const char *fmt])],
+   [AC_MSG_RESULT(no)
+    AC_DEFINE(SNPRINTF_CONST, [/* not const */])])
+
+# Check for missing getpeereid (or equiv) support
+NO_PEERCHECK=""
+if test "x$ac_cv_func_getpeereid" != "xyes" -a "x$ac_cv_func_getpeerucred" != "xyes"; then
+       AC_MSG_CHECKING([whether system supports SO_PEERCRED getsockopt])
+       AC_TRY_COMPILE(
+               [#include <sys/types.h>
+                #include <sys/socket.h>],
+               [int i = SO_PEERCRED;],
+               [ AC_MSG_RESULT(yes)
+                 AC_DEFINE(HAVE_SO_PEERCRED, 1, [Have PEERCRED socket option])
+               ],
+               [AC_MSG_RESULT(no)
+               NO_PEERCHECK=1]
+        )
+fi
+
+dnl see whether mkstemp() requires XXXXXX
+if test "x$ac_cv_func_mkdtemp" = "xyes" ; then
+AC_MSG_CHECKING([for (overly) strict mkstemp])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <stdlib.h>
+main() { char template[]="conftest.mkstemp-test";
+if (mkstemp(template) == -1)
+       exit(1);
+unlink(template); exit(0);
+}
+       ]])],
+       [
+               AC_MSG_RESULT(no)
+       ],
+       [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_STRICT_MKSTEMP, 1, [Silly mkstemp()])
+       ],
+       [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_STRICT_MKSTEMP)
+       ]
+)
+fi
+
+dnl make sure that openpty does not reacquire controlling terminal
+if test ! -z "$check_for_openpty_ctty_bug"; then
+       AC_MSG_CHECKING(if openpty correctly handles controlling tty)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int
+main()
+{
+       pid_t pid;
+       int fd, ptyfd, ttyfd, status;
+
+       pid = fork();
+       if (pid < 0) {          /* failed */
+               exit(1);
+       } else if (pid > 0) {   /* parent */
+               waitpid(pid, &status, 0);
+               if (WIFEXITED(status))
+                       exit(WEXITSTATUS(status));
+               else
+                       exit(2);
+       } else {                /* child */
+               close(0); close(1); close(2);
+               setsid();
+               openpty(&ptyfd, &ttyfd, NULL, NULL, NULL);
+               fd = open("/dev/tty", O_RDWR | O_NOCTTY);
+               if (fd >= 0)
+                       exit(3);        /* Acquired ctty: broken */
+               else
+                       exit(0);        /* Did not acquire ctty: OK */
+       }
+}
+               ]])],
+               [
+                       AC_MSG_RESULT(yes)
+               ],
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(SSHD_ACQUIRES_CTTY)
+               ],
+               [
+                       AC_MSG_RESULT(cross-compiling, assuming yes)
+               ]
+       )
+fi
+
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+    test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then
+       AC_MSG_CHECKING(if getaddrinfo seems to work)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+
+int
+main(void)
+{
+       int err, sock;
+       struct addrinfo *gai_ai, *ai, hints;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+       if (err != 0) {
+               fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+               exit(1);
+       }
+
+       for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET6)
+                       continue;
+
+               err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+                   sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+               if (err != 0) {
+                       if (err == EAI_SYSTEM)
+                               perror("getnameinfo EAI_SYSTEM");
+                       else
+                               fprintf(stderr, "getnameinfo failed: %s\n",
+                                   gai_strerror(err));
+                       exit(2);
+               }
+
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0)
+                       perror("socket");
+               if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+                       if (errno == EBADF)
+                               exit(3);
+               }
+       }
+       exit(0);
+}
+               ]])],
+               [
+                       AC_MSG_RESULT(yes)
+               ],
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(BROKEN_GETADDRINFO)
+               ],
+               [
+                       AC_MSG_RESULT(cross-compiling, assuming yes)
+               ]
+       )
+fi
+
+if test "x$ac_cv_func_getaddrinfo" = "xyes" && \
+    test "x$check_for_aix_broken_getaddrinfo" = "x1"; then
+       AC_MSG_CHECKING(if getaddrinfo seems to work)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+#define TEST_PORT "2222"
+
+int
+main(void)
+{
+       int err, sock;
+       struct addrinfo *gai_ai, *ai, hints;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV], *name = NULL;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_PASSIVE;
+
+       err = getaddrinfo(name, TEST_PORT, &hints, &gai_ai);
+       if (err != 0) {
+               fprintf(stderr, "getaddrinfo failed (%s)", gai_strerror(err));
+               exit(1);
+       }
+
+       for (ai = gai_ai; ai != NULL; ai = ai->ai_next) {
+               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
+                       continue;
+
+               err = getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop,
+                   sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV);
+
+               if (ai->ai_family == AF_INET && err != 0) {
+                       perror("getnameinfo");
+                       exit(2);
+               }
+       }
+       exit(0);
+}
+               ]])],
+               [
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(AIX_GETNAMEINFO_HACK, 1,
+                               [Define if you have a getaddrinfo that fails
+                               for the all-zeros IPv6 address])
+               ],
+               [
+                       AC_MSG_RESULT(no)
+                       AC_DEFINE(BROKEN_GETADDRINFO)
+               ],
+               [
+                       AC_MSG_RESULT(cross-compiling, assuming no)
+               ]
+       )
+fi
+
+if test "x$check_for_conflicting_getspnam" = "x1"; then
+       AC_MSG_CHECKING(for conflicting getspnam in shadow.h)
+       AC_COMPILE_IFELSE(
+               [
+#include <shadow.h>
+int main(void) {exit(0);}
+               ],
+               [
+                       AC_MSG_RESULT(no)
+               ],
+               [
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(GETSPNAM_CONFLICTING_DEFS, 1,
+                           [Conflicting defs for getspnam])
+               ]
+       )
+fi
+
+AC_FUNC_GETPGRP
+
+# Search for OpenSSL
+saved_CPPFLAGS="$CPPFLAGS"
+saved_LDFLAGS="$LDFLAGS"
+AC_ARG_WITH(ssl-dir,
+       [  --with-ssl-dir=PATH     Specify path to OpenSSL installation ],
+       [
+               if test "x$withval" != "xno" ; then
+                       case "$withval" in
+                               # Relative paths
+                               ./*|../*)       withval="`pwd`/$withval"
+                       esac
+                       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
+                       elif test -d "$withval/lib64"; then
+                               if test -n "${need_dash_r}"; then
+                                       LDFLAGS="-L${withval}/lib64 -R${withval}/lib64 ${LDFLAGS}"
+                               else
+                                       LDFLAGS="-L${withval}/lib64 ${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="-lcrypto $LIBS"
+AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL, 1,
+       [Define if your ssl headers are included
+       with #include <openssl/header.h>]),
+       [
+               dnl Check default openssl install dir
+               if test -n "${need_dash_r}"; then
+                       LDFLAGS="-L/usr/local/ssl/lib -R/usr/local/ssl/lib ${saved_LDFLAGS}"
+               else
+                       LDFLAGS="-L/usr/local/ssl/lib ${saved_LDFLAGS}"
+               fi
+               CPPFLAGS="-I/usr/local/ssl/include ${saved_CPPFLAGS}"
+               AC_CHECK_HEADER([openssl/opensslv.h], ,
+                   AC_MSG_ERROR([*** OpenSSL headers missing - please install first or check config.log ***]))
+               AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL),
+                       [
+                               AC_MSG_ERROR([*** Can't find recent OpenSSL libcrypto (see config.log for details) ***])
+                       ]
+               )
+       ]
+)
+
+# Determine OpenSSL header version
+AC_MSG_CHECKING([OpenSSL header version])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#define DATA "conftest.sslincver"
+int main(void) {
+       FILE *fd;
+       int rc;
+
+       fd = fopen(DATA,"w");
+       if(fd == NULL)
+               exit(1);
+
+       if ((rc = fprintf(fd ,"%x (%s)\n", OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT)) <0)
+               exit(1);
+
+       exit(0);
+}
+       ]])],
+       [
+               ssl_header_ver=`cat conftest.sslincver`
+               AC_MSG_RESULT($ssl_header_ver)
+       ],
+       [
+               AC_MSG_RESULT(not found)
+               AC_MSG_ERROR(OpenSSL version header not found.)
+       ],
+       [
+               AC_MSG_WARN([cross compiling: not checking])
+       ]
+)
+
+# Determine OpenSSL library version
+AC_MSG_CHECKING([OpenSSL library version])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <stdio.h>
+#include <string.h>
+#include <openssl/opensslv.h>
+#include <openssl/crypto.h>
+#define DATA "conftest.ssllibver"
+int main(void) {
+       FILE *fd;
+       int rc;
+
+       fd = fopen(DATA,"w");
+       if(fd == NULL)
+               exit(1);
+
+       if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0)
+               exit(1);
+
+       exit(0);
+}
+       ]])],
+       [
+               ssl_library_ver=`cat conftest.ssllibver`
+               AC_MSG_RESULT($ssl_library_ver)
+       ],
+       [
+               AC_MSG_RESULT(not found)
+               AC_MSG_ERROR(OpenSSL library not found.)
+       ],
+       [
+               AC_MSG_WARN([cross compiling: not checking])
+       ]
+)
+
+AC_ARG_WITH(openssl-header-check,
+       [  --without-openssl-header-check Disable OpenSSL version consistency check],
+       [  if test "x$withval" = "xno" ; then
+               openssl_check_nonfatal=1
+          fi
+       ]
+)
+
+# Sanity check OpenSSL headers
+AC_MSG_CHECKING([whether OpenSSL's headers match the library])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <string.h>
+#include <openssl/opensslv.h>
+int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); }
+       ]])],
+       [
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+               if test "x$openssl_check_nonfatal" = "x"; then
+                       AC_MSG_ERROR([Your OpenSSL headers do not match your
+library. Check config.log for details.
+If you are sure your installation is consistent, you can disable the check
+by running "./configure --without-openssl-header-check".
+Also see contrib/findssl.sh for help identifying header/library mismatches.
+])
+               else
+                       AC_MSG_WARN([Your OpenSSL headers do not match your
+library. Check config.log for details.
+Also see contrib/findssl.sh for help identifying header/library mismatches.])
+               fi
+       ],
+       [
+               AC_MSG_WARN([cross compiling: not checking])
+       ]
+)
+
+AC_MSG_CHECKING([if programs using OpenSSL functions will link])
+AC_LINK_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <openssl/evp.h>
+int main(void) { SSLeay_add_all_algorithms(); }
+       ]])],
+       [
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+               saved_LIBS="$LIBS"
+               LIBS="$LIBS -ldl"
+               AC_MSG_CHECKING([if programs using OpenSSL need -ldl])
+               AC_LINK_IFELSE(
+                       [AC_LANG_SOURCE([[
+#include <openssl/evp.h>
+int main(void) { SSLeay_add_all_algorithms(); }
+                       ]])],
+                       [
+                               AC_MSG_RESULT(yes)
+                       ],
+                       [
+                               AC_MSG_RESULT(no)
+                               LIBS="$saved_LIBS"
+                       ]
+               )
+       ]
+)
+
+AC_CHECK_FUNCS(RSA_generate_key_ex DSA_generate_parameters_ex BN_is_prime_ex RSA_get_default_method)
+
+AC_ARG_WITH(ssl-engine,
+       [  --with-ssl-engine       Enable OpenSSL (hardware) ENGINE support ],
+       [ if test "x$withval" != "xno" ; then
+               AC_MSG_CHECKING(for OpenSSL ENGINE support)
+               AC_TRY_COMPILE(
+                       [ #include <openssl/engine.h>],
+                       [
+ENGINE_load_builtin_engines();ENGINE_register_all_complete();
+                       ],
+                       [ AC_MSG_RESULT(yes)
+                         AC_DEFINE(USE_OPENSSL_ENGINE, 1,
+                            [Enable OpenSSL engine support])
+                       ],
+                       [ AC_MSG_ERROR(OpenSSL ENGINE support not found)]
+               )
+         fi ]
+)
+
+# Check for OpenSSL without EVP_aes_{192,256}_cbc
+AC_MSG_CHECKING([whether OpenSSL has crippled AES support])
+AC_LINK_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <string.h>
+#include <openssl/evp.h>
+int main(void) { exit(EVP_aes_192_cbc() == NULL || EVP_aes_256_cbc() == NULL);}
+       ]])],
+       [
+               AC_MSG_RESULT(no)
+       ],
+       [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(OPENSSL_LOBOTOMISED_AES, 1,
+                   [libcrypto is missing AES 192 and 256 bit functions])
+       ]
+)
+
+AC_MSG_CHECKING([if EVP_DigestUpdate returns an int])
+AC_LINK_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <string.h>
+#include <openssl/evp.h>
+int main(void) { if(EVP_DigestUpdate(NULL, NULL,0)) exit(0); }
+       ]])],
+       [
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+               AC_DEFINE(OPENSSL_EVP_DIGESTUPDATE_VOID, 1,
+                   [Define if EVP_DigestUpdate returns void])
+       ]
+)
+
+# Some systems want crypt() from libcrypt, *not* the version in OpenSSL,
+# because the system crypt() is more featureful.
+if test "x$check_for_libcrypt_before" = "x1"; then
+       AC_CHECK_LIB(crypt, crypt)
+fi
+
+# Some Linux systems (Slackware) need crypt() from libcrypt, *not* the
+# version in OpenSSL.
+if test "x$check_for_libcrypt_later" = "x1"; then
+       AC_CHECK_LIB(crypt, crypt, LIBS="$LIBS -lcrypt")
+fi
+
+# Search for SHA256 support in libc and/or OpenSSL
+AC_CHECK_FUNCS(SHA256_Update EVP_sha256, [TEST_SSH_SHA256=yes],
+    [TEST_SSH_SHA256=no])
+AC_SUBST(TEST_SSH_SHA256)
+
+# Check complete ECC support in OpenSSL
+AC_MSG_CHECKING([whether OpenSSL has complete ECC support])
+AC_LINK_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
+# error "OpenSSL < 0.9.8g has unreliable ECC code"
+#endif
+int main(void) {
+       EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
+       const EVP_MD *m = EVP_sha512(); /* We need this too */
+}
+       ]])],
+       [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(OPENSSL_HAS_ECC, 1,
+                   [libcrypto includes complete ECC support])
+               TEST_SSH_ECC=yes
+               COMMENT_OUT_ECC=""
+       ],
+       [
+               AC_MSG_RESULT(no)
+               TEST_SSH_ECC=no
+               COMMENT_OUT_ECC="#no ecc#"
+       ]
+)
+AC_SUBST(TEST_SSH_ECC)
+AC_SUBST(COMMENT_OUT_ECC)
+
+saved_LIBS="$LIBS"
+AC_CHECK_LIB(iaf, ia_openinfo, [
+       LIBS="$LIBS -liaf"
+       AC_CHECK_FUNCS(set_id, [SSHDLIBS="$SSHDLIBS -liaf"
+                               AC_DEFINE(HAVE_LIBIAF, 1,
+                       [Define if system has libiaf that supports set_id])
+                               ])
+])
+LIBS="$saved_LIBS"
+
+### Configure cryptographic random number support
+
+# Check wheter OpenSSL seeds itself
+AC_MSG_CHECKING([whether OpenSSL's PRNG is internally seeded])
+AC_RUN_IFELSE(
+       [AC_LANG_SOURCE([[
+#include <string.h>
+#include <openssl/rand.h>
+int main(void) { exit(RAND_status() == 1 ? 0 : 1); }
+       ]])],
+       [
+               OPENSSL_SEEDS_ITSELF=yes
+               AC_MSG_RESULT(yes)
+       ],
+       [
+               AC_MSG_RESULT(no)
+               # Default to use of the rand helper if OpenSSL doesn't
+               # seed itself
+               USE_RAND_HELPER=yes
+       ],
+       [
+               AC_MSG_WARN([cross compiling: assuming yes])
+               # This is safe, since all recent OpenSSL versions will
+               # complain at runtime if not seeded correctly.
+               OPENSSL_SEEDS_ITSELF=yes
+       ]
+)
+
+# 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" && \
+                          test "x$ac_cv_header_pam_pam_appl_h" != "xyes" ; then
+                               AC_MSG_ERROR([PAM headers not found])
+                       fi
+
+                       saved_LIBS="$LIBS"
+                       AC_CHECK_LIB(dl, dlopen, , )
+                       AC_CHECK_LIB(pam, pam_set_item, , AC_MSG_ERROR([*** libpam missing]))
+                       AC_CHECK_FUNCS(pam_getenvlist)
+                       AC_CHECK_FUNCS(pam_putenv)
+                       LIBS="$saved_LIBS"
+
+                       PAM_MSG="yes"
+
+                       SSHDLIBS="$SSHDLIBS -lpam"
+                       AC_DEFINE(USE_PAM, 1,
+                               [Define if you want to enable PAM support])
+
+                       if test $ac_cv_lib_dl_dlopen = yes; then
+                               case "$LIBS" in
+                               *-ldl*)
+                                       # libdl already in LIBS
+                                       ;;
+                               *)
+                                       SSHDLIBS="$SSHDLIBS -ldl"
+                                       ;;
+                               esac
+                       fi
+               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>
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+#include <security/pam_appl.h>
+#elif defined (HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+               ],
+               [(void)pam_strerror((pam_handle_t *)NULL, -1);],
+               [AC_MSG_RESULT(no)],
+               [
+                       AC_DEFINE(HAVE_OLD_PAM, 1,
+                               [Define if you have an old version of PAM
+                               which takes only one argument to pam_strerror])
+                       AC_MSG_RESULT(yes)
+                       PAM_MSG="yes (old library)"
+               ]
+       )
+fi
+
+# Do we want to force the use of the rand helper?
+AC_ARG_WITH(rand-helper,
+       [  --with-rand-helper      Use subprocess to gather strong randomness ],
+       [
+               if test "x$withval" = "xno" ; then
+                       # Force use of OpenSSL's internal RNG, even if
+                       # the previous test showed it to be unseeded.
+                       if test -z "$OPENSSL_SEEDS_ITSELF" ; then
+                               AC_MSG_WARN([*** Forcing use of OpenSSL's non-self-seeding PRNG])
+                               OPENSSL_SEEDS_ITSELF=yes
+                               USE_RAND_HELPER=""
+                       fi
+               else
+                       USE_RAND_HELPER=yes
+               fi
+       ],
+)
+
+# Which randomness source do we use?
+if test ! -z "$OPENSSL_SEEDS_ITSELF" && test -z "$USE_RAND_HELPER" ; then
+       # OpenSSL only
+       AC_DEFINE(OPENSSL_PRNG_ONLY, 1,
+               [Define if you want OpenSSL's internally seeded PRNG only])
+       RAND_MSG="OpenSSL internal ONLY"
+       INSTALL_SSH_RAND_HELPER=""
+elif test ! -z "$USE_RAND_HELPER" ; then
+       # install rand helper
+       RAND_MSG="ssh-rand-helper"
+       INSTALL_SSH_RAND_HELPER="yes"
+fi
+AC_SUBST(INSTALL_SSH_RAND_HELPER)
+
+### Configuration of ssh-rand-helper
+
+# PRNGD TCP socket
+AC_ARG_WITH(prngd-port,
+       [  --with-prngd-port=PORT  read entropy from PRNGD/EGD TCP localhost:PORT],
+       [
+               case "$withval" in
+               no)
+                       withval=""
+                       ;;
+               [[0-9]]*)
+                       ;;
+               *)
+                       AC_MSG_ERROR(You must specify a numeric port number for --with-prngd-port)
+                       ;;
+               esac
+               if test ! -z "$withval" ; then
+                       PRNGD_PORT="$withval"
+                       AC_DEFINE_UNQUOTED(PRNGD_PORT, $PRNGD_PORT,
+                               [Port number of PRNGD/EGD random number socket])
+               fi
+       ]
+)
+
+# PRNGD Unix domain socket
+AC_ARG_WITH(prngd-socket,
+       [  --with-prngd-socket=FILE read entropy from PRNGD/EGD socket FILE (default=/var/run/egd-pool)],
+       [
+               case "$withval" in
+               yes)
+                       withval="/var/run/egd-pool"
+                       ;;
+               no)
+                       withval=""
+                       ;;
+               /*)
+                       ;;
+               *)
+                       AC_MSG_ERROR(You must specify an absolute path to the entropy socket)
+                       ;;
+               esac
+
+               if test ! -z "$withval" ; then
+                       if test ! -z "$PRNGD_PORT" ; then
+                               AC_MSG_ERROR(You may not specify both a PRNGD/EGD port and socket)
+                       fi
+                       if test ! -r "$withval" ; then
+                               AC_MSG_WARN(Entropy socket is not readable)
+                       fi
+                       PRNGD_SOCKET="$withval"
+                       AC_DEFINE_UNQUOTED(PRNGD_SOCKET, "$PRNGD_SOCKET",
+                               [Location of PRNGD/EGD random number socket])
+               fi
+       ],
+       [
+               # Check for existing socket only if we don't have a random device already
+               if test "$USE_RAND_HELPER" = yes ; 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
+       ]
+)
+
+# Change default command timeout for hashing entropy source
+entropy_timeout=200
+AC_ARG_WITH(entropy-timeout,
+       [  --with-entropy-timeout  Specify entropy gathering command timeout (msec)],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       entropy_timeout=$withval
+               fi
+       ]
+)
+AC_DEFINE_UNQUOTED(ENTROPY_TIMEOUT_MSEC, $entropy_timeout,
+       [Builtin PRNG command timeout])
+
+SSH_PRIVSEP_USER=sshd
+AC_ARG_WITH(privsep-user,
+       [  --with-privsep-user=user Specify non-privileged user for privilege separation],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       SSH_PRIVSEP_USER=$withval
+               fi
+       ]
+)
+AC_DEFINE_UNQUOTED(SSH_PRIVSEP_USER, "$SSH_PRIVSEP_USER",
+       [non-privileged user for privilege separation])
+AC_SUBST(SSH_PRIVSEP_USER)
+
+# We do this little dance with the search path to insure
+# that programs that we select for use by installed programs
+# (which may be run by the super-user) come from trusted
+# locations before they come from the user's private area.
+# This should help avoid accidentally configuring some
+# random version of a program in someone's personal bin.
+
+OPATH=$PATH
+PATH=/bin:/usr/bin
+test -h /bin 2> /dev/null && PATH=/usr/bin
+test -d /sbin && PATH=$PATH:/sbin
+test -d /usr/sbin && PATH=$PATH:/usr/sbin
+PATH=$PATH:/etc:$OPATH
+
+# These programs are used by the command hashing source to gather 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)
+# restore PATH
+PATH=$OPATH
+
+# Where does ssh-rand-helper get its randomness from?
+INSTALL_SSH_PRNG_CMDS=""
+if test ! -z "$INSTALL_SSH_RAND_HELPER" ; then
+       if test ! -z "$PRNGD_PORT" ; then
+               RAND_HELPER_MSG="TCP localhost:$PRNGD_PORT"
+       elif test ! -z "$PRNGD_SOCKET" ; then
+               RAND_HELPER_MSG="Unix domain socket \"$PRNGD_SOCKET\""
+       else
+               RAND_HELPER_MSG="Command hashing (timeout $entropy_timeout)"
+               RAND_HELPER_CMDHASH=yes
+               INSTALL_SSH_PRNG_CMDS="yes"
+       fi
+fi
+AC_SUBST(INSTALL_SSH_PRNG_CMDS)
+
+
+# Cheap hack to ensure NEWS-OS libraries are arranged right.
+if test ! -z "$SONY" ; then
+  LIBS="$LIBS -liberty";
+fi
+
+# Check for  long long datatypes
+AC_CHECK_TYPES([long long, unsigned long long, long double])
+
+# Check datatype sizes
+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)
+
+# Sanity check long long for some platforms (AIX)
+if test "x$ac_cv_sizeof_long_long_int" = "x4" ; then
+       ac_cv_sizeof_long_long_int=0
+fi
+
+# compute LLONG_MIN and LLONG_MAX if we don't know them.
+if test -z "$have_llong_max"; then
+       AC_MSG_CHECKING([for max value of long long])
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#include <stdio.h>
+/* Why is this so damn hard? */
+#ifdef __GNUC__
+# undef __GNUC__
+#endif
+#define __USE_ISOC99
+#include <limits.h>
+#define DATA "conftest.llminmax"
+#define my_abs(a) ((a) < 0 ? ((a) * -1) : (a))
+
+/*
+ * printf in libc on some platforms (eg old Tru64) does not understand %lld so
+ * we do this the hard way.
+ */
+static int
+fprint_ll(FILE *f, long long n)
+{
+       unsigned int i;
+       int l[sizeof(long long) * 8];
+
+       if (n < 0)
+               if (fprintf(f, "-") < 0)
+                       return -1;
+       for (i = 0; n != 0; i++) {
+               l[i] = my_abs(n % 10);
+               n /= 10;
+       }
+       do {
+               if (fprintf(f, "%d", l[--i]) < 0)
+                       return -1;
+       } while (i != 0);
+       if (fprintf(f, " ") < 0)
+               return -1;
+       return 0;
+}
+
+int main(void) {
+       FILE *f;
+       long long i, llmin, llmax = 0;
+
+       if((f = fopen(DATA,"w")) == NULL)
+               exit(1);
+
+#if defined(LLONG_MIN) && defined(LLONG_MAX)
+       fprintf(stderr, "Using system header for LLONG_MIN and LLONG_MAX\n");
+       llmin = LLONG_MIN;
+       llmax = LLONG_MAX;
+#else
+       fprintf(stderr, "Calculating  LLONG_MIN and LLONG_MAX\n");
+       /* This will work on one's complement and two's complement */
+       for (i = 1; i > llmax; i <<= 1, i++)
+               llmax = i;
+       llmin = llmax + 1LL;    /* wrap */
+#endif
+
+       /* Sanity check */
+       if (llmin + 1 < llmin || llmin - 1 < llmin || llmax + 1 > llmax
+           || llmax - 1 > llmax || llmin == llmax || llmin == 0
+           || llmax == 0 || llmax < LONG_MAX || llmin > LONG_MIN) {
+               fprintf(f, "unknown unknown\n");
+               exit(2);
+       }
+
+       if (fprint_ll(f, llmin) < 0)
+               exit(3);
+       if (fprint_ll(f, llmax) < 0)
+               exit(4);
+       if (fclose(f) < 0)
+               exit(5);
+       exit(0);
+}
+               ]])],
+               [
+                       llong_min=`$AWK '{print $1}' conftest.llminmax`
+                       llong_max=`$AWK '{print $2}' conftest.llminmax`
+
+                       AC_MSG_RESULT($llong_max)
+                       AC_DEFINE_UNQUOTED(LLONG_MAX, [${llong_max}LL],
+                           [max value of long long calculated by configure])
+                       AC_MSG_CHECKING([for min value of long long])
+                       AC_MSG_RESULT($llong_min)
+                       AC_DEFINE_UNQUOTED(LLONG_MIN, [${llong_min}LL],
+                           [min value of long long calculated by configure])
+               ],
+               [
+                       AC_MSG_RESULT(not found)
+               ],
+               [
+                       AC_MSG_WARN([cross compiling: not checking])
+               ]
+       )
+fi
+
+
+# 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, 1, [define if you have u_int data type])
+       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, 1, [define if you have intxx_t data type])
+       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>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h>
+#endif
+               ],
+               [ 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, 1, [define if you have int64_t data type])
+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, 1, [define if you have u_intxx_t data type])
+       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, 1, [define if you have u_int64_t data type])
+       have_u_int64_t=1
+fi
+
+if test -z "$have_u_int64_t" ; then
+    AC_MSG_CHECKING([for u_int64_t type in sys/bitypes.h])
+       AC_TRY_COMPILE(
+               [ #include <sys/bitypes.h> ],
+               [ u_int64_t a; a = 1],
+               [
+                       AC_DEFINE(HAVE_U_INT64_T)
+                       AC_MSG_RESULT(yes)
+               ],
+               [ AC_MSG_RESULT(no) ]
+       )
+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, 1,
+                       [define if you have uintxx_t data type])
+       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, 1, [define if you have u_char data type])
+fi
+
+TYPE_SOCKLEN_T
+
+AC_CHECK_TYPES(sig_atomic_t,,,[#include <signal.h>])
+AC_CHECK_TYPES([fsblkcnt_t, fsfilcnt_t],,,[
+#include <sys/types.h>
+#ifdef HAVE_SYS_BITYPES_H
+#include <sys/bitypes.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+])
+
+AC_CHECK_TYPES([in_addr_t, in_port_t],,,
+[#include <sys/types.h>
+#include <netinet/in.h>])
+
+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, 1, [define if you have size_t data type])
+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, 1, [define if you have ssize_t data type])
+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, 1, [define if you have clock_t data type])
+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, 1,
+               [define if you have sa_family_t data type])
+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, 1, [define if you have pid_t data type])
+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, 1, [define if you have mode_t data type])
+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, 1,
+               [define if you have struct sockaddr_storage data type])
+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, 1,
+               [define if you have struct sockaddr_in6 data type])
+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, 1,
+               [define if you have struct in6_addr data type])
+
+dnl Now check for sin6_scope_id
+       AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,,
+               [
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <netinet/in.h>
+               ])
+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, 1,
+               [define if you have struct addrinfo data type])
+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, 1, [define if you have struct timeval])
+       have_struct_timeval=1
+fi
+
+AC_CHECK_TYPES(struct timespec)
+
+# We need int64_t or else certian parts of the compile will fail.
+if test "x$ac_cv_have_int64_t" = "xno" && \
+       test "x$ac_cv_sizeof_long_int" != "x8" && \
+       test "x$ac_cv_sizeof_long_long_int" = "x0" ; then
+       echo "OpenSSH requires int64_t support.  Contact your vendor or install"
+       echo "an alternative compiler (I.E., GCC) before continuing."
+       echo ""
+       exit 1;
+else
+dnl test snprintf (broken on SCO w/gcc)
+       AC_RUN_IFELSE(
+               [AC_LANG_SOURCE([[
+#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) ],
+               AC_MSG_WARN([cross compiling: Assuming working snprintf()])
+       )
+fi
+
+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_CHECK_MEMBER([struct __res_state.retrans], [], [AC_DEFINE(__res_state, state,
+       [Define if we don't have struct __res_state in resolv.h])],
+[
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+])
+
+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, 1, [Fields in struct sockaddr_storage])
+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, 1,
+               [Fields in struct sockaddr_storage])
+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, 1,
+               [Define if your password has a pw_class field])
+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, 1,
+               [Define if your password has a pw_expire field])
+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, 1,
+               [Define if your password has a pw_change field])
+fi
+
+dnl make sure we're using the real structure members and not defines
+AC_CACHE_CHECK([for msg_accrights field in struct msghdr],
+               ac_cv_have_accrights_in_msghdr, [
+       AC_COMPILE_IFELSE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+int main() {
+#ifdef msg_accrights
+#error "msg_accrights is a macro"
+exit(1);
+#endif
+struct msghdr m;
+m.msg_accrights = 0;
+exit(0);
+}
+               ],
+               [ ac_cv_have_accrights_in_msghdr="yes" ],
+               [ ac_cv_have_accrights_in_msghdr="no" ]
+       )
+])
+if test "x$ac_cv_have_accrights_in_msghdr" = "xyes" ; then
+       AC_DEFINE(HAVE_ACCRIGHTS_IN_MSGHDR, 1,
+               [Define if your system uses access rights style
+               file descriptor passing])
+fi
+
+AC_MSG_CHECKING(if struct statvfs.f_fsid is integral type)
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+], [struct statvfs s; s.f_fsid = 0;],
+[ AC_MSG_RESULT(yes) ],
+[ AC_MSG_RESULT(no)
+
+       AC_MSG_CHECKING(if fsid_t has member val)
+       AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/statvfs.h>],
+       [fsid_t t; t.val[0] = 0;],
+       [ AC_MSG_RESULT(yes)
+         AC_DEFINE(FSID_HAS_VAL, 1, fsid_t has member val) ],
+       [ AC_MSG_RESULT(no) ])
+
+       AC_MSG_CHECKING(if f_fsid has member __val)
+       AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/statvfs.h>],
+       [fsid_t t; t.__val[0] = 0;],
+       [ AC_MSG_RESULT(yes)
+         AC_DEFINE(FSID_HAS___VAL, 1, fsid_t has member __val) ],
+       [ AC_MSG_RESULT(no) ])
+])
+
+AC_CACHE_CHECK([for msg_control field in struct msghdr],
+               ac_cv_have_control_in_msghdr, [
+       AC_COMPILE_IFELSE(
+               [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+int main() {
+#ifdef msg_control
+#error "msg_control is a macro"
+exit(1);
+#endif
+struct msghdr m;
+m.msg_control = 0;
+exit(0);
+}
+               ],
+               [ ac_cv_have_control_in_msghdr="yes" ],
+               [ ac_cv_have_control_in_msghdr="no" ]
+       )
+])
+if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then
+       AC_DEFINE(HAVE_CONTROL_IN_MSGHDR, 1,
+               [Define if your system uses ancillary data style
+               file descriptor passing])
+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, 1, [Define if libc defines __progname])
+fi
+
+AC_CACHE_CHECK([whether $CC implements __FUNCTION__], ac_cv_cc_implements___FUNCTION__, [
+       AC_TRY_LINK([
+#include <stdio.h>
+],
+               [ printf("%s", __FUNCTION__); ],
+               [ ac_cv_cc_implements___FUNCTION__="yes" ],
+               [ ac_cv_cc_implements___FUNCTION__="no" ]
+       )
+])
+if test "x$ac_cv_cc_implements___FUNCTION__" = "xyes" ; then
+       AC_DEFINE(HAVE___FUNCTION__, 1,
+               [Define if compiler implements __FUNCTION__])
+fi
+
+AC_CACHE_CHECK([whether $CC implements __func__], ac_cv_cc_implements___func__, [
+       AC_TRY_LINK([
+#include <stdio.h>
+],
+               [ printf("%s", __func__); ],
+               [ ac_cv_cc_implements___func__="yes" ],
+               [ ac_cv_cc_implements___func__="no" ]
+       )
+])
+if test "x$ac_cv_cc_implements___func__" = "xyes" ; then
+       AC_DEFINE(HAVE___func__, 1, [Define if compiler implements __func__])
+fi
+
+AC_CACHE_CHECK([whether va_copy exists], ac_cv_have_va_copy, [
+       AC_TRY_LINK(
+               [#include <stdarg.h>
+                va_list x,y;],
+               [va_copy(x,y);],
+               [ ac_cv_have_va_copy="yes" ],
+               [ ac_cv_have_va_copy="no" ]
+       )
+])
+if test "x$ac_cv_have_va_copy" = "xyes" ; then
+       AC_DEFINE(HAVE_VA_COPY, 1, [Define if va_copy exists])
+fi
+
+AC_CACHE_CHECK([whether __va_copy exists], ac_cv_have___va_copy, [
+       AC_TRY_LINK(
+               [#include <stdarg.h>
+                va_list x,y;],
+               [__va_copy(x,y);],
+               [ ac_cv_have___va_copy="yes" ],
+               [ ac_cv_have___va_copy="no" ]
+       )
+])
+if test "x$ac_cv_have___va_copy" = "xyes" ; then
+       AC_DEFINE(HAVE___VA_COPY, 1, [Define if __va_copy exists])
+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, 1,
+               [Define if your getopt(3) defines and uses 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, 1,
+               [Define if your system defines 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, 1, [Define if your system defines sys_nerr])
+fi
+
+# Check libraries needed by DNS fingerprint support
+AC_SEARCH_LIBS(getrrsetbyname, resolv,
+       [AC_DEFINE(HAVE_GETRRSETBYNAME, 1,
+               [Define if getrrsetbyname() exists])],
+       [
+               # Needed by our getrrsetbyname()
+               AC_SEARCH_LIBS(res_query, resolv)
+               AC_SEARCH_LIBS(dn_expand, resolv)
+               AC_MSG_CHECKING(if res_query will link)
+               AC_LINK_IFELSE([
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+int main()
+{
+       res_query (0, 0, 0, 0, 0);
+       return 0;
+}
+                  ],
+                   AC_MSG_RESULT(yes),
+                  [AC_MSG_RESULT(no)
+                   saved_LIBS="$LIBS"
+                   LIBS="$LIBS -lresolv"
+                   AC_MSG_CHECKING(for res_query in -lresolv)
+                   AC_LINK_IFELSE([
+#include "confdefs.h"
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+int main()
+{
+       res_query (0, 0, 0, 0, 0);
+       return 0;
+}
+                       ],
+                       [AC_MSG_RESULT(yes)],
+                       [LIBS="$saved_LIBS"
+                        AC_MSG_RESULT(no)])
+                   ])
+               AC_CHECK_FUNCS(_getshort _getlong)
+               AC_CHECK_DECLS([_getshort, _getlong], , ,
+                   [#include <sys/types.h>
+                   #include <arpa/nameser.h>])
+               AC_CHECK_MEMBER(HEADER.ad,
+                       [AC_DEFINE(HAVE_HEADER_AD, 1,
+                           [Define if HEADER.ad exists in arpa/nameser.h])],,
+                       [#include <arpa/nameser.h>])
+       ])
+
+AC_MSG_CHECKING(if struct __res_state _res is an extern)
+AC_LINK_IFELSE([
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+extern struct __res_state _res;
+int main() { return 0; }
+               ],
+               [AC_MSG_RESULT(yes)
+                AC_DEFINE(HAVE__RES_EXTERN, 1,
+                   [Define if you have struct __res_state _res as an extern])
+               ],
+               [ AC_MSG_RESULT(no) ]
+)
+
+# Check whether user wants SELinux support
+SELINUX_MSG="no"
+LIBSELINUX=""
+AC_ARG_WITH(selinux,
+       [  --with-selinux          Enable SELinux support],
+       [ if test "x$withval" != "xno" ; then
+               save_LIBS="$LIBS"
+               AC_DEFINE(WITH_SELINUX,1,[Define if you want SELinux support.])
+               SELINUX_MSG="yes"
+               AC_CHECK_HEADER([selinux/selinux.h], ,
+                       AC_MSG_ERROR(SELinux support requires selinux.h header))
+               AC_CHECK_LIB(selinux, setexeccon,
+                       [ LIBSELINUX="-lselinux"
+                         LIBS="$LIBS -lselinux"
+                       ],
+                       AC_MSG_ERROR(SELinux support requires libselinux library))
+               SSHLIBS="$SSHLIBS $LIBSELINUX"
+               SSHDLIBS="$SSHDLIBS $LIBSELINUX"
+               AC_CHECK_FUNCS(getseuserbyname get_default_context_with_level)
+               LIBS="$save_LIBS"
+       fi ]
+)
+AC_SUBST(SSHLIBS)
+AC_SUBST(SSHDLIBS)
+
+# Check whether user wants Kerberos 5 support
+KRB5_MSG="no"
+AC_ARG_WITH(kerberos5,
+       [  --with-kerberos5=PATH   Enable Kerberos 5 support],
+       [ if test "x$withval" != "xno" ; then
+               if test "x$withval" = "xyes" ; then
+                       KRB5ROOT="/usr/local"
+               else
+                       KRB5ROOT=${withval}
+               fi
+
+               AC_DEFINE(KRB5, 1, [Define if you want Kerberos 5 support])
+               KRB5_MSG="yes"
+
+               AC_PATH_PROG([KRB5CONF],[krb5-config],
+                            [$KRB5ROOT/bin/krb5-config],
+                            [$KRB5ROOT/bin:$PATH])
+               if test -x $KRB5CONF ; then
+
+                       AC_MSG_CHECKING(for gssapi support)
+                       if $KRB5CONF | grep gssapi >/dev/null ; then
+                               AC_MSG_RESULT(yes)
+                               AC_DEFINE(GSSAPI, 1,
+                                       [Define this if you want GSSAPI
+                                       support in the version 2 protocol])
+                               k5confopts=gssapi
+                       else
+                               AC_MSG_RESULT(no)
+                               k5confopts=""
+                       fi
+                       K5CFLAGS="`$KRB5CONF --cflags $k5confopts`"
+                       K5LIBS="`$KRB5CONF --libs $k5confopts`"
+                       CPPFLAGS="$CPPFLAGS $K5CFLAGS"
+                       AC_MSG_CHECKING(whether we are using Heimdal)
+                       AC_TRY_COMPILE([ #include <krb5.h> ],
+                                      [ char *tmp = heimdal_version; ],
+                                      [ AC_MSG_RESULT(yes)
+                                        AC_DEFINE(HEIMDAL, 1,
+                                       [Define this if you are using the
+                                       Heimdal version of Kerberos V5]) ],
+                                        AC_MSG_RESULT(no)
+                       )
+               else
+                       CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include"
+                       LDFLAGS="$LDFLAGS -L${KRB5ROOT}/lib"
+                       AC_MSG_CHECKING(whether we are using Heimdal)
+                       AC_TRY_COMPILE([ #include <krb5.h> ],
+                                      [ char *tmp = heimdal_version; ],
+                                      [ AC_MSG_RESULT(yes)
+                                        AC_DEFINE(HEIMDAL)
+                                        K5LIBS="-lkrb5"
+                                        K5LIBS="$K5LIBS -lcom_err -lasn1"
+                                        AC_CHECK_LIB(roken, net_write,
+                                          [K5LIBS="$K5LIBS -lroken"])
+                                        AC_CHECK_LIB(des, des_cbc_encrypt,
+                                          [K5LIBS="$K5LIBS -ldes"])
+                                      ],
+                                      [ AC_MSG_RESULT(no)
+                                        K5LIBS="-lkrb5 -lk5crypto -lcom_err"
+                                      ]
+                       )
+                       AC_SEARCH_LIBS(dn_expand, resolv)
+
+                       AC_CHECK_LIB(gssapi_krb5, gss_init_sec_context,
+                               [ AC_DEFINE(GSSAPI)
+                                 K5LIBS="-lgssapi_krb5 $K5LIBS" ],
+                               [ AC_CHECK_LIB(gssapi, gss_init_sec_context,
+                                       [ AC_DEFINE(GSSAPI)
+                                         K5LIBS="-lgssapi $K5LIBS" ],
+                                       AC_MSG_WARN([Cannot find any suitable gss-api library - build may fail]),
+                                       $K5LIBS)
+                               ],
+                               $K5LIBS)
+
+                       AC_CHECK_HEADER(gssapi.h, ,
+                               [ unset ac_cv_header_gssapi_h
+                                 CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+                                 AC_CHECK_HEADERS(gssapi.h, ,
+                                       AC_MSG_WARN([Cannot find any suitable gss-api header - build may fail])
+                                 )
+                               ]
+                       )
+
+                       oldCPP="$CPPFLAGS"
+                       CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+                       AC_CHECK_HEADER(gssapi_krb5.h, ,
+                                       [ CPPFLAGS="$oldCPP" ])
+
+               fi
+               if test ! -z "$need_dash_r" ; then
+                       LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
+               fi
+               if test ! -z "$blibpath" ; then
+                       blibpath="$blibpath:${KRB5ROOT}/lib"
+               fi
+
+               AC_CHECK_HEADERS(gssapi.h gssapi/gssapi.h)
+               AC_CHECK_HEADERS(gssapi_krb5.h gssapi/gssapi_krb5.h)
+               AC_CHECK_HEADERS(gssapi_generic.h gssapi/gssapi_generic.h)
+
+               LIBS="$LIBS $K5LIBS"
+               AC_SEARCH_LIBS(k_hasafs, kafs, AC_DEFINE(USE_AFS, 1,
+                       [Define this if you want to use libkafs' AFS support]))
+       fi
+       ]
+)
+
+# Looking for programs, paths and files
+
+PRIVSEP_PATH=/var/empty
+AC_ARG_WITH(privsep-path,
+       [  --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       PRIVSEP_PATH=$withval
+               fi
+       ]
+)
+AC_SUBST(PRIVSEP_PATH)
+
+AC_ARG_WITH(xauth,
+       [  --with-xauth=PATH       Specify path to xauth program ],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       xauth_path=$withval
+               fi
+       ],
+       [
+               TestPath="$PATH"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/X/bin"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/bin/X11"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/X11R6/bin"
+               TestPath="${TestPath}${PATH_SEPARATOR}/usr/openwin/bin"
+               AC_PATH_PROG(xauth_path, xauth, , $TestPath)
+               if (test ! -z "$xauth_path" && test -x "/usr/openwin/bin/xauth") ; then
+                       xauth_path="/usr/openwin/bin/xauth"
+               fi
+       ]
+)
+
+STRIP_OPT=-s
+AC_ARG_ENABLE(strip,
+       [  --disable-strip         Disable calling strip(1) on install],
+       [
+               if test "x$enableval" = "xno" ; then
+                       STRIP_OPT=
+               fi
+       ]
+)
+AC_SUBST(STRIP_OPT)
+
+if test -z "$xauth_path" ; then
+       XAUTH_PATH="undefined"
+       AC_SUBST(XAUTH_PATH)
+else
+       AC_DEFINE_UNQUOTED(XAUTH_PATH, "$xauth_path",
+               [Define if xauth is found in your path])
+       XAUTH_PATH=$xauth_path
+       AC_SUBST(XAUTH_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",
+               [Set this to your mail directory if you don't have maillock.h])
+fi
+
+if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes"; then
+       AC_MSG_WARN([cross compiling: Disabling /dev/ptmx test])
+       disable_ptmx_check=yes
+fi
+if test -z "$no_dev_ptmx" ; then
+       if test "x$disable_ptmx_check" != "xyes" ; then
+               AC_CHECK_FILE("/dev/ptmx",
+                       [
+                               AC_DEFINE_UNQUOTED(HAVE_DEV_PTMX, 1,
+                                       [Define if you have /dev/ptmx])
+                               have_dev_ptmx=1
+                       ]
+               )
+       fi
+fi
+
+if test ! -z "$cross_compiling" && test "x$cross_compiling" != "xyes"; then
+       AC_CHECK_FILE("/dev/ptc",
+               [
+                       AC_DEFINE_UNQUOTED(HAVE_DEV_PTS_AND_PTC, 1,
+                               [Define if you have /dev/ptc])
+                       have_dev_ptc=1
+               ]
+       )
+else
+       AC_MSG_WARN([cross compiling: Disabling /dev/ptc test])
+fi
+
+# Options from here on. Some of these are preset by platform above
+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
+       TestPath="/usr/bin${PATH_SEPARATOR}/usr/ucb"
+       AC_PATH_PROGS(NROFF, nroff awf, /bin/false, $TestPath)
+       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, 1,
+                               [Define if you want to allow 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, 1,
+                   [Define if you want to use shadow password expire field])
+       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, 1,
+               [Define if you need to use IP address
+               instead of hostname 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
+
+# check for /etc/default/login and use it if present.
+AC_ARG_ENABLE(etc-default-login,
+       [  --disable-etc-default-login Disable using PATH from /etc/default/login [no]],
+       [ if test "x$enableval" = "xno"; then
+               AC_MSG_NOTICE([/etc/default/login handling disabled])
+               etc_default_login=no
+         else
+               etc_default_login=yes
+         fi ],
+       [ if test ! -z "$cross_compiling" && test "x$cross_compiling" = "xyes";
+         then
+               AC_MSG_WARN([cross compiling: not checking /etc/default/login])
+               etc_default_login=no
+         else
+               etc_default_login=yes
+         fi ]
+)
+
+if test "x$etc_default_login" != "xno"; then
+       AC_CHECK_FILE("/etc/default/login",
+           [ external_path_file=/etc/default/login ])
+       if test "x$external_path_file" = "x/etc/default/login"; then
+               AC_DEFINE(HAVE_ETC_DEFAULT_LOGIN, 1,
+                       [Define if your system has /etc/default/login])
+       fi
+fi
+
+dnl BSD systems use /etc/login.conf so --with-default-path= has no effect
+if test $ac_cv_func_login_getcapbool = "yes" && \
+       test $ac_cv_header_login_cap_h = "yes" ; then
+       external_path_file=/etc/login.conf
+fi
+
+# Whether to mess with the default path
+SERVER_PATH_MSG="(default)"
+AC_ARG_WITH(default-path,
+       [  --with-default-path=    Specify default \$PATH environment for server],
+       [
+               if test "x$external_path_file" = "x/etc/login.conf" ; then
+                       AC_MSG_WARN([
+--with-default-path=PATH has no effect on this system.
+Edit /etc/login.conf instead.])
+               elif test "x$withval" != "xno" ; then
+                       if test ! -z "$external_path_file" ; then
+                               AC_MSG_WARN([
+--with-default-path=PATH will only be used if PATH is not defined in
+$external_path_file .])
+                       fi
+                       user_path="$withval"
+                       SERVER_PATH_MSG="$withval"
+               fi
+       ],
+       [ if test "x$external_path_file" = "x/etc/login.conf" ; then
+               AC_MSG_WARN([Make sure the path to scp is in /etc/login.conf])
+       else
+               if test ! -z "$external_path_file" ; then
+                       AC_MSG_WARN([
+If PATH is defined in $external_path_file, ensure the path to scp is included,
+otherwise scp will not work.])
+               fi
+               AC_RUN_IFELSE(
+                       [AC_LANG_SOURCE([[
+/* find out what STDPATH is */
+#include <stdio.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#ifndef _PATH_STDPATH
+# ifdef _PATH_USERPATH /* Irix */
+#  define _PATH_STDPATH _PATH_USERPATH
+# else
+#  define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin"
+# endif
+#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
+       fi ]
+)
+if test "x$external_path_file" != "x/etc/login.conf" ; then
+       AC_DEFINE_UNQUOTED(USER_PATH, "$user_path", [Specify default $PATH])
+       AC_SUBST(user_path)
+fi
+
+# Set superuser path separately to user path
+AC_ARG_WITH(superuser-path,
+       [  --with-superuser-path=  Specify different path for super-user],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       AC_DEFINE_UNQUOTED(SUPERUSER_PATH, "$withval",
+                               [Define if you want a different $PATH
+                               for the superuser])
+                       superuser_path=$withval
+               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, 1,
+                               [Detect IPv4 in IPv6 mapped addresses
+                               and treat as IPv4])
+                       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
+BSD_AUTH_MSG=no
+AC_ARG_WITH(bsd-auth,
+       [  --with-bsd-auth         Enable BSD auth support],
+       [
+               if test "x$withval" != "xno" ; then
+                       AC_DEFINE(BSD_AUTH, 1,
+                               [Define if you have BSD auth support])
+                       BSD_AUTH_MSG=yes
+               fi
+       ]
+)
+
+# Where to place sshd.pid
+piddir=/var/run
+# 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_ARG_WITH(pid-dir,
+       [  --with-pid-dir=PATH     Specify location of ssh.pid file],
+       [
+               if test -n "$withval"  &&  test "x$withval" != "xno"  &&  \
+                   test "x${withval}" != "xyes"; then
+                       piddir=$withval
+                       if test ! -d $piddir ; then
+                       AC_MSG_WARN([** no $piddir directory on this system **])
+                       fi
+               fi
+       ]
+)
+
+AC_DEFINE_UNQUOTED(_PATH_SSH_PIDDIR, "$piddir", [Specify location of ssh.pid])
+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]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_LASTLOG)
+               fi
+       ]
+)
+AC_ARG_ENABLE(utmp,
+       [  --disable-utmp          disable use of utmp even if detected [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_UTMP)
+               fi
+       ]
+)
+AC_ARG_ENABLE(utmpx,
+       [  --disable-utmpx         disable use of utmpx even if detected [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_UTMPX, 1,
+                               [Define if you don't want to use utmpx])
+               fi
+       ]
+)
+AC_ARG_ENABLE(wtmp,
+       [  --disable-wtmp          disable use of wtmp even if detected [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_WTMP)
+               fi
+       ]
+)
+AC_ARG_ENABLE(wtmpx,
+       [  --disable-wtmpx         disable use of wtmpx even if detected [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_WTMPX, 1,
+                               [Define if you don't want to use wtmpx])
+               fi
+       ]
+)
+AC_ARG_ENABLE(libutil,
+       [  --disable-libutil       disable use of libutil (login() etc.) [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_LOGIN)
+               fi
+       ]
+)
+AC_ARG_ENABLE(pututline,
+       [  --disable-pututline     disable use of pututline() etc. ([uw]tmp) [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_PUTUTLINE, 1,
+                               [Define if you don't want to use pututline()
+                               etc. to write [uw]tmp])
+               fi
+       ]
+)
+AC_ARG_ENABLE(pututxline,
+       [  --disable-pututxline    disable use of pututxline() etc. ([uw]tmpx) [no]],
+       [
+               if test "x$enableval" = "xno" ; then
+                       AC_DEFINE(DISABLE_PUTUTXLINE, 1,
+                               [Define if you don't want to use pututxline()
+                               etc. to write [uw]tmpx])
+               fi
+       ]
+)
+AC_ARG_WITH(lastlog,
+  [  --with-lastlog=FILE|DIR specify lastlog location [common locations]],
+       [
+               if test "x$withval" = "xno" ; then
+                       AC_DEFINE(DISABLE_LASTLOG)
+               elif test -n "$withval"  &&  test "x${withval}" != "xyes"; then
+                       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",
+               [Define if you want to specify the path to your lastlog file])
+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",
+               [Define if you want to specify the path to your utmp file])
+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",
+               [Define if you want to specify the path to your wtmp file])
+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",
+               [Define if you want to specify the path to your wtmpx file])
+fi
+
+
+if test ! -z "$blibpath" ; then
+       LDFLAGS="$LDFLAGS $blibflags$blibpath"
+       AC_MSG_WARN([Please check and edit blibpath in LDFLAGS in Makefile])
+fi
+
+dnl Adding -Werror to CFLAGS early prevents configure tests from running.
+dnl Add now.
+CFLAGS="$CFLAGS $werror_flags"
+
+if test "x$ac_cv_func_getaddrinfo" != "xyes" ; then
+       TEST_SSH_IPV6=no
+else
+       TEST_SSH_IPV6=yes
+fi
+AC_CHECK_DECL(BROKEN_GETADDRINFO,  TEST_SSH_IPV6=no)
+AC_SUBST(TEST_SSH_IPV6, $TEST_SSH_IPV6)
+
+AC_EXEEXT
+AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
+       openbsd-compat/Makefile openbsd-compat/regress/Makefile \
+       ssh_prng_cmds survey.sh])
+AC_OUTPUT
+
+# Print summary of options
+
+# 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 ${PRIVSEP_PATH}` ; H=`eval echo ${H}`
+I=`eval echo ${user_path}` ; I=`eval echo ${I}`
+J=`eval echo ${superuser_path}` ; J=`eval echo ${J}`
+
+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 "  Privilege separation chroot path: $H"
+if test "x$external_path_file" = "x/etc/login.conf" ; then
+echo "   At runtime, sshd will use the path defined in $external_path_file"
+echo "   Make sure the path to scp is present, otherwise scp will not work"
+else
+echo "            sshd default user PATH: $I"
+       if test ! -z "$external_path_file"; then
+echo "   (If PATH is set in $external_path_file it will be used instead. If"
+echo "   used, ensure the path to scp is present, otherwise scp will not work.)"
+       fi
+fi
+if test ! -z "$superuser_path" ; then
+echo "          sshd superuser user PATH: $J"
+fi
+echo "                    Manpage format: $MANTYPE"
+echo "                       PAM support: $PAM_MSG"
+echo "                   OSF SIA support: $SIA_MSG"
+echo "                 KerberosV support: $KRB5_MSG"
+echo "                   SELinux support: $SELINUX_MSG"
+echo "                 Smartcard support: $SCARD_MSG"
+echo "                     S/KEY support: $SKEY_MSG"
+echo "              TCP Wrappers support: $TCPW_MSG"
+echo "              MD5 password support: $MD5_MSG"
+echo "                   libedit support: $LIBEDIT_MSG"
+echo "  Solaris process contract support: $SPC_MSG"
+echo "           Solaris project support: $SP_MSG"
+echo "       IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
+echo "           Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
+echo "                  BSD Auth support: $BSD_AUTH_MSG"
+echo "              Random number source: $RAND_MSG"
+if test ! -z "$USE_RAND_HELPER" ; then
+echo "     ssh-rand-helper collects from: $RAND_HELPER_MSG"
+fi
+
+echo ""
+
+echo "              Host: ${host}"
+echo "          Compiler: ${CC}"
+echo "    Compiler flags: ${CFLAGS}"
+echo "Preprocessor flags: ${CPPFLAGS}"
+echo "      Linker flags: ${LDFLAGS}"
+echo "         Libraries: ${LIBS}"
+if test ! -z "${SSHDLIBS}"; then
+echo "         +for sshd: ${SSHDLIBS}"
+fi
+if test ! -z "${SSHLIBS}"; then
+echo "          +for ssh: ${SSHLIBS}"
+fi
+
+echo ""
+
+if test "x$MAKE_PACKAGE_SUPPORTED" = "xyes" ; then
+       echo "SVR4 style packages are supported with \"make package\""
+       echo ""
+fi
+
+if test "x$PAM_MSG" = "xyes" ; then
+       echo "PAM is enabled. You may need to install a PAM control file "
+       echo "for sshd, otherwise password authentication may fail. "
+       echo "Example PAM control files can be found in the contrib/ "
+       echo "subdirectory"
+       echo ""
+fi
+
+if test ! -z "$RAND_HELPER_CMDHASH" ; then
+       echo "WARNING: you are using the builtin random number collection "
+       echo "service. Please read WARNING.RNG and request that your OS "
+       echo "vendor includes kernel-based random number collection in "
+       echo "future versions of your OS."
+       echo ""
+fi
+
+if test ! -z "$NO_PEERCHECK" ; then
+       echo "WARNING: the operating system that you are using does not"
+       echo "appear to support getpeereid(), getpeerucred() or the"
+       echo "SO_PEERCRED getsockopt() option. These facilities are used to"
+       echo "enforce security checks to prevent unauthorised connections to"
+       echo "ssh-agent. Their absence increases the risk that a malicious"
+       echo "user can connect to your agent."
+       echo ""
+fi
+
+if test "$AUDIT_MODULE" = "bsm" ; then
+       echo "WARNING: BSM audit support is currently considered EXPERIMENTAL."
+       echo "See the Solaris section in README.platform for details."
+fi
diff --git a/contrib/Makefile b/contrib/Makefile
new file mode 100644 (file)
index 0000000..8b34eb2
--- /dev/null
@@ -0,0 +1,15 @@
+all:
+       @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2"
+
+gnome-ssh-askpass1: gnome-ssh-askpass1.c
+       $(CC) `gnome-config --cflags gnome gnomeui` \
+               gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \
+               `gnome-config --libs gnome gnomeui`
+
+gnome-ssh-askpass2: gnome-ssh-askpass2.c
+       $(CC) `pkg-config --cflags gtk+-2.0` \
+               gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \
+               `pkg-config --libs gtk+-2.0 x11`
+
+clean:
+       rm -f *.o gnome-ssh-askpass1 gnome-ssh-askpass2 gnome-ssh-askpass
diff --git a/contrib/README b/contrib/README
new file mode 100644 (file)
index 0000000..c002238
--- /dev/null
@@ -0,0 +1,70 @@
+Other patches and addons for OpenSSH. Please send submissions to
+djm@mindrot.org
+
+Externally maintained
+---------------------
+
+SSH Proxy Command -- connect.c
+
+Shun-ichi GOTO <gotoh@imasy.or.jp> has written a very useful ProxyCommand
+which allows the use of outbound SSH from behind a SOCKS4, SOCKS5 or
+https CONNECT style proxy server. His page for connect.c has extensive
+documentation on its use as well as compiled versions for Win32.
+
+http://www.taiyo.co.jp/~gotoh/ssh/connect.html
+
+
+X11 SSH Askpass:
+
+Jim Knoble <jmknoble@pobox.com> has written an excellent X11
+passphrase requester. This is highly recommended:
+
+http://www.jmknoble.net/software/x11-ssh-askpass/
+
+
+In this directory
+-----------------
+
+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[12]:
+
+A GNOME and Gtk2 passphrase requesters. Use "make gnome-ssh-askpass1" or
+"make gnome-ssh-askpass2" to build.
+
+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>
+
+findssl.sh:
+
+Search for all instances of OpenSSL headers and libraries and print their 
+versions.  This is intended to help diagnose OpenSSH's "OpenSSL headers do not
+match your library" errors. 
+
+aix:
+    Files to build an AIX native (installp or SMIT installable) package.
+
+caldera:
+    RPM spec file and scripts for building Caldera OpenLinuix packages
+
+cygwin:
+    Support files for Cygwin
+
+hpux:
+    Support files for HP-UX
+
+redhat:
+    RPM spec file and scripts for building Redhat packages
+
+suse:
+    RPM spec file and scripts for building SuSE packages
+
diff --git a/contrib/aix/README b/contrib/aix/README
new file mode 100644 (file)
index 0000000..2a29935
--- /dev/null
@@ -0,0 +1,50 @@
+Overview:
+
+This directory contains files to build an AIX native (installp or SMIT
+installable) openssh package.
+
+
+Directions:
+
+(optional) create config.local in your build dir
+./configure [options]
+contrib/aix/buildbff.sh
+
+The file config.local or the environment is read to set the following options
+(default first):
+PERMIT_ROOT_LOGIN=[no|yes]
+X11_FORWARDING=[no|yes]
+AIX_SRC=[no|yes]
+
+Acknowledgements:
+
+The contents of this directory are based on Ben Lindstrom's Solaris
+buildpkg.sh. Ben also supplied inventory.sh.
+
+Jim Abbey's (GPL'ed) lppbuild-2.1 was used to learn how to build .bff's
+and for comparison with the output from this script, however no code
+from lppbuild is included and it is not required for operation.
+
+SRC support based on examples provided by Sandor Sklar and Maarten Kreuger.
+PrivSep account handling fixes contributed by W. Earl Allen.
+
+
+Other notes:
+
+The script treats all packages as USR packages (not ROOT+USR when
+appropriate).  It seems to work, though......
+
+If there are any patches to this that have not yet been integrated they
+may be found at http://www.zip.com.au/~dtucker/openssh/.
+
+
+Disclaimer:
+
+It is hoped that it is useful but there is no warranty. If it breaks
+you get to keep both pieces.
+
+
+       - Darren Tucker (dtucker at zip dot com dot au)
+         2002/03/01
+
+$Id: README,v 1.4 2003/08/25 05:01:04 dtucker Exp $
diff --git a/contrib/aix/buildbff.sh b/contrib/aix/buildbff.sh
new file mode 100755 (executable)
index 0000000..ca4bf02
--- /dev/null
@@ -0,0 +1,388 @@
+#!/bin/sh
+#
+# buildbff.sh: Create AIX SMIT-installable OpenSSH packages
+# $Id: buildbff.sh,v 1.12 2010/04/18 03:35:00 dtucker Exp $
+#
+# Author: Darren Tucker (dtucker at zip dot com dot au)
+# This file is placed in the public domain and comes with absolutely
+# no warranty.
+#
+# Based originally on Ben Lindstrom's buildpkg.sh for Solaris
+#
+
+#
+# Tunable configuration settings
+#      create a "config.local" in your build directory or set
+#      environment variables to override these.
+#
+[ -z "$PERMIT_ROOT_LOGIN" ] && PERMIT_ROOT_LOGIN=no
+[ -z "$X11_FORWARDING" ] && X11_FORWARDING=no
+[ -z "$AIX_SRC" ] && AIX_SRC=no
+
+umask 022
+
+startdir=`pwd`
+
+perl -v >/dev/null || (echo perl required; exit 1)
+
+# Path to inventory.sh: same place as buildbff.sh
+if  echo $0 | egrep '^/'
+then
+       inventory=`dirname $0`/inventory.sh             # absolute path
+else
+       inventory=`pwd`/`dirname $0`/inventory.sh       # relative path
+fi
+
+#
+# We still support running from contrib/aix, but this is deprecated
+#
+if pwd | egrep 'contrib/aix$'
+then
+       echo "Changing directory to `pwd`/../.."
+       echo "Please run buildbff.sh from your build directory in future."
+       cd ../..
+       contribaix=1
+fi
+
+if [ ! -f Makefile ]
+then
+       echo "Makefile not found (did you run configure?)"
+       exit 1
+fi
+
+#
+# Directories used during build:
+# current dir = $objdir                directory you ran ./configure in.
+# $objdir/$PKGDIR/             directory package files are constructed in
+# $objdir/$PKGDIR/root/                package root ($FAKE_ROOT)
+#
+objdir=`pwd`
+PKGNAME=openssh
+PKGDIR=package
+
+#
+# Collect local configuration settings to override defaults
+#
+if [ -s ./config.local ]
+then
+       echo Reading local settings from config.local
+       . ./config.local
+fi
+
+#
+# Fill in some details from Makefile, like prefix and sysconfdir
+#      the eval also expands variables like sysconfdir=${prefix}/etc
+#      provided they are eval'ed in the correct order
+#
+for confvar in prefix exec_prefix bindir sbindir libexecdir datadir mandir mansubdir sysconfdir piddir srcdir
+do
+       eval $confvar=`grep "^$confvar=" $objdir/Makefile | cut -d = -f 2`
+done
+
+#
+# Collect values of privsep user and privsep path
+#      currently only found in config.h
+#
+for confvar in SSH_PRIVSEP_USER PRIVSEP_PATH
+do
+       eval $confvar=`awk '/#define[ \t]'$confvar'/{print $3}' $objdir/config.h`
+done
+
+# Set privsep defaults if not defined
+if [ -z "$SSH_PRIVSEP_USER" ]
+then
+       SSH_PRIVSEP_USER=sshd
+fi
+if [ -z "$PRIVSEP_PATH" ]
+then
+       PRIVSEP_PATH=/var/empty
+fi
+
+# Clean package build directory
+rm -rf $objdir/$PKGDIR
+FAKE_ROOT=$objdir/$PKGDIR/root
+mkdir -p $FAKE_ROOT
+
+# Start by faking root install
+echo "Faking root install..."
+cd $objdir
+make install-nokeys DESTDIR=$FAKE_ROOT
+
+if [ $? -gt 0 ]
+then
+       echo "Fake root install failed, stopping."
+       exit 1
+fi
+
+#
+# Copy informational files to include in package
+#
+cp $srcdir/LICENCE $objdir/$PKGDIR/
+cp $srcdir/README* $objdir/$PKGDIR/
+
+#
+# Extract common info requires for the 'info' part of the package.
+#      AIX requires 4-part version numbers
+#
+VERSION=`./ssh -V 2>&1 | cut -f 1 -d , | cut -f 2 -d _`
+MAJOR=`echo $VERSION | cut -f 1 -d p | cut -f 1 -d .`
+MINOR=`echo $VERSION | cut -f 1 -d p | cut -f 2 -d .`
+PATCH=`echo $VERSION | cut -f 1 -d p | cut -f 3 -d .`
+PORTABLE=`echo $VERSION | awk 'BEGIN{FS="p"}{print $2}'`
+[ "$PATCH" = "" ] && PATCH=0
+[ "$PORTABLE" = "" ] && PORTABLE=0
+BFFVERSION=`printf "%d.%d.%d.%d" $MAJOR $MINOR $PATCH $PORTABLE`
+
+echo "Building BFF for $PKGNAME $VERSION (package version $BFFVERSION)"
+
+#
+# Set ssh and sshd parameters as per config.local
+#
+if [ "${PERMIT_ROOT_LOGIN}" = no ]
+then
+       perl -p -i -e "s/#PermitRootLogin yes/PermitRootLogin no/" \
+               $FAKE_ROOT/${sysconfdir}/sshd_config
+fi
+if [ "${X11_FORWARDING}" = yes ]
+then
+       perl -p -i -e "s/#X11Forwarding no/X11Forwarding yes/" \
+               $FAKE_ROOT/${sysconfdir}/sshd_config
+fi
+
+
+# Rename config files; postinstall script will copy them if necessary
+for cfgfile in ssh_config sshd_config
+do
+       mv $FAKE_ROOT/$sysconfdir/$cfgfile $FAKE_ROOT/$sysconfdir/$cfgfile.default
+done
+
+# AIX 5.3 and newer have /dev/random and don't create ssh_prng_cmds
+if [ -f $FAKE_ROOT/$sysconfdir/ssh_prng_cmds ]
+then
+       mv $FAKE_ROOT/$sysconfdir/ssh_prng_cmds \
+               $FAKE_ROOT/$sysconfdir/ssh_prng_cmds.default
+fi
+
+#
+# Generate lpp control files.
+#      working dir is $FAKE_ROOT but files are generated in dir above
+#      and moved into place just before creation of .bff
+#
+cd $FAKE_ROOT
+echo Generating LPP control files
+find . ! -name . -print >../openssh.al
+$inventory >../openssh.inventory
+
+cat <<EOD >../openssh.copyright
+This software is distributed under a BSD-style license.
+For the full text of the license, see /usr/lpp/openssh/LICENCE
+EOD
+
+#
+# openssh.size file allows filesystem expansion as required
+# generate list of directories containing files
+# then calculate disk usage for each directory and store in openssh.size
+#
+files=`find . -type f -print`
+dirs=`for file in $files; do dirname $file; done | sort -u`
+for dir in $dirs
+do
+       du $dir
+done > ../openssh.size
+
+#
+# Create postinstall script
+#
+cat <<EOF >>../openssh.post_i
+#!/bin/sh
+
+echo Creating configs from defaults if necessary.
+for cfgfile in ssh_config sshd_config ssh_prng_cmds
+do
+       if [ ! -f $sysconfdir/\$cfgfile ]
+       then
+               echo "Creating \$cfgfile from default"
+               cp $sysconfdir/\$cfgfile.default $sysconfdir/\$cfgfile
+       else
+               echo "\$cfgfile already exists."
+       fi
+done
+echo
+
+# Create PrivilegeSeparation user and group if not present
+echo Checking for PrivilegeSeparation user and group.
+if cut -f1 -d: /etc/group | egrep '^'$SSH_PRIVSEP_USER'\$' >/dev/null
+then
+       echo "PrivSep group $SSH_PRIVSEP_USER already exists."
+else
+       echo "Creating PrivSep group $SSH_PRIVSEP_USER."
+       mkgroup -A $SSH_PRIVSEP_USER
+fi
+
+# Create user if required
+if lsuser "$SSH_PRIVSEP_USER" >/dev/null
+then
+       echo "PrivSep user $SSH_PRIVSEP_USER already exists."
+else
+       echo "Creating PrivSep user $SSH_PRIVSEP_USER."
+       mkuser gecos='SSHD PrivSep User' login=false rlogin=false account_locked=true pgrp=$SSH_PRIVSEP_USER $SSH_PRIVSEP_USER
+fi
+
+if egrep '^[ \t]*UsePrivilegeSeparation[ \t]+no' $sysconfdir/sshd_config >/dev/null
+then
+       echo UsePrivilegeSeparation not enabled, privsep directory not required.
+else
+       # create chroot directory if required
+       if [ -d $PRIVSEP_PATH ]
+       then
+               echo "PrivSep chroot directory $PRIVSEP_PATH already exists."
+       else
+               echo "Creating PrivSep chroot directory $PRIVSEP_PATH."
+               mkdir $PRIVSEP_PATH
+               chown 0 $PRIVSEP_PATH
+               chgrp 0 $PRIVSEP_PATH
+               chmod 755 $PRIVSEP_PATH
+       fi
+fi
+echo
+
+# Generate keys unless they already exist
+echo Creating host keys if required.
+if [ -f "$sysconfdir/ssh_host_key" ] ; then
+       echo "$sysconfdir/ssh_host_key already exists, skipping."
+else
+       $bindir/ssh-keygen -t rsa1 -f $sysconfdir/ssh_host_key -N ""
+fi
+if [ -f $sysconfdir/ssh_host_dsa_key ] ; then
+       echo "$sysconfdir/ssh_host_dsa_key already exists, skipping."
+else
+       $bindir/ssh-keygen -t dsa -f $sysconfdir/ssh_host_dsa_key -N ""
+fi
+if [ -f $sysconfdir/ssh_host_rsa_key ] ; then
+       echo "$sysconfdir/ssh_host_rsa_key already exists, skipping."
+else
+       $bindir/ssh-keygen -t rsa -f $sysconfdir/ssh_host_rsa_key -N ""
+fi
+echo
+
+# Set startup command depending on SRC support
+if [ "$AIX_SRC" = "yes" ]
+then
+       echo Creating SRC sshd subsystem.
+       rmssys -s sshd 2>&1 >/dev/null
+       mkssys -s sshd -p "$sbindir/sshd" -a '-D' -u 0 -S -n 15 -f 9 -R -G tcpip
+       startupcmd="start $sbindir/sshd \\\"\\\$src_running\\\""
+       oldstartcmd="$sbindir/sshd"
+else
+       startupcmd="$sbindir/sshd"
+       oldstartcmd="start $sbindir/sshd \\\"$src_running\\\""
+fi
+
+# If migrating to or from SRC, change previous startup command
+# otherwise add to rc.tcpip
+if egrep "^\$oldstartcmd" /etc/rc.tcpip >/dev/null
+then
+       if sed "s|^\$oldstartcmd|\$startupcmd|g" /etc/rc.tcpip >/etc/rc.tcpip.new
+       then
+               chmod 0755 /etc/rc.tcpip.new
+               mv /etc/rc.tcpip /etc/rc.tcpip.old && \
+               mv /etc/rc.tcpip.new /etc/rc.tcpip
+       else
+               echo "Updating /etc/rc.tcpip failed, please check."
+       fi
+else
+       # Add to system startup if required
+       if grep "^\$startupcmd" /etc/rc.tcpip >/dev/null
+       then
+               echo "sshd found in rc.tcpip, not adding."
+       else
+               echo "Adding sshd to rc.tcpip"
+               echo >>/etc/rc.tcpip
+               echo "# Start sshd" >>/etc/rc.tcpip
+               echo "\$startupcmd" >>/etc/rc.tcpip
+       fi
+fi
+EOF
+
+#
+# Create liblpp.a and move control files into it
+#
+echo Creating liblpp.a
+(
+       cd ..
+       for i in openssh.al openssh.copyright openssh.inventory openssh.post_i openssh.size LICENCE README*
+       do
+               ar -r liblpp.a $i
+               rm $i
+       done
+)
+
+#
+# Create lpp_name
+#
+# This will end up looking something like:
+# 4 R I OpenSSH {
+# OpenSSH 3.0.2.1 1 N U en_US OpenSSH 3.0.2p1 Portable for AIX
+# [
+# %
+# /usr/local/bin 8073
+# /usr/local/etc 189
+# /usr/local/libexec 185
+# /usr/local/man/man1 145
+# /usr/local/man/man8 83
+# /usr/local/sbin 2105
+# /usr/local/share 3
+# %
+# ]
+# }
+
+echo Creating lpp_name
+cat <<EOF >../lpp_name
+4 R I $PKGNAME {
+$PKGNAME $BFFVERSION 1 N U en_US OpenSSH $VERSION Portable for AIX
+[
+%
+EOF
+
+for i in $bindir $sysconfdir $libexecdir $mandir/${mansubdir}1 $mandir/${mansubdir}8 $sbindir $datadir /usr/lpp/openssh
+do
+       # get size in 512 byte blocks
+       if [ -d $FAKE_ROOT/$i ]
+       then
+               size=`du $FAKE_ROOT/$i | awk '{print $1}'`
+               echo "$i $size" >>../lpp_name
+       fi
+done
+
+echo '%' >>../lpp_name
+echo ']' >>../lpp_name
+echo '}' >>../lpp_name
+
+#
+# Move pieces into place
+#
+mkdir -p usr/lpp/openssh
+mv ../liblpp.a usr/lpp/openssh
+mv ../lpp_name .
+
+#
+# Now invoke backup to create .bff file
+#      note: lpp_name needs to be the first file so we generate the
+#      file list on the fly and feed it to backup using -i
+#
+echo Creating $PKGNAME-$VERSION.bff with backup...
+rm -f $PKGNAME-$VERSION.bff
+(
+       echo "./lpp_name"
+       find . ! -name lpp_name -a ! -name . -print
+) | backup  -i -q -f ../$PKGNAME-$VERSION.bff $filelist
+
+#
+# Move package into final location and clean up
+#
+mv ../$PKGNAME-$VERSION.bff $startdir
+cd $startdir
+rm -rf $objdir/$PKGDIR
+
+echo $0: done.
+
diff --git a/contrib/aix/inventory.sh b/contrib/aix/inventory.sh
new file mode 100755 (executable)
index 0000000..e2641e7
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# inventory.sh
+# $Id: inventory.sh,v 1.6 2003/11/21 12:48:56 djm Exp $
+#
+# Originally written by Ben Lindstrom, modified by Darren Tucker to use perl
+# This file is placed into the public domain.
+#
+# This will produce an AIX package inventory file, which looks like:
+#
+# /usr/local/bin:
+#          class=apply,inventory,openssh
+#          owner=root
+#          group=system
+#          mode=755
+#          type=DIRECTORY
+# /usr/local/bin/slogin:
+#          class=apply,inventory,openssh
+#          owner=root
+#          group=system
+#          mode=777
+#          type=SYMLINK
+#          target=ssh
+# /usr/local/share/Ssh.bin:
+#          class=apply,inventory,openssh
+#          owner=root
+#          group=system
+#          mode=644
+#          type=FILE
+#          size=VOLATILE
+#          checksum=VOLATILE
+
+find . ! -name . -print | perl -ne '{
+       chomp;
+       if ( -l $_ ) {
+               ($dev,$ino,$mod,$nl,$uid,$gid,$rdev,$sz,$at,$mt,$ct,$bsz,$blk)=lstat;
+       } else {
+               ($dev,$ino,$mod,$nl,$uid,$gid,$rdev,$sz,$at,$mt,$ct,$bsz,$blk)=stat;
+       }
+
+       # Start to display inventory information
+       $name = $_;
+       $name =~ s|^.||;        # Strip leading dot from path
+       print "$name:\n";
+       print "\tclass=apply,inventory,openssh\n";
+       print "\towner=root\n";
+       print "\tgroup=system\n";
+       printf "\tmode=%lo\n", $mod & 07777;    # Mask perm bits
+       
+       if ( -l $_ ) {
+               # Entry is SymLink
+               print "\ttype=SYMLINK\n";
+               printf "\ttarget=%s\n", readlink($_);
+       } elsif ( -f $_ ) {
+               # Entry is File
+               print "\ttype=FILE\n";
+               print "\tsize=$sz\n";
+               print "\tchecksum=VOLATILE\n";
+       } elsif ( -d $_ ) {
+               # Entry is Directory
+               print "\ttype=DIRECTORY\n";
+       }
+}'
diff --git a/contrib/aix/pam.conf b/contrib/aix/pam.conf
new file mode 100644 (file)
index 0000000..f1528b0
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# PAM configuration file /etc/pam.conf
+# Example for OpenSSH on AIX 5.2
+#
+
+# Authentication Management
+sshd    auth            required        /usr/lib/security/pam_aix
+OTHER   auth            required        /usr/lib/security/pam_aix
+
+# Account Management
+sshd    account         required        /usr/lib/security/pam_aix
+OTHER   account         required        /usr/lib/security/pam_aix
+
+# Password Management
+sshd    password        required        /usr/lib/security/pam_aix
+OTHER   password        required        /usr/lib/security/pam_aix
+
+# Session Management
+sshd    session         required        /usr/lib/security/pam_aix
+OTHER   session         required        /usr/lib/security/pam_aix
diff --git a/contrib/caldera/openssh.spec b/contrib/caldera/openssh.spec
new file mode 100644 (file)
index 0000000..435003a
--- /dev/null
@@ -0,0 +1,366 @@
+
+# Some of this will need re-evaluation post-LSB.  The SVIdir is there
+# because the link appeared broken.  The rest is for easy compilation,
+# the tradeoff open to discussion.  (LC957)
+
+%define        SVIdir          /etc/rc.d/init.d
+%{!?_defaultdocdir:%define     _defaultdocdir  %{_prefix}/share/doc/packages}
+%{!?SVIcdir:%define            SVIcdir         /etc/sysconfig/daemons}
+
+%define _mandir                %{_prefix}/share/man/en
+%define _sysconfdir    /etc/ssh
+%define        _libexecdir     %{_libdir}/ssh
+
+# Do we want to disable root_login? (1=yes 0=no)
+%define no_root_login 0
+
+#old cvs stuff.  please update before use.  may be deprecated.
+%define use_stable     1
+%define version        5.8p1
+%if %{use_stable}
+  %define cvs          %{nil}
+  %define release      1
+%else
+  %define cvs          cvs20050315
+  %define release      0r1
+%endif
+%define xsa            x11-ssh-askpass         
+%define askpass                %{xsa}-1.2.4.1
+
+# OpenSSH privilege separation requires a user & group ID
+%define sshd_uid    67
+%define sshd_gid    67
+
+Name           : openssh
+Version        : %{version}%{cvs}
+Release        : %{release}
+Group          : System/Network
+
+Summary        : OpenSSH free Secure Shell (SSH) implementation.
+Summary(de)    : OpenSSH - freie Implementation der Secure Shell (SSH).
+Summary(es)    : OpenSSH implementación libre de Secure Shell (SSH).
+Summary(fr)    : Implémentation libre du shell sécurisé OpenSSH (SSH).
+Summary(it)    : Implementazione gratuita OpenSSH della Secure Shell.
+Summary(pt)    : Implementação livre OpenSSH do protocolo 'Secure Shell' (SSH).
+Summary(pt_BR)         : Implementação livre OpenSSH do protocolo Secure Shell (SSH).
+
+Copyright      : BSD
+Packager       : Raymund Will <ray@caldera.de>
+URL            : http://www.openssh.com/
+
+Obsoletes      : ssh, ssh-clients, openssh-clients
+
+BuildRoot      : /tmp/%{name}-%{version}
+BuildRequires  : XFree86-imake
+
+# %{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.asc
+%endif
+Source2: http://www.jmknoble.net/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).
+Summary(de)    : OpenSSH Secure Shell Protocol-Server (sshd).
+Summary(es)    : Servidor del protocolo OpenSSH Secure Shell (sshd).
+Summary(fr)    : Serveur de protocole du shell sécurisé OpenSSH (sshd).
+Summary(it)    : Server OpenSSH per il protocollo Secure Shell (sshd).
+Summary(pt)    : Servidor do protocolo 'Secure Shell' OpenSSH (sshd).
+Summary(pt_BR)         : Servidor do protocolo Secure Shell OpenSSH (sshd).
+
+
+%Package askpass
+Group          : System/Network
+Requires       : openssh = %{version}
+URL            : http://www.jmknoble.net/software/x11-ssh-askpass/
+Obsoletes      : ssh-extras
+
+Summary        : OpenSSH X11 pass-phrase dialog.
+Summary(de)    : OpenSSH X11 Passwort-Dialog.
+Summary(es)    : Aplicación de petición de frase clave OpenSSH X11.
+Summary(fr)    : Dialogue pass-phrase X11 d'OpenSSH.
+Summary(it)    : Finestra di dialogo X11 per la frase segreta di OpenSSH.
+Summary(pt)    : Diálogo de pedido de senha para X11 do OpenSSH.
+Summary(pt_BR)         : Diálogo de pedido de senha para X11 do OpenSSH.
+
+
+%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 -l de
+OpenSSH (Secure Shell) stellt den Zugang zu anderen Rechnern her. Es ersetzt
+telnet, rlogin, rexec und rsh und stellt eine sichere, verschlüsselte
+Verbindung zwischen zwei nicht vertrauenswürdigen Hosts Ã¼ber eine unsicheres
+Netzwerk her. X11 Verbindungen und beliebige andere TCP/IP Ports können ebenso
+über den sicheren Channel weitergeleitet werden.
+
+%Description -l es
+OpenSSH (Secure Shell) proporciona acceso a sistemas remotos. Reemplaza a
+telnet, rlogin, rexec, y rsh, y proporciona comunicaciones seguras encriptadas
+entre dos equipos entre los que no se ha establecido confianza a través de una
+red insegura. Las conexiones X11 y puertos TCP/IP arbitrarios también pueden
+ser canalizadas sobre el canal seguro.
+
+%Description -l fr
+OpenSSH (Secure Shell) fournit un accès Ã  un système distant. Il remplace
+telnet, rlogin, rexec et rsh, tout en assurant des communications cryptées
+securisées entre deux hôtes non fiabilisés sur un réseau non sécurisé. Des
+connexions X11 et des ports TCP/IP arbitraires peuvent Ã©galement Ãªtre
+transmis sur le canal sécurisé.
+
+%Description -l it
+OpenSSH (Secure Shell) fornisce l'accesso ad un sistema remoto.
+Sostituisce telnet, rlogin, rexec, e rsh, e fornisce comunicazioni sicure
+e crittate tra due host non fidati su una rete non sicura. Le connessioni
+X11 ad una porta TCP/IP arbitraria possono essere inoltrate attraverso
+un canale sicuro.
+
+%Description -l pt
+OpenSSH (Secure Shell) fornece acesso a um sistema remoto. Substitui o
+telnet, rlogin, rexec, e o rsh e fornece comunicações seguras e cifradas
+entre duas máquinas sem confiança mútua sobre uma rede insegura.
+Ligações X11 e portos TCP/IP arbitrários também poder ser reenviados
+pelo canal seguro.
+
+%Description -l pt_BR
+O OpenSSH (Secure Shell) fornece acesso a um sistema remoto. Substitui o
+telnet, rlogin, rexec, e o rsh e fornece comunicações seguras e criptografadas
+entre duas máquinas sem confiança mútua sobre uma rede insegura.
+Ligações X11 e portas TCP/IP arbitrárias também podem ser reenviadas
+pelo canal seguro.
+
+%Description server
+This package installs the sshd, the server portion of OpenSSH. 
+
+%Description -l de server
+Dieses Paket installiert den sshd, den Server-Teil der OpenSSH.
+
+%Description -l es server
+Este paquete instala sshd, la parte servidor de OpenSSH.
+
+%Description -l fr server
+Ce paquetage installe le 'sshd', partie serveur de OpenSSH.
+
+%Description -l it server
+Questo pacchetto installa sshd, il server di OpenSSH.
+
+%Description -l pt server
+Este pacote intala o sshd, o servidor do OpenSSH.
+
+%Description -l pt_BR server
+Este pacote intala o sshd, o servidor do 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>.
+
+
+%Prep
+%setup %([ -z "%{cvs}" ] || echo "-n %{name}_cvs") -a2
+%if ! %{use_stable}
+  autoreconf
+%endif
+
+
+%Build
+CFLAGS="$RPM_OPT_FLAGS" \
+%configure \
+            --with-pam \
+            --with-tcp-wrappers \
+           --with-privsep-path=%{_var}/empty/sshd \
+           #leave this line for easy edits.
+
+%__make
+
+cd %{askpass}
+%configure \
+           #leave this line for easy edits.
+
+xmkmf
+%__make includes
+%__make
+
+
+%Install
+[ %{buildroot} != "/" ] && rm -rf %{buildroot}
+
+make install DESTDIR=%{buildroot}
+%makeinstall -C %{askpass} \
+    BINDIR=%{_libexecdir} \
+    MANPATH=%{_mandir} \
+    DESTDIR=%{buildroot}
+
+# OpenLinux specific configuration
+mkdir -p %{buildroot}{/etc/pam.d,%{SVIcdir},%{SVIdir}}
+mkdir -p %{buildroot}%{_var}/empty/sshd
+
+# enabling X11 forwarding on the server is convenient and okay,
+# on the client side it's a potential security risk!
+%__perl -pi -e 's:#X11Forwarding no:X11Forwarding yes:g' \
+    %{buildroot}%{_sysconfdir}/sshd_config
+
+%if %{no_root_login}
+%__perl -pi -e 's:#PermitRootLogin yes:PermitRootLogin no:g' \
+    %{buildroot}%{_sysconfdir}/sshd_config
+%endif
+
+install -m644 contrib/caldera/sshd.pam %{buildroot}/etc/pam.d/sshd
+# FIXME: disabled, find out why this doesn't work with nis
+%__perl -pi -e 's:(.*pam_limits.*):#$1:' \
+    %{buildroot}/etc/pam.d/sshd
+
+install -m 0755 contrib/caldera/sshd.init %{buildroot}%{SVIdir}/sshd
+
+# the last one is needless, but more future-proof
+find %{buildroot}%{SVIdir} -type f -exec \
+    %__perl -pi -e 's:\@SVIdir\@:%{SVIdir}:g;\
+                   s:\@sysconfdir\@:%{_sysconfdir}:g; \
+                   s:/usr/sbin:%{_sbindir}:g'\
+    \{\} \;
+
+cat <<-EoD > %{buildroot}%{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=%{buildroot}%{_sbindir}/ssh-host-keygen
+install -m 0755 contrib/caldera/ssh-host-keygen $SKG
+# Fix up some path names in the keygen toy^Hol
+    %__perl -pi -e 's:\@sysconfdir\@:%{_sysconfdir}:g; \
+                   s:\@sshkeygen\@:%{_bindir}/ssh-keygen:g' \
+       %{buildroot}%{_sbindir}/ssh-host-keygen
+
+# This looks terrible.  Expect it to change.
+# install remaining docs
+DocD="%{buildroot}%{_defaultdocdir}/%{name}-%{version}"
+mkdir -p $DocD/%{askpass}
+cp -a CREDITS ChangeLog LICENCE OVERVIEW README* TODO PROTOCOL* $DocD
+install -p -m 0444 %{SOURCE3}  $DocD/faq.html
+cp -a %{askpass}/{README,ChangeLog,TODO,SshAskpass*.ad}  $DocD/%{askpass}
+%if %{use_stable}
+  cp -p %{askpass}/%{xsa}.man $DocD/%{askpass}/%{xsa}.1
+%else
+  cp -p %{askpass}/%{xsa}.man %{buildroot}%{_mandir}man1/%{xsa}.1
+  ln -s  %{xsa}.1 %{buildroot}%{_mandir}man1/ssh-askpass.1
+%endif
+
+find %{buildroot}%{_mandir} -type f -not -name '*.gz' -print0 | xargs -0r %__gzip -9nf
+rm %{buildroot}%{_mandir}/man1/slogin.1 && \
+    ln -s %{_mandir}/man1/ssh.1.gz \
+    %{buildroot}%{_mandir}/man1/slogin.1.gz
+
+
+%Clean
+#%{rmDESTDIR}
+[ %{buildroot} != "/" ] && rm -rf %{buildroot}
+
+%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
+
+%pre server
+%{_sbindir}/groupadd -g %{sshd_gid} sshd 2>/dev/null || :
+%{_sbindir}/useradd -d /var/empty/sshd -s /bin/false -u %{sshd_uid} \
+       -c "SSH Daemon virtual user" -g sshd sshd 2>/dev/null || :
+: # to protect the rpm database
+
+%Post server
+if [ -x %{LSBinit}-install ]; then
+  %{LSBinit}-install sshd
+else
+  lisa --SysV-init install sshd S55 2:3:4:5 K45 0:1: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
+if [ -x %{LSBinit}-remove ]; then
+  %{LSBinit}-remove sshd
+else
+  lisa --SysV-init remove sshd $1
+fi
+: # to protect the rpm database
+
+%Files 
+%defattr(-,root,root)
+%dir %{_sysconfdir}
+%config %{_sysconfdir}/ssh_config
+%{_bindir}/scp
+%{_bindir}/sftp
+%{_bindir}/ssh
+%{_bindir}/slogin
+%{_bindir}/ssh-add
+%attr(2755,root,nobody) %{_bindir}/ssh-agent
+%{_bindir}/ssh-keygen
+%{_bindir}/ssh-keyscan
+%dir %{_libexecdir}
+%attr(4711,root,root) %{_libexecdir}/ssh-keysign
+%{_libexecdir}/ssh-pkcs11-helper
+%{_sbindir}/ssh-host-keygen
+%dir %{_defaultdocdir}/%{name}-%{version}
+%{_defaultdocdir}/%{name}-%{version}/CREDITS
+%{_defaultdocdir}/%{name}-%{version}/ChangeLog
+%{_defaultdocdir}/%{name}-%{version}/LICENCE
+%{_defaultdocdir}/%{name}-%{version}/OVERVIEW
+%{_defaultdocdir}/%{name}-%{version}/README*
+%{_defaultdocdir}/%{name}-%{version}/TODO
+%{_defaultdocdir}/%{name}-%{version}/faq.html
+%{_mandir}/man1/*
+%{_mandir}/man8/ssh-keysign.8.gz
+%{_mandir}/man8/ssh-pkcs11-helper.8.gz
+%{_mandir}/man5/ssh_config.5.gz
+%Files server
+%defattr(-,root,root)
+%dir %{_var}/empty/sshd
+%config %{SVIdir}/sshd
+%config /etc/pam.d/sshd
+%config %{_sysconfdir}/moduli
+%config %{_sysconfdir}/sshd_config
+%config %{SVIcdir}/sshd
+%{_libexecdir}/sftp-server
+%{_sbindir}/sshd
+%{_mandir}/man5/moduli.5.gz
+%{_mandir}/man5/sshd_config.5.gz
+%{_mandir}/man8/sftp-server.8.gz
+%{_mandir}/man8/sshd.8.gz
+%Files askpass
+%defattr(-,root,root)
+%{_libexecdir}/ssh-askpass
+%{_libexecdir}/x11-ssh-askpass
+%{_defaultdocdir}/%{name}-%{version}/%{askpass}
+
+%ChangeLog
+* Tue Jan 18 2011 Tim Rice <tim@multitalents.net>
+- Use CFLAGS from Makefile instead of RPM so build completes.
+- Signatures were changed to .asc since 4.1p1.
+
+* Mon Jan 01 1998 ...
+Template Version: 1.31
+
+$Id: openssh.spec,v 1.73.4.1 2011/02/04 00:57:54 djm Exp $
diff --git a/contrib/caldera/ssh-host-keygen b/contrib/caldera/ssh-host-keygen
new file mode 100755 (executable)
index 0000000..86382dd
--- /dev/null
@@ -0,0 +1,36 @@
+#! /bin/sh
+#
+# $Id: ssh-host-keygen,v 1.3 2008/11/03 09:16:01 djm Exp $
+#
+# 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 SSH1 RSA host key."
+  $keygen -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 SSH2 RSA host key."
+  $keygen -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/contrib/caldera/sshd.init b/contrib/caldera/sshd.init
new file mode 100755 (executable)
index 0000000..983146f
--- /dev/null
@@ -0,0 +1,125 @@
+#! /bin/bash
+#
+# $Id: sshd.init,v 1.4 2003/11/21 12:48:57 djm Exp $
+#
+### 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/contrib/caldera/sshd.pam b/contrib/caldera/sshd.pam
new file mode 100644 (file)
index 0000000..f050a9a
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_pwdb.so shadow nodelay
+account    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/contrib/cygwin/Makefile b/contrib/cygwin/Makefile
new file mode 100644 (file)
index 0000000..dc857f2
--- /dev/null
@@ -0,0 +1,78 @@
+srcdir=../..
+copyidsrcdir=..
+prefix=/usr
+exec_prefix=$(prefix)
+bindir=$(prefix)/bin
+datadir=$(prefix)/share
+mandir=$(datadir)/man
+docdir=$(datadir)/doc
+sshdocdir=$(docdir)/openssh
+cygdocdir=$(docdir)/Cygwin
+sysconfdir=/etc
+defaultsdir=$(sysconfdir)/defaults/etc
+inetdefdir=$(defaultsdir)/inetd.d
+PRIVSEP_PATH=/var/empty
+INSTALL=/usr/bin/install -c
+
+DESTDIR=
+
+all:
+       @echo
+       @echo "Use \`make cygwin-postinstall DESTDIR=[package directory]'"
+       @echo "Be sure having DESTDIR set correctly!"
+       @echo
+
+move-config-files: $(DESTDIR)$(sysconfdir)/ssh_config $(DESTDIR)$(sysconfdir)/sshd_config
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(defaultsdir)
+       mv $(DESTDIR)$(sysconfdir)/ssh_config $(DESTDIR)$(defaultsdir)
+       mv $(DESTDIR)$(sysconfdir)/sshd_config $(DESTDIR)$(defaultsdir)
+
+remove-empty-dir:
+       rm -rf $(DESTDIR)$(PRIVSEP_PATH)
+
+install-inetd-config:
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(inetdefdir)
+       $(INSTALL) -m 644 sshd-inetd  $(DESTDIR)$(inetdefdir)/sshd-inetd
+
+install-sshdoc:
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(sshdocdir)
+       $(INSTALL) -m 644 $(srcdir)/CREDITS $(DESTDIR)$(sshdocdir)/CREDITS
+       $(INSTALL) -m 644 $(srcdir)/ChangeLog $(DESTDIR)$(sshdocdir)/ChangeLog
+       $(INSTALL) -m 644 $(srcdir)/LICENCE $(DESTDIR)$(sshdocdir)/LICENCE
+       $(INSTALL) -m 644 $(srcdir)/OVERVIEW $(DESTDIR)$(sshdocdir)/OVERVIEW
+       $(INSTALL) -m 644 $(srcdir)/PROTOCOL $(DESTDIR)$(sshdocdir)/PROTOCOL
+       $(INSTALL) -m 644 $(srcdir)/PROTOCOL.agent $(DESTDIR)$(sshdocdir)/PROTOCOL.agent
+       $(INSTALL) -m 644 $(srcdir)/PROTOCOL.certkeys $(DESTDIR)$(sshdocdir)/PROTOCOL.certkeys
+       $(INSTALL) -m 644 $(srcdir)/PROTOCOL.mux $(DESTDIR)$(sshdocdir)/PROTOCOL.mux
+       $(INSTALL) -m 644 $(srcdir)/README $(DESTDIR)$(sshdocdir)/README
+       $(INSTALL) -m 644 $(srcdir)/README.dns $(DESTDIR)$(sshdocdir)/README.dns
+       $(INSTALL) -m 644 $(srcdir)/README.platform $(DESTDIR)$(sshdocdir)/README.platform
+       $(INSTALL) -m 644 $(srcdir)/README.privsep $(DESTDIR)$(sshdocdir)/README.privsep
+       $(INSTALL) -m 644 $(srcdir)/README.tun $(DESTDIR)$(sshdocdir)/README.tun
+       $(INSTALL) -m 644 $(srcdir)/TODO $(DESTDIR)$(sshdocdir)/TODO
+       $(INSTALL) -m 644 $(srcdir)/WARNING.RNG $(DESTDIR)$(sshdocdir)/WARNING.RNG
+
+install-cygwindoc: README
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(cygdocdir)
+       $(INSTALL) -m 644 README $(DESTDIR)$(cygdocdir)/openssh.README
+
+install-doc: install-sshdoc install-cygwindoc
+
+install-scripts: ssh-host-config ssh-user-config
+       $(srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(INSTALL) -m 755 ssh-host-config $(DESTDIR)$(bindir)/ssh-host-config
+       $(INSTALL) -m 755 ssh-user-config $(DESTDIR)$(bindir)/ssh-user-config
+
+install-copy-id: $(copyidsrcdir)/ssh-copy-id $(copyidsrcdir)/ssh-copy-id.1
+       $(INSTALL) -m 755 $(copyidsrcdir)/ssh-copy-id $(DESTDIR)$(bindir)/ssh-copy-id
+       $(INSTALL) -m 644 $(copyidsrcdir)/ssh-copy-id.1 $(DESTDIR)$(mandir)/man1/ssh-copy-id.1
+
+gzip-man-pages:
+       rm $(DESTDIR)$(mandir)/man1/slogin.1
+       gzip $(DESTDIR)$(mandir)/man1/*.1
+       gzip $(DESTDIR)$(mandir)/man5/*.5
+       gzip $(DESTDIR)$(mandir)/man8/*.8
+       cd $(DESTDIR)$(mandir)/man1 && ln -s ssh.1.gz slogin.1.gz
+
+cygwin-postinstall: move-config-files remove-empty-dir install-inetd-config install-doc install-scripts install-copy-id gzip-man-pages
+       @echo "Cygwin specific configuration finished."
diff --git a/contrib/cygwin/README b/contrib/cygwin/README
new file mode 100644 (file)
index 0000000..5f911e9
--- /dev/null
@@ -0,0 +1,237 @@
+This package describes important Cygwin specific stuff concerning OpenSSH.
+
+The binary package is usually built for recent Cygwin versions and might
+not run on older versions.  Please check http://cygwin.com/ for information
+about current Cygwin releases.
+
+Build instructions are at the end of the file.
+
+===========================================================================
+Important change since 3.7.1p2-2:
+
+The ssh-host-config file doesn't create the /etc/ssh_config and
+/etc/sshd_config files from builtin here-scripts anymore, but it uses
+skeleton files installed in /etc/defaults/etc.
+
+Also it now tries hard to create appropriate permissions on files.
+Same applies for ssh-user-config.
+
+After creating the sshd service with ssh-host-config, it's advisable to
+call ssh-user-config for all affected users, also already exising user
+configurations.  In the latter case, file and directory permissions are
+checked and changed, if requireed to match the host configuration.
+
+Important note for Windows 2003 Server users:
+---------------------------------------------
+
+2003 Server has a funny new feature.  When starting services under SYSTEM
+account, these services have nearly all user rights which SYSTEM holds...
+except for the "Create a token object" right, which is needed to allow
+public key authentication :-(
+
+There's no way around this, except for creating a substitute account which
+has the appropriate privileges.  Basically, this account should be member
+of the administrators group, plus it should have the following user rights:
+
+       Create a token object
+       Logon as a service
+       Replace a process level token
+       Increase Quota
+
+The ssh-host-config script asks you, if it should create such an account,
+called "sshd_server".  If you say "no" here, you're on your own.  Please
+follow the instruction in ssh-host-config exactly if possible.  Note that
+ssh-user-config sets the permissions on 2003 Server machines dependent of
+whether a sshd_server account exists or not.
+===========================================================================
+
+===========================================================================
+Important change since 3.4p1-2:
+
+This version adds privilege separation as default setting, see
+/usr/doc/openssh/README.privsep.  According to that document the
+privsep feature requires a non-privileged account called 'sshd'.
+
+The new ssh-host-config file which is part of this version asks
+to create 'sshd' as local user if you want to use privilege
+separation.  If you confirm, it creates that NT user and adds
+the necessary entry to /etc/passwd.
+
+On 9x/Me systems the script just sets UsePrivilegeSeparation to "no"
+since that feature doesn't make any sense on a system which doesn't
+differ between privileged and unprivileged users.
+
+The new ssh-host-config script also adds the /var/empty directory
+needed by privilege separation.  When creating the /var/empty directory
+by yourself, please note that in contrast to the README.privsep document
+the owner sshould not be "root" but the user which is running sshd.  So,
+in the standard configuration this is SYSTEM.  The ssh-host-config script
+chowns /var/empty accordingly.
+===========================================================================
+
+===========================================================================
+Important change since 3.0.1p1-2:
+
+This version introduces the ability to register sshd as service on
+Windows 9x/Me systems.  This is done only when the options -D and/or
+-d are not given.
+===========================================================================
+
+===========================================================================
+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.
+    --cygwin -c <options>  Use "options" as value for CYGWIN environment var.
+    --port   -p <n>        sshd listens on port n.
+    --pwd    -w <passwd>   Use "pwd" as password for user 'sshd_server'.
+
+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:
+
+ssh 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:
+
+   ssh         22/tcp          #SSH daemon
+
+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 Cygwin's login(1) port:
+
+  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-...
+
+Note that the CYGWIN=ntsec setting is required for public key authentication.
+
+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='${sbindir}' \
+       --localstatedir=/var \
+       --datadir='${prefix}/share' \
+       --mandir='${datadir}/man' \
+       --infodir='${datadir}/info'
+       --with-tcp-wrappers
+       --with-libedit
+
+If you want to create a Cygwin package, equivalent to the one
+in the Cygwin binary distribution, install like this:
+
+       mkdir /tmp/cygwin-ssh
+       cd ${builddir}
+       make install DESTDIR=/tmp/cygwin-ssh
+       cd ${srcdir}/contrib/cygwin
+       make cygwin-postinstall DESTDIR=/tmp/cygwin-ssh
+       cd /tmp/cygwin-ssh
+       find * \! -type d | tar cvjfT my-openssh.tar.bz2 -
+
+You must have installed the following packages to be able to build OpenSSH:
+
+- zlib
+- openssl-devel
+
+If you want to build with --with-tcp-wrappers, you also need the package
+
+- tcp_wrappers
+
+If you want to build with --with-libedit, you also need the package
+
+- libedit-devel
+
+Please send requests, error reports etc. to cygwin@cygwin.com.
+
+
+Have fun,
+
+Corinna Vinschen
+Cygwin Developer
+Red Hat Inc.
diff --git a/contrib/cygwin/ssh-host-config b/contrib/cygwin/ssh-host-config
new file mode 100644 (file)
index 0000000..d968d46
--- /dev/null
@@ -0,0 +1,561 @@
+#!/bin/bash
+#
+# ssh-host-config, Copyright 2000-2009 Red Hat Inc.
+#
+# This file is part of the Cygwin port of OpenSSH.
+#
+# 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", 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.                               
+
+# ======================================================================
+# Initialization
+# ======================================================================
+PROGNAME=$(basename $0)
+_tdir=$(dirname $0)
+PROGDIR=$(cd $_tdir && pwd)
+
+CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh
+
+# Subdirectory where the new package is being installed
+PREFIX=/usr
+
+# Directory where the config files are stored
+SYSCONFDIR=/etc
+LOCALSTATEDIR=/var
+
+source ${CSIH_SCRIPT}
+
+port_number=22
+privsep_configured=no
+privsep_used=yes
+cygwin_value=""
+user_account=
+password_value=
+opt_force=no
+
+# ======================================================================
+# Routine: create_host_keys
+# ======================================================================
+create_host_keys() {
+  if [ ! -f "${SYSCONFDIR}/ssh_host_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_key"
+    ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null
+  fi
+
+  if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_rsa_key"
+    ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null
+  fi
+
+  if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ]
+  then
+    csih_inform "Generating ${SYSCONFDIR}/ssh_host_dsa_key"
+    ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null
+  fi
+} # --- End of create_host_keys --- #
+
+# ======================================================================
+# Routine: update_services_file
+# ======================================================================
+update_services_file() {
+  local _my_etcdir="/ssh-host-config.$$"
+  local _win_etcdir
+  local _services
+  local _spaces
+  local _serv_tmp
+  local _wservices
+
+  if csih_is_nt
+  then
+    _win_etcdir="${SYSTEMROOT}\\system32\\drivers\\etc"
+    _services="${_my_etcdir}/services"
+    # On NT, 27 spaces, no space after the hash
+    _spaces="                           #"
+  else
+    _win_etcdir="${WINDIR}"
+    _services="${_my_etcdir}/SERVICES"
+    # On 9x, 18 spaces (95 is very touchy), a space after the hash
+    _spaces="                  # "
+  fi
+  _serv_tmp="${_my_etcdir}/srv.out.$$"
+
+  mount -o text,posix=0,noacl -f "${_win_etcdir}" "${_my_etcdir}"
+
+  # Depends on the above mount
+  _wservices=`cygpath -w "${_services}"`
+
+  # Remove sshd 22/port from services
+  if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
+  then
+    grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
+    if [ -f "${_serv_tmp}" ]
+    then
+      if mv "${_serv_tmp}" "${_services}"
+      then
+       csih_inform "Removing sshd from ${_wservices}"
+      else
+       csih_warning "Removing sshd from ${_wservices} failed!"
+      fi
+      rm -f "${_serv_tmp}"
+    else
+      csih_warning "Removing sshd from ${_wservices} failed!"
+    fi
+  fi
+
+  # Add ssh 22/tcp  and ssh 22/udp to services
+  if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
+  then
+    if awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh                22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh                22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
+    then
+      if mv "${_serv_tmp}" "${_services}"
+      then
+       csih_inform "Added ssh to ${_wservices}"
+      else
+       csih_warning "Adding ssh to ${_wservices} failed!"
+      fi
+      rm -f "${_serv_tmp}"
+    else
+      csih_warning "Adding ssh to ${_wservices} failed!"
+    fi
+  fi
+  umount "${_my_etcdir}"
+} # --- End of update_services_file --- #
+
+# ======================================================================
+# Routine: sshd_privsep
+#  MODIFIES: privsep_configured  privsep_used
+# ======================================================================
+sshd_privsep() {
+  local sshdconfig_tmp
+
+  if [ "${privsep_configured}" != "yes" ]
+  then
+    if csih_is_nt
+    then
+      csih_inform "Privilege separation is set to yes by default since OpenSSH 3.3."
+      csih_inform "However, this requires a non-privileged account called 'sshd'."
+      csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
+      if csih_request "Should privilege separation be used?"
+      then
+       privsep_used=yes
+       if ! csih_create_unprivileged_user sshd
+       then
+         csih_warning "Couldn't create user 'sshd'!"
+         csih_warning "Privilege separation set to 'no' again!"
+         csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
+         privsep_used=no
+       fi
+      else
+       privsep_used=no
+      fi
+    else
+      # On 9x don't use privilege separation.  Since security isn't
+      # available it just adds useless additional processes.
+      privsep_used=no
+    fi
+  fi
+
+  # Create default sshd_config from skeleton files in /etc/defaults/etc or
+  # modify to add the missing privsep configuration option
+  if cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
+  then
+    csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
+    sshdconfig_tmp=${SYSCONFDIR}/sshd_config.$$
+    sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/
+         s/^#Port 22/Port ${port_number}/
+         s/^#StrictModes yes/StrictModes no/" \
+       < ${SYSCONFDIR}/sshd_config \
+       > "${sshdconfig_tmp}"
+    mv "${sshdconfig_tmp}" ${SYSCONFDIR}/sshd_config
+  elif [ "${privsep_configured}" != "yes" ]
+  then
+    echo >> ${SYSCONFDIR}/sshd_config
+    echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config
+  fi
+} # --- End of sshd_privsep --- #
+
+# ======================================================================
+# Routine: update_inetd_conf
+# ======================================================================
+update_inetd_conf() {
+  local _inetcnf="${SYSCONFDIR}/inetd.conf"
+  local _inetcnf_tmp="${SYSCONFDIR}/inetd.conf.$$"
+  local _inetcnf_dir="${SYSCONFDIR}/inetd.d"
+  local _sshd_inetd_conf="${_inetcnf_dir}/sshd-inetd"
+  local _sshd_inetd_conf_tmp="${_inetcnf_dir}/sshd-inetd.$$"
+  local _with_comment=1
+
+  if [ -d "${_inetcnf_dir}" ]
+  then
+    # we have inetutils-1.5 inetd.d support
+    if [ -f "${_inetcnf}" ]
+    then
+      grep -q '^[ \t]*ssh' "${_inetcnf}" && _with_comment=0
+
+      # check for sshd OR ssh in top-level inetd.conf file, and remove
+      # will be replaced by a file in inetd.d/
+      if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -eq 0 ]
+      then
+       grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}"
+       if [ -f "${_inetcnf_tmp}" ]
+       then
+         if mv "${_inetcnf_tmp}" "${_inetcnf}"
+         then
+           csih_inform "Removed ssh[d] from ${_inetcnf}"
+         else
+           csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
+         fi
+         rm -f "${_inetcnf_tmp}"
+       else
+         csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
+       fi
+      fi
+    fi
+
+    csih_install_config "${_sshd_inetd_conf}"   "${SYSCONFDIR}/defaults"
+    if cmp "${SYSCONFDIR}/defaults${_sshd_inetd_conf}" "${_sshd_inetd_conf}" >/dev/null 2>&1
+    then
+      if [ "${_with_comment}" -eq 0 ]
+      then
+       sed -e 's/@COMMENT@[ \t]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+      else
+       sed -e 's/@COMMENT@[ \t]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
+      fi
+      mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}"
+      csih_inform "Updated ${_sshd_inetd_conf}"
+    fi
+
+  elif [ -f "${_inetcnf}" ]
+  then
+    grep -q '^[ \t]*sshd' "${_inetcnf}" && _with_comment=0
+
+    # check for sshd in top-level inetd.conf file, and remove
+    # will be replaced by a file in inetd.d/
+    if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
+    then
+      grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
+      if [ -f "${_inetcnf_tmp}" ]
+      then
+       if mv "${_inetcnf_tmp}" "${_inetcnf}"
+       then
+           csih_inform "Removed sshd from ${_inetcnf}"
+       else
+           csih_warning "Removing sshd from ${_inetcnf} failed!"
+       fi
+       rm -f "${_inetcnf_tmp}"
+      else
+       csih_warning "Removing sshd from ${_inetcnf} failed!"
+      fi
+    fi
+
+    # Add ssh line to inetd.conf
+    if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ]
+    then
+      if [ "${_with_comment}" -eq 0 ]
+      then
+       echo 'ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
+      else
+       echo '# ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
+      fi
+      csih_inform "Added ssh to ${_inetcnf}"
+    fi
+  fi
+} # --- End of update_inetd_conf --- #
+
+# ======================================================================
+# Routine: install_service
+#   Install sshd as a service
+# ======================================================================
+install_service() {
+  local run_service_as
+  local password
+
+  if csih_is_nt
+  then
+    if ! cygrunsrv -Q sshd >/dev/null 2>&1
+    then
+      echo
+      echo
+      csih_warning "The following functions require administrator privileges!"
+      echo
+      echo -e "${_csih_QUERY_STR} Do you want to install sshd as a service?"
+      if csih_request "(Say \"no\" if it is already installed as a service)"
+      then
+       csih_get_cygenv "${cygwin_value}"
+
+       if ( csih_is_nt2003 || [ "$csih_FORCE_PRIVILEGED_USER" = "yes" ] )
+       then
+         csih_inform "On Windows Server 2003, Windows Vista, and above, the"
+         csih_inform "SYSTEM account cannot setuid to other users -- a capability"
+         csih_inform "sshd requires.  You need to have or to create a privileged"
+         csih_inform "account.  This script will help you do so."
+         echo
+
+         [ "${opt_force}" = "yes" ] && opt_f=-f
+         [ -n "${user_account}" ] && opt_u="-u ""${user_account}"""
+         csih_select_privileged_username ${opt_f} ${opt_u} sshd
+
+         if ! csih_create_privileged_user "${password_value}"
+         then
+           csih_error_recoverable "There was a serious problem creating a privileged user."
+           csih_request "Do you want to proceed anyway?" || exit 1
+         fi
+       fi
+
+       # never returns empty if NT or above
+       run_service_as=$(csih_service_should_run_as)
+
+       if [ "${run_service_as}" = "${csih_PRIVILEGED_USERNAME}" ]
+       then
+         password="${csih_PRIVILEGED_PASSWORD}"
+         if [ -z "${password}" ]
+         then
+           csih_get_value "Please enter the password for user '${run_service_as}':" "-s"
+           password="${csih_value}"
+         fi
+       fi
+
+       # at this point, we either have $run_service_as = "system" and $password is empty,
+       # or $run_service_as is some privileged user and (hopefully) $password contains
+       # the correct password.  So, from here out, we use '-z "${password}"' to discriminate
+       # the two cases.
+
+       csih_check_user "${run_service_as}"
+
+       if [ -n "${csih_cygenv}" ]
+       then
+         cygwin_env=( -e "CYGWIN=${csih_cygenv}" )
+       fi
+       if [ -z "${password}" ]
+       then
+         if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
+                           -a "-D" -y tcpip "${cygwin_env[@]}"
+         then
+           echo
+           csih_inform "The sshd service has been installed under the LocalSystem"
+           csih_inform "account (also known as SYSTEM). To start the service now, call"
+           csih_inform "\`net start sshd' or \`cygrunsrv -S sshd'.  Otherwise, it"
+           csih_inform "will start automatically after the next reboot."
+         fi
+       else
+         if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
+                           -a "-D" -y tcpip "${cygwin_env[@]}" \
+                           -u "${run_service_as}" -w "${password}"
+         then
+           echo
+           csih_inform "The sshd service has been installed under the '${run_service_as}'"
+           csih_inform "account.  To start the service now, call \`net start sshd' or"
+           csih_inform "\`cygrunsrv -S sshd'.  Otherwise, it will start automatically"
+           csih_inform "after the next reboot."
+         fi
+       fi
+
+       # now, if successfully installed, set ownership of the affected files
+       if cygrunsrv -Q sshd >/dev/null 2>&1
+       then
+         chown "${run_service_as}" ${SYSCONFDIR}/ssh*
+         chown "${run_service_as}".544 ${LOCALSTATEDIR}/empty
+         chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/lastlog
+         if [ -f ${LOCALSTATEDIR}/log/sshd.log ]
+         then
+           chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/sshd.log
+         fi
+       else
+         csih_warning "Something went wrong installing the sshd service."
+       fi
+      fi # user allowed us to install as service
+    fi # service not yet installed
+  fi # csih_is_nt
+} # --- End of install_service --- #
+
+# ======================================================================
+# Main Entry Point
+# ======================================================================
+
+# Check how the script has been started.  If
+#   (1) it has been started by giving the full path and
+#       that path is /etc/postinstall, OR
+#   (2) Otherwise, if the environment variable
+#       SSH_HOST_CONFIG_AUTO_ANSWER_NO is set
+# then set auto_answer to "no".  This allows automatic
+# creation of the config files in /etc w/o overwriting
+# them if they already exist.  In both cases, color
+# escape sequences are suppressed, so as to prevent
+# cluttering setup's logfiles.
+if [ "$PROGDIR" = "/etc/postinstall" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+  opt_force=yes
+fi
+if [ -n "${SSH_HOST_CONFIG_AUTO_ANSWER_NO}" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+  opt_force=yes
+fi
+
+# ======================================================================
+# Parse options
+# ======================================================================
+while :
+do
+  case $# in
+  0)
+    break
+    ;;
+  esac
+
+  option=$1
+  shift
+
+  case "${option}" in
+  -d | --debug )
+    set -x
+    csih_trace_on
+    ;;
+
+  -y | --yes )
+    csih_auto_answer=yes
+    opt_force=yes
+    ;;
+
+  -n | --no )
+    csih_auto_answer=no
+    opt_force=yes
+    ;;
+
+  -c | --cygwin )
+    cygwin_value="$1"
+    shift
+    ;;
+
+  -p | --port )
+    port_number=$1
+    shift
+    ;;
+
+  -u | --user )
+    user_account="$1"
+    shift
+    ;;
+    
+  -w | --pwd )
+    password_value="$1"
+    shift
+    ;;
+
+  --privileged )
+    csih_FORCE_PRIVILEGED_USER=yes
+    ;;
+
+  *)
+    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 "  --cygwin -c <options>  Use \"options\" as value for CYGWIN environment var."
+    echo "  --port   -p <n>        sshd listens on port n."
+    echo "  --user   -u <account>  privileged user for service."
+    echo "  --pwd    -w <passwd>   Use \"pwd\" as password for privileged user."
+    echo "  --privileged           On Windows NT/2k/XP, require privileged user"
+    echo "                         instead of LocalSystem for sshd service."
+    echo
+    exit 1
+    ;;
+
+  esac
+done
+
+# ======================================================================
+# Action!
+# ======================================================================
+
+# Check for running ssh/sshd processes first. Refuse to do anything while
+# some ssh processes are still running
+if ps -ef | grep -q '/sshd\?$'
+then
+  echo
+  csih_error "There are still ssh processes running. Please shut them down first."
+fi
+
+# Check for ${SYSCONFDIR} directory
+csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files."
+chmod 775 "${SYSCONFDIR}"
+setfacl -m u:system:rwx "${SYSCONFDIR}"
+
+# Check for /var/log directory
+csih_make_dir "${LOCALSTATEDIR}/log" "Cannot create log directory."
+chmod 775 "${LOCALSTATEDIR}/log"
+setfacl -m u:system:rwx "${LOCALSTATEDIR}/log"
+
+# Create /var/log/lastlog if not already exists
+if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ]
+then
+  echo
+  csih_error_multi "${LOCALSTATEDIR}/log/lastlog exists, but is not a file." \
+                  "Cannot create ssh host configuration."
+fi
+if [ ! -e ${LOCALSTATEDIR}/log/lastlog ]
+then
+  cat /dev/null > ${LOCALSTATEDIR}/log/lastlog
+  chmod 644 ${LOCALSTATEDIR}/log/lastlog
+fi
+
+# Create /var/empty file used as chroot jail for privilege separation
+csih_make_dir "${LOCALSTATEDIR}/empty" "Cannot create ${LOCALSTATEDIR}/empty directory."
+chmod 755 "${LOCALSTATEDIR}/empty"
+setfacl -m u:system:rwx "${LOCALSTATEDIR}/empty"
+
+# host keys
+create_host_keys
+
+# use 'cmp' program to determine if a config file is identical
+# to the default version of that config file
+csih_check_program_or_error cmp diffutils
+
+
+# handle ssh_config
+csih_install_config "${SYSCONFDIR}/ssh_config"   "${SYSCONFDIR}/defaults"
+if cmp "${SYSCONFDIR}/ssh_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/ssh_config" >/dev/null 2>&1
+then
+  if [ "${port_number}" != "22" ]
+  then
+    csih_inform "Updating ${SYSCONFDIR}/ssh_config file with requested port"
+    echo "Host localhost" >> ${SYSCONFDIR}/ssh_config
+    echo "    Port ${port_number}" >> ${SYSCONFDIR}/ssh_config
+  fi
+fi
+
+# handle sshd_config (and privsep)
+csih_install_config "${SYSCONFDIR}/sshd_config"   "${SYSCONFDIR}/defaults"
+if ! cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
+then
+  grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes
+fi
+sshd_privsep
+
+
+
+update_services_file
+update_inetd_conf
+install_service
+
+echo
+csih_inform "Host configuration finished. Have fun!"
+
diff --git a/contrib/cygwin/ssh-user-config b/contrib/cygwin/ssh-user-config
new file mode 100644 (file)
index 0000000..f1a001a
--- /dev/null
@@ -0,0 +1,322 @@
+#!/bin/bash
+#
+# ssh-user-config, Copyright 2000-2008 Red Hat Inc.
+#
+# This file is part of the Cygwin port of OpenSSH.
+#
+# 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", 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.                               
+
+# ======================================================================
+# Initialization
+# ======================================================================
+PROGNAME=$(basename -- $0)
+_tdir=$(dirname -- $0)
+PROGDIR=$(cd $_tdir && pwd)
+
+CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh
+
+# Subdirectory where the new package is being installed
+PREFIX=/usr
+
+# Directory where the config files are stored
+SYSCONFDIR=/etc
+
+source ${CSIH_SCRIPT}
+
+auto_passphrase="no"
+passphrase=""
+pwdhome=
+with_passphrase=
+
+# ======================================================================
+# Routine: create_ssh1_identity
+#   optionally create ~/.ssh/identity[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh1_identity() {
+  if [ ! -f "${pwdhome}/.ssh/identity" ]
+  then
+    if csih_request "Shall I create an SSH1 RSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/identity"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t rsa1 -N "${passphrase}" -f "${pwdhome}/.ssh/identity" > /dev/null
+      else
+        ssh-keygen -t rsa1 -f "${pwdhome}/.ssh/identity" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/identity.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh1_identity() === #
+readonly -f create_ssh1_identity
+
+# ======================================================================
+# Routine: create_ssh2_rsa_identity
+#   optionally create ~/.ssh/id_rsa[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh2_rsa_identity() {
+  if [ ! -f "${pwdhome}/.ssh/id_rsa" ]
+  then
+    if csih_request "Shall I create an SSH2 RSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/id_rsa"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t rsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+      else
+        ssh-keygen -t rsa -f "${pwdhome}/.ssh/id_rsa" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/id_rsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh2_rsa_identity() === #
+readonly -f create_ssh2_rsa_identity
+
+# ======================================================================
+# Routine: create_ssh2_dsa_identity
+#   optionally create ~/.ssh/id_dsa[.pub]
+#   optionally add result to ~/.ssh/authorized_keys
+# ======================================================================
+create_ssh2_dsa_identity() {
+  if [ ! -f "${pwdhome}/.ssh/id_dsa" ]
+  then
+    if csih_request "Shall I create an SSH2 DSA identity file for you?"
+    then
+      csih_inform "Generating ${pwdhome}/.ssh/id_dsa"
+      if [ "${with_passphrase}" = "yes" ]
+      then
+        ssh-keygen -t dsa -N "${passphrase}" -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+      else
+        ssh-keygen -t dsa -f "${pwdhome}/.ssh/id_dsa" > /dev/null
+      fi
+      if csih_request "Do you want to use this identity to login to this machine?"
+      then
+        csih_inform "Adding to ${pwdhome}/.ssh/authorized_keys"
+        cat "${pwdhome}/.ssh/id_dsa.pub" >> "${pwdhome}/.ssh/authorized_keys"
+      fi
+    fi
+  fi
+} # === End of create_ssh2_dsa_identity() === #
+readonly -f create_ssh2_dsa_identity
+
+# ======================================================================
+# Routine: check_user_homedir
+#   Perform various checks on the user's home directory
+# SETS GLOBAL VARIABLE:
+#   pwdhome
+# ======================================================================
+check_user_homedir() {
+  local uid=$(id -u)
+  pwdhome=$(awk -F: '{ if ( $3 == '${uid}' ) print $6; }' < ${SYSCONFDIR}/passwd)
+  if [ "X${pwdhome}" = "X" ]
+  then
+    csih_error_multi \
+      "There is no home directory set for you in ${SYSCONFDIR}/passwd." \
+      'Setting $HOME is not sufficient!'
+  fi
+  
+  if [ ! -d "${pwdhome}" ]
+  then
+    csih_error_multi \
+      "${pwdhome} is set in ${SYSCONFDIR}/passwd as your home directory" \
+      'but it is not a valid directory. Cannot create user identity files.'
+  fi
+  
+  # If home is the root dir, set home to empty string to avoid error messages
+  # in subsequent parts of that script.
+  if [ "X${pwdhome}" = "X/" ]
+  then
+    # But first raise a warning!
+    csih_warning "Your home directory in ${SYSCONFDIR}/passwd is set to root (/). This is not recommended!"
+    if csih_request "Would you like to proceed anyway?"
+    then
+      pwdhome=''
+    else
+      csih_warning "Exiting. Configuration is not complete"
+      exit 1
+    fi
+  fi
+  
+  if [ -d "${pwdhome}" -a csih_is_nt -a -n "`chmod -c g-w,o-w "${pwdhome}"`" ]
+  then
+    echo
+    csih_warning 'group and other have been revoked write permission to your home'
+    csih_warning "directory ${pwdhome}."
+    csih_warning 'This is required by OpenSSH to allow public key authentication using'
+    csih_warning 'the key files stored in your .ssh subdirectory.'
+    csih_warning 'Revert this change ONLY if you know what you are doing!'
+    echo
+  fi
+} # === End of check_user_homedir() === #
+readonly -f check_user_homedir
+
+# ======================================================================
+# Routine: check_user_dot_ssh_dir
+#   Perform various checks on the ~/.ssh directory
+# PREREQUISITE:
+#   pwdhome -- check_user_homedir()
+# ======================================================================
+check_user_dot_ssh_dir() {
+  if [ -e "${pwdhome}/.ssh" -a ! -d "${pwdhome}/.ssh" ]
+  then
+    csih_error "${pwdhome}/.ssh is existant but not a directory. Cannot create user identity files."
+  fi
+  
+  if [ ! -e "${pwdhome}/.ssh" ]
+  then
+    mkdir "${pwdhome}/.ssh"
+    if [ ! -e "${pwdhome}/.ssh" ]
+    then
+      csih_error "Creating users ${pwdhome}/.ssh directory failed"
+    fi
+  fi
+} # === End of check_user_dot_ssh_dir() === #
+readonly -f check_user_dot_ssh_dir
+
+# ======================================================================
+# Routine: fix_authorized_keys_perms
+#   Corrects the permissions of ~/.ssh/authorized_keys
+# PREREQUISITE:
+#   pwdhome   -- check_user_homedir()
+# ======================================================================
+fix_authorized_keys_perms() {
+  if [ csih_is_nt -a -e "${pwdhome}/.ssh/authorized_keys" ]
+  then
+    if ! setfacl -m "u::rw-,g::---,o::---" "${pwdhome}/.ssh/authorized_keys"
+    then
+      csih_warning "Setting correct permissions to ${pwdhome}/.ssh/authorized_keys"
+      csih_warning "failed.  Please care for the correct permissions.  The minimum requirement"
+      csih_warning "is, the owner needs read permissions."
+      echo
+    fi
+  fi
+} # === End of fix_authorized_keys_perms() === #
+readonly -f fix_authorized_keys_perms
+
+
+# ======================================================================
+# Main Entry Point
+# ======================================================================
+
+# Check how the script has been started.  If
+#   (1) it has been started by giving the full path and
+#       that path is /etc/postinstall, OR
+#   (2) Otherwise, if the environment variable
+#       SSH_USER_CONFIG_AUTO_ANSWER_NO is set
+# then set auto_answer to "no".  This allows automatic
+# creation of the config files in /etc w/o overwriting
+# them if they already exist.  In both cases, color
+# escape sequences are suppressed, so as to prevent
+# cluttering setup's logfiles.
+if [ "$PROGDIR" = "/etc/postinstall" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+fi
+if [ -n "${SSH_USER_CONFIG_AUTO_ANSWER_NO}" ]
+then
+  csih_auto_answer="no"
+  csih_disable_color
+fi
+
+# ======================================================================
+# Parse options
+# ======================================================================
+while :
+do
+  case $# in
+  0)
+    break
+    ;;
+  esac
+
+  option=$1
+  shift
+
+  case "$option" in
+  -d | --debug )
+    set -x
+    csih_trace_on
+    ;;
+
+  -y | --yes )
+    csih_auto_answer=yes
+    ;;
+
+  -n | --no )
+    csih_auto_answer=no
+    ;;
+
+  -p | --passphrase )
+    with_passphrase="yes"
+    passphrase=$1
+    shift
+    ;;
+
+  --privileged )
+    csih_FORCE_PRIVILEGED_USER=yes
+    ;;
+
+  *)
+    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 "    --privileged           On Windows NT/2k/XP, assume privileged user"
+    echo "                           instead of LocalSystem for sshd service."
+    echo
+    exit 1
+    ;;
+
+  esac
+done
+
+# ======================================================================
+# Action!
+# ======================================================================
+
+# Check passwd file
+if [ ! -f ${SYSCONFDIR}/passwd ]
+then
+  csih_error_multi \
+    "${SYSCONFDIR}/passwd is nonexistant. Please generate an ${SYSCONFDIR}/passwd file" \
+    'first using mkpasswd. Check if it contains an entry for you and' \
+    'please care for the home directory in your entry as well.'
+fi
+
+check_user_homedir
+check_user_dot_ssh_dir
+create_ssh1_identity
+create_ssh2_rsa_identity
+create_ssh2_dsa_identity
+fix_authorized_keys_perms
+
+echo
+csih_inform "Configuration finished. Have fun!"
+
+
diff --git a/contrib/cygwin/sshd-inetd b/contrib/cygwin/sshd-inetd
new file mode 100644 (file)
index 0000000..aa6bf07
--- /dev/null
@@ -0,0 +1,4 @@
+# This file can be used to enable sshd as a slave of the inetd service
+# To do so, the line below should be uncommented.
+@COMMENT@ ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i
+
diff --git a/contrib/findssl.sh b/contrib/findssl.sh
new file mode 100644 (file)
index 0000000..263fd26
--- /dev/null
@@ -0,0 +1,186 @@
+#!/bin/sh
+#
+# $Id: findssl.sh,v 1.4 2007/02/19 11:44:25 dtucker Exp $
+#
+# findssl.sh
+#      Search for all instances of OpenSSL headers and libraries
+#      and print their versions.
+#      Intended to help diagnose OpenSSH's "OpenSSL headers do not
+#      match your library" errors.
+#
+#      Written by Darren Tucker (dtucker at zip dot com dot au)
+#      This file is placed in the public domain.
+#
+#      Release history:
+#      2002-07-27: Initial release.
+#      2002-08-04: Added public domain notice.
+#      2003-06-24: Incorporated readme, set library paths. First cvs version.
+#      2004-12-13: Add traps to cleanup temp files, from Amarendra Godbole.
+#
+# "OpenSSL headers do not match your library" are usually caused by
+# OpenSSH's configure picking up an older version of OpenSSL headers
+# or libraries.  You can use the following # procedure to help identify
+# the cause.
+#
+# The  output  of  configure  will  tell you the versions of the OpenSSL
+# headers and libraries that were picked up, for example:
+#
+# checking OpenSSL header version... 90604f (OpenSSL 0.9.6d 9 May 2002)
+# checking OpenSSL library version... 90602f (OpenSSL 0.9.6b [engine] 9 Jul 2001)
+# checking whether OpenSSL's headers match the library... no
+# configure: error: Your OpenSSL headers do not match your library
+#
+# Now run findssl.sh. This should identify the headers and libraries
+# present  and  their  versions.  You  should  be  able  to identify the
+# libraries  and headers used and adjust your CFLAGS or remove incorrect
+# versions.  The  output will show OpenSSL's internal version identifier
+# and should look something like:
+
+# $ ./findssl.sh
+# Searching for OpenSSL header files.
+# 0x0090604fL /usr/include/openssl/opensslv.h
+# 0x0090604fL /usr/local/ssl/include/openssl/opensslv.h
+#
+# Searching for OpenSSL shared library files.
+# 0x0090602fL /lib/libcrypto.so.0.9.6b
+# 0x0090602fL /lib/libcrypto.so.2
+# 0x0090581fL /usr/lib/libcrypto.so.0
+# 0x0090602fL /usr/lib/libcrypto.so
+# 0x0090581fL /usr/lib/libcrypto.so.0.9.5a
+# 0x0090600fL /usr/lib/libcrypto.so.0.9.6
+# 0x0090600fL /usr/lib/libcrypto.so.1
+#
+# Searching for OpenSSL static library files.
+# 0x0090602fL /usr/lib/libcrypto.a
+# 0x0090604fL /usr/local/ssl/lib/libcrypto.a
+#
+# In  this  example, I gave configure no extra flags, so it's picking up
+# the  OpenSSL header from /usr/include/openssl (90604f) and the library
+# from /usr/lib/ (90602f).
+
+#
+# Adjust these to suit your compiler.
+# You may also need to set the *LIB*PATH environment variables if
+# DEFAULT_LIBPATH is not correct for your system.
+#
+CC=gcc
+STATIC=-static
+
+#
+# Cleanup on interrupt
+#
+trap 'rm -f conftest.c' INT HUP TERM
+
+#
+# Set up conftest C source
+#
+rm -f findssl.log
+cat >conftest.c <<EOD
+#include <stdio.h>
+int main(){printf("0x%08xL\n", SSLeay());}
+EOD
+
+#
+# Set default library paths if not already set
+#
+DEFAULT_LIBPATH=/usr/lib:/usr/local/lib
+LIBPATH=${LIBPATH:=$DEFAULT_LIBPATH}
+LD_LIBRARY_PATH=${LD_LIBRARY_PATH:=$DEFAULT_LIBPATH}
+LIBRARY_PATH=${LIBRARY_PATH:=$DEFAULT_LIBPATH}
+export LIBPATH LD_LIBRARY_PATH LIBRARY_PATH
+
+# not all platforms have a 'which' command
+if which ls >/dev/null 2>/dev/null; then
+    : which is defined
+else
+    which () {
+       saveIFS="$IFS"
+       IFS=:
+       for p in $PATH; do
+           if test -x "$p/$1" -a -f "$p/$1"; then
+               IFS="$saveIFS"
+               echo "$p/$1"
+               return 0
+           fi
+       done
+       IFS="$saveIFS"
+       return 1
+    }
+fi
+
+#
+# Search for OpenSSL headers and print versions
+#
+echo Searching for OpenSSL header files.
+if [ -x "`which locate`" ]
+then
+       headers=`locate opensslv.h`
+else
+       headers=`find / -name opensslv.h -print 2>/dev/null`
+fi
+
+for header in $headers
+do
+       ver=`awk '/OPENSSL_VERSION_NUMBER/{printf \$3}' $header`
+       echo "$ver $header"
+done
+echo
+
+#
+# Search for shared libraries.
+# Relies on shared libraries looking like "libcrypto.s*"
+#
+echo Searching for OpenSSL shared library files.
+if [ -x "`which locate`" ]
+then
+       libraries=`locate libcrypto.s`
+else
+       libraries=`find / -name 'libcrypto.s*' -print 2>/dev/null`
+fi
+
+for lib in $libraries
+do
+       (echo "Trying libcrypto $lib" >>findssl.log
+       dir=`dirname $lib`
+       LIBPATH="$dir:$LIBPATH"
+       LD_LIBRARY_PATH="$dir:$LIBPATH"
+       LIBRARY_PATH="$dir:$LIBPATH"
+       export LIBPATH LD_LIBRARY_PATH LIBRARY_PATH
+       ${CC} -o conftest conftest.c $lib 2>>findssl.log
+       if [ -x ./conftest ]
+       then
+               ver=`./conftest 2>/dev/null`
+               rm -f ./conftest
+               echo "$ver $lib"
+       fi)
+done
+echo
+
+#
+# Search for static OpenSSL libraries and print versions
+#
+echo Searching for OpenSSL static library files.
+if [ -x "`which locate`" ]
+then
+       libraries=`locate libcrypto.a`
+else
+       libraries=`find / -name libcrypto.a -print 2>/dev/null`
+fi
+
+for lib in $libraries
+do
+       libdir=`dirname $lib`
+       echo "Trying libcrypto $lib" >>findssl.log
+       ${CC} ${STATIC} -o conftest conftest.c -L${libdir} -lcrypto 2>>findssl.log
+       if [ -x ./conftest ]
+       then
+               ver=`./conftest 2>/dev/null`
+               rm -f ./conftest
+               echo "$ver $lib"
+       fi
+done
+
+#
+# Clean up
+#
+rm -f conftest.c
diff --git a/contrib/gnome-ssh-askpass1.c b/contrib/gnome-ssh-askpass1.c
new file mode 100644 (file)
index 0000000..4d51032
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2000-2002 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.
+ */
+
+/*
+ * This is a simple GNOME SSH passphrase grabber. To use it, set the
+ * environment variable SSH_ASKPASS to point to the location of
+ * gnome-ssh-askpass before calling "ssh-add < /dev/null".
+ *
+ * There is only two run-time options: if you set the environment variable
+ * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
+ * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
+ * pointer will be grabbed too. These may have some benefit to security if
+ * you don't trust your X server. We grab the keyboard always.
+ */
+
+/*
+ * Compile with:
+ *
+ * cc `gnome-config --cflags gnome gnomeui` \
+ *    gnome-ssh-askpass1.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));
+}
+
+int
+passphrase_dialog(char *message)
+{
+       char *passphrase;
+       char **messages;
+       int result, i, grab_server, grab_pointer;
+       GtkWidget *dialog, *entry, *label;
+
+       grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
+       grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
+
+       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 */
+       if (grab_server)
+               XGrabServer(GDK_DISPLAY());
+       if (grab_pointer && 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 */
+       if (grab_server)
+               XUngrabServer(GDK_DISPLAY());
+       if (grab_pointer)
+               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 (result == 0 ? 0 : -1);
+
+       /* 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:
+       if (grab_server)
+               XUngrabServer(GDK_DISPLAY());
+       gnome_dialog_close(GNOME_DIALOG(dialog));
+       
+       report_failed_grab();
+       return (-1);
+}
+
+int
+main(int argc, char **argv)
+{
+       char *message;
+       int result;
+
+       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);
+       result = passphrase_dialog(message);
+
+       return (result);
+}
diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c
new file mode 100644 (file)
index 0000000..9d97c30
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2000-2002 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.
+ */
+
+/* GTK2 support by Nalin Dahyabhai <nalin@redhat.com> */
+
+/*
+ * This is a simple GNOME SSH passphrase grabber. To use it, set the
+ * environment variable SSH_ASKPASS to point to the location of
+ * gnome-ssh-askpass before calling "ssh-add < /dev/null".
+ *
+ * There is only two run-time options: if you set the environment variable
+ * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
+ * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
+ * pointer will be grabbed too. These may have some benefit to security if
+ * you don't trust your X server. We grab the keyboard always.
+ */
+
+#define GRAB_TRIES     16
+#define GRAB_WAIT      250 /* milliseconds */
+
+/*
+ * Compile with:
+ *
+ * cc -Wall `pkg-config --cflags gtk+-2.0` \
+ *    gnome-ssh-askpass2.c -o gnome-ssh-askpass \
+ *    `pkg-config --libs gtk+-2.0`
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+static void
+report_failed_grab (const char *what)
+{
+       GtkWidget *err;
+
+       err = gtk_message_dialog_new(NULL, 0,
+                                    GTK_MESSAGE_ERROR,
+                                    GTK_BUTTONS_CLOSE,
+                                    "Could not grab %s. "
+                                    "A malicious client may be eavesdropping "
+                                    "on your session.", what);
+       gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
+       gtk_label_set_line_wrap(GTK_LABEL((GTK_MESSAGE_DIALOG(err))->label),
+                               TRUE);
+
+       gtk_dialog_run(GTK_DIALOG(err));
+
+       gtk_widget_destroy(err);
+}
+
+static void
+ok_dialog(GtkWidget *entry, gpointer dialog)
+{
+       g_return_if_fail(GTK_IS_DIALOG(dialog));
+       gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+}
+
+static int
+passphrase_dialog(char *message)
+{
+       const char *failed;
+       char *passphrase, *local;
+       int result, grab_tries, grab_server, grab_pointer;
+       GtkWidget *dialog, *entry;
+       GdkGrabStatus status;
+
+       grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
+       grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
+       grab_tries = 0;
+
+       dialog = gtk_message_dialog_new(NULL, 0,
+                                       GTK_MESSAGE_QUESTION,
+                                       GTK_BUTTONS_OK_CANCEL,
+                                       "%s",
+                                       message);
+
+       entry = gtk_entry_new();
+       gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE,
+           FALSE, 0);
+       gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+       gtk_widget_grab_focus(entry);
+       gtk_widget_show(entry);
+
+       gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
+       gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+       gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+       gtk_label_set_line_wrap(GTK_LABEL((GTK_MESSAGE_DIALOG(dialog))->label),
+                               TRUE);
+
+       /* Make <enter> close dialog */
+       gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+       g_signal_connect(G_OBJECT(entry), "activate",
+                        G_CALLBACK(ok_dialog), dialog);
+
+       gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);
+
+       /* Grab focus */
+       gtk_widget_show_now(dialog);
+       if (grab_pointer) {
+               for(;;) {
+                       status = gdk_pointer_grab(
+                          (GTK_WIDGET(dialog))->window, TRUE, 0, NULL,
+                          NULL, GDK_CURRENT_TIME);
+                       if (status == GDK_GRAB_SUCCESS)
+                               break;
+                       usleep(GRAB_WAIT * 1000);
+                       if (++grab_tries > GRAB_TRIES) {
+                               failed = "mouse";
+                               goto nograb;
+                       }
+               }
+       }
+       for(;;) {
+               status = gdk_keyboard_grab((GTK_WIDGET(dialog))->window,
+                  FALSE, GDK_CURRENT_TIME);
+               if (status == GDK_GRAB_SUCCESS)
+                       break;
+               usleep(GRAB_WAIT * 1000);
+               if (++grab_tries > GRAB_TRIES) {
+                       failed = "keyboard";
+                       goto nograbkb;
+               }
+       }
+       if (grab_server) {
+               gdk_x11_grab_server();
+       }
+
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+
+       /* Ungrab */
+       if (grab_server)
+               XUngrabServer(GDK_DISPLAY());
+       if (grab_pointer)
+               gdk_pointer_ungrab(GDK_CURRENT_TIME);
+       gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+       gdk_flush();
+
+       /* Report passphrase if user selected OK */
+       passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
+       if (result == GTK_RESPONSE_OK) {
+               local = g_locale_from_utf8(passphrase, strlen(passphrase),
+                                          NULL, NULL, NULL);
+               if (local != NULL) {
+                       puts(local);
+                       memset(local, '\0', strlen(local));
+                       g_free(local);
+               } else {
+                       puts(passphrase);
+               }
+       }
+               
+       /* Zero passphrase in memory */
+       memset(passphrase, '\b', strlen(passphrase));
+       gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
+       memset(passphrase, '\0', strlen(passphrase));
+       g_free(passphrase);
+                       
+       gtk_widget_destroy(dialog);
+       return (result == GTK_RESPONSE_OK ? 0 : -1);
+
+       /* 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:
+       if (grab_server)
+               XUngrabServer(GDK_DISPLAY());
+       gtk_widget_destroy(dialog);
+       
+       report_failed_grab(failed);
+
+       return (-1);
+}
+
+int
+main(int argc, char **argv)
+{
+       char *message;
+       int result;
+
+       gtk_init(&argc, &argv);
+
+       if (argc > 1) {
+               message = g_strjoinv(" ", argv + 1);
+       } else {
+               message = g_strdup("Enter your OpenSSH passphrase:");
+       }
+
+       setvbuf(stdout, 0, _IONBF, 0);
+       result = passphrase_dialog(message);
+       g_free(message);
+
+       return (result);
+}
diff --git a/contrib/hpux/README b/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/contrib/hpux/egd b/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/contrib/hpux/egd.rc b/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/contrib/hpux/sshd b/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/contrib/hpux/sshd.rc b/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/contrib/redhat/gnome-ssh-askpass.csh b/contrib/redhat/gnome-ssh-askpass.csh
new file mode 100644 (file)
index 0000000..dd77712
--- /dev/null
@@ -0,0 +1 @@
+setenv SSH_ASKPASS /usr/libexec/openssh/gnome-ssh-askpass
diff --git a/contrib/redhat/gnome-ssh-askpass.sh b/contrib/redhat/gnome-ssh-askpass.sh
new file mode 100644 (file)
index 0000000..355189f
--- /dev/null
@@ -0,0 +1,2 @@
+SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
+export SSH_ASKPASS
diff --git a/contrib/redhat/openssh.spec b/contrib/redhat/openssh.spec
new file mode 100644 (file)
index 0000000..e99e33d
--- /dev/null
@@ -0,0 +1,812 @@
+%define ver 5.8p1
+%define rel 1
+
+# OpenSSH privilege separation requires a user & group ID
+%define sshd_uid    74
+%define sshd_gid    74
+
+# 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 GTK2 instead of GNOME in gnome-ssh-askpass
+%define gtk2 1
+
+# Is this build for RHL 6.x?
+%define build6x 0
+
+# Do we want kerberos5 support (1=yes 0=no)
+%define kerberos5 1
+
+# 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}
+
+# Add option to build without GTK2 for older platforms with only GTK+.
+# RedHat <= 7.2 and Red Hat Advanced Server 2.1 are examples.
+# rpm -ba|--rebuild --define 'no_gtk2 1'
+%{?no_gtk2:%define gtk2 0}
+
+# Is this a build for RHL 6.x or earlier?
+%{?build_6x:%define build6x 1}
+
+# If this is RHL 6.x, the default configuration has sysconfdir in /usr/etc.
+%if %{build6x}
+%define _sysconfdir /etc
+%endif
+
+# 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}
+
+# Is this a build for the rescue CD (without PAM, with MD5)? (1=yes 0=no)
+%define rescue 0
+%{?build_rescue:%define rescue 1}
+
+# Turn off some stuff for resuce builds
+%if %{rescue}
+%define kerberos5 0
+%endif
+
+Summary: The OpenSSH implementation of SSH protocol versions 1 and 2.
+Name: openssh
+Version: %{ver}
+%if %{rescue}
+Release: %{rel}rescue
+%else
+Release: %{rel}
+%endif
+URL: http://www.openssh.com/portable.html
+Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
+%if ! %{no_x11_askpass}
+Source1: http://www.jmknoble.net/software/x11-ssh-askpass/x11-ssh-askpass-%{aversion}.tar.gz
+%endif
+License: BSD
+Group: Applications/Internet
+BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
+Obsoletes: ssh
+%if %{build6x}
+PreReq: initscripts >= 5.00
+%else
+PreReq: initscripts >= 5.20
+%endif
+BuildPreReq: perl, openssl-devel, tcp_wrappers
+BuildPreReq: /bin/login
+%if ! %{build6x}
+BuildPreReq: glibc-devel, pam
+%else
+BuildPreReq: /usr/include/security/pam_appl.h
+%endif
+%if ! %{no_x11_askpass}
+BuildPreReq: /usr/include/X11/Xlib.h
+%endif
+%if ! %{no_gnome_askpass}
+BuildPreReq: pkgconfig
+%endif
+%if %{kerberos5}
+BuildPreReq: krb5-devel
+BuildPreReq: krb5-libs
+%endif
+
+%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 ! %{build6x}
+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
+SSH (Secure SHell) is a program for logging into and executing
+commands on a remote machine. SSH is intended to replace rlogin and
+rsh, and 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.
+
+OpenSSH is OpenBSD's version 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 separate libraries.
+
+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 a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. This package includes
+the clients necessary to make encrypted connections to SSH servers.
+You'll also need to install the openssh package on OpenSSH clients.
+
+%description server
+OpenSSH is a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. 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 a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. This package contains
+an X11 passphrase dialog for OpenSSH.
+
+%description askpass-gnome
+OpenSSH is a free version of SSH (Secure SHell), a program for logging
+into and executing commands on a remote machine. 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
+%if %{rescue}
+CFLAGS="$RPM_OPT_FLAGS -Os"; export CFLAGS
+%endif
+
+%if %{kerberos5}
+K5DIR=`rpm -ql krb5-devel | grep include/krb5.h | sed 's,\/include\/krb5.h,,'`
+echo K5DIR=$K5DIR
+%endif
+
+%configure \
+       --sysconfdir=%{_sysconfdir}/ssh \
+       --libexecdir=%{_libexecdir}/openssh \
+       --datadir=%{_datadir}/openssh \
+       --with-tcp-wrappers \
+       --with-rsh=%{_bindir}/rsh \
+       --with-default-path=/usr/local/bin:/bin:/usr/bin \
+       --with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
+       --with-privsep-path=%{_var}/empty/sshd \
+       --with-md5-passwords \
+%if %{scard}
+       --with-smartcard \
+%endif
+%if %{rescue}
+       --without-pam \
+%else
+       --with-pam \
+%endif
+%if %{kerberos5}
+        --with-kerberos5=$K5DIR \
+%endif
+
+
+%if %{static_libcrypto}
+perl -pi -e "s|-lcrypto|%{_libdir}/libcrypto.a|g" Makefile
+%endif
+
+make
+
+%if ! %{no_x11_askpass}
+pushd x11-ssh-askpass-%{aversion}
+%configure --libexecdir=%{_libexecdir}/openssh
+xmkmf -a
+make
+popd
+%endif
+
+# Define a variable to toggle gnome1/gtk2 building.  This is necessary
+# because RPM doesn't handle nested %if statements.
+%if %{gtk2}
+       gtk2=yes
+%else
+       gtk2=no
+%endif
+
+%if ! %{no_gnome_askpass}
+pushd contrib
+if [ $gtk2 = yes ] ; then
+       make gnome-ssh-askpass2
+       mv gnome-ssh-askpass2 gnome-ssh-askpass
+else
+       make gnome-ssh-askpass1
+       mv gnome-ssh-askpass1 gnome-ssh-askpass
+fi
+popd
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p -m755 $RPM_BUILD_ROOT%{_sysconfdir}/ssh
+mkdir -p -m755 $RPM_BUILD_ROOT%{_libexecdir}/openssh
+mkdir -p -m755 $RPM_BUILD_ROOT%{_var}/empty/sshd
+
+make install DESTDIR=$RPM_BUILD_ROOT
+
+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 %{build6x}
+install -m644 contrib/redhat/sshd.pam.old $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 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
+
+%if ! %{scard}
+        rm -f $RPM_BUILD_ROOT/usr/share/openssh/Ssh.bin
+%endif
+
+%if ! %{no_gnome_askpass}
+install -m 755 -d $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
+install -m 755 contrib/redhat/gnome-ssh-askpass.csh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
+install -m 755 contrib/redhat/gnome-ssh-askpass.sh $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/
+%endif
+
+perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/*
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%triggerun server -- ssh-server
+if [ "$1" != 0 -a -r /var/run/sshd.pid ] ; then
+       touch /var/run/sshd.restart
+fi
+
+%triggerun server -- openssh-server < 2.5.0p1
+# Count the number of HostKey and HostDsaKey statements we have.
+gawk   'BEGIN {IGNORECASE=1}
+        /^hostkey/ || /^hostdsakey/ {sawhostkey = sawhostkey + 1}
+        END {exit sawhostkey}' /etc/ssh/sshd_config
+# And if we only found one, we know the client was relying on the old default
+# behavior, which loaded the the SSH2 DSA host key when HostDsaKey wasn't
+# specified.  Now that HostKey is used for both SSH1 and SSH2 keys, specifying
+# one nullifies the default, which would have loaded both.
+if [ $? -eq 1 ] ; then
+       echo HostKey /etc/ssh/ssh_host_rsa_key >> /etc/ssh/sshd_config
+       echo HostKey /etc/ssh/ssh_host_dsa_key >> /etc/ssh/sshd_config
+fi
+
+%triggerpostun server -- ssh-server
+if [ "$1" != 0 ] ; then
+       /sbin/chkconfig --add sshd
+       if test -f /var/run/sshd.restart ; then
+               rm -f /var/run/sshd.restart
+               /sbin/service sshd start > /dev/null 2>&1 || :
+       fi
+fi
+
+%pre server
+%{_sbindir}/groupadd -r -g %{sshd_gid} sshd 2>/dev/null || :
+%{_sbindir}/useradd -d /var/empty/sshd -s /bin/false -u %{sshd_uid} \
+       -g sshd -M -r sshd 2>/dev/null || :
+
+%post server
+/sbin/chkconfig --add sshd
+
+%postun server
+/sbin/service sshd condrestart > /dev/null 2>&1 || :
+
+%preun server
+if [ "$1" = 0 ]
+then
+       /sbin/service sshd stop > /dev/null 2>&1 || :
+       /sbin/chkconfig --del sshd
+fi
+
+%files
+%defattr(-,root,root)
+%doc CREDITS ChangeLog INSTALL LICENCE OVERVIEW README* PROTOCOL* TODO WARNING*
+%attr(0755,root,root) %{_bindir}/scp
+%attr(0644,root,root) %{_mandir}/man1/scp.1*
+%attr(0755,root,root) %dir %{_sysconfdir}/ssh
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli
+%if ! %{rescue}
+%attr(0755,root,root) %{_bindir}/ssh-keygen
+%attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1*
+%attr(0755,root,root) %dir %{_libexecdir}/openssh
+%attr(4711,root,root) %{_libexecdir}/openssh/ssh-keysign
+%attr(0755,root,root) %{_libexecdir}/openssh/ssh-pkcs11-helper
+%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8*
+%attr(0644,root,root) %{_mandir}/man8/ssh-pkcs11-helper.8*
+%endif
+%if %{scard}
+%attr(0755,root,root) %dir %{_datadir}/openssh
+%attr(0644,root,root) %{_datadir}/openssh/Ssh.bin
+%endif
+
+%files clients
+%defattr(-,root,root)
+%attr(0755,root,root) %{_bindir}/ssh
+%attr(0644,root,root) %{_mandir}/man1/ssh.1*
+%attr(0644,root,root) %{_mandir}/man5/ssh_config.5*
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config
+%attr(-,root,root) %{_bindir}/slogin
+%attr(-,root,root) %{_mandir}/man1/slogin.1*
+%if ! %{rescue}
+%attr(2755,root,nobody) %{_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-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*
+%endif
+
+%if ! %{rescue}
+%files server
+%defattr(-,root,root)
+%dir %attr(0111,root,root) %{_var}/empty/sshd
+%attr(0755,root,root) %{_sbindir}/sshd
+%attr(0755,root,root) %{_libexecdir}/openssh/sftp-server
+%attr(0644,root,root) %{_mandir}/man8/sshd.8*
+%attr(0644,root,root) %{_mandir}/man5/moduli.5*
+%attr(0644,root,root) %{_mandir}/man5/sshd_config.5*
+%attr(0644,root,root) %{_mandir}/man8/sftp-server.8*
+%attr(0755,root,root) %dir %{_sysconfdir}/ssh
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config
+%attr(0600,root,root) %config(noreplace) /etc/pam.d/sshd
+%attr(0755,root,root) %config /etc/rc.d/init.d/sshd
+%endif
+
+%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) %config %{_sysconfdir}/profile.d/gnome-ssh-askpass.*
+%attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass
+%endif
+
+%changelog
+* Wed Jul 14 2010 Tim Rice <tim@multitalents.net>
+- test for skip_x11_askpass (line 77) should have been for no_x11_askpass
+
+* Mon Jun 2 2003 Damien Miller <djm@mindrot.org>
+- Remove noip6 option. This may be controlled at run-time in client config
+  file using new AddressFamily directive
+
+* Mon May 12 2003 Damien Miller <djm@mindrot.org>
+- Don't install profile.d scripts when not building with GNOME/GTK askpass
+  (patch from bet@rahul.net)
+
+* Wed Oct 01 2002 Damien Miller <djm@mindrot.org>
+- Install ssh-agent setgid nobody to prevent ptrace() key theft attacks
+
+* Mon Sep 30 2002 Damien Miller <djm@mindrot.org>
+- Use contrib/ Makefile for building askpass programs
+
+* Fri Jun 21 2002 Damien Miller <djm@mindrot.org>
+- Merge in spec changes from seba@iq.pl (Sebastian Pachuta)
+- Add new {ssh,sshd}_config.5 manpages
+- Add new ssh-keysign program and remove setuid from ssh client
+
+* Fri May 10 2002 Damien Miller <djm@mindrot.org>
+- Merge in spec changes from RedHat, reorgansie a little
+- Add Privsep user, group and directory
+
+* Thu Mar  7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-2
+- bump and grind (through the build system)
+
+* Thu Mar  7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-1
+- require sharutils for building (mindrot #137)
+- require db1-devel only when building for 6.x (#55105), which probably won't
+  work anyway (3.1 requires OpenSSL 0.9.6 to build), but what the heck
+- require pam-devel by file (not by package name) again
+- add Markus's patch to compile with OpenSSL 0.9.5a (from
+  http://bugzilla.mindrot.org/show_bug.cgi?id=141) and apply it if we're
+  building for 6.x
+
+* Thu Mar  7 2002 Nalin Dahyabhai <nalin@redhat.com> 3.1p1-0
+- update to 3.1p1
+
+* Tue Mar  5 2002 Nalin Dahyabhai <nalin@redhat.com> SNAP-20020305
+- update to SNAP-20020305
+- drop debug patch, fixed upstream
+
+* Wed Feb 20 2002 Nalin Dahyabhai <nalin@redhat.com> SNAP-20020220
+- update to SNAP-20020220 for testing purposes (you've been warned, if there's
+  anything to be warned about, gss patches won't apply, I don't mind)
+
+* Wed Feb 13 2002 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-3
+- add patches from Simon Wilkinson and Nicolas Williams for GSSAPI key
+  exchange, authentication, and named key support
+
+* Wed Jan 23 2002 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-2
+- remove dependency on db1-devel, which has just been swallowed up whole
+  by gnome-libs-devel
+
+* Sun Dec 29 2001 Nalin Dahyabhai <nalin@redhat.com>
+- adjust build dependencies so that build6x actually works right (fix
+  from Hugo van der Kooij)
+
+* Tue Dec  4 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0.2p1-1
+- update to 3.0.2p1
+
+* Fri Nov 16 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0.1p1-1
+- update to 3.0.1p1
+
+* Tue Nov 13 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to current CVS (not for use in distribution)
+
+* Thu Nov  8 2001 Nalin Dahyabhai <nalin@redhat.com> 3.0p1-1
+- merge some of Damien Miller <djm@mindrot.org> changes from the upstream
+  3.0p1 spec file and init script
+
+* Wed Nov  7 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 3.0p1
+- update to x11-ssh-askpass 1.2.4.1
+- change build dependency on a file from pam-devel to the pam-devel package
+- replace primes with moduli
+
+* Thu Sep 27 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-9
+- incorporate fix from Markus Friedl's advisory for IP-based authorization bugs
+
+* Thu Sep 13 2001 Bernhard Rosenkraenzer <bero@redhat.com> 2.9p2-8
+- Merge changes to rescue build from current sysadmin survival cd
+
+* Thu Sep  6 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-7
+- fix scp's server's reporting of file sizes, and build with the proper
+  preprocessor define to get large-file capable open(), stat(), etc.
+  (sftp has been doing this correctly all along) (#51827)
+- configure without --with-ipv4-default on RHL 7.x and newer (#45987,#52247)
+- pull cvs patch to fix support for /etc/nologin for non-PAM logins (#47298)
+- mark profile.d scriptlets as config files (#42337)
+- refer to Jason Stone's mail for zsh workaround for exit-hanging quasi-bug
+- change a couple of log() statements to debug() statements (#50751)
+- pull cvs patch to add -t flag to sshd (#28611)
+- clear fd_sets correctly (one bit per FD, not one byte per FD) (#43221)
+
+* Mon Aug 20 2001 Nalin Dahyabhai <nalin@redhat.com> 2.9p2-6
+- add db1-devel as a BuildPrerequisite (noted by Hans Ecke)
+
+* Thu Aug 16 2001 Nalin Dahyabhai <nalin@redhat.com>
+- pull cvs patch to fix remote port forwarding with protocol 2
+
+* Thu Aug  9 2001 Nalin Dahyabhai <nalin@redhat.com>
+- pull cvs patch to add session initialization to no-pty sessions
+- pull cvs patch to not cut off challengeresponse auth needlessly
+- refuse to do X11 forwarding if xauth isn't there, handy if you enable
+  it by default on a system that doesn't have X installed (#49263)
+
+* Wed Aug  8 2001 Nalin Dahyabhai <nalin@redhat.com>
+- don't apply patches to code we don't intend to build (spotted by Matt Galgoci)
+
+* Mon Aug  6 2001 Nalin Dahyabhai <nalin@redhat.com>
+- pass OPTIONS correctly to initlog (#50151)
+
+* Wed Jul 25 2001 Nalin Dahyabhai <nalin@redhat.com>
+- switch to x11-ssh-askpass 1.2.2
+
+* Wed Jul 11 2001 Nalin Dahyabhai <nalin@redhat.com>
+- rebuild in new environment
+
+* Mon Jun 25 2001 Nalin Dahyabhai <nalin@redhat.com>
+- disable the gssapi patch
+
+* Mon Jun 18 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 2.9p2
+- refresh to a new version of the gssapi patch
+
+* Thu Jun  7 2001 Nalin Dahyabhai <nalin@redhat.com>
+- change Copyright: BSD to License: BSD
+- add Markus Friedl's unverified patch for the cookie file deletion problem
+  so that we can verify it
+- drop patch to check if xauth is present (was folded into cookie patch)
+- don't apply gssapi patches for the errata candidate
+- clear supplemental groups list at startup
+
+* Fri May 25 2001 Nalin Dahyabhai <nalin@redhat.com>
+- fix an error parsing the new default sshd_config
+- add a fix from Markus Friedl (via openssh-unix-dev) for ssh-keygen not
+  dealing with comments right
+
+* Thu May 24 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add in Simon Wilkinson's GSSAPI patch to give it some testing in-house,
+  to be removed before the next beta cycle because it's a big departure
+  from the upstream version
+
+* Thu May  3 2001 Nalin Dahyabhai <nalin@redhat.com>
+- finish marking strings in the init script for translation
+- modify init script to source /etc/sysconfig/sshd and pass $OPTIONS to sshd
+  at startup (change merged from openssh.com init script, originally by
+  Pekka Savola)
+- refuse to do X11 forwarding if xauth isn't there, handy if you enable
+  it by default on a system that doesn't have X installed
+
+* Wed May  2 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 2.9
+- drop various patches that came from or went upstream or to or from CVS
+
+* Wed Apr 18 2001 Nalin Dahyabhai <nalin@redhat.com>
+- only require initscripts 5.00 on 6.2 (reported by Peter Bieringer)
+
+* Sun Apr  8 2001 Preston Brown <pbrown@redhat.com>
+- remove explicit openssl requirement, fixes builddistro issue
+- make initscript stop() function wait until sshd really dead to avoid
+  races in condrestart
+
+* Mon Apr  2 2001 Nalin Dahyabhai <nalin@redhat.com>
+- mention that challengereponse supports PAM, so disabling password doesn't
+  limit users to pubkey and rsa auth (#34378)
+- bypass the daemon() function in the init script and call initlog directly,
+  because daemon() won't start a daemon it detects is already running (like
+  open connections)
+- require the version of openssl we had when we were built
+
+* Fri Mar 23 2001 Nalin Dahyabhai <nalin@redhat.com>
+- make do_pam_setcred() smart enough to know when to establish creds and
+  when to reinitialize them
+- add in a couple of other fixes from Damien for inclusion in the errata
+
+* Thu Mar 22 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 2.5.2p2
+- call setcred() again after initgroups, because the "creds" could actually
+  be group memberships
+
+* Tue Mar 20 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 2.5.2p1 (includes endianness fixes in the rijndael implementation)
+- don't enable challenge-response by default until we find a way to not
+  have too many userauth requests (we may make up to six pubkey and up to
+  three password attempts as it is)
+- remove build dependency on rsh to match openssh.com's packages more closely
+
+* Sat Mar  3 2001 Nalin Dahyabhai <nalin@redhat.com>
+- remove dependency on openssl -- would need to be too precise
+
+* Fri Mar  2 2001 Nalin Dahyabhai <nalin@redhat.com>
+- rebuild in new environment
+
+* Mon Feb 26 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Revert the patch to move pam_open_session.
+- Init script and spec file changes from Pekka Savola. (#28750)
+- Patch sftp to recognize '-o protocol' arguments. (#29540)
+
+* Thu Feb 22 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Chuck the closing patch.
+- Add a trigger to add host keys for protocol 2 to the config file, now that
+  configuration file syntax requires us to specify it with HostKey if we
+  specify any other HostKey values, which we do.
+
+* Tue Feb 20 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Redo patch to move pam_open_session after the server setuid()s to the user.
+- Rework the nopam patch to use be picked up by autoconf.
+
+* Mon Feb 19 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Update for 2.5.1p1.
+- Add init script mods from Pekka Savola.
+- Tweak the init script to match the CVS contrib script more closely.
+- Redo patch to ssh-add to try to adding both identity and id_dsa to also try
+  adding id_rsa.
+
+* Fri Feb 16 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Update for 2.5.0p1.
+- Use $RPM_OPT_FLAGS instead of -O when building gnome-ssh-askpass
+- Resync with parts of Damien Miller's openssh.spec from CVS, including
+  update of x11 askpass to 1.2.0.
+- Only require openssl (don't prereq) because we generate keys in the init
+  script now.
+
+* Tue Feb 13 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Don't open a PAM session until we've forked and become the user (#25690).
+- Apply Andrew Bartlett's patch for letting pam_authenticate() know which
+  host the user is attempting a login from.
+- Resync with parts of Damien Miller's openssh.spec from CVS.
+- Don't expose KbdInt responses in debug messages (from CVS).
+- Detect and handle errors in rsa_{public,private}_decrypt (from CVS).
+
+* Wed Feb  7 2001 Trond Eivind Glomsrxd <teg@redhat.com>
+- i18n-tweak to initscript.
+
+* Tue Jan 23 2001 Nalin Dahyabhai <nalin@redhat.com>
+- More gettextizing.
+- Close all files after going into daemon mode (needs more testing).
+- Extract patch from CVS to handle auth banners (in the client).
+- Extract patch from CVS to handle compat weirdness.
+
+* Fri Jan 19 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Finish with the gettextizing.
+
+* Thu Jan 18 2001 Nalin Dahyabhai <nalin@redhat.com>
+- Fix a bug in auth2-pam.c (#23877)
+- Gettextize the init script.
+
+* Wed Dec 20 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Incorporate a switch for using PAM configs for 6.x, just in case.
+
+* Tue Dec  5 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Incorporate Bero's changes for a build specifically for rescue CDs.
+
+* Wed Nov 29 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Don't treat pam_setcred() failure as fatal unless pam_authenticate() has
+  succeeded, to allow public-key authentication after a failure with "none"
+  authentication.  (#21268)
+
+* Tue Nov 28 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to x11-askpass 1.1.1. (#21301)
+- Don't second-guess fixpaths, which causes paths to get fixed twice. (#21290)
+
+* Mon Nov 27 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Merge multiple PAM text messages into subsequent prompts when possible when
+  doing keyboard-interactive authentication.
+
+* Sun Nov 26 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Disable the built-in MD5 password support.  We're using PAM.
+- Take a crack at doing keyboard-interactive authentication with PAM, and
+  enable use of it in the default client configuration so that the client
+  will try it when the server disallows password authentication.
+- Build with debugging flags.  Build root policies strip all binaries anyway.
+
+* Tue Nov 21 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Use DESTDIR instead of %%makeinstall.
+- Remove /usr/X11R6/bin from the path-fixing patch.
+
+* Mon Nov 20 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Add the primes file from the latest snapshot to the main package (#20884).
+- Add the dev package to the prereq list (#19984).
+- Remove the default path and mimic login's behavior in the server itself.
+
+* Fri Nov 17 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Resync with conditional options in Damien Miller's .spec file for an errata.
+- Change libexecdir from %%{_libexecdir}/ssh to %%{_libexecdir}/openssh.
+
+* Tue Nov  7 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to OpenSSH 2.3.0p1.
+- Update to x11-askpass 1.1.0.
+- Enable keyboard-interactive authentication.
+
+* Mon Oct 30 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to ssh-askpass-x11 1.0.3.
+- Change authentication related messages to be private (#19966).
+
+* Tue Oct 10 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Patch ssh-keygen to be able to list signatures for DSA public key files
+  it generates.
+
+* Thu Oct  5 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Add BuildPreReq on /usr/include/security/pam_appl.h to be sure we always
+  build PAM authentication in.
+- Try setting SSH_ASKPASS if gnome-ssh-askpass is installed.
+- Clean out no-longer-used patches.
+- Patch ssh-add to try to add both identity and id_dsa, and to error only
+  when neither exists.
+
+* Mon Oct  2 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update x11-askpass to 1.0.2. (#17835)
+- Add BuildPreReqs for /bin/login and /usr/bin/rsh so that configure will
+  always find them in the right place. (#17909)
+- Set the default path to be the same as the one supplied by /bin/login, but
+  add /usr/X11R6/bin. (#17909)
+- Try to handle obsoletion of ssh-server more cleanly.  Package names
+  are different, but init script name isn't. (#17865)
+
+* Wed Sep  6 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 2.2.0p1. (#17835)
+- Tweak the init script to allow proper restarting. (#18023)
+
+* Wed Aug 23 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 20000823 snapshot.
+- Change subpackage requirements from %%{version} to %%{version}-%%{release}
+- Back out the pipe patch.
+
+* Mon Jul 17 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 2.1.1p4, which includes fixes for config file parsing problems.
+- Move the init script back.
+- Add Damien's quick fix for wackiness.
+
+* Wed Jul 12 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 2.1.1p3, which includes fixes for X11 forwarding and strtok().
+
+* Thu Jul  6 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Move condrestart to server postun.
+- Move key generation to init script.
+- Actually use the right patch for moving the key generation to the init script.
+- Clean up the init script a bit.
+
+* Wed Jul  5 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Fix X11 forwarding, from mail post by Chan Shih-Ping Richard.
+
+* Sun Jul  2 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 2.1.1p2.
+- Use of strtok() considered harmful.
+
+* Sat Jul  1 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Get the build root out of the man pages.
+
+* Thu Jun 29 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Add and use condrestart support in the init script.
+- Add newer initscripts as a prereq.
+
+* Tue Jun 27 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Build in new environment (release 2)
+- Move -clients subpackage to Applications/Internet group
+
+* Fri Jun  9 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Update to 2.2.1p1
+
+* Sat Jun  3 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Patch to build with neither RSA nor RSAref.
+- Miscellaneous FHS-compliance tweaks.
+- Fix for possibly-compressed man pages.
+
+* 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/contrib/redhat/sshd.init b/contrib/redhat/sshd.init
new file mode 100755 (executable)
index 0000000..854aff6
--- /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
+
+# pull in sysconfig settings
+[ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd
+
+RETVAL=0
+prog="sshd"
+
+# Some functions to make the below more readable
+KEYGEN=/usr/bin/ssh-keygen
+SSHD=/usr/sbin/sshd
+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
+
+do_rsa1_keygen() {
+       if [ ! -s $RSA1_KEY ]; then
+               echo -n $"Generating SSH1 RSA host key: "
+               if $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $RSA1_KEY
+                       chmod 644 $RSA1_KEY.pub
+                       if [ -x /sbin/restorecon ]; then
+                           /sbin/restorecon $RSA1_KEY.pub
+                       fi
+                       success $"RSA1 key generation"
+                       echo
+               else
+                       failure $"RSA1 key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+
+do_rsa_keygen() {
+       if [ ! -s $RSA_KEY ]; then
+               echo -n $"Generating SSH2 RSA host key: "
+               if $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $RSA_KEY
+                       chmod 644 $RSA_KEY.pub
+                       if [ -x /sbin/restorecon ]; then
+                           /sbin/restorecon $RSA_KEY.pub
+                       fi
+                       success $"RSA key generation"
+                       echo
+               else
+                       failure $"RSA key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+
+do_dsa_keygen() {
+       if [ ! -s $DSA_KEY ]; then
+               echo -n $"Generating SSH2 DSA host key: "
+               if $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $DSA_KEY
+                       chmod 644 $DSA_KEY.pub
+                       if [ -x /sbin/restorecon ]; then
+                           /sbin/restorecon $DSA_KEY.pub
+                       fi
+                       success $"DSA key generation"
+                       echo
+               else
+                       failure $"DSA key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+
+do_restart_sanity_check()
+{
+       $SSHD -t
+       RETVAL=$?
+       if [ ! "$RETVAL" = 0 ]; then
+               failure $"Configuration file or keys are invalid"
+               echo
+       fi
+}
+
+start()
+{
+       # Create keys if necessary
+       do_rsa1_keygen
+       do_rsa_keygen
+       do_dsa_keygen
+
+       echo -n $"Starting $prog:"
+       $SSHD $OPTIONS && success || failure
+       RETVAL=$?
+       [ "$RETVAL" = 0 ] && touch /var/lock/subsys/sshd
+       echo
+}
+
+stop()
+{
+       echo -n $"Stopping $prog:"
+       killproc $SSHD -TERM
+       RETVAL=$?
+       [ "$RETVAL" = 0 ] && rm -f /var/lock/subsys/sshd
+       echo
+}
+
+reload()
+{
+       echo -n $"Reloading $prog:"
+       killproc $SSHD -HUP
+       RETVAL=$?
+       echo
+}
+
+case "$1" in
+       start)
+               start
+               ;;
+       stop)
+               stop
+               ;;
+       restart)
+               stop
+               start
+               ;;
+       reload)
+               reload
+               ;;
+       condrestart)
+               if [ -f /var/lock/subsys/sshd ] ; then
+                       do_restart_sanity_check
+                       if [ "$RETVAL" = 0 ] ; then
+                               stop
+                               # avoid race
+                               sleep 3
+                               start
+                       fi
+               fi
+               ;;
+       status)
+               status $SSHD
+               RETVAL=$?
+               ;;
+       *)
+               echo $"Usage: $0 {start|stop|restart|reload|condrestart|status}"
+               RETVAL=1
+esac
+exit $RETVAL
diff --git a/contrib/redhat/sshd.init.old b/contrib/redhat/sshd.init.old
new file mode 100755 (executable)
index 0000000..0deb608
--- /dev/null
@@ -0,0 +1,172 @@
+#!/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
+
+# pull in sysconfig settings
+[ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd
+
+RETVAL=0
+prog="sshd"
+
+# Some functions to make the below more readable
+KEYGEN=/usr/bin/ssh-keygen
+SSHD=/usr/sbin/sshd
+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 [ ! -s $RSA1_KEY ]; then
+               echo -n "Generating SSH1 RSA host key: "
+               if $KEYGEN -q -t rsa1 -f $RSA1_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $RSA1_KEY
+                       chmod 644 $RSA1_KEY.pub
+                       my_success "RSA1 key generation"
+                       echo
+               else
+                       my_failure "RSA1 key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+do_rsa_keygen() {
+       if [ ! -s $RSA_KEY ]; then
+               echo -n "Generating SSH2 RSA host key: "
+               if $KEYGEN -q -t rsa -f $RSA_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $RSA_KEY
+                       chmod 644 $RSA_KEY.pub
+                       my_success "RSA key generation"
+                       echo
+               else
+                       my_failure "RSA key generation"
+                       echo
+                       exit 1
+               fi
+       fi
+}
+do_dsa_keygen() {
+       if [ ! -s $DSA_KEY ]; then
+               echo -n "Generating SSH2 DSA host key: "
+               if $KEYGEN -q -t dsa -f $DSA_KEY -C '' -N '' >&/dev/null; then
+                       chmod 600 $DSA_KEY
+                       chmod 644 $DSA_KEY.pub
+                       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
+       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/contrib/redhat/sshd.pam b/contrib/redhat/sshd.pam
new file mode 100644 (file)
index 0000000..ffa5adb
--- /dev/null
@@ -0,0 +1,6 @@
+#%PAM-1.0
+auth       required     pam_stack.so service=system-auth
+account    required     pam_nologin.so
+account    required     pam_stack.so service=system-auth
+password   required     pam_stack.so service=system-auth
+session    required     pam_stack.so service=system-auth
diff --git a/contrib/redhat/sshd.pam.old b/contrib/redhat/sshd.pam.old
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/contrib/solaris/README b/contrib/solaris/README
new file mode 100755 (executable)
index 0000000..fefdd4b
--- /dev/null
@@ -0,0 +1,30 @@
+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.  As of 3.1p2 the script should work on all platforms that have
+SVR4 style package tools.
+
+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. look at the top of buildpkg.sh for the configurable options and put
+   any changes you want in openssh-config.local. Additional customizations
+   can be done to the build process by creating one or more of the following
+   scripts that will be sourced by buildpkg.sh.
+       pkg_post_make_install_fixes.sh pkg-post-prototype-edit.sh
+       pkg-preinstall.local pkg-postinstall.local pkg-preremove.local
+       pkg-postremove.local pkg-request.local
+4. Run "make package"
+
+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
+
diff --git a/contrib/ssh-copy-id b/contrib/ssh-copy-id
new file mode 100644 (file)
index 0000000..368645c
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# Shell script to install your public key 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/id_rsa.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" > /dev/null ; 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 ] && ssh-add -L >/dev/null 2>&1; then
+    GET_ID="$GET_ID ssh-add -L"
+  fi
+fi
+
+if [ -z "`eval $GET_ID`" ] && [ -r "${ID_FILE}" ] ; then
+  GET_ID="cat ${ID_FILE}"
+fi
+
+if [ -z "`eval $GET_ID`" ]; then
+  echo "$0: ERROR: No identities found" >&2
+  exit 1
+fi
+
+if [ "$#" -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
+  echo "Usage: $0 [-i [identity_file]] [user@]machine" >&2
+  exit 1
+fi
+
+# strip any trailing colon
+host=`echo $1 | sed 's/:$//'`
+
+{ eval "$GET_ID" ; } | ssh $host "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys" || exit 1
+
+cat <<EOF
+Now try logging into the machine, with "ssh '$host'", and check in:
+
+  ~/.ssh/authorized_keys
+
+to make sure we haven't added extra keys that you weren't expecting.
+
+EOF
+
diff --git a/contrib/ssh-copy-id.1 b/contrib/ssh-copy-id.1
new file mode 100644 (file)
index 0000000..cb15ab2
--- /dev/null
@@ -0,0 +1,75 @@
+.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 public key 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 and
+append the indicated identity file to that machine's
+.B ~/.ssh/authorized_keys
+file.
+.PP
+If the
+.B -i
+option is given then the identity file (defaults to
+.BR ~/.ssh/id_rsa.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 NOTES
+This program does not modify the permissions of any
+pre-existing files or directories. Therefore, if the remote
+.B sshd
+has
+.B StrictModes
+set in its
+configuration, then the user's home,
+.B ~/.ssh
+folder, and
+.B ~/.ssh/authorized_keys
+file may need to have group writability disabled manually, e.g. via
+
+.B "      chmod go-w ~ ~/.ssh ~/.ssh/authorized_keys"
+
+on the remote machine.
+
+.SH "SEE ALSO"
+.BR ssh (1),
+.BR ssh-agent (1),
+.BR sshd (8)
diff --git a/contrib/sshd.pam.freebsd b/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/contrib/sshd.pam.generic b/contrib/sshd.pam.generic
new file mode 100644 (file)
index 0000000..215f0fe
--- /dev/null
@@ -0,0 +1,8 @@
+#%PAM-1.0
+auth       required     /lib/security/pam_unix.so shadow nodelay
+account    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/contrib/suse/openssh.spec b/contrib/suse/openssh.spec
new file mode 100644 (file)
index 0000000..6afdcc4
--- /dev/null
@@ -0,0 +1,252 @@
+# Default values for additional components
+%define build_x11_askpass      1
+
+# Define the UID/GID to use for privilege separation
+%define sshd_gid       65
+%define sshd_uid       71
+
+# The version of x11-ssh-askpass to use
+%define xversion       1.2.4.1
+
+# Allow the ability to override defaults with -D skip_xxx=1
+%{?skip_x11_askpass:%define build_x11_askpass 0}
+
+Summary:       OpenSSH, a free Secure Shell (SSH) protocol implementation
+Name:          openssh
+Version:       5.8p1
+URL:           http://www.openssh.com/
+Release:       1
+Source0:       openssh-%{version}.tar.gz
+Source1:       x11-ssh-askpass-%{xversion}.tar.gz
+License:       BSD
+Group:         Productivity/Networking/SSH
+BuildRoot:     %{_tmppath}/openssh-%{version}-buildroot
+PreReq:                openssl
+Obsoletes:     ssh
+Provides:      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
+
+%package       askpass
+Summary:       A passphrase dialog for OpenSSH and the X window System.
+Group:         Productivity/Networking/SSH
+Requires:      openssh = %{version}
+Obsoletes:     ssh-extras
+Provides:      openssh:${_libdir}/ssh/ssh-askpass
+
+%if %{build_x11_askpass}
+BuildPrereq:   XFree86-devel
+%endif
+
+%description
+Ssh (Secure Shell) is 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.
+
+%description askpass
+Ssh (Secure Shell) is 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 contains an X Window System passphrase dialog for OpenSSH.
+
+%changelog
+* Wed Oct 26 2005 Iain Morgan <imorgan@nas.nasa.gov>
+- Removed accidental inclusion of --without-zlib-version-check
+* Tue Oct 25 2005 Iain Morgan <imorgan@nas.nasa.gov>
+- Overhaul to deal with newer versions of SuSE and OpenSSH
+* 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
+
+%if %{build_x11_askpass}
+%setup -q -a 1
+%else
+%setup -q
+%endif
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" \
+%configure     --prefix=/usr \
+               --sysconfdir=%{_sysconfdir}/ssh \
+               --mandir=%{_mandir} \
+               --with-privsep-path=/var/lib/empty \
+               --with-pam \
+               --with-tcp-wrappers \
+               --libexecdir=%{_libdir}/ssh
+make
+
+%if %{build_x11_askpass}
+cd x11-ssh-askpass-%{xversion}
+%configure     --mandir=/usr/X11R6/man \
+               --libexecdir=%{_libdir}/ssh
+xmkmf -a
+make
+cd ..
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT/
+install -d $RPM_BUILD_ROOT/etc/pam.d/
+install -d $RPM_BUILD_ROOT/etc/init.d/
+install -d $RPM_BUILD_ROOT/var/adm/fillup-templates
+install -m644 contrib/sshd.pam.generic $RPM_BUILD_ROOT/etc/pam.d/sshd
+install -m744 contrib/suse/rc.sshd $RPM_BUILD_ROOT/etc/init.d/sshd
+install -m744 contrib/suse/sysconfig.ssh \
+   $RPM_BUILD_ROOT/var/adm/fillup-templates
+
+%if %{build_x11_askpass}
+cd x11-ssh-askpass-%{xversion}
+make install install.man BINDIR=%{_libdir}/ssh DESTDIR=$RPM_BUILD_ROOT/
+rm -f $RPM_BUILD_ROOT/usr/share/Ssh.bin
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%pre
+/usr/sbin/groupadd -g %{sshd_gid} -o -r sshd 2> /dev/null || :
+/usr/sbin/useradd -r -o -g sshd -u %{sshd_uid} -s /bin/false -c "SSH Privilege Separation User" -d /var/lib/sshd sshd 2> /dev/null || :
+
+%post
+if [ ! -f /etc/ssh/ssh_host_key -o ! -s /etc/ssh/ssh_host_key ]; then
+       echo "Generating SSH RSA host key..."
+       /usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_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 -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' >&2
+fi
+%{fillup_and_insserv -n -s -y ssh sshd START_SSHD}
+%run_permissions
+
+%verifyscript
+%verify_permissions -e /etc/ssh/sshd_config -e /etc/ssh/ssh_config -e /usr/bin/ssh
+
+%preun
+%stop_on_removal sshd
+
+%postun
+%restart_on_update sshd
+%{insserv_cleanup}
+
+%files
+%defattr(-,root,root)
+%doc ChangeLog OVERVIEW README* PROTOCOL*
+%doc TODO CREDITS LICENCE
+%attr(0755,root,root) %dir %{_sysconfdir}/ssh
+%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ssh_config
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/sshd_config
+%attr(0600,root,root) %config(noreplace) %{_sysconfdir}/ssh/moduli
+%attr(0644,root,root) %config(noreplace) /etc/pam.d/sshd
+%attr(0755,root,root) %config /etc/init.d/sshd
+%attr(0755,root,root) %{_bindir}/ssh-keygen
+%attr(0755,root,root) %{_bindir}/scp
+%attr(0755,root,root) %{_bindir}/ssh
+%attr(-,root,root) %{_bindir}/slogin
+%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(0755,root,root) %{_sbindir}/sshd
+%attr(0755,root,root) %dir %{_libdir}/ssh
+%attr(0755,root,root) %{_libdir}/ssh/sftp-server
+%attr(4711,root,root) %{_libdir}/ssh/ssh-keysign
+%attr(0755,root,root) %{_libdir}/ssh/ssh-pkcs11-helper
+%attr(0644,root,root) %doc %{_mandir}/man1/scp.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/sftp.1*
+%attr(-,root,root) %doc %{_mandir}/man1/slogin.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/ssh.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/ssh-add.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/ssh-agent.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/ssh-keygen.1*
+%attr(0644,root,root) %doc %{_mandir}/man1/ssh-keyscan.1*
+%attr(0644,root,root) %doc %{_mandir}/man5/moduli.5*
+%attr(0644,root,root) %doc %{_mandir}/man5/ssh_config.5*
+%attr(0644,root,root) %doc %{_mandir}/man5/sshd_config.5*
+%attr(0644,root,root) %doc %{_mandir}/man8/sftp-server.8*
+%attr(0644,root,root) %doc %{_mandir}/man8/ssh-keysign.8*
+%attr(0644,root,root) %doc %{_mandir}/man8/ssh-pkcs11-helper.8*
+%attr(0644,root,root) %doc %{_mandir}/man8/sshd.8*
+%attr(0644,root,root) /var/adm/fillup-templates/sysconfig.ssh
+
+%if %{build_x11_askpass}
+%files askpass
+%defattr(-,root,root)
+%doc x11-ssh-askpass-%{xversion}/README
+%doc x11-ssh-askpass-%{xversion}/ChangeLog
+%doc x11-ssh-askpass-%{xversion}/SshAskpass*.ad
+%attr(0755,root,root) %{_libdir}/ssh/ssh-askpass
+%attr(0755,root,root) %{_libdir}/ssh/x11-ssh-askpass
+%attr(0644,root,root) %doc /usr/X11R6/man/man1/ssh-askpass.1x*
+%attr(0644,root,root) %doc /usr/X11R6/man/man1/x11-ssh-askpass.1x*
+%attr(0644,root,root) %config /usr/X11R6/lib/X11/app-defaults/SshAskpass
+%endif
diff --git a/contrib/suse/rc.config.sshd b/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/contrib/suse/rc.sshd b/contrib/suse/rc.sshd
new file mode 100644 (file)
index 0000000..4d4880d
--- /dev/null
@@ -0,0 +1,133 @@
+#! /bin/sh
+# Copyright (c) 1995-2000 SuSE GmbH Nuernberg, Germany.
+#
+# Author: Jiri Smid <feedback@suse.de>
+#
+# /etc/init.d/sshd
+#
+#   and symbolic its link
+#
+# /usr/sbin/rcsshd
+#
+### BEGIN INIT INFO
+# Provides: sshd
+# Required-Start: $network $remote_fs
+# Required-Stop: $network $remote_fs
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Description: Start the sshd daemon
+### END INIT INFO
+
+SSHD_BIN=/usr/sbin/sshd
+test -x $SSHD_BIN || exit 5
+
+SSHD_SYSCONFIG=/etc/sysconfig/ssh
+test -r $SSHD_SYSCONFIG || exit 6
+. $SSHD_SYSCONFIG
+
+SSHD_PIDFILE=/var/run/sshd.init.pid
+
+. /etc/rc.status
+
+# Shell functions sourced from /etc/rc.status:
+#      rc_check         check and set local and overall rc status
+#      rc_status        check and set local and overall rc status
+#      rc_status -v     ditto but be verbose in local rc status
+#      rc_status -v -r  ditto and clear the local rc status
+#      rc_failed        set local and overall rc status to failed
+#      rc_reset         clear local rc status (overall remains)
+#      rc_exit          exit appropriate to overall rc status
+
+# First reset status of this service
+rc_reset
+
+case "$1" in
+    start)
+        if ! test -f /etc/ssh/ssh_host_key ; then
+           echo Generating /etc/ssh/ssh_host_key.
+           ssh-keygen -t rsa1 -f /etc/ssh/ssh_host_key -N ''
+        fi
+        if ! test -f /etc/ssh/ssh_host_dsa_key ; then
+           echo Generating /etc/ssh/ssh_host_dsa_key.
+           
+           ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ''
+        fi
+        if ! test -f /etc/ssh/ssh_host_rsa_key ; then
+           echo Generating /etc/ssh/ssh_host_rsa_key.
+           
+           ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
+        fi
+       echo -n "Starting SSH daemon"
+       ## Start daemon with startproc(8). If this fails
+       ## the echo return value is set appropriate.
+
+       startproc -f -p $SSHD_PIDFILE /usr/sbin/sshd $SSHD_OPTS -o "PidFile=$SSHD_PIDFILE" 
+
+       # Remember status and be verbose
+       rc_status -v
+       ;;
+    stop)
+       echo -n "Shutting down SSH daemon"
+       ## Stop daemon with killproc(8) and if this fails
+       ## set echo the echo return value.
+
+       killproc -p $SSHD_PIDFILE -TERM /usr/sbin/sshd
+
+       # Remember status and be verbose
+       rc_status -v
+       ;;
+    try-restart)
+        ## Stop the service and if this succeeds (i.e. the 
+        ## service was running before), start it again.
+        $0 status >/dev/null &&  $0 restart
+
+        # Remember status and be quiet
+        rc_status
+        ;;
+    restart)
+        ## Stop the service and regardless of whether it was
+        ## running or not, start it again.
+        $0 stop
+        $0 start
+
+        # Remember status and be quiet
+        rc_status
+        ;;
+    force-reload|reload)
+       ## Signal the daemon to reload its config. Most daemons
+       ## do this on signal 1 (SIGHUP).
+
+       echo -n "Reload service sshd"
+
+       killproc -p $SSHD_PIDFILE -HUP /usr/sbin/sshd
+
+        rc_status -v
+
+        ;;
+    status)
+       echo -n "Checking for service sshd "
+        ## Check status with checkproc(8), if process is running
+        ## checkproc will return with exit status 0.
+
+        # Status has a slightly different for the status command:
+        # 0 - service running
+        # 1 - service dead, but /var/run/  pid  file exists
+        # 2 - service dead, but /var/lock/ lock file exists
+        # 3 - service not running
+
+       checkproc -p $SSHD_PIDFILE /usr/sbin/sshd
+
+       rc_status -v
+       ;;
+    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 $SSHD_PIDFILE && echo reload
+       ;;
+    *)
+       echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
+       exit 1
+       ;;
+esac
+rc_exit
diff --git a/contrib/suse/sysconfig.ssh b/contrib/suse/sysconfig.ssh
new file mode 100644 (file)
index 0000000..c6a37e5
--- /dev/null
@@ -0,0 +1,9 @@
+## Path:       Network/Remote access/SSH
+## Description:        SSH server settings
+## Type:       string
+## Default:    ""
+## ServiceRestart: sshd
+#
+# Options for sshd
+#
+SSHD_OPTS=""
diff --git a/crc32.c b/crc32.c
new file mode 100644 (file)
index 0000000..c192eb4
--- /dev/null
+++ b/crc32.c
@@ -0,0 +1,105 @@
+/* $OpenBSD: crc32.c,v 1.11 2006/04/22 18:29:33 stevesk Exp $ */
+
+/*
+ * Copyright (c) 2003 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 "crc32.h"
+
+static const u_int32_t crc32tab[] = {
+       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
+};
+
+u_int32_t
+ssh_crc32(const u_char *buf, u_int32_t size)
+{
+       u_int32_t i, crc;
+
+       crc = 0;
+       for (i = 0; i < size; i++)
+               crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8);
+       return crc;
+}
diff --git a/crc32.h b/crc32.h
new file mode 100644 (file)
index 0000000..5d7131a
--- /dev/null
+++ b/crc32.h
@@ -0,0 +1,30 @@
+/* $OpenBSD: crc32.h,v 1.15 2006/03/25 22:22:43 djm Exp $ */
+
+/*
+ * Copyright (c) 2003 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_CRC32_H
+#define SSH_CRC32_H
+u_int32_t       ssh_crc32(const u_char *, u_int32_t);
+#endif
diff --git a/deattack.c b/deattack.c
new file mode 100644 (file)
index 0000000..1b37e4d
--- /dev/null
@@ -0,0 +1,160 @@
+/* $OpenBSD: deattack.c,v 1.30 2006/09/16 19:53:37 djm 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 <sys/types.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "deattack.h"
+#include "log.h"
+#include "crc32.h"
+#include "misc.h"
+
+/*
+ * CRC attack detection has a worst-case behaviour that is O(N^3) over
+ * the number of identical blocks in a packet. This behaviour can be 
+ * exploited to create a limited denial of service attack. 
+ * 
+ * However, because we are dealing with encrypted data, identical
+ * blocks should only occur every 2^35 maximally-sized packets or so. 
+ * Consequently, we can detect this DoS by looking for identical blocks
+ * in a packet.
+ *
+ * The parameter below determines how many identical blocks we will
+ * accept in a single packet, trading off between attack detection and
+ * likelihood of terminating a legitimate connection. A value of 32 
+ * corresponds to an average of 2^40 messages before an attack is
+ * misdetected
+ */
+#define MAX_IDENTICAL  32
+
+/* 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_u32(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_int32_t crc;
+       u_char *c;
+
+       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)
+{
+       static u_int16_t *h = (u_int16_t *) NULL;
+       static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
+       u_int32_t i, j;
+       u_int32_t l, same;
+       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.");
+               h = (u_int16_t *) xcalloc(l, HASH_ENTRYSIZE);
+               n = l;
+       } else {
+               if (l > n) {
+                       h = (u_int16_t *)xrealloc(h, l, HASH_ENTRYSIZE);
+                       n = l;
+               }
+       }
+
+       if (len <= HASH_MINBLOCKS) {
+               for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
+                       for (d = buf; d < c; d += SSH_BLOCKSIZE) {
+                               if (!CMP(c, d)) {
+                                       if ((check_crc(c, buf, len)))
+                                               return (DEATTACK_DETECTED);
+                                       else
+                                               break;
+                               }
+                       }
+               }
+               return (DEATTACK_OK);
+       }
+       memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
+
+       for (c = buf, same = 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 (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
+                               if (++same > MAX_IDENTICAL)
+                                       return (DEATTACK_DOS_DETECTED);
+                               if (check_crc(c, buf, len))
+                                       return (DEATTACK_DETECTED);
+                               else
+                                       break;
+                       }
+               }
+               h[i] = j;
+       }
+       return (DEATTACK_OK);
+}
diff --git a/deattack.h b/deattack.h
new file mode 100644 (file)
index 0000000..0316fb2
--- /dev/null
@@ -0,0 +1,31 @@
+/* $OpenBSD: deattack.h,v 1.10 2006/09/16 19:53:37 djm 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
+#define DEATTACK_DOS_DETECTED  2
+
+int     detect_attack(u_char *, u_int32_t);
+#endif
diff --git a/defines.h b/defines.h
new file mode 100644 (file)
index 0000000..cd27306
--- /dev/null
+++ b/defines.h
@@ -0,0 +1,810 @@
+/*
+ * Copyright (c) 1999-2003 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.
+ */
+
+#ifndef _DEFINES_H
+#define _DEFINES_H
+
+/* $Id: defines.h,v 1.164 2011/01/17 10:15:31 dtucker Exp $ */
+
+
+/* Constants */
+
+#if defined(HAVE_DECL_SHUT_RD) && HAVE_DECL_SHUT_RD == 0
+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
+
+/*
+ * Definitions for IP type of service (ip_tos)
+ */
+#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 */
+
+/*
+ * Definitions for DiffServ Codepoints as per RFC2474
+ */
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifndef IPTOS_DSCP_AF11
+# define       IPTOS_DSCP_AF11         0x28
+# define       IPTOS_DSCP_AF12         0x30
+# define       IPTOS_DSCP_AF13         0x38
+# define       IPTOS_DSCP_AF21         0x48
+# define       IPTOS_DSCP_AF22         0x50
+# define       IPTOS_DSCP_AF23         0x58
+# define       IPTOS_DSCP_AF31         0x68
+# define       IPTOS_DSCP_AF32         0x70
+# define       IPTOS_DSCP_AF33         0x78
+# define       IPTOS_DSCP_AF41         0x88
+# define       IPTOS_DSCP_AF42         0x90
+# define       IPTOS_DSCP_AF43         0x98
+# define       IPTOS_DSCP_EF           0xb8
+#endif /* IPTOS_DSCP_AF11 */
+#ifndef IPTOS_DSCP_CS0
+# define       IPTOS_DSCP_CS0          0x00
+# define       IPTOS_DSCP_CS1          0x20
+# define       IPTOS_DSCP_CS2          0x40
+# define       IPTOS_DSCP_CS3          0x60
+# define       IPTOS_DSCP_CS4          0x80
+# define       IPTOS_DSCP_CS5          0xa0
+# define       IPTOS_DSCP_CS6          0xc0
+# define       IPTOS_DSCP_CS7          0xe0
+#endif /* IPTOS_DSCP_CS0 */
+#ifndef IPTOS_DSCP_EF
+# define       IPTOS_DSCP_EF           0xb8
+#endif /* IPTOS_DSCP_EF */
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+#  define MAXPATHLEN PATH_MAX
+# else /* PATH_MAX */
+#  define MAXPATHLEN 64
+/* realpath uses a fixed buffer of size MAXPATHLEN, so force use of ours */
+#  ifndef BROKEN_REALPATH
+#   define BROKEN_REALPATH 1
+#  endif /* BROKEN_REALPATH */
+# endif /* PATH_MAX */
+#endif /* MAXPATHLEN */
+
+#ifndef PATH_MAX
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# endif
+#endif
+
+#if defined(HAVE_DECL_MAXSYMLINKS) && HAVE_DECL_MAXSYMLINKS == 0
+# define MAXSYMLINKS 5
+#endif
+
+#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
+
+#if defined(HAVE_DECL_O_NONBLOCK) && HAVE_DECL_O_NONBLOCK == 0
+# define O_NONBLOCK      00004 /* Non Blocking Open */
+#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 */
+
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+#ifndef MAP_FAILED
+# define MAP_FAILED ((void *)-1)
+#endif
+
+/* *-*-nto-qnx doesn't define this constant in the system headers */
+#ifdef MISSING_NFDBITS
+# define       NFDBITS (8 * sizeof(unsigned long))
+#endif
+
+/*
+SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but
+including rpc/rpc.h breaks Solaris 6
+*/
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ((u_long)0x7f000001)
+#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 _UNICOS
+#   if (SIZEOF_SHORT_INT == 4)
+typedef short int16_t;
+#   else
+typedef long  int16_t;
+#   endif
+#  else
+#   error "16 bit int type not found."
+#  endif /* _UNICOS */
+# endif
+# if (SIZEOF_INT == 4)
+typedef int int32_t;
+# else
+#  ifdef _UNICOS
+typedef long  int32_t;
+#  else
+#   error "32 bit int type not found."
+#  endif /* _UNICOS */
+# 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 _UNICOS
+#    if (SIZEOF_SHORT_INT == 4)
+typedef unsigned short u_int16_t;
+#    else
+typedef unsigned long  u_int16_t;
+#    endif
+#   else
+#    error "16 bit int type not found."
+#   endif
+#  endif
+#  if (SIZEOF_INT == 4)
+typedef unsigned int u_int32_t;
+#  else
+#   ifdef _UNICOS
+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;
+# else
+#  if (SIZEOF_LONG_LONG_INT == 8)
+typedef long long int int64_t;
+#  endif
+# endif
+#endif
+#ifndef HAVE_U_INT64_T
+# if (SIZEOF_LONG_INT == 8)
+typedef unsigned long int u_int64_t;
+# else
+#  if (SIZEOF_LONG_LONG_INT == 8)
+typedef unsigned long long int u_int64_t;
+#  endif
+# endif
+#endif
+
+#ifndef HAVE_U_CHAR
+typedef unsigned char u_char;
+# define HAVE_U_CHAR
+#endif /* HAVE_U_CHAR */
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ULONG_MAX
+#endif /* SIZE_T_MAX */
+
+#ifndef HAVE_SIZE_T
+typedef unsigned int size_t;
+# define HAVE_SIZE_T
+# define SIZE_T_MAX UINT_MAX
+#endif /* HAVE_SIZE_T */
+
+#ifndef SIZE_MAX
+#define SIZE_MAX SIZE_T_MAX
+#endif
+
+#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_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+# define HAVE_SIG_ATOMIC_T
+#endif /* HAVE_SIG_ATOMIC_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 */
+
+#ifndef HAVE_IN_ADDR_T
+typedef u_int32_t      in_addr_t;
+#endif
+#ifndef HAVE_IN_PORT_T
+typedef u_int16_t      in_port_t;
+#endif
+
+#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
+
+#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 SUPERUSER_PATH
+# define SUPERUSER_PATH        _PATH_STDPATH
+#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_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 */
+
+/* derived from XF4/xc/lib/dps/Xlibnet.h */
+#ifndef X_UNIX_PATH
+#  ifdef __hpux
+#    define X_UNIX_PATH "/var/spool/sockets/X11/%u"
+#  else
+#    define X_UNIX_PATH "/tmp/.X11-unix/X%u"
+#  endif
+#endif /* X_UNIX_PATH */
+#define _PATH_UNIX_X X_UNIX_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 TIMEVAL_TO_TIMESPEC
+#define        TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
+       (ts)->tv_sec = (tv)->tv_sec;                                    \
+       (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
+}
+#endif
+
+#ifndef TIMESPEC_TO_TIMEVAL
+#define        TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
+       (tv)->tv_sec = (ts)->tv_sec;                                    \
+       (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
+}
+#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) */
+
+#if !defined(HAVE_ATTRIBUTE__SENTINEL__) && !defined(__sentinel__)
+# define __sentinel__
+#endif
+
+#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__)
+# define __bounded__(x, y, z)
+#endif
+
+#if !defined(HAVE_ATTRIBUTE__NONNULL__) && !defined(__nonnull__)
+# define __nonnull__(x)
+#endif
+
+/* *-*-nto-qnx doesn't define this macro in the system headers */
+#ifdef MISSING_HOWMANY
+# define howmany(x,y)  (((x)+((y)-1))/(y))
+#endif
+
+#ifndef OSSH_ALIGNBYTES
+#define OSSH_ALIGNBYTES        (sizeof(int) - 1)
+#endif
+#ifndef __CMSG_ALIGN
+#define        __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES)
+#endif
+
+/* Length of the contents of a control message of length len */
+#ifndef CMSG_LEN
+#define        CMSG_LEN(len)   (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
+#endif
+
+/* Length of the space taken up by a padded control message of length len */
+#ifndef CMSG_SPACE
+#define        CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
+#endif
+
+/* given pointer to struct cmsghdr, return pointer to data */
+#ifndef CMSG_DATA
+#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + __CMSG_ALIGN(sizeof(struct cmsghdr)))
+#endif /* CMSG_DATA */
+
+/*
+ * RFC 2292 requires to check msg_controllen, in case that the kernel returns
+ * an empty list for some reasons.
+ */
+#ifndef CMSG_FIRSTHDR
+#define CMSG_FIRSTHDR(mhdr) \
+       ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \
+        (struct cmsghdr *)(mhdr)->msg_control : \
+        (struct cmsghdr *)NULL)
+#endif /* CMSG_FIRSTHDR */
+
+#if defined(HAVE_DECL_OFFSETOF) && HAVE_DECL_OFFSETOF == 0
+# define offsetof(type, member) ((size_t) &((type *)0)->member)
+#endif
+
+/* Set up BSD-style BYTE_ORDER definition if it isn't there already */
+/* XXX: doesn't try to cope with strange byte orders (PDP_ENDIAN) */
+#ifndef BYTE_ORDER
+# ifndef LITTLE_ENDIAN
+#  define LITTLE_ENDIAN  1234
+# endif /* LITTLE_ENDIAN */
+# ifndef BIG_ENDIAN
+#  define BIG_ENDIAN     4321
+# endif /* BIG_ENDIAN */
+# ifdef WORDS_BIGENDIAN
+#  define BYTE_ORDER BIG_ENDIAN
+# else /* WORDS_BIGENDIAN */
+#  define BYTE_ORDER LITTLE_ENDIAN
+# endif /* WORDS_BIGENDIAN */
+#endif /* BYTE_ORDER */
+
+/* Function replacement / compatibility hacks */
+
+#if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO))
+# define HAVE_GETADDRINFO
+#endif
+
+#ifndef HAVE_GETOPT_OPTRESET
+# undef getopt
+# undef opterr
+# undef optind
+# undef optopt
+# undef optreset
+# undef optarg
+# define getopt(ac, av, o)  BSDgetopt(ac, av, o)
+# define opterr             BSDopterr
+# define optind             BSDoptind
+# define optopt             BSDoptopt
+# define optreset           BSDoptreset
+# define optarg             BSDoptarg
+#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(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX)
+# undef HAVE_UPDWTMPX
+#endif
+
+#if defined(BROKEN_SHADOW_EXPIRE) && defined(HAS_SHADOW_EXPIRE)
+# undef HAS_SHADOW_EXPIRE
+#endif
+
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) && \
+    defined(SYSLOG_R_SAFE_IN_SIGHAND)
+# define DO_LOG_SAFE_IN_SIGHAND
+#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_VHANGUP) && !defined(HAVE_DEV_PTMX)
+#  define USE_VHANGUP
+#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */
+
+#ifndef GETPGRP_VOID
+# include <unistd.h>
+# define getpgrp() getpgrp(0)
+#endif
+
+#ifdef USE_BSM_AUDIT
+# define SSH_AUDIT_EVENTS
+# define CUSTOM_SSH_AUDIT_EVENTS
+#endif
+
+#ifdef USE_LINUX_AUDIT
+# define SSH_AUDIT_EVENTS
+# define CUSTOM_SSH_AUDIT_EVENTS
+#endif
+
+#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__)
+#  define __func__ __FUNCTION__
+#elif !defined(HAVE___func__)
+#  define __func__ ""
+#endif
+
+#if defined(KRB5) && !defined(HEIMDAL)
+#  define krb5_get_err_text(context,code) error_message(code)
+#endif
+
+#if defined(SKEYCHALLENGE_4ARG)
+# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c,d)
+#else
+# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c)
+#endif
+
+/* Maximum number of file descriptors available */
+#ifdef HAVE_SYSCONF
+# define SSH_SYSFDMAX sysconf(_SC_OPEN_MAX)
+#else
+# define SSH_SYSFDMAX 10000
+#endif
+
+#ifdef FSID_HAS_VAL
+/* encode f_fsid into a 64 bit value  */
+#define FSID_TO_ULONG(f) \
+       ((((u_int64_t)(f).val[0] & 0xffffffffUL) << 32) | \
+           ((f).val[1] & 0xffffffffUL))
+#elif defined(FSID_HAS___VAL)
+#define FSID_TO_ULONG(f) \
+       ((((u_int64_t)(f).__val[0] & 0xffffffffUL) << 32) | \
+           ((f).__val[1] & 0xffffffffUL))
+#else
+# define FSID_TO_ULONG(f) ((f))
+#endif
+
+#if defined(__Lynx__)
+ /*
+  * LynxOS defines these in param.h which we do not want to include since
+  * it will also pull in a bunch of kernel definitions.
+  */
+# define ALIGNBYTES (sizeof(int) - 1)
+# define ALIGN(p) (((unsigned)p + ALIGNBYTES) & ~ALIGNBYTES)
+  /* Missing prototypes on LynxOS */
+  int snprintf (char *, size_t, const char *, ...);
+  int mkstemp (char *);
+  char *crypt (const char *, const char *);
+  int seteuid (uid_t);
+  int setegid (gid_t);
+  char *mkdtemp (char *);
+  int rresvport_af (int *, sa_family_t);
+  int innetgr (const char *, const char *, const char *, const char *);
+#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
+ **/
+
+/* 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
+
+#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+# define USE_SHADOW
+#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(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
+
+#ifndef UT_LINESIZE
+# define UT_LINESIZE 8
+#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
+
+#ifdef HAVE_OSF_SIA
+# ifdef USE_SHADOW
+#  undef USE_SHADOW
+# endif
+# define CUSTOM_SYS_AUTH_PASSWD 1
+#endif
+
+#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(HAVE_SECUREWARE)
+# define CUSTOM_SYS_AUTH_PASSWD 1
+#endif
+#if defined(HAVE_LIBIAF) && defined(HAVE_SET_ID) && !defined(BROKEN_LIBIAF)
+# define USE_LIBIAF
+#endif
+
+/* HP-UX 11.11 */
+#ifdef BTMP_FILE
+# define _PATH_BTMP BTMP_FILE
+#endif
+
+#if defined(USE_BTMP) && defined(_PATH_BTMP)
+# define CUSTOM_FAILED_LOGIN
+#endif
+
+/** end of login recorder definitions */
+
+#ifdef BROKEN_GETGROUPS
+# define getgroups(a,b) ((a)==0 && (b)==NULL ? NGROUPS_MAX : getgroups((a),(b)))
+#endif
+
+#if defined(HAVE_MMAP) && defined(BROKEN_MMAP)
+# undef HAVE_MMAP
+#endif
+
+#ifndef IOV_MAX
+# if defined(_XOPEN_IOV_MAX)
+#  define      IOV_MAX         _XOPEN_IOV_MAX
+# elif defined(DEF_IOV_MAX)
+#  define      IOV_MAX         DEF_IOV_MAX
+# else
+#  define      IOV_MAX         16
+# endif
+#endif
+
+#ifndef EWOULDBLOCK
+# define EWOULDBLOCK EAGAIN
+#endif
+
+#ifndef INET6_ADDRSTRLEN       /* for non IPv6 machines */
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef SSH_IOBUFSZ
+# define SSH_IOBUFSZ 8192
+#endif
+
+#ifndef _NSIG
+# ifdef NSIG
+#  define _NSIG NSIG
+# else
+#  define _NSIG 128
+# endif
+#endif
+
+#endif /* _DEFINES_H */
diff --git a/dh.c b/dh.c
new file mode 100644 (file)
index 0000000..b9029d8
--- /dev/null
+++ b/dh.c
@@ -0,0 +1,346 @@
+/* $OpenBSD: dh.c,v 1.48 2009/10/01 11:37:33 grunk 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.
+ */
+
+#include "includes.h"
+
+#include <sys/param.h>
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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;
+       const char *errstr = NULL;
+       long long n;
+
+       cp = line;
+       if ((arg = strdelim(&cp)) == NULL)
+               return 0;
+       /* Ignore leading whitespace */
+       if (*arg == '\0')
+               arg = strdelim(&cp);
+       if (!arg || !*arg || *arg == '#')
+               return 0;
+
+       /* time */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       arg = strsep(&cp, " "); /* type */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       /* Ensure this is a safe prime */
+       n = strtonum(arg, 0, 5, &errstr);
+       if (errstr != NULL || n != MODULI_TYPE_SAFE)
+               goto fail;
+       arg = strsep(&cp, " "); /* tests */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       /* Ensure prime has been tested and is not composite */
+       n = strtonum(arg, 0, 0x1f, &errstr);
+       if (errstr != NULL ||
+           (n & MODULI_TESTS_COMPOSITE) || !(n & ~MODULI_TESTS_COMPOSITE))
+               goto fail;
+       arg = strsep(&cp, " "); /* tries */
+       if (cp == NULL || *arg == '\0')
+               goto fail;
+       n = strtonum(arg, 0, 1<<30, &errstr);
+       if (errstr != NULL || n == 0)
+               goto fail;
+       strsize = strsep(&cp, " "); /* size */
+       if (cp == NULL || *strsize == '\0' ||
+           (dhg->size = (int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 ||
+           errstr)
+               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;
+
+       if ((dhg->g = BN_new()) == NULL)
+               fatal("parse_prime: BN_new failed");
+       if ((dhg->p = BN_new()) == NULL)
+               fatal("parse_prime: BN_new failed");
+       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;
+
+       if (BN_is_zero(dhg->g) || BN_is_one(dhg->g))
+               goto failclean;
+
+       return (1);
+
+ failclean:
+       BN_clear_free(dhg->g);
+       BN_clear_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[4096];
+       int best, bestcount, which;
+       int linenum;
+       struct dhgroup dhg;
+
+       if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
+           (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
+               logit("WARNING: %s does not exist, using fixed modulus",
+                   _PATH_DH_MODULI);
+               return (dh_new_group14());
+       }
+
+       linenum = 0;
+       best = bestcount = 0;
+       while (fgets(line, sizeof(line), f)) {
+               linenum++;
+               if (!parse_prime(linenum, line, &dhg))
+                       continue;
+               BN_clear_free(dhg.g);
+               BN_clear_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);
+               logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
+               return (dh_new_group14());
+       }
+
+       linenum = 0;
+       which = arc4random_uniform(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_clear_free(dhg.g);
+                       BN_clear_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-groupN-sha1 */
+
+int
+dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
+{
+       int i;
+       int n = BN_num_bits(dh_pub);
+       int bits_set = 0;
+       BIGNUM *tmp;
+
+       if (dh_pub->neg) {
+               logit("invalid public DH value: negative");
+               return 0;
+       }
+       if (BN_cmp(dh_pub, BN_value_one()) != 1) {      /* pub_exp <= 1 */
+               logit("invalid public DH value: <= 1");
+               return 0;
+       }
+
+       if ((tmp = BN_new()) == NULL) {
+               error("%s: BN_new failed", __func__);
+               return 0;
+       }
+       if (!BN_sub(tmp, dh->p, BN_value_one()) ||
+           BN_cmp(dh_pub, tmp) != -1) {                /* pub_exp > p-2 */
+               BN_clear_free(tmp);
+               logit("invalid public DH value: >= p-1");
+               return 0;
+       }
+       BN_clear_free(tmp);
+
+       for (i = 0; i <= n; i++)
+               if (BN_is_bit_set(dh_pub, i))
+                       bits_set++;
+       debug2("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)
+               return 1;
+
+       logit("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, tries = 0;
+
+       if (dh->p == NULL)
+               fatal("dh_gen_key: dh->p == NULL");
+       if (need > INT_MAX / 2 || 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_clear_free(dh->priv_key);
+               if ((dh->priv_key = BN_new()) == 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, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++)
+                       if (BN_is_bit_set(dh->priv_key, i))
+                               bits_set++;
+               debug2("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;
+
+       if ((dh = DH_new()) == NULL)
+               fatal("dh_new_group_asc: 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;
+
+       if ((dh = DH_new()) == NULL)
+               fatal("dh_new_group: 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));
+}
+
+DH *
+dh_new_group14(void)
+{
+       static char *gen = "2", *group14 =
+           "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" "ECE45B3D"
+           "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
+           "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
+           "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
+           "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
+           "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
+           "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
+
+       return (dh_new_group_asc(gen, group14));
+}
+
+/*
+ * 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 <= 128)
+               return (1024);  /* O(2**86) */
+       if (bits <= 192)
+               return (2048);  /* O(2**116) */
+       return (4096);          /* O(2**156) */
+}
diff --git a/dh.h b/dh.h
new file mode 100644 (file)
index 0000000..dfc1480
--- /dev/null
+++ b/dh.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: dh.h,v 1.10 2008/06/26 09:19:40 djm 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);
+DH     *dh_new_group14(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
+
+/*
+ * Values for "type" field of moduli(5)
+ * Specifies the internal structure of the prime modulus.
+ */
+#define MODULI_TYPE_UNKNOWN            (0)
+#define MODULI_TYPE_UNSTRUCTURED       (1)
+#define MODULI_TYPE_SAFE               (2)
+#define MODULI_TYPE_SCHNORR            (3)
+#define MODULI_TYPE_SOPHIE_GERMAIN     (4)
+#define MODULI_TYPE_STRONG             (5)
+
+/*
+ * Values for "tests" field of moduli(5)
+ * Specifies the methods used in checking for primality.
+ * Usually, more than one test is used.
+ */
+#define MODULI_TESTS_UNTESTED          (0x00)
+#define MODULI_TESTS_COMPOSITE         (0x01)
+#define MODULI_TESTS_SIEVE             (0x02)
+#define MODULI_TESTS_MILLER_RABIN      (0x04)
+#define MODULI_TESTS_JACOBI            (0x08)
+#define MODULI_TESTS_ELLIPTIC          (0x10)
+
+
+#endif
diff --git a/dispatch.c b/dispatch.c
new file mode 100644 (file)
index 0000000..64bb809
--- /dev/null
@@ -0,0 +1,104 @@
+/* $OpenBSD: dispatch.c,v 1.22 2008/10/31 15:05:34 stevesk 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 <sys/types.h>
+
+#include <signal.h>
+#include <stdarg.h>
+
+#include "ssh1.h"
+#include "ssh2.h"
+#include "log.h"
+#include "dispatch.h"
+#include "packet.h"
+#include "compat.h"
+
+#define DISPATCH_MAX   255
+
+dispatch_fn *dispatch[DISPATCH_MAX];
+
+void
+dispatch_protocol_error(int type, u_int32_t seq, void *ctxt)
+{
+       logit("dispatch_protocol_error: type %d seq %u", type, seq);
+       if (!compat20)
+               fatal("protocol error");
+       packet_start(SSH2_MSG_UNIMPLEMENTED);
+       packet_put_int(seq);
+       packet_send();
+       packet_write_wait();
+}
+void
+dispatch_protocol_ignore(int type, u_int32_t seq, void *ctxt)
+{
+       logit("dispatch_protocol_ignore: type %d seq %u", type, seq);
+}
+void
+dispatch_init(dispatch_fn *dflt)
+{
+       u_int i;
+       for (i = 0; i < DISPATCH_MAX; i++)
+               dispatch[i] = dflt;
+}
+void
+dispatch_range(u_int from, u_int to, dispatch_fn *fn)
+{
+       u_int i;
+
+       for (i = from; i <= to; i++) {
+               if (i >= DISPATCH_MAX)
+                       break;
+               dispatch[i] = fn;
+       }
+}
+void
+dispatch_set(int type, dispatch_fn *fn)
+{
+       dispatch[type] = fn;
+}
+void
+dispatch_run(int mode, volatile sig_atomic_t *done, void *ctxt)
+{
+       for (;;) {
+               int type;
+               u_int32_t seqnr;
+
+               if (mode == DISPATCH_BLOCK) {
+                       type = packet_read_seqnr(&seqnr);
+               } else {
+                       type = packet_read_poll_seqnr(&seqnr);
+                       if (type == SSH_MSG_NONE)
+                               return;
+               }
+               if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL)
+                       (*dispatch[type])(type, seqnr, ctxt);
+               else
+                       packet_disconnect("protocol error: rcvd type %d", type);
+               if (done != NULL && *done)
+                       return;
+       }
+}
diff --git a/dispatch.h b/dispatch.h
new file mode 100644 (file)
index 0000000..3e3d1a1
--- /dev/null
@@ -0,0 +1,41 @@
+/* $OpenBSD: dispatch.h,v 1.11 2006/04/20 09:27:09 djm 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 <signal.h>
+
+enum {
+       DISPATCH_BLOCK,
+       DISPATCH_NONBLOCK
+};
+
+typedef void dispatch_fn(int, u_int32_t, void *);
+
+void    dispatch_init(dispatch_fn *);
+void    dispatch_set(int, dispatch_fn *);
+void    dispatch_range(u_int, u_int, dispatch_fn *);
+void    dispatch_run(int, volatile sig_atomic_t *, void *);
+void    dispatch_protocol_error(int, u_int32_t, void *);
+void    dispatch_protocol_ignore(int, u_int32_t, void *);
diff --git a/dns.c b/dns.c
new file mode 100644 (file)
index 0000000..131cb3d
--- /dev/null
+++ b/dns.c
@@ -0,0 +1,306 @@
+/* $OpenBSD: dns.c,v 1.27 2010/08/31 11:54:45 djm Exp $ */
+
+/*
+ * Copyright (c) 2003 Wesley Griffin. All rights reserved.
+ * Copyright (c) 2003 Jakob Schlyter. 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "dns.h"
+#include "log.h"
+
+static const char *errset_text[] = {
+       "success",              /* 0 ERRSET_SUCCESS */
+       "out of memory",        /* 1 ERRSET_NOMEMORY */
+       "general failure",      /* 2 ERRSET_FAIL */
+       "invalid parameter",    /* 3 ERRSET_INVAL */
+       "name does not exist",  /* 4 ERRSET_NONAME */
+       "data does not exist",  /* 5 ERRSET_NODATA */
+};
+
+static const char *
+dns_result_totext(unsigned int res)
+{
+       switch (res) {
+       case ERRSET_SUCCESS:
+               return errset_text[ERRSET_SUCCESS];
+       case ERRSET_NOMEMORY:
+               return errset_text[ERRSET_NOMEMORY];
+       case ERRSET_FAIL:
+               return errset_text[ERRSET_FAIL];
+       case ERRSET_INVAL:
+               return errset_text[ERRSET_INVAL];
+       case ERRSET_NONAME:
+               return errset_text[ERRSET_NONAME];
+       case ERRSET_NODATA:
+               return errset_text[ERRSET_NODATA];
+       default:
+               return "unknown error";
+       }
+}
+
+/*
+ * Read SSHFP parameters from key buffer.
+ */
+static int
+dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
+    u_char **digest, u_int *digest_len, Key *key)
+{
+       int success = 0;
+
+       switch (key->type) {
+       case KEY_RSA:
+               *algorithm = SSHFP_KEY_RSA;
+               break;
+       case KEY_DSA:
+               *algorithm = SSHFP_KEY_DSA;
+               break;
+       /* XXX KEY_ECDSA */
+       default:
+               *algorithm = SSHFP_KEY_RESERVED; /* 0 */
+       }
+
+       if (*algorithm) {
+               *digest_type = SSHFP_HASH_SHA1;
+               *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
+               if (*digest == NULL)
+                       fatal("dns_read_key: null from key_fingerprint_raw()");
+               success = 1;
+       } else {
+               *digest_type = SSHFP_HASH_RESERVED;
+               *digest = NULL;
+               *digest_len = 0;
+               success = 0;
+       }
+
+       return success;
+}
+
+/*
+ * Read SSHFP parameters from rdata buffer.
+ */
+static int
+dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
+    u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
+{
+       int success = 0;
+
+       *algorithm = SSHFP_KEY_RESERVED;
+       *digest_type = SSHFP_HASH_RESERVED;
+
+       if (rdata_len >= 2) {
+               *algorithm = rdata[0];
+               *digest_type = rdata[1];
+               *digest_len = rdata_len - 2;
+
+               if (*digest_len > 0) {
+                       *digest = (u_char *) xmalloc(*digest_len);
+                       memcpy(*digest, rdata + 2, *digest_len);
+               } else {
+                       *digest = (u_char *)xstrdup("");
+               }
+
+               success = 1;
+       }
+
+       return success;
+}
+
+/*
+ * Check if hostname is numerical.
+ * Returns -1 if hostname is numeric, 0 otherwise
+ */
+static int
+is_numeric_hostname(const char *hostname)
+{
+       struct addrinfo hints, *ai;
+
+       /*
+        * We shouldn't ever get a null host but if we do then log an error
+        * and return -1 which stops DNS key fingerprint processing.
+        */
+       if (hostname == NULL) {
+               error("is_numeric_hostname called with NULL hostname");
+               return -1;
+       }
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_socktype = SOCK_DGRAM;
+       hints.ai_flags = AI_NUMERICHOST;
+
+       if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
+               freeaddrinfo(ai);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Verify the given hostname, address and host key using DNS.
+ * Returns 0 if lookup succeeds, -1 otherwise
+ */
+int
+verify_host_key_dns(const char *hostname, struct sockaddr *address,
+    Key *hostkey, int *flags)
+{
+       u_int counter;
+       int result;
+       struct rrsetinfo *fingerprints = NULL;
+
+       u_int8_t hostkey_algorithm;
+       u_int8_t hostkey_digest_type;
+       u_char *hostkey_digest;
+       u_int hostkey_digest_len;
+
+       u_int8_t dnskey_algorithm;
+       u_int8_t dnskey_digest_type;
+       u_char *dnskey_digest;
+       u_int dnskey_digest_len;
+
+       *flags = 0;
+
+       debug3("verify_host_key_dns");
+       if (hostkey == NULL)
+               fatal("No key to look up!");
+
+       if (is_numeric_hostname(hostname)) {
+               debug("skipped DNS lookup for numerical hostname");
+               return -1;
+       }
+
+       result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
+           DNS_RDATATYPE_SSHFP, 0, &fingerprints);
+       if (result) {
+               verbose("DNS lookup error: %s", dns_result_totext(result));
+               return -1;
+       }
+
+       if (fingerprints->rri_flags & RRSET_VALIDATED) {
+               *flags |= DNS_VERIFY_SECURE;
+               debug("found %d secure fingerprints in DNS",
+                   fingerprints->rri_nrdatas);
+       } else {
+               debug("found %d insecure fingerprints in DNS",
+                   fingerprints->rri_nrdatas);
+       }
+
+       /* Initialize host key parameters */
+       if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
+           &hostkey_digest, &hostkey_digest_len, hostkey)) {
+               error("Error calculating host key fingerprint.");
+               freerrset(fingerprints);
+               return -1;
+       }
+
+       if (fingerprints->rri_nrdatas)
+               *flags |= DNS_VERIFY_FOUND;
+
+       for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
+               /*
+                * Extract the key from the answer. Ignore any badly
+                * formatted fingerprints.
+                */
+               if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
+                   &dnskey_digest, &dnskey_digest_len,
+                   fingerprints->rri_rdatas[counter].rdi_data,
+                   fingerprints->rri_rdatas[counter].rdi_length)) {
+                       verbose("Error parsing fingerprint from DNS.");
+                       continue;
+               }
+
+               /* Check if the current key is the same as the given key */
+               if (hostkey_algorithm == dnskey_algorithm &&
+                   hostkey_digest_type == dnskey_digest_type) {
+
+                       if (hostkey_digest_len == dnskey_digest_len &&
+                           memcmp(hostkey_digest, dnskey_digest,
+                           hostkey_digest_len) == 0) {
+
+                               *flags |= DNS_VERIFY_MATCH;
+                       }
+               }
+               xfree(dnskey_digest);
+       }
+
+       xfree(hostkey_digest); /* from key_fingerprint_raw() */
+       freerrset(fingerprints);
+
+       if (*flags & DNS_VERIFY_FOUND)
+               if (*flags & DNS_VERIFY_MATCH)
+                       debug("matching host key fingerprint found in DNS");
+               else
+                       debug("mismatching host key fingerprint found in DNS");
+       else
+               debug("no host key fingerprint found in DNS");
+
+       return 0;
+}
+
+/*
+ * Export the fingerprint of a key as a DNS resource record
+ */
+int
+export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
+{
+       u_int8_t rdata_pubkey_algorithm = 0;
+       u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
+       u_char *rdata_digest;
+       u_int rdata_digest_len;
+
+       u_int i;
+       int success = 0;
+
+       if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
+           &rdata_digest, &rdata_digest_len, key)) {
+
+               if (generic)
+                       fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname,
+                           DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len,
+                           rdata_pubkey_algorithm, rdata_digest_type);
+               else
+                       fprintf(f, "%s IN SSHFP %d %d ", hostname,
+                           rdata_pubkey_algorithm, rdata_digest_type);
+
+               for (i = 0; i < rdata_digest_len; i++)
+                       fprintf(f, "%02x", rdata_digest[i]);
+               fprintf(f, "\n");
+               xfree(rdata_digest); /* from key_fingerprint_raw() */
+               success = 1;
+       } else {
+               error("export_dns_rr: unsupported algorithm");
+       }
+
+       return success;
+}
diff --git a/dns.h b/dns.h
new file mode 100644 (file)
index 0000000..90cfd7b
--- /dev/null
+++ b/dns.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */
+
+/*
+ * Copyright (c) 2003 Wesley Griffin. All rights reserved.
+ * Copyright (c) 2003 Jakob Schlyter. 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 DNS_H
+#define DNS_H
+
+enum sshfp_types {
+       SSHFP_KEY_RESERVED,
+       SSHFP_KEY_RSA,
+       SSHFP_KEY_DSA
+};
+
+enum sshfp_hashes {
+       SSHFP_HASH_RESERVED,
+       SSHFP_HASH_SHA1
+};
+
+#define DNS_RDATACLASS_IN      1
+#define DNS_RDATATYPE_SSHFP    44
+
+#define DNS_VERIFY_FOUND       0x00000001
+#define DNS_VERIFY_MATCH       0x00000002
+#define DNS_VERIFY_SECURE      0x00000004
+
+int    verify_host_key_dns(const char *, struct sockaddr *, Key *, int *);
+int    export_dns_rr(const char *, Key *, FILE *, int);
+
+#endif /* DNS_H */
diff --git a/entropy.c b/entropy.c
new file mode 100644 (file)
index 0000000..a821662
--- /dev/null
+++ b/entropy.c
@@ -0,0 +1,194 @@
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#include "ssh.h"
+#include "misc.h"
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+#include "buffer.h"
+
+/*
+ * Portable OpenSSH PRNG seeding:
+ * If OpenSSL has not "internally seeded" itself (e.g. pulled data from
+ * /dev/random), then we execute a "ssh-rand-helper" program which
+ * collects entropy and writes it to stdout. The child program must
+ * write at least RANDOM_SEED_SIZE bytes. The child is run with stderr
+ * attached, so error/debugging output should be visible.
+ *
+ * XXX: we should tell the child how many bytes we need.
+ */
+
+#ifndef OPENSSL_PRNG_ONLY
+#define RANDOM_SEED_SIZE 48
+static uid_t original_uid, original_euid;
+#endif
+
+void
+seed_rng(void)
+{
+#ifndef OPENSSL_PRNG_ONLY
+       int devnull;
+       int p[2];
+       pid_t pid;
+       int ret;
+       unsigned char buf[RANDOM_SEED_SIZE];
+       mysig_t old_sigchld;
+
+       if (RAND_status() == 1) {
+               debug3("RNG is ready, skipping seeding");
+               return;
+       }
+
+       debug3("Seeding PRNG from %s", SSH_RAND_HELPER);
+
+       if ((devnull = open("/dev/null", O_RDWR)) == -1)
+               fatal("Couldn't open /dev/null: %s", strerror(errno));
+       if (pipe(p) == -1)
+               fatal("pipe: %s", strerror(errno));
+
+       old_sigchld = signal(SIGCHLD, SIG_DFL);
+       if ((pid = fork()) == -1)
+               fatal("Couldn't fork: %s", strerror(errno));
+       if (pid == 0) {
+               dup2(devnull, STDIN_FILENO);
+               dup2(p[1], STDOUT_FILENO);
+               /* Keep stderr open for errors */
+               close(p[0]);
+               close(p[1]);
+               close(devnull);
+
+               if (original_uid != original_euid &&
+                   ( seteuid(getuid()) == -1 ||
+                     setuid(original_uid) == -1) ) {
+                       fprintf(stderr, "(rand child) setuid(%li): %s\n",
+                           (long int)original_uid, strerror(errno));
+                       _exit(1);
+               }
+
+               execl(SSH_RAND_HELPER, "ssh-rand-helper", NULL);
+               fprintf(stderr, "(rand child) Couldn't exec '%s': %s\n",
+                   SSH_RAND_HELPER, strerror(errno));
+               _exit(1);
+       }
+
+       close(devnull);
+       close(p[1]);
+
+       memset(buf, '\0', sizeof(buf));
+       ret = atomicio(read, p[0], buf, sizeof(buf));
+       if (ret == -1)
+               fatal("Couldn't read from ssh-rand-helper: %s",
+                   strerror(errno));
+       if (ret != sizeof(buf))
+               fatal("ssh-rand-helper child produced insufficient data");
+
+       close(p[0]);
+
+       if (waitpid(pid, &ret, 0) == -1)
+               fatal("Couldn't wait for ssh-rand-helper completion: %s",
+                   strerror(errno));
+       signal(SIGCHLD, old_sigchld);
+
+       /* We don't mind if the child exits upon a SIGPIPE */
+       if (!WIFEXITED(ret) &&
+           (!WIFSIGNALED(ret) || WTERMSIG(ret) != SIGPIPE))
+               fatal("ssh-rand-helper terminated abnormally");
+       if (WEXITSTATUS(ret) != 0)
+               fatal("ssh-rand-helper exit with exit status %d", ret);
+
+       RAND_add(buf, sizeof(buf), sizeof(buf));
+       memset(buf, '\0', sizeof(buf));
+
+#endif /* OPENSSL_PRNG_ONLY */
+       if (RAND_status() != 1)
+               fatal("PRNG is not seeded");
+}
+
+void
+init_rng(void)
+{
+       /*
+        * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
+        * We match major, minor, fix and status (not patch)
+        */
+       if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L)
+               fatal("OpenSSL version mismatch. Built against %lx, you "
+                   "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
+
+#ifndef OPENSSL_PRNG_ONLY
+       original_uid = getuid();
+       original_euid = geteuid();
+#endif
+}
+
+#ifndef OPENSSL_PRNG_ONLY
+void
+rexec_send_rng_seed(Buffer *m)
+{
+       u_char buf[RANDOM_SEED_SIZE];
+
+       if (RAND_bytes(buf, sizeof(buf)) <= 0) {
+               error("Couldn't obtain random bytes (error %ld)",
+                   ERR_get_error());
+               buffer_put_string(m, "", 0);
+       } else 
+               buffer_put_string(m, buf, sizeof(buf));
+}
+
+void
+rexec_recv_rng_seed(Buffer *m)
+{
+       u_char *buf;
+       u_int len;
+
+       buf = buffer_get_string_ret(m, &len);
+       if (buf != NULL) {
+               debug3("rexec_recv_rng_seed: seeding rng with %u bytes", len);
+               RAND_add(buf, len, len);
+       }
+}
+#endif
diff --git a/entropy.h b/entropy.h
new file mode 100644 (file)
index 0000000..ec1ebcc
--- /dev/null
+++ b/entropy.h
@@ -0,0 +1,38 @@
+/*
+ * 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: entropy.h,v 1.5 2005/09/27 12:46:32 dtucker Exp $ */
+
+#ifndef _RANDOMS_H
+#define _RANDOMS_H
+
+#include "buffer.h"
+
+void seed_rng(void);
+void init_rng(void);
+
+void rexec_send_rng_seed(Buffer *);
+void rexec_recv_rng_seed(Buffer *);
+
+#endif /* _RANDOMS_H */
diff --git a/fatal.c b/fatal.c
new file mode 100644 (file)
index 0000000..5e5aa3f
--- /dev/null
+++ b/fatal.c
@@ -0,0 +1,45 @@
+/* $OpenBSD: fatal.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2002 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 <sys/types.h>
+
+#include <stdarg.h>
+
+#include "log.h"
+
+/* 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);
+       cleanup_exit(255);
+}
diff --git a/fixpaths b/fixpaths
new file mode 100755 (executable)
index 0000000..60a6799
--- /dev/null
+++ b/fixpaths
@@ -0,0 +1,22 @@
+#!/bin/sh
+#
+# fixpaths  - substitute makefile variables into text files
+# Usage: fixpaths -Dsomething=somethingelse ...
+
+die() {
+       echo $*
+       exit -1
+}
+
+test -n "`echo $1|grep -- -D`" || \
+       die $0: nothing to do - no substitutions listed!
+
+test -n "`echo $1|grep -- '-D[^=]\+=[^ ]\+'`" || \
+       die $0: error in command line arguments.
+
+test -n "`echo $*|grep -- ' [^-]'`" || \
+       die Usage: $0 '[-Dstring=replacement] [[infile] ...]'
+
+sed `echo $*|sed -e 's/-D\([^=]\+\)=\([^ ]*\)/-e s=\1=\2=g/g'`
+
+exit 0
diff --git a/fixprogs b/fixprogs
new file mode 100755 (executable)
index 0000000..af76ee3
--- /dev/null
+++ b/fixprogs
@@ -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/groupaccess.c b/groupaccess.c
new file mode 100644 (file)
index 0000000..2381aeb
--- /dev/null
@@ -0,0 +1,129 @@
+/* $OpenBSD: groupaccess.c,v 1.13 2008/07/04 03:44:59 djm 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 <sys/types.h>
+#include <sys/param.h>
+
+#include <grp.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "groupaccess.h"
+#include "match.h"
+#include "log.h"
+
+static int ngroups;
+static char **groups_byname;
+
+/*
+ * 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;
+       int i, j;
+       struct group *gr;
+
+       if (ngroups > 0)
+               ga_free();
+
+       ngroups = NGROUPS_MAX;
+#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
+       ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX));
+#endif
+
+       groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid));
+       groups_byname = xcalloc(ngroups, sizeof(*groups_byname));
+
+       if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
+               logit("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);
+       xfree(groups_bygid);
+       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;
+}
+
+/*
+ * Return 1 if one of user's groups matches group_pattern list.
+ * Return 0 on negated or no match.
+ */
+int
+ga_match_pattern_list(const char *group_pattern)
+{
+       int i, found = 0;
+       size_t len = strlen(group_pattern);
+
+       for (i = 0; i < ngroups; i++) {
+               switch (match_pattern_list(groups_byname[i],
+                   group_pattern, len, 0)) {
+               case -1:
+                       return 0;       /* Negated match wins */
+               case 0:
+                       continue;
+               case 1:
+                       found = 1;
+               }
+       }
+       return found;
+}
+
+/*
+ * Free memory allocated for group access list.
+ */
+void
+ga_free(void)
+{
+       int i;
+
+       if (ngroups > 0) {
+               for (i = 0; i < ngroups; i++)
+                       xfree(groups_byname[i]);
+               ngroups = 0;
+               xfree(groups_byname);
+       }
+}
diff --git a/groupaccess.h b/groupaccess.h
new file mode 100644 (file)
index 0000000..000578e
--- /dev/null
@@ -0,0 +1,35 @@
+/* $OpenBSD: groupaccess.h,v 1.8 2008/07/04 03:44:59 djm 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
+
+int     ga_init(const char *, gid_t);
+int     ga_match(char * const *, int);
+int     ga_match_pattern_list(const char *);
+void    ga_free(void);
+
+#endif
diff --git a/gss-genr.c b/gss-genr.c
new file mode 100644 (file)
index 0000000..842f385
--- /dev/null
@@ -0,0 +1,281 @@
+/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2001-2007 Simon Wilkinson. 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 GSSAPI
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "ssh2.h"
+
+#include "ssh-gss.h"
+
+extern u_char *session_id2;
+extern u_int session_id2_len;
+
+/* Check that the OID in a data stream matches that in the context */
+int
+ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
+{
+       return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
+           ctx->oid->length == len &&
+           memcmp(ctx->oid->elements, data, len) == 0);
+}
+
+/* Set the contexts OID from a data stream */
+void
+ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
+{
+       if (ctx->oid != GSS_C_NO_OID) {
+               xfree(ctx->oid->elements);
+               xfree(ctx->oid);
+       }
+       ctx->oid = xmalloc(sizeof(gss_OID_desc));
+       ctx->oid->length = len;
+       ctx->oid->elements = xmalloc(len);
+       memcpy(ctx->oid->elements, data, len);
+}
+
+/* Set the contexts OID */
+void
+ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
+{
+       ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
+}
+
+/* All this effort to report an error ... */
+void
+ssh_gssapi_error(Gssctxt *ctxt)
+{
+       char *s;
+
+       s = ssh_gssapi_last_error(ctxt, NULL, NULL);
+       debug("%s", s);
+       xfree(s);
+}
+
+char *
+ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *major_status,
+    OM_uint32 *minor_status)
+{
+       OM_uint32 lmin;
+       gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
+       OM_uint32 ctx;
+       Buffer b;
+       char *ret;
+
+       buffer_init(&b);
+
+       if (major_status != NULL)
+               *major_status = ctxt->major;
+       if (minor_status != NULL)
+               *minor_status = ctxt->minor;
+
+       ctx = 0;
+       /* The GSSAPI error */
+       do {
+               gss_display_status(&lmin, ctxt->major,
+                   GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg);
+
+               buffer_append(&b, msg.value, msg.length);
+               buffer_put_char(&b, '\n');
+
+               gss_release_buffer(&lmin, &msg);
+       } while (ctx != 0);
+
+       /* The mechanism specific error */
+       do {
+               gss_display_status(&lmin, ctxt->minor,
+                   GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg);
+
+               buffer_append(&b, msg.value, msg.length);
+               buffer_put_char(&b, '\n');
+
+               gss_release_buffer(&lmin, &msg);
+       } while (ctx != 0);
+
+       buffer_put_char(&b, '\0');
+       ret = xmalloc(buffer_len(&b));
+       buffer_get(&b, ret, buffer_len(&b));
+       buffer_free(&b);
+       return (ret);
+}
+
+/*
+ * Initialise our GSSAPI context. We use this opaque structure to contain all
+ * of the data which both the client and server need to persist across
+ * {accept,init}_sec_context calls, so that when we do it from the userauth
+ * stuff life is a little easier
+ */
+void
+ssh_gssapi_build_ctx(Gssctxt **ctx)
+{
+       *ctx = xcalloc(1, sizeof (Gssctxt));
+       (*ctx)->context = GSS_C_NO_CONTEXT;
+       (*ctx)->name = GSS_C_NO_NAME;
+       (*ctx)->oid = GSS_C_NO_OID;
+       (*ctx)->creds = GSS_C_NO_CREDENTIAL;
+       (*ctx)->client = GSS_C_NO_NAME;
+       (*ctx)->client_creds = GSS_C_NO_CREDENTIAL;
+}
+
+/* Delete our context, providing it has been built correctly */
+void
+ssh_gssapi_delete_ctx(Gssctxt **ctx)
+{
+       OM_uint32 ms;
+
+       if ((*ctx) == NULL)
+               return;
+       if ((*ctx)->context != GSS_C_NO_CONTEXT)
+               gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
+       if ((*ctx)->name != GSS_C_NO_NAME)
+               gss_release_name(&ms, &(*ctx)->name);
+       if ((*ctx)->oid != GSS_C_NO_OID) {
+               xfree((*ctx)->oid->elements);
+               xfree((*ctx)->oid);
+               (*ctx)->oid = GSS_C_NO_OID;
+       }
+       if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
+               gss_release_cred(&ms, &(*ctx)->creds);
+       if ((*ctx)->client != GSS_C_NO_NAME)
+               gss_release_name(&ms, &(*ctx)->client);
+       if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
+               gss_release_cred(&ms, &(*ctx)->client_creds);
+
+       xfree(*ctx);
+       *ctx = NULL;
+}
+
+/*
+ * Wrapper to init_sec_context
+ * Requires that the context contains:
+ *     oid
+ *     server name (from ssh_gssapi_import_name)
+ */
+OM_uint32
+ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
+    gss_buffer_desc* send_tok, OM_uint32 *flags)
+{
+       int deleg_flag = 0;
+
+       if (deleg_creds) {
+               deleg_flag = GSS_C_DELEG_FLAG;
+               debug("Delegating credentials");
+       }
+
+       ctx->major = gss_init_sec_context(&ctx->minor,
+           GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
+           GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
+           0, NULL, recv_tok, NULL, send_tok, flags, NULL);
+
+       if (GSS_ERROR(ctx->major))
+               ssh_gssapi_error(ctx);
+
+       return (ctx->major);
+}
+
+/* Create a service name for the given host */
+OM_uint32
+ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+{
+       gss_buffer_desc gssbuf;
+       char *val;
+
+       xasprintf(&val, "host@%s", host);
+       gssbuf.value = val;
+       gssbuf.length = strlen(gssbuf.value);
+
+       if ((ctx->major = gss_import_name(&ctx->minor,
+           &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+               ssh_gssapi_error(ctx);
+
+       xfree(gssbuf.value);
+       return (ctx->major);
+}
+
+OM_uint32
+ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
+{
+       if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
+           GSS_C_QOP_DEFAULT, buffer, hash)))
+               ssh_gssapi_error(ctx);
+
+       return (ctx->major);
+}
+
+void
+ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
+    const char *context)
+{
+       buffer_init(b);
+       buffer_put_string(b, session_id2, session_id2_len);
+       buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST);
+       buffer_put_cstring(b, user);
+       buffer_put_cstring(b, service);
+       buffer_put_cstring(b, context);
+}
+
+int
+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host)
+{
+       gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+       OM_uint32 major, minor;
+       gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"};
+
+       /* RFC 4462 says we MUST NOT do SPNEGO */
+       if (oid->length == spnego_oid.length && 
+           (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0))
+               return 0; /* false */
+
+       ssh_gssapi_build_ctx(ctx);
+       ssh_gssapi_set_oid(*ctx, oid);
+       major = ssh_gssapi_import_name(*ctx, host);
+       if (!GSS_ERROR(major)) {
+               major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, 
+                   NULL);
+               gss_release_buffer(&minor, &token);
+               if ((*ctx)->context != GSS_C_NO_CONTEXT)
+                       gss_delete_sec_context(&minor, &(*ctx)->context,
+                           GSS_C_NO_BUFFER);
+       }
+
+       if (GSS_ERROR(major)) 
+               ssh_gssapi_delete_ctx(ctx);
+
+       return (!GSS_ERROR(major));
+}
+
+#endif /* GSSAPI */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
new file mode 100644 (file)
index 0000000..5a625ac
--- /dev/null
@@ -0,0 +1,199 @@
+/* $OpenBSD: gss-serv-krb5.c,v 1.7 2006/08/03 03:34:42 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. 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 GSSAPI
+#ifdef KRB5
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "servconf.h"
+
+#include "buffer.h"
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+#ifdef HEIMDAL
+# include <krb5.h>
+#else
+# ifdef HAVE_GSSAPI_KRB5_H
+#  include <gssapi_krb5.h>
+# elif HAVE_GSSAPI_GSSAPI_KRB5_H
+#  include <gssapi/gssapi_krb5.h>
+# endif
+#endif
+
+static krb5_context krb_context = NULL;
+
+/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+
+static int
+ssh_gssapi_krb5_init(void)
+{
+       krb5_error_code problem;
+
+       if (krb_context != NULL)
+               return 1;
+
+       problem = krb5_init_context(&krb_context);
+       if (problem) {
+               logit("Cannot initialize krb5 context");
+               return 0;
+       }
+
+       return 1;
+}
+
+/* Check if this user is OK to login. This only works with krb5 - other
+ * GSSAPI mechanisms will need their own.
+ * Returns true if the user is OK to log in, otherwise returns 0
+ */
+
+static int
+ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+{
+       krb5_principal princ;
+       int retval;
+
+       if (ssh_gssapi_krb5_init() == 0)
+               return 0;
+
+       if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
+           &princ))) {
+               logit("krb5_parse_name(): %.100s",
+                   krb5_get_err_text(krb_context, retval));
+               return 0;
+       }
+       if (krb5_kuserok(krb_context, princ, name)) {
+               retval = 1;
+               logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+                   name, (char *)client->displayname.value);
+       } else
+               retval = 0;
+
+       krb5_free_principal(krb_context, princ);
+       return retval;
+}
+
+
+/* This writes out any forwarded credentials from the structure populated
+ * during userauth. Called after we have setuid to the user */
+
+static void
+ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
+{
+       krb5_ccache ccache;
+       krb5_error_code problem;
+       krb5_principal princ;
+       OM_uint32 maj_status, min_status;
+       int len;
+
+       if (client->creds == NULL) {
+               debug("No credentials stored");
+               return;
+       }
+
+       if (ssh_gssapi_krb5_init() == 0)
+               return;
+
+#ifdef HEIMDAL
+       if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) {
+               logit("krb5_cc_gen_new(): %.100s",
+                   krb5_get_err_text(krb_context, problem));
+               return;
+       }
+#else
+       if ((problem = ssh_krb5_cc_gen(krb_context, &ccache))) {
+               logit("ssh_krb5_cc_gen(): %.100s",
+                   krb5_get_err_text(krb_context, problem));
+               return;
+       }
+#endif /* #ifdef HEIMDAL */
+
+       if ((problem = krb5_parse_name(krb_context,
+           client->exportedname.value, &princ))) {
+               logit("krb5_parse_name(): %.100s",
+                   krb5_get_err_text(krb_context, problem));
+               krb5_cc_destroy(krb_context, ccache);
+               return;
+       }
+
+       if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
+               logit("krb5_cc_initialize(): %.100s",
+                   krb5_get_err_text(krb_context, problem));
+               krb5_free_principal(krb_context, princ);
+               krb5_cc_destroy(krb_context, ccache);
+               return;
+       }
+
+       krb5_free_principal(krb_context, princ);
+
+       if ((maj_status = gss_krb5_copy_ccache(&min_status,
+           client->creds, ccache))) {
+               logit("gss_krb5_copy_ccache() failed");
+               krb5_cc_destroy(krb_context, ccache);
+               return;
+       }
+
+       client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
+       client->store.envvar = "KRB5CCNAME";
+       len = strlen(client->store.filename) + 6;
+       client->store.envval = xmalloc(len);
+       snprintf(client->store.envval, len, "FILE:%s", client->store.filename);
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               do_pam_putenv(client->store.envvar, client->store.envval);
+#endif
+
+       krb5_cc_close(krb_context, ccache);
+
+       return;
+}
+
+ssh_gssapi_mech gssapi_kerberos_mech = {
+       "toWM5Slw5Ew8Mqkay+al2g==",
+       "Kerberos",
+       {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+       NULL,
+       &ssh_gssapi_krb5_userok,
+       NULL,
+       &ssh_gssapi_krb5_storecreds
+};
+
+#endif /* KRB5 */
+
+#endif /* GSSAPI */
diff --git a/gss-serv.c b/gss-serv.c
new file mode 100644 (file)
index 0000000..2ec7ea1
--- /dev/null
@@ -0,0 +1,365 @@
+/* $OpenBSD: gss-serv.c,v 1.22 2008/05/08 12:02:23 djm Exp $ */
+
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. 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 GSSAPI
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "channels.h"
+#include "session.h"
+#include "misc.h"
+
+#include "ssh-gss.h"
+
+static ssh_gssapi_client gssapi_client =
+    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
+    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
+
+ssh_gssapi_mech gssapi_null_mech =
+    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
+
+#ifdef KRB5
+extern ssh_gssapi_mech gssapi_kerberos_mech;
+#endif
+
+ssh_gssapi_mech* supported_mechs[]= {
+#ifdef KRB5
+       &gssapi_kerberos_mech,
+#endif
+       &gssapi_null_mech,
+};
+
+
+/*
+ * Acquire credentials for a server running on the current host.
+ * Requires that the context structure contains a valid OID
+ */
+
+/* Returns a GSSAPI error code */
+/* Privileged (called from ssh_gssapi_server_ctx) */
+static OM_uint32
+ssh_gssapi_acquire_cred(Gssctxt *ctx)
+{
+       OM_uint32 status;
+       char lname[MAXHOSTNAMELEN];
+       gss_OID_set oidset;
+
+       gss_create_empty_oid_set(&status, &oidset);
+       gss_add_oid_set_member(&status, ctx->oid, &oidset);
+
+       if (gethostname(lname, MAXHOSTNAMELEN)) {
+               gss_release_oid_set(&status, &oidset);
+               return (-1);
+       }
+
+       if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) {
+               gss_release_oid_set(&status, &oidset);
+               return (ctx->major);
+       }
+
+       if ((ctx->major = gss_acquire_cred(&ctx->minor,
+           ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
+               ssh_gssapi_error(ctx);
+
+       gss_release_oid_set(&status, &oidset);
+       return (ctx->major);
+}
+
+/* Privileged */
+OM_uint32
+ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
+{
+       if (*ctx)
+               ssh_gssapi_delete_ctx(ctx);
+       ssh_gssapi_build_ctx(ctx);
+       ssh_gssapi_set_oid(*ctx, oid);
+       return (ssh_gssapi_acquire_cred(*ctx));
+}
+
+/* Unprivileged */
+void
+ssh_gssapi_supported_oids(gss_OID_set *oidset)
+{
+       int i = 0;
+       OM_uint32 min_status;
+       int present;
+       gss_OID_set supported;
+
+       gss_create_empty_oid_set(&min_status, oidset);
+       gss_indicate_mechs(&min_status, &supported);
+
+       while (supported_mechs[i]->name != NULL) {
+               if (GSS_ERROR(gss_test_oid_set_member(&min_status,
+                   &supported_mechs[i]->oid, supported, &present)))
+                       present = 0;
+               if (present)
+                       gss_add_oid_set_member(&min_status,
+                           &supported_mechs[i]->oid, oidset);
+               i++;
+       }
+
+       gss_release_oid_set(&min_status, &supported);
+}
+
+
+/* Wrapper around accept_sec_context
+ * Requires that the context contains:
+ *    oid
+ *    credentials      (from ssh_gssapi_acquire_cred)
+ */
+/* Privileged */
+OM_uint32
+ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
+    gss_buffer_desc *send_tok, OM_uint32 *flags)
+{
+       OM_uint32 status;
+       gss_OID mech;
+
+       ctx->major = gss_accept_sec_context(&ctx->minor,
+           &ctx->context, ctx->creds, recv_tok,
+           GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
+           send_tok, flags, NULL, &ctx->client_creds);
+
+       if (GSS_ERROR(ctx->major))
+               ssh_gssapi_error(ctx);
+
+       if (ctx->client_creds)
+               debug("Received some client credentials");
+       else
+               debug("Got no client credentials");
+
+       status = ctx->major;
+
+       /* Now, if we're complete and we have the right flags, then
+        * we flag the user as also having been authenticated
+        */
+
+       if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
+           (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
+               if (ssh_gssapi_getclient(ctx, &gssapi_client))
+                       fatal("Couldn't convert client name");
+       }
+
+       return (status);
+}
+
+/*
+ * This parses an exported name, extracting the mechanism specific portion
+ * to use for ACL checking. It verifies that the name belongs the mechanism
+ * originally selected.
+ */
+static OM_uint32
+ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
+{
+       u_char *tok;
+       OM_uint32 offset;
+       OM_uint32 oidl;
+
+       tok = ename->value;
+
+       /*
+        * Check that ename is long enough for all of the fixed length
+        * header, and that the initial ID bytes are correct
+        */
+
+       if (ename->length < 6 || memcmp(tok, "\x04\x01", 2) != 0)
+               return GSS_S_FAILURE;
+
+       /*
+        * Extract the OID, and check it. Here GSSAPI breaks with tradition
+        * and does use the OID type and length bytes. To confuse things
+        * there are two lengths - the first including these, and the
+        * second without.
+        */
+
+       oidl = get_u16(tok+2); /* length including next two bytes */
+       oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
+
+       /*
+        * Check the BER encoding for correct type and length, that the
+        * string is long enough and that the OID matches that in our context
+        */
+       if (tok[4] != 0x06 || tok[5] != oidl ||
+           ename->length < oidl+6 ||
+           !ssh_gssapi_check_oid(ctx, tok+6, oidl))
+               return GSS_S_FAILURE;
+
+       offset = oidl+6;
+
+       if (ename->length < offset+4)
+               return GSS_S_FAILURE;
+
+       name->length = get_u32(tok+offset);
+       offset += 4;
+
+       if (ename->length < offset+name->length)
+               return GSS_S_FAILURE;
+
+       name->value = xmalloc(name->length+1);
+       memcpy(name->value, tok+offset, name->length);
+       ((char *)name->value)[name->length] = 0;
+
+       return GSS_S_COMPLETE;
+}
+
+/* Extract the client details from a given context. This can only reliably
+ * be called once for a context */
+
+/* Privileged (called from accept_secure_ctx) */
+OM_uint32
+ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+{
+       int i = 0;
+
+       gss_buffer_desc ename;
+
+       client->mech = NULL;
+
+       while (supported_mechs[i]->name != NULL) {
+               if (supported_mechs[i]->oid.length == ctx->oid->length &&
+                   (memcmp(supported_mechs[i]->oid.elements,
+                   ctx->oid->elements, ctx->oid->length) == 0))
+                       client->mech = supported_mechs[i];
+               i++;
+       }
+
+       if (client->mech == NULL)
+               return GSS_S_FAILURE;
+
+       if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
+           &client->displayname, NULL))) {
+               ssh_gssapi_error(ctx);
+               return (ctx->major);
+       }
+
+       if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
+           &ename))) {
+               ssh_gssapi_error(ctx);
+               return (ctx->major);
+       }
+
+       if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
+           &client->exportedname))) {
+               return (ctx->major);
+       }
+
+       /* We can't copy this structure, so we just move the pointer to it */
+       client->creds = ctx->client_creds;
+       ctx->client_creds = GSS_C_NO_CREDENTIAL;
+       return (ctx->major);
+}
+
+/* As user - called on fatal/exit */
+void
+ssh_gssapi_cleanup_creds(void)
+{
+       if (gssapi_client.store.filename != NULL) {
+               /* Unlink probably isn't sufficient */
+               debug("removing gssapi cred file\"%s\"",
+                   gssapi_client.store.filename);
+               unlink(gssapi_client.store.filename);
+       }
+}
+
+/* As user */
+void
+ssh_gssapi_storecreds(void)
+{
+       if (gssapi_client.mech && gssapi_client.mech->storecreds) {
+               (*gssapi_client.mech->storecreds)(&gssapi_client);
+       } else
+               debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+}
+
+/* This allows GSSAPI methods to do things to the childs environment based
+ * on the passed authentication process and credentials.
+ */
+/* As user */
+void
+ssh_gssapi_do_child(char ***envp, u_int *envsizep)
+{
+
+       if (gssapi_client.store.envvar != NULL &&
+           gssapi_client.store.envval != NULL) {
+               debug("Setting %s to %s", gssapi_client.store.envvar,
+                   gssapi_client.store.envval);
+               child_set_env(envp, envsizep, gssapi_client.store.envvar,
+                   gssapi_client.store.envval);
+       }
+}
+
+/* Privileged */
+int
+ssh_gssapi_userok(char *user)
+{
+       OM_uint32 lmin;
+
+       if (gssapi_client.exportedname.length == 0 ||
+           gssapi_client.exportedname.value == NULL) {
+               debug("No suitable client data");
+               return 0;
+       }
+       if (gssapi_client.mech && gssapi_client.mech->userok)
+               if ((*gssapi_client.mech->userok)(&gssapi_client, user))
+                       return 1;
+               else {
+                       /* Destroy delegated credentials if userok fails */
+                       gss_release_buffer(&lmin, &gssapi_client.displayname);
+                       gss_release_buffer(&lmin, &gssapi_client.exportedname);
+                       gss_release_cred(&lmin, &gssapi_client.creds);
+                       memset(&gssapi_client, 0, sizeof(ssh_gssapi_client));
+                       return 0;
+               }
+       else
+               debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
+       return (0);
+}
+
+/* Privileged */
+OM_uint32
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+{
+       ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
+           gssbuf, gssmic, NULL);
+
+       return (ctx->major);
+}
+
+#endif
diff --git a/hostfile.c b/hostfile.c
new file mode 100644 (file)
index 0000000..b6f924b
--- /dev/null
@@ -0,0 +1,488 @@
+/* $OpenBSD: hostfile.c,v 1.50 2010/12/04 13:31:37 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <resolv.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "match.h"
+#include "key.h"
+#include "hostfile.h"
+#include "log.h"
+#include "misc.h"
+
+struct hostkeys {
+       struct hostkey_entry *entries;
+       u_int num_entries;
+};
+
+static int
+extract_salt(const char *s, u_int l, char *salt, size_t salt_len)
+{
+       char *p, *b64salt;
+       u_int b64len;
+       int ret;
+
+       if (l < sizeof(HASH_MAGIC) - 1) {
+               debug2("extract_salt: string too short");
+               return (-1);
+       }
+       if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) {
+               debug2("extract_salt: invalid magic identifier");
+               return (-1);
+       }
+       s += sizeof(HASH_MAGIC) - 1;
+       l -= sizeof(HASH_MAGIC) - 1;
+       if ((p = memchr(s, HASH_DELIM, l)) == NULL) {
+               debug2("extract_salt: missing salt termination character");
+               return (-1);
+       }
+
+       b64len = p - s;
+       /* Sanity check */
+       if (b64len == 0 || b64len > 1024) {
+               debug2("extract_salt: bad encoded salt length %u", b64len);
+               return (-1);
+       }
+       b64salt = xmalloc(1 + b64len);
+       memcpy(b64salt, s, b64len);
+       b64salt[b64len] = '\0';
+
+       ret = __b64_pton(b64salt, salt, salt_len);
+       xfree(b64salt);
+       if (ret == -1) {
+               debug2("extract_salt: salt decode error");
+               return (-1);
+       }
+       if (ret != SHA_DIGEST_LENGTH) {
+               debug2("extract_salt: expected salt len %d, got %d",
+                   SHA_DIGEST_LENGTH, ret);
+               return (-1);
+       }
+
+       return (0);
+}
+
+char *
+host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
+{
+       const EVP_MD *md = EVP_sha1();
+       HMAC_CTX mac_ctx;
+       char salt[256], result[256], uu_salt[512], uu_result[512];
+       static char encoded[1024];
+       u_int i, len;
+
+       len = EVP_MD_size(md);
+
+       if (name_from_hostfile == NULL) {
+               /* Create new salt */
+               for (i = 0; i < len; i++)
+                       salt[i] = arc4random();
+       } else {
+               /* Extract salt from known host entry */
+               if (extract_salt(name_from_hostfile, src_len, salt,
+                   sizeof(salt)) == -1)
+                       return (NULL);
+       }
+
+       HMAC_Init(&mac_ctx, salt, len, md);
+       HMAC_Update(&mac_ctx, host, strlen(host));
+       HMAC_Final(&mac_ctx, result, NULL);
+       HMAC_cleanup(&mac_ctx);
+
+       if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 ||
+           __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1)
+               fatal("host_hash: __b64_ntop failed");
+
+       snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt,
+           HASH_DELIM, uu_result);
+
+       return (encoded);
+}
+
+/*
+ * 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.
+ */
+
+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;
+       if (bitsp != NULL)
+               *bitsp = key_size(ret);
+       return 1;
+}
+
+static int
+hostfile_check_key(int bits, const Key *key, const char *host,
+    const char *filename, u_long linenum)
+{
+       if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
+               return 1;
+       if (bits != BN_num_bits(key->rsa->n)) {
+               logit("Warning: %s, line %lu: keysize mismatch for host %s: "
+                   "actual %d vs. announced %d.",
+                   filename, linenum, host, BN_num_bits(key->rsa->n), bits);
+               logit("Warning: replace %d with %d in %s, line %lu.",
+                   bits, BN_num_bits(key->rsa->n), filename, linenum);
+       }
+       return 1;
+}
+
+static HostkeyMarker
+check_markers(char **cpp)
+{
+       char marker[32], *sp, *cp = *cpp;
+       int ret = MRK_NONE;
+
+       while (*cp == '@') {
+               /* Only one marker is allowed */
+               if (ret != MRK_NONE)
+                       return MRK_ERROR;
+               /* Markers are terminated by whitespace */
+               if ((sp = strchr(cp, ' ')) == NULL &&
+                   (sp = strchr(cp, '\t')) == NULL)
+                       return MRK_ERROR;
+               /* Extract marker for comparison */
+               if (sp <= cp + 1 || sp >= cp + sizeof(marker))
+                       return MRK_ERROR;
+               memcpy(marker, cp, sp - cp);
+               marker[sp - cp] = '\0';
+               if (strcmp(marker, CA_MARKER) == 0)
+                       ret = MRK_CA;
+               else if (strcmp(marker, REVOKE_MARKER) == 0)
+                       ret = MRK_REVOKE;
+               else
+                       return MRK_ERROR;
+
+               /* Skip past marker and any whitespace that follows it */
+               cp = sp;
+               for (; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+       }
+       *cpp = cp;
+       return ret;
+}
+
+struct hostkeys *
+init_hostkeys(void)
+{
+       struct hostkeys *ret = xcalloc(1, sizeof(*ret));
+
+       ret->entries = NULL;
+       return ret;
+}
+
+void
+load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
+{
+       FILE *f;
+       char line[8192];
+       u_long linenum = 0, num_loaded = 0;
+       char *cp, *cp2, *hashed_host;
+       HostkeyMarker marker;
+       Key *key;
+       int kbits;
+
+       if ((f = fopen(path, "r")) == NULL)
+               return;
+       debug3("%s: loading entries for host \"%.100s\" from file \"%s\"",
+           __func__, host, path);
+       while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
+               cp = line;
+
+               /* Skip any leading whitespace, comments and empty lines. */
+               for (; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '#' || *cp == '\n')
+                       continue;
+
+               if ((marker = check_markers(&cp)) == MRK_ERROR) {
+                       verbose("%s: invalid marker at %s:%lu",
+                           __func__, path, linenum);
+                       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) {
+                       if (*cp != HASH_DELIM)
+                               continue;
+                       hashed_host = host_hash(host, cp, (u_int) (cp2 - cp));
+                       if (hashed_host == NULL) {
+                               debug("Invalid hashed host line %lu of %s",
+                                   linenum, path);
+                               continue;
+                       }
+                       if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0)
+                               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.
+                */
+               key = key_new(KEY_UNSPEC);
+               if (!hostfile_read_key(&cp, &kbits, key)) {
+                       key_free(key);
+                       key = key_new(KEY_RSA1);
+                       if (!hostfile_read_key(&cp, &kbits, key)) {
+                               key_free(key);
+                               continue;
+                       }
+               }
+               if (!hostfile_check_key(kbits, key, host, path, linenum))
+                       continue;
+
+               debug3("%s: found %skey type %s in file %s:%lu", __func__,
+                   marker == MRK_NONE ? "" :
+                   (marker == MRK_CA ? "ca " : "revoked "),
+                   key_type(key), path, linenum);
+               hostkeys->entries = xrealloc(hostkeys->entries,
+                   hostkeys->num_entries + 1, sizeof(*hostkeys->entries));
+               hostkeys->entries[hostkeys->num_entries].host = xstrdup(host);
+               hostkeys->entries[hostkeys->num_entries].file = xstrdup(path);
+               hostkeys->entries[hostkeys->num_entries].line = linenum;
+               hostkeys->entries[hostkeys->num_entries].key = key;
+               hostkeys->entries[hostkeys->num_entries].marker = marker;
+               hostkeys->num_entries++;
+               num_loaded++;
+       }
+       debug3("%s: loaded %lu keys", __func__, num_loaded);
+       fclose(f);
+       return;
+}      
+
+void
+free_hostkeys(struct hostkeys *hostkeys)
+{
+       u_int i;
+
+       for (i = 0; i < hostkeys->num_entries; i++) {
+               xfree(hostkeys->entries[i].host);
+               xfree(hostkeys->entries[i].file);
+               key_free(hostkeys->entries[i].key);
+               bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
+       }
+       if (hostkeys->entries != NULL)
+               xfree(hostkeys->entries);
+       hostkeys->entries = NULL;
+       hostkeys->num_entries = 0;
+       xfree(hostkeys);
+}
+
+static int
+check_key_not_revoked(struct hostkeys *hostkeys, Key *k)
+{
+       int is_cert = key_is_cert(k);
+       u_int i;
+
+       for (i = 0; i < hostkeys->num_entries; i++) {
+               if (hostkeys->entries[i].marker != MRK_REVOKE)
+                       continue;
+               if (key_equal_public(k, hostkeys->entries[i].key))
+                       return -1;
+               if (is_cert &&
+                   key_equal_public(k->cert->signature_key,
+                   hostkeys->entries[i].key))
+                       return -1;
+       }
+       return 0;
+}
+
+/*
+ * Match keys against a specified key, or look one up by key type.
+ *
+ * If looking for a keytype (key == NULL) and one is found then return
+ * HOST_FOUND, otherwise HOST_NEW.
+ *
+ * If looking for a key (key != NULL):
+ *  1. If the key is a cert and a matching CA is found, return HOST_OK
+ *  2. If the key is not a cert and a matching key is found, return HOST_OK
+ *  3. If no key matches but a key with a different type is found, then
+ *     return HOST_CHANGED
+ *  4. If no matching keys are found, then return HOST_NEW.
+ *
+ * Finally, check any found key is not revoked.
+ */
+static HostStatus
+check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
+    Key *k, int keytype, const struct hostkey_entry **found)
+{
+       u_int i;
+       HostStatus end_return = HOST_NEW;
+       int want_cert = key_is_cert(k);
+       HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
+       int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2;
+
+       if (found != NULL)
+               *found = NULL;
+
+       for (i = 0; i < hostkeys->num_entries; i++) {
+               if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1)
+                       continue;
+               if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1)
+                       continue;
+               if (hostkeys->entries[i].marker != want_marker)
+                       continue;
+               if (k == NULL) {
+                       if (hostkeys->entries[i].key->type != keytype)
+                               continue;
+                       end_return = HOST_FOUND;
+                       if (found != NULL)
+                               *found = hostkeys->entries + i;
+                       k = hostkeys->entries[i].key;
+                       break;
+               }
+               if (want_cert) {
+                       if (key_equal_public(k->cert->signature_key,
+                           hostkeys->entries[i].key)) {
+                               /* A matching CA exists */
+                               end_return = HOST_OK;
+                               if (found != NULL)
+                                       *found = hostkeys->entries + i;
+                               break;
+                       }
+               } else {
+                       if (key_equal(k, hostkeys->entries[i].key)) {
+                               end_return = HOST_OK;
+                               if (found != NULL)
+                                       *found = hostkeys->entries + i;
+                               break;
+                       }
+                       /* A non-maching key exists */
+                       end_return = HOST_CHANGED;
+                       if (found != NULL)
+                               *found = hostkeys->entries + i;
+               }
+       }
+       if (check_key_not_revoked(hostkeys, k) != 0) {
+               end_return = HOST_REVOKED;
+               if (found != NULL)
+                       *found = NULL;
+       }
+       return end_return;
+}
+       
+HostStatus
+check_key_in_hostkeys(struct hostkeys *hostkeys, Key *key,
+    const struct hostkey_entry **found)
+{
+       if (key == NULL)
+               fatal("no key to look up");
+       return check_hostkeys_by_key_or_type(hostkeys, key, 0, found);
+}
+
+int
+lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype,
+    const struct hostkey_entry **found)
+{
+       return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype,
+           found) == HOST_FOUND);
+}
+
+/*
+ * 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, const Key *key,
+    int store_hash)
+{
+       FILE *f;
+       int success = 0;
+       char *hashed_host = NULL;
+
+       if (key == NULL)
+               return 1;       /* XXX ? */
+       f = fopen(filename, "a");
+       if (!f)
+               return 0;
+
+       if (store_hash) {
+               if ((hashed_host = host_hash(host, NULL, 0)) == NULL) {
+                       error("add_host_to_hostfile: host_hash failed");
+                       fclose(f);
+                       return 0;
+               }
+       }
+       fprintf(f, "%s ", store_hash ? hashed_host : 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/hostfile.h b/hostfile.h
new file mode 100644 (file)
index 0000000..d84d422
--- /dev/null
@@ -0,0 +1,54 @@
+/* $OpenBSD: hostfile.h,v 1.19 2010/11/29 23:45:51 djm 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, HOST_REVOKED, HOST_FOUND
+}       HostStatus;
+
+typedef enum {
+       MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA
+}      HostkeyMarker;
+
+struct hostkey_entry {
+       char *host;
+       char *file;
+       u_long line;
+       Key *key;
+       HostkeyMarker marker;
+};
+struct hostkeys;
+
+struct hostkeys *init_hostkeys(void);
+void    load_hostkeys(struct hostkeys *, const char *, const char *);
+void    free_hostkeys(struct hostkeys *);
+
+HostStatus check_key_in_hostkeys(struct hostkeys *, Key *,
+    const struct hostkey_entry **);
+int     lookup_key_in_hostkeys_by_type(struct hostkeys *, int,
+    const struct hostkey_entry **);
+
+int     hostfile_read_key(char **, u_int *, Key *);
+int     add_host_to_hostfile(const char *, const char *, const Key *, int);
+
+#define HASH_MAGIC     "|1|"
+#define HASH_DELIM     '|'
+
+#define CA_MARKER      "@cert-authority"
+#define REVOKE_MARKER  "@revoked"
+
+char   *host_hash(const char *, const char *, u_int);
+
+#endif
diff --git a/includes.h b/includes.h
new file mode 100644 (file)
index 0000000..b4c53d9
--- /dev/null
@@ -0,0 +1,175 @@
+/* $OpenBSD: includes.h,v 1.54 2006/07/22 20:48:23 stevesk 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
+
+#include "config.h"
+
+#define _GNU_SOURCE /* activate extra prototypes for glibc */
+
+#include <sys/types.h>
+#include <sys/socket.h> /* For CMSG_* */
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h> /* For PATH_MAX */
+#endif
+#ifdef HAVE_BSTRING_H
+# include <bstring.h>
+#endif
+#if defined(HAVE_GLOB_H) && defined(GLOB_HAS_ALTDIRFUNC) && \
+    defined(GLOB_HAS_GL_MATCHC) && defined(GLOB_HAS_GL_STATV) && \
+    defined(HAVE_DECL_GLOB_NOMATCH) &&  HAVE_DECL_GLOB_NOMATCH != 0 && \
+    !defined(BROKEN_GLOB)
+# include <glob.h>
+#endif
+#ifdef HAVE_ENDIAN_H
+# include <endian.h>
+#endif
+#ifdef HAVE_TTYENT_H
+# include <ttyent.h>
+#endif
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif
+#ifdef HAVE_MAILLOCK_H
+# include <maillock.h> /* For _PATH_MAILDIR */
+#endif
+#ifdef HAVE_NEXT
+# include <libc.h>
+#endif
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+
+/*
+ *-*-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
+
+#ifdef HAVE_UTMP_H
+#  include <utmp.h>
+#endif
+#ifdef HAVE_UTMPX_H
+#  include <utmpx.h>
+#endif
+#ifdef HAVE_LASTLOG_H
+#  include <lastlog.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_BSDTTY_H
+# include <sys/bsdtty.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <termios.h>
+#ifdef HAVE_SYS_BITYPES_H
+# include <sys/bitypes.h> /* For u_intXX_t */
+#endif
+#ifdef HAVE_SYS_CDEFS_H
+# include <sys/cdefs.h> /* For __P() */
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h> /* For S_* constants and macros */
+#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+# include <sys/sysmacros.h> /* For MIN, MAX, etc */
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h> /* for MAP_ANONYMOUS */
+#endif
+#ifdef HAVE_SYS_STRTIO_H
+#include <sys/strtio.h>        /* for TIOCCBRK on HP-UX */
+#endif
+#if defined(HAVE_SYS_PTMS_H) && defined(HAVE_DEV_PTMX)
+# if defined(HAVE_SYS_STREAM_H)
+#  include <sys/stream.h>      /* reqd for queue_t on Solaris 2.5.1 */
+# endif
+#include <sys/ptms.h>  /* for grantpt() and friends */
+#endif
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h> /* For typedefs */
+#ifdef HAVE_RPC_TYPES_H
+# include <rpc/types.h> /* For INADDR_LOOPBACK */
+#endif
+#ifdef USE_PAM
+#if defined(HAVE_SECURITY_PAM_APPL_H)
+# include <security/pam_appl.h>
+#elif defined (HAVE_PAM_PAM_APPL_H)
+# include <pam/pam_appl.h>
+#endif
+#endif
+#ifdef HAVE_READPASSPHRASE_H
+# include <readpassphrase.h>
+#endif
+
+#ifdef HAVE_IA_H
+# include <ia.h>
+#endif
+
+#ifdef HAVE_IAF_H
+# include <iaf.h>
+#endif
+
+#ifdef HAVE_TMPDIR_H
+# include <tmpdir.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h> /* Openpty on FreeBSD at least */
+#endif
+
+#if defined(KRB5) && defined(USE_AFS)
+# include <krb5.h>
+# include <kafs.h>
+#endif
+
+#if defined(HAVE_SYS_SYSLOG_H)
+# include <sys/syslog.h>
+#endif
+
+#include <errno.h>
+
+/*
+ * On HP-UX 11.11, shadow.h and prot.h provide conflicting declarations
+ * of getspnam when _INCLUDE__STDC__ is defined, so we unset it here.
+ */
+#ifdef GETSPNAM_CONFLICTING_DEFS
+# ifdef _INCLUDE__STDC__
+#  undef _INCLUDE__STDC__
+# endif
+#endif
+
+#include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
+
+#include "defines.h"
+
+#include "platform.h"
+#include "openbsd-compat/openbsd-compat.h"
+#include "openbsd-compat/bsd-nextstep.h"
+
+#include "entropy.h"
+
+#endif /* INCLUDES_H */
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..220abbf
--- /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/jpake.c b/jpake.c
new file mode 100644 (file)
index 0000000..ac9a4bc
--- /dev/null
+++ b/jpake.c
@@ -0,0 +1,456 @@
+/* $OpenBSD: jpake.c,v 1.6 2010/09/20 04:54:07 djm Exp $ */
+/*
+ * Copyright (c) 2008 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Shared components of zero-knowledge password auth using J-PAKE protocol
+ * as described in:
+ *
+ * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling",
+ * 16th Workshop on Security Protocols, Cambridge, April 2008
+ *
+ * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "buffer.h"
+#include "packet.h"
+#include "dispatch.h"
+#include "log.h"
+#include "misc.h"
+
+#include "jpake.h"
+#include "schnorr.h"
+
+#ifdef JPAKE
+
+/* RFC3526 group 5, 1536 bits */
+#define JPAKE_GROUP_G "2"
+#define JPAKE_GROUP_P \
+       "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74" \
+       "020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437" \
+       "4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+       "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05" \
+       "98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB" \
+       "9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+
+struct modp_group *
+jpake_default_group(void)
+{
+       return modp_group_from_g_and_safe_p(JPAKE_GROUP_G, JPAKE_GROUP_P);
+}
+
+struct jpake_ctx *
+jpake_new(void)
+{
+       struct jpake_ctx *ret;
+
+       ret = xcalloc(1, sizeof(*ret));
+
+       ret->grp = jpake_default_group();
+
+       ret->s = ret->k = NULL;
+       ret->x1 = ret->x2 = ret->x3 = ret->x4 = NULL;
+       ret->g_x1 = ret->g_x2 = ret->g_x3 = ret->g_x4 = NULL;
+       ret->a = ret->b = NULL;
+
+       ret->client_id = ret->server_id = NULL;
+       ret->h_k_cid_sessid = ret->h_k_sid_sessid = NULL;
+
+       debug3("%s: alloc %p", __func__, ret);
+
+       return ret;
+}
+
+void
+jpake_free(struct jpake_ctx *pctx)
+{
+       debug3("%s: free %p", __func__, pctx);
+
+#define JPAKE_BN_CLEAR_FREE(v)                 \
+       do {                                    \
+               if ((v) != NULL) {              \
+                       BN_clear_free(v);       \
+                       (v) = NULL;             \
+               }                               \
+       } while (0)
+#define JPAKE_BUF_CLEAR_FREE(v, l)             \
+       do {                                    \
+               if ((v) != NULL) {              \
+                       bzero((v), (l));        \
+                       xfree(v);               \
+                       (v) = NULL;             \
+                       (l) = 0;                \
+               }                               \
+       } while (0)
+
+       JPAKE_BN_CLEAR_FREE(pctx->s);
+       JPAKE_BN_CLEAR_FREE(pctx->k);
+       JPAKE_BN_CLEAR_FREE(pctx->x1);
+       JPAKE_BN_CLEAR_FREE(pctx->x2);
+       JPAKE_BN_CLEAR_FREE(pctx->x3);
+       JPAKE_BN_CLEAR_FREE(pctx->x4);
+       JPAKE_BN_CLEAR_FREE(pctx->g_x1);
+       JPAKE_BN_CLEAR_FREE(pctx->g_x2);
+       JPAKE_BN_CLEAR_FREE(pctx->g_x3);
+       JPAKE_BN_CLEAR_FREE(pctx->g_x4);
+       JPAKE_BN_CLEAR_FREE(pctx->a);
+       JPAKE_BN_CLEAR_FREE(pctx->b);
+
+       JPAKE_BUF_CLEAR_FREE(pctx->client_id, pctx->client_id_len);
+       JPAKE_BUF_CLEAR_FREE(pctx->server_id, pctx->server_id_len);
+       JPAKE_BUF_CLEAR_FREE(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len);
+       JPAKE_BUF_CLEAR_FREE(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
+
+#undef JPAKE_BN_CLEAR_FREE
+#undef JPAKE_BUF_CLEAR_FREE
+
+       bzero(pctx, sizeof(pctx));
+       xfree(pctx);
+}
+
+/* dump entire jpake_ctx. NB. includes private values! */
+void
+jpake_dump(struct jpake_ctx *pctx, const char *fmt, ...)
+{
+       char *out;
+       va_list args;
+
+       out = NULL;
+       va_start(args, fmt);
+       vasprintf(&out, fmt, args);
+       va_end(args);
+       if (out == NULL)
+               fatal("%s: vasprintf failed", __func__);
+
+       debug3("%s: %s (ctx at %p)", __func__, out, pctx);
+       if (pctx == NULL) {
+               free(out);
+               return;
+       }
+
+#define JPAKE_DUMP_BN(a)       do { \
+               if ((a) != NULL) \
+                       JPAKE_DEBUG_BN(((a), "%s = ", #a)); \
+       } while (0)
+#define JPAKE_DUMP_BUF(a, b)   do { \
+               if ((a) != NULL) \
+                       JPAKE_DEBUG_BUF((a, b, "%s", #a)); \
+       } while (0)
+
+       JPAKE_DUMP_BN(pctx->s);
+       JPAKE_DUMP_BN(pctx->k);
+       JPAKE_DUMP_BN(pctx->x1);
+       JPAKE_DUMP_BN(pctx->x2);
+       JPAKE_DUMP_BN(pctx->x3);
+       JPAKE_DUMP_BN(pctx->x4);
+       JPAKE_DUMP_BN(pctx->g_x1);
+       JPAKE_DUMP_BN(pctx->g_x2);
+       JPAKE_DUMP_BN(pctx->g_x3);
+       JPAKE_DUMP_BN(pctx->g_x4);
+       JPAKE_DUMP_BN(pctx->a);
+       JPAKE_DUMP_BN(pctx->b);
+
+       JPAKE_DUMP_BUF(pctx->client_id, pctx->client_id_len);
+       JPAKE_DUMP_BUF(pctx->server_id, pctx->server_id_len);
+       JPAKE_DUMP_BUF(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len);
+       JPAKE_DUMP_BUF(pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
+
+       debug3("%s: %s done", __func__, out);
+       free(out);
+}
+
+/* Shared parts of step 1 exchange calculation */
+void
+jpake_step1(struct modp_group *grp,
+    u_char **id, u_int *id_len,
+    BIGNUM **priv1, BIGNUM **priv2, BIGNUM **g_priv1, BIGNUM **g_priv2,
+    u_char **priv1_proof, u_int *priv1_proof_len,
+    u_char **priv2_proof, u_int *priv2_proof_len)
+{
+       BN_CTX *bn_ctx;
+
+       if ((bn_ctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new", __func__);
+
+       /* Random nonce to prevent replay */
+       *id = xmalloc(KZP_ID_LEN);
+       *id_len = KZP_ID_LEN;
+       arc4random_buf(*id, *id_len);
+
+       /*
+        * x1/x3 is a random element of Zq
+        * x2/x4 is a random element of Z*q
+        * We also exclude [1] from x1/x3 candidates and [0, 1] from
+        * x2/x4 candiates to avoid possible degeneracy (i.e. g^0, g^1).
+        */
+       if ((*priv1 = bn_rand_range_gt_one(grp->q)) == NULL ||
+           (*priv2 = bn_rand_range_gt_one(grp->q)) == NULL)
+               fatal("%s: bn_rand_range_gt_one", __func__);
+
+       /*
+        * client: g_x1 = g^x1 mod p / server: g_x3 = g^x3 mod p
+        * client: g_x2 = g^x2 mod p / server: g_x4 = g^x4 mod p
+        */
+       if ((*g_priv1 = BN_new()) == NULL ||
+           (*g_priv2 = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       if (BN_mod_exp(*g_priv1, grp->g, *priv1, grp->p, bn_ctx) == -1)
+               fatal("%s: BN_mod_exp", __func__);
+       if (BN_mod_exp(*g_priv2, grp->g, *priv2, grp->p, bn_ctx) == -1)
+               fatal("%s: BN_mod_exp", __func__);
+
+       /* Generate proofs for holding x1/x3 and x2/x4 */
+       if (schnorr_sign_buf(grp->p, grp->q, grp->g,
+           *priv1, *g_priv1, *id, *id_len,
+           priv1_proof, priv1_proof_len) != 0)
+               fatal("%s: schnorr_sign", __func__);
+       if (schnorr_sign_buf(grp->p, grp->q, grp->g,
+           *priv2, *g_priv2, *id, *id_len,
+           priv2_proof, priv2_proof_len) != 0)
+               fatal("%s: schnorr_sign", __func__);
+
+       BN_CTX_free(bn_ctx);
+}
+
+/* Shared parts of step 2 exchange calculation */
+void
+jpake_step2(struct modp_group *grp, BIGNUM *s,
+    BIGNUM *mypub1, BIGNUM *theirpub1, BIGNUM *theirpub2, BIGNUM *mypriv2,
+    const u_char *theirid, u_int theirid_len,
+    const u_char *myid, u_int myid_len,
+    const u_char *theirpub1_proof, u_int theirpub1_proof_len,
+    const u_char *theirpub2_proof, u_int theirpub2_proof_len,
+    BIGNUM **newpub,
+    u_char **newpub_exponent_proof, u_int *newpub_exponent_proof_len)
+{
+       BN_CTX *bn_ctx;
+       BIGNUM *tmp, *exponent;
+
+       /* Validate peer's step 1 values */
+       if (BN_cmp(theirpub1, BN_value_one()) <= 0)
+               fatal("%s: theirpub1 <= 1", __func__);
+       if (BN_cmp(theirpub1, grp->p) >= 0)
+               fatal("%s: theirpub1 >= p", __func__);
+       if (BN_cmp(theirpub2, BN_value_one()) <= 0)
+               fatal("%s: theirpub2 <= 1", __func__);
+       if (BN_cmp(theirpub2, grp->p) >= 0)
+               fatal("%s: theirpub2 >= p", __func__);
+
+       if (schnorr_verify_buf(grp->p, grp->q, grp->g, theirpub1,
+           theirid, theirid_len, theirpub1_proof, theirpub1_proof_len) != 1)
+               fatal("%s: schnorr_verify theirpub1 failed", __func__);
+       if (schnorr_verify_buf(grp->p, grp->q, grp->g, theirpub2,
+           theirid, theirid_len, theirpub2_proof, theirpub2_proof_len) != 1)
+               fatal("%s: schnorr_verify theirpub2 failed", __func__);
+
+       if ((bn_ctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new", __func__);
+
+       if ((*newpub = BN_new()) == NULL ||
+           (tmp = BN_new()) == NULL ||
+           (exponent = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       /*
+        * client: exponent = x2 * s mod p
+        * server: exponent = x4 * s mod p
+        */
+       if (BN_mod_mul(exponent, mypriv2, s, grp->q, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (exponent = mypriv2 * s mod p)",
+                   __func__);
+
+       /*
+        * client: tmp = g^(x1 + x3 + x4) mod p
+        * server: tmp = g^(x1 + x2 + x3) mod p
+        */
+       if (BN_mod_mul(tmp, mypub1, theirpub1, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (tmp = mypub1 * theirpub1 mod p)",
+                   __func__);
+       if (BN_mod_mul(tmp, tmp, theirpub2, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (tmp = tmp * theirpub2 mod p)", __func__);
+
+       /*
+        * client: a = tmp^exponent = g^((x1+x3+x4) * x2 * s) mod p
+        * server: b = tmp^exponent = g^((x1+x2+x3) * x4 * s) mod p
+        */
+       if (BN_mod_exp(*newpub, tmp, exponent, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (newpub = tmp^exponent mod p)", __func__);
+
+       JPAKE_DEBUG_BN((tmp, "%s: tmp = ", __func__));
+       JPAKE_DEBUG_BN((exponent, "%s: exponent = ", __func__));
+
+       /* Note the generator here is 'tmp', not g */
+       if (schnorr_sign_buf(grp->p, grp->q, tmp, exponent, *newpub,
+           myid, myid_len,
+           newpub_exponent_proof, newpub_exponent_proof_len) != 0)
+               fatal("%s: schnorr_sign newpub", __func__);
+
+       BN_clear_free(tmp); /* XXX stash for later use? */
+       BN_clear_free(exponent); /* XXX stash for later use? (yes, in conf) */
+
+       BN_CTX_free(bn_ctx);
+}
+
+/* Confirmation hash calculation */
+void
+jpake_confirm_hash(const BIGNUM *k,
+    const u_char *endpoint_id, u_int endpoint_id_len,
+    const u_char *sess_id, u_int sess_id_len,
+    u_char **confirm_hash, u_int *confirm_hash_len)
+{
+       Buffer b;
+
+       /*
+        * Calculate confirmation proof:
+        *     client: H(k || client_id || session_id)
+        *     server: H(k || server_id || session_id)
+        */
+       buffer_init(&b);
+       buffer_put_bignum2(&b, k);
+       buffer_put_string(&b, endpoint_id, endpoint_id_len);
+       buffer_put_string(&b, sess_id, sess_id_len);
+       if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(),
+           confirm_hash, confirm_hash_len) != 0)
+               fatal("%s: hash_buffer", __func__);
+       buffer_free(&b);
+}
+
+/* Shared parts of key derivation and confirmation calculation */
+void
+jpake_key_confirm(struct modp_group *grp, BIGNUM *s, BIGNUM *step2_val,
+    BIGNUM *mypriv2, BIGNUM *mypub1, BIGNUM *mypub2,
+    BIGNUM *theirpub1, BIGNUM *theirpub2,
+    const u_char *my_id, u_int my_id_len,
+    const u_char *their_id, u_int their_id_len,
+    const u_char *sess_id, u_int sess_id_len,
+    const u_char *theirpriv2_s_proof, u_int theirpriv2_s_proof_len,
+    BIGNUM **k,
+    u_char **confirm_hash, u_int *confirm_hash_len)
+{
+       BN_CTX *bn_ctx;
+       BIGNUM *tmp;
+
+       if ((bn_ctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new", __func__);
+       if ((tmp = BN_new()) == NULL ||
+           (*k = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       /* Validate step 2 values */
+       if (BN_cmp(step2_val, BN_value_one()) <= 0)
+               fatal("%s: step2_val <= 1", __func__);
+       if (BN_cmp(step2_val, grp->p) >= 0)
+               fatal("%s: step2_val >= p", __func__);
+
+       /*
+        * theirpriv2_s_proof is calculated with a different generator:
+        * tmp = g^(mypriv1+mypriv2+theirpub1) = g^mypub1*g^mypub2*g^theirpub1
+        * Calculate it here so we can check the signature.
+        */
+       if (BN_mod_mul(tmp, mypub1, mypub2, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (tmp = mypub1 * mypub2 mod p)", __func__);
+       if (BN_mod_mul(tmp, tmp, theirpub1, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (tmp = tmp * theirpub1 mod p)", __func__);
+
+       JPAKE_DEBUG_BN((tmp, "%s: tmp = ", __func__));
+
+       if (schnorr_verify_buf(grp->p, grp->q, tmp, step2_val, 
+           their_id, their_id_len,
+           theirpriv2_s_proof, theirpriv2_s_proof_len) != 1)
+               fatal("%s: schnorr_verify theirpriv2_s_proof failed", __func__);
+
+       /*
+        * Derive shared key:
+        *     client: k = (b / g^(x2*x4*s))^x2 = g^((x1+x3)*x2*x4*s)
+        *     server: k = (a / g^(x2*x4*s))^x4 = g^((x1+x3)*x2*x4*s)
+        *
+        * Computed as:
+        *     client: k = (g_x4^(q - (x2 * s)) * b)^x2 mod p
+        *     server: k = (g_x2^(q - (x4 * s)) * b)^x4 mod p
+        */
+       if (BN_mul(tmp, mypriv2, s, bn_ctx) != 1)
+               fatal("%s: BN_mul (tmp = mypriv2 * s)", __func__);
+       if (BN_mod_sub(tmp, grp->q, tmp, grp->q, bn_ctx) != 1)
+               fatal("%s: BN_mod_sub (tmp = q - tmp mod q)", __func__);
+       if (BN_mod_exp(tmp, theirpub2, tmp, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_exp (tmp = theirpub2^tmp) mod p", __func__);
+       if (BN_mod_mul(tmp, tmp, step2_val, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_mul (tmp = tmp * step2_val) mod p", __func__);
+       if (BN_mod_exp(*k, tmp, mypriv2, grp->p, bn_ctx) != 1)
+               fatal("%s: BN_mod_exp (k = tmp^mypriv2) mod p", __func__);
+       
+       BN_CTX_free(bn_ctx);
+       BN_clear_free(tmp);
+
+       jpake_confirm_hash(*k, my_id, my_id_len, sess_id, sess_id_len,
+           confirm_hash, confirm_hash_len);
+}
+
+/*
+ * Calculate and check confirmation hash from peer. Returns 1 on success
+ * 0 on failure/mismatch.
+ */
+int
+jpake_check_confirm(const BIGNUM *k,
+    const u_char *peer_id, u_int peer_id_len,
+    const u_char *sess_id, u_int sess_id_len,
+    const u_char *peer_confirm_hash, u_int peer_confirm_hash_len)
+{
+       u_char *expected_confirm_hash;
+       u_int expected_confirm_hash_len;
+       int success = 0;
+
+       /* Calculate and verify expected confirmation hash */
+       jpake_confirm_hash(k, peer_id, peer_id_len, sess_id, sess_id_len,
+           &expected_confirm_hash, &expected_confirm_hash_len);
+
+       JPAKE_DEBUG_BUF((expected_confirm_hash, expected_confirm_hash_len,
+           "%s: expected confirm hash", __func__));
+       JPAKE_DEBUG_BUF((peer_confirm_hash, peer_confirm_hash_len,
+           "%s: received confirm hash", __func__));
+
+       if (peer_confirm_hash_len != expected_confirm_hash_len)
+               error("%s: confirmation length mismatch (my %u them %u)",
+                   __func__, expected_confirm_hash_len, peer_confirm_hash_len);
+       else if (timingsafe_bcmp(peer_confirm_hash, expected_confirm_hash,
+           expected_confirm_hash_len) == 0)
+               success = 1;
+       bzero(expected_confirm_hash, expected_confirm_hash_len);
+       xfree(expected_confirm_hash);
+       debug3("%s: success = %d", __func__, success);
+       return success;
+}
+
+/* XXX main() function with tests */
+
+#endif /* JPAKE */
+
diff --git a/jpake.h b/jpake.h
new file mode 100644 (file)
index 0000000..a3f2cf0
--- /dev/null
+++ b/jpake.h
@@ -0,0 +1,114 @@
+/* $OpenBSD: jpake.h,v 1.2 2009/03/05 07:18:19 djm Exp $ */
+/*
+ * Copyright (c) 2008 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef JPAKE_H
+#define JPAKE_H
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+
+/* Set JPAKE_DEBUG in CFLAGS for privacy-violating debugging */
+#ifndef JPAKE_DEBUG
+# define JPAKE_DEBUG_BN(a)
+# define JPAKE_DEBUG_BUF(a)
+# define JPAKE_DEBUG_CTX(a)
+#else
+# define JPAKE_DEBUG_BN(a)     debug3_bn a
+# define JPAKE_DEBUG_BUF(a)    debug3_buf a
+# define JPAKE_DEBUG_CTX(a)    jpake_dump a
+#endif /* JPAKE_DEBUG */
+
+#define KZP_ID_LEN     16      /* Length of client and server IDs */
+
+struct jpake_ctx {
+       /* Parameters */
+       struct modp_group *grp;
+
+       /* Private values shared by client and server */
+       BIGNUM *s;                      /* Secret (salted, crypted password) */
+       BIGNUM *k;                      /* Derived key */
+
+       /* Client private values (NULL for server) */
+       BIGNUM *x1;                     /* random in Zq */
+       BIGNUM *x2;                     /* random in Z*q */
+
+       /* Server private values (NULL for server) */
+       BIGNUM *x3;                     /* random in Zq */
+       BIGNUM *x4;                     /* random in Z*q */
+
+       /* Step 1: C->S */
+       u_char *client_id;              /* Anti-replay nonce */
+       u_int client_id_len;
+       BIGNUM *g_x1;                   /* g^x1 */
+       BIGNUM *g_x2;                   /* g^x2 */
+
+       /* Step 1: S->C */
+       u_char *server_id;              /* Anti-replay nonce */
+       u_int server_id_len;
+       BIGNUM *g_x3;                   /* g^x3 */
+       BIGNUM *g_x4;                   /* g^x4 */
+
+       /* Step 2: C->S */
+       BIGNUM *a;                      /* g^((x1+x3+x4)*x2*s) */
+
+       /* Step 2: S->C */
+       BIGNUM *b;                      /* g^((x1+x2+x3)*x4*s) */
+
+       /* Confirmation: C->S */
+       u_char *h_k_cid_sessid;         /* H(k || client_id || session_id) */
+       u_int h_k_cid_sessid_len;
+
+       /* Confirmation: S->C */
+       u_char *h_k_sid_sessid;         /* H(k || server_id || session_id) */
+       u_int h_k_sid_sessid_len;
+};
+
+/* jpake.c */
+struct modp_group *jpake_default_group(void);
+void jpake_dump(struct jpake_ctx *, const char *, ...)
+    __attribute__((__nonnull__ (2)))
+    __attribute__((format(printf, 2, 3)));
+struct jpake_ctx *jpake_new(void);
+void jpake_free(struct jpake_ctx *);
+
+void jpake_step1(struct modp_group *, u_char **, u_int *,
+    BIGNUM **, BIGNUM **, BIGNUM **, BIGNUM **,
+    u_char **, u_int *, u_char **, u_int *);
+
+void jpake_step2(struct modp_group *, BIGNUM *,
+    BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
+    const u_char *, u_int, const u_char *, u_int,
+    const u_char *, u_int, const u_char *, u_int,
+    BIGNUM **, u_char **, u_int *);
+
+void jpake_confirm_hash(const BIGNUM *,
+    const u_char *, u_int,
+    const u_char *, u_int,
+    u_char **, u_int *);
+
+void jpake_key_confirm(struct modp_group *, BIGNUM *, BIGNUM *,
+    BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
+    const u_char *, u_int, const u_char *, u_int,
+    const u_char *, u_int, const u_char *, u_int,
+    BIGNUM **, u_char **, u_int *);
+
+int jpake_check_confirm(const BIGNUM *, const u_char *, u_int,
+    const u_char *, u_int, const u_char *, u_int);
+
+#endif /* JPAKE_H */
+
diff --git a/kex.c b/kex.c
new file mode 100644 (file)
index 0000000..c65e28f
--- /dev/null
+++ b/kex.c
@@ -0,0 +1,610 @@
+/* $OpenBSD: kex.c,v 1.86 2010/09/22 05:01:29 djm 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.
+ */
+
+#include "includes.h"
+
+#include <sys/param.h>
+
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/crypto.h>
+
+#include "xmalloc.h"
+#include "ssh2.h"
+#include "buffer.h"
+#include "packet.h"
+#include "compat.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include "log.h"
+#include "mac.h"
+#include "match.h"
+#include "dispatch.h"
+#include "monitor.h"
+#include "roaming.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+# if defined(HAVE_EVP_SHA256)
+# define evp_ssh_sha256 EVP_sha256
+# else
+extern const EVP_MD *evp_ssh_sha256(void);
+# endif
+#endif
+
+/* prototype */
+static void kex_kexinit_finish(Kex *);
+static void kex_choose_conf(Kex *);
+
+/* Validate KEX method name list */
+int
+kex_names_valid(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, ","))) {
+               if (strcmp(p, KEX_DHGEX_SHA256) != 0 &&
+                   strcmp(p, KEX_DHGEX_SHA1) != 0 &&
+                   strcmp(p, KEX_DH14) != 0 &&
+                   strcmp(p, KEX_DH1) != 0 &&
+                   (strncmp(p, KEX_ECDH_SHA2_STEM,
+                   sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 ||
+                   kex_ecdh_name_to_nid(p) == -1)) {
+                       error("Unsupported KEX algorithm \"%.100s\"", p);
+                       xfree(s);
+                       return 0;
+               }
+       }
+       debug3("kex names ok: [%s]", names);
+       xfree(s);
+       return 1;
+}
+
+/* put algorithm proposal into buffer */
+static void
+kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
+{
+       u_int i;
+
+       buffer_clear(b);
+       /*
+        * add a dummy cookie, the cookie will be overwritten by
+        * kex_send_kexinit(), each time a kexinit is set
+        */
+       for (i = 0; i < KEX_COOKIE_LEN; i++)
+               buffer_put_char(b, 0);
+       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, int *first_kex_follows)
+{
+       Buffer b;
+       u_int i;
+       char **proposal;
+
+       proposal = xcalloc(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_cstring(&b,NULL);
+               debug2("kex_parse_kexinit: %s", proposal[i]);
+       }
+       /* first kex follows / reserved */
+       i = buffer_get_char(&b);
+       if (first_kex_follows != NULL)
+               *first_kex_follows = i;
+       debug2("kex_parse_kexinit: first_kex_follows %d ", i);
+       i = buffer_get_int(&b);
+       debug2("kex_parse_kexinit: reserved %u ", i);
+       buffer_free(&b);
+       return proposal;
+}
+
+static void
+kex_prop_free(char **proposal)
+{
+       u_int i;
+
+       for (i = 0; i < PROPOSAL_MAX; i++)
+               xfree(proposal[i]);
+       xfree(proposal);
+}
+
+/* ARGSUSED */
+static void
+kex_protocol_error(int type, u_int32_t seq, void *ctxt)
+{
+       error("Hm, kex protocol error: type %d seq %u", type, seq);
+}
+
+static void
+kex_reset_dispatch(void)
+{
+       dispatch_range(SSH2_MSG_TRANSPORT_MIN,
+           SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
+       dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit);
+}
+
+void
+kex_finish(Kex *kex)
+{
+       kex_reset_dispatch();
+
+       packet_start(SSH2_MSG_NEWKEYS);
+       packet_send();
+       /* packet_write_wait(); */
+       debug("SSH2_MSG_NEWKEYS sent");
+
+       debug("expecting SSH2_MSG_NEWKEYS");
+       packet_read_expect(SSH2_MSG_NEWKEYS);
+       packet_check_eom();
+       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)
+{
+       u_int32_t rnd = 0;
+       u_char *cookie;
+       u_int i;
+
+       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;
+
+       /* generate a random cookie */
+       if (buffer_len(&kex->my) < KEX_COOKIE_LEN)
+               fatal("kex_send_kexinit: kex proposal too short");
+       cookie = buffer_ptr(&kex->my);
+       for (i = 0; i < KEX_COOKIE_LEN; i++) {
+               if (i % 4 == 0)
+                       rnd = arc4random();
+               cookie[i] = rnd;
+               rnd >>= 8;
+       }
+       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;
+}
+
+/* ARGSUSED */
+void
+kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
+{
+       char *ptr;
+       u_int i, dlen;
+       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));
+       (void) packet_get_char();
+       (void) packet_get_int();
+       packet_check_eom();
+
+       kex_kexinit_finish(kex);
+}
+
+Kex *
+kex_setup(char *proposal[PROPOSAL_MAX])
+{
+       Kex *kex;
+
+       kex = xcalloc(1, 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_reset_dispatch();
+
+       return kex;
+}
+
+static void
+kex_kexinit_finish(Kex *kex)
+{
+       if (!(kex->flags & KEX_INIT_SENT))
+               kex_send_kexinit(kex);
+
+       kex_choose_conf(kex);
+
+       if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX &&
+           kex->kex[kex->kex_type] != NULL) {
+               (kex->kex[kex->kex_type])(kex);
+       } else {
+               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);
+       if ((enc->cipher = cipher_by_name(name)) == NULL)
+               fatal("matching cipher is not supported: %s", name);
+       enc->name = name;
+       enc->enabled = 0;
+       enc->iv = NULL;
+       enc->key = NULL;
+       enc->key_len = cipher_keylen(enc->cipher);
+       enc->block_size = cipher_blocksize(enc->cipher);
+}
+
+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_setup(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@openssh.com") == 0) {
+               comp->type = COMP_DELAYED;
+       } else if (strcmp(name, "zlib") == 0) {
+               comp->type = COMP_ZLIB;
+       } else if (strcmp(name, "none") == 0) {
+               comp->type = COMP_NONE;
+       } 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("Unable to negotiate a key exchange method");
+       if (strcmp(k->name, KEX_DH1) == 0) {
+               k->kex_type = KEX_DH_GRP1_SHA1;
+               k->evp_md = EVP_sha1();
+       } else if (strcmp(k->name, KEX_DH14) == 0) {
+               k->kex_type = KEX_DH_GRP14_SHA1;
+               k->evp_md = EVP_sha1();
+       } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) {
+               k->kex_type = KEX_DH_GEX_SHA1;
+               k->evp_md = EVP_sha1();
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+       } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) {
+               k->kex_type = KEX_DH_GEX_SHA256;
+               k->evp_md = evp_ssh_sha256();
+       } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM,
+           sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) {
+               k->kex_type = KEX_ECDH_SHA2;
+               k->evp_md = kex_ecdh_name_to_evpmd(k->name);
+#endif
+       } 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 int
+proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
+{
+       static int check[] = {
+               PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1
+       };
+       int *idx;
+       char *p;
+
+       for (idx = &check[0]; *idx != -1; idx++) {
+               if ((p = strchr(my[*idx], ',')) != NULL)
+                       *p = '\0';
+               if ((p = strchr(peer[*idx], ',')) != NULL)
+                       *p = '\0';
+               if (strcmp(my[*idx], peer[*idx]) != 0) {
+                       debug2("proposal mismatch: my %s peer %s",
+                           my[*idx], peer[*idx]);
+                       return (0);
+               }
+       }
+       debug2("proposals match");
+       return (1);
+}
+
+static void
+kex_choose_conf(Kex *kex)
+{
+       Newkeys *newkeys;
+       char **my, **peer;
+       char **cprop, **sprop;
+       int nenc, nmac, ncomp;
+       u_int mode, ctos, need;
+       int first_kex_follows, type;
+
+       my   = kex_buf2prop(&kex->my, NULL);
+       peer = kex_buf2prop(&kex->peer, &first_kex_follows);
+
+       if (kex->server) {
+               cprop=peer;
+               sprop=my;
+       } else {
+               cprop=my;
+               sprop=peer;
+       }
+
+       /* Check whether server offers roaming */
+       if (!kex->server) {
+               char *roaming;
+               roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL);
+               if (roaming) {
+                       kex->roaming = 1;
+                       xfree(roaming);
+               }
+       }
+
+       /* Algorithm Negotiation */
+       for (mode = 0; mode < MODE_MAX; mode++) {
+               newkeys = xcalloc(1, 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.key_len)
+                       need = newkeys->enc.key_len;
+               if (need < newkeys->enc.block_size)
+                       need = newkeys->enc.block_size;
+               if (need < newkeys->mac.key_len)
+                       need = newkeys->mac.key_len;
+       }
+       /* XXX need runden? */
+       kex->we_need = need;
+
+       /* ignore the next message if the proposals do not match */
+       if (first_kex_follows && !proposals_match(my, peer) &&
+           !(datafellows & SSH_BUG_FIRSTKEX)) {
+               type = packet_read();
+               debug2("skipping next packet (type %u)", type);
+       }
+
+       kex_prop_free(my);
+       kex_prop_free(peer);
+}
+
+static u_char *
+derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
+    BIGNUM *shared_secret)
+{
+       Buffer b;
+       EVP_MD_CTX md;
+       char c = id;
+       u_int have;
+       int mdsz;
+       u_char *digest;
+
+       if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0)
+               fatal("bad kex md size %d", mdsz);
+       digest = xmalloc(roundup(need, mdsz));
+
+       buffer_init(&b);
+       buffer_put_bignum2(&b, shared_secret);
+
+       /* K1 = HASH(K || H || "A" || session_id) */
+       EVP_DigestInit(&md, kex->evp_md);
+       if (!(datafellows & SSH_BUG_DERIVEKEY))
+               EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestUpdate(&md, hash, hashlen);
+       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, kex->evp_md);
+               if (!(datafellows & SSH_BUG_DERIVEKEY))
+                       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+               EVP_DigestUpdate(&md, hash, hashlen);
+               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, u_int hashlen, BIGNUM *shared_secret)
+{
+       u_char *keys[NKEYS];
+       u_int i, mode, ctos;
+
+       for (i = 0; i < NKEYS; i++) {
+               keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen,
+                   shared_secret);
+       }
+
+       debug2("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;
+}
+
+void
+derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
+    u_int8_t cookie[8], u_int8_t id[16])
+{
+       const EVP_MD *evp_md = EVP_md5();
+       EVP_MD_CTX md;
+       u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE];
+       int len;
+
+       EVP_DigestInit(&md, evp_md);
+
+       len = BN_num_bytes(host_modulus);
+       if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
+               fatal("%s: bad host modulus (len %d)", __func__, len);
+       BN_bn2bin(host_modulus, nbuf);
+       EVP_DigestUpdate(&md, nbuf, len);
+
+       len = BN_num_bytes(server_modulus);
+       if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
+               fatal("%s: bad server modulus (len %d)", __func__, len);
+       BN_bn2bin(server_modulus, nbuf);
+       EVP_DigestUpdate(&md, nbuf, len);
+
+       EVP_DigestUpdate(&md, cookie, 8);
+
+       EVP_DigestFinal(&md, obuf, NULL);
+       memcpy(id, obuf, 16);
+
+       memset(nbuf, 0, sizeof(nbuf));
+       memset(obuf, 0, sizeof(obuf));
+       memset(&md, 0, sizeof(md));
+}
+
+#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
+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/kex.h b/kex.h
new file mode 100644 (file)
index 0000000..7373d3c
--- /dev/null
+++ b/kex.h
@@ -0,0 +1,185 @@
+/* $OpenBSD: kex.h,v 1.52 2010/09/22 05:01:29 djm 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 <signal.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#ifdef OPENSSL_HAS_ECC
+#include <openssl/ec.h>
+#endif
+
+#define KEX_COOKIE_LEN 16
+
+#define        KEX_DH1                 "diffie-hellman-group1-sha1"
+#define        KEX_DH14                "diffie-hellman-group14-sha1"
+#define        KEX_DHGEX_SHA1          "diffie-hellman-group-exchange-sha1"
+#define        KEX_DHGEX_SHA256        "diffie-hellman-group-exchange-sha256"
+#define        KEX_RESUME              "resume@appgate.com"
+/* The following represents the family of ECDH methods */
+#define        KEX_ECDH_SHA2_STEM      "ecdh-sha2-"
+
+#define COMP_NONE      0
+#define COMP_ZLIB      1
+#define COMP_DELAYED   2
+
+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 {
+       KEX_DH_GRP1_SHA1,
+       KEX_DH_GRP14_SHA1,
+       KEX_DH_GEX_SHA1,
+       KEX_DH_GEX_SHA256,
+       KEX_ECDH_SHA2,
+       KEX_MAX
+};
+
+#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_int   key_len;
+       u_int   block_size;
+       u_char  *key;
+       u_char  *iv;
+};
+struct Mac {
+       char    *name;
+       int     enabled;
+       u_int   mac_len;
+       u_char  *key;
+       u_int   key_len;
+       int     type;
+       const EVP_MD    *evp_md;
+       HMAC_CTX        evp_ctx;
+       struct umac_ctx *umac_ctx;
+};
+struct Comp {
+       int     type;
+       int     enabled;
+       char    *name;
+};
+struct Newkeys {
+       Enc     enc;
+       Mac     mac;
+       Comp    comp;
+};
+struct Kex {
+       u_char  *session_id;
+       u_int   session_id_len;
+       Newkeys *newkeys[MODE_MAX];
+       u_int   we_need;
+       int     server;
+       char    *name;
+       int     hostkey_type;
+       int     kex_type;
+       int     roaming;
+       Buffer  my;
+       Buffer  peer;
+       sig_atomic_t done;
+       int     flags;
+       const EVP_MD *evp_md;
+       char    *client_version_string;
+       char    *server_version_string;
+       int     (*verify_host_key)(Key *);
+       Key     *(*load_host_public_key)(int);
+       Key     *(*load_host_private_key)(int);
+       int     (*host_key_index)(Key *);
+       void    (*kex[KEX_MAX])(Kex *);
+};
+
+int     kex_names_valid(const char *);
+
+Kex    *kex_setup(char *[PROPOSAL_MAX]);
+void    kex_finish(Kex *);
+
+void    kex_send_kexinit(Kex *);
+void    kex_input_kexinit(int, u_int32_t, void *);
+void    kex_derive_keys(Kex *, u_char *, u_int, BIGNUM *);
+
+Newkeys *kex_get_newkeys(int);
+
+void    kexdh_client(Kex *);
+void    kexdh_server(Kex *);
+void    kexgex_client(Kex *);
+void    kexgex_server(Kex *);
+void    kexecdh_client(Kex *);
+void    kexecdh_server(Kex *);
+
+void
+kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
+    BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *);
+void
+kexgex_hash(const EVP_MD *, char *, char *, char *, int, char *,
+    int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *,
+    BIGNUM *, BIGNUM *, u_char **, u_int *);
+#ifdef OPENSSL_HAS_ECC
+void
+kex_ecdh_hash(const EVP_MD *, const EC_GROUP *, char *, char *, char *, int,
+    char *, int, u_char *, int, const EC_POINT *, const EC_POINT *,
+    const BIGNUM *, u_char **, u_int *);
+int    kex_ecdh_name_to_nid(const char *);
+const EVP_MD *kex_ecdh_name_to_evpmd(const char *);
+#else
+# define kex_ecdh_name_to_nid(x) (-1)
+# define kex_ecdh_name_to_evpmd(x) (NULL)
+#endif
+
+void
+derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
+
+#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
+void   dump_digest(char *, u_char *, int);
+#endif
+
+#endif
diff --git a/kexdh.c b/kexdh.c
new file mode 100644 (file)
index 0000000..56e22f5
--- /dev/null
+++ b/kexdh.c
@@ -0,0 +1,88 @@
+/* $OpenBSD: kexdh.c,v 1.23 2006/08/03 03:34:42 deraadt 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <signal.h>
+
+#include <openssl/evp.h>
+
+#include "buffer.h"
+#include "ssh2.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+
+void
+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,
+    u_char **hash, u_int *hashlen)
+{
+       Buffer b;
+       static u_char digest[EVP_MAX_MD_SIZE];
+       const 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_size(evp_md));
+#endif
+       *hash = digest;
+       *hashlen = EVP_MD_size(evp_md);
+}
diff --git a/kexdhc.c b/kexdhc.c
new file mode 100644 (file)
index 0000000..76ceb5d
--- /dev/null
+++ b/kexdhc.c
@@ -0,0 +1,161 @@
+/* $OpenBSD: kexdhc.c,v 1.12 2010/11/10 01:33:07 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <openssl/dh.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+
+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, slen, sbloblen, hashlen;
+       int kout;
+
+       /* generate and send 'e', client DH public key */
+       switch (kex->kex_type) {
+       case KEX_DH_GRP1_SHA1:
+               dh = dh_new_group1();
+               break;
+       case KEX_DH_GRP14_SHA1:
+               dh = dh_new_group14();
+               break;
+       default:
+               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
+       }
+       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(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 (server_host_key->type != kex->hostkey_type)
+               fatal("type mismatch for decoded 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 parameter f, server public DH key */
+       if ((dh_server_pub = BN_new()) == NULL)
+               fatal("dh_server_pub == NULL");
+       packet_get_bignum2(dh_server_pub);
+
+#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_check_eom();
+
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0)
+               fatal("DH_compute_key: failed");
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("kexdh_client: BN_new failed");
+       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+               fatal("kexdh_client: BN_bin2bn failed");
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       /* calc and verify H */
+       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,
+           &hash, &hashlen
+       );
+       xfree(server_host_key_blob);
+       BN_clear_free(dh_server_pub);
+       DH_free(dh);
+
+       if (key_verify(server_host_key, signature, slen, hash, hashlen) != 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 = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       kex_derive_keys(kex, hash, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
diff --git a/kexdhs.c b/kexdhs.c
new file mode 100644 (file)
index 0000000..f56e887
--- /dev/null
+++ b/kexdhs.c
@@ -0,0 +1,168 @@
+/* $OpenBSD: kexdhs.c,v 1.12 2010/11/10 01:33:07 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+
+#include <openssl/dh.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+void
+kexdh_server(Kex *kex)
+{
+       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       DH *dh;
+       Key *server_host_public, *server_host_private;
+       u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+       u_int sbloblen, klen, hashlen, slen;
+       int kout;
+
+       /* generate server DH public key */
+       switch (kex->kex_type) {
+       case KEX_DH_GRP1_SHA1:
+               dh = dh_new_group1();
+               break;
+       case KEX_DH_GRP14_SHA1:
+               dh = dh_new_group14();
+               break;
+       default:
+               fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
+       }
+       dh_gen_key(dh, kex->we_need * 8);
+
+       debug("expecting SSH2_MSG_KEXDH_INIT");
+       packet_read_expect(SSH2_MSG_KEXDH_INIT);
+
+       if (kex->load_host_public_key == NULL ||
+           kex->load_host_private_key == NULL)
+               fatal("Cannot load hostkey");
+       server_host_public = kex->load_host_public_key(kex->hostkey_type);
+       if (server_host_public == NULL)
+               fatal("Unsupported hostkey type %d", kex->hostkey_type);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type);
+       if (server_host_private == NULL)
+               fatal("Missing private key for hostkey type %d",
+                   kex->hostkey_type);
+
+       /* key, cert */
+       if ((dh_client_pub = BN_new()) == NULL)
+               fatal("dh_client_pub == NULL");
+       packet_get_bignum2(dh_client_pub);
+       packet_check_eom();
+
+#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);
+       if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
+               fatal("DH_compute_key: failed");
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("kexdh_server: BN_new failed");
+       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+               fatal("kexdh_server: BN_bin2bn failed");
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
+
+       /* calc H */
+       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,
+           &hash, &hashlen
+       );
+       BN_clear_free(dh_client_pub);
+
+       /* save session id := H */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       /* sign H */
+       if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash,
+           hashlen)) < 0)
+               fatal("kexdh_server: key_sign failed");
+
+       /* 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, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
diff --git a/kexecdh.c b/kexecdh.c
new file mode 100644 (file)
index 0000000..f13f69d
--- /dev/null
+++ b/kexecdh.c
@@ -0,0 +1,117 @@
+/* $OpenBSD: kexecdh.c,v 1.3 2010/09/22 05:01:29 djm Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2010 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 OPENSSL_HAS_ECC
+
+#include <sys/types.h>
+
+#include <signal.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+
+#include "buffer.h"
+#include "ssh2.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+
+int
+kex_ecdh_name_to_nid(const char *kexname)
+{
+       if (strlen(kexname) < sizeof(KEX_ECDH_SHA2_STEM) - 1)
+               fatal("%s: kexname too short \"%s\"", __func__, kexname);
+       return key_curve_name_to_nid(kexname + sizeof(KEX_ECDH_SHA2_STEM) - 1);
+}
+
+const EVP_MD *
+kex_ecdh_name_to_evpmd(const char *kexname)
+{
+       int nid = kex_ecdh_name_to_nid(kexname);
+
+       if (nid == -1)
+               fatal("%s: unsupported ECDH curve \"%s\"", __func__, kexname);
+       return key_ec_nid_to_evpmd(nid);
+}
+
+void
+kex_ecdh_hash(
+    const EVP_MD *evp_md,
+    const EC_GROUP *ec_group,
+    char *client_version_string,
+    char *server_version_string,
+    char *ckexinit, int ckexinitlen,
+    char *skexinit, int skexinitlen,
+    u_char *serverhostkeyblob, int sbloblen,
+    const EC_POINT *client_dh_pub,
+    const EC_POINT *server_dh_pub,
+    const BIGNUM *shared_secret,
+    u_char **hash, u_int *hashlen)
+{
+       Buffer b;
+       EVP_MD_CTX md;
+       static u_char digest[EVP_MAX_MD_SIZE];
+
+       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_ecpoint(&b, ec_group, client_dh_pub);
+       buffer_put_ecpoint(&b, ec_group, 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_size(evp_md));
+#endif
+       *hash = digest;
+       *hashlen = EVP_MD_size(evp_md);
+}
+
+#endif /* OPENSSL_HAS_ECC */
diff --git a/kexecdhc.c b/kexecdhc.c
new file mode 100644 (file)
index 0000000..115d4bf
--- /dev/null
@@ -0,0 +1,168 @@
+/* $OpenBSD: kexecdhc.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2010 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 <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+
+#ifdef OPENSSL_HAS_ECC
+
+#include <openssl/ecdh.h>
+
+void
+kexecdh_client(Kex *kex)
+{
+       EC_KEY *client_key;
+       EC_POINT *server_public;
+       const EC_GROUP *group;
+       BIGNUM *shared_secret;
+       Key *server_host_key;
+       u_char *server_host_key_blob = NULL, *signature = NULL;
+       u_char *kbuf, *hash;
+       u_int klen, slen, sbloblen, hashlen;
+       int curve_nid;
+
+       if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1)
+               fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
+       if ((client_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
+               fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
+       if (EC_KEY_generate_key(client_key) != 1)
+               fatal("%s: EC_KEY_generate_key failed", __func__);
+       group = EC_KEY_get0_group(client_key);
+
+       packet_start(SSH2_MSG_KEX_ECDH_INIT);
+       packet_put_ecpoint(group, EC_KEY_get0_public_key(client_key));
+       packet_send();
+       debug("sending SSH2_MSG_KEX_ECDH_INIT");
+
+#ifdef DEBUG_KEXECDH
+       fputs("client private key:\n", stderr);
+       key_dump_ec_key(client_key);
+#endif
+
+       debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
+       packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY);
+
+       /* hostkey */
+       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 (server_host_key->type != kex->hostkey_type)
+               fatal("type mismatch for decoded 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");
+
+       /* Q_S, server public key */
+       if ((server_public = EC_POINT_new(group)) == NULL)
+               fatal("%s: EC_POINT_new failed", __func__);
+       packet_get_ecpoint(group, server_public);
+
+       if (key_ec_validate_public(group, server_public) != 0)
+               fatal("%s: invalid server public key", __func__);
+
+#ifdef DEBUG_KEXECDH
+       fputs("server public key:\n", stderr);
+       key_dump_ec_point(group, server_public);
+#endif
+
+       /* signed H */
+       signature = packet_get_string(&slen);
+       packet_check_eom();
+
+       klen = (EC_GROUP_get_degree(group) + 7) / 8;
+       kbuf = xmalloc(klen);
+       if (ECDH_compute_key(kbuf, klen, server_public,
+           client_key, NULL) != (int)klen)
+               fatal("%s: ECDH_compute_key failed", __func__);
+
+#ifdef DEBUG_KEXECDH
+       dump_digest("shared secret", kbuf, klen);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+       if (BN_bin2bn(kbuf, klen, shared_secret) == NULL)
+               fatal("%s: BN_bin2bn failed", __func__);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       /* calc and verify H */
+       kex_ecdh_hash(
+           kex->evp_md,
+           group,
+           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,
+           EC_KEY_get0_public_key(client_key),
+           server_public,
+           shared_secret,
+           &hash, &hashlen
+       );
+       xfree(server_host_key_blob);
+       EC_POINT_clear_free(server_public);
+       EC_KEY_free(client_key);
+
+       if (key_verify(server_host_key, signature, slen, hash, hashlen) != 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 = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       kex_derive_keys(kex, hash, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
+#else /* OPENSSL_HAS_ECC */
+void
+kexecdh_client(Kex *kex)
+{
+       fatal("ECC support is not enabled");
+}
+#endif /* OPENSSL_HAS_ECC */
diff --git a/kexecdhs.c b/kexecdhs.c
new file mode 100644 (file)
index 0000000..8c515df
--- /dev/null
@@ -0,0 +1,173 @@
+/* $OpenBSD: kexecdhs.c,v 1.2 2010/09/22 05:01:29 djm Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2010 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 <sys/types.h>
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+#ifdef OPENSSL_HAS_ECC
+
+#include <openssl/ecdh.h>
+
+void
+kexecdh_server(Kex *kex)
+{
+       EC_POINT *client_public;
+       EC_KEY *server_key;
+       const EC_GROUP *group;
+       BIGNUM *shared_secret;
+       Key *server_host_private, *server_host_public;
+       u_char *server_host_key_blob = NULL, *signature = NULL;
+       u_char *kbuf, *hash;
+       u_int klen, slen, sbloblen, hashlen;
+       int curve_nid;
+
+       if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1)
+               fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name);
+       if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL)
+               fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
+       if (EC_KEY_generate_key(server_key) != 1)
+               fatal("%s: EC_KEY_generate_key failed", __func__);
+       group = EC_KEY_get0_group(server_key);
+
+#ifdef DEBUG_KEXECDH
+       fputs("server private key:\n", stderr);
+       key_dump_ec_key(server_key);
+#endif
+
+       if (kex->load_host_public_key == NULL ||
+           kex->load_host_private_key == NULL)
+               fatal("Cannot load hostkey");
+       server_host_public = kex->load_host_public_key(kex->hostkey_type);
+       if (server_host_public == NULL)
+               fatal("Unsupported hostkey type %d", kex->hostkey_type);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type);
+       if (server_host_private == NULL)
+               fatal("Missing private key for hostkey type %d",
+                   kex->hostkey_type);
+
+       debug("expecting SSH2_MSG_KEX_ECDH_INIT");
+       packet_read_expect(SSH2_MSG_KEX_ECDH_INIT);
+       if ((client_public = EC_POINT_new(group)) == NULL)
+               fatal("%s: EC_POINT_new failed", __func__);
+       packet_get_ecpoint(group, client_public);
+       packet_check_eom();
+
+       if (key_ec_validate_public(group, client_public) != 0)
+               fatal("%s: invalid client public key", __func__);
+
+#ifdef DEBUG_KEXECDH
+       fputs("client public key:\n", stderr);
+       key_dump_ec_point(group, client_public);
+#endif
+
+       /* Calculate shared_secret */
+       klen = (EC_GROUP_get_degree(group) + 7) / 8;
+       kbuf = xmalloc(klen);
+       if (ECDH_compute_key(kbuf, klen, client_public,
+           server_key, NULL) != (int)klen)
+               fatal("%s: ECDH_compute_key failed", __func__);
+
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, klen);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+       if (BN_bin2bn(kbuf, klen, shared_secret) == NULL)
+               fatal("%s: BN_bin2bn failed", __func__);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       /* calc H */
+       key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
+       kex_ecdh_hash(
+           kex->evp_md,
+           group,
+           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,
+           client_public,
+           EC_KEY_get0_public_key(server_key),
+           shared_secret,
+           &hash, &hashlen
+       );
+       EC_POINT_clear_free(client_public);
+
+       /* save session id := H */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       /* sign H */
+       if (PRIVSEP(key_sign(server_host_private, &signature, &slen,
+           hash, hashlen)) < 0)
+               fatal("kexdh_server: key_sign failed");
+
+       /* destroy_sensitive_data(); */
+
+       /* send server hostkey, ECDH pubkey 'Q_S' and signed H */
+       packet_start(SSH2_MSG_KEX_ECDH_REPLY);
+       packet_put_string(server_host_key_blob, sbloblen);
+       packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key));
+       packet_put_string(signature, slen);
+       packet_send();
+
+       xfree(signature);
+       xfree(server_host_key_blob);
+       /* have keys, free server key */
+       EC_KEY_free(server_key);
+
+       kex_derive_keys(kex, hash, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+       kex_finish(kex);
+}
+#else /* OPENSSL_HAS_ECC */
+void
+kexecdh_server(Kex *kex)
+{
+       fatal("ECC support is not enabled");
+}
+#endif /* OPENSSL_HAS_ECC */
diff --git a/kexgex.c b/kexgex.c
new file mode 100644 (file)
index 0000000..b60ab5c
--- /dev/null
+++ b/kexgex.c
@@ -0,0 +1,98 @@
+/* $OpenBSD: kexgex.c,v 1.27 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <openssl/evp.h>
+#include <signal.h>
+
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "ssh2.h"
+
+void
+kexgex_hash(
+    const EVP_MD *evp_md,
+    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,
+    u_char **hash, u_int *hashlen)
+{
+       Buffer b;
+       static u_char digest[EVP_MAX_MD_SIZE];
+       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);
+       *hash = digest;
+       *hashlen = EVP_MD_size(evp_md);
+#ifdef DEBUG_KEXDH
+       dump_digest("hash", digest, *hashlen);
+#endif
+}
diff --git a/kexgexc.c b/kexgexc.c
new file mode 100644 (file)
index 0000000..79552d7
--- /dev/null
+++ b/kexgexc.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: kexgexc.c,v 1.12 2010/11/10 01:33:07 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <openssl/dh.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "compat.h"
+
+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, slen, sbloblen, hashlen;
+       int kout;
+       int min, max, nbits;
+       DH *dh;
+
+       nbits = dh_estimate(kex->we_need * 8);
+
+       if (datafellows & SSH_OLD_DHGEX) {
+               /* Old GEX request */
+               packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
+               packet_put_int(nbits);
+               min = DH_GRP_MIN;
+               max = DH_GRP_MAX;
+
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits);
+       } else {
+               /* 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);
+
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
+                   min, nbits, 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(SSH2_MSG_KEX_DH_GEX_GROUP);
+
+       if ((p = BN_new()) == NULL)
+               fatal("BN_new");
+       packet_get_bignum2(p);
+       if ((g = BN_new()) == NULL)
+               fatal("BN_new");
+       packet_get_bignum2(g);
+       packet_check_eom();
+
+       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(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 (server_host_key->type != kex->hostkey_type)
+               fatal("type mismatch for decoded 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 parameter f, server public DH key */
+       if ((dh_server_pub = BN_new()) == NULL)
+               fatal("dh_server_pub == NULL");
+       packet_get_bignum2(dh_server_pub);
+
+#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_check_eom();
+
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
+
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0)
+               fatal("DH_compute_key: failed");
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("kexgex_client: BN_new failed");
+       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+               fatal("kexgex_client: BN_bin2bn failed");
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       if (datafellows & SSH_OLD_DHGEX)
+               min = max = -1;
+
+       /* calc and verify H */
+       kexgex_hash(
+           kex->evp_md,
+           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,
+           &hash, &hashlen
+       );
+
+       /* have keys, free DH */
+       DH_free(dh);
+       xfree(server_host_key_blob);
+       BN_clear_free(dh_server_pub);
+
+       if (key_verify(server_host_key, signature, slen, hash, hashlen) != 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 = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+       kex_derive_keys(kex, hash, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+
+       kex_finish(kex);
+}
diff --git a/kexgexs.c b/kexgexs.c
new file mode 100644 (file)
index 0000000..a5e3df7
--- /dev/null
+++ b/kexgexs.c
@@ -0,0 +1,213 @@
+/* $OpenBSD: kexgexs.c,v 1.14 2010/11/10 01:33:07 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <openssl/dh.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "compat.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+
+void
+kexgex_server(Kex *kex)
+{
+       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       Key *server_host_public, *server_host_private;
+       DH *dh;
+       u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+       u_int sbloblen, klen, slen, hashlen;
+       int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1;
+       int type, kout;
+
+       if (kex->load_host_public_key == NULL ||
+           kex->load_host_private_key == NULL)
+               fatal("Cannot load hostkey");
+       server_host_public = kex->load_host_public_key(kex->hostkey_type);
+       if (server_host_public == NULL)
+               fatal("Unsupported hostkey type %d", kex->hostkey_type);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type);
+       if (server_host_private == NULL)
+               fatal("Missing private key for hostkey type %d",
+                   kex->hostkey_type);
+
+
+       type = packet_read();
+       switch (type) {
+       case SSH2_MSG_KEX_DH_GEX_REQUEST:
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
+               omin = min = packet_get_int();
+               onbits = nbits = packet_get_int();
+               omax = max = packet_get_int();
+               min = MAX(DH_GRP_MIN, min);
+               max = MIN(DH_GRP_MAX, max);
+               nbits = MAX(DH_GRP_MIN, nbits);
+               nbits = MIN(DH_GRP_MAX, nbits);
+               break;
+       case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
+               debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
+               onbits = nbits = packet_get_int();
+               /* unused for old GEX */
+               omin = min = DH_GRP_MIN;
+               omax = max = DH_GRP_MAX;
+               break;
+       default:
+               fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
+       }
+       packet_check_eom();
+
+       if (omax < omin || onbits < omin || omax < onbits)
+               fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
+                   omin, onbits, omax);
+
+       /* Contact privileged parent */
+       dh = PRIVSEP(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(SSH2_MSG_KEX_DH_GEX_INIT);
+
+       /* key, cert */
+       if ((dh_client_pub = BN_new()) == NULL)
+               fatal("dh_client_pub == NULL");
+       packet_get_bignum2(dh_client_pub);
+       packet_check_eom();
+
+#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);
+       if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0)
+               fatal("DH_compute_key: failed");
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       if ((shared_secret = BN_new()) == NULL)
+               fatal("kexgex_server: BN_new failed");
+       if (BN_bin2bn(kbuf, kout, shared_secret) == NULL)
+               fatal("kexgex_server: BN_bin2bn failed");
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       key_to_blob(server_host_public, &server_host_key_blob, &sbloblen);
+
+       if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
+               omin = min = omax = max = -1;
+
+       /* calc H */
+       kexgex_hash(
+           kex->evp_md,
+           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,
+           omin, onbits, omax,
+           dh->p, dh->g,
+           dh_client_pub,
+           dh->pub_key,
+           shared_secret,
+           &hash, &hashlen
+       );
+       BN_clear_free(dh_client_pub);
+
+       /* save session id := H */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = hashlen;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       /* sign H */
+       if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash,
+           hashlen)) < 0)
+               fatal("kexgex_server: key_sign failed");
+
+       /* 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, hashlen, shared_secret);
+       BN_clear_free(shared_secret);
+
+       kex_finish(kex);
+}
diff --git a/key.c b/key.c
new file mode 100644 (file)
index 0000000..e3a305e
--- /dev/null
+++ b/key.c
@@ -0,0 +1,2270 @@
+/* $OpenBSD: key.c,v 1.96 2011/02/04 00:44:21 djm Exp $ */
+/*
+ * 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.
+ * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 <sys/param.h>
+#include <sys/types.h>
+
+#include <openssl/evp.h>
+#include <openbsd-compat/openssl-compat.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "rsa.h"
+#include "uuencode.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+#include "ssh2.h"
+
+static struct KeyCert *
+cert_new(void)
+{
+       struct KeyCert *cert;
+
+       cert = xcalloc(1, sizeof(*cert));
+       buffer_init(&cert->certblob);
+       buffer_init(&cert->critical);
+       buffer_init(&cert->extensions);
+       cert->key_id = NULL;
+       cert->principals = NULL;
+       cert->signature_key = NULL;
+       return cert;
+}
+
+Key *
+key_new(int type)
+{
+       Key *k;
+       RSA *rsa;
+       DSA *dsa;
+       k = xcalloc(1, sizeof(*k));
+       k->type = type;
+       k->ecdsa = NULL;
+       k->ecdsa_nid = -1;
+       k->dsa = NULL;
+       k->rsa = NULL;
+       k->cert = NULL;
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               if ((rsa = RSA_new()) == NULL)
+                       fatal("key_new: RSA_new failed");
+               if ((rsa->n = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               if ((rsa->e = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               k->rsa = rsa;
+               break;
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               if ((dsa = DSA_new()) == NULL)
+                       fatal("key_new: DSA_new failed");
+               if ((dsa->p = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               if ((dsa->q = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               if ((dsa->g = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               if ((dsa->pub_key = BN_new()) == NULL)
+                       fatal("key_new: BN_new failed");
+               k->dsa = dsa;
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               /* Cannot do anything until we know the group */
+               break;
+#endif
+       case KEY_UNSPEC:
+               break;
+       default:
+               fatal("key_new: bad key type %d", k->type);
+               break;
+       }
+
+       if (key_is_cert(k))
+               k->cert = cert_new();
+
+       return k;
+}
+
+void
+key_add_private(Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               if ((k->rsa->d = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               if ((k->rsa->iqmp = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               if ((k->rsa->q = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               if ((k->rsa->p = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               if ((k->rsa->dmq1 = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               if ((k->rsa->dmp1 = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               break;
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               if ((k->dsa->priv_key = BN_new()) == NULL)
+                       fatal("key_new_private: BN_new failed");
+               break;
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               /* Cannot do anything until we know the group */
+               break;
+       case KEY_UNSPEC:
+               break;
+       default:
+               break;
+       }
+}
+
+Key *
+key_new_private(int type)
+{
+       Key *k = key_new(type);
+
+       key_add_private(k);
+       return k;
+}
+
+static void
+cert_free(struct KeyCert *cert)
+{
+       u_int i;
+
+       buffer_free(&cert->certblob);
+       buffer_free(&cert->critical);
+       buffer_free(&cert->extensions);
+       if (cert->key_id != NULL)
+               xfree(cert->key_id);
+       for (i = 0; i < cert->nprincipals; i++)
+               xfree(cert->principals[i]);
+       if (cert->principals != NULL)
+               xfree(cert->principals);
+       if (cert->signature_key != NULL)
+               key_free(cert->signature_key);
+}
+
+void
+key_free(Key *k)
+{
+       if (k == NULL)
+               fatal("key_free: key is NULL");
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               if (k->rsa != NULL)
+                       RSA_free(k->rsa);
+               k->rsa = NULL;
+               break;
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               if (k->dsa != NULL)
+                       DSA_free(k->dsa);
+               k->dsa = NULL;
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               if (k->ecdsa != NULL)
+                       EC_KEY_free(k->ecdsa);
+               k->ecdsa = NULL;
+               break;
+#endif
+       case KEY_UNSPEC:
+               break;
+       default:
+               fatal("key_free: bad key type %d", k->type);
+               break;
+       }
+       if (key_is_cert(k)) {
+               if (k->cert != NULL)
+                       cert_free(k->cert);
+               k->cert = NULL;
+       }
+
+       xfree(k);
+}
+
+static int
+cert_compare(struct KeyCert *a, struct KeyCert *b)
+{
+       if (a == NULL && b == NULL)
+               return 1;
+       if (a == NULL || b == NULL)
+               return 0;
+       if (buffer_len(&a->certblob) != buffer_len(&b->certblob))
+               return 0;
+       if (timingsafe_bcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob),
+           buffer_len(&a->certblob)) != 0)
+               return 0;
+       return 1;
+}
+
+/*
+ * Compare public portions of key only, allowing comparisons between
+ * certificates and plain keys too.
+ */
+int
+key_equal_public(const Key *a, const Key *b)
+{
+#ifdef OPENSSL_HAS_ECC
+       BN_CTX *bnctx;
+#endif
+
+       if (a == NULL || b == NULL ||
+           key_type_plain(a->type) != key_type_plain(b->type))
+               return 0;
+
+       switch (a->type) {
+       case KEY_RSA1:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+       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;
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+       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;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+       case KEY_ECDSA:
+               if (a->ecdsa == NULL || b->ecdsa == NULL ||
+                   EC_KEY_get0_public_key(a->ecdsa) == NULL ||
+                   EC_KEY_get0_public_key(b->ecdsa) == NULL)
+                       return 0;
+               if ((bnctx = BN_CTX_new()) == NULL)
+                       fatal("%s: BN_CTX_new failed", __func__);
+               if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
+                   EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
+                   EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
+                   EC_KEY_get0_public_key(a->ecdsa),
+                   EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
+                       BN_CTX_free(bnctx);
+                       return 0;
+               }
+               BN_CTX_free(bnctx);
+               return 1;
+#endif /* OPENSSL_HAS_ECC */
+       default:
+               fatal("key_equal: bad key type %d", a->type);
+       }
+       /* NOTREACHED */
+}
+
+int
+key_equal(const Key *a, const Key *b)
+{
+       if (a == NULL || b == NULL || a->type != b->type)
+               return 0;
+       if (key_is_cert(a)) {
+               if (!cert_compare(a->cert, b->cert))
+                       return 0;
+       }
+       return key_equal_public(a, b);
+}
+
+u_char*
+key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
+{
+       const EVP_MD *md = NULL;
+       EVP_MD_CTX ctx;
+       u_char *blob = NULL;
+       u_char *retval = NULL;
+       u_int len = 0;
+       int nlen, elen, otype;
+
+       *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_ECDSA:
+       case KEY_RSA:
+               key_to_blob(k, &blob, &len);
+               break;
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA_CERT:
+       case KEY_ECDSA_CERT:
+       case KEY_RSA_CERT:
+               /* We want a fingerprint of the _key_ not of the cert */
+               otype = k->type;
+               k->type = key_type_plain(k->type);
+               key_to_blob(k, &blob, &len);
+               k->type = otype;
+               break;
+       case KEY_UNSPEC:
+               return retval;
+       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, dgst_raw_length);
+               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, u_int dgst_raw_len)
+{
+       char *retval;
+       u_int i;
+
+       retval = xcalloc(1, dgst_raw_len * 3 + 1);
+       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 + 1);
+       }
+
+       /* Remove the trailing ':' character */
+       retval[(dgst_raw_len * 3) - 1] = '\0';
+       return retval;
+}
+
+static char *
+key_fingerprint_bubblebabble(u_char *dgst_raw, u_int 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 = xcalloc((rounds * 6), sizeof(char));
+       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;
+}
+
+/*
+ * Draw an ASCII-Art representing the fingerprint so human brain can
+ * profit from its built-in pattern recognition ability.
+ * This technique is called "random art" and can be found in some
+ * scientific publications like this original paper:
+ *
+ * "Hash Visualization: a New Technique to improve Real-World Security",
+ * Perrig A. and Song D., 1999, International Workshop on Cryptographic
+ * Techniques and E-Commerce (CrypTEC '99)
+ * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+ *
+ * The subject came up in a talk by Dan Kaminsky, too.
+ *
+ * If you see the picture is different, the key is different.
+ * If the picture looks the same, you still know nothing.
+ *
+ * The algorithm used here is a worm crawling over a discrete plane,
+ * leaving a trace (augmenting the field) everywhere it goes.
+ * Movement is taken from dgst_raw 2bit-wise.  Bumping into walls
+ * makes the respective movement vector be ignored for this turn.
+ * Graphs are not unambiguous, because circles in graphs can be
+ * walked in either direction.
+ */
+
+/*
+ * Field sizes for the random art.  Have to be odd, so the starting point
+ * can be in the exact middle of the picture, and FLDBASE should be >=8 .
+ * Else pictures would be too dense, and drawing the frame would
+ * fail, too, because the key type would not fit in anymore.
+ */
+#define        FLDBASE         8
+#define        FLDSIZE_Y       (FLDBASE + 1)
+#define        FLDSIZE_X       (FLDBASE * 2 + 1)
+static char *
+key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k)
+{
+       /*
+        * Chars to be used after each other every time the worm
+        * intersects with itself.  Matter of taste.
+        */
+       char    *augmentation_string = " .o+=*BOX@%&#/^SE";
+       char    *retval, *p;
+       u_char   field[FLDSIZE_X][FLDSIZE_Y];
+       u_int    i, b;
+       int      x, y;
+       size_t   len = strlen(augmentation_string) - 1;
+
+       retval = xcalloc(1, (FLDSIZE_X + 3) * (FLDSIZE_Y + 2));
+
+       /* initialize field */
+       memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
+       x = FLDSIZE_X / 2;
+       y = FLDSIZE_Y / 2;
+
+       /* process raw key */
+       for (i = 0; i < dgst_raw_len; i++) {
+               int input;
+               /* each byte conveys four 2-bit move commands */
+               input = dgst_raw[i];
+               for (b = 0; b < 4; b++) {
+                       /* evaluate 2 bit, rest is shifted later */
+                       x += (input & 0x1) ? 1 : -1;
+                       y += (input & 0x2) ? 1 : -1;
+
+                       /* assure we are still in bounds */
+                       x = MAX(x, 0);
+                       y = MAX(y, 0);
+                       x = MIN(x, FLDSIZE_X - 1);
+                       y = MIN(y, FLDSIZE_Y - 1);
+
+                       /* augment the field */
+                       if (field[x][y] < len - 2)
+                               field[x][y]++;
+                       input = input >> 2;
+               }
+       }
+
+       /* mark starting point and end point*/
+       field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
+       field[x][y] = len;
+
+       /* fill in retval */
+       snprintf(retval, FLDSIZE_X, "+--[%4s %4u]", key_type(k), key_size(k));
+       p = strchr(retval, '\0');
+
+       /* output upper border */
+       for (i = p - retval - 1; i < FLDSIZE_X; i++)
+               *p++ = '-';
+       *p++ = '+';
+       *p++ = '\n';
+
+       /* output content */
+       for (y = 0; y < FLDSIZE_Y; y++) {
+               *p++ = '|';
+               for (x = 0; x < FLDSIZE_X; x++)
+                       *p++ = augmentation_string[MIN(field[x][y], len)];
+               *p++ = '|';
+               *p++ = '\n';
+       }
+
+       /* output lower border */
+       *p++ = '+';
+       for (i = 0; i < FLDSIZE_X; i++)
+               *p++ = '-';
+       *p++ = '+';
+
+       return retval;
+}
+
+char *
+key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep)
+{
+       char *retval = NULL;
+       u_char *dgst_raw;
+       u_int 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;
+       case SSH_FP_RANDOMART:
+               retval = key_fingerprint_randomart(dgst_raw, dgst_raw_len, k);
+               break;
+       default:
+               fatal("key_fingerprint: 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;
+#ifdef OPENSSL_HAS_ECC
+       int curve_nid = -1;
+#endif
+
+       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;
+               /* validate the claimed number of bits */
+               if ((u_int)BN_num_bits(ret->rsa->n) != bits) {
+                       verbose("key_read: claimed key size %d does not match "
+                          "actual %d", bits, BN_num_bits(ret->rsa->n));
+                       return -1;
+               }
+               success = 1;
+               break;
+       case KEY_UNSPEC:
+       case KEY_RSA:
+       case KEY_DSA:
+       case KEY_ECDSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA_CERT:
+       case KEY_ECDSA_CERT:
+       case KEY_RSA_CERT:
+               space = strchr(cp, ' ');
+               if (space == NULL) {
+                       debug3("key_read: missing whitespace");
+                       return -1;
+               }
+               *space = '\0';
+               type = key_type_from_name(cp);
+#ifdef OPENSSL_HAS_ECC
+               if (key_type_plain(type) == KEY_ECDSA &&
+                   (curve_nid = key_ecdsa_nid_from_name(cp)) == -1) {
+                       debug("key_read: invalid curve");
+                       return -1;
+               }
+#endif
+               *space = ' ';
+               if (type == KEY_UNSPEC) {
+                       debug3("key_read: missing keytype");
+                       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);
+                       xfree(blob);
+                       return -1;
+               }
+               k = key_from_blob(blob, (u_int)n);
+               xfree(blob);
+               if (k == NULL) {
+                       error("key_read: key_from_blob %s failed", cp);
+                       return -1;
+               }
+               if (k->type != type) {
+                       error("key_read: type mismatch: encoding error");
+                       key_free(k);
+                       return -1;
+               }
+#ifdef OPENSSL_HAS_ECC
+               if (key_type_plain(type) == KEY_ECDSA &&
+                   curve_nid != k->ecdsa_nid) {
+                       error("key_read: type mismatch: EC curve mismatch");
+                       key_free(k);
+                       return -1;
+               }
+#endif
+/*XXXX*/
+               if (key_is_cert(ret)) {
+                       if (!key_is_cert(k)) {
+                               error("key_read: loaded key is not a cert");
+                               key_free(k);
+                               return -1;
+                       }
+                       if (ret->cert != NULL)
+                               cert_free(ret->cert);
+                       ret->cert = k->cert;
+                       k->cert = NULL;
+               }
+               if (key_type_plain(ret->type) == KEY_RSA) {
+                       if (ret->rsa != NULL)
+                               RSA_free(ret->rsa);
+                       ret->rsa = k->rsa;
+                       k->rsa = NULL;
+#ifdef DEBUG_PK
+                       RSA_print_fp(stderr, ret->rsa, 8);
+#endif
+               }
+               if (key_type_plain(ret->type) == KEY_DSA) {
+                       if (ret->dsa != NULL)
+                               DSA_free(ret->dsa);
+                       ret->dsa = k->dsa;
+                       k->dsa = NULL;
+#ifdef DEBUG_PK
+                       DSA_print_fp(stderr, ret->dsa, 8);
+#endif
+               }
+#ifdef OPENSSL_HAS_ECC
+               if (key_type_plain(ret->type) == KEY_ECDSA) {
+                       if (ret->ecdsa != NULL)
+                               EC_KEY_free(ret->ecdsa);
+                       ret->ecdsa = k->ecdsa;
+                       ret->ecdsa_nid = k->ecdsa_nid;
+                       k->ecdsa = NULL;
+                       k->ecdsa_nid = -1;
+#ifdef DEBUG_PK
+                       key_dump_ec_key(ret->ecdsa);
+#endif
+               }
+#endif
+               success = 1;
+/*XXXX*/
+               key_free(k);
+               if (success != 1)
+                       break;
+               /* 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(const Key *key, FILE *f)
+{
+       int n, success = 0;
+       u_int len, bits = 0;
+       u_char *blob;
+       char *uu;
+
+       if (key_is_cert(key)) {
+               if (key->cert == NULL) {
+                       error("%s: no cert data", __func__);
+                       return 0;
+               }
+               if (buffer_len(&key->cert->certblob) == 0) {
+                       error("%s: no signed certificate blob", __func__);
+                       return 0;
+               }
+       }
+
+       switch (key->type) {
+       case KEY_RSA1:
+               if (key->rsa == NULL)
+                       return 0;
+               /* 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))
+                       return 1;
+               error("key_write: failed for RSA key");
+               return 0;
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               if (key->dsa == NULL)
+                       return 0;
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               if (key->ecdsa == NULL)
+                       return 0;
+               break;
+#endif
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               if (key->rsa == NULL)
+                       return 0;
+               break;
+       default:
+               return 0;
+       }
+
+       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;
+}
+
+const char *
+key_type(const Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA1:
+               return "RSA1";
+       case KEY_RSA:
+               return "RSA";
+       case KEY_DSA:
+               return "DSA";
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               return "ECDSA";
+#endif
+       case KEY_RSA_CERT_V00:
+               return "RSA-CERT-V00";
+       case KEY_DSA_CERT_V00:
+               return "DSA-CERT-V00";
+       case KEY_RSA_CERT:
+               return "RSA-CERT";
+       case KEY_DSA_CERT:
+               return "DSA-CERT";
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+               return "ECDSA-CERT";
+#endif
+       }
+       return "unknown";
+}
+
+const char *
+key_cert_type(const Key *k)
+{
+       switch (k->cert->type) {
+       case SSH2_CERT_TYPE_USER:
+               return "user";
+       case SSH2_CERT_TYPE_HOST:
+               return "host";
+       default:
+               return "unknown";
+       }
+}
+
+static const char *
+key_ssh_name_from_type_nid(int type, int nid)
+{
+       switch (type) {
+       case KEY_RSA:
+               return "ssh-rsa";
+       case KEY_DSA:
+               return "ssh-dss";
+       case KEY_RSA_CERT_V00:
+               return "ssh-rsa-cert-v00@openssh.com";
+       case KEY_DSA_CERT_V00:
+               return "ssh-dss-cert-v00@openssh.com";
+       case KEY_RSA_CERT:
+               return "ssh-rsa-cert-v01@openssh.com";
+       case KEY_DSA_CERT:
+               return "ssh-dss-cert-v01@openssh.com";
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               switch (nid) {
+               case NID_X9_62_prime256v1:
+                       return "ecdsa-sha2-nistp256";
+               case NID_secp384r1:
+                       return "ecdsa-sha2-nistp384";
+               case NID_secp521r1:
+                       return "ecdsa-sha2-nistp521";
+               default:
+                       break;
+               }
+               break;
+       case KEY_ECDSA_CERT:
+               switch (nid) {
+               case NID_X9_62_prime256v1:
+                       return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
+               case NID_secp384r1:
+                       return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
+               case NID_secp521r1:
+                       return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
+               default:
+                       break;
+               }
+               break;
+#endif /* OPENSSL_HAS_ECC */
+       }
+       return "ssh-unknown";
+}
+
+const char *
+key_ssh_name(const Key *k)
+{
+       return key_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
+}
+
+const char *
+key_ssh_name_plain(const Key *k)
+{
+       return key_ssh_name_from_type_nid(key_type_plain(k->type),
+           k->ecdsa_nid);
+}
+
+u_int
+key_size(const Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA1:
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               return BN_num_bits(k->rsa->n);
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               return BN_num_bits(k->dsa->p);
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               return key_curve_nid_to_bits(k->ecdsa_nid);
+#endif
+       }
+       return 0;
+}
+
+static RSA *
+rsa_generate_private_key(u_int bits)
+{
+       RSA *private = RSA_new();
+       BIGNUM *f4 = BN_new();
+
+       if (private == NULL)
+               fatal("%s: RSA_new failed", __func__);
+       if (f4 == NULL)
+               fatal("%s: BN_new failed", __func__);
+       if (!BN_set_word(f4, RSA_F4))
+               fatal("%s: BN_new failed", __func__);
+       if (!RSA_generate_key_ex(private, bits, f4, NULL))
+               fatal("%s: key generation failed.", __func__);
+       BN_free(f4);
+       return private;
+}
+
+static DSA*
+dsa_generate_private_key(u_int bits)
+{
+       DSA *private = DSA_new();
+
+       if (private == NULL)
+               fatal("%s: DSA_new failed", __func__);
+       if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
+           NULL, NULL))
+               fatal("%s: DSA_generate_parameters failed", __func__);
+       if (!DSA_generate_key(private))
+               fatal("%s: DSA_generate_key failed.", __func__);
+       return private;
+}
+
+int
+key_ecdsa_bits_to_nid(int bits)
+{
+       switch (bits) {
+#ifdef OPENSSL_HAS_ECC
+       case 256:
+               return NID_X9_62_prime256v1;
+       case 384:
+               return NID_secp384r1;
+       case 521:
+               return NID_secp521r1;
+#endif
+       default:
+               return -1;
+       }
+}
+
+#ifdef OPENSSL_HAS_ECC
+int
+key_ecdsa_key_to_nid(EC_KEY *k)
+{
+       EC_GROUP *eg;
+       int nids[] = {
+               NID_X9_62_prime256v1,
+               NID_secp384r1,
+               NID_secp521r1,
+               -1
+       };
+       int nid;
+       u_int i;
+       BN_CTX *bnctx;
+       const EC_GROUP *g = EC_KEY_get0_group(k);
+
+       /*
+        * The group may be stored in a ASN.1 encoded private key in one of two
+        * ways: as a "named group", which is reconstituted by ASN.1 object ID
+        * or explicit group parameters encoded into the key blob. Only the
+        * "named group" case sets the group NID for us, but we can figure
+        * it out for the other case by comparing against all the groups that
+        * are supported.
+        */
+       if ((nid = EC_GROUP_get_curve_name(g)) > 0)
+               return nid;
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new() failed", __func__);
+       for (i = 0; nids[i] != -1; i++) {
+               if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
+                       fatal("%s: EC_GROUP_new_by_curve_name failed",
+                           __func__);
+               if (EC_GROUP_cmp(g, eg, bnctx) == 0)
+                       break;
+               EC_GROUP_free(eg);
+       }
+       BN_CTX_free(bnctx);
+       debug3("%s: nid = %d", __func__, nids[i]);
+       if (nids[i] != -1) {
+               /* Use the group with the NID attached */
+               EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
+               if (EC_KEY_set_group(k, eg) != 1)
+                       fatal("%s: EC_KEY_set_group", __func__);
+       }
+       return nids[i];
+}
+
+static EC_KEY*
+ecdsa_generate_private_key(u_int bits, int *nid)
+{
+       EC_KEY *private;
+
+       if ((*nid = key_ecdsa_bits_to_nid(bits)) == -1)
+               fatal("%s: invalid key length", __func__);
+       if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL)
+               fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
+       if (EC_KEY_generate_key(private) != 1)
+               fatal("%s: EC_KEY_generate_key failed", __func__);
+       EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
+       return private;
+}
+#endif /* OPENSSL_HAS_ECC */
+
+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;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               k->ecdsa = ecdsa_generate_private_key(bits, &k->ecdsa_nid);
+               break;
+#endif
+       case KEY_RSA:
+       case KEY_RSA1:
+               k->rsa = rsa_generate_private_key(bits);
+               break;
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT:
+       case KEY_DSA_CERT:
+               fatal("key_generate: cert keys cannot be generated directly");
+       default:
+               fatal("key_generate: unknown type %d", type);
+       }
+       k->type = type;
+       return k;
+}
+
+void
+key_cert_copy(const Key *from_key, struct Key *to_key)
+{
+       u_int i;
+       const struct KeyCert *from;
+       struct KeyCert *to;
+
+       if (to_key->cert != NULL) {
+               cert_free(to_key->cert);
+               to_key->cert = NULL;
+       }
+
+       if ((from = from_key->cert) == NULL)
+               return;
+
+       to = to_key->cert = cert_new();
+
+       buffer_append(&to->certblob, buffer_ptr(&from->certblob),
+           buffer_len(&from->certblob));
+
+       buffer_append(&to->critical,
+           buffer_ptr(&from->critical), buffer_len(&from->critical));
+       buffer_append(&to->extensions,
+           buffer_ptr(&from->extensions), buffer_len(&from->extensions));
+
+       to->serial = from->serial;
+       to->type = from->type;
+       to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id);
+       to->valid_after = from->valid_after;
+       to->valid_before = from->valid_before;
+       to->signature_key = from->signature_key == NULL ?
+           NULL : key_from_private(from->signature_key);
+
+       to->nprincipals = from->nprincipals;
+       if (to->nprincipals > CERT_MAX_PRINCIPALS)
+               fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)",
+                   __func__, to->nprincipals, CERT_MAX_PRINCIPALS);
+       if (to->nprincipals > 0) {
+               to->principals = xcalloc(from->nprincipals,
+                   sizeof(*to->principals));
+               for (i = 0; i < to->nprincipals; i++)
+                       to->principals[i] = xstrdup(from->principals[i]);
+       }
+}
+
+Key *
+key_from_private(const Key *k)
+{
+       Key *n = NULL;
+       switch (k->type) {
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               n = key_new(k->type);
+               if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
+                   (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
+                   (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
+                   (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL))
+                       fatal("key_from_private: BN_copy failed");
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+       case KEY_ECDSA_CERT:
+               n = key_new(k->type);
+               n->ecdsa_nid = k->ecdsa_nid;
+               if ((n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL)
+                       fatal("%s: EC_KEY_new_by_curve_name failed", __func__);
+               if (EC_KEY_set_public_key(n->ecdsa,
+                   EC_KEY_get0_public_key(k->ecdsa)) != 1)
+                       fatal("%s: EC_KEY_set_public_key failed", __func__);
+               break;
+#endif
+       case KEY_RSA:
+       case KEY_RSA1:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               n = key_new(k->type);
+               if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
+                   (BN_copy(n->rsa->e, k->rsa->e) == NULL))
+                       fatal("key_from_private: BN_copy failed");
+               break;
+       default:
+               fatal("key_from_private: unknown type %d", k->type);
+               break;
+       }
+       if (key_is_cert(k))
+               key_cert_copy(k, n);
+       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;
+#ifdef OPENSSL_HAS_ECC
+       } else if (strcmp(name, "ecdsa") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp521") == 0) {
+               return KEY_ECDSA;
+#endif
+       } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) {
+               return KEY_RSA_CERT_V00;
+       } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) {
+               return KEY_DSA_CERT_V00;
+       } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
+               return KEY_RSA_CERT;
+       } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) {
+               return KEY_DSA_CERT;
+#ifdef OPENSSL_HAS_ECC
+       } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
+               return KEY_ECDSA_CERT;
+#endif
+       }
+
+       debug2("key_type_from_name: unknown key type '%s'", name);
+       return KEY_UNSPEC;
+}
+
+int
+key_ecdsa_nid_from_name(const char *name)
+{
+#ifdef OPENSSL_HAS_ECC
+       if (strcmp(name, "ecdsa-sha2-nistp256") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0)
+               return NID_X9_62_prime256v1;
+       if (strcmp(name, "ecdsa-sha2-nistp384") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0)
+               return NID_secp384r1;
+       if (strcmp(name, "ecdsa-sha2-nistp521") == 0 ||
+           strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0)
+               return NID_secp521r1;
+#endif /* OPENSSL_HAS_ECC */
+
+       debug2("%s: unknown/non-ECDSA key type '%s'", __func__, name);
+       return -1;
+}
+
+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;
+}
+
+static int
+cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen)
+{
+       u_char *principals, *critical, *exts, *sig_key, *sig;
+       u_int signed_len, plen, clen, sklen, slen, kidlen, elen;
+       Buffer tmp;
+       char *principal;
+       int ret = -1;
+       int v00 = key->type == KEY_DSA_CERT_V00 ||
+           key->type == KEY_RSA_CERT_V00;
+
+       buffer_init(&tmp);
+
+       /* Copy the entire key blob for verification and later serialisation */
+       buffer_append(&key->cert->certblob, blob, blen);
+
+       elen = 0; /* Not touched for v00 certs */
+       principals = exts = critical = sig_key = sig = NULL;
+       if ((!v00 && buffer_get_int64_ret(&key->cert->serial, b) != 0) ||
+           buffer_get_int_ret(&key->cert->type, b) != 0 ||
+           (key->cert->key_id = buffer_get_cstring_ret(b, &kidlen)) == NULL ||
+           (principals = buffer_get_string_ret(b, &plen)) == NULL ||
+           buffer_get_int64_ret(&key->cert->valid_after, b) != 0 ||
+           buffer_get_int64_ret(&key->cert->valid_before, b) != 0 ||
+           (critical = buffer_get_string_ret(b, &clen)) == NULL ||
+           (!v00 && (exts = buffer_get_string_ret(b, &elen)) == NULL) ||
+           (v00 && buffer_get_string_ptr_ret(b, NULL) == NULL) || /* nonce */
+           buffer_get_string_ptr_ret(b, NULL) == NULL || /* reserved */
+           (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) {
+               error("%s: parse error", __func__);
+               goto out;
+       }
+
+       if (kidlen != strlen(key->cert->key_id)) {
+               error("%s: key ID contains \\0 character", __func__);
+               goto out;
+       }
+
+       /* Signature is left in the buffer so we can calculate this length */
+       signed_len = buffer_len(&key->cert->certblob) - buffer_len(b);
+
+       if ((sig = buffer_get_string_ret(b, &slen)) == NULL) {
+               error("%s: parse error", __func__);
+               goto out;
+       }
+
+       if (key->cert->type != SSH2_CERT_TYPE_USER &&
+           key->cert->type != SSH2_CERT_TYPE_HOST) {
+               error("Unknown certificate type %u", key->cert->type);
+               goto out;
+       }
+
+       buffer_append(&tmp, principals, plen);
+       while (buffer_len(&tmp) > 0) {
+               if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) {
+                       error("%s: Too many principals", __func__);
+                       goto out;
+               }
+               if ((principal = buffer_get_cstring_ret(&tmp, &plen)) == NULL) {
+                       error("%s: Principals data invalid", __func__);
+                       goto out;
+               }
+               key->cert->principals = xrealloc(key->cert->principals,
+                   key->cert->nprincipals + 1, sizeof(*key->cert->principals));
+               key->cert->principals[key->cert->nprincipals++] = principal;
+       }
+
+       buffer_clear(&tmp);
+
+       buffer_append(&key->cert->critical, critical, clen);
+       buffer_append(&tmp, critical, clen);
+       /* validate structure */
+       while (buffer_len(&tmp) != 0) {
+               if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
+                   buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
+                       error("%s: critical option data invalid", __func__);
+                       goto out;
+               }
+       }
+       buffer_clear(&tmp);
+
+       buffer_append(&key->cert->extensions, exts, elen);
+       buffer_append(&tmp, exts, elen);
+       /* validate structure */
+       while (buffer_len(&tmp) != 0) {
+               if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL ||
+                   buffer_get_string_ptr_ret(&tmp, NULL) == NULL) {
+                       error("%s: extension data invalid", __func__);
+                       goto out;
+               }
+       }
+       buffer_clear(&tmp);
+
+       if ((key->cert->signature_key = key_from_blob(sig_key,
+           sklen)) == NULL) {
+               error("%s: Signature key invalid", __func__);
+               goto out;
+       }
+       if (key->cert->signature_key->type != KEY_RSA &&
+           key->cert->signature_key->type != KEY_DSA &&
+           key->cert->signature_key->type != KEY_ECDSA) {
+               error("%s: Invalid signature key type %s (%d)", __func__,
+                   key_type(key->cert->signature_key),
+                   key->cert->signature_key->type);
+               goto out;
+       }
+
+       switch (key_verify(key->cert->signature_key, sig, slen, 
+           buffer_ptr(&key->cert->certblob), signed_len)) {
+       case 1:
+               ret = 0;
+               break; /* Good signature */
+       case 0:
+               error("%s: Invalid signature on certificate", __func__);
+               goto out;
+       case -1:
+               error("%s: Certificate signature verification failed",
+                   __func__);
+               goto out;
+       }
+
+ out:
+       buffer_free(&tmp);
+       if (principals != NULL)
+               xfree(principals);
+       if (critical != NULL)
+               xfree(critical);
+       if (exts != NULL)
+               xfree(exts);
+       if (sig_key != NULL)
+               xfree(sig_key);
+       if (sig != NULL)
+               xfree(sig);
+       return ret;
+}
+
+Key *
+key_from_blob(const u_char *blob, u_int blen)
+{
+       Buffer b;
+       int rlen, type;
+       char *ktype = NULL, *curve = NULL;
+       Key *key = NULL;
+#ifdef OPENSSL_HAS_ECC
+       EC_POINT *q = NULL;
+       int nid = -1;
+#endif
+
+#ifdef DEBUG_PK
+       dump_base64(stderr, blob, blen);
+#endif
+       buffer_init(&b);
+       buffer_append(&b, blob, blen);
+       if ((ktype = buffer_get_cstring_ret(&b, NULL)) == NULL) {
+               error("key_from_blob: can't read key type");
+               goto out;
+       }
+
+       type = key_type_from_name(ktype);
+#ifdef OPENSSL_HAS_ECC
+       if (key_type_plain(type) == KEY_ECDSA)
+               nid = key_ecdsa_nid_from_name(ktype);
+#endif
+
+       switch (type) {
+       case KEY_RSA_CERT:
+               (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
+               /* FALLTHROUGH */
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+               key = key_new(type);
+               if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 ||
+                   buffer_get_bignum2_ret(&b, key->rsa->n) == -1) {
+                       error("key_from_blob: can't read rsa key");
+ badkey:
+                       key_free(key);
+                       key = NULL;
+                       goto out;
+               }
+#ifdef DEBUG_PK
+               RSA_print_fp(stderr, key->rsa, 8);
+#endif
+               break;
+       case KEY_DSA_CERT:
+               (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
+               /* FALLTHROUGH */
+       case KEY_DSA:
+       case KEY_DSA_CERT_V00:
+               key = key_new(type);
+               if (buffer_get_bignum2_ret(&b, key->dsa->p) == -1 ||
+                   buffer_get_bignum2_ret(&b, key->dsa->q) == -1 ||
+                   buffer_get_bignum2_ret(&b, key->dsa->g) == -1 ||
+                   buffer_get_bignum2_ret(&b, key->dsa->pub_key) == -1) {
+                       error("key_from_blob: can't read dsa key");
+                       goto badkey;
+               }
+#ifdef DEBUG_PK
+               DSA_print_fp(stderr, key->dsa, 8);
+#endif
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+               (void)buffer_get_string_ptr_ret(&b, NULL); /* Skip nonce */
+               /* FALLTHROUGH */
+       case KEY_ECDSA:
+               key = key_new(type);
+               key->ecdsa_nid = nid;
+               if ((curve = buffer_get_string_ret(&b, NULL)) == NULL) {
+                       error("key_from_blob: can't read ecdsa curve");
+                       goto badkey;
+               }
+               if (key->ecdsa_nid != key_curve_name_to_nid(curve)) {
+                       error("key_from_blob: ecdsa curve doesn't match type");
+                       goto badkey;
+               }
+               if (key->ecdsa != NULL)
+                       EC_KEY_free(key->ecdsa);
+               if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
+                   == NULL)
+                       fatal("key_from_blob: EC_KEY_new_by_curve_name failed");
+               if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL)
+                       fatal("key_from_blob: EC_POINT_new failed");
+               if (buffer_get_ecpoint_ret(&b, EC_KEY_get0_group(key->ecdsa),
+                   q) == -1) {
+                       error("key_from_blob: can't read ecdsa key point");
+                       goto badkey;
+               }
+               if (key_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
+                   q) != 0)
+                       goto badkey;
+               if (EC_KEY_set_public_key(key->ecdsa, q) != 1)
+                       fatal("key_from_blob: EC_KEY_set_public_key failed");
+#ifdef DEBUG_PK
+               key_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
+#endif
+               break;
+#endif /* OPENSSL_HAS_ECC */
+       case KEY_UNSPEC:
+               key = key_new(type);
+               break;
+       default:
+               error("key_from_blob: cannot handle type %s", ktype);
+               goto out;
+       }
+       if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) {
+               error("key_from_blob: can't parse cert data");
+               goto badkey;
+       }
+       rlen = buffer_len(&b);
+       if (key != NULL && rlen != 0)
+               error("key_from_blob: remaining bytes in key blob %d", rlen);
+ out:
+       if (ktype != NULL)
+               xfree(ktype);
+       if (curve != NULL)
+               xfree(curve);
+#ifdef OPENSSL_HAS_ECC
+       if (q != NULL)
+               EC_POINT_free(q);
+#endif
+       buffer_free(&b);
+       return key;
+}
+
+int
+key_to_blob(const Key *key, u_char **blobp, u_int *lenp)
+{
+       Buffer b;
+       int len;
+
+       if (key == NULL) {
+               error("key_to_blob: key == NULL");
+               return 0;
+       }
+       buffer_init(&b);
+       switch (key->type) {
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA_CERT:
+       case KEY_ECDSA_CERT:
+       case KEY_RSA_CERT:
+               /* Use the existing blob */
+               buffer_append(&b, buffer_ptr(&key->cert->certblob),
+                   buffer_len(&key->cert->certblob));
+               break;
+       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;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               buffer_put_cstring(&b, key_ssh_name(key));
+               buffer_put_cstring(&b, key_curve_nid_to_name(key->ecdsa_nid));
+               buffer_put_ecpoint(&b, EC_KEY_get0_group(key->ecdsa),
+                   EC_KEY_get0_public_key(key->ecdsa));
+               break;
+#endif
+       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);
+       if (lenp != NULL)
+               *lenp = len;
+       if (blobp != NULL) {
+               *blobp = xmalloc(len);
+               memcpy(*blobp, buffer_ptr(&b), len);
+       }
+       memset(buffer_ptr(&b), 0, len);
+       buffer_free(&b);
+       return len;
+}
+
+int
+key_sign(
+    const Key *key,
+    u_char **sigp, u_int *lenp,
+    const u_char *data, u_int datalen)
+{
+       switch (key->type) {
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+       case KEY_DSA:
+               return ssh_dss_sign(key, sigp, lenp, data, datalen);
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+       case KEY_ECDSA:
+               return ssh_ecdsa_sign(key, sigp, lenp, data, datalen);
+#endif
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+       case KEY_RSA:
+               return ssh_rsa_sign(key, sigp, lenp, data, datalen);
+       default:
+               error("key_sign: invalid key type %d", key->type);
+               return -1;
+       }
+}
+
+/*
+ * key_verify returns 1 for a correct signature, 0 for an incorrect signature
+ * and -1 on error.
+ */
+int
+key_verify(
+    const Key *key,
+    const u_char *signature, u_int signaturelen,
+    const u_char *data, u_int datalen)
+{
+       if (signaturelen == 0)
+               return -1;
+
+       switch (key->type) {
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+       case KEY_DSA:
+               return ssh_dss_verify(key, signature, signaturelen, data, datalen);
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+       case KEY_ECDSA:
+               return ssh_ecdsa_verify(key, signature, signaturelen, data, datalen);
+#endif
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+       case KEY_RSA:
+               return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
+       default:
+               error("key_verify: invalid key type %d", key->type);
+               return -1;
+       }
+}
+
+/* Converts a private to a public key */
+Key *
+key_demote(const Key *k)
+{
+       Key *pk;
+
+       pk = xcalloc(1, sizeof(*pk));
+       pk->type = k->type;
+       pk->flags = k->flags;
+       pk->ecdsa_nid = k->ecdsa_nid;
+       pk->dsa = NULL;
+       pk->ecdsa = NULL;
+       pk->rsa = NULL;
+
+       switch (k->type) {
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               key_cert_copy(k, pk);
+               /* FALLTHROUGH */
+       case KEY_RSA1:
+       case KEY_RSA:
+               if ((pk->rsa = RSA_new()) == NULL)
+                       fatal("key_demote: RSA_new failed");
+               if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               break;
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               key_cert_copy(k, pk);
+               /* FALLTHROUGH */
+       case KEY_DSA:
+               if ((pk->dsa = DSA_new()) == NULL)
+                       fatal("key_demote: DSA_new failed");
+               if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL)
+                       fatal("key_demote: BN_dup failed");
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+               key_cert_copy(k, pk);
+               /* FALLTHROUGH */
+       case KEY_ECDSA:
+               if ((pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid)) == NULL)
+                       fatal("key_demote: EC_KEY_new_by_curve_name failed");
+               if (EC_KEY_set_public_key(pk->ecdsa,
+                   EC_KEY_get0_public_key(k->ecdsa)) != 1)
+                       fatal("key_demote: EC_KEY_set_public_key failed");
+               break;
+#endif
+       default:
+               fatal("key_free: bad key type %d", k->type);
+               break;
+       }
+
+       return (pk);
+}
+
+int
+key_is_cert(const Key *k)
+{
+       if (k == NULL)
+               return 0;
+       switch (k->type) {
+       case KEY_RSA_CERT_V00:
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT:
+       case KEY_DSA_CERT:
+       case KEY_ECDSA_CERT:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/* Return the cert-less equivalent to a certified key type */
+int
+key_type_plain(int type)
+{
+       switch (type) {
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               return KEY_RSA;
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               return KEY_DSA;
+       case KEY_ECDSA_CERT:
+               return KEY_ECDSA;
+       default:
+               return type;
+       }
+}
+
+/* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */
+int
+key_to_certified(Key *k, int legacy)
+{
+       switch (k->type) {
+       case KEY_RSA:
+               k->cert = cert_new();
+               k->type = legacy ? KEY_RSA_CERT_V00 : KEY_RSA_CERT;
+               return 0;
+       case KEY_DSA:
+               k->cert = cert_new();
+               k->type = legacy ? KEY_DSA_CERT_V00 : KEY_DSA_CERT;
+               return 0;
+       case KEY_ECDSA:
+               k->cert = cert_new();
+               k->type = KEY_ECDSA_CERT;
+               return 0;
+       default:
+               error("%s: key has incorrect type %s", __func__, key_type(k));
+               return -1;
+       }
+}
+
+/* Convert a KEY_RSA_CERT or KEY_DSA_CERT to their raw key equivalent */
+int
+key_drop_cert(Key *k)
+{
+       switch (k->type) {
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               cert_free(k->cert);
+               k->type = KEY_RSA;
+               return 0;
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               cert_free(k->cert);
+               k->type = KEY_DSA;
+               return 0;
+       case KEY_ECDSA_CERT:
+               cert_free(k->cert);
+               k->type = KEY_ECDSA;
+               return 0;
+       default:
+               error("%s: key has incorrect type %s", __func__, key_type(k));
+               return -1;
+       }
+}
+
+/*
+ * Sign a KEY_RSA_CERT, KEY_DSA_CERT or KEY_ECDSA_CERT, (re-)generating
+ * the signed certblob
+ */
+int
+key_certify(Key *k, Key *ca)
+{
+       Buffer principals;
+       u_char *ca_blob, *sig_blob, nonce[32];
+       u_int i, ca_len, sig_len;
+
+       if (k->cert == NULL) {
+               error("%s: key lacks cert info", __func__);
+               return -1;
+       }
+
+       if (!key_is_cert(k)) {
+               error("%s: certificate has unknown type %d", __func__,
+                   k->cert->type);
+               return -1;
+       }
+
+       if (ca->type != KEY_RSA && ca->type != KEY_DSA &&
+           ca->type != KEY_ECDSA) {
+               error("%s: CA key has unsupported type %s", __func__,
+                   key_type(ca));
+               return -1;
+       }
+
+       key_to_blob(ca, &ca_blob, &ca_len);
+
+       buffer_clear(&k->cert->certblob);
+       buffer_put_cstring(&k->cert->certblob, key_ssh_name(k));
+
+       /* -v01 certs put nonce first */
+       arc4random_buf(&nonce, sizeof(nonce));
+       if (!key_cert_is_legacy(k))
+               buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
+
+       switch (k->type) {
+       case KEY_DSA_CERT_V00:
+       case KEY_DSA_CERT:
+               buffer_put_bignum2(&k->cert->certblob, k->dsa->p);
+               buffer_put_bignum2(&k->cert->certblob, k->dsa->q);
+               buffer_put_bignum2(&k->cert->certblob, k->dsa->g);
+               buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key);
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA_CERT:
+               buffer_put_cstring(&k->cert->certblob,
+                   key_curve_nid_to_name(k->ecdsa_nid));
+               buffer_put_ecpoint(&k->cert->certblob,
+                   EC_KEY_get0_group(k->ecdsa),
+                   EC_KEY_get0_public_key(k->ecdsa));
+               break;
+#endif
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+               buffer_put_bignum2(&k->cert->certblob, k->rsa->e);
+               buffer_put_bignum2(&k->cert->certblob, k->rsa->n);
+               break;
+       default:
+               error("%s: key has incorrect type %s", __func__, key_type(k));
+               buffer_clear(&k->cert->certblob);
+               xfree(ca_blob);
+               return -1;
+       }
+
+       /* -v01 certs have a serial number next */
+       if (!key_cert_is_legacy(k))
+               buffer_put_int64(&k->cert->certblob, k->cert->serial);
+
+       buffer_put_int(&k->cert->certblob, k->cert->type);
+       buffer_put_cstring(&k->cert->certblob, k->cert->key_id);
+
+       buffer_init(&principals);
+       for (i = 0; i < k->cert->nprincipals; i++)
+               buffer_put_cstring(&principals, k->cert->principals[i]);
+       buffer_put_string(&k->cert->certblob, buffer_ptr(&principals),
+           buffer_len(&principals));
+       buffer_free(&principals);
+
+       buffer_put_int64(&k->cert->certblob, k->cert->valid_after);
+       buffer_put_int64(&k->cert->certblob, k->cert->valid_before);
+       buffer_put_string(&k->cert->certblob,
+           buffer_ptr(&k->cert->critical), buffer_len(&k->cert->critical));
+
+       /* -v01 certs have non-critical options here */
+       if (!key_cert_is_legacy(k)) {
+               buffer_put_string(&k->cert->certblob,
+                   buffer_ptr(&k->cert->extensions),
+                   buffer_len(&k->cert->extensions));
+       }
+
+       /* -v00 certs put the nonce at the end */
+       if (key_cert_is_legacy(k))
+               buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce));
+
+       buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */
+       buffer_put_string(&k->cert->certblob, ca_blob, ca_len);
+       xfree(ca_blob);
+
+       /* Sign the whole mess */
+       if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob),
+           buffer_len(&k->cert->certblob)) != 0) {
+               error("%s: signature operation failed", __func__);
+               buffer_clear(&k->cert->certblob);
+               return -1;
+       }
+       /* Append signature and we are done */
+       buffer_put_string(&k->cert->certblob, sig_blob, sig_len);
+       xfree(sig_blob);
+
+       return 0;
+}
+
+int
+key_cert_check_authority(const Key *k, int want_host, int require_principal,
+    const char *name, const char **reason)
+{
+       u_int i, principal_matches;
+       time_t now = time(NULL);
+
+       if (want_host) {
+               if (k->cert->type != SSH2_CERT_TYPE_HOST) {
+                       *reason = "Certificate invalid: not a host certificate";
+                       return -1;
+               }
+       } else {
+               if (k->cert->type != SSH2_CERT_TYPE_USER) {
+                       *reason = "Certificate invalid: not a user certificate";
+                       return -1;
+               }
+       }
+       if (now < 0) {
+               error("%s: system clock lies before epoch", __func__);
+               *reason = "Certificate invalid: not yet valid";
+               return -1;
+       }
+       if ((u_int64_t)now < k->cert->valid_after) {
+               *reason = "Certificate invalid: not yet valid";
+               return -1;
+       }
+       if ((u_int64_t)now >= k->cert->valid_before) {
+               *reason = "Certificate invalid: expired";
+               return -1;
+       }
+       if (k->cert->nprincipals == 0) {
+               if (require_principal) {
+                       *reason = "Certificate lacks principal list";
+                       return -1;
+               }
+       } else if (name != NULL) {
+               principal_matches = 0;
+               for (i = 0; i < k->cert->nprincipals; i++) {
+                       if (strcmp(name, k->cert->principals[i]) == 0) {
+                               principal_matches = 1;
+                               break;
+                       }
+               }
+               if (!principal_matches) {
+                       *reason = "Certificate invalid: name is not a listed "
+                           "principal";
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+int
+key_cert_is_legacy(Key *k)
+{
+       switch (k->type) {
+       case KEY_DSA_CERT_V00:
+       case KEY_RSA_CERT_V00:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/* XXX: these are really begging for a table-driven approach */
+int
+key_curve_name_to_nid(const char *name)
+{
+#ifdef OPENSSL_HAS_ECC
+       if (strcmp(name, "nistp256") == 0)
+               return NID_X9_62_prime256v1;
+       else if (strcmp(name, "nistp384") == 0)
+               return NID_secp384r1;
+       else if (strcmp(name, "nistp521") == 0)
+               return NID_secp521r1;
+#endif
+
+       debug("%s: unsupported EC curve name \"%.100s\"", __func__, name);
+       return -1;
+}
+
+u_int
+key_curve_nid_to_bits(int nid)
+{
+       switch (nid) {
+#ifdef OPENSSL_HAS_ECC
+       case NID_X9_62_prime256v1:
+               return 256;
+       case NID_secp384r1:
+               return 384;
+       case NID_secp521r1:
+               return 521;
+#endif
+       default:
+               error("%s: unsupported EC curve nid %d", __func__, nid);
+               return 0;
+       }
+}
+
+const char *
+key_curve_nid_to_name(int nid)
+{
+#ifdef OPENSSL_HAS_ECC
+       if (nid == NID_X9_62_prime256v1)
+               return "nistp256";
+       else if (nid == NID_secp384r1)
+               return "nistp384";
+       else if (nid == NID_secp521r1)
+               return "nistp521";
+#endif
+       error("%s: unsupported EC curve nid %d", __func__, nid);
+       return NULL;
+}
+
+#ifdef OPENSSL_HAS_ECC
+const EVP_MD *
+key_ec_nid_to_evpmd(int nid)
+{
+       int kbits = key_curve_nid_to_bits(nid);
+
+       if (kbits == 0)
+               fatal("%s: invalid nid %d", __func__, nid);
+       /* RFC5656 section 6.2.1 */
+       if (kbits <= 256)
+               return EVP_sha256();
+       else if (kbits <= 384)
+               return EVP_sha384();
+       else
+               return EVP_sha512();
+}
+
+int
+key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
+{
+       BN_CTX *bnctx;
+       EC_POINT *nq = NULL;
+       BIGNUM *order, *x, *y, *tmp;
+       int ret = -1;
+
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new failed", __func__);
+       BN_CTX_start(bnctx);
+
+       /*
+        * We shouldn't ever hit this case because bignum_get_ecpoint()
+        * refuses to load GF2m points.
+        */
+       if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+           NID_X9_62_prime_field) {
+               error("%s: group is not a prime field", __func__);
+               goto out;
+       }
+
+       /* Q != infinity */
+       if (EC_POINT_is_at_infinity(group, public)) {
+               error("%s: received degenerate public key (infinity)",
+                   __func__);
+               goto out;
+       }
+
+       if ((x = BN_CTX_get(bnctx)) == NULL ||
+           (y = BN_CTX_get(bnctx)) == NULL ||
+           (order = BN_CTX_get(bnctx)) == NULL ||
+           (tmp = BN_CTX_get(bnctx)) == NULL)
+               fatal("%s: BN_CTX_get failed", __func__);
+
+       /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
+       if (EC_GROUP_get_order(group, order, bnctx) != 1)
+               fatal("%s: EC_GROUP_get_order failed", __func__);
+       if (EC_POINT_get_affine_coordinates_GFp(group, public,
+           x, y, bnctx) != 1)
+               fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__);
+       if (BN_num_bits(x) <= BN_num_bits(order) / 2) {
+               error("%s: public key x coordinate too small: "
+                   "bits(x) = %d, bits(order)/2 = %d", __func__,
+                   BN_num_bits(x), BN_num_bits(order) / 2);
+               goto out;
+       }
+       if (BN_num_bits(y) <= BN_num_bits(order) / 2) {
+               error("%s: public key y coordinate too small: "
+                   "bits(y) = %d, bits(order)/2 = %d", __func__,
+                   BN_num_bits(x), BN_num_bits(order) / 2);
+               goto out;
+       }
+
+       /* nQ == infinity (n == order of subgroup) */
+       if ((nq = EC_POINT_new(group)) == NULL)
+               fatal("%s: BN_CTX_tmp failed", __func__);
+       if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1)
+               fatal("%s: EC_GROUP_mul failed", __func__);
+       if (EC_POINT_is_at_infinity(group, nq) != 1) {
+               error("%s: received degenerate public key (nQ != infinity)",
+                   __func__);
+               goto out;
+       }
+
+       /* x < order - 1, y < order - 1 */
+       if (!BN_sub(tmp, order, BN_value_one()))
+               fatal("%s: BN_sub failed", __func__);
+       if (BN_cmp(x, tmp) >= 0) {
+               error("%s: public key x coordinate >= group order - 1",
+                   __func__);
+               goto out;
+       }
+       if (BN_cmp(y, tmp) >= 0) {
+               error("%s: public key y coordinate >= group order - 1",
+                   __func__);
+               goto out;
+       }
+       ret = 0;
+ out:
+       BN_CTX_free(bnctx);
+       EC_POINT_free(nq);
+       return ret;
+}
+
+int
+key_ec_validate_private(const EC_KEY *key)
+{
+       BN_CTX *bnctx;
+       BIGNUM *order, *tmp;
+       int ret = -1;
+
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new failed", __func__);
+       BN_CTX_start(bnctx);
+
+       if ((order = BN_CTX_get(bnctx)) == NULL ||
+           (tmp = BN_CTX_get(bnctx)) == NULL)
+               fatal("%s: BN_CTX_get failed", __func__);
+
+       /* log2(private) > log2(order)/2 */
+       if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1)
+               fatal("%s: EC_GROUP_get_order failed", __func__);
+       if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
+           BN_num_bits(order) / 2) {
+               error("%s: private key too small: "
+                   "bits(y) = %d, bits(order)/2 = %d", __func__,
+                   BN_num_bits(EC_KEY_get0_private_key(key)),
+                   BN_num_bits(order) / 2);
+               goto out;
+       }
+
+       /* private < order - 1 */
+       if (!BN_sub(tmp, order, BN_value_one()))
+               fatal("%s: BN_sub failed", __func__);
+       if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) {
+               error("%s: private key >= group order - 1", __func__);
+               goto out;
+       }
+       ret = 0;
+ out:
+       BN_CTX_free(bnctx);
+       return ret;
+}
+
+#if defined(DEBUG_KEXECDH) || defined(DEBUG_PK)
+void
+key_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
+{
+       BIGNUM *x, *y;
+       BN_CTX *bnctx;
+
+       if (point == NULL) {
+               fputs("point=(NULL)\n", stderr);
+               return;
+       }
+       if ((bnctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new failed", __func__);
+       BN_CTX_start(bnctx);
+       if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL)
+               fatal("%s: BN_CTX_get failed", __func__);
+       if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
+           NID_X9_62_prime_field)
+               fatal("%s: group is not a prime field", __func__);
+       if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, bnctx) != 1)
+               fatal("%s: EC_POINT_get_affine_coordinates_GFp", __func__);
+       fputs("x=", stderr);
+       BN_print_fp(stderr, x);
+       fputs("\ny=", stderr);
+       BN_print_fp(stderr, y);
+       fputs("\n", stderr);
+       BN_CTX_free(bnctx);
+}
+
+void
+key_dump_ec_key(const EC_KEY *key)
+{
+       const BIGNUM *exponent;
+
+       key_dump_ec_point(EC_KEY_get0_group(key), EC_KEY_get0_public_key(key));
+       fputs("exponent=", stderr);
+       if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
+               fputs("(NULL)", stderr);
+       else
+               BN_print_fp(stderr, EC_KEY_get0_private_key(key));
+       fputs("\n", stderr);
+}
+#endif /* defined(DEBUG_KEXECDH) || defined(DEBUG_PK) */
+#endif /* OPENSSL_HAS_ECC */
diff --git a/key.h b/key.h
new file mode 100644 (file)
index 0000000..ec5ac5e
--- /dev/null
+++ b/key.h
@@ -0,0 +1,151 @@
+/* $OpenBSD: key.h,v 1.33 2010/10/28 11:22:09 djm 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 "buffer.h"
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#ifdef OPENSSL_HAS_ECC
+#include <openssl/ec.h>
+#endif
+
+typedef struct Key Key;
+enum types {
+       KEY_RSA1,
+       KEY_RSA,
+       KEY_DSA,
+       KEY_ECDSA,
+       KEY_RSA_CERT,
+       KEY_DSA_CERT,
+       KEY_ECDSA_CERT,
+       KEY_RSA_CERT_V00,
+       KEY_DSA_CERT_V00,
+       KEY_UNSPEC
+};
+enum fp_type {
+       SSH_FP_SHA1,
+       SSH_FP_MD5
+};
+enum fp_rep {
+       SSH_FP_HEX,
+       SSH_FP_BUBBLEBABBLE,
+       SSH_FP_RANDOMART
+};
+
+/* key is stored in external hardware */
+#define KEY_FLAG_EXT           0x0001
+
+#define CERT_MAX_PRINCIPALS    256
+struct KeyCert {
+       Buffer           certblob; /* Kept around for use on wire */
+       u_int            type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */
+       u_int64_t        serial;
+       char            *key_id;
+       u_int            nprincipals;
+       char            **principals;
+       u_int64_t        valid_after, valid_before;
+       Buffer           critical;
+       Buffer           extensions;
+       Key             *signature_key;
+};
+
+struct Key {
+       int      type;
+       int      flags;
+       RSA     *rsa;
+       DSA     *dsa;
+       int      ecdsa_nid;     /* NID of curve */
+#ifdef OPENSSL_HAS_ECC
+       EC_KEY  *ecdsa;
+#else
+       void    *ecdsa;
+#endif
+       struct KeyCert *cert;
+};
+
+Key            *key_new(int);
+void            key_add_private(Key *);
+Key            *key_new_private(int);
+void            key_free(Key *);
+Key            *key_demote(const Key *);
+int             key_equal_public(const Key *, const Key *);
+int             key_equal(const Key *, const Key *);
+char           *key_fingerprint(Key *, enum fp_type, enum fp_rep);
+u_char         *key_fingerprint_raw(Key *, enum fp_type, u_int *);
+const char     *key_type(const Key *);
+const char     *key_cert_type(const Key *);
+int             key_write(const Key *, FILE *);
+int             key_read(Key *, char **);
+u_int           key_size(const Key *);
+
+Key    *key_generate(int, u_int);
+Key    *key_from_private(const Key *);
+int     key_type_from_name(char *);
+int     key_is_cert(const Key *);
+int     key_type_plain(int);
+int     key_to_certified(Key *, int);
+int     key_drop_cert(Key *);
+int     key_certify(Key *, Key *);
+void    key_cert_copy(const Key *, struct Key *);
+int     key_cert_check_authority(const Key *, int, int, const char *,
+           const char **);
+int     key_cert_is_legacy(Key *);
+
+int             key_ecdsa_nid_from_name(const char *);
+int             key_curve_name_to_nid(const char *);
+const char *    key_curve_nid_to_name(int);
+u_int           key_curve_nid_to_bits(int);
+int             key_ecdsa_bits_to_nid(int);
+#ifdef OPENSSL_HAS_ECC
+int             key_ecdsa_key_to_nid(EC_KEY *);
+const EVP_MD *  key_ec_nid_to_evpmd(int nid);
+int             key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
+int             key_ec_validate_private(const EC_KEY *);
+#endif
+
+Key            *key_from_blob(const u_char *, u_int);
+int             key_to_blob(const Key *, u_char **, u_int *);
+const char     *key_ssh_name(const Key *);
+const char     *key_ssh_name_plain(const Key *);
+int             key_names_valid2(const char *);
+
+int     key_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
+int     key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+
+int     ssh_dss_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
+int     ssh_dss_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+int     ssh_ecdsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
+int     ssh_ecdsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+int     ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int);
+int     ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
+
+#if defined(OPENSSL_HAS_ECC) && (defined(DEBUG_KEXECDH) || defined(DEBUG_PK))
+void   key_dump_ec_point(const EC_GROUP *, const EC_POINT *);
+void   key_dump_ec_key(const EC_KEY *);
+#endif
+
+#endif
diff --git a/log.c b/log.c
new file mode 100644 (file)
index 0000000..4a8239b
--- /dev/null
+++ b/log.c
@@ -0,0 +1,401 @@
+/* $OpenBSD: log.c,v 1.41 2008/06/10 04:50:25 dtucker Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    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"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <errno.h>
+#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+# include <vis.h>
+#endif
+
+#include "xmalloc.h"
+#include "log.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;
+
+#define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL)
+#define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL)
+
+/* 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,         SYSLOG_FACILITY_NOT_SET }
+};
+
+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,         SYSLOG_LEVEL_NOT_SET }
+};
+
+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 SYSLOG_FACILITY_NOT_SET;
+}
+
+const char *
+log_facility_name(SyslogFacility facility)
+{
+       u_int i;
+
+       for (i = 0;  log_facilities[i].name; i++)
+               if (log_facilities[i].val == facility)
+                       return log_facilities[i].name;
+       return NULL;
+}
+
+LogLevel
+log_level_number(char *name)
+{
+       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 SYSLOG_LEVEL_NOT_SET;
+}
+
+const char *
+log_level_name(LogLevel level)
+{
+       u_int i;
+
+       for (i = 0; log_levels[i].name != NULL; i++)
+               if (log_levels[i].val == level)
+                       return log_levels[i].name;
+       return NULL;
+}
+
+/* Error messages that should be logged. */
+
+void
+error(const char *fmt,...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_ERROR, fmt, args);
+       va_end(args);
+}
+
+void
+sigdie(const char *fmt,...)
+{
+#ifdef DO_LOG_SAFE_IN_SIGHAND
+       va_list args;
+
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+       va_end(args);
+#endif
+       _exit(1);
+}
+
+
+/* Log this message (information that usually should go to the log). */
+
+void
+logit(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);
+}
+
+/*
+ * Initialize the log.
+ */
+
+void
+log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
+{
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
+       struct syslog_data sdata = SYSLOG_DATA_INIT;
+#endif
+
+       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);
+       }
+
+       /*
+        * If an external library (eg libwrap) attempts to use syslog
+        * immediately after reexec, syslog may be pointing to the wrong
+        * facility, so we force an open/close of syslog here.
+        */
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
+       openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
+       closelog_r(&sdata);
+#else
+       openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
+       closelog();
+#endif
+}
+
+#define MSGBUFSIZ 1024
+
+void
+do_log(LogLevel level, const char *fmt, va_list args)
+{
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
+       struct syslog_data sdata = SYSLOG_DATA_INIT;
+#endif
+       char msgbuf[MSGBUFSIZ];
+       char fmtbuf[MSGBUFSIZ];
+       char *txt = NULL;
+       int pri = LOG_INFO;
+       int saved_errno = errno;
+
+       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);
+       }
+       strnvis(fmtbuf, msgbuf, sizeof(fmtbuf),
+           log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS);
+       if (log_on_stderr) {
+               snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf);
+               write(STDERR_FILENO, msgbuf, strlen(msgbuf));
+       } else {
+#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT)
+               openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata);
+               syslog_r(pri, &sdata, "%.500s", fmtbuf);
+               closelog_r(&sdata);
+#else
+               openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
+               syslog(pri, "%.500s", fmtbuf);
+               closelog();
+#endif
+       }
+       errno = saved_errno;
+}
diff --git a/log.h b/log.h
new file mode 100644 (file)
index 0000000..6505827
--- /dev/null
+++ b/log.h
@@ -0,0 +1,69 @@
+/* $OpenBSD: log.h,v 1.17 2008/06/13 00:12:02 dtucker 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
+
+/* 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,
+       SYSLOG_FACILITY_NOT_SET = -1
+}       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,
+       SYSLOG_LEVEL_NOT_SET = -1
+}       LogLevel;
+
+void     log_init(char *, LogLevel, SyslogFacility, int);
+
+SyslogFacility log_facility_number(char *);
+const char *   log_facility_name(SyslogFacility);
+LogLevel       log_level_number(char *);
+const char *   log_level_name(LogLevel);
+
+void     fatal(const char *, ...) __attribute__((noreturn))
+    __attribute__((format(printf, 1, 2)));
+void     error(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     sigdie(const char *, ...)  __attribute__((noreturn))
+    __attribute__((format(printf, 1, 2)));
+void     logit(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     verbose(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug2(const char *, ...) __attribute__((format(printf, 1, 2)));
+void     debug3(const char *, ...) __attribute__((format(printf, 1, 2)));
+
+void    do_log(LogLevel, const char *, va_list);
+void    cleanup_exit(int) __attribute__((noreturn));
+#endif
diff --git a/loginrec.c b/loginrec.c
new file mode 100644 (file)
index 0000000..32941c9
--- /dev/null
@@ -0,0 +1,1727 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * The btmp logging code is derived from login.c from util-linux and is under
+ * the the following license:
+ *
+ * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University 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 WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+
+/**
+ ** 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!
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <pwd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "ssh.h"
+#include "loginrec.h"
+#include "log.h"
+#include "atomicio.h"
+#include "packet.h"
+#include "canohost.h"
+#include "auth.h"
+#include "buffer.h"
+
+#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 utmpx_get_entry(struct logininfo *li);
+int wtmp_get_entry(struct logininfo *li);
+int wtmpx_get_entry(struct logininfo *li);
+
+extern Buffer loginmsg;
+
+/* 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 uid_t 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 uid_t 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("%s: Cannot find account for uid %ld", __func__,
+                   (long)uid);
+
+       /* No MIN_SIZEOF here - we absolutely *must not* truncate the
+        * username (XXX - so check for trunc!) */
+       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(pid_t pid, const char *username,
+    const char *hostname, const char *line)
+{
+       struct logininfo *newli;
+
+       newli = xmalloc(sizeof(*newli));
+       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, pid_t 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("%s: Cannot find user \"%s\"", __func__,
+                           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(&li->hostaddr.sa, sa, bufsize);
+}
+
+
+/**
+ ** login_write: Call low-level recording functions based on autoconf
+ ** results
+ **/
+int
+login_write(struct logininfo *li)
+{
+#ifndef HAVE_CYGWIN
+       if (geteuid() != 0) {
+               logit("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
+#ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN
+       if (li->type == LTYPE_LOGIN &&
+           !sys_auth_record_login(li->username,li->hostname,li->line,
+           &loginmsg))
+               logit("Writing login record failed for %s", li->username);
+#endif
+#ifdef SSH_AUDIT_EVENTS
+       if (li->type == LTYPE_LOGIN)
+               audit_session_open(li);
+       else if (li->type == LTYPE_LOGOUT)
+               audit_session_close(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 */
+#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
+    defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
+       return (utmpx_get_entry(li));
+#endif
+
+#if defined(DISABLE_LASTLOG)
+       /* On some systems we shouldn't even try to obtain last login
+        * time, e.g. AIX */
+       return (0);
+# elif defined(USE_WTMP) && \
+    (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP))
+       /* retrieve last login time from utmp */
+       return (wtmp_get_entry(li));
+# elif defined(USE_WTMPX) && \
+    (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX))
+       /* If wtmp isn't available, try wtmpx */
+       return (wtmpx_get_entry(li));
+# else
+       /* Give up: No means of retrieving last login time */
+       return (0);
+# 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, u_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;
+
+#ifdef WITH_ABBREV_NO_TTY
+       if (strncmp(src, "tty", 3) == 0)
+               src += 3;
+#endif
+
+       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)
+{
+# if defined(HAVE_TV_IN_UTMP)
+       ut->ut_tv.tv_sec = li->tv_sec;
+       ut->ut_tv.tv_usec = li->tv_usec;
+# elif defined(HAVE_TIME_IN_UTMP)
+       ut->ut_time = li->tv_sec;
+# endif
+}
+
+void
+construct_utmp(struct logininfo *li,
+                   struct utmp *ut)
+{
+# ifdef HAVE_ADDR_V6_IN_UTMP
+       struct sockaddr_in6 *sa6;
+# endif
+
+       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 _UNICOS
+               cray_set_tmpdir(ut);
+#endif
+               break;
+       case LTYPE_LOGOUT:
+               ut->ut_type = DEAD_PROCESS;
+#ifdef _UNICOS
+               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
+# ifdef HAVE_ADDR_V6_IN_UTMP
+       /* this is just a 128-bit IPv6 address */
+       if (li->hostaddr.sa.sa_family == AF_INET6) {
+               sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
+               memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
+               if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
+                       ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
+                       ut->ut_addr_v6[1] = 0;
+                       ut->ut_addr_v6[2] = 0;
+                       ut->ut_addr_v6[3] = 0;
+               }
+       }
+# 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)
+{
+# if defined(HAVE_TV_IN_UTMPX)
+       utx->ut_tv.tv_sec = li->tv_sec;
+       utx->ut_tv.tv_usec = li->tv_usec;
+# elif defined(HAVE_TIME_IN_UTMPX)
+       utx->ut_time = li->tv_sec;
+# endif
+}
+
+void
+construct_utmpx(struct logininfo *li, struct utmpx *utx)
+{
+# ifdef HAVE_ADDR_V6_IN_UTMP
+       struct sockaddr_in6 *sa6;
+#  endif
+       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;
+
+       /* strncpy(): Don't necessarily want null termination */
+       strncpy(utx->ut_user, li->username,
+           MIN_SIZEOF(utx->ut_user, li->username));
+
+       if (li->type == LTYPE_LOGOUT)
+               return;
+
+       /*
+        * These fields are only used when logging in, and are blank
+        * for logouts.
+        */
+
+# 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_ADDR_V6_IN_UTMP
+       /* this is just a 128-bit IPv6 address */
+       if (li->hostaddr.sa.sa_family == AF_INET6) {
+               sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa);
+               memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16);
+               if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) {
+                       ut->ut_addr_v6[0] = ut->ut_addr_v6[3];
+                       ut->ut_addr_v6[1] = 0;
+                       ut->ut_addr_v6[2] = 0;
+                       ut->ut_addr_v6[3] = 0;
+               }
+       }
+# 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)
+       struct ttyent *ty;
+
+       tty=0;
+       setttyent();
+       while (NULL != (ty = getttyent())) {
+               tty++;
+               if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
+                       break;
+       }
+       endttyent();
+
+       if (NULL == ty) {
+               logit("%s: tty not found", __func__);
+               return (0);
+       }
+#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) {
+               off_t pos, ret;
+
+               pos = (off_t)tty * sizeof(struct utmp);
+               if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
+                       logit("%s: lseek: %s", __func__, strerror(errno));
+                       close(fd);
+                       return (0);
+               }
+               if (ret != pos) {
+                       logit("%s: Couldn't seek to tty %d slot in %s",
+                           __func__, tty, UTMP_FILE);
+                       close(fd);
+                       return (0);
+               }
+               /*
+                * 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))
+                       memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
+
+               if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
+                       logit("%s: lseek: %s", __func__, strerror(errno));
+                       close(fd);
+                       return (0);
+               }
+               if (ret != pos) {
+                       logit("%s: Couldn't seek to tty %d slot in %s",
+                           __func__, tty, UTMP_FILE);
+                       close(fd);
+                       return (0);
+               }
+               if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
+                       logit("%s: error writing %s: %s", __func__,
+                           UTMP_FILE, strerror(errno));
+                       close(fd);
+                       return (0);
+               }
+
+               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)) {
+               logit("%s: utmp_write_library() failed", __func__);
+               return (0);
+       }
+# else
+       if (!utmp_write_direct(li, &ut)) {
+               logit("%s: utmp_write_direct() failed", __func__);
+               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)) {
+               logit("%s: utmp_write_library() failed", __func__);
+               return (0);
+       }
+# else
+       if (!utmp_write_direct(li, &ut)) {
+               logit("%s: utmp_write_direct() failed", __func__);
+               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:
+               logit("%s: invalid type field", __func__);
+               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)
+{
+       logit("%s: not implemented!", __func__);
+       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)) {
+               logit("%s: utmp_write_library() failed", __func__);
+               return (0);
+       }
+# else
+       if (!utmpx_write_direct(li, &ut)) {
+               logit("%s: utmp_write_direct() failed", __func__);
+               return (0);
+       }
+# endif
+       return (1);
+}
+
+
+static int
+utmpx_perform_logout(struct logininfo *li)
+{
+       struct utmpx utx;
+
+       construct_utmpx(li, &utx);
+# 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:
+               logit("%s: invalid type field", __func__);
+               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) {
+               logit("%s: problem writing %s: %s", __func__,
+                   WTMP_FILE, strerror(errno));
+               return (0);
+       }
+       if (fstat(fd, &buf) == 0)
+               if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
+                       ftruncate(fd, buf.st_size);
+                       logit("%s: problem writing %s: %s", __func__,
+                           WTMP_FILE, strerror(errno));
+                       ret = 0;
+               }
+       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:
+               logit("%s: invalid type field", __func__);
+               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) {
+               logit("%s: problem opening %s: %s", __func__,
+                   WTMP_FILE, strerror(errno));
+               return (0);
+       }
+       if (fstat(fd, &st) != 0) {
+               logit("%s: couldn't stat %s: %s", __func__,
+                   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)) {
+                       logit("%s: read of %s failed: %s", __func__,
+                           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)
+{
+#ifndef HAVE_UPDWTMPX
+       struct stat buf;
+       int fd, ret = 1;
+
+       if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) {
+               logit("%s: problem opening %s: %s", __func__,
+                   WTMPX_FILE, strerror(errno));
+               return (0);
+       }
+
+       if (fstat(fd, &buf) == 0)
+               if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) {
+                       ftruncate(fd, buf.st_size);
+                       logit("%s: problem writing %s: %s", __func__,
+                           WTMPX_FILE, strerror(errno));
+                       ret = 0;
+               }
+       close(fd);
+
+       return (ret);
+#else
+       updwtmpx(WTMPX_FILE, utx);
+       return (1);
+#endif
+}
+
+
+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:
+               logit("%s: invalid type field", __func__);
+               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_user,
+           MIN_SIZEOF(li->username, utx->ut_user)) == 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) {
+               logit("%s: problem opening %s: %s", __func__,
+                   WTMPX_FILE, strerror(errno));
+               return (0);
+       }
+       if (fstat(fd, &st) != 0) {
+               logit("%s: couldn't stat %s: %s", __func__,
+                   WTMPX_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)) {
+                       logit("%s: read of %s failed: %s", __func__,
+                           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)) {
+                       found = 1;
+# if defined(HAVE_TV_IN_UTMPX)
+                       li->tv_sec = utx.ut_tv.tv_sec;
+# elif defined(HAVE_TIME_IN_UTMPX)
+                       li->tv_sec = utx.ut_time;
+# endif
+                       line_fullname(li->line, utx.ut_line, sizeof(li->line));
+# if defined(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;
+
+       ut = xmalloc(sizeof(*ut));
+       construct_utmp(li, ut);
+       login(ut);
+       free(ut);
+
+       return (1);
+}
+
+static int
+syslogin_perform_logout(struct logininfo *li)
+{
+# ifdef HAVE_LOGOUT
+       char line[UT_LINESIZE];
+
+       (void)line_stripname(line, li->line, sizeof(line));
+
+       if (!logout(line))
+               logit("%s: logout() returned an error", __func__);
+#  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:
+               logit("%s: Invalid type field", __func__);
+               return (0);
+       }
+}
+#endif /* USE_LOGIN */
+
+/* end of file log-syslogin.c */
+
+/**
+ ** Low-level lastlog functions
+ **/
+
+#ifdef USE_LASTLOG
+
+#if !defined(LASTLOG_WRITE_PUTUTXLINE) || !defined(HAVE_GETLASTLOGXBYNAME)
+/* 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;
+       char lastlog_file[1024];
+       struct stat st;
+
+       if (stat(LASTLOG_FILE, &st) != 0) {
+               logit("%s: Couldn't stat %s: %s", __func__,
+                   LASTLOG_FILE, strerror(errno));
+               return (0);
+       }
+       if (S_ISDIR(st.st_mode)) {
+               snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s",
+                   LASTLOG_FILE, li->username);
+       } else if (S_ISREG(st.st_mode)) {
+               strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file));
+       } else {
+               logit("%s: %.100s is not a file or directory!", __func__,
+                   LASTLOG_FILE);
+               return (0);
+       }
+
+       *fd = open(lastlog_file, filemode, 0600);
+       if (*fd < 0) {
+               debug("%s: Couldn't open %s: %s", __func__,
+                   lastlog_file, strerror(errno));
+               return (0);
+       }
+
+       if (S_ISREG(st.st_mode)) {
+               /* find this uid's offset in the lastlog file */
+               offset = (off_t) ((u_long)li->uid * sizeof(struct lastlog));
+
+               if (lseek(*fd, offset, SEEK_SET) != offset) {
+                       logit("%s: %s->lseek(): %s", __func__,
+                           lastlog_file, strerror(errno));
+                       close(*fd);
+                       return (0);
+               }
+       }
+
+       return (1);
+}
+#endif /* !LASTLOG_WRITE_PUTUTXLINE || !HAVE_GETLASTLOGXBYNAME */
+
+#ifdef LASTLOG_WRITE_PUTUTXLINE
+int
+lastlog_write_entry(struct logininfo *li)
+{
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               return 1; /* lastlog written by pututxline */
+       default:
+               logit("lastlog_write_entry: Invalid type field");
+               return 0;
+       }
+}
+#else /* LASTLOG_WRITE_PUTUTXLINE */
+int
+lastlog_write_entry(struct logininfo *li)
+{
+       struct lastlog last;
+       int fd;
+
+       switch(li->type) {
+       case LTYPE_LOGIN:
+               /* create our struct lastlog */
+               memset(&last, '\0', sizeof(last));
+               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;
+       
+               if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT))
+                       return (0);
+       
+               /* write the entry */
+               if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) {
+                       close(fd);
+                       logit("%s: Error writing to %s: %s", __func__,
+                           LASTLOG_FILE, strerror(errno));
+                       return (0);
+               }
+       
+               close(fd);
+               return (1);
+       default:
+               logit("%s: Invalid type field", __func__);
+               return (0);
+       }
+}
+#endif /* LASTLOG_WRITE_PUTUTXLINE */
+
+#ifdef HAVE_GETLASTLOGXBYNAME
+int
+lastlog_get_entry(struct logininfo *li)
+{
+       struct lastlogx l, *ll;
+
+       if ((ll = getlastlogxbyname(li->username, &l)) == NULL) {
+               memset(&l, '\0', sizeof(l));
+               ll = &l;
+       }
+       line_fullname(li->line, ll->ll_line, sizeof(li->line));
+       strlcpy(li->hostname, ll->ll_host,
+               MIN_SIZEOF(li->hostname, ll->ll_host));
+       li->tv_sec = ll->ll_tv.tv_sec;
+       li->tv_usec = ll->ll_tv.tv_usec;
+       return (1);
+}
+#else /* HAVE_GETLASTLOGXBYNAME */
+int
+lastlog_get_entry(struct logininfo *li)
+{
+       struct lastlog last;
+       int fd, ret;
+
+       if (!lastlog_openseek(li, &fd, O_RDONLY))
+               return (0);
+
+       ret = atomicio(read, fd, &last, sizeof(last));
+       close(fd);
+
+       switch (ret) {
+       case 0:
+               memset(&last, '\0', sizeof(last));
+               /* FALLTHRU */
+       case sizeof(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;
+               return (1);
+       case -1:
+               error("%s: Error reading from %s: %s", __func__,
+                   LASTLOG_FILE, strerror(errno));
+               return (0);
+       default:
+               error("%s: Error reading from %s: Expecting %d, got %d",
+                   __func__, LASTLOG_FILE, (int)sizeof(last), ret);
+               return (0);
+       }
+
+       /* NOTREACHED */
+       return (0);
+}
+#endif /* HAVE_GETLASTLOGXBYNAME */
+#endif /* USE_LASTLOG */
+
+#if defined(USE_UTMPX) && defined(HAVE_SETUTXDB) && \
+    defined(UTXDB_LASTLOGIN) && defined(HAVE_GETUTXUSER)
+int
+utmpx_get_entry(struct logininfo *li)
+{
+       struct utmpx *utx;
+
+       if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0)
+               return (0);
+       utx = getutxuser(li->username);
+       if (utx == NULL) {
+               endutxent();
+               return (0);
+       }
+
+       line_fullname(li->line, utx->ut_line,
+           MIN_SIZEOF(li->line, utx->ut_line));
+       strlcpy(li->hostname, utx->ut_host,
+           MIN_SIZEOF(li->hostname, utx->ut_host));
+       li->tv_sec = utx->ut_tv.tv_sec;
+       li->tv_usec = utx->ut_tv.tv_usec;
+       endutxent();
+       return (1);
+}
+#endif /* USE_UTMPX && HAVE_SETUTXDB && UTXDB_LASTLOGIN && HAVE_GETUTXUSER */
+
+#ifdef USE_BTMP
+  /*
+   * Logs failed login attempts in _PATH_BTMP if that exists.
+   * The most common login failure is to give password instead of username.
+   * So the _PATH_BTMP file checked for the correct permission, so that
+   * only root can read it.
+   */
+
+void
+record_failed_login(const char *username, const char *hostname,
+    const char *ttyn)
+{
+       int fd;
+       struct utmp ut;
+       struct sockaddr_storage from;
+       socklen_t fromlen = sizeof(from);
+       struct sockaddr_in *a4;
+       struct sockaddr_in6 *a6;
+       time_t t;
+       struct stat fst;
+
+       if (geteuid() != 0)
+               return;
+       if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) {
+               debug("Unable to open the btmp file %s: %s", _PATH_BTMP,
+                   strerror(errno));
+               return;
+       }
+       if (fstat(fd, &fst) < 0) {
+               logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP,
+                   strerror(errno));
+               goto out;
+       }
+       if((fst.st_mode & (S_IXGRP | S_IRWXO)) || (fst.st_uid != 0)){
+               logit("Excess permission or bad ownership on file %s",
+                   _PATH_BTMP);
+               goto out;
+       }
+
+       memset(&ut, 0, sizeof(ut));
+       /* strncpy because we don't necessarily want nul termination */
+       strncpy(ut.ut_user, username, sizeof(ut.ut_user));
+       strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line));
+
+       time(&t);
+       ut.ut_time = t;     /* ut_time is not always a time_t */
+       ut.ut_type = LOGIN_PROCESS;
+       ut.ut_pid = getpid();
+
+       /* strncpy because we don't necessarily want nul termination */
+       strncpy(ut.ut_host, hostname, sizeof(ut.ut_host));
+
+       if (packet_connection_is_on_socket() &&
+           getpeername(packet_get_connection_in(),
+           (struct sockaddr *)&from, &fromlen) == 0) {
+               ipv64_normalise_mapped(&from, &fromlen);
+               if (from.ss_family == AF_INET) {
+                       a4 = (struct sockaddr_in *)&from;
+                       memcpy(&ut.ut_addr, &(a4->sin_addr),
+                           MIN_SIZEOF(ut.ut_addr, a4->sin_addr));
+               }
+#ifdef HAVE_ADDR_V6_IN_UTMP
+               if (from.ss_family == AF_INET6) {
+                       a6 = (struct sockaddr_in6 *)&from;
+                       memcpy(&ut.ut_addr_v6, &(a6->sin6_addr),
+                           MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr));
+               }
+#endif
+       }
+
+       if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut))
+               error("Failed to write to %s: %s", _PATH_BTMP,
+                   strerror(errno));
+
+out:
+       close(fd);
+}
+#endif /* USE_BTMP */
diff --git a/loginrec.h b/loginrec.h
new file mode 100644 (file)
index 0000000..28923e7
--- /dev/null
@@ -0,0 +1,131 @@
+#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.
+ *
+ * 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"
+
+/**
+ ** 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 512
+#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_*) */
+       pid_t      pid;                          /* PID of login process */
+       uid_t      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(pid_t 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, pid_t 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 uid_t uid);
+/* lastlog *time* functions return time_t equivalent (uint) */
+unsigned int login_get_lastlog_time(const uid_t uid);
+
+/* produce various forms of the line filename */
+char *line_fullname(char *dst, const char *src, u_int dstsize);
+char *line_stripname(char *dst, const char *src, int dstsize);
+char *line_abbrevname(char *dst, const char *src, int dstsize);
+
+void record_failed_login(const char *, const char *, const char *);
+
+#endif /* _HAVE_LOGINREC_H_ */
diff --git a/logintest.c b/logintest.c
new file mode 100644 (file)
index 0000000..4897ae0
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ *
+ * 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 <sys/socket.h>
+
+#include <netinet/in.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"
+
+extern char *__progname;
+
+#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\n");
+#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 = ssh_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/mac.c b/mac.c
new file mode 100644 (file)
index 0000000..fabc3ed
--- /dev/null
+++ b/mac.c
@@ -0,0 +1,188 @@
+/* $OpenBSD: mac.c,v 1.15 2008/06/13 00:51:47 dtucker 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <openssl/hmac.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "cipher.h"
+#include "buffer.h"
+#include "key.h"
+#include "kex.h"
+#include "mac.h"
+#include "misc.h"
+
+#include "umac.h"
+
+#define SSH_EVP                1       /* OpenSSL EVP-based MAC */
+#define SSH_UMAC       2       /* UMAC (not integrated with OpenSSL) */
+
+struct {
+       char            *name;
+       int             type;
+       const EVP_MD *  (*mdfunc)(void);
+       int             truncatebits;   /* truncate digest if != 0 */
+       int             key_len;        /* just for UMAC */
+       int             len;            /* just for UMAC */
+} macs[] = {
+       { "hmac-sha1",                  SSH_EVP, EVP_sha1, 0, -1, -1 },
+       { "hmac-sha1-96",               SSH_EVP, EVP_sha1, 96, -1, -1 },
+       { "hmac-md5",                   SSH_EVP, EVP_md5, 0, -1, -1 },
+       { "hmac-md5-96",                SSH_EVP, EVP_md5, 96, -1, -1 },
+       { "hmac-ripemd160",             SSH_EVP, EVP_ripemd160, 0, -1, -1 },
+       { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, -1, -1 },
+       { "umac-64@openssh.com",        SSH_UMAC, NULL, 0, 128, 64 },
+       { NULL,                         0, NULL, 0, -1, -1 }
+};
+
+static void
+mac_setup_by_id(Mac *mac, int which)
+{
+       int evp_len;
+       mac->type = macs[which].type;
+       if (mac->type == SSH_EVP) {
+               mac->evp_md = (*macs[which].mdfunc)();
+               if ((evp_len = EVP_MD_size(mac->evp_md)) <= 0)
+                       fatal("mac %s len %d", mac->name, evp_len);
+               mac->key_len = mac->mac_len = (u_int)evp_len;
+       } else {
+               mac->mac_len = macs[which].len / 8;
+               mac->key_len = macs[which].key_len / 8;
+               mac->umac_ctx = NULL;
+       }
+       if (macs[which].truncatebits != 0)
+               mac->mac_len = macs[which].truncatebits / 8;
+}
+
+int
+mac_setup(Mac *mac, char *name)
+{
+       int i;
+
+       for (i = 0; macs[i].name; i++) {
+               if (strcmp(name, macs[i].name) == 0) {
+                       if (mac != NULL)
+                               mac_setup_by_id(mac, i);
+                       debug2("mac_setup: found %s", name);
+                       return (0);
+               }
+       }
+       debug2("mac_setup: unknown %s", name);
+       return (-1);
+}
+
+int
+mac_init(Mac *mac)
+{
+       if (mac->key == NULL)
+               fatal("mac_init: no key");
+       switch (mac->type) {
+       case SSH_EVP:
+               if (mac->evp_md == NULL)
+                       return -1;
+               HMAC_Init(&mac->evp_ctx, mac->key, mac->key_len, mac->evp_md);
+               return 0;
+       case SSH_UMAC:
+               mac->umac_ctx = umac_new(mac->key);
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+u_char *
+mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen)
+{
+       static u_char m[EVP_MAX_MD_SIZE];
+       u_char b[4], nonce[8];
+
+       if (mac->mac_len > sizeof(m))
+               fatal("mac_compute: mac too long %u %lu",
+                   mac->mac_len, (u_long)sizeof(m));
+
+       switch (mac->type) {
+       case SSH_EVP:
+               put_u32(b, seqno);
+               /* reset HMAC context */
+               HMAC_Init(&mac->evp_ctx, NULL, 0, NULL);
+               HMAC_Update(&mac->evp_ctx, b, sizeof(b));
+               HMAC_Update(&mac->evp_ctx, data, datalen);
+               HMAC_Final(&mac->evp_ctx, m, NULL);
+               break;
+       case SSH_UMAC:
+               put_u64(nonce, seqno);
+               umac_update(mac->umac_ctx, data, datalen);
+               umac_final(mac->umac_ctx, m, nonce);
+               break;
+       default:
+               fatal("mac_compute: unknown MAC type");
+       }
+       return (m);
+}
+
+void
+mac_clear(Mac *mac)
+{
+       if (mac->type == SSH_UMAC) {
+               if (mac->umac_ctx != NULL)
+                       umac_delete(mac->umac_ctx);
+       } else if (mac->evp_md != NULL)
+               HMAC_cleanup(&mac->evp_ctx);
+       mac->evp_md = NULL;
+       mac->umac_ctx = NULL;
+}
+
+/* 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_setup(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/mac.h b/mac.h
new file mode 100644 (file)
index 0000000..39f564d
--- /dev/null
+++ b/mac.h
@@ -0,0 +1,30 @@
+/* $OpenBSD: mac.h,v 1.6 2007/06/07 19:37:34 pvalchev 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_setup(Mac *, char *);
+int     mac_init(Mac *);
+u_char *mac_compute(Mac *, u_int32_t, u_char *, int);
+void    mac_clear(Mac *);
diff --git a/match.c b/match.c
new file mode 100644 (file)
index 0000000..2389477
--- /dev/null
+++ b/match.c
@@ -0,0 +1,278 @@
+/* $OpenBSD: match.c,v 1.27 2008/06/10 23:06:19 djm Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ *                    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"
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "match.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 string 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_pattern_list(const char *string, const char *pattern, u_int len,
+    int dolower)
+{
+       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] = dolower && isupper(pattern[i]) ?
+                           (char)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 string. */
+               if (match_pattern(string, 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;
+}
+
+/*
+ * 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)
+{
+       return match_pattern_list(host, pattern, len, 1);
+}
+
+/*
+ * returns 0 if we get a negative match for the hostname or the ip
+ * or if we get no match at all.  returns -1 on error, or 1 on
+ * successful match.
+ */
+int
+match_host_and_ip(const char *host, const char *ipaddr,
+    const char *patterns)
+{
+       int mhost, mip;
+
+       /* error in ipaddr match */
+       if ((mip = addr_match_list(ipaddr, patterns)) == -2)
+               return -1;
+       else if (mip == -1) /* negative ip address match */
+               return 0;
+
+       /* negative hostname match */
+       if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1)
+               return 0;
+       /* 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        40
+#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) : (u_int)(cp - c);
+                               xfree(c);
+                               xfree(s);
+                               return ret;
+                       }
+               }
+       }
+       if (next != NULL)
+               *next = strlen(c);
+       xfree(c);
+       xfree(s);
+       return NULL;
+}
diff --git a/match.h b/match.h
new file mode 100644 (file)
index 0000000..3d7f70f
--- /dev/null
+++ b/match.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: match.h,v 1.15 2010/02/26 20:29:54 djm 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_pattern_list(const char *, const char *, u_int, int);
+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 *);
+
+/* addrmatch.c */
+int     addr_match_list(const char *, const char *);
+int     addr_match_cidr_list(const char *, const char *);
+#endif
diff --git a/md-sha256.c b/md-sha256.c
new file mode 100644 (file)
index 0000000..8c1b3b9
--- /dev/null
@@ -0,0 +1,86 @@
+/* $OpenBSD: md-sha256.c,v 1.5 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2005 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* EVP wrapper for SHA256 */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <openssl/opensslv.h>
+
+#if !defined(HAVE_EVP_SHA256) && (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+
+#include <string.h>
+#include <openssl/evp.h>
+#ifdef HAVE_SHA256_UPDATE
+# ifdef HAVE_SHA2_H
+#  include <sha2.h>
+# elif defined(HAVE_CRYPTO_SHA2_H)
+#  include <crypto/sha2.h>
+# endif
+#endif
+
+const EVP_MD *evp_ssh_sha256(void);
+
+static int
+ssh_sha256_init(EVP_MD_CTX *ctxt)
+{
+       SHA256_Init(ctxt->md_data);
+       return (1);
+}
+
+static int
+ssh_sha256_update(EVP_MD_CTX *ctxt, const void *data, unsigned long len)
+{
+       SHA256_Update(ctxt->md_data, data, len);
+       return (1);
+}
+
+static int
+ssh_sha256_final(EVP_MD_CTX *ctxt, unsigned char *digest)
+{
+       SHA256_Final(digest, ctxt->md_data);
+       return (1);
+}
+
+static int
+ssh_sha256_cleanup(EVP_MD_CTX *ctxt)
+{
+       memset(ctxt->md_data, 0, sizeof(SHA256_CTX));
+       return (1);
+}
+
+const EVP_MD *
+evp_ssh_sha256(void)
+{
+       static EVP_MD ssh_sha256;
+
+       memset(&ssh_sha256, 0, sizeof(ssh_sha256));
+       ssh_sha256.type = NID_undef;
+       ssh_sha256.md_size = SHA256_DIGEST_LENGTH;
+       ssh_sha256.init = ssh_sha256_init;
+       ssh_sha256.update = ssh_sha256_update;
+       ssh_sha256.final = ssh_sha256_final;
+       ssh_sha256.cleanup = ssh_sha256_cleanup;
+       ssh_sha256.block_size = SHA256_BLOCK_LENGTH;
+       ssh_sha256.ctx_size = sizeof(SHA256_CTX);
+
+       return (&ssh_sha256);
+}
+
+#endif /* !defined(HAVE_EVP_SHA256) && (OPENSSL_VERSION_NUMBER >= 0x00907000L) */
+
diff --git a/md5crypt.c b/md5crypt.c
new file mode 100644 (file)
index 0000000..22ef989
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ */
+
+#include "includes.h"
+
+#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
+#include <sys/types.h>
+
+#include <string.h>
+
+#include <openssl/md5.h>
+
+/* 0 ... 63 => ascii - 64 */
+static unsigned char itoa64[] =
+    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *magic = "$1$";
+
+static char *
+to64(unsigned long v, int n)
+{
+       static char buf[5];
+       char *s = buf;
+
+       if (n > 4)
+               return (NULL);
+
+       memset(buf, '\0', sizeof(buf));
+       while (--n >= 0) {
+               *s++ = itoa64[v&0x3f];
+               v >>= 6;
+       }
+
+       return (buf);
+}
+
+int
+is_md5_salt(const char *salt)
+{
+       return (strncmp(salt, magic, strlen(magic)) == 0);
+}
+
+char *
+md5_crypt(const char *pw, const char *salt)
+{
+       static char passwd[120], salt_copy[9], *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)) == 0)
+               sp += strlen(magic);
+
+       /* It stops at the first '$', max 8 chars */
+       for (ep = sp; *ep != '$'; ep++) {
+               if (*ep == '\0' || ep >= (sp + 8))
+                       return (NULL);
+       }
+
+       /* get the length of the true salt */
+       sl = ep - sp;
+
+       /* Stash the salt */
+       memcpy(salt_copy, sp, sl);
+       salt_copy[sl] = '\0';
+
+       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 != 0; i >>= 1)
+               if (i & 1)
+                       MD5_Update(&ctx, final + j, 1);
+               else
+                       MD5_Update(&ctx, pw + j, 1);
+
+       /* Now make the output string */
+       snprintf(passwd, sizeof(passwd), "%s%s$", magic, salt_copy);
+
+       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];
+       strlcat(passwd, to64(l, 4), sizeof(passwd));
+       l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
+       strlcat(passwd, to64(l, 4), sizeof(passwd));
+       l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
+       strlcat(passwd, to64(l, 4), sizeof(passwd));
+       l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
+       strlcat(passwd, to64(l, 4), sizeof(passwd));
+       l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
+       strlcat(passwd, to64(l, 4), sizeof(passwd));
+       l =                    final[11]                ;
+       strlcat(passwd, to64(l, 2), sizeof(passwd));
+
+       /* Don't leave anything around in vm they could use. */
+       memset(final, 0, sizeof(final));
+       memset(salt_copy, 0, sizeof(salt_copy));
+       memset(&ctx, 0, sizeof(ctx));
+       memset(&ctx1, 0, sizeof(ctx1));
+       (void)to64(0, 4);
+
+       return (passwd);
+}
+
+#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
diff --git a/md5crypt.h b/md5crypt.h
new file mode 100644 (file)
index 0000000..2341e2c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ */
+
+/* $Id: md5crypt.h,v 1.4 2003/05/18 14:46:46 djm Exp $ */
+
+#ifndef _MD5CRYPT_H
+#define _MD5CRYPT_H
+
+#include "config.h"
+
+#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
+
+int is_md5_salt(const char *);
+char *md5_crypt(const char *, const char *);
+
+#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
+
+#endif /* MD5CRYPT_H */
diff --git a/mdoc2man.awk b/mdoc2man.awk
new file mode 100644 (file)
index 0000000..80e8d5f
--- /dev/null
@@ -0,0 +1,370 @@
+#!/usr/bin/awk
+#
+# $Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp $
+#
+# Version history:
+#  v4+ Adapted for OpenSSH Portable (see cvs Id and history)
+#  v3, I put the program under a proper license
+#      Dan Nelson <dnelson@allantgroup.com> added .An, .Aq and fixed a typo
+#  v2, fixed to work on GNU awk --posix and MacOS X
+#  v1, first attempt, didn't work on MacOS X
+#
+# Copyright (c) 2003 Peter Stuge <stuge-mdoc2man@cdy.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+BEGIN {
+  optlist=0
+  oldoptlist=0
+  nospace=0
+  synopsis=0
+  reference=0
+  block=0
+  ext=0
+  extopt=0
+  literal=0
+  prenl=0
+  breakw=0
+  line=""
+}
+
+function wtail() {
+  retval=""
+  while(w<nwords) {
+    if(length(retval))
+      retval=retval OFS
+    retval=retval words[++w]
+  }
+  return retval
+}
+
+function add(str) {
+  for(;prenl;prenl--)
+    line=line "\n"
+  line=line str
+}
+
+! /^\./ {
+  for(;prenl;prenl--)
+    print ""
+  print
+  if(literal)
+    print ".br"
+  next
+}
+
+/^\.\\"/ { next }
+
+{
+  option=0
+  parens=0
+  angles=0
+  sub("^\\.","")
+  nwords=split($0,words)
+  for(w=1;w<=nwords;w++) {
+    skip=0
+    if(match(words[w],"^Li|Pf$")) {
+      skip=1
+    } else if(match(words[w],"^Xo$")) {
+      skip=1
+      ext=1
+      if(length(line)&&!(match(line," $")||prenl))
+       add(OFS)
+    } else if(match(words[w],"^Xc$")) {
+      skip=1
+      ext=0
+      if(!extopt)
+       prenl++
+      w=nwords
+    } else if(match(words[w],"^Bd$")) {
+      skip=1
+      if(match(words[w+1],"-literal")) {
+       literal=1
+       prenl++
+       w=nwords
+      }
+    } else if(match(words[w],"^Ed$")) {
+      skip=1
+      literal=0
+    } else if(match(words[w],"^Ns$")) {
+      skip=1
+      if(!nospace)
+       nospace=1
+      sub(" $","",line)
+    } else if(match(words[w],"^No$")) {
+      skip=1
+      sub(" $","",line)
+      add(words[++w])
+    } else if(match(words[w],"^Dq$")) {
+      skip=1
+      add("``")
+      add(words[++w])
+      while(w<nwords&&!match(words[w+1],"^[\\.,]"))
+       add(OFS words[++w])
+      add("''")
+      if(!nospace&&match(words[w+1],"^[\\.,]"))
+       nospace=1
+    } else if(match(words[w],"^Sq|Ql$")) {
+      skip=1
+      add("`" words[++w] "'")
+      if(!nospace&&match(words[w+1],"^[\\.,]"))
+       nospace=1
+    } else if(match(words[w],"^Oo$")) {
+      skip=1
+      extopt=1
+      if(!nospace)
+       nospace=1
+      add("[")
+    } else if(match(words[w],"^Oc$")) {
+      skip=1
+      extopt=0
+      add("]")
+    }
+    if(!skip) {
+      if(!nospace&&length(line)&&!(match(line," $")||prenl))
+       add(OFS)
+      if(nospace==1)
+       nospace=0
+    }
+    if(match(words[w],"^Dd$")) {
+      if(match(words[w+1],"^\\$Mdocdate:")) {
+        w++;
+        if(match(words[w+4],"^\\$$")) {
+          words[w+4] = ""
+        }
+      }
+      date=wtail()
+      next
+    } else if(match(words[w],"^Dt$")) {
+      id=wtail()
+      next
+    } else if(match(words[w],"^Ux$")) {
+      add("UNIX")
+      skip=1
+    } else if(match(words[w],"^Ox$")) {
+      add("OpenBSD")
+      skip=1
+    } else if(match(words[w],"^Os$")) {
+      add(".TH " id " \"" date "\" \"" wtail() "\"")
+    } else if(match(words[w],"^Sh$")) {
+      add(".SH")
+      synopsis=match(words[w+1],"SYNOPSIS")
+    } else if(match(words[w],"^Xr$")) {
+      add("\\fB" words[++w] "\\fP(" words[++w] ")" words[++w])
+    } else if(match(words[w],"^Rs$")) {
+      split("",refauthors)
+      nrefauthors=0
+      reftitle=""
+      refissue=""
+      refdate=""
+      refopt=""
+      refreport=""
+      reference=1
+      next
+    } else if(match(words[w],"^Re$")) {
+      prenl++
+      for(i=nrefauthors-1;i>0;i--) {
+       add(refauthors[i])
+       if(i>1)
+         add(", ")
+      }
+      if(nrefauthors>1)
+       add(" and ")
+      if(nrefauthors>0)
+        add(refauthors[0] ", ")
+      add("\\fI" reftitle "\\fP")
+      if(length(refissue))
+       add(", " refissue)
+      if(length(refreport)) {
+       add(", " refreport)
+      }
+      if(length(refdate))
+       add(", " refdate)
+      if(length(refopt))
+       add(", " refopt)
+      add(".")
+      reference=0
+    } else if(reference) {
+      if(match(words[w],"^%A$")) { refauthors[nrefauthors++]=wtail() }
+      if(match(words[w],"^%T$")) {
+       reftitle=wtail()
+       sub("^\"","",reftitle)
+       sub("\"$","",reftitle)
+      }
+      if(match(words[w],"^%N$")) { refissue=wtail() }
+      if(match(words[w],"^%D$")) { refdate=wtail() }
+      if(match(words[w],"^%O$")) { refopt=wtail() }
+      if(match(words[w],"^%R$")) { refreport=wtail() }
+    } else if(match(words[w],"^Nm$")) {
+      if(synopsis) {
+       add(".br")
+       prenl++
+      }
+      n=words[++w]
+      if(!length(name))
+       name=n
+      if(!length(n))
+       n=name
+      add("\\fB" n "\\fP")
+      if(!nospace&&match(words[w+1],"^[\\.,]"))
+       nospace=1
+    } else if(match(words[w],"^Nd$")) {
+      add("\\- " wtail())
+    } else if(match(words[w],"^Fl$")) {
+      add("\\fB\\-" words[++w] "\\fP")
+      if(!nospace&&match(words[w+1],"^[\\.,]"))
+       nospace=1
+    } else if(match(words[w],"^Ar$")) {
+      add("\\fI")
+      if(w==nwords)
+       add("file ...\\fP")
+      else {
+       add(words[++w] "\\fP")
+       while(match(words[w+1],"^\\|$"))
+         add(OFS words[++w] " \\fI" words[++w] "\\fP")
+      }
+      if(!nospace&&match(words[w+1],"^[\\.,]"))
+       nospace=1
+    } else if(match(words[w],"^Cm$")) {
+      add("\\fB" words[++w] "\\fP")
+      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
+       add(words[++w])
+    } else if(match(words[w],"^Op$")) {
+      option=1
+      if(!nospace)
+       nospace=1
+      add("[")
+    } else if(match(words[w],"^Pp$")) {
+      prenl++
+    } else if(match(words[w],"^An$")) {
+      prenl++
+    } else if(match(words[w],"^Ss$")) {
+      add(".SS")
+    } else if(match(words[w],"^Pa$")&&!option) {
+      add("\\fI")
+      w++
+      if(match(words[w],"^\\."))
+       add("\\&")
+      add(words[w] "\\fP")
+      while(w<nwords&&match(words[w+1],"^[\\.,:;)]"))
+       add(words[++w])
+    } else if(match(words[w],"^Dv$")) {
+      add(".BR")
+    } else if(match(words[w],"^Em|Ev$")) {
+      add(".IR")
+    } else if(match(words[w],"^Pq$")) {
+      add("(")
+      nospace=1
+      parens=1
+    } else if(match(words[w],"^Aq$")) {
+      add("<")
+      nospace=1
+      angles=1
+    } else if(match(words[w],"^S[xy]$")) {
+      add(".B " wtail())
+    } else if(match(words[w],"^Ic$")) {
+      plain=1
+      add("\\fB")
+      while(w<nwords) {
+       w++
+       if(match(words[w],"^Op$")) {
+         w++
+         add("[")
+         words[nwords]=words[nwords] "]"
+       }
+       if(match(words[w],"^Ar$")) {
+         add("\\fI" words[++w] "\\fP")
+       } else if(match(words[w],"^[\\.,]")) {
+         sub(" $","",line)
+         if(plain) {
+           add("\\fP")
+           plain=0
+         }
+         add(words[w])
+       } else {
+         if(!plain) {
+           add("\\fB")
+           plain=1
+         }
+         add(words[w])
+       }
+       if(!nospace)
+         add(OFS)
+      }
+      sub(" $","",line)
+      if(plain)
+       add("\\fP")
+    } else if(match(words[w],"^Bl$")) {
+      oldoptlist=optlist
+      if(match(words[w+1],"-bullet"))
+       optlist=1
+      else if(match(words[w+1],"-enum")) {
+       optlist=2
+       enum=0
+      } else if(match(words[w+1],"-tag"))
+       optlist=3
+      else if(match(words[w+1],"-item"))
+       optlist=4
+      else if(match(words[w+1],"-bullet"))
+       optlist=1
+      w=nwords
+    } else if(match(words[w],"^El$")) {
+      optlist=oldoptlist
+    } else if(match(words[w],"^Bk$")) {
+      if(match(words[w+1],"-words")) {
+       w++
+       breakw=1
+      }
+    } else if(match(words[w],"^Ek$")) {
+      breakw=0
+    } else if(match(words[w],"^It$")&&optlist) {
+      if(optlist==1)
+       add(".IP \\(bu")
+      else if(optlist==2)
+       add(".IP " ++enum ".")
+      else if(optlist==3) {
+       add(".TP")
+       prenl++
+       if(match(words[w+1],"^Pa$|^Ev$")) {
+         add(".B")
+         w++
+       }
+      } else if(optlist==4)
+       add(".IP")
+    } else if(match(words[w],"^Sm$")) {
+      if(match(words[w+1],"off"))
+       nospace=2
+      else if(match(words[w+1],"on"))
+       nospace=0
+      w++
+    } else if(!skip) {
+      add(words[w])
+    }
+  }
+  if(match(line,"^\\.[^a-zA-Z]"))
+    sub("^\\.","",line)
+  if(parens)
+    add(")")
+  if(angles)
+    add(">")
+  if(option)
+    add("]")
+  if(ext&&!extopt&&!match(line," $"))
+    add(OFS)
+  if(!ext&&!extopt&&length(line)) {
+    print line
+    prenl=0
+    line=""
+  }
+}
diff --git a/misc.c b/misc.c
new file mode 100644 (file)
index 0000000..919b04e
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,998 @@
+/* $OpenBSD: misc.c,v 1.84 2010/11/21 01:01:13 djm Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2005,2006 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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#include <pwd.h>
+#endif
+#ifdef SSH_TUN_OPENBSD
+#include <net/if.h>
+#endif
+
+#include "xmalloc.h"
+#include "misc.h"
+#include "log.h"
+#include "ssh.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 */
+int
+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 (-1);
+       }
+       if (val & O_NONBLOCK) {
+               debug3("fd %d is O_NONBLOCK", fd);
+               return (0);
+       }
+       debug2("fd %d setting O_NONBLOCK", fd);
+       val |= O_NONBLOCK;
+       if (fcntl(fd, F_SETFL, val) == -1) {
+               debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
+                   strerror(errno));
+               return (-1);
+       }
+       return (0);
+}
+
+int
+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 (-1);
+       }
+       if (!(val & O_NONBLOCK)) {
+               debug3("fd %d is not O_NONBLOCK", fd);
+               return (0);
+       }
+       debug("fd %d clearing O_NONBLOCK", fd);
+       val &= ~O_NONBLOCK;
+       if (fcntl(fd, F_SETFL, val) == -1) {
+               debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
+                   fd, strerror(errno));
+               return (-1);
+       }
+       return (0);
+}
+
+const char *
+ssh_gai_strerror(int gaierr)
+{
+       if (gaierr == EAI_SYSTEM)
+               return strerror(errno);
+       return gai_strerror(gaierr);
+}
+
+/* disable nagle on socket */
+void
+set_nodelay(int fd)
+{
+       int opt;
+       socklen_t optlen;
+
+       optlen = sizeof opt;
+       if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
+               debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
+               return;
+       }
+       if (opt == 1) {
+               debug2("fd %d is TCP_NODELAY", fd);
+               return;
+       }
+       opt = 1;
+       debug2("fd %d setting TCP_NODELAY", fd);
+       if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
+               error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
+}
+
+/* Characters considered whitespace in strsep calls. */
+#define WHITESPACE " \t\r\n"
+#define QUOTE  "\""
+
+/* 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 QUOTE "=");
+       if (*s == NULL)
+               return (old);
+
+       if (*s[0] == '\"') {
+               memmove(*s, *s + 1, strlen(*s)); /* move nul too */
+               /* Find matching quote */
+               if ((*s = strpbrk(*s, QUOTE)) == NULL) {
+                       return (NULL);          /* no matching quote */
+               } else {
+                       *s[0] = '\0';
+                       *s += strspn(*s + 1, WHITESPACE) + 1;
+                       return (old);
+               }
+       }
+
+       /* Allow only one '=' to be skipped */
+       if (*s[0] == '=')
+               wspace = 1;
+       *s[0] = '\0';
+
+       /* Skip any extra whitespace after first token */
+       *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 = xcalloc(1, 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 -1 if invalid.
+ */
+int
+a2port(const char *s)
+{
+       long long port;
+       const char *errstr;
+
+       port = strtonum(s, 0, 65535, &errstr);
+       if (errstr != NULL)
+               return -1;
+       return (int)port;
+}
+
+int
+a2tun(const char *s, int *remote)
+{
+       const char *errstr = NULL;
+       char *sp, *ep;
+       int tun;
+
+       if (remote != NULL) {
+               *remote = SSH_TUNID_ANY;
+               sp = xstrdup(s);
+               if ((ep = strchr(sp, ':')) == NULL) {
+                       xfree(sp);
+                       return (a2tun(s, NULL));
+               }
+               ep[0] = '\0'; ep++;
+               *remote = a2tun(ep, NULL);
+               tun = a2tun(sp, NULL);
+               xfree(sp);
+               return (*remote == SSH_TUNID_ERR ? *remote : tun);
+       }
+
+       if (strcasecmp(s, "any") == 0)
+               return (SSH_TUNID_ANY);
+
+       tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr);
+       if (errstr != NULL)
+               return (SSH_TUNID_ERR);
+
+       return (tun);
+}
+
+#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--;
+                       break;
+               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;
+}
+
+/*
+ * Returns a standardized host+port identifier string.
+ * Caller must free returned string.
+ */
+char *
+put_host_port(const char *host, u_short port)
+{
+       char *hoststr;
+
+       if (port == 0 || port == SSH_DEFAULT_PORT)
+               return(xstrdup(host));
+       if (asprintf(&hoststr, "[%s]:%d", host, (int)port) < 0)
+               fatal("put_host_port: asprintf: %s", strerror(errno));
+       debug3("put_host_port: %s", hoststr);
+       return hoststr;
+}
+
+/*
+ * Search for next delimiter between hostnames/addresses and ports.
+ * Argument may be modified (for termination).
+ * Returns *cp if parsing succeeds.
+ * *cp is set to the start of the next delimiter, if one was found.
+ * If this is the last field, *cp is set to NULL.
+ */
+char *
+hpdelim(char **cp)
+{
+       char *s, *old;
+
+       if (cp == NULL || *cp == NULL)
+               return NULL;
+
+       old = s = *cp;
+       if (*s == '[') {
+               if ((s = strchr(s, ']')) == NULL)
+                       return NULL;
+               else
+                       s++;
+       } else if ((s = strpbrk(s, ":/")) == NULL)
+               s = *cp + strlen(*cp); /* skip to end (see first case below) */
+
+       switch (*s) {
+       case '\0':
+               *cp = NULL;     /* no more fields*/
+               break;
+
+       case ':':
+       case '/':
+               *s = '\0';      /* terminate */
+               *cp = s + 1;
+               break;
+
+       default:
+               return NULL;
+       }
+
+       return old;
+}
+
+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 NULL;
+       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 NULL;
+       }
+       return NULL;
+}
+
+/* function to assist building execv() arguments */
+void
+addargs(arglist *args, char *fmt, ...)
+{
+       va_list ap;
+       char *cp;
+       u_int nalloc;
+       int r;
+
+       va_start(ap, fmt);
+       r = vasprintf(&cp, fmt, ap);
+       va_end(ap);
+       if (r == -1)
+               fatal("addargs: argument too long");
+
+       nalloc = args->nalloc;
+       if (args->list == NULL) {
+               nalloc = 32;
+               args->num = 0;
+       } else if (args->num+2 >= nalloc)
+               nalloc *= 2;
+
+       args->list = xrealloc(args->list, nalloc, sizeof(char *));
+       args->nalloc = nalloc;
+       args->list[args->num++] = cp;
+       args->list[args->num] = NULL;
+}
+
+void
+replacearg(arglist *args, u_int which, char *fmt, ...)
+{
+       va_list ap;
+       char *cp;
+       int r;
+
+       va_start(ap, fmt);
+       r = vasprintf(&cp, fmt, ap);
+       va_end(ap);
+       if (r == -1)
+               fatal("replacearg: argument too long");
+
+       if (which >= args->num)
+               fatal("replacearg: tried to replace invalid arg %d >= %d",
+                   which, args->num);
+       xfree(args->list[which]);
+       args->list[which] = cp;
+}
+
+void
+freeargs(arglist *args)
+{
+       u_int i;
+
+       if (args->list != NULL) {
+               for (i = 0; i < args->num; i++)
+                       xfree(args->list[i]);
+               xfree(args->list);
+               args->nalloc = args->num = 0;
+               args->list = NULL;
+       }
+}
+
+/*
+ * Expands tildes in the file name.  Returns data allocated by xmalloc.
+ * Warning: this calls getpw*.
+ */
+char *
+tilde_expand_filename(const char *filename, uid_t uid)
+{
+       const char *path;
+       char user[128], ret[MAXPATHLEN];
+       struct passwd *pw;
+       u_int len, slash;
+
+       if (*filename != '~')
+               return (xstrdup(filename));
+       filename++;
+
+       path = strchr(filename, '/');
+       if (path != NULL && path > filename) {          /* ~user/path */
+               slash = path - filename;
+               if (slash > sizeof(user) - 1)
+                       fatal("tilde_expand_filename: ~username too long");
+               memcpy(user, filename, slash);
+               user[slash] = '\0';
+               if ((pw = getpwnam(user)) == NULL)
+                       fatal("tilde_expand_filename: No such user %s", user);
+       } else if ((pw = getpwuid(uid)) == NULL)        /* ~/path */
+               fatal("tilde_expand_filename: No such uid %ld", (long)uid);
+
+       if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
+               fatal("tilde_expand_filename: Path too long");
+
+       /* Make sure directory has a trailing '/' */
+       len = strlen(pw->pw_dir);
+       if ((len == 0 || pw->pw_dir[len - 1] != '/') &&
+           strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))
+               fatal("tilde_expand_filename: Path too long");
+
+       /* Skip leading '/' from specified path */
+       if (path != NULL)
+               filename = path + 1;
+       if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret))
+               fatal("tilde_expand_filename: Path too long");
+
+       return (xstrdup(ret));
+}
+
+/*
+ * Expand a string with a set of %[char] escapes. A number of escapes may be
+ * specified as (char *escape_chars, char *replacement) pairs. The list must
+ * be terminated by a NULL escape_char. Returns replaced string in memory
+ * allocated by xmalloc.
+ */
+char *
+percent_expand(const char *string, ...)
+{
+#define EXPAND_MAX_KEYS        16
+       u_int num_keys, i, j;
+       struct {
+               const char *key;
+               const char *repl;
+       } keys[EXPAND_MAX_KEYS];
+       char buf[4096];
+       va_list ap;
+
+       /* Gather keys */
+       va_start(ap, string);
+       for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
+               keys[num_keys].key = va_arg(ap, char *);
+               if (keys[num_keys].key == NULL)
+                       break;
+               keys[num_keys].repl = va_arg(ap, char *);
+               if (keys[num_keys].repl == NULL)
+                       fatal("%s: NULL replacement", __func__);
+       }
+       if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL)
+               fatal("%s: too many keys", __func__);
+       va_end(ap);
+
+       /* Expand string */
+       *buf = '\0';
+       for (i = 0; *string != '\0'; string++) {
+               if (*string != '%') {
+ append:
+                       buf[i++] = *string;
+                       if (i >= sizeof(buf))
+                               fatal("%s: string too long", __func__);
+                       buf[i] = '\0';
+                       continue;
+               }
+               string++;
+               /* %% case */
+               if (*string == '%')
+                       goto append;
+               for (j = 0; j < num_keys; j++) {
+                       if (strchr(keys[j].key, *string) != NULL) {
+                               i = strlcat(buf, keys[j].repl, sizeof(buf));
+                               if (i >= sizeof(buf))
+                                       fatal("%s: string too long", __func__);
+                               break;
+                       }
+               }
+               if (j >= num_keys)
+                       fatal("%s: unknown key %%%c", __func__, *string);
+       }
+       return (xstrdup(buf));
+#undef EXPAND_MAX_KEYS
+}
+
+/*
+ * Read an entire line from a public key file into a static buffer, discarding
+ * lines that exceed the buffer size.  Returns 0 on success, -1 on failure.
+ */
+int
+read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
+   u_long *lineno)
+{
+       while (fgets(buf, bufsz, f) != NULL) {
+               if (buf[0] == '\0')
+                       continue;
+               (*lineno)++;
+               if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
+                       return 0;
+               } else {
+                       debug("%s: %s line %lu exceeds size limit", __func__,
+                           filename, *lineno);
+                       /* discard remainder of line */
+                       while (fgetc(f) != '\n' && !feof(f))
+                               ;       /* nothing */
+               }
+       }
+       return -1;
+}
+
+int
+tun_open(int tun, int mode)
+{
+#if defined(CUSTOM_SYS_TUN_OPEN)
+       return (sys_tun_open(tun, mode));
+#elif defined(SSH_TUN_OPENBSD)
+       struct ifreq ifr;
+       char name[100];
+       int fd = -1, sock;
+
+       /* Open the tunnel device */
+       if (tun <= SSH_TUNID_MAX) {
+               snprintf(name, sizeof(name), "/dev/tun%d", tun);
+               fd = open(name, O_RDWR);
+       } else if (tun == SSH_TUNID_ANY) {
+               for (tun = 100; tun >= 0; tun--) {
+                       snprintf(name, sizeof(name), "/dev/tun%d", tun);
+                       if ((fd = open(name, O_RDWR)) >= 0)
+                               break;
+               }
+       } else {
+               debug("%s: invalid tunnel %u", __func__, tun);
+               return (-1);
+       }
+
+       if (fd < 0) {
+               debug("%s: %s open failed: %s", __func__, name, strerror(errno));
+               return (-1);
+       }
+
+       debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
+
+       /* Set the tunnel device operation mode */
+       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun);
+       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
+               goto failed;
+
+       if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
+               goto failed;
+
+       /* Set interface mode */
+       ifr.ifr_flags &= ~IFF_UP;
+       if (mode == SSH_TUNMODE_ETHERNET)
+               ifr.ifr_flags |= IFF_LINK0;
+       else
+               ifr.ifr_flags &= ~IFF_LINK0;
+       if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
+               goto failed;
+
+       /* Bring interface up */
+       ifr.ifr_flags |= IFF_UP;
+       if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
+               goto failed;
+
+       close(sock);
+       return (fd);
+
+ failed:
+       if (fd >= 0)
+               close(fd);
+       if (sock >= 0)
+               close(sock);
+       debug("%s: failed to set %s mode %d: %s", __func__, name,
+           mode, strerror(errno));
+       return (-1);
+#else
+       error("Tunnel interfaces are not supported on this platform");
+       return (-1);
+#endif
+}
+
+void
+sanitise_stdfd(void)
+{
+       int nullfd, dupfd;
+
+       if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+               fprintf(stderr, "Couldn't open /dev/null: %s\n",
+                   strerror(errno));
+               exit(1);
+       }
+       while (++dupfd <= 2) {
+               /* Only clobber closed fds */
+               if (fcntl(dupfd, F_GETFL, 0) >= 0)
+                       continue;
+               if (dup2(nullfd, dupfd) == -1) {
+                       fprintf(stderr, "dup2: %s\n", strerror(errno));
+                       exit(1);
+               }
+       }
+       if (nullfd > 2)
+               close(nullfd);
+}
+
+char *
+tohex(const void *vp, size_t l)
+{
+       const u_char *p = (const u_char *)vp;
+       char b[3], *r;
+       size_t i, hl;
+
+       if (l > 65536)
+               return xstrdup("tohex: length > 65536");
+
+       hl = l * 2 + 1;
+       r = xcalloc(1, hl);
+       for (i = 0; i < l; i++) {
+               snprintf(b, sizeof(b), "%02x", p[i]);
+               strlcat(r, b, hl);
+       }
+       return (r);
+}
+
+u_int64_t
+get_u64(const void *vp)
+{
+       const u_char *p = (const u_char *)vp;
+       u_int64_t v;
+
+       v  = (u_int64_t)p[0] << 56;
+       v |= (u_int64_t)p[1] << 48;
+       v |= (u_int64_t)p[2] << 40;
+       v |= (u_int64_t)p[3] << 32;
+       v |= (u_int64_t)p[4] << 24;
+       v |= (u_int64_t)p[5] << 16;
+       v |= (u_int64_t)p[6] << 8;
+       v |= (u_int64_t)p[7];
+
+       return (v);
+}
+
+u_int32_t
+get_u32(const void *vp)
+{
+       const u_char *p = (const u_char *)vp;
+       u_int32_t v;
+
+       v  = (u_int32_t)p[0] << 24;
+       v |= (u_int32_t)p[1] << 16;
+       v |= (u_int32_t)p[2] << 8;
+       v |= (u_int32_t)p[3];
+
+       return (v);
+}
+
+u_int16_t
+get_u16(const void *vp)
+{
+       const u_char *p = (const u_char *)vp;
+       u_int16_t v;
+
+       v  = (u_int16_t)p[0] << 8;
+       v |= (u_int16_t)p[1];
+
+       return (v);
+}
+
+void
+put_u64(void *vp, u_int64_t v)
+{
+       u_char *p = (u_char *)vp;
+
+       p[0] = (u_char)(v >> 56) & 0xff;
+       p[1] = (u_char)(v >> 48) & 0xff;
+       p[2] = (u_char)(v >> 40) & 0xff;
+       p[3] = (u_char)(v >> 32) & 0xff;
+       p[4] = (u_char)(v >> 24) & 0xff;
+       p[5] = (u_char)(v >> 16) & 0xff;
+       p[6] = (u_char)(v >> 8) & 0xff;
+       p[7] = (u_char)v & 0xff;
+}
+
+void
+put_u32(void *vp, u_int32_t v)
+{
+       u_char *p = (u_char *)vp;
+
+       p[0] = (u_char)(v >> 24) & 0xff;
+       p[1] = (u_char)(v >> 16) & 0xff;
+       p[2] = (u_char)(v >> 8) & 0xff;
+       p[3] = (u_char)v & 0xff;
+}
+
+
+void
+put_u16(void *vp, u_int16_t v)
+{
+       u_char *p = (u_char *)vp;
+
+       p[0] = (u_char)(v >> 8) & 0xff;
+       p[1] = (u_char)v & 0xff;
+}
+
+void
+ms_subtract_diff(struct timeval *start, int *ms)
+{
+       struct timeval diff, finish;
+
+       gettimeofday(&finish, NULL);
+       timersub(&finish, start, &diff);        
+       *ms -= (diff.tv_sec * 1000) + (diff.tv_usec / 1000);
+}
+
+void
+ms_to_timeval(struct timeval *tv, int ms)
+{
+       if (ms < 0)
+               ms = 0;
+       tv->tv_sec = ms / 1000;
+       tv->tv_usec = (ms % 1000) * 1000;
+}
+
+void
+bandwidth_limit_init(struct bwlimit *bw, u_int64_t kbps, size_t buflen)
+{
+       bw->buflen = buflen;
+       bw->rate = kbps;
+       bw->thresh = bw->rate;
+       bw->lamt = 0;
+       timerclear(&bw->bwstart);
+       timerclear(&bw->bwend);
+}      
+
+/* Callback from read/write loop to insert bandwidth-limiting delays */
+void
+bandwidth_limit(struct bwlimit *bw, size_t read_len)
+{
+       u_int64_t waitlen;
+       struct timespec ts, rm;
+
+       if (!timerisset(&bw->bwstart)) {
+               gettimeofday(&bw->bwstart, NULL);
+               return;
+       }
+
+       bw->lamt += read_len;
+       if (bw->lamt < bw->thresh)
+               return;
+
+       gettimeofday(&bw->bwend, NULL);
+       timersub(&bw->bwend, &bw->bwstart, &bw->bwend);
+       if (!timerisset(&bw->bwend))
+               return;
+
+       bw->lamt *= 8;
+       waitlen = (double)1000000L * bw->lamt / bw->rate;
+
+       bw->bwstart.tv_sec = waitlen / 1000000L;
+       bw->bwstart.tv_usec = waitlen % 1000000L;
+
+       if (timercmp(&bw->bwstart, &bw->bwend, >)) {
+               timersub(&bw->bwstart, &bw->bwend, &bw->bwend);
+
+               /* Adjust the wait time */
+               if (bw->bwend.tv_sec) {
+                       bw->thresh /= 2;
+                       if (bw->thresh < bw->buflen / 4)
+                               bw->thresh = bw->buflen / 4;
+               } else if (bw->bwend.tv_usec < 10000) {
+                       bw->thresh *= 2;
+                       if (bw->thresh > bw->buflen * 8)
+                               bw->thresh = bw->buflen * 8;
+               }
+
+               TIMEVAL_TO_TIMESPEC(&bw->bwend, &ts);
+               while (nanosleep(&ts, &rm) == -1) {
+                       if (errno != EINTR)
+                               break;
+                       ts = rm;
+               }
+       }
+
+       bw->lamt = 0;
+       gettimeofday(&bw->bwstart, NULL);
+}
+
+/* Make a template filename for mk[sd]temp() */
+void
+mktemp_proto(char *s, size_t len)
+{
+       const char *tmpdir;
+       int r;
+
+       if ((tmpdir = getenv("TMPDIR")) != NULL) {
+               r = snprintf(s, len, "%s/ssh-XXXXXXXXXXXX", tmpdir);
+               if (r > 0 && (size_t)r < len)
+                       return;
+       }
+       r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX");
+       if (r < 0 || (size_t)r >= len)
+               fatal("%s: template string too short", __func__);
+}
+
+static const struct {
+       const char *name;
+       int value;
+} ipqos[] = {
+       { "af11", IPTOS_DSCP_AF11 },
+       { "af12", IPTOS_DSCP_AF12 },
+       { "af13", IPTOS_DSCP_AF13 },
+       { "af14", IPTOS_DSCP_AF21 },
+       { "af22", IPTOS_DSCP_AF22 },
+       { "af23", IPTOS_DSCP_AF23 },
+       { "af31", IPTOS_DSCP_AF31 },
+       { "af32", IPTOS_DSCP_AF32 },
+       { "af33", IPTOS_DSCP_AF33 },
+       { "af41", IPTOS_DSCP_AF41 },
+       { "af42", IPTOS_DSCP_AF42 },
+       { "af43", IPTOS_DSCP_AF43 },
+       { "cs0", IPTOS_DSCP_CS0 },
+       { "cs1", IPTOS_DSCP_CS1 },
+       { "cs2", IPTOS_DSCP_CS2 },
+       { "cs3", IPTOS_DSCP_CS3 },
+       { "cs4", IPTOS_DSCP_CS4 },
+       { "cs5", IPTOS_DSCP_CS5 },
+       { "cs6", IPTOS_DSCP_CS6 },
+       { "cs7", IPTOS_DSCP_CS7 },
+       { "ef", IPTOS_DSCP_EF },
+       { "lowdelay", IPTOS_LOWDELAY },
+       { "throughput", IPTOS_THROUGHPUT },
+       { "reliability", IPTOS_RELIABILITY },
+       { NULL, -1 }
+};
+
+int
+parse_ipqos(const char *cp)
+{
+       u_int i;
+       char *ep;
+       long val;
+
+       if (cp == NULL)
+               return -1;
+       for (i = 0; ipqos[i].name != NULL; i++) {
+               if (strcasecmp(cp, ipqos[i].name) == 0)
+                       return ipqos[i].value;
+       }
+       /* Try parsing as an integer */
+       val = strtol(cp, &ep, 0);
+       if (*cp == '\0' || *ep != '\0' || val < 0 || val > 255)
+               return -1;
+       return val;
+}
+
+void
+sock_set_v6only(int s)
+{
+#ifdef IPV6_V6ONLY
+       int on = 1;
+
+       debug3("%s: set socket %d IPV6_V6ONLY", __func__, s);
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)
+               error("setsockopt IPV6_V6ONLY: %s", strerror(errno));
+#endif
+}
diff --git a/misc.h b/misc.h
new file mode 100644 (file)
index 0000000..65cf4a6
--- /dev/null
+++ b/misc.h
@@ -0,0 +1,105 @@
+/* $OpenBSD: misc.h,v 1.47 2010/11/21 01:01:13 djm 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 _MISC_H
+#define _MISC_H
+
+/* misc.c */
+
+char   *chop(char *);
+char   *strdelim(char **);
+int     set_nonblock(int);
+int     unset_nonblock(int);
+void    set_nodelay(int);
+int     a2port(const char *);
+int     a2tun(const char *, int *);
+char   *put_host_port(const char *, u_short);
+char   *hpdelim(char **);
+char   *cleanhostname(char *);
+char   *colon(char *);
+long    convtime(const char *);
+char   *tilde_expand_filename(const char *, uid_t);
+char   *percent_expand(const char *, ...) __attribute__((__sentinel__));
+char   *tohex(const void *, size_t);
+void    sanitise_stdfd(void);
+void    ms_subtract_diff(struct timeval *, int *);
+void    ms_to_timeval(struct timeval *, int);
+void    sock_set_v6only(int);
+
+struct passwd *pwcopy(struct passwd *);
+const char *ssh_gai_strerror(int);
+
+typedef struct arglist arglist;
+struct arglist {
+       char    **list;
+       u_int   num;
+       u_int   nalloc;
+};
+void    addargs(arglist *, char *, ...)
+            __attribute__((format(printf, 2, 3)));
+void    replacearg(arglist *, u_int, char *, ...)
+            __attribute__((format(printf, 3, 4)));
+void    freeargs(arglist *);
+
+int     tun_open(int, int);
+
+/* Common definitions for ssh tunnel device forwarding */
+#define SSH_TUNMODE_NO         0x00
+#define SSH_TUNMODE_POINTOPOINT        0x01
+#define SSH_TUNMODE_ETHERNET   0x02
+#define SSH_TUNMODE_DEFAULT    SSH_TUNMODE_POINTOPOINT
+#define SSH_TUNMODE_YES                (SSH_TUNMODE_POINTOPOINT|SSH_TUNMODE_ETHERNET)
+
+#define SSH_TUNID_ANY          0x7fffffff
+#define SSH_TUNID_ERR          (SSH_TUNID_ANY - 1)
+#define SSH_TUNID_MAX          (SSH_TUNID_ANY - 2)
+
+/* Functions to extract or store big-endian words of various sizes */
+u_int64_t      get_u64(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 8)));
+u_int32_t      get_u32(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 4)));
+u_int16_t      get_u16(const void *)
+    __attribute__((__bounded__( __minbytes__, 1, 2)));
+void           put_u64(void *, u_int64_t)
+    __attribute__((__bounded__( __minbytes__, 1, 8)));
+void           put_u32(void *, u_int32_t)
+    __attribute__((__bounded__( __minbytes__, 1, 4)));
+void           put_u16(void *, u_int16_t)
+    __attribute__((__bounded__( __minbytes__, 1, 2)));
+
+struct bwlimit {
+       size_t buflen;
+       u_int64_t rate, thresh, lamt;
+       struct timeval bwstart, bwend;
+};
+
+void bandwidth_limit_init(struct bwlimit *, u_int64_t, size_t);
+void bandwidth_limit(struct bwlimit *, size_t);
+
+int parse_ipqos(const char *);
+void mktemp_proto(char *, size_t);
+
+/* readpass.c */
+
+#define RP_ECHO                        0x0001
+#define RP_ALLOW_STDIN         0x0002
+#define RP_ALLOW_EOF           0x0004
+#define RP_USE_ASKPASS         0x0008
+
+char   *read_passphrase(const char *, int);
+int     ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
+int     read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
+
+#endif /* _MISC_H */
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755 (executable)
index 0000000..47d5f43
--- /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: mkinstalldirs,v 1.2 2003/11/21 12:48:55 djm Exp $
+
+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/moduli b/moduli
new file mode 100644 (file)
index 0000000..65d2814
--- /dev/null
+++ b/moduli
@@ -0,0 +1,188 @@
+#    $OpenBSD: moduli,v 1.4 2008/01/01 08:51:20 dtucker Exp $
+# Time Type Tests Tries Size Generator Modulus
+20060827013849 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE261778F3
+20060827013906 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE261CC47B
+20060827013924 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE2621AFA3
+20060827014045 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26551B8B
+20060827014056 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26556A27
+20060827014115 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE265B7273
+20060827014137 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26644D77
+20060827014203 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26717773
+20060827014214 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26722EBB
+20060827014312 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26961C8B
+20060827014407 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26BA7BBF
+20060827014418 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26BAC107
+20060827014436 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26C05207
+20060827014515 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26D48C73
+20060827014527 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26D65CD7
+20060827014538 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26D7096F
+20060827014607 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26E3760B
+20060827014626 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26EAF29F
+20060827014637 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26EBCF4F
+20060827014653 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE26F0D6BB
+20060827014732 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27088963
+20060827014835 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27320A73
+20060827014915 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27486FA3
+20060827014926 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE2748FD9F
+20060827014940 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE274BB323
+20060827014956 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE274F8F7F
+20060827015028 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE275C008F
+20060827015112 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE2776D9EF
+20060827015134 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27809AA3
+20060827015146 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27826DFB
+20060827015200 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE2785363F
+20060827015231 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27951F4F
+20060827015246 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27991903
+20060827015300 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE279C7B37
+20060827015329 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27AB4843
+20060827015347 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27B0F9D7
+20060827015359 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27B24D5B
+20060827015430 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27C2CE27
+20060827015449 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27CA3BA3
+20060827015546 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27E90A07
+20060827015607 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27F116BF
+20060827015630 2 6 100 1023 5 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE27FBB66F
+20060827015649 2 6 100 1023 2 DE49FC9069994C379D2B6563EFD37EFAE6785EEB1DD0A12B090AAC272B22DF8C64A4A2AB7B99CE0B77A9A52E0833D52D53B258CEDFFD175DC8A3766A9B9807362646DC9215628C3F4AF0E08D00AB60A3B9E55BAE47E82651DA0C15A27355DDB06365CAE1DDDE4C0C97DC9942FD65E9867FA50E72E1C785411EDD28DE2803E313
+20060827024302 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AD6C361B
+20060827024350 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AD6F7E93
+20060827024537 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AD7DE4BB
+20060827025000 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6ADB6D4D7
+20060827025429 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6ADEF2D8B
+20060827025612 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6ADFCCB13
+20060827030138 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AE41E89B
+20060827030223 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AE44A263
+20060827030555 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AE6FD2A7
+20060827031244 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AECC68C3
+20060827031437 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AEDFB4EB
+20060827031602 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AEEB07E7
+20060827032434 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AF5B1533
+20060827032933 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AF99D5D3
+20060827033028 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AF9CF037
+20060827033120 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AFA14BBF
+20060827033331 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AFB9FD2B
+20060827033555 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AFD32F8B
+20060827033806 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6AFEBB7DB
+20060827034045 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B009C8D3
+20060827034214 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0177447
+20060827034316 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B01EFC27
+20060827034514 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0313F9B
+20060827035109 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B07D542B
+20060827035412 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0A3485F
+20060827035525 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0AAF3BB
+20060827035829 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0CFE04F
+20060827040101 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B0E988E7
+20060827040504 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B11D001B
+20060827040746 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B13A45DF
+20060827041350 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B188B89F
+20060827041513 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B193B2EB
+20060827041621 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B19B9807
+20060827041657 2 6 100 1535 5 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B19C0107
+20060827041817 2 6 100 1535 2 DF09936D6567325CD4EDE975CB3B9BFFB26C5EC31A71ABA0931BE89AEEB81A531708540B7EA03875E5DF4935ED021F3955D5C941BB682DBDA5425F4EF84DD1F42C6DCC5E313D64DE5B658682A51785102358771DDB6C2B86079C3D0A4EB0DA149E7B2CAC0AC254FFBCD82DF11D74A4E0BBE3FA0AD0675B8A3C6E794E943B7F3799BA8C0F80D602F85D3032D206A96EB16DAFD2C036F8D4F3DA1CCDB2178F08BD851D7BB1C2E964F48F91B2546916E76A80D8E16F700E1FC194308DD6B1A6BE4B
+20060827052122 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C77E8ED3
+20060827055248 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C8549C07
+20060827055453 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C85B17DF
+20060827060456 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C899BBE7
+20060827061203 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C8C362B3
+20060827061433 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C8CC69F7
+20060827061904 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C8E44BC7
+20060827062255 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C8F6B23F
+20060827063052 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C926C817
+20060827063354 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C9351ABF
+20060827063925 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C9541A43
+20060827064904 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C98CFAE7
+20060827070314 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C9E30823
+20060827070806 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532C9F90C33
+20060827071119 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CA04D477
+20060827072534 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CA5A1ADB
+20060827073212 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CA7E88A3
+20060827073641 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CA93A193
+20060827073850 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CA999B57
+20060827080040 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CB21505F
+20060827080817 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CB4C2F97
+20060827083711 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CC0FAA7F
+20060827084308 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CC30FD83
+20060827084830 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CC4EFB67
+20060827085653 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CC8152FB
+20060827090522 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CCB5AE6B
+20060827092253 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CD252FCB
+20060827095916 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CE117E2F
+20060827100246 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CE2087CB
+20060827102041 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CE925537
+20060827102556 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CEAF2A27
+20060827103749 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CEF9826F
+20060827103917 2 6 100 2047 5 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CEFBC467
+20060827104611 2 6 100 2047 2 C038282DE061BE1AD34F31325EFE9B1D8520DB14276CEB61FE3A2CB8D77FFE3B9A067505205BBA8353847FD2EA1E2471E4294862A5D4C4F9A2B80F9DA0619327CDBF2EB608B0B5549294A955972AA3512821B24782DD8AB97B53AAB04B48180394ABFBC4DCF9B819FC0CB5AC1275AC5F16EC378163501E4B27D49C67F660333888F1D503B96FA9C6C880543D8B5F04D70FE508FFCA161798AD32015145B8E9AD43AAB48ADA81FD1E5A8EA7711A8FF57EC7C4C081B47FAB0C2E9FA468E70DD6700F3412224890D5E99527A596CE635195F3A6D35E563BF4892DF2C79C809704411018D919102D12CB112CE1E66EBF5DB9F409F6C82A6A6E1E21E23532CF24A6E3
+20060827130320 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFA80B3F
+20060827132001 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFC2F2A3
+20060827132659 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFC83DE3
+20060827133231 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFCAE263
+20060827134212 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFD5D943
+20060827135606 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084EFEAD4AB
+20060827142452 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F01CBFBB
+20060827185212 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F24CFF67
+20060827190158 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F2599507
+20060827202730 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F305315B
+20060827213252 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F38A5B63
+20060827214322 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F3987FC7
+20060827214825 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F39A3CDB
+20060827232520 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F46375AB
+20060828030405 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F62B17EB
+20060828043230 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F6E0BB4F
+20060828081338 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F8A9B0EF
+20060828083613 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F8D164EF
+20060828090529 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F906488B
+20060828100621 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084F97FF4CB
+20060828121421 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FA80824B
+20060828141024 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FB659087
+20060828142059 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FB739E8F
+20060828170552 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FCC5CE57
+20060828171327 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FCCCF9D3
+20060828185943 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FDA67727
+20060828190537 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FDAAC673
+20060828191202 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FDAFC737
+20060828192613 2 6 100 3071 2 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FDC50FBB
+20060828193738 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FDD6023F
+20060828204936 2 6 100 3071 5 D3230D237572ECE9F92358715EBAC3A4D89F2D6B4DC39F056450263BEF1665FBD7B93916ABC867B7064802159D273C7EB01C5F9281A3D6DCCB7CF997D385998EC0E1FA3319AFE771A90ADBACEB414A020630D7C7F161FAFEC6C9FC06D3205C712AAE8848A1B2C21DFF301C7FFC0B75D13F060A313C32AFEEAF1493F641760EBEF38829B3371699D2A3264D0ECEB4E5C19581ED8C57699F559B9828BBFE147952E289F0E171C9C60335DD2F492CB409A4DB97BDF86E2DBA605064DB040A3DF5678E24F66718CA115C95C892FF7AEDFAABC2E6414716298CEC1A604270FEADF191B7C8A59C238C395A65442C0B963BF83025BED3951A271B7440EC7687C31DE63355DA7FEAC15DC962C7BF7614EB59B077B9889AD8703DFE98AC99615B722A0ABE89956D1058E025C7733420CB51D7E1608EFF2C0A30C9A5EB77CCA02C6B00CE781B172001C6C458630890062E27CE307D513A7686A69D1D548DE8334B13136D9E842A5E17FD67522C93823E03F08AEE8024AF5D88B2EE01D4D9980084FE68405F
+20060829063416 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE57DE9222B
+20060829082327 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE57E5385E7
+20060829092010 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE57E8501A3
+20060830004204 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE5825F180F
+20060830013522 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE5828DFA2B
+20060830124707 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE58555C9EB
+20060830180312 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE586989437
+20060831041205 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE5891334BF
+20060831102341 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE58A8F8B27
+20060831234001 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE58DD7278B
+20060901032352 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE58EBE93EB
+20060901061345 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE58F693A3F
+20060901123055 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE590F80AE7
+20060901191922 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE592994C63
+20060901203957 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE592E5D92F
+20060901210250 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE592F4A5F3
+20060901225047 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE5935D124B
+20060902020657 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE5942520CB
+20060902070624 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE59553E03F
+20060902095300 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE595F6EC6B
+20060902113306 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE596599BEF
+20060902142302 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE59703582B
+20060902210839 2 6 100 4095 5 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE598A695F7
+20060903073325 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE59B315E9B
+20060903095626 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE59BBD7153
+20060903162601 2 6 100 4095 2 DA110847314B537539F2A20681212A0B2ED264BF1F2595B817CC516D5AA4211585948B248F77277B11AB206738C71B5FB2FCC4041927B40B985282795A89EF66BDB111E1D07D790AC487DA5841B66FC407ED5DD8612703136422C442139C12040CE776FEB6C8B59B95408F31FB50073AD54B03F97113E61BE577E76D13AA971BA82CEE621C31C4770A7E076245A16689A9FE3E9190FB617FB330AA70AAC623B447D1858C24993D486C2B9A3C63FFCB3F230E7185F163C1EED434C24EE11EAC5B2369FEAF790523BD8BF7E8F9C87467ED6C89E5596974DCA6960E537259EA3AA587BF5198B26CE37638BC57012851903BB4CC0E2A28EC741EECB6220556EC5C118AE0142E5374AE2A3D1CEF165C09C0988A37877BCA6BBCAE28D52DA6701BF077307195C3618D4CAC58DDF64B6A8C2BF8E2FDCC0840973A8ED1F8413689BE05EA54AB6CD30464F94DD926D8CEC6B56704F534C6D8329A27ECAD9836721BC0C283E63CDA54FCEA851C0203E747BB02B75C92036928EFC201FFCBB747A2E093CCED157C3C3F74258D5607B6B8AA330DECCF42A73A6F81D300BAFCA921BAFF635DFC90824938F7454B258C1967FF90C1D828E028F9FA86AA7B287A87EC750EDCECEEEC223EAEA78511CB3C0130043950478737FDF6D56EA2B705D5E4C57701E955A9C862DBCAF36D0624D2F2C20616AA3E0478A4A722BBA577BC02578EE59D48AEE3
+20040305011518 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080E4CE974B
+20040305043124 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080E5050933
+20040305084728 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080E54C7783
+20040306205350 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080E809C413
+20040309221333 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080ED7F9CFB
+20040311222059 2 6 100 6143 5 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080F103209F
+20040312160304 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080F247861B
+20040312210904 2 6 100 6143 5 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080F29D939F
+20040316074005 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080F8B1F7DB
+20040317113309 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080FAAE1F73
+20040317195246 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080FB3F2B93
+20040319025848 2 6 100 6143 2 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C7080FD81741B
+20040323194658 2 6 100 6143 5 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C708105AF04AF
+20040324041535 2 6 100 6143 5 E95A4131F86234D27EE1E51791599559EEDB618912E4FE36B81B80CDA4D497959DBFAEE929317A66BE64A328BAB6183EA5A5CBB3581490B4B613B225ADD00EFD38540356E0F4716229CDDB260283AF044FDAF1EF9248BB0CE9031C117CF15D3259B3E7B0301CA1AAC91AFA7A57CCDEED2DA4EFC2DBC7A9FC53BB4D3CB2D57D209D5DDEF25DE14F8226404296BD504EC14F6340F0AA2A1A943B9552C4B91D3EB48C08A13671C36EE5042857625DD2CB58965C0975EB775057FF82BC2B8B69D0BF26E2F80115B3E1A984D1D73D9D02AD69C3A1AF90EC915DE6FC9F574BD755B2EF6BBE62F3717E128DC797A06FE35C1C28CED57A0F64F61A4439ACFE7A7B95A1A948417A5B8B69916A32989B00E2C3FB7C74139A4DA9E533C439E59FC7C4F90780D2BBCDF012C499C15A1E0B5C318F84FB17DF97AB3EC356FD0072CFA3884EFBED319009DE6DBF2A5C7C87A93DEB04CCD9147EF8C9BEC2FD713793E4F0BF8C4EFCEBFBF95D555E523AB5D742808C4E425979A1C216C8CB2B42C7715B8CA5907E84E6FBC35DA7BFBFC892870B659C882C6E3697E0DCC6C24771F26D51A890786DA516DBC2D161680B134F1715B32F734E667650398EC2241AF78877BB3D61D83D0158DDE894862EE6E1BEE278724EA7B34C74F0A5D6B7F79F1322E20AD5757E11D9AC31BFE27C56ABB23A275130533433DC41DDBA1081E3A018E0D0B55DF33ECAE104909DC74F1CA2256CFD423A859B0AC2112A0AE684396C0029AD07D0D30AC84FFD2C2E80B74DE29310FCAFE7D0CB8864729B6FD1F86052D7DD9A9CB085A186259A67C175B3F81C5DA19AFED1BF9C5C07F40A29ED47ED4F1C7DE878B8411E3239ED15AC0E4CCC1D7F8842E9FD9C989F301E2689F800C3D14A38810906A36EEA34207014E99C843C599D56FCFBC14278A2A009C13B6E4AC7460B54D2C7EF38D72AC450540097D2AF609D3FFF874D14582FA8FF21027DEC92844BD22A9A7EC14C66BCC8DB1E058B95AF87ACB60A5725767A76C9185744E483BCCD9278ED9FF15A04061D0F6E32D98B6853A39AA498673C7DD012982B1913B3C3CE2C70810643E737
+20061002171426 2 6 100 8191 2 D2D64D8CC6FDFA9897C8AE805EA7CB972D7A10F5A268EB5B33B0CCE2C75E480365A49070185D8B316872BAF0F3AAF94498A8E0007A13D574C905441F19D4B0D55A83E2A70C09F7B3E353DEA76F5FEB4191E31F4A52D0BC643B9FD1959BDF8B99C13F245B5D9E8589D6C18A844814486F25A8E189B964A9E72675DDE4D759C901C09F7C24CB3E939B54D2009AE9331446C1EDE5FA9D0A33B36F6A6C9B55E956A94169FBE9C1A24EC9A3E497371F4131F2B1E4FB25A1BB27B23A6661155F37C6EC913E5CB207AD894C2319852C556CA040C6B72DE6E913BCF419E5914507119F771206FAB25B1D6BAD57AFEAF74D807CC576549CD979B0AAC13F5D2B637CCF4A54D2D903A4B29C16B9E8BEE8AD6200D24E4E3E97EB25B2DD13C31AE2A4F27D6EFBFA113F9334F92204FCFFCAA5EBDCCBA986C5B6E665FE71D6654ACA3C8051424133597FD65A18BB2AA24FFDD8B09A8758D984E09BE1F55B16A37B36B058295B1E9942A89D386D4B4DB58C516429248052D97DE42BFC32AB14F13D7F963E86867B8B7245062061C9F315EA94C38FCC0E118373BEFC41D1004CF0FA6D951E20BAC5D2C15F5796163469B88A75FE5F5D2C69C949DA47DAC75D22869F37FAB2490791FA5A5854360EAA13701CEE40EC371797272A12746ABA9CB303224B82F8CCE3F62C0D3EA0D62BF3B2C387E015B1A96A4C4A2A73ADA521B0536B81A536A5119EC559D524BA7F2B25A094A164A4EEBB8ADA886DCBA9647FC4D2D4A91BA0DB32805EDA75B61E09F44BC49862D70B8F28C8E630CD6F0DF245535D79DCD75ECBDE51B29AA6DD3F59736E5028E3AB1E75CFCDA1FF9E6F8D52027A4BC218FC9A9E660BF7EB14D300F4199C04B24725405AFA6535DF0837FEF33C0F8B57B9BDFFB1D956E7B40E822FF40603FB5417523B115FE5864094001CEF2526395C19532F153C4630B95E9835FAC985E1C9DF62188DBA12D5B8BEEB414FFD90AFEDF8F986DF33EF5BC7F7C16ACDC4D40A00822CE17A9724066EED89127195BB9D037CB7FB74AA7178A1A4CBECC5D9F67747AA74156C70E54BABA8641A55B93637385A0D1D56E5220867B5A11ED44CFC405AC238DC39690A966A2DE238FFA1E3B3C859D988DE14916C32AB2A2CB35C57F3609C34F1E8E4B5FAC2F446E0EB78CFD64DD7A3570677D373E8FEC6FF47D5471577D92F22B115D03F302C8CD1A43FCDCEBBA823EE942D7733FF7F78672BEAACCEA279744CC14D60E3912E81A14421989CF5B2C10FD1CDB6CA95E2CA8C574AA6C4F3856602A0D32A9978697752878C0DCB50EF5463EE61C83F776AB9D8098755AF00D2972D3E5E502C39A9CE52C8588472C1D3242CA658290F472D48CB0876752643C2F63CFEB66DF6E93C8BE2404DFA10AB3D8EEF214C371DC0EC29755C086574B1AA92A892B517F6E01056DD5EFEB2437E23100E487E3D4B
+20061005090403 2 6 100 8191 5 D2D64D8CC6FDFA9897C8AE805EA7CB972D7A10F5A268EB5B33B0CCE2C75E480365A49070185D8B316872BAF0F3AAF94498A8E0007A13D574C905441F19D4B0D55A83E2A70C09F7B3E353DEA76F5FEB4191E31F4A52D0BC643B9FD1959BDF8B99C13F245B5D9E8589D6C18A844814486F25A8E189B964A9E72675DDE4D759C901C09F7C24CB3E939B54D2009AE9331446C1EDE5FA9D0A33B36F6A6C9B55E956A94169FBE9C1A24EC9A3E497371F4131F2B1E4FB25A1BB27B23A6661155F37C6EC913E5CB207AD894C2319852C556CA040C6B72DE6E913BCF419E5914507119F771206FAB25B1D6BAD57AFEAF74D807CC576549CD979B0AAC13F5D2B637CCF4A54D2D903A4B29C16B9E8BEE8AD6200D24E4E3E97EB25B2DD13C31AE2A4F27D6EFBFA113F9334F92204FCFFCAA5EBDCCBA986C5B6E665FE71D6654ACA3C8051424133597FD65A18BB2AA24FFDD8B09A8758D984E09BE1F55B16A37B36B058295B1E9942A89D386D4B4DB58C516429248052D97DE42BFC32AB14F13D7F963E86867B8B7245062061C9F315EA94C38FCC0E118373BEFC41D1004CF0FA6D951E20BAC5D2C15F5796163469B88A75FE5F5D2C69C949DA47DAC75D22869F37FAB2490791FA5A5854360EAA13701CEE40EC371797272A12746ABA9CB303224B82F8CCE3F62C0D3EA0D62BF3B2C387E015B1A96A4C4A2A73ADA521B0536B81A536A5119EC559D524BA7F2B25A094A164A4EEBB8ADA886DCBA9647FC4D2D4A91BA0DB32805EDA75B61E09F44BC49862D70B8F28C8E630CD6F0DF245535D79DCD75ECBDE51B29AA6DD3F59736E5028E3AB1E75CFCDA1FF9E6F8D52027A4BC218FC9A9E660BF7EB14D300F4199C04B24725405AFA6535DF0837FEF33C0F8B57B9BDFFB1D956E7B40E822FF40603FB5417523B115FE5864094001CEF2526395C19532F153C4630B95E9835FAC985E1C9DF62188DBA12D5B8BEEB414FFD90AFEDF8F986DF33EF5BC7F7C16ACDC4D40A00822CE17A9724066EED89127195BB9D037CB7FB74AA7178A1A4CBECC5D9F67747AA74156C70E54BABA8641A55B93637385A0D1D56E5220867B5A11ED44CFC405AC238DC39690A966A2DE238FFA1E3B3C859D988DE14916C32AB2A2CB35C57F3609C34F1E8E4B5FAC2F446E0EB78CFD64DD7A3570677D373E8FEC6FF47D5471577D92F22B115D03F302C8CD1A43FCDCEBBA823EE942D7733FF7F78672BEAACCEA279744CC14D60E3912E81A14421989CF5B2C10FD1CDB6CA95E2CA8C574AA6C4F3856602A0D32A9978697752878C0DCB50EF5463EE61C83F776AB9D8098755AF00D2972D3E5E502C39A9CE52C8588472C1D3242CA658290F472D48CB0876752643C2F63CFEB66DF6E93C8BE2404DFA10AB3D8EEF214C371DC0EC29755C086574B1AA92A892B517F6E01056DD5EFEB2437E23100E4A242A2F
+20061005152228 2 6 100 8191 2 D2D64D8CC6FDFA9897C8AE805EA7CB972D7A10F5A268EB5B33B0CCE2C75E480365A49070185D8B316872BAF0F3AAF94498A8E0007A13D574C905441F19D4B0D55A83E2A70C09F7B3E353DEA76F5FEB4191E31F4A52D0BC643B9FD1959BDF8B99C13F245B5D9E8589D6C18A844814486F25A8E189B964A9E72675DDE4D759C901C09F7C24CB3E939B54D2009AE9331446C1EDE5FA9D0A33B36F6A6C9B55E956A94169FBE9C1A24EC9A3E497371F4131F2B1E4FB25A1BB27B23A6661155F37C6EC913E5CB207AD894C2319852C556CA040C6B72DE6E913BCF419E5914507119F771206FAB25B1D6BAD57AFEAF74D807CC576549CD979B0AAC13F5D2B637CCF4A54D2D903A4B29C16B9E8BEE8AD6200D24E4E3E97EB25B2DD13C31AE2A4F27D6EFBFA113F9334F92204FCFFCAA5EBDCCBA986C5B6E665FE71D6654ACA3C8051424133597FD65A18BB2AA24FFDD8B09A8758D984E09BE1F55B16A37B36B058295B1E9942A89D386D4B4DB58C516429248052D97DE42BFC32AB14F13D7F963E86867B8B7245062061C9F315EA94C38FCC0E118373BEFC41D1004CF0FA6D951E20BAC5D2C15F5796163469B88A75FE5F5D2C69C949DA47DAC75D22869F37FAB2490791FA5A5854360EAA13701CEE40EC371797272A12746ABA9CB303224B82F8CCE3F62C0D3EA0D62BF3B2C387E015B1A96A4C4A2A73ADA521B0536B81A536A5119EC559D524BA7F2B25A094A164A4EEBB8ADA886DCBA9647FC4D2D4A91BA0DB32805EDA75B61E09F44BC49862D70B8F28C8E630CD6F0DF245535D79DCD75ECBDE51B29AA6DD3F59736E5028E3AB1E75CFCDA1FF9E6F8D52027A4BC218FC9A9E660BF7EB14D300F4199C04B24725405AFA6535DF0837FEF33C0F8B57B9BDFFB1D956E7B40E822FF40603FB5417523B115FE5864094001CEF2526395C19532F153C4630B95E9835FAC985E1C9DF62188DBA12D5B8BEEB414FFD90AFEDF8F986DF33EF5BC7F7C16ACDC4D40A00822CE17A9724066EED89127195BB9D037CB7FB74AA7178A1A4CBECC5D9F67747AA74156C70E54BABA8641A55B93637385A0D1D56E5220867B5A11ED44CFC405AC238DC39690A966A2DE238FFA1E3B3C859D988DE14916C32AB2A2CB35C57F3609C34F1E8E4B5FAC2F446E0EB78CFD64DD7A3570677D373E8FEC6FF47D5471577D92F22B115D03F302C8CD1A43FCDCEBBA823EE942D7733FF7F78672BEAACCEA279744CC14D60E3912E81A14421989CF5B2C10FD1CDB6CA95E2CA8C574AA6C4F3856602A0D32A9978697752878C0DCB50EF5463EE61C83F776AB9D8098755AF00D2972D3E5E502C39A9CE52C8588472C1D3242CA658290F472D48CB0876752643C2F63CFEB66DF6E93C8BE2404DFA10AB3D8EEF214C371DC0EC29755C086574B1AA92A892B517F6E01056DD5EFEB2437E23100E4A4C3B0B
diff --git a/moduli.0 b/moduli.0
new file mode 100644 (file)
index 0000000..ded094f
--- /dev/null
+++ b/moduli.0
@@ -0,0 +1,72 @@
+MODULI(5)                 OpenBSD Programmer's Manual                MODULI(5)
+
+NAME
+     moduli - Diffie Hellman moduli
+
+DESCRIPTION
+     The /etc/moduli file contains prime numbers and generators for use by
+     sshd(8) in the Diffie-Hellman Group Exchange key exchange method.
+
+     New moduli may be generated with ssh-keygen(1) using a two-step process.
+     An initial candidate generation pass, using ssh-keygen -G, calculates
+     numbers that are likely to be useful.  A second primality testing pass,
+     using ssh-keygen -T provides a high degree of assurance that the numbers
+     are prime and are safe for use in Diffie Hellman operations by sshd(8).
+     This moduli format is used as the output from each pass.
+
+     The file consists of newline-separated records, one per modulus,
+     containing seven space separated fields.  These fields are as follows:
+
+           timestamp    The time that the modulus was last processed as
+                        YYYYMMDDHHMMSS.
+
+           type         Decimal number specifying the internal structure of
+                        the prime modulus.  Supported types are:
+
+                        0     Unknown, not tested
+                        2     "Safe" prime; (p-1)/2 is also prime.
+                        4     Sophie Germain; (p+1)*2 is also prime.
+
+                        Moduli candidates initially produced by ssh-keygen(1)
+                        are Sophie Germain primes (type 4).  Futher primality
+                        testing with ssh-keygen(1) produces safe prime moduli
+                        (type 2) that are ready for use in sshd(8).  Other
+                        types are not used by OpenSSH.
+
+           tests        Decimal number indicating the type of primality tests
+                        that the number has been subjected to represented as a
+                        bitmask of the following values:
+
+                        0x00  Not tested
+                        0x01  Composite number - not prime.
+                        0x02  Sieve of Eratosthenes
+                        0x04  Probabalistic Miller-Rabin primality tests.
+
+                        The ssh-keygen(1) moduli candidate generation uses the
+                        Sieve of Eratosthenes (flag 0x02).  Subsequent
+                        ssh-keygen(1) primality tests are Miller-Rabin tests
+                        (flag 0x04).
+
+           trials       Decimal number indicating of primaility trials that
+                        have been performed on the modulus.
+
+           size         Decimal number indicating the size of the prime in
+                        bits.
+
+           generator    The recommended generator for use with this modulus
+                        (hexadecimal).
+
+           modulus      The modulus itself in hexadecimal.
+
+     When performing Diffie Hellman Group Exchange, sshd(8) first estimates
+     the size of the modulus required to produce enough Diffie Hellman output
+     to sufficiently key the selected symmetric cipher.  sshd(8) then randomly
+     selects a modulus from /etc/moduli that best meets the size requirement.
+
+SEE ALSO
+     ssh-keygen(1), sshd(8),
+
+     Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
+     Protocol, RFC 4419, 2006.
+
+OpenBSD 4.9                      June 26, 2008                     OpenBSD 4.9
diff --git a/moduli.5 b/moduli.5
new file mode 100644 (file)
index 0000000..4a99439
--- /dev/null
+++ b/moduli.5
@@ -0,0 +1,124 @@
+.\"    $OpenBSD: moduli.5,v 1.12 2008/06/26 05:57:54 djm Exp $
+.\"
+.\" Copyright (c) 2008 Damien Miller <djm@mindrot.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.Dd $Mdocdate: June 26 2008 $
+.Dt MODULI 5
+.Os
+.Sh NAME
+.Nm moduli
+.Nd Diffie Hellman moduli
+.Sh DESCRIPTION
+The
+.Pa /etc/moduli
+file contains prime numbers and generators for use by 
+.Xr sshd 8
+in the Diffie-Hellman Group Exchange key exchange method.
+.Pp
+New moduli may be generated with
+.Xr ssh-keygen 1
+using a two-step process.
+An initial
+.Em candidate generation
+pass, using 
+.Ic ssh-keygen -G ,
+calculates numbers that are likely to be useful.
+A second
+.Em primality testing
+pass, using
+.Ic ssh-keygen -T
+provides a high degree of assurance that the numbers are prime and are
+safe for use in Diffie Hellman operations by
+.Xr sshd 8 .
+This
+.Nm
+format is used as the output from each pass.
+.Pp
+The file consists of newline-separated records, one per modulus,
+containing seven space separated fields.
+These fields are as follows:
+.Pp
+.Bl -tag -width Description -offset indent
+.It timestamp
+The time that the modulus was last processed as YYYYMMDDHHMMSS.
+.It type
+Decimal number specifying the internal structure of the prime modulus.
+Supported types are:
+.Pp
+.Bl -tag -width 0x00 -compact
+.It 0
+Unknown, not tested
+.It 2
+"Safe" prime; (p-1)/2 is also prime.
+.It 4
+Sophie Germain; (p+1)*2 is also prime.
+.El
+.Pp
+Moduli candidates initially produced by
+.Xr ssh-keygen 1
+are Sophie Germain primes (type 4).
+Futher primality testing with
+.Xr ssh-keygen 1
+produces safe prime moduli (type 2) that are ready for use in
+.Xr sshd 8 .
+Other types are not used by OpenSSH.
+.It tests
+Decimal number indicating the type of primality tests that the number
+has been subjected to represented as a bitmask of the following values:
+.Pp
+.Bl -tag -width 0x00 -compact
+.It 0x00
+Not tested
+.It 0x01
+Composite number - not prime.
+.It 0x02
+Sieve of Eratosthenes
+.It 0x04
+Probabalistic Miller-Rabin primality tests.
+.El
+.Pp
+The
+.Xr ssh-keygen 1
+moduli candidate generation uses the Sieve of Eratosthenes (flag 0x02).
+Subsequent
+.Xr ssh-keygen 1
+primality tests are Miller-Rabin tests (flag 0x04).
+.It trials
+Decimal number indicating of primaility trials that have been performed
+on the modulus.
+.It size
+Decimal number indicating the size of the prime in bits.
+.It generator
+The recommended generator for use with this modulus (hexadecimal).
+.It modulus
+The modulus itself in hexadecimal.
+.El
+.Pp
+When performing Diffie Hellman Group Exchange,
+.Xr sshd 8
+first estimates the size of the modulus required to produce enough
+Diffie Hellman output to sufficiently key the selected symmetric cipher.
+.Xr sshd 8
+then randomly selects a modulus from
+.Fa /etc/moduli
+that best meets the size requirement.
+.Pp
+.Sh SEE ALSO
+.Xr ssh-keygen 1 ,
+.Xr sshd 8 ,
+.Rs
+.%R RFC 4419
+.%T "Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol"
+.%D 2006
+.Re
diff --git a/moduli.c b/moduli.c
new file mode 100644 (file)
index 0000000..2964a8b
--- /dev/null
+++ b/moduli.c
@@ -0,0 +1,652 @@
+/* $OpenBSD: moduli.c,v 1.22 2010/11/10 01:33:07 djm Exp $ */
+/*
+ * Copyright 1994 Phil Karn <karn@qualcomm.com>
+ * Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
+ * Copyright 2000 Niels Provos <provos@citi.umich.edu>
+ * 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.
+ */
+
+/*
+ * Two-step process to generate safe primes for DHGEX
+ *
+ *  Sieve candidates for "safe" primes,
+ *  suitable for use as Diffie-Hellman moduli;
+ *  that is, where q = (p-1)/2 is also prime.
+ *
+ * First step: generate candidate primes (memory intensive)
+ * Second step: test primes' safety (processor intensive)
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "xmalloc.h"
+#include "dh.h"
+#include "log.h"
+
+#include "openbsd-compat/openssl-compat.h"
+
+/*
+ * File output defines
+ */
+
+/* need line long enough for largest moduli plus headers */
+#define QLINESIZE              (100+8192)
+
+/*
+ * Size: decimal.
+ * Specifies the number of the most significant bit (0 to M).
+ * WARNING: internally, usually 1 to N.
+ */
+#define QSIZE_MINIMUM          (511)
+
+/*
+ * Prime sieving defines
+ */
+
+/* Constant: assuming 8 bit bytes and 32 bit words */
+#define SHIFT_BIT      (3)
+#define SHIFT_BYTE     (2)
+#define SHIFT_WORD     (SHIFT_BIT+SHIFT_BYTE)
+#define SHIFT_MEGABYTE (20)
+#define SHIFT_MEGAWORD (SHIFT_MEGABYTE-SHIFT_BYTE)
+
+/*
+ * Using virtual memory can cause thrashing.  This should be the largest
+ * number that is supported without a large amount of disk activity --
+ * that would increase the run time from hours to days or weeks!
+ */
+#define LARGE_MINIMUM  (8UL)   /* megabytes */
+
+/*
+ * Do not increase this number beyond the unsigned integer bit size.
+ * Due to a multiple of 4, it must be LESS than 128 (yielding 2**30 bits).
+ */
+#define LARGE_MAXIMUM  (127UL) /* megabytes */
+
+/*
+ * Constant: when used with 32-bit integers, the largest sieve prime
+ * has to be less than 2**32.
+ */
+#define SMALL_MAXIMUM  (0xffffffffUL)
+
+/* Constant: can sieve all primes less than 2**32, as 65537**2 > 2**32-1. */
+#define TINY_NUMBER    (1UL<<16)
+
+/* Ensure enough bit space for testing 2*q. */
+#define TEST_MAXIMUM   (1UL<<16)
+#define TEST_MINIMUM   (QSIZE_MINIMUM + 1)
+/* real TEST_MINIMUM   (1UL << (SHIFT_WORD - TEST_POWER)) */
+#define TEST_POWER     (3)     /* 2**n, n < SHIFT_WORD */
+
+/* bit operations on 32-bit words */
+#define BIT_CLEAR(a,n) ((a)[(n)>>SHIFT_WORD] &= ~(1L << ((n) & 31)))
+#define BIT_SET(a,n)   ((a)[(n)>>SHIFT_WORD] |= (1L << ((n) & 31)))
+#define BIT_TEST(a,n)  ((a)[(n)>>SHIFT_WORD] & (1L << ((n) & 31)))
+
+/*
+ * Prime testing defines
+ */
+
+/* Minimum number of primality tests to perform */
+#define TRIAL_MINIMUM  (4)
+
+/*
+ * Sieving data (XXX - move to struct)
+ */
+
+/* sieve 2**16 */
+static u_int32_t *TinySieve, tinybits;
+
+/* sieve 2**30 in 2**16 parts */
+static u_int32_t *SmallSieve, smallbits, smallbase;
+
+/* sieve relative to the initial value */
+static u_int32_t *LargeSieve, largewords, largetries, largenumbers;
+static u_int32_t largebits, largememory;       /* megabytes */
+static BIGNUM *largebase;
+
+int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
+int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
+
+/*
+ * print moduli out in consistent form,
+ */
+static int
+qfileout(FILE * ofile, u_int32_t otype, u_int32_t otests, u_int32_t otries,
+    u_int32_t osize, u_int32_t ogenerator, BIGNUM * omodulus)
+{
+       struct tm *gtm;
+       time_t time_now;
+       int res;
+
+       time(&time_now);
+       gtm = gmtime(&time_now);
+
+       res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ",
+           gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday,
+           gtm->tm_hour, gtm->tm_min, gtm->tm_sec,
+           otype, otests, otries, osize, ogenerator);
+
+       if (res < 0)
+               return (-1);
+
+       if (BN_print_fp(ofile, omodulus) < 1)
+               return (-1);
+
+       res = fprintf(ofile, "\n");
+       fflush(ofile);
+
+       return (res > 0 ? 0 : -1);
+}
+
+
+/*
+ ** Sieve p's and q's with small factors
+ */
+static void
+sieve_large(u_int32_t s)
+{
+       u_int32_t r, u;
+
+       debug3("sieve_large %u", s);
+       largetries++;
+       /* r = largebase mod s */
+       r = BN_mod_word(largebase, s);
+       if (r == 0)
+               u = 0; /* s divides into largebase exactly */
+       else
+               u = s - r; /* largebase+u is first entry divisible by s */
+
+       if (u < largebits * 2) {
+               /*
+                * The sieve omits p's and q's divisible by 2, so ensure that
+                * largebase+u is odd. Then, step through the sieve in
+                * increments of 2*s
+                */
+               if (u & 0x1)
+                       u += s; /* Make largebase+u odd, and u even */
+
+               /* Mark all multiples of 2*s */
+               for (u /= 2; u < largebits; u += s)
+                       BIT_SET(LargeSieve, u);
+       }
+
+       /* r = p mod s */
+       r = (2 * r + 1) % s;
+       if (r == 0)
+               u = 0; /* s divides p exactly */
+       else
+               u = s - r; /* p+u is first entry divisible by s */
+
+       if (u < largebits * 4) {
+               /*
+                * The sieve omits p's divisible by 4, so ensure that
+                * largebase+u is not. Then, step through the sieve in
+                * increments of 4*s
+                */
+               while (u & 0x3) {
+                       if (SMALL_MAXIMUM - u < s)
+                               return;
+                       u += s;
+               }
+
+               /* Mark all multiples of 4*s */
+               for (u /= 4; u < largebits; u += s)
+                       BIT_SET(LargeSieve, u);
+       }
+}
+
+/*
+ * list candidates for Sophie-Germain primes (where q = (p-1)/2)
+ * to standard output.
+ * The list is checked against small known primes (less than 2**30).
+ */
+int
+gen_candidates(FILE *out, u_int32_t memory, u_int32_t power, BIGNUM *start)
+{
+       BIGNUM *q;
+       u_int32_t j, r, s, t;
+       u_int32_t smallwords = TINY_NUMBER >> 6;
+       u_int32_t tinywords = TINY_NUMBER >> 6;
+       time_t time_start, time_stop;
+       u_int32_t i;
+       int ret = 0;
+
+       largememory = memory;
+
+       if (memory != 0 &&
+           (memory < LARGE_MINIMUM || memory > LARGE_MAXIMUM)) {
+               error("Invalid memory amount (min %ld, max %ld)",
+                   LARGE_MINIMUM, LARGE_MAXIMUM);
+               return (-1);
+       }
+
+       /*
+        * Set power to the length in bits of the prime to be generated.
+        * This is changed to 1 less than the desired safe prime moduli p.
+        */
+       if (power > TEST_MAXIMUM) {
+               error("Too many bits: %u > %lu", power, TEST_MAXIMUM);
+               return (-1);
+       } else if (power < TEST_MINIMUM) {
+               error("Too few bits: %u < %u", power, TEST_MINIMUM);
+               return (-1);
+       }
+       power--; /* decrement before squaring */
+
+       /*
+        * The density of ordinary primes is on the order of 1/bits, so the
+        * density of safe primes should be about (1/bits)**2. Set test range
+        * to something well above bits**2 to be reasonably sure (but not
+        * guaranteed) of catching at least one safe prime.
+        */
+       largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER));
+
+       /*
+        * Need idea of how much memory is available. We don't have to use all
+        * of it.
+        */
+       if (largememory > LARGE_MAXIMUM) {
+               logit("Limited memory: %u MB; limit %lu MB",
+                   largememory, LARGE_MAXIMUM);
+               largememory = LARGE_MAXIMUM;
+       }
+
+       if (largewords <= (largememory << SHIFT_MEGAWORD)) {
+               logit("Increased memory: %u MB; need %u bytes",
+                   largememory, (largewords << SHIFT_BYTE));
+               largewords = (largememory << SHIFT_MEGAWORD);
+       } else if (largememory > 0) {
+               logit("Decreased memory: %u MB; want %u bytes",
+                   largememory, (largewords << SHIFT_BYTE));
+               largewords = (largememory << SHIFT_MEGAWORD);
+       }
+
+       TinySieve = xcalloc(tinywords, sizeof(u_int32_t));
+       tinybits = tinywords << SHIFT_WORD;
+
+       SmallSieve = xcalloc(smallwords, sizeof(u_int32_t));
+       smallbits = smallwords << SHIFT_WORD;
+
+       /*
+        * dynamically determine available memory
+        */
+       while ((LargeSieve = calloc(largewords, sizeof(u_int32_t))) == NULL)
+               largewords -= (1L << (SHIFT_MEGAWORD - 2)); /* 1/4 MB chunks */
+
+       largebits = largewords << SHIFT_WORD;
+       largenumbers = largebits * 2;   /* even numbers excluded */
+
+       /* validation check: count the number of primes tried */
+       largetries = 0;
+       if ((q = BN_new()) == NULL)
+               fatal("BN_new failed");
+
+       /*
+        * Generate random starting point for subprime search, or use
+        * specified parameter.
+        */
+       if ((largebase = BN_new()) == NULL)
+               fatal("BN_new failed");
+       if (start == NULL) {
+               if (BN_rand(largebase, power, 1, 1) == 0)
+                       fatal("BN_rand failed");
+       } else {
+               if (BN_copy(largebase, start) == NULL)
+                       fatal("BN_copy: failed");
+       }
+
+       /* ensure odd */
+       if (BN_set_bit(largebase, 0) == 0)
+               fatal("BN_set_bit: failed");
+
+       time(&time_start);
+
+       logit("%.24s Sieve next %u plus %u-bit", ctime(&time_start),
+           largenumbers, power);
+       debug2("start point: 0x%s", BN_bn2hex(largebase));
+
+       /*
+        * TinySieve
+        */
+       for (i = 0; i < tinybits; i++) {
+               if (BIT_TEST(TinySieve, i))
+                       continue; /* 2*i+3 is composite */
+
+               /* The next tiny prime */
+               t = 2 * i + 3;
+
+               /* Mark all multiples of t */
+               for (j = i + t; j < tinybits; j += t)
+                       BIT_SET(TinySieve, j);
+
+               sieve_large(t);
+       }
+
+       /*
+        * Start the small block search at the next possible prime. To avoid
+        * fencepost errors, the last pass is skipped.
+        */
+       for (smallbase = TINY_NUMBER + 3;
+           smallbase < (SMALL_MAXIMUM - TINY_NUMBER);
+           smallbase += TINY_NUMBER) {
+               for (i = 0; i < tinybits; i++) {
+                       if (BIT_TEST(TinySieve, i))
+                               continue; /* 2*i+3 is composite */
+
+                       /* The next tiny prime */
+                       t = 2 * i + 3;
+                       r = smallbase % t;
+
+                       if (r == 0) {
+                               s = 0; /* t divides into smallbase exactly */
+                       } else {
+                               /* smallbase+s is first entry divisible by t */
+                               s = t - r;
+                       }
+
+                       /*
+                        * The sieve omits even numbers, so ensure that
+                        * smallbase+s is odd. Then, step through the sieve
+                        * in increments of 2*t
+                        */
+                       if (s & 1)
+                               s += t; /* Make smallbase+s odd, and s even */
+
+                       /* Mark all multiples of 2*t */
+                       for (s /= 2; s < smallbits; s += t)
+                               BIT_SET(SmallSieve, s);
+               }
+
+               /*
+                * SmallSieve
+                */
+               for (i = 0; i < smallbits; i++) {
+                       if (BIT_TEST(SmallSieve, i))
+                               continue; /* 2*i+smallbase is composite */
+
+                       /* The next small prime */
+                       sieve_large((2 * i) + smallbase);
+               }
+
+               memset(SmallSieve, 0, smallwords << SHIFT_BYTE);
+       }
+
+       time(&time_stop);
+
+       logit("%.24s Sieved with %u small primes in %ld seconds",
+           ctime(&time_stop), largetries, (long) (time_stop - time_start));
+
+       for (j = r = 0; j < largebits; j++) {
+               if (BIT_TEST(LargeSieve, j))
+                       continue; /* Definitely composite, skip */
+
+               debug2("test q = largebase+%u", 2 * j);
+               if (BN_set_word(q, 2 * j) == 0)
+                       fatal("BN_set_word failed");
+               if (BN_add(q, q, largebase) == 0)
+                       fatal("BN_add failed");
+               if (qfileout(out, MODULI_TYPE_SOPHIE_GERMAIN,
+                   MODULI_TESTS_SIEVE, largetries,
+                   (power - 1) /* MSB */, (0), q) == -1) {
+                       ret = -1;
+                       break;
+               }
+
+               r++; /* count q */
+       }
+
+       time(&time_stop);
+
+       xfree(LargeSieve);
+       xfree(SmallSieve);
+       xfree(TinySieve);
+
+       logit("%.24s Found %u candidates", ctime(&time_stop), r);
+
+       return (ret);
+}
+
+/*
+ * perform a Miller-Rabin primality test
+ * on the list of candidates
+ * (checking both q and p)
+ * The result is a list of so-call "safe" primes
+ */
+int
+prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted)
+{
+       BIGNUM *q, *p, *a;
+       BN_CTX *ctx;
+       char *cp, *lp;
+       u_int32_t count_in = 0, count_out = 0, count_possible = 0;
+       u_int32_t generator_known, in_tests, in_tries, in_type, in_size;
+       time_t time_start, time_stop;
+       int res;
+
+       if (trials < TRIAL_MINIMUM) {
+               error("Minimum primality trials is %d", TRIAL_MINIMUM);
+               return (-1);
+       }
+
+       time(&time_start);
+
+       if ((p = BN_new()) == NULL)
+               fatal("BN_new failed");
+       if ((q = BN_new()) == NULL)
+               fatal("BN_new failed");
+       if ((ctx = BN_CTX_new()) == NULL)
+               fatal("BN_CTX_new failed");
+
+       debug2("%.24s Final %u Miller-Rabin trials (%x generator)",
+           ctime(&time_start), trials, generator_wanted);
+
+       res = 0;
+       lp = xmalloc(QLINESIZE + 1);
+       while (fgets(lp, QLINESIZE + 1, in) != NULL) {
+               count_in++;
+               if (strlen(lp) < 14 || *lp == '!' || *lp == '#') {
+                       debug2("%10u: comment or short line", count_in);
+                       continue;
+               }
+
+               /* XXX - fragile parser */
+               /* time */
+               cp = &lp[14];   /* (skip) */
+
+               /* type */
+               in_type = strtoul(cp, &cp, 10);
+
+               /* tests */
+               in_tests = strtoul(cp, &cp, 10);
+
+               if (in_tests & MODULI_TESTS_COMPOSITE) {
+                       debug2("%10u: known composite", count_in);
+                       continue;
+               }
+
+               /* tries */
+               in_tries = strtoul(cp, &cp, 10);
+
+               /* size (most significant bit) */
+               in_size = strtoul(cp, &cp, 10);
+
+               /* generator (hex) */
+               generator_known = strtoul(cp, &cp, 16);
+
+               /* Skip white space */
+               cp += strspn(cp, " ");
+
+               /* modulus (hex) */
+               switch (in_type) {
+               case MODULI_TYPE_SOPHIE_GERMAIN:
+                       debug2("%10u: (%u) Sophie-Germain", count_in, in_type);
+                       a = q;
+                       if (BN_hex2bn(&a, cp) == 0)
+                               fatal("BN_hex2bn failed");
+                       /* p = 2*q + 1 */
+                       if (BN_lshift(p, q, 1) == 0)
+                               fatal("BN_lshift failed");
+                       if (BN_add_word(p, 1) == 0)
+                               fatal("BN_add_word failed");
+                       in_size += 1;
+                       generator_known = 0;
+                       break;
+               case MODULI_TYPE_UNSTRUCTURED:
+               case MODULI_TYPE_SAFE:
+               case MODULI_TYPE_SCHNORR:
+               case MODULI_TYPE_STRONG:
+               case MODULI_TYPE_UNKNOWN:
+                       debug2("%10u: (%u)", count_in, in_type);
+                       a = p;
+                       if (BN_hex2bn(&a, cp) == 0)
+                               fatal("BN_hex2bn failed");
+                       /* q = (p-1) / 2 */
+                       if (BN_rshift(q, p, 1) == 0)
+                               fatal("BN_rshift failed");
+                       break;
+               default:
+                       debug2("Unknown prime type");
+                       break;
+               }
+
+               /*
+                * due to earlier inconsistencies in interpretation, check
+                * the proposed bit size.
+                */
+               if ((u_int32_t)BN_num_bits(p) != (in_size + 1)) {
+                       debug2("%10u: bit size %u mismatch", count_in, in_size);
+                       continue;
+               }
+               if (in_size < QSIZE_MINIMUM) {
+                       debug2("%10u: bit size %u too short", count_in, in_size);
+                       continue;
+               }
+
+               if (in_tests & MODULI_TESTS_MILLER_RABIN)
+                       in_tries += trials;
+               else
+                       in_tries = trials;
+
+               /*
+                * guess unknown generator
+                */
+               if (generator_known == 0) {
+                       if (BN_mod_word(p, 24) == 11)
+                               generator_known = 2;
+                       else if (BN_mod_word(p, 12) == 5)
+                               generator_known = 3;
+                       else {
+                               u_int32_t r = BN_mod_word(p, 10);
+
+                               if (r == 3 || r == 7)
+                                       generator_known = 5;
+                       }
+               }
+               /*
+                * skip tests when desired generator doesn't match
+                */
+               if (generator_wanted > 0 &&
+                   generator_wanted != generator_known) {
+                       debug2("%10u: generator %d != %d",
+                           count_in, generator_known, generator_wanted);
+                       continue;
+               }
+
+               /*
+                * Primes with no known generator are useless for DH, so
+                * skip those.
+                */
+               if (generator_known == 0) {
+                       debug2("%10u: no known generator", count_in);
+                       continue;
+               }
+
+               count_possible++;
+
+               /*
+                * The (1/4)^N performance bound on Miller-Rabin is
+                * extremely pessimistic, so don't spend a lot of time
+                * really verifying that q is prime until after we know
+                * that p is also prime. A single pass will weed out the
+                * vast majority of composite q's.
+                */
+               if (BN_is_prime_ex(q, 1, ctx, NULL) <= 0) {
+                       debug("%10u: q failed first possible prime test",
+                           count_in);
+                       continue;
+               }
+
+               /*
+                * q is possibly prime, so go ahead and really make sure
+                * that p is prime. If it is, then we can go back and do
+                * the same for q. If p is composite, chances are that
+                * will show up on the first Rabin-Miller iteration so it
+                * doesn't hurt to specify a high iteration count.
+                */
+               if (!BN_is_prime_ex(p, trials, ctx, NULL)) {
+                       debug("%10u: p is not prime", count_in);
+                       continue;
+               }
+               debug("%10u: p is almost certainly prime", count_in);
+
+               /* recheck q more rigorously */
+               if (!BN_is_prime_ex(q, trials - 1, ctx, NULL)) {
+                       debug("%10u: q is not prime", count_in);
+                       continue;
+               }
+               debug("%10u: q is almost certainly prime", count_in);
+
+               if (qfileout(out, MODULI_TYPE_SAFE,
+                   in_tests | MODULI_TESTS_MILLER_RABIN,
+                   in_tries, in_size, generator_known, p)) {
+                       res = -1;
+                       break;
+               }
+
+               count_out++;
+       }
+
+       time(&time_stop);
+       xfree(lp);
+       BN_free(p);
+       BN_free(q);
+       BN_CTX_free(ctx);
+
+       logit("%.24s Found %u safe primes of %u candidates in %ld seconds",
+           ctime(&time_stop), count_out, count_possible,
+           (long) (time_stop - time_start));
+
+       return (res);
+}
diff --git a/monitor.c b/monitor.c
new file mode 100644 (file)
index 0000000..29d987c
--- /dev/null
+++ b/monitor.c
@@ -0,0 +1,2198 @@
+/* $OpenBSD: monitor.c,v 1.110 2010/09/09 10:45:45 djm Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2002 Markus Friedl <markus@openbsd.org>
+ * 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 <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include "openbsd-compat/sys-tree.h"
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef SKEY
+#include <skey.h>
+#endif
+
+#include <openssl/dh.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "key.h"
+#include "buffer.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "cipher.h"
+#include "kex.h"
+#include "dh.h"
+#ifdef TARGET_OS_MAC   /* XXX Broken krb5 headers on Mac */
+#undef TARGET_OS_MAC
+#include "zlib.h"
+#define TARGET_OS_MAC 1
+#else
+#include "zlib.h"
+#endif
+#include "packet.h"
+#include "auth-options.h"
+#include "sshpty.h"
+#include "channels.h"
+#include "session.h"
+#include "sshlogin.h"
+#include "canohost.h"
+#include "log.h"
+#include "servconf.h"
+#include "monitor.h"
+#include "monitor_mm.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "monitor_fdpass.h"
+#include "misc.h"
+#include "compat.h"
+#include "ssh2.h"
+#include "jpake.h"
+#include "roaming.h"
+
+#ifdef GSSAPI
+static Gssctxt *gsscontext = NULL;
+#endif
+
+/* Imports */
+extern ServerOptions options;
+extern u_int utmp_len;
+extern Newkeys *current_keys[];
+extern z_stream incoming_stream;
+extern z_stream outgoing_stream;
+extern u_char session_id[];
+extern Buffer auth_debug;
+extern int auth_debug_init;
+extern Buffer loginmsg;
+
+/* State exported from the child */
+
+struct {
+       z_stream incoming;
+       z_stream outgoing;
+       u_char *keyin;
+       u_int keyinlen;
+       u_char *keyout;
+       u_int keyoutlen;
+       u_char *ivin;
+       u_int ivinlen;
+       u_char *ivout;
+       u_int ivoutlen;
+       u_char *ssh1key;
+       u_int ssh1keylen;
+       int ssh1cipher;
+       int ssh1protoflags;
+       u_char *input;
+       u_int ilen;
+       u_char *output;
+       u_int olen;
+       u_int64_t sent_bytes;
+       u_int64_t recv_bytes;
+} child_state;
+
+/* Functions on the monitor that answer unprivileged requests */
+
+int mm_answer_moduli(int, Buffer *);
+int mm_answer_sign(int, Buffer *);
+int mm_answer_pwnamallow(int, Buffer *);
+int mm_answer_auth2_read_banner(int, Buffer *);
+int mm_answer_authserv(int, Buffer *);
+int mm_answer_authpassword(int, Buffer *);
+int mm_answer_bsdauthquery(int, Buffer *);
+int mm_answer_bsdauthrespond(int, Buffer *);
+int mm_answer_skeyquery(int, Buffer *);
+int mm_answer_skeyrespond(int, Buffer *);
+int mm_answer_keyallowed(int, Buffer *);
+int mm_answer_keyverify(int, Buffer *);
+int mm_answer_pty(int, Buffer *);
+int mm_answer_pty_cleanup(int, Buffer *);
+int mm_answer_term(int, Buffer *);
+int mm_answer_rsa_keyallowed(int, Buffer *);
+int mm_answer_rsa_challenge(int, Buffer *);
+int mm_answer_rsa_response(int, Buffer *);
+int mm_answer_sesskey(int, Buffer *);
+int mm_answer_sessid(int, Buffer *);
+int mm_answer_jpake_get_pwdata(int, Buffer *);
+int mm_answer_jpake_step1(int, Buffer *);
+int mm_answer_jpake_step2(int, Buffer *);
+int mm_answer_jpake_key_confirm(int, Buffer *);
+int mm_answer_jpake_check_confirm(int, Buffer *);
+
+#ifdef USE_PAM
+int mm_answer_pam_start(int, Buffer *);
+int mm_answer_pam_account(int, Buffer *);
+int mm_answer_pam_init_ctx(int, Buffer *);
+int mm_answer_pam_query(int, Buffer *);
+int mm_answer_pam_respond(int, Buffer *);
+int mm_answer_pam_free_ctx(int, Buffer *);
+#endif
+
+#ifdef GSSAPI
+int mm_answer_gss_setup_ctx(int, Buffer *);
+int mm_answer_gss_accept_ctx(int, Buffer *);
+int mm_answer_gss_userok(int, Buffer *);
+int mm_answer_gss_checkmic(int, Buffer *);
+#endif
+
+#ifdef SSH_AUDIT_EVENTS
+int mm_answer_audit_event(int, Buffer *);
+int mm_answer_audit_command(int, Buffer *);
+#endif
+
+static Authctxt *authctxt;
+static BIGNUM *ssh1_challenge = NULL;  /* used for ssh1 rsa auth */
+
+/* local state for key verify */
+static u_char *key_blob = NULL;
+static u_int key_bloblen = 0;
+static int key_blobtype = MM_NOKEY;
+static char *hostbased_cuser = NULL;
+static char *hostbased_chost = NULL;
+static char *auth_method = "unknown";
+static u_int session_id2_len = 0;
+static u_char *session_id2 = NULL;
+static pid_t monitor_child_pid;
+
+struct mon_table {
+       enum monitor_reqtype type;
+       int flags;
+       int (*f)(int, Buffer *);
+};
+
+#define MON_ISAUTH     0x0004  /* Required for Authentication */
+#define MON_AUTHDECIDE 0x0008  /* Decides Authentication */
+#define MON_ONCE       0x0010  /* Disable after calling */
+#define MON_ALOG       0x0020  /* Log auth attempt without authenticating */
+
+#define MON_AUTH       (MON_ISAUTH|MON_AUTHDECIDE)
+
+#define MON_PERMIT     0x1000  /* Request is permitted */
+
+struct mon_table mon_dispatch_proto20[] = {
+    {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
+    {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
+    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+    {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
+    {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
+    {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+#ifdef USE_PAM
+    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+    {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+    {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+    {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond},
+    {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx},
+#endif
+#ifdef SSH_AUDIT_EVENTS
+    {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+#endif
+#ifdef BSD_AUTH
+    {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+    {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond},
+#endif
+#ifdef SKEY
+    {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
+    {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+#endif
+    {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
+    {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
+#endif
+#ifdef JPAKE
+    {MONITOR_REQ_JPAKE_GET_PWDATA, MON_ONCE, mm_answer_jpake_get_pwdata},
+    {MONITOR_REQ_JPAKE_STEP1, MON_ISAUTH, mm_answer_jpake_step1},
+    {MONITOR_REQ_JPAKE_STEP2, MON_ONCE, mm_answer_jpake_step2},
+    {MONITOR_REQ_JPAKE_KEY_CONFIRM, MON_ONCE, mm_answer_jpake_key_confirm},
+    {MONITOR_REQ_JPAKE_CHECK_CONFIRM, MON_AUTH, mm_answer_jpake_check_confirm},
+#endif
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_postauth20[] = {
+    {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
+    {MONITOR_REQ_SIGN, 0, mm_answer_sign},
+    {MONITOR_REQ_PTY, 0, mm_answer_pty},
+    {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup},
+    {MONITOR_REQ_TERM, 0, mm_answer_term},
+#ifdef SSH_AUDIT_EVENTS
+    {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+    {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
+#endif
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_proto15[] = {
+    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+    {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey},
+    {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid},
+    {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
+    {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH|MON_ALOG, mm_answer_rsa_keyallowed},
+    {MONITOR_REQ_KEYALLOWED, MON_ISAUTH|MON_ALOG, mm_answer_keyallowed},
+    {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge},
+    {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response},
+#ifdef BSD_AUTH
+    {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
+    {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond},
+#endif
+#ifdef SKEY
+    {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
+    {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
+#endif
+#ifdef USE_PAM
+    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
+    {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
+    {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
+    {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond},
+    {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx},
+#endif
+#ifdef SSH_AUDIT_EVENTS
+    {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+#endif
+    {0, 0, NULL}
+};
+
+struct mon_table mon_dispatch_postauth15[] = {
+    {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
+    {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
+    {MONITOR_REQ_TERM, 0, mm_answer_term},
+#ifdef SSH_AUDIT_EVENTS
+    {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
+    {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command},
+#endif
+    {0, 0, NULL}
+};
+
+struct mon_table *mon_dispatch;
+
+/* Specifies if a certain message is allowed at the moment */
+
+static void
+monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit)
+{
+       while (ent->f != NULL) {
+               if (ent->type == type) {
+                       ent->flags &= ~MON_PERMIT;
+                       ent->flags |= permit ? MON_PERMIT : 0;
+                       return;
+               }
+               ent++;
+       }
+}
+
+static void
+monitor_permit_authentications(int permit)
+{
+       struct mon_table *ent = mon_dispatch;
+
+       while (ent->f != NULL) {
+               if (ent->flags & MON_AUTH) {
+                       ent->flags &= ~MON_PERMIT;
+                       ent->flags |= permit ? MON_PERMIT : 0;
+               }
+               ent++;
+       }
+}
+
+void
+monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
+{
+       struct mon_table *ent;
+       int authenticated = 0;
+
+       debug3("preauth child monitor started");
+
+       authctxt = _authctxt;
+       memset(authctxt, 0, sizeof(*authctxt));
+
+       authctxt->loginmsg = &loginmsg;
+
+       if (compat20) {
+               mon_dispatch = mon_dispatch_proto20;
+
+               /* Permit requests for moduli and signatures */
+               monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+       } else {
+               mon_dispatch = mon_dispatch_proto15;
+
+               monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
+       }
+
+       /* The first few requests do not require asynchronous access */
+       while (!authenticated) {
+               auth_method = "unknown";
+               authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
+               if (authenticated) {
+                       if (!(ent->flags & MON_AUTHDECIDE))
+                               fatal("%s: unexpected authentication from %d",
+                                   __func__, ent->type);
+                       if (authctxt->pw->pw_uid == 0 &&
+                           !auth_root_allowed(auth_method))
+                               authenticated = 0;
+#ifdef USE_PAM
+                       /* PAM needs to perform account checks after auth */
+                       if (options.use_pam && authenticated) {
+                               Buffer m;
+
+                               buffer_init(&m);
+                               mm_request_receive_expect(pmonitor->m_sendfd,
+                                   MONITOR_REQ_PAM_ACCOUNT, &m);
+                               authenticated = mm_answer_pam_account(pmonitor->m_sendfd, &m);
+                               buffer_free(&m);
+                       }
+#endif
+               }
+
+               if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) {
+                       auth_log(authctxt, authenticated, auth_method,
+                           compat20 ? " ssh2" : "");
+                       if (!authenticated)
+                               authctxt->failures++;
+               }
+#ifdef JPAKE
+               /* Cleanup JPAKE context after authentication */
+               if (ent->flags & MON_AUTHDECIDE) {
+                       if (authctxt->jpake_ctx != NULL) {
+                               jpake_free(authctxt->jpake_ctx);
+                               authctxt->jpake_ctx = NULL;
+                       }
+               }
+#endif
+       }
+
+       if (!authctxt->valid)
+               fatal("%s: authenticated invalid user", __func__);
+       if (strcmp(auth_method, "unknown") == 0)
+               fatal("%s: authentication method name unknown", __func__);
+
+       debug("%s: %s has been authenticated by privileged process",
+           __func__, authctxt->user);
+
+       mm_get_keystate(pmonitor);
+}
+
+static void
+monitor_set_child_handler(pid_t pid)
+{
+       monitor_child_pid = pid;
+}
+
+static void
+monitor_child_handler(int sig)
+{
+       kill(monitor_child_pid, sig);
+}
+
+void
+monitor_child_postauth(struct monitor *pmonitor)
+{
+       monitor_set_child_handler(pmonitor->m_pid);
+       signal(SIGHUP, &monitor_child_handler);
+       signal(SIGTERM, &monitor_child_handler);
+       signal(SIGINT, &monitor_child_handler);
+
+       if (compat20) {
+               mon_dispatch = mon_dispatch_postauth20;
+
+               /* Permit requests for moduli and signatures */
+               monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+       } else {
+               mon_dispatch = mon_dispatch_postauth15;
+               monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+       }
+       if (!no_pty_flag) {
+               monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
+       }
+
+       for (;;)
+               monitor_read(pmonitor, mon_dispatch, NULL);
+}
+
+void
+monitor_sync(struct monitor *pmonitor)
+{
+       if (options.compression) {
+               /* The member allocation is not visible, so sync it */
+               mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback);
+       }
+}
+
+int
+monitor_read(struct monitor *pmonitor, struct mon_table *ent,
+    struct mon_table **pent)
+{
+       Buffer m;
+       int ret;
+       u_char type;
+
+       buffer_init(&m);
+
+       mm_request_receive(pmonitor->m_sendfd, &m);
+       type = buffer_get_char(&m);
+
+       debug3("%s: checking request %d", __func__, type);
+
+       while (ent->f != NULL) {
+               if (ent->type == type)
+                       break;
+               ent++;
+       }
+
+       if (ent->f != NULL) {
+               if (!(ent->flags & MON_PERMIT))
+                       fatal("%s: unpermitted request %d", __func__,
+                           type);
+               ret = (*ent->f)(pmonitor->m_sendfd, &m);
+               buffer_free(&m);
+
+               /* The child may use this request only once, disable it */
+               if (ent->flags & MON_ONCE) {
+                       debug2("%s: %d used once, disabling now", __func__,
+                           type);
+                       ent->flags &= ~MON_PERMIT;
+               }
+
+               if (pent != NULL)
+                       *pent = ent;
+
+               return ret;
+       }
+
+       fatal("%s: unsupported request: %d", __func__, type);
+
+       /* NOTREACHED */
+       return (-1);
+}
+
+/* allowed key state */
+static int
+monitor_allowed_key(u_char *blob, u_int bloblen)
+{
+       /* make sure key is allowed */
+       if (key_blob == NULL || key_bloblen != bloblen ||
+           timingsafe_bcmp(key_blob, blob, key_bloblen))
+               return (0);
+       return (1);
+}
+
+static void
+monitor_reset_key_state(void)
+{
+       /* reset state */
+       if (key_blob != NULL)
+               xfree(key_blob);
+       if (hostbased_cuser != NULL)
+               xfree(hostbased_cuser);
+       if (hostbased_chost != NULL)
+               xfree(hostbased_chost);
+       key_blob = NULL;
+       key_bloblen = 0;
+       key_blobtype = MM_NOKEY;
+       hostbased_cuser = NULL;
+       hostbased_chost = NULL;
+}
+
+int
+mm_answer_moduli(int sock, Buffer *m)
+{
+       DH *dh;
+       int min, want, max;
+
+       min = buffer_get_int(m);
+       want = buffer_get_int(m);
+       max = buffer_get_int(m);
+
+       debug3("%s: got parameters: %d %d %d",
+           __func__, min, want, max);
+       /* We need to check here, too, in case the child got corrupted */
+       if (max < min || want < min || max < want)
+               fatal("%s: bad parameters: %d %d %d",
+                   __func__, min, want, max);
+
+       buffer_clear(m);
+
+       dh = choose_dh(min, want, max);
+       if (dh == NULL) {
+               buffer_put_char(m, 0);
+               return (0);
+       } else {
+               /* Send first bignum */
+               buffer_put_char(m, 1);
+               buffer_put_bignum2(m, dh->p);
+               buffer_put_bignum2(m, dh->g);
+
+               DH_free(dh);
+       }
+       mm_request_send(sock, MONITOR_ANS_MODULI, m);
+       return (0);
+}
+
+int
+mm_answer_sign(int sock, Buffer *m)
+{
+       Key *key;
+       u_char *p;
+       u_char *signature;
+       u_int siglen, datlen;
+       int keyid;
+
+       debug3("%s", __func__);
+
+       keyid = buffer_get_int(m);
+       p = buffer_get_string(m, &datlen);
+
+       /*
+        * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes),
+        * SHA384 (48 bytes) and SHA512 (64 bytes).
+        */
+       if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64)
+               fatal("%s: data length incorrect: %u", __func__, datlen);
+
+       /* save session id, it will be passed on the first call */
+       if (session_id2_len == 0) {
+               session_id2_len = datlen;
+               session_id2 = xmalloc(session_id2_len);
+               memcpy(session_id2, p, session_id2_len);
+       }
+
+       if ((key = get_hostkey_by_index(keyid)) == NULL)
+               fatal("%s: no hostkey from index %d", __func__, keyid);
+       if (key_sign(key, &signature, &siglen, p, datlen) < 0)
+               fatal("%s: key_sign failed", __func__);
+
+       debug3("%s: signature %p(%u)", __func__, signature, siglen);
+
+       buffer_clear(m);
+       buffer_put_string(m, signature, siglen);
+
+       xfree(p);
+       xfree(signature);
+
+       mm_request_send(sock, MONITOR_ANS_SIGN, m);
+
+       /* Turn on permissions for getpwnam */
+       monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+       return (0);
+}
+
+/* Retrieves the password entry and also checks if the user is permitted */
+
+int
+mm_answer_pwnamallow(int sock, Buffer *m)
+{
+       char *username;
+       struct passwd *pwent;
+       int allowed = 0;
+
+       debug3("%s", __func__);
+
+       if (authctxt->attempt++ != 0)
+               fatal("%s: multiple attempts for getpwnam", __func__);
+
+       username = buffer_get_string(m, NULL);
+
+       pwent = getpwnamallow(username);
+
+       authctxt->user = xstrdup(username);
+       setproctitle("%s [priv]", pwent ? username : "unknown");
+       xfree(username);
+
+       buffer_clear(m);
+
+       if (pwent == NULL) {
+               buffer_put_char(m, 0);
+               authctxt->pw = fakepw();
+               goto out;
+       }
+
+       allowed = 1;
+       authctxt->pw = pwent;
+       authctxt->valid = 1;
+
+       buffer_put_char(m, 1);
+       buffer_put_string(m, pwent, sizeof(struct passwd));
+       buffer_put_cstring(m, pwent->pw_name);
+       buffer_put_cstring(m, "*");
+       buffer_put_cstring(m, pwent->pw_gecos);
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       buffer_put_cstring(m, pwent->pw_class);
+#endif
+       buffer_put_cstring(m, pwent->pw_dir);
+       buffer_put_cstring(m, pwent->pw_shell);
+
+ out:
+       buffer_put_string(m, &options, sizeof(options));
+       if (options.banner != NULL)
+               buffer_put_cstring(m, options.banner);
+       debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed);
+       mm_request_send(sock, MONITOR_ANS_PWNAM, m);
+
+       /* For SSHv1 allow authentication now */
+       if (!compat20)
+               monitor_permit_authentications(1);
+       else {
+               /* Allow service/style information on the auth context */
+               monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1);
+       }
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1);
+#endif
+
+       return (0);
+}
+
+int mm_answer_auth2_read_banner(int sock, Buffer *m)
+{
+       char *banner;
+
+       buffer_clear(m);
+       banner = auth2_read_banner();
+       buffer_put_cstring(m, banner != NULL ? banner : "");
+       mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m);
+
+       if (banner != NULL)
+               xfree(banner);
+
+       return (0);
+}
+
+int
+mm_answer_authserv(int sock, Buffer *m)
+{
+       monitor_permit_authentications(1);
+
+       authctxt->service = buffer_get_string(m, NULL);
+       authctxt->style = buffer_get_string(m, NULL);
+       debug3("%s: service=%s, style=%s",
+           __func__, authctxt->service, authctxt->style);
+
+       if (strlen(authctxt->style) == 0) {
+               xfree(authctxt->style);
+               authctxt->style = NULL;
+       }
+
+       return (0);
+}
+
+int
+mm_answer_authpassword(int sock, Buffer *m)
+{
+       static int call_count;
+       char *passwd;
+       int authenticated;
+       u_int plen;
+
+       passwd = buffer_get_string(m, &plen);
+       /* Only authenticate if the context is valid */
+       authenticated = options.password_authentication &&
+           auth_password(authctxt, passwd);
+       memset(passwd, 0, strlen(passwd));
+       xfree(passwd);
+
+       buffer_clear(m);
+       buffer_put_int(m, authenticated);
+
+       debug3("%s: sending result %d", __func__, authenticated);
+       mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m);
+
+       call_count++;
+       if (plen == 0 && call_count == 1)
+               auth_method = "none";
+       else
+               auth_method = "password";
+
+       /* Causes monitor loop to terminate if authenticated */
+       return (authenticated);
+}
+
+#ifdef BSD_AUTH
+int
+mm_answer_bsdauthquery(int sock, Buffer *m)
+{
+       char *name, *infotxt;
+       u_int numprompts;
+       u_int *echo_on;
+       char **prompts;
+       u_int success;
+
+       success = bsdauth_query(authctxt, &name, &infotxt, &numprompts,
+           &prompts, &echo_on) < 0 ? 0 : 1;
+
+       buffer_clear(m);
+       buffer_put_int(m, success);
+       if (success)
+               buffer_put_cstring(m, prompts[0]);
+
+       debug3("%s: sending challenge success: %u", __func__, success);
+       mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m);
+
+       if (success) {
+               xfree(name);
+               xfree(infotxt);
+               xfree(prompts);
+               xfree(echo_on);
+       }
+
+       return (0);
+}
+
+int
+mm_answer_bsdauthrespond(int sock, Buffer *m)
+{
+       char *response;
+       int authok;
+
+       if (authctxt->as == 0)
+               fatal("%s: no bsd auth session", __func__);
+
+       response = buffer_get_string(m, NULL);
+       authok = options.challenge_response_authentication &&
+           auth_userresponse(authctxt->as, response, 0);
+       authctxt->as = NULL;
+       debug3("%s: <%s> = <%d>", __func__, response, authok);
+       xfree(response);
+
+       buffer_clear(m);
+       buffer_put_int(m, authok);
+
+       debug3("%s: sending authenticated: %d", __func__, authok);
+       mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m);
+
+       auth_method = "bsdauth";
+
+       return (authok != 0);
+}
+#endif
+
+#ifdef SKEY
+int
+mm_answer_skeyquery(int sock, Buffer *m)
+{
+       struct skey skey;
+       char challenge[1024];
+       u_int success;
+
+       success = _compat_skeychallenge(&skey, authctxt->user, challenge,
+           sizeof(challenge)) < 0 ? 0 : 1;
+
+       buffer_clear(m);
+       buffer_put_int(m, success);
+       if (success)
+               buffer_put_cstring(m, challenge);
+
+       debug3("%s: sending challenge success: %u", __func__, success);
+       mm_request_send(sock, MONITOR_ANS_SKEYQUERY, m);
+
+       return (0);
+}
+
+int
+mm_answer_skeyrespond(int sock, Buffer *m)
+{
+       char *response;
+       int authok;
+
+       response = buffer_get_string(m, NULL);
+
+       authok = (options.challenge_response_authentication &&
+           authctxt->valid &&
+           skey_haskey(authctxt->pw->pw_name) == 0 &&
+           skey_passcheck(authctxt->pw->pw_name, response) != -1);
+
+       xfree(response);
+
+       buffer_clear(m);
+       buffer_put_int(m, authok);
+
+       debug3("%s: sending authenticated: %d", __func__, authok);
+       mm_request_send(sock, MONITOR_ANS_SKEYRESPOND, m);
+
+       auth_method = "skey";
+
+       return (authok != 0);
+}
+#endif
+
+#ifdef USE_PAM
+int
+mm_answer_pam_start(int sock, Buffer *m)
+{
+       if (!options.use_pam)
+               fatal("UsePAM not set, but ended up in %s anyway", __func__);
+
+       start_pam(authctxt);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_PAM_ACCOUNT, 1);
+
+       return (0);
+}
+
+int
+mm_answer_pam_account(int sock, Buffer *m)
+{
+       u_int ret;
+
+       if (!options.use_pam)
+               fatal("UsePAM not set, but ended up in %s anyway", __func__);
+
+       ret = do_pam_account();
+
+       buffer_put_int(m, ret);
+       buffer_put_string(m, buffer_ptr(&loginmsg), buffer_len(&loginmsg));
+
+       mm_request_send(sock, MONITOR_ANS_PAM_ACCOUNT, m);
+
+       return (ret);
+}
+
+static void *sshpam_ctxt, *sshpam_authok;
+extern KbdintDevice sshpam_device;
+
+int
+mm_answer_pam_init_ctx(int sock, Buffer *m)
+{
+
+       debug3("%s", __func__);
+       authctxt->user = buffer_get_string(m, NULL);
+       sshpam_ctxt = (sshpam_device.init_ctx)(authctxt);
+       sshpam_authok = NULL;
+       buffer_clear(m);
+       if (sshpam_ctxt != NULL) {
+               monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1);
+               buffer_put_int(m, 1);
+       } else {
+               buffer_put_int(m, 0);
+       }
+       mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m);
+       return (0);
+}
+
+int
+mm_answer_pam_query(int sock, Buffer *m)
+{
+       char *name = NULL, *info = NULL, **prompts = NULL;
+       u_int i, num = 0, *echo_on = 0;
+       int ret;
+
+       debug3("%s", __func__);
+       sshpam_authok = NULL;
+       ret = (sshpam_device.query)(sshpam_ctxt, &name, &info, &num, &prompts, &echo_on);
+       if (ret == 0 && num == 0)
+               sshpam_authok = sshpam_ctxt;
+       if (num > 1 || name == NULL || info == NULL)
+               ret = -1;
+       buffer_clear(m);
+       buffer_put_int(m, ret);
+       buffer_put_cstring(m, name);
+       xfree(name);
+       buffer_put_cstring(m, info);
+       xfree(info);
+       buffer_put_int(m, num);
+       for (i = 0; i < num; ++i) {
+               buffer_put_cstring(m, prompts[i]);
+               xfree(prompts[i]);
+               buffer_put_int(m, echo_on[i]);
+       }
+       if (prompts != NULL)
+               xfree(prompts);
+       if (echo_on != NULL)
+               xfree(echo_on);
+       auth_method = "keyboard-interactive/pam";
+       mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m);
+       return (0);
+}
+
+int
+mm_answer_pam_respond(int sock, Buffer *m)
+{
+       char **resp;
+       u_int i, num;
+       int ret;
+
+       debug3("%s", __func__);
+       sshpam_authok = NULL;
+       num = buffer_get_int(m);
+       if (num > 0) {
+               resp = xcalloc(num, sizeof(char *));
+               for (i = 0; i < num; ++i)
+                       resp[i] = buffer_get_string(m, NULL);
+               ret = (sshpam_device.respond)(sshpam_ctxt, num, resp);
+               for (i = 0; i < num; ++i)
+                       xfree(resp[i]);
+               xfree(resp);
+       } else {
+               ret = (sshpam_device.respond)(sshpam_ctxt, num, NULL);
+       }
+       buffer_clear(m);
+       buffer_put_int(m, ret);
+       mm_request_send(sock, MONITOR_ANS_PAM_RESPOND, m);
+       auth_method = "keyboard-interactive/pam";
+       if (ret == 0)
+               sshpam_authok = sshpam_ctxt;
+       return (0);
+}
+
+int
+mm_answer_pam_free_ctx(int sock, Buffer *m)
+{
+
+       debug3("%s", __func__);
+       (sshpam_device.free_ctx)(sshpam_ctxt);
+       buffer_clear(m);
+       mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m);
+       auth_method = "keyboard-interactive/pam";
+       return (sshpam_authok == sshpam_ctxt);
+}
+#endif
+
+int
+mm_answer_keyallowed(int sock, Buffer *m)
+{
+       Key *key;
+       char *cuser, *chost;
+       u_char *blob;
+       u_int bloblen;
+       enum mm_keytype type = 0;
+       int allowed = 0;
+
+       debug3("%s entering", __func__);
+
+       type = buffer_get_int(m);
+       cuser = buffer_get_string(m, NULL);
+       chost = buffer_get_string(m, NULL);
+       blob = buffer_get_string(m, &bloblen);
+
+       key = key_from_blob(blob, bloblen);
+
+       if ((compat20 && type == MM_RSAHOSTKEY) ||
+           (!compat20 && type != MM_RSAHOSTKEY))
+               fatal("%s: key type and protocol mismatch", __func__);
+
+       debug3("%s: key_from_blob: %p", __func__, key);
+
+       if (key != NULL && authctxt->valid) {
+               switch (type) {
+               case MM_USERKEY:
+                       allowed = options.pubkey_authentication &&
+                           user_key_allowed(authctxt->pw, key);
+                       auth_method = "publickey";
+                       if (options.pubkey_authentication && allowed != 1)
+                               auth_clear_options();
+                       break;
+               case MM_HOSTKEY:
+                       allowed = options.hostbased_authentication &&
+                           hostbased_key_allowed(authctxt->pw,
+                           cuser, chost, key);
+                       auth_method = "hostbased";
+                       break;
+               case MM_RSAHOSTKEY:
+                       key->type = KEY_RSA1; /* XXX */
+                       allowed = options.rhosts_rsa_authentication &&
+                           auth_rhosts_rsa_key_allowed(authctxt->pw,
+                           cuser, chost, key);
+                       if (options.rhosts_rsa_authentication && allowed != 1)
+                               auth_clear_options();
+                       auth_method = "rsa";
+                       break;
+               default:
+                       fatal("%s: unknown key type %d", __func__, type);
+                       break;
+               }
+       }
+       if (key != NULL)
+               key_free(key);
+
+       /* clear temporarily storage (used by verify) */
+       monitor_reset_key_state();
+
+       if (allowed) {
+               /* Save temporarily for comparison in verify */
+               key_blob = blob;
+               key_bloblen = bloblen;
+               key_blobtype = type;
+               hostbased_cuser = cuser;
+               hostbased_chost = chost;
+       } else {
+               /* Log failed attempt */
+               auth_log(authctxt, 0, auth_method, compat20 ? " ssh2" : "");
+               xfree(blob);
+               xfree(cuser);
+               xfree(chost);
+       }
+
+       debug3("%s: key %p is %s",
+           __func__, key, allowed ? "allowed" : "not allowed");
+
+       buffer_clear(m);
+       buffer_put_int(m, allowed);
+       buffer_put_int(m, forced_command != NULL);
+
+       mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m);
+
+       if (type == MM_RSAHOSTKEY)
+               monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed);
+
+       return (0);
+}
+
+static int
+monitor_valid_userblob(u_char *data, u_int datalen)
+{
+       Buffer b;
+       char *p;
+       u_int len;
+       int fail = 0;
+
+       buffer_init(&b);
+       buffer_append(&b, data, datalen);
+
+       if (datafellows & SSH_OLD_SESSIONID) {
+               p = buffer_ptr(&b);
+               len = buffer_len(&b);
+               if ((session_id2 == NULL) ||
+                   (len < session_id2_len) ||
+                   (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
+                       fail++;
+               buffer_consume(&b, session_id2_len);
+       } else {
+               p = buffer_get_string(&b, &len);
+               if ((session_id2 == NULL) ||
+                   (len != session_id2_len) ||
+                   (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
+                       fail++;
+               xfree(p);
+       }
+       if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+               fail++;
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(authctxt->user, p) != 0) {
+               logit("wrong user name passed to monitor: expected %s != %.100s",
+                   authctxt->user, p);
+               fail++;
+       }
+       xfree(p);
+       buffer_skip_string(&b);
+       if (datafellows & SSH_BUG_PKAUTH) {
+               if (!buffer_get_char(&b))
+                       fail++;
+       } else {
+               p = buffer_get_string(&b, NULL);
+               if (strcmp("publickey", p) != 0)
+                       fail++;
+               xfree(p);
+               if (!buffer_get_char(&b))
+                       fail++;
+               buffer_skip_string(&b);
+       }
+       buffer_skip_string(&b);
+       if (buffer_len(&b) != 0)
+               fail++;
+       buffer_free(&b);
+       return (fail == 0);
+}
+
+static int
+monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
+    char *chost)
+{
+       Buffer b;
+       char *p;
+       u_int len;
+       int fail = 0;
+
+       buffer_init(&b);
+       buffer_append(&b, data, datalen);
+
+       p = buffer_get_string(&b, &len);
+       if ((session_id2 == NULL) ||
+           (len != session_id2_len) ||
+           (timingsafe_bcmp(p, session_id2, session_id2_len) != 0))
+               fail++;
+       xfree(p);
+
+       if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+               fail++;
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(authctxt->user, p) != 0) {
+               logit("wrong user name passed to monitor: expected %s != %.100s",
+                   authctxt->user, p);
+               fail++;
+       }
+       xfree(p);
+       buffer_skip_string(&b); /* service */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(p, "hostbased") != 0)
+               fail++;
+       xfree(p);
+       buffer_skip_string(&b); /* pkalg */
+       buffer_skip_string(&b); /* pkblob */
+
+       /* verify client host, strip trailing dot if necessary */
+       p = buffer_get_string(&b, NULL);
+       if (((len = strlen(p)) > 0) && p[len - 1] == '.')
+               p[len - 1] = '\0';
+       if (strcmp(p, chost) != 0)
+               fail++;
+       xfree(p);
+
+       /* verify client user */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp(p, cuser) != 0)
+               fail++;
+       xfree(p);
+
+       if (buffer_len(&b) != 0)
+               fail++;
+       buffer_free(&b);
+       return (fail == 0);
+}
+
+int
+mm_answer_keyverify(int sock, Buffer *m)
+{
+       Key *key;
+       u_char *signature, *data, *blob;
+       u_int signaturelen, datalen, bloblen;
+       int verified = 0;
+       int valid_data = 0;
+
+       blob = buffer_get_string(m, &bloblen);
+       signature = buffer_get_string(m, &signaturelen);
+       data = buffer_get_string(m, &datalen);
+
+       if (hostbased_cuser == NULL || hostbased_chost == NULL ||
+         !monitor_allowed_key(blob, bloblen))
+               fatal("%s: bad key, not previously allowed", __func__);
+
+       key = key_from_blob(blob, bloblen);
+       if (key == NULL)
+               fatal("%s: bad public key blob", __func__);
+
+       switch (key_blobtype) {
+       case MM_USERKEY:
+               valid_data = monitor_valid_userblob(data, datalen);
+               break;
+       case MM_HOSTKEY:
+               valid_data = monitor_valid_hostbasedblob(data, datalen,
+                   hostbased_cuser, hostbased_chost);
+               break;
+       default:
+               valid_data = 0;
+               break;
+       }
+       if (!valid_data)
+               fatal("%s: bad signature data blob", __func__);
+
+       verified = key_verify(key, signature, signaturelen, data, datalen);
+       debug3("%s: key %p signature %s",
+           __func__, key, (verified == 1) ? "verified" : "unverified");
+
+       key_free(key);
+       xfree(blob);
+       xfree(signature);
+       xfree(data);
+
+       auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
+
+       monitor_reset_key_state();
+
+       buffer_clear(m);
+       buffer_put_int(m, verified);
+       mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m);
+
+       return (verified == 1);
+}
+
+static void
+mm_record_login(Session *s, struct passwd *pw)
+{
+       socklen_t fromlen;
+       struct sockaddr_storage from;
+
+       /*
+        * 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));
+       fromlen = sizeof(from);
+       if (packet_connection_is_on_socket()) {
+               if (getpeername(packet_get_connection_in(),
+                   (struct sockaddr *)&from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       cleanup_exit(255);
+               }
+       }
+       /* Record that there was a login on that tty from the remote host. */
+       record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid,
+           get_remote_name_or_ip(utmp_len, options.use_dns),
+           (struct sockaddr *)&from, fromlen);
+}
+
+static void
+mm_session_close(Session *s)
+{
+       debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid);
+       if (s->ttyfd != -1) {
+               debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
+               session_pty_cleanup2(s);
+       }
+       session_unused(s->self);
+}
+
+int
+mm_answer_pty(int sock, Buffer *m)
+{
+       extern struct monitor *pmonitor;
+       Session *s;
+       int res, fd0;
+
+       debug3("%s entering", __func__);
+
+       buffer_clear(m);
+       s = session_new();
+       if (s == NULL)
+               goto error;
+       s->authctxt = authctxt;
+       s->pw = authctxt->pw;
+       s->pid = pmonitor->m_pid;
+       res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty));
+       if (res == 0)
+               goto error;
+       pty_setowner(authctxt->pw, s->tty);
+
+       buffer_put_int(m, 1);
+       buffer_put_cstring(m, s->tty);
+
+       /* We need to trick ttyslot */
+       if (dup2(s->ttyfd, 0) == -1)
+               fatal("%s: dup2", __func__);
+
+       mm_record_login(s, authctxt->pw);
+
+       /* Now we can close the file descriptor again */
+       close(0);
+
+       /* send messages generated by record_login */
+       buffer_put_string(m, buffer_ptr(&loginmsg), buffer_len(&loginmsg));
+       buffer_clear(&loginmsg);
+
+       mm_request_send(sock, MONITOR_ANS_PTY, m);
+
+       if (mm_send_fd(sock, s->ptyfd) == -1 ||
+           mm_send_fd(sock, s->ttyfd) == -1)
+               fatal("%s: send fds failed", __func__);
+
+       /* make sure nothing uses fd 0 */
+       if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0)
+               fatal("%s: open(/dev/null): %s", __func__, strerror(errno));
+       if (fd0 != 0)
+               error("%s: fd0 %d != 0", __func__, fd0);
+
+       /* slave is not needed */
+       close(s->ttyfd);
+       s->ttyfd = s->ptyfd;
+       /* no need to dup() because nobody closes ptyfd */
+       s->ptymaster = s->ptyfd;
+
+       debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ttyfd);
+
+       return (0);
+
+ error:
+       if (s != NULL)
+               mm_session_close(s);
+       buffer_put_int(m, 0);
+       mm_request_send(sock, MONITOR_ANS_PTY, m);
+       return (0);
+}
+
+int
+mm_answer_pty_cleanup(int sock, Buffer *m)
+{
+       Session *s;
+       char *tty;
+
+       debug3("%s entering", __func__);
+
+       tty = buffer_get_string(m, NULL);
+       if ((s = session_by_tty(tty)) != NULL)
+               mm_session_close(s);
+       buffer_clear(m);
+       xfree(tty);
+       return (0);
+}
+
+int
+mm_answer_sesskey(int sock, Buffer *m)
+{
+       BIGNUM *p;
+       int rsafail;
+
+       /* Turn off permissions */
+       monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 0);
+
+       if ((p = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       buffer_get_bignum2(m, p);
+
+       rsafail = ssh1_session_key(p);
+
+       buffer_clear(m);
+       buffer_put_int(m, rsafail);
+       buffer_put_bignum2(m, p);
+
+       BN_clear_free(p);
+
+       mm_request_send(sock, MONITOR_ANS_SESSKEY, m);
+
+       /* Turn on permissions for sessid passing */
+       monitor_permit(mon_dispatch, MONITOR_REQ_SESSID, 1);
+
+       return (0);
+}
+
+int
+mm_answer_sessid(int sock, Buffer *m)
+{
+       int i;
+
+       debug3("%s entering", __func__);
+
+       if (buffer_len(m) != 16)
+               fatal("%s: bad ssh1 session id", __func__);
+       for (i = 0; i < 16; i++)
+               session_id[i] = buffer_get_char(m);
+
+       /* Turn on permissions for getpwnam */
+       monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+
+       return (0);
+}
+
+int
+mm_answer_rsa_keyallowed(int sock, Buffer *m)
+{
+       BIGNUM *client_n;
+       Key *key = NULL;
+       u_char *blob = NULL;
+       u_int blen = 0;
+       int allowed = 0;
+
+       debug3("%s entering", __func__);
+
+       auth_method = "rsa";
+       if (options.rsa_authentication && authctxt->valid) {
+               if ((client_n = BN_new()) == NULL)
+                       fatal("%s: BN_new", __func__);
+               buffer_get_bignum2(m, client_n);
+               allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key);
+               BN_clear_free(client_n);
+       }
+       buffer_clear(m);
+       buffer_put_int(m, allowed);
+       buffer_put_int(m, forced_command != NULL);
+
+       /* clear temporarily storage (used by generate challenge) */
+       monitor_reset_key_state();
+
+       if (allowed && key != NULL) {
+               key->type = KEY_RSA;    /* cheat for key_to_blob */
+               if (key_to_blob(key, &blob, &blen) == 0)
+                       fatal("%s: key_to_blob failed", __func__);
+               buffer_put_string(m, blob, blen);
+
+               /* Save temporarily for comparison in verify */
+               key_blob = blob;
+               key_bloblen = blen;
+               key_blobtype = MM_RSAUSERKEY;
+       }
+       if (key != NULL)
+               key_free(key);
+
+       mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed);
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0);
+       return (0);
+}
+
+int
+mm_answer_rsa_challenge(int sock, Buffer *m)
+{
+       Key *key = NULL;
+       u_char *blob;
+       u_int blen;
+
+       debug3("%s entering", __func__);
+
+       if (!authctxt->valid)
+               fatal("%s: authctxt not valid", __func__);
+       blob = buffer_get_string(m, &blen);
+       if (!monitor_allowed_key(blob, blen))
+               fatal("%s: bad key, not previously allowed", __func__);
+       if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY)
+               fatal("%s: key type mismatch", __func__);
+       if ((key = key_from_blob(blob, blen)) == NULL)
+               fatal("%s: received bad key", __func__);
+       if (key->type != KEY_RSA)
+               fatal("%s: received bad key type %d", __func__, key->type);
+       key->type = KEY_RSA1;
+       if (ssh1_challenge)
+               BN_clear_free(ssh1_challenge);
+       ssh1_challenge = auth_rsa_generate_challenge(key);
+
+       buffer_clear(m);
+       buffer_put_bignum2(m, ssh1_challenge);
+
+       debug3("%s sending reply", __func__);
+       mm_request_send(sock, MONITOR_ANS_RSACHALLENGE, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1);
+
+       xfree(blob);
+       key_free(key);
+       return (0);
+}
+
+int
+mm_answer_rsa_response(int sock, Buffer *m)
+{
+       Key *key = NULL;
+       u_char *blob, *response;
+       u_int blen, len;
+       int success;
+
+       debug3("%s entering", __func__);
+
+       if (!authctxt->valid)
+               fatal("%s: authctxt not valid", __func__);
+       if (ssh1_challenge == NULL)
+               fatal("%s: no ssh1_challenge", __func__);
+
+       blob = buffer_get_string(m, &blen);
+       if (!monitor_allowed_key(blob, blen))
+               fatal("%s: bad key, not previously allowed", __func__);
+       if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY)
+               fatal("%s: key type mismatch: %d", __func__, key_blobtype);
+       if ((key = key_from_blob(blob, blen)) == NULL)
+               fatal("%s: received bad key", __func__);
+       response = buffer_get_string(m, &len);
+       if (len != 16)
+               fatal("%s: received bad response to challenge", __func__);
+       success = auth_rsa_verify_response(key, ssh1_challenge, response);
+
+       xfree(blob);
+       key_free(key);
+       xfree(response);
+
+       auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa";
+
+       /* reset state */
+       BN_clear_free(ssh1_challenge);
+       ssh1_challenge = NULL;
+       monitor_reset_key_state();
+
+       buffer_clear(m);
+       buffer_put_int(m, success);
+       mm_request_send(sock, MONITOR_ANS_RSARESPONSE, m);
+
+       return (success);
+}
+
+int
+mm_answer_term(int sock, Buffer *req)
+{
+       extern struct monitor *pmonitor;
+       int res, status;
+
+       debug3("%s: tearing down sessions", __func__);
+
+       /* The child is terminating */
+       session_destroy_all(&mm_session_close);
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               sshpam_cleanup();
+#endif
+
+       while (waitpid(pmonitor->m_pid, &status, 0) == -1)
+               if (errno != EINTR)
+                       exit(1);
+
+       res = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
+
+       /* Terminate process */
+       exit(res);
+}
+
+#ifdef SSH_AUDIT_EVENTS
+/* Report that an audit event occurred */
+int
+mm_answer_audit_event(int socket, Buffer *m)
+{
+       ssh_audit_event_t event;
+
+       debug3("%s entering", __func__);
+
+       event = buffer_get_int(m);
+       switch(event) {
+       case SSH_AUTH_FAIL_PUBKEY:
+       case SSH_AUTH_FAIL_HOSTBASED:
+       case SSH_AUTH_FAIL_GSSAPI:
+       case SSH_LOGIN_EXCEED_MAXTRIES:
+       case SSH_LOGIN_ROOT_DENIED:
+       case SSH_CONNECTION_CLOSE:
+       case SSH_INVALID_USER:
+               audit_event(event);
+               break;
+       default:
+               fatal("Audit event type %d not permitted", event);
+       }
+
+       return (0);
+}
+
+int
+mm_answer_audit_command(int socket, Buffer *m)
+{
+       u_int len;
+       char *cmd;
+
+       debug3("%s entering", __func__);
+       cmd = buffer_get_string(m, &len);
+       /* sanity check command, if so how? */
+       audit_run_command(cmd);
+       xfree(cmd);
+       return (0);
+}
+#endif /* SSH_AUDIT_EVENTS */
+
+void
+monitor_apply_keystate(struct monitor *pmonitor)
+{
+       if (compat20) {
+               set_newkeys(MODE_IN);
+               set_newkeys(MODE_OUT);
+       } else {
+               packet_set_protocol_flags(child_state.ssh1protoflags);
+               packet_set_encryption_key(child_state.ssh1key,
+                   child_state.ssh1keylen, child_state.ssh1cipher);
+               xfree(child_state.ssh1key);
+       }
+
+       /* for rc4 and other stateful ciphers */
+       packet_set_keycontext(MODE_OUT, child_state.keyout);
+       xfree(child_state.keyout);
+       packet_set_keycontext(MODE_IN, child_state.keyin);
+       xfree(child_state.keyin);
+
+       if (!compat20) {
+               packet_set_iv(MODE_OUT, child_state.ivout);
+               xfree(child_state.ivout);
+               packet_set_iv(MODE_IN, child_state.ivin);
+               xfree(child_state.ivin);
+       }
+
+       memcpy(&incoming_stream, &child_state.incoming,
+           sizeof(incoming_stream));
+       memcpy(&outgoing_stream, &child_state.outgoing,
+           sizeof(outgoing_stream));
+
+       /* Update with new address */
+       if (options.compression)
+               mm_init_compression(pmonitor->m_zlib);
+
+       /* Network I/O buffers */
+       /* XXX inefficient for large buffers, need: buffer_init_from_string */
+       buffer_clear(packet_get_input());
+       buffer_append(packet_get_input(), child_state.input, child_state.ilen);
+       memset(child_state.input, 0, child_state.ilen);
+       xfree(child_state.input);
+
+       buffer_clear(packet_get_output());
+       buffer_append(packet_get_output(), child_state.output,
+                     child_state.olen);
+       memset(child_state.output, 0, child_state.olen);
+       xfree(child_state.output);
+
+       /* Roaming */
+       if (compat20)
+               roam_set_bytes(child_state.sent_bytes, child_state.recv_bytes);
+}
+
+static Kex *
+mm_get_kex(Buffer *m)
+{
+       Kex *kex;
+       void *blob;
+       u_int bloblen;
+
+       kex = xcalloc(1, sizeof(*kex));
+       kex->session_id = buffer_get_string(m, &kex->session_id_len);
+       if (session_id2 == NULL ||
+           kex->session_id_len != session_id2_len ||
+           timingsafe_bcmp(kex->session_id, session_id2, session_id2_len) != 0)
+               fatal("mm_get_get: internal error: bad session id");
+       kex->we_need = buffer_get_int(m);
+       kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
+       kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
+       kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+       kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+       kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
+       kex->server = 1;
+       kex->hostkey_type = buffer_get_int(m);
+       kex->kex_type = buffer_get_int(m);
+       blob = buffer_get_string(m, &bloblen);
+       buffer_init(&kex->my);
+       buffer_append(&kex->my, blob, bloblen);
+       xfree(blob);
+       blob = buffer_get_string(m, &bloblen);
+       buffer_init(&kex->peer);
+       buffer_append(&kex->peer, blob, bloblen);
+       xfree(blob);
+       kex->done = 1;
+       kex->flags = buffer_get_int(m);
+       kex->client_version_string = buffer_get_string(m, NULL);
+       kex->server_version_string = buffer_get_string(m, NULL);
+       kex->load_host_public_key=&get_hostkey_public_by_type;
+       kex->load_host_private_key=&get_hostkey_private_by_type;
+       kex->host_key_index=&get_hostkey_index;
+
+       return (kex);
+}
+
+/* This function requries careful sanity checking */
+
+void
+mm_get_keystate(struct monitor *pmonitor)
+{
+       Buffer m;
+       u_char *blob, *p;
+       u_int bloblen, plen;
+       u_int32_t seqnr, packets;
+       u_int64_t blocks, bytes;
+
+       debug3("%s: Waiting for new keys", __func__);
+
+       buffer_init(&m);
+       mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m);
+       if (!compat20) {
+               child_state.ssh1protoflags = buffer_get_int(&m);
+               child_state.ssh1cipher = buffer_get_int(&m);
+               child_state.ssh1key = buffer_get_string(&m,
+                   &child_state.ssh1keylen);
+               child_state.ivout = buffer_get_string(&m,
+                   &child_state.ivoutlen);
+               child_state.ivin = buffer_get_string(&m, &child_state.ivinlen);
+               goto skip;
+       } else {
+               /* Get the Kex for rekeying */
+               *pmonitor->m_pkex = mm_get_kex(&m);
+       }
+
+       blob = buffer_get_string(&m, &bloblen);
+       current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen);
+       xfree(blob);
+
+       debug3("%s: Waiting for second key", __func__);
+       blob = buffer_get_string(&m, &bloblen);
+       current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen);
+       xfree(blob);
+
+       /* Now get sequence numbers for the packets */
+       seqnr = buffer_get_int(&m);
+       blocks = buffer_get_int64(&m);
+       packets = buffer_get_int(&m);
+       bytes = buffer_get_int64(&m);
+       packet_set_state(MODE_OUT, seqnr, blocks, packets, bytes);
+       seqnr = buffer_get_int(&m);
+       blocks = buffer_get_int64(&m);
+       packets = buffer_get_int(&m);
+       bytes = buffer_get_int64(&m);
+       packet_set_state(MODE_IN, seqnr, blocks, packets, bytes);
+
+ skip:
+       /* Get the key context */
+       child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen);
+       child_state.keyin  = buffer_get_string(&m, &child_state.keyinlen);
+
+       debug3("%s: Getting compression state", __func__);
+       /* Get compression state */
+       p = buffer_get_string(&m, &plen);
+       if (plen != sizeof(child_state.outgoing))
+               fatal("%s: bad request size", __func__);
+       memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing));
+       xfree(p);
+
+       p = buffer_get_string(&m, &plen);
+       if (plen != sizeof(child_state.incoming))
+               fatal("%s: bad request size", __func__);
+       memcpy(&child_state.incoming, p, sizeof(child_state.incoming));
+       xfree(p);
+
+       /* Network I/O buffers */
+       debug3("%s: Getting Network I/O buffers", __func__);
+       child_state.input = buffer_get_string(&m, &child_state.ilen);
+       child_state.output = buffer_get_string(&m, &child_state.olen);
+
+       /* Roaming */
+       if (compat20) {
+               child_state.sent_bytes = buffer_get_int64(&m);
+               child_state.recv_bytes = buffer_get_int64(&m);
+       }
+
+       buffer_free(&m);
+}
+
+
+/* Allocation functions for zlib */
+void *
+mm_zalloc(struct mm_master *mm, u_int ncount, u_int size)
+{
+       size_t len = (size_t) size * ncount;
+       void *address;
+
+       if (len == 0 || ncount > SIZE_T_MAX / size)
+               fatal("%s: mm_zalloc(%u, %u)", __func__, ncount, size);
+
+       address = mm_malloc(mm, len);
+
+       return (address);
+}
+
+void
+mm_zfree(struct mm_master *mm, void *address)
+{
+       mm_free(mm, address);
+}
+
+void
+mm_init_compression(struct mm_master *mm)
+{
+       outgoing_stream.zalloc = (alloc_func)mm_zalloc;
+       outgoing_stream.zfree = (free_func)mm_zfree;
+       outgoing_stream.opaque = mm;
+
+       incoming_stream.zalloc = (alloc_func)mm_zalloc;
+       incoming_stream.zfree = (free_func)mm_zfree;
+       incoming_stream.opaque = mm;
+}
+
+/* XXX */
+
+#define FD_CLOSEONEXEC(x) do { \
+       if (fcntl(x, F_SETFD, 1) == -1) \
+               fatal("fcntl(%d, F_SETFD)", x); \
+} while (0)
+
+static void
+monitor_socketpair(int *pair)
+{
+#ifdef HAVE_SOCKETPAIR
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
+               fatal("%s: socketpair", __func__);
+#else
+       fatal("%s: UsePrivilegeSeparation=yes not supported",
+           __func__);
+#endif
+       FD_CLOSEONEXEC(pair[0]);
+       FD_CLOSEONEXEC(pair[1]);
+}
+
+#define MM_MEMSIZE     65536
+
+struct monitor *
+monitor_init(void)
+{
+       struct monitor *mon;
+       int pair[2];
+
+       mon = xcalloc(1, sizeof(*mon));
+
+       monitor_socketpair(pair);
+
+       mon->m_recvfd = pair[0];
+       mon->m_sendfd = pair[1];
+
+       /* Used to share zlib space across processes */
+       if (options.compression) {
+               mon->m_zback = mm_create(NULL, MM_MEMSIZE);
+               mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE);
+
+               /* Compression needs to share state across borders */
+               mm_init_compression(mon->m_zlib);
+       }
+
+       return mon;
+}
+
+void
+monitor_reinit(struct monitor *mon)
+{
+       int pair[2];
+
+       monitor_socketpair(pair);
+
+       mon->m_recvfd = pair[0];
+       mon->m_sendfd = pair[1];
+}
+
+#ifdef GSSAPI
+int
+mm_answer_gss_setup_ctx(int sock, Buffer *m)
+{
+       gss_OID_desc goid;
+       OM_uint32 major;
+       u_int len;
+
+       goid.elements = buffer_get_string(m, &len);
+       goid.length = len;
+
+       major = ssh_gssapi_server_ctx(&gsscontext, &goid);
+
+       xfree(goid.elements);
+
+       buffer_clear(m);
+       buffer_put_int(m, major);
+
+       mm_request_send(sock, MONITOR_ANS_GSSSETUP, m);
+
+       /* Now we have a context, enable the step */
+       monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
+
+       return (0);
+}
+
+int
+mm_answer_gss_accept_ctx(int sock, Buffer *m)
+{
+       gss_buffer_desc in;
+       gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
+       OM_uint32 major, minor;
+       OM_uint32 flags = 0; /* GSI needs this */
+       u_int len;
+
+       in.value = buffer_get_string(m, &len);
+       in.length = len;
+       major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
+       xfree(in.value);
+
+       buffer_clear(m);
+       buffer_put_int(m, major);
+       buffer_put_string(m, out.value, out.length);
+       buffer_put_int(m, flags);
+       mm_request_send(sock, MONITOR_ANS_GSSSTEP, m);
+
+       gss_release_buffer(&minor, &out);
+
+       if (major == GSS_S_COMPLETE) {
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+       }
+       return (0);
+}
+
+int
+mm_answer_gss_checkmic(int sock, Buffer *m)
+{
+       gss_buffer_desc gssbuf, mic;
+       OM_uint32 ret;
+       u_int len;
+
+       gssbuf.value = buffer_get_string(m, &len);
+       gssbuf.length = len;
+       mic.value = buffer_get_string(m, &len);
+       mic.length = len;
+
+       ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic);
+
+       xfree(gssbuf.value);
+       xfree(mic.value);
+
+       buffer_clear(m);
+       buffer_put_int(m, ret);
+
+       mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m);
+
+       if (!GSS_ERROR(ret))
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+
+       return (0);
+}
+
+int
+mm_answer_gss_userok(int sock, Buffer *m)
+{
+       int authenticated;
+
+       authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
+
+       buffer_clear(m);
+       buffer_put_int(m, authenticated);
+
+       debug3("%s: sending result %d", __func__, authenticated);
+       mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
+
+       auth_method = "gssapi-with-mic";
+
+       /* Monitor loop will terminate if authenticated */
+       return (authenticated);
+}
+#endif /* GSSAPI */
+
+#ifdef JPAKE
+int
+mm_answer_jpake_step1(int sock, Buffer *m)
+{
+       struct jpake_ctx *pctx;
+       u_char *x3_proof, *x4_proof;
+       u_int x3_proof_len, x4_proof_len;
+
+       if (!options.zero_knowledge_password_authentication)
+               fatal("zero_knowledge_password_authentication disabled");
+
+       if (authctxt->jpake_ctx != NULL)
+               fatal("%s: authctxt->jpake_ctx already set (%p)",
+                   __func__, authctxt->jpake_ctx);
+       authctxt->jpake_ctx = pctx = jpake_new();
+
+       jpake_step1(pctx->grp,
+           &pctx->server_id, &pctx->server_id_len,
+           &pctx->x3, &pctx->x4, &pctx->g_x3, &pctx->g_x4,
+           &x3_proof, &x3_proof_len,
+           &x4_proof, &x4_proof_len);
+
+       JPAKE_DEBUG_CTX((pctx, "step1 done in %s", __func__));
+
+       buffer_clear(m);
+
+       buffer_put_string(m, pctx->server_id, pctx->server_id_len);
+       buffer_put_bignum2(m, pctx->g_x3);
+       buffer_put_bignum2(m, pctx->g_x4);
+       buffer_put_string(m, x3_proof, x3_proof_len);
+       buffer_put_string(m, x4_proof, x4_proof_len);
+
+       debug3("%s: sending step1", __func__);
+       mm_request_send(sock, MONITOR_ANS_JPAKE_STEP1, m);
+
+       bzero(x3_proof, x3_proof_len);
+       bzero(x4_proof, x4_proof_len);
+       xfree(x3_proof);
+       xfree(x4_proof);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_GET_PWDATA, 1);
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP1, 0);
+
+       return 0;
+}
+
+int
+mm_answer_jpake_get_pwdata(int sock, Buffer *m)
+{
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       char *hash_scheme, *salt;
+
+       if (pctx == NULL)
+               fatal("%s: pctx == NULL", __func__);
+
+       auth2_jpake_get_pwdata(authctxt, &pctx->s, &hash_scheme, &salt);
+
+       buffer_clear(m);
+       /* pctx->s is sensitive, not returned to slave */
+       buffer_put_cstring(m, hash_scheme);
+       buffer_put_cstring(m, salt);
+
+       debug3("%s: sending pwdata", __func__);
+       mm_request_send(sock, MONITOR_ANS_JPAKE_GET_PWDATA, m);
+
+       bzero(hash_scheme, strlen(hash_scheme));
+       bzero(salt, strlen(salt));
+       xfree(hash_scheme);
+       xfree(salt);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP2, 1);
+
+       return 0;
+}
+
+int
+mm_answer_jpake_step2(int sock, Buffer *m)
+{
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       u_char *x1_proof, *x2_proof, *x4_s_proof;
+       u_int x1_proof_len, x2_proof_len, x4_s_proof_len;
+
+       if (pctx == NULL)
+               fatal("%s: pctx == NULL", __func__);
+
+       if ((pctx->g_x1 = BN_new()) == NULL ||
+           (pctx->g_x2 = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       buffer_get_bignum2(m, pctx->g_x1);
+       buffer_get_bignum2(m, pctx->g_x2);
+       pctx->client_id = buffer_get_string(m, &pctx->client_id_len);
+       x1_proof = buffer_get_string(m, &x1_proof_len);
+       x2_proof = buffer_get_string(m, &x2_proof_len);
+
+       jpake_step2(pctx->grp, pctx->s, pctx->g_x3,
+           pctx->g_x1, pctx->g_x2, pctx->x4,
+           pctx->client_id, pctx->client_id_len,
+           pctx->server_id, pctx->server_id_len,
+           x1_proof, x1_proof_len,
+           x2_proof, x2_proof_len,
+           &pctx->b,
+           &x4_s_proof, &x4_s_proof_len);
+
+       JPAKE_DEBUG_CTX((pctx, "step2 done in %s", __func__));
+
+       bzero(x1_proof, x1_proof_len);
+       bzero(x2_proof, x2_proof_len);
+       xfree(x1_proof);
+       xfree(x2_proof);
+
+       buffer_clear(m);
+
+       buffer_put_bignum2(m, pctx->b);
+       buffer_put_string(m, x4_s_proof, x4_s_proof_len);
+
+       debug3("%s: sending step2", __func__);
+       mm_request_send(sock, MONITOR_ANS_JPAKE_STEP2, m);
+
+       bzero(x4_s_proof, x4_s_proof_len);
+       xfree(x4_s_proof);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_KEY_CONFIRM, 1);
+
+       return 0;
+}
+
+int
+mm_answer_jpake_key_confirm(int sock, Buffer *m)
+{
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+       u_char *x2_s_proof;
+       u_int x2_s_proof_len;
+
+       if (pctx == NULL)
+               fatal("%s: pctx == NULL", __func__);
+
+       if ((pctx->a = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       buffer_get_bignum2(m, pctx->a);
+       x2_s_proof = buffer_get_string(m, &x2_s_proof_len);
+
+       jpake_key_confirm(pctx->grp, pctx->s, pctx->a,
+           pctx->x4, pctx->g_x3, pctx->g_x4, pctx->g_x1, pctx->g_x2,
+           pctx->server_id, pctx->server_id_len,
+           pctx->client_id, pctx->client_id_len,
+           session_id2, session_id2_len,
+           x2_s_proof, x2_s_proof_len,
+           &pctx->k,
+           &pctx->h_k_sid_sessid, &pctx->h_k_sid_sessid_len);
+
+       JPAKE_DEBUG_CTX((pctx, "key_confirm done in %s", __func__));
+
+       bzero(x2_s_proof, x2_s_proof_len);
+       buffer_clear(m);
+
+       /* pctx->k is sensitive, not sent */
+       buffer_put_string(m, pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len);
+
+       debug3("%s: sending confirmation hash", __func__);
+       mm_request_send(sock, MONITOR_ANS_JPAKE_KEY_CONFIRM, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_CHECK_CONFIRM, 1);
+
+       return 0;
+}
+
+int
+mm_answer_jpake_check_confirm(int sock, Buffer *m)
+{
+       int authenticated = 0;
+       u_char *peer_confirm_hash;
+       u_int peer_confirm_hash_len;
+       struct jpake_ctx *pctx = authctxt->jpake_ctx;
+
+       if (pctx == NULL)
+               fatal("%s: pctx == NULL", __func__);
+
+       peer_confirm_hash = buffer_get_string(m, &peer_confirm_hash_len);
+
+       authenticated = jpake_check_confirm(pctx->k,
+           pctx->client_id, pctx->client_id_len,
+           session_id2, session_id2_len,
+           peer_confirm_hash, peer_confirm_hash_len) && authctxt->valid;
+
+       JPAKE_DEBUG_CTX((pctx, "check_confirm done in %s", __func__));
+
+       bzero(peer_confirm_hash, peer_confirm_hash_len);
+       xfree(peer_confirm_hash);
+
+       buffer_clear(m);
+       buffer_put_int(m, authenticated);
+
+       debug3("%s: sending result %d", __func__, authenticated);
+       mm_request_send(sock, MONITOR_ANS_JPAKE_CHECK_CONFIRM, m);
+
+       monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP1, 1);
+
+       auth_method = "jpake-01@openssh.com";
+       return authenticated;
+}
+
+#endif /* JPAKE */
diff --git a/monitor.h b/monitor.h
new file mode 100644 (file)
index 0000000..a8a2c0c
--- /dev/null
+++ b/monitor.h
@@ -0,0 +1,97 @@
+/* $OpenBSD: monitor.h,v 1.15 2008/11/04 08:22:13 djm Exp $ */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 _MONITOR_H_
+#define _MONITOR_H_
+
+enum monitor_reqtype {
+       MONITOR_REQ_MODULI, MONITOR_ANS_MODULI,
+       MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV,
+       MONITOR_REQ_SIGN, MONITOR_ANS_SIGN,
+       MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM,
+       MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER,
+       MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD,
+       MONITOR_REQ_BSDAUTHQUERY, MONITOR_ANS_BSDAUTHQUERY,
+       MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
+       MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
+       MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+       MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
+       MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
+       MONITOR_REQ_KEYEXPORT,
+       MONITOR_REQ_PTY, MONITOR_ANS_PTY,
+       MONITOR_REQ_PTYCLEANUP,
+       MONITOR_REQ_SESSKEY, MONITOR_ANS_SESSKEY,
+       MONITOR_REQ_SESSID,
+       MONITOR_REQ_RSAKEYALLOWED, MONITOR_ANS_RSAKEYALLOWED,
+       MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE,
+       MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE,
+       MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
+       MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
+       MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
+       MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
+       MONITOR_REQ_PAM_START,
+       MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
+       MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
+       MONITOR_REQ_PAM_QUERY, MONITOR_ANS_PAM_QUERY,
+       MONITOR_REQ_PAM_RESPOND, MONITOR_ANS_PAM_RESPOND,
+       MONITOR_REQ_PAM_FREE_CTX, MONITOR_ANS_PAM_FREE_CTX,
+       MONITOR_REQ_AUDIT_EVENT, MONITOR_REQ_AUDIT_COMMAND,
+       MONITOR_REQ_TERM,
+       MONITOR_REQ_JPAKE_STEP1, MONITOR_ANS_JPAKE_STEP1,
+       MONITOR_REQ_JPAKE_GET_PWDATA, MONITOR_ANS_JPAKE_GET_PWDATA,
+       MONITOR_REQ_JPAKE_STEP2, MONITOR_ANS_JPAKE_STEP2,
+       MONITOR_REQ_JPAKE_KEY_CONFIRM, MONITOR_ANS_JPAKE_KEY_CONFIRM,
+       MONITOR_REQ_JPAKE_CHECK_CONFIRM, MONITOR_ANS_JPAKE_CHECK_CONFIRM,
+};
+
+struct mm_master;
+struct monitor {
+       int                      m_recvfd;
+       int                      m_sendfd;
+       struct mm_master        *m_zback;
+       struct mm_master        *m_zlib;
+       struct Kex              **m_pkex;
+       pid_t                    m_pid;
+};
+
+struct monitor *monitor_init(void);
+void monitor_reinit(struct monitor *);
+void monitor_sync(struct monitor *);
+
+struct Authctxt;
+void monitor_child_preauth(struct Authctxt *, struct monitor *);
+void monitor_child_postauth(struct monitor *);
+
+struct mon_table;
+int monitor_read(struct monitor*, struct mon_table *, struct mon_table **);
+
+/* Prototypes for request sending and receiving */
+void mm_request_send(int, enum monitor_reqtype, Buffer *);
+void mm_request_receive(int, Buffer *);
+void mm_request_receive_expect(int, enum monitor_reqtype, Buffer *);
+
+#endif /* _MONITOR_H_ */
diff --git a/monitor_fdpass.c b/monitor_fdpass.c
new file mode 100644 (file)
index 0000000..7eb6f5c
--- /dev/null
@@ -0,0 +1,182 @@
+/* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 djm Exp $ */
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#include <errno.h>
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#include <string.h>
+#include <stdarg.h>
+
+#include "log.h"
+#include "monitor_fdpass.h"
+
+int
+mm_send_fd(int sock, int fd)
+{
+#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
+       struct msghdr msg;
+#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
+       union {
+               struct cmsghdr hdr;
+               char buf[CMSG_SPACE(sizeof(int))];
+       } cmsgbuf;
+       struct cmsghdr *cmsg;
+#endif
+       struct iovec vec;
+       char ch = '\0';
+       ssize_t n;
+       struct pollfd pfd;
+
+       memset(&msg, 0, sizeof(msg));
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
+       msg.msg_accrights = (caddr_t)&fd;
+       msg.msg_accrightslen = sizeof(fd);
+#else
+       msg.msg_control = (caddr_t)&cmsgbuf.buf;
+       msg.msg_controllen = sizeof(cmsgbuf.buf);
+       cmsg = CMSG_FIRSTHDR(&msg);
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+       *(int *)CMSG_DATA(cmsg) = fd;
+#endif
+
+       vec.iov_base = &ch;
+       vec.iov_len = 1;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+
+       pfd.fd = sock;
+       pfd.events = POLLOUT;
+       while ((n = sendmsg(sock, &msg, 0)) == -1 &&
+           (errno == EAGAIN || errno == EINTR)) {
+               debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno));
+               (void)poll(&pfd, 1, -1);
+       }
+       if (n == -1) {
+               error("%s: sendmsg(%d): %s", __func__, fd,
+                   strerror(errno));
+               return -1;
+       }
+
+       if (n != 1) {
+               error("%s: sendmsg: expected sent 1 got %ld",
+                   __func__, (long)n);
+               return -1;
+       }
+       return 0;
+#else
+       error("%s: file descriptor passing not supported", __func__);
+       return -1;
+#endif
+}
+
+int
+mm_receive_fd(int sock)
+{
+#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR))
+       struct msghdr msg;
+#ifndef HAVE_ACCRIGHTS_IN_MSGHDR
+       union {
+               struct cmsghdr hdr;
+               char buf[CMSG_SPACE(sizeof(int))];
+       } cmsgbuf;
+       struct cmsghdr *cmsg;
+#endif
+       struct iovec vec;
+       ssize_t n;
+       char ch;
+       int fd;
+       struct pollfd pfd;
+
+       memset(&msg, 0, sizeof(msg));
+       vec.iov_base = &ch;
+       vec.iov_len = 1;
+       msg.msg_iov = &vec;
+       msg.msg_iovlen = 1;
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
+       msg.msg_accrights = (caddr_t)&fd;
+       msg.msg_accrightslen = sizeof(fd);
+#else
+       msg.msg_control = &cmsgbuf.buf;
+       msg.msg_controllen = sizeof(cmsgbuf.buf);
+#endif
+
+       pfd.fd = sock;
+       pfd.events = POLLIN;
+       while ((n = recvmsg(sock, &msg, 0)) == -1 &&
+           (errno == EAGAIN || errno == EINTR)) {
+               debug3("%s: recvmsg: %s", __func__, strerror(errno));
+               (void)poll(&pfd, 1, -1);
+       }
+       if (n == -1) {
+               error("%s: recvmsg: %s", __func__, strerror(errno));
+               return -1;
+       }
+
+       if (n != 1) {
+               error("%s: recvmsg: expected received 1 got %ld",
+                   __func__, (long)n);
+               return -1;
+       }
+
+#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
+       if (msg.msg_accrightslen != sizeof(fd)) {
+               error("%s: no fd", __func__);
+               return -1;
+       }
+#else
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (cmsg == NULL) {
+               error("%s: no message header", __func__);
+               return -1;
+       }
+
+#ifndef BROKEN_CMSG_TYPE
+       if (cmsg->cmsg_type != SCM_RIGHTS) {
+               error("%s: expected type %d got %d", __func__,
+                   SCM_RIGHTS, cmsg->cmsg_type);
+               return -1;
+       }
+#endif
+       fd = (*(int *)CMSG_DATA(cmsg));
+#endif
+       return fd;
+#else
+       error("%s: file descriptor passing not supported", __func__);
+       return -1;
+#endif
+}
diff --git a/monitor_fdpass.h b/monitor_fdpass.h
new file mode 100644 (file)
index 0000000..a4b1f63
--- /dev/null
@@ -0,0 +1,34 @@
+/* $OpenBSD: monitor_fdpass.h,v 1.4 2007/09/04 03:21:03 djm Exp $ */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 _MM_FDPASS_H_
+#define _MM_FDPASS_H_
+
+int mm_send_fd(int, int);
+int mm_receive_fd(int);
+
+#endif /* _MM_FDPASS_H_ */
diff --git a/monitor_mm.c b/monitor_mm.c
new file mode 100644 (file)
index 0000000..faf9f3d
--- /dev/null
@@ -0,0 +1,352 @@
+/* $OpenBSD: monitor_mm.c,v 1.16 2009/06/22 05:39:28 dtucker Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/param.h>
+#include "openbsd-compat/sys-tree.h"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "log.h"
+#include "monitor_mm.h"
+
+static int
+mm_compare(struct mm_share *a, struct mm_share *b)
+{
+       long diff = (char *)a->address - (char *)b->address;
+
+       if (diff == 0)
+               return (0);
+       else if (diff < 0)
+               return (-1);
+       else
+               return (1);
+}
+
+RB_GENERATE(mmtree, mm_share, next, mm_compare)
+
+static struct mm_share *
+mm_make_entry(struct mm_master *mm, struct mmtree *head,
+    void *address, size_t size)
+{
+       struct mm_share *tmp, *tmp2;
+
+       if (mm->mmalloc == NULL)
+               tmp = xmalloc(sizeof(struct mm_share));
+       else
+               tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share));
+       tmp->address = address;
+       tmp->size = size;
+
+       tmp2 = RB_INSERT(mmtree, head, tmp);
+       if (tmp2 != NULL)
+               fatal("mm_make_entry(%p): double address %p->%p(%lu)",
+                   mm, tmp2, address, (u_long)size);
+
+       return (tmp);
+}
+
+/* Creates a shared memory area of a certain size */
+
+struct mm_master *
+mm_create(struct mm_master *mmalloc, size_t size)
+{
+       void *address;
+       struct mm_master *mm;
+
+       if (mmalloc == NULL)
+               mm = xmalloc(sizeof(struct mm_master));
+       else
+               mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
+
+       /*
+        * If the memory map has a mm_master it can be completely
+        * shared including authentication between the child
+        * and the client.
+        */
+       mm->mmalloc = mmalloc;
+
+       address = xmmap(size);
+       if (address == (void *)MAP_FAILED)
+               fatal("mmap(%lu): %s", (u_long)size, strerror(errno));
+
+       mm->address = address;
+       mm->size = size;
+
+       RB_INIT(&mm->rb_free);
+       RB_INIT(&mm->rb_allocated);
+
+       mm_make_entry(mm, &mm->rb_free, address, size);
+
+       return (mm);
+}
+
+/* Frees either the allocated or the free list */
+
+static void
+mm_freelist(struct mm_master *mmalloc, struct mmtree *head)
+{
+       struct mm_share *mms, *next;
+
+       for (mms = RB_ROOT(head); mms; mms = next) {
+               next = RB_NEXT(mmtree, head, mms);
+               RB_REMOVE(mmtree, head, mms);
+               if (mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mmalloc, mms);
+       }
+}
+
+/* Destroys a memory mapped area */
+
+void
+mm_destroy(struct mm_master *mm)
+{
+       mm_freelist(mm->mmalloc, &mm->rb_free);
+       mm_freelist(mm->mmalloc, &mm->rb_allocated);
+
+#ifdef HAVE_MMAP
+       if (munmap(mm->address, mm->size) == -1)
+               fatal("munmap(%p, %lu): %s", mm->address, (u_long)mm->size,
+                   strerror(errno));
+#else
+       fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported",
+           __func__);
+#endif
+       if (mm->mmalloc == NULL)
+               xfree(mm);
+       else
+               mm_free(mm->mmalloc, mm);
+}
+
+void *
+mm_xmalloc(struct mm_master *mm, size_t size)
+{
+       void *address;
+
+       address = mm_malloc(mm, size);
+       if (address == NULL)
+               fatal("%s: mm_malloc(%lu)", __func__, (u_long)size);
+       return (address);
+}
+
+
+/* Allocates data from a memory mapped area */
+
+void *
+mm_malloc(struct mm_master *mm, size_t size)
+{
+       struct mm_share *mms, *tmp;
+
+       if (size == 0)
+               fatal("mm_malloc: try to allocate 0 space");
+       if (size > SIZE_T_MAX - MM_MINSIZE + 1)
+               fatal("mm_malloc: size too big");
+
+       size = ((size + (MM_MINSIZE - 1)) / MM_MINSIZE) * MM_MINSIZE;
+
+       RB_FOREACH(mms, mmtree, &mm->rb_free) {
+               if (mms->size >= size)
+                       break;
+       }
+
+       if (mms == NULL)
+               return (NULL);
+
+       /* Debug */
+       memset(mms->address, 0xd0, size);
+
+       tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size);
+
+       /* Does not change order in RB tree */
+       mms->size -= size;
+       mms->address = (u_char *)mms->address + size;
+
+       if (mms->size == 0) {
+               RB_REMOVE(mmtree, &mm->rb_free, mms);
+               if (mm->mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mm->mmalloc, mms);
+       }
+
+       return (tmp->address);
+}
+
+/* Frees memory in a memory mapped area */
+
+void
+mm_free(struct mm_master *mm, void *address)
+{
+       struct mm_share *mms, *prev, tmp;
+
+       tmp.address = address;
+       mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp);
+       if (mms == NULL)
+               fatal("mm_free(%p): can not find %p", mm, address);
+
+       /* Debug */
+       memset(mms->address, 0xd0, mms->size);
+
+       /* Remove from allocated list and insert in free list */
+       RB_REMOVE(mmtree, &mm->rb_allocated, mms);
+       if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL)
+               fatal("mm_free(%p): double address %p", mm, address);
+
+       /* Find previous entry */
+       prev = mms;
+       if (RB_LEFT(prev, next)) {
+               prev = RB_LEFT(prev, next);
+               while (RB_RIGHT(prev, next))
+                       prev = RB_RIGHT(prev, next);
+       } else {
+               if (RB_PARENT(prev, next) &&
+                   (prev == RB_RIGHT(RB_PARENT(prev, next), next)))
+                       prev = RB_PARENT(prev, next);
+               else {
+                       while (RB_PARENT(prev, next) &&
+                           (prev == RB_LEFT(RB_PARENT(prev, next), next)))
+                               prev = RB_PARENT(prev, next);
+                       prev = RB_PARENT(prev, next);
+               }
+       }
+
+       /* Check if range does not overlap */
+       if (prev != NULL && MM_ADDRESS_END(prev) > address)
+               fatal("mm_free: memory corruption: %p(%lu) > %p",
+                   prev->address, (u_long)prev->size, address);
+
+       /* See if we can merge backwards */
+       if (prev != NULL && MM_ADDRESS_END(prev) == address) {
+               prev->size += mms->size;
+               RB_REMOVE(mmtree, &mm->rb_free, mms);
+               if (mm->mmalloc == NULL)
+                       xfree(mms);
+               else
+                       mm_free(mm->mmalloc, mms);
+       } else
+               prev = mms;
+
+       if (prev == NULL)
+               return;
+
+       /* Check if we can merge forwards */
+       mms = RB_NEXT(mmtree, &mm->rb_free, prev);
+       if (mms == NULL)
+               return;
+
+       if (MM_ADDRESS_END(prev) > mms->address)
+               fatal("mm_free: memory corruption: %p < %p(%lu)",
+                   mms->address, prev->address, (u_long)prev->size);
+       if (MM_ADDRESS_END(prev) != mms->address)
+               return;
+
+       prev->size += mms->size;
+       RB_REMOVE(mmtree, &mm->rb_free, mms);
+
+       if (mm->mmalloc == NULL)
+               xfree(mms);
+       else
+               mm_free(mm->mmalloc, mms);
+}
+
+static void
+mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree,
+    struct mm_master *mm, struct mm_master *mmold)
+{
+       struct mm_master *mmalloc = mm->mmalloc;
+       struct mm_share *mms, *new;
+
+       /* Sync free list */
+       RB_FOREACH(mms, mmtree, oldtree) {
+               /* Check the values */
+               mm_memvalid(mmold, mms, sizeof(struct mm_share));
+               mm_memvalid(mm, mms->address, mms->size);
+
+               new = mm_xmalloc(mmalloc, sizeof(struct mm_share));
+               memcpy(new, mms, sizeof(struct mm_share));
+               RB_INSERT(mmtree, newtree, new);
+       }
+}
+
+void
+mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc)
+{
+       struct mm_master *mm;
+       struct mm_master *mmalloc;
+       struct mm_master *mmold;
+       struct mmtree rb_free, rb_allocated;
+
+       debug3("%s: Share sync", __func__);
+
+       mm = *pmm;
+       mmold = mm->mmalloc;
+       mm_memvalid(mmold, mm, sizeof(*mm));
+
+       mmalloc = mm_create(NULL, mm->size);
+       mm = mm_xmalloc(mmalloc, sizeof(struct mm_master));
+       memcpy(mm, *pmm, sizeof(struct mm_master));
+       mm->mmalloc = mmalloc;
+
+       rb_free = mm->rb_free;
+       rb_allocated = mm->rb_allocated;
+
+       RB_INIT(&mm->rb_free);
+       RB_INIT(&mm->rb_allocated);
+
+       mm_sync_list(&rb_free, &mm->rb_free, mm, mmold);
+       mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold);
+
+       mm_destroy(mmold);
+
+       *pmm = mm;
+       *pmmalloc = mmalloc;
+
+       debug3("%s: Share sync end", __func__);
+}
+
+void
+mm_memvalid(struct mm_master *mm, void *address, size_t size)
+{
+       void *end = (u_char *)address + size;
+
+       if (address < mm->address)
+               fatal("mm_memvalid: address too small: %p", address);
+       if (end < address)
+               fatal("mm_memvalid: end < address: %p < %p", end, address);
+       if (end > (void *)((u_char *)mm->address + mm->size))
+               fatal("mm_memvalid: address too large: %p", address);
+}
diff --git a/monitor_mm.h b/monitor_mm.h
new file mode 100644 (file)
index 0000000..c890f77
--- /dev/null
@@ -0,0 +1,62 @@
+/* $OpenBSD: monitor_mm.h,v 1.5 2008/04/29 11:20:31 otto Exp $ */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 _MM_H_
+#define _MM_H_
+
+struct mm_share {
+       RB_ENTRY(mm_share) next;
+       void *address;
+       size_t size;
+};
+
+struct mm_master {
+       RB_HEAD(mmtree, mm_share) rb_free;
+       struct mmtree rb_allocated;
+       void *address;
+       size_t size;
+
+       struct mm_master *mmalloc;      /* Used to completely share */
+};
+
+RB_PROTOTYPE(mmtree, mm_share, next, mm_compare)
+
+#define MM_MINSIZE             128
+
+#define MM_ADDRESS_END(x)      (void *)((u_char *)(x)->address + (x)->size)
+
+struct mm_master *mm_create(struct mm_master *, size_t);
+void mm_destroy(struct mm_master *);
+
+void mm_share_sync(struct mm_master **, struct mm_master **);
+
+void *mm_malloc(struct mm_master *, size_t);
+void *mm_xmalloc(struct mm_master *, size_t);
+void mm_free(struct mm_master *, void *);
+
+void mm_memvalid(struct mm_master *, void *, size_t);
+#endif /* _MM_H_ */
diff --git a/monitor_wrap.c b/monitor_wrap.c
new file mode 100644 (file)
index 0000000..1a5dda5
--- /dev/null
@@ -0,0 +1,1414 @@
+/* $OpenBSD: monitor_wrap.c,v 1.70 2010/08/31 11:54:45 djm Exp $ */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * Copyright 2002 Markus Friedl <markus@openbsd.org>
+ * 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 <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "dh.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-options.h"
+#include "packet.h"
+#include "mac.h"
+#include "log.h"
+#ifdef TARGET_OS_MAC    /* XXX Broken krb5 headers on Mac */
+#undef TARGET_OS_MAC
+#include "zlib.h"
+#define TARGET_OS_MAC 1
+#else
+#include "zlib.h"
+#endif
+#include "monitor.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "atomicio.h"
+#include "monitor_fdpass.h"
+#include "misc.h"
+#include "schnorr.h"
+#include "jpake.h"
+#include "uuencode.h"
+
+#include "channels.h"
+#include "session.h"
+#include "servconf.h"
+#include "roaming.h"
+
+/* Imports */
+extern int compat20;
+extern z_stream incoming_stream;
+extern z_stream outgoing_stream;
+extern struct monitor *pmonitor;
+extern Buffer loginmsg;
+extern ServerOptions options;
+
+int
+mm_is_monitor(void)
+{
+       /*
+        * m_pid is only set in the privileged part, and
+        * points to the unprivileged child.
+        */
+       return (pmonitor && pmonitor->m_pid > 0);
+}
+
+void
+mm_request_send(int sock, enum monitor_reqtype type, Buffer *m)
+{
+       u_int mlen = buffer_len(m);
+       u_char buf[5];
+
+       debug3("%s entering: type %d", __func__, type);
+
+       put_u32(buf, mlen + 1);
+       buf[4] = (u_char) type;         /* 1st byte of payload is mesg-type */
+       if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf))
+               fatal("%s: write: %s", __func__, strerror(errno));
+       if (atomicio(vwrite, sock, buffer_ptr(m), mlen) != mlen)
+               fatal("%s: write: %s", __func__, strerror(errno));
+}
+
+void
+mm_request_receive(int sock, Buffer *m)
+{
+       u_char buf[4];
+       u_int msg_len;
+
+       debug3("%s entering", __func__);
+
+       if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) {
+               if (errno == EPIPE)
+                       cleanup_exit(255);
+               fatal("%s: read: %s", __func__, strerror(errno));
+       }
+       msg_len = get_u32(buf);
+       if (msg_len > 256 * 1024)
+               fatal("%s: read: bad msg_len %d", __func__, msg_len);
+       buffer_clear(m);
+       buffer_append_space(m, msg_len);
+       if (atomicio(read, sock, buffer_ptr(m), msg_len) != msg_len)
+               fatal("%s: read: %s", __func__, strerror(errno));
+}
+
+void
+mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
+{
+       u_char rtype;
+
+       debug3("%s entering: type %d", __func__, type);
+
+       mm_request_receive(sock, m);
+       rtype = buffer_get_char(m);
+       if (rtype != type)
+               fatal("%s: read: rtype %d != type %d", __func__,
+                   rtype, type);
+}
+
+DH *
+mm_choose_dh(int min, int nbits, int max)
+{
+       BIGNUM *p, *g;
+       int success = 0;
+       Buffer m;
+
+       buffer_init(&m);
+       buffer_put_int(&m, min);
+       buffer_put_int(&m, nbits);
+       buffer_put_int(&m, max);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_MODULI, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_MODULI", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_MODULI, &m);
+
+       success = buffer_get_char(&m);
+       if (success == 0)
+               fatal("%s: MONITOR_ANS_MODULI failed", __func__);
+
+       if ((p = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+       if ((g = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+       buffer_get_bignum2(&m, p);
+       buffer_get_bignum2(&m, g);
+
+       debug3("%s: remaining %d", __func__, buffer_len(&m));
+       buffer_free(&m);
+
+       return (dh_new_group(g, p));
+}
+
+int
+mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen)
+{
+       Kex *kex = *pmonitor->m_pkex;
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_int(&m, kex->host_key_index(key));
+       buffer_put_string(&m, data, datalen);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_SIGN", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, &m);
+       *sigp  = buffer_get_string(&m, lenp);
+       buffer_free(&m);
+
+       return (0);
+}
+
+struct passwd *
+mm_getpwnamallow(const char *username)
+{
+       Buffer m;
+       struct passwd *pw;
+       u_int len;
+       ServerOptions *newopts;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, username);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PWNAM, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_PWNAM", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PWNAM, &m);
+
+       if (buffer_get_char(&m) == 0) {
+               pw = NULL;
+               goto out;
+       }
+       pw = buffer_get_string(&m, &len);
+       if (len != sizeof(struct passwd))
+               fatal("%s: struct passwd size mismatch", __func__);
+       pw->pw_name = buffer_get_string(&m, NULL);
+       pw->pw_passwd = buffer_get_string(&m, NULL);
+       pw->pw_gecos = buffer_get_string(&m, NULL);
+#ifdef HAVE_PW_CLASS_IN_PASSWD
+       pw->pw_class = buffer_get_string(&m, NULL);
+#endif
+       pw->pw_dir = buffer_get_string(&m, NULL);
+       pw->pw_shell = buffer_get_string(&m, NULL);
+
+out:
+       /* copy options block as a Match directive may have changed some */
+       newopts = buffer_get_string(&m, &len);
+       if (len != sizeof(*newopts))
+               fatal("%s: option block size mismatch", __func__);
+       if (newopts->banner != NULL)
+               newopts->banner = buffer_get_string(&m, NULL);
+       copy_set_server_options(&options, newopts, 1);
+       xfree(newopts);
+
+       buffer_free(&m);
+
+       return (pw);
+}
+
+char *
+mm_auth2_read_banner(void)
+{
+       Buffer m;
+       char *banner;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTH2_READ_BANNER, &m);
+       buffer_clear(&m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_AUTH2_READ_BANNER, &m);
+       banner = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       /* treat empty banner as missing banner */
+       if (strlen(banner) == 0) {
+               xfree(banner);
+               banner = NULL;
+       }
+       return (banner);
+}
+
+/* Inform the privileged process about service and style */
+
+void
+mm_inform_authserv(char *service, char *style)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, service);
+       buffer_put_cstring(&m, style ? style : "");
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m);
+
+       buffer_free(&m);
+}
+
+/* Do the password authentication */
+int
+mm_auth_password(Authctxt *authctxt, char *password)
+{
+       Buffer m;
+       int authenticated = 0;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, password);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUTHPASSWORD, &m);
+
+       authenticated = buffer_get_int(&m);
+
+       buffer_free(&m);
+
+       debug3("%s: user %sauthenticated",
+           __func__, authenticated ? "" : "not ");
+       return (authenticated);
+}
+
+int
+mm_user_key_allowed(struct passwd *pw, Key *key)
+{
+       return (mm_key_allowed(MM_USERKEY, NULL, NULL, key));
+}
+
+int
+mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host,
+    Key *key)
+{
+       return (mm_key_allowed(MM_HOSTKEY, user, host, key));
+}
+
+int
+mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
+    char *host, Key *key)
+{
+       int ret;
+
+       key->type = KEY_RSA; /* XXX hack for key_to_blob */
+       ret = mm_key_allowed(MM_RSAHOSTKEY, user, host, key);
+       key->type = KEY_RSA1;
+       return (ret);
+}
+
+int
+mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key)
+{
+       Buffer m;
+       u_char *blob;
+       u_int len;
+       int allowed = 0, have_forced = 0;
+
+       debug3("%s entering", __func__);
+
+       /* Convert the key to a blob and the pass it over */
+       if (!key_to_blob(key, &blob, &len))
+               return (0);
+
+       buffer_init(&m);
+       buffer_put_int(&m, type);
+       buffer_put_cstring(&m, user ? user : "");
+       buffer_put_cstring(&m, host ? host : "");
+       buffer_put_string(&m, blob, len);
+       xfree(blob);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m);
+
+       allowed = buffer_get_int(&m);
+
+       /* fake forced command */
+       auth_clear_options();
+       have_forced = buffer_get_int(&m);
+       forced_command = have_forced ? xstrdup("true") : NULL;
+
+       buffer_free(&m);
+
+       return (allowed);
+}
+
+/*
+ * This key verify needs to send the key type along, because the
+ * privileged parent makes the decision if the key is allowed
+ * for authentication.
+ */
+
+int
+mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
+{
+       Buffer m;
+       u_char *blob;
+       u_int len;
+       int verified = 0;
+
+       debug3("%s entering", __func__);
+
+       /* Convert the key to a blob and the pass it over */
+       if (!key_to_blob(key, &blob, &len))
+               return (0);
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, len);
+       buffer_put_string(&m, sig, siglen);
+       buffer_put_string(&m, data, datalen);
+       xfree(blob);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m);
+
+       verified = buffer_get_int(&m);
+
+       buffer_free(&m);
+
+       return (verified);
+}
+
+/* Export key state after authentication */
+Newkeys *
+mm_newkeys_from_blob(u_char *blob, int blen)
+{
+       Buffer b;
+       u_int len;
+       Newkeys *newkey = NULL;
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+
+       debug3("%s: %p(%d)", __func__, blob, blen);
+#ifdef DEBUG_PK
+       dump_base64(stderr, blob, blen);
+#endif
+       buffer_init(&b);
+       buffer_append(&b, blob, blen);
+
+       newkey = xmalloc(sizeof(*newkey));
+       enc = &newkey->enc;
+       mac = &newkey->mac;
+       comp = &newkey->comp;
+
+       /* Enc structure */
+       enc->name = buffer_get_string(&b, NULL);
+       buffer_get(&b, &enc->cipher, sizeof(enc->cipher));
+       enc->enabled = buffer_get_int(&b);
+       enc->block_size = buffer_get_int(&b);
+       enc->key = buffer_get_string(&b, &enc->key_len);
+       enc->iv = buffer_get_string(&b, &len);
+       if (len != enc->block_size)
+               fatal("%s: bad ivlen: expected %u != %u", __func__,
+                   enc->block_size, len);
+
+       if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher)
+               fatal("%s: bad cipher name %s or pointer %p", __func__,
+                   enc->name, enc->cipher);
+
+       /* Mac structure */
+       mac->name = buffer_get_string(&b, NULL);
+       if (mac->name == NULL || mac_setup(mac, mac->name) == -1)
+               fatal("%s: can not setup mac %s", __func__, mac->name);
+       mac->enabled = buffer_get_int(&b);
+       mac->key = buffer_get_string(&b, &len);
+       if (len > mac->key_len)
+               fatal("%s: bad mac key length: %u > %d", __func__, len,
+                   mac->key_len);
+       mac->key_len = len;
+
+       /* Comp structure */
+       comp->type = buffer_get_int(&b);
+       comp->enabled = buffer_get_int(&b);
+       comp->name = buffer_get_string(&b, NULL);
+
+       len = buffer_len(&b);
+       if (len != 0)
+               error("newkeys_from_blob: remaining bytes in blob %u", len);
+       buffer_free(&b);
+       return (newkey);
+}
+
+int
+mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp)
+{
+       Buffer b;
+       int len;
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+       Newkeys *newkey = (Newkeys *)packet_get_newkeys(mode);
+
+       debug3("%s: converting %p", __func__, newkey);
+
+       if (newkey == NULL) {
+               error("%s: newkey == NULL", __func__);
+               return 0;
+       }
+       enc = &newkey->enc;
+       mac = &newkey->mac;
+       comp = &newkey->comp;
+
+       buffer_init(&b);
+       /* Enc structure */
+       buffer_put_cstring(&b, enc->name);
+       /* The cipher struct is constant and shared, you export pointer */
+       buffer_append(&b, &enc->cipher, sizeof(enc->cipher));
+       buffer_put_int(&b, enc->enabled);
+       buffer_put_int(&b, enc->block_size);
+       buffer_put_string(&b, enc->key, enc->key_len);
+       packet_get_keyiv(mode, enc->iv, enc->block_size);
+       buffer_put_string(&b, enc->iv, enc->block_size);
+
+       /* Mac structure */
+       buffer_put_cstring(&b, mac->name);
+       buffer_put_int(&b, mac->enabled);
+       buffer_put_string(&b, mac->key, mac->key_len);
+
+       /* Comp structure */
+       buffer_put_int(&b, comp->type);
+       buffer_put_int(&b, comp->enabled);
+       buffer_put_cstring(&b, comp->name);
+
+       len = buffer_len(&b);
+       if (lenp != NULL)
+               *lenp = len;
+       if (blobp != NULL) {
+               *blobp = xmalloc(len);
+               memcpy(*blobp, buffer_ptr(&b), len);
+       }
+       memset(buffer_ptr(&b), 0, len);
+       buffer_free(&b);
+       return len;
+}
+
+static void
+mm_send_kex(Buffer *m, Kex *kex)
+{
+       buffer_put_string(m, kex->session_id, kex->session_id_len);
+       buffer_put_int(m, kex->we_need);
+       buffer_put_int(m, kex->hostkey_type);
+       buffer_put_int(m, kex->kex_type);
+       buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my));
+       buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer));
+       buffer_put_int(m, kex->flags);
+       buffer_put_cstring(m, kex->client_version_string);
+       buffer_put_cstring(m, kex->server_version_string);
+}
+
+void
+mm_send_keystate(struct monitor *monitor)
+{
+       Buffer m, *input, *output;
+       u_char *blob, *p;
+       u_int bloblen, plen;
+       u_int32_t seqnr, packets;
+       u_int64_t blocks, bytes;
+
+       buffer_init(&m);
+
+       if (!compat20) {
+               u_char iv[24];
+               u_char *key;
+               u_int ivlen, keylen;
+
+               buffer_put_int(&m, packet_get_protocol_flags());
+
+               buffer_put_int(&m, packet_get_ssh1_cipher());
+
+               debug3("%s: Sending ssh1 KEY+IV", __func__);
+               keylen = packet_get_encryption_key(NULL);
+               key = xmalloc(keylen+1);        /* add 1 if keylen == 0 */
+               keylen = packet_get_encryption_key(key);
+               buffer_put_string(&m, key, keylen);
+               memset(key, 0, keylen);
+               xfree(key);
+
+               ivlen = packet_get_keyiv_len(MODE_OUT);
+               packet_get_keyiv(MODE_OUT, iv, ivlen);
+               buffer_put_string(&m, iv, ivlen);
+               ivlen = packet_get_keyiv_len(MODE_OUT);
+               packet_get_keyiv(MODE_IN, iv, ivlen);
+               buffer_put_string(&m, iv, ivlen);
+               goto skip;
+       } else {
+               /* Kex for rekeying */
+               mm_send_kex(&m, *monitor->m_pkex);
+       }
+
+       debug3("%s: Sending new keys: %p %p",
+           __func__, packet_get_newkeys(MODE_OUT),
+           packet_get_newkeys(MODE_IN));
+
+       /* Keys from Kex */
+       if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen))
+               fatal("%s: conversion of newkeys failed", __func__);
+
+       buffer_put_string(&m, blob, bloblen);
+       xfree(blob);
+
+       if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen))
+               fatal("%s: conversion of newkeys failed", __func__);
+
+       buffer_put_string(&m, blob, bloblen);
+       xfree(blob);
+
+       packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes);
+       buffer_put_int(&m, seqnr);
+       buffer_put_int64(&m, blocks);
+       buffer_put_int(&m, packets);
+       buffer_put_int64(&m, bytes);
+       packet_get_state(MODE_IN, &seqnr, &blocks, &packets, &bytes);
+       buffer_put_int(&m, seqnr);
+       buffer_put_int64(&m, blocks);
+       buffer_put_int(&m, packets);
+       buffer_put_int64(&m, bytes);
+
+       debug3("%s: New keys have been sent", __func__);
+ skip:
+       /* More key context */
+       plen = packet_get_keycontext(MODE_OUT, NULL);
+       p = xmalloc(plen+1);
+       packet_get_keycontext(MODE_OUT, p);
+       buffer_put_string(&m, p, plen);
+       xfree(p);
+
+       plen = packet_get_keycontext(MODE_IN, NULL);
+       p = xmalloc(plen+1);
+       packet_get_keycontext(MODE_IN, p);
+       buffer_put_string(&m, p, plen);
+       xfree(p);
+
+       /* Compression state */
+       debug3("%s: Sending compression state", __func__);
+       buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream));
+       buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream));
+
+       /* Network I/O buffers */
+       input = (Buffer *)packet_get_input();
+       output = (Buffer *)packet_get_output();
+       buffer_put_string(&m, buffer_ptr(input), buffer_len(input));
+       buffer_put_string(&m, buffer_ptr(output), buffer_len(output));
+
+       /* Roaming */
+       if (compat20) {
+               buffer_put_int64(&m, get_sent_bytes());
+               buffer_put_int64(&m, get_recv_bytes());
+       }
+
+       mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m);
+       debug3("%s: Finished sending state", __func__);
+
+       buffer_free(&m);
+}
+
+int
+mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
+{
+       Buffer m;
+       char *p, *msg;
+       int success = 0, tmp1 = -1, tmp2 = -1;
+
+       /* Kludge: ensure there are fds free to receive the pty/tty */
+       if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
+           (tmp2 = dup(pmonitor->m_recvfd)) == -1) {
+               error("%s: cannot allocate fds for pty", __func__);
+               if (tmp1 > 0)
+                       close(tmp1);
+               if (tmp2 > 0)
+                       close(tmp2);
+               return 0;
+       }
+       close(tmp1);
+       close(tmp2);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_PTY", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PTY, &m);
+
+       success = buffer_get_int(&m);
+       if (success == 0) {
+               debug3("%s: pty alloc failed", __func__);
+               buffer_free(&m);
+               return (0);
+       }
+       p = buffer_get_string(&m, NULL);
+       msg = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       strlcpy(namebuf, p, namebuflen); /* Possible truncation */
+       xfree(p);
+
+       buffer_append(&loginmsg, msg, strlen(msg));
+       xfree(msg);
+
+       if ((*ptyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1 ||
+           (*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
+               fatal("%s: receive fds failed", __func__);
+
+       /* Success */
+       return (1);
+}
+
+void
+mm_session_pty_cleanup2(Session *s)
+{
+       Buffer m;
+
+       if (s->ttyfd == -1)
+               return;
+       buffer_init(&m);
+       buffer_put_cstring(&m, s->tty);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, &m);
+       buffer_free(&m);
+
+       /* closed dup'ed master */
+       if (s->ptymaster != -1 && close(s->ptymaster) < 0)
+               error("close(s->ptymaster/%d): %s",
+                   s->ptymaster, strerror(errno));
+
+       /* unlink pty from session */
+       s->ttyfd = -1;
+}
+
+#ifdef USE_PAM
+void
+mm_start_pam(Authctxt *authctxt)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+       if (!options.use_pam)
+               fatal("UsePAM=no, but ended up in %s anyway", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, &m);
+
+       buffer_free(&m);
+}
+
+u_int
+mm_do_pam_account(void)
+{
+       Buffer m;
+       u_int ret;
+       char *msg;
+
+       debug3("%s entering", __func__);
+       if (!options.use_pam)
+               fatal("UsePAM=no, but ended up in %s anyway", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_PAM_ACCOUNT, &m);
+       ret = buffer_get_int(&m);
+       msg = buffer_get_string(&m, NULL);
+       buffer_append(&loginmsg, msg, strlen(msg));
+       xfree(msg);
+
+       buffer_free(&m);
+
+       debug3("%s returning %d", __func__, ret);
+
+       return (ret);
+}
+
+void *
+mm_sshpam_init_ctx(Authctxt *authctxt)
+{
+       Buffer m;
+       int success;
+
+       debug3("%s", __func__);
+       buffer_init(&m);
+       buffer_put_cstring(&m, authctxt->user);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m);
+       debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m);
+       success = buffer_get_int(&m);
+       if (success == 0) {
+               debug3("%s: pam_init_ctx failed", __func__);
+               buffer_free(&m);
+               return (NULL);
+       }
+       buffer_free(&m);
+       return (authctxt);
+}
+
+int
+mm_sshpam_query(void *ctx, char **name, char **info,
+    u_int *num, char ***prompts, u_int **echo_on)
+{
+       Buffer m;
+       u_int i;
+       int ret;
+
+       debug3("%s", __func__);
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, &m);
+       debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, &m);
+       ret = buffer_get_int(&m);
+       debug3("%s: pam_query returned %d", __func__, ret);
+       *name = buffer_get_string(&m, NULL);
+       *info = buffer_get_string(&m, NULL);
+       *num = buffer_get_int(&m);
+       if (*num > PAM_MAX_NUM_MSG)
+               fatal("%s: recieved %u PAM messages, expected <= %u",
+                   __func__, *num, PAM_MAX_NUM_MSG);
+       *prompts = xcalloc((*num + 1), sizeof(char *));
+       *echo_on = xcalloc((*num + 1), sizeof(u_int));
+       for (i = 0; i < *num; ++i) {
+               (*prompts)[i] = buffer_get_string(&m, NULL);
+               (*echo_on)[i] = buffer_get_int(&m);
+       }
+       buffer_free(&m);
+       return (ret);
+}
+
+int
+mm_sshpam_respond(void *ctx, u_int num, char **resp)
+{
+       Buffer m;
+       u_int i;
+       int ret;
+
+       debug3("%s", __func__);
+       buffer_init(&m);
+       buffer_put_int(&m, num);
+       for (i = 0; i < num; ++i)
+               buffer_put_cstring(&m, resp[i]);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, &m);
+       debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, &m);
+       ret = buffer_get_int(&m);
+       debug3("%s: pam_respond returned %d", __func__, ret);
+       buffer_free(&m);
+       return (ret);
+}
+
+void
+mm_sshpam_free_ctx(void *ctxtp)
+{
+       Buffer m;
+
+       debug3("%s", __func__);
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, &m);
+       debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, &m);
+       buffer_free(&m);
+}
+#endif /* USE_PAM */
+
+/* Request process termination */
+
+void
+mm_terminate(void)
+{
+       Buffer m;
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_TERM, &m);
+       buffer_free(&m);
+}
+
+int
+mm_ssh1_session_key(BIGNUM *num)
+{
+       int rsafail;
+       Buffer m;
+
+       buffer_init(&m);
+       buffer_put_bignum2(&m, num);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SESSKEY, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SESSKEY, &m);
+
+       rsafail = buffer_get_int(&m);
+       buffer_get_bignum2(&m, num);
+
+       buffer_free(&m);
+
+       return (rsafail);
+}
+
+static void
+mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
+    char ***prompts, u_int **echo_on)
+{
+       *name = xstrdup("");
+       *infotxt = xstrdup("");
+       *numprompts = 1;
+       *prompts = xcalloc(*numprompts, sizeof(char *));
+       *echo_on = xcalloc(*numprompts, sizeof(u_int));
+       (*echo_on)[0] = 0;
+}
+
+int
+mm_bsdauth_query(void *ctx, char **name, char **infotxt,
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+       Buffer m;
+       u_int success;
+       char *challenge;
+
+       debug3("%s: entering", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY,
+           &m);
+       success = buffer_get_int(&m);
+       if (success == 0) {
+               debug3("%s: no challenge", __func__);
+               buffer_free(&m);
+               return (-1);
+       }
+
+       /* Get the challenge, and format the response */
+       challenge  = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
+       (*prompts)[0] = challenge;
+
+       debug3("%s: received challenge: %s", __func__, challenge);
+
+       return (0);
+}
+
+int
+mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Buffer m;
+       int authok;
+
+       debug3("%s: entering", __func__);
+       if (numresponses != 1)
+               return (-1);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, responses[0]);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_BSDAUTHRESPOND, &m);
+
+       authok = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return ((authok == 0) ? -1 : 0);
+}
+
+#ifdef SKEY
+int
+mm_skey_query(void *ctx, char **name, char **infotxt,
+   u_int *numprompts, char ***prompts, u_int **echo_on)
+{
+       Buffer m;
+       u_int success;
+       char *challenge;
+
+       debug3("%s: entering", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SKEYQUERY,
+           &m);
+       success = buffer_get_int(&m);
+       if (success == 0) {
+               debug3("%s: no challenge", __func__);
+               buffer_free(&m);
+               return (-1);
+       }
+
+       /* Get the challenge, and format the response */
+       challenge  = buffer_get_string(&m, NULL);
+       buffer_free(&m);
+
+       debug3("%s: received challenge: %s", __func__, challenge);
+
+       mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
+
+       xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
+       xfree(challenge);
+
+       return (0);
+}
+
+int
+mm_skey_respond(void *ctx, u_int numresponses, char **responses)
+{
+       Buffer m;
+       int authok;
+
+       debug3("%s: entering", __func__);
+       if (numresponses != 1)
+               return (-1);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, responses[0]);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m);
+
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_SKEYRESPOND, &m);
+
+       authok = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return ((authok == 0) ? -1 : 0);
+}
+#endif /* SKEY */
+
+void
+mm_ssh1_session_id(u_char session_id[16])
+{
+       Buffer m;
+       int i;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       for (i = 0; i < 16; i++)
+               buffer_put_char(&m, session_id[i]);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SESSID, &m);
+       buffer_free(&m);
+}
+
+int
+mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
+{
+       Buffer m;
+       Key *key;
+       u_char *blob;
+       u_int blen;
+       int allowed = 0, have_forced = 0;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_bignum2(&m, client_n);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m);
+
+       allowed = buffer_get_int(&m);
+
+       /* fake forced command */
+       auth_clear_options();
+       have_forced = buffer_get_int(&m);
+       forced_command = have_forced ? xstrdup("true") : NULL;
+
+       if (allowed && rkey != NULL) {
+               blob = buffer_get_string(&m, &blen);
+               if ((key = key_from_blob(blob, blen)) == NULL)
+                       fatal("%s: key_from_blob failed", __func__);
+               *rkey = key;
+               xfree(blob);
+       }
+       buffer_free(&m);
+
+       return (allowed);
+}
+
+BIGNUM *
+mm_auth_rsa_generate_challenge(Key *key)
+{
+       Buffer m;
+       BIGNUM *challenge;
+       u_char *blob;
+       u_int blen;
+
+       debug3("%s entering", __func__);
+
+       if ((challenge = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+
+       key->type = KEY_RSA;    /* XXX cheat for key_to_blob */
+       if (key_to_blob(key, &blob, &blen) == 0)
+               fatal("%s: key_to_blob failed", __func__);
+       key->type = KEY_RSA1;
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, blen);
+       xfree(blob);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m);
+
+       buffer_get_bignum2(&m, challenge);
+       buffer_free(&m);
+
+       return (challenge);
+}
+
+int
+mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
+{
+       Buffer m;
+       u_char *blob;
+       u_int blen;
+       int success = 0;
+
+       debug3("%s entering", __func__);
+
+       key->type = KEY_RSA;    /* XXX cheat for key_to_blob */
+       if (key_to_blob(key, &blob, &blen) == 0)
+               fatal("%s: key_to_blob failed", __func__);
+       key->type = KEY_RSA1;
+
+       buffer_init(&m);
+       buffer_put_string(&m, blob, blen);
+       buffer_put_string(&m, response, 16);
+       xfree(blob);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m);
+
+       success = buffer_get_int(&m);
+       buffer_free(&m);
+
+       return (success);
+}
+
+#ifdef SSH_AUDIT_EVENTS
+void
+mm_audit_event(ssh_audit_event_t event)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_int(&m, event);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, &m);
+       buffer_free(&m);
+}
+
+void
+mm_audit_run_command(const char *command)
+{
+       Buffer m;
+
+       debug3("%s entering command %s", __func__, command);
+
+       buffer_init(&m);
+       buffer_put_cstring(&m, command);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
+       buffer_free(&m);
+}
+#endif /* SSH_AUDIT_EVENTS */
+
+#ifdef GSSAPI
+OM_uint32
+mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
+{
+       Buffer m;
+       OM_uint32 major;
+
+       /* Client doesn't get to see the context */
+       *ctx = NULL;
+
+       buffer_init(&m);
+       buffer_put_string(&m, goid->elements, goid->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
+
+       major = buffer_get_int(&m);
+
+       buffer_free(&m);
+       return (major);
+}
+
+OM_uint32
+mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
+    gss_buffer_desc *out, OM_uint32 *flags)
+{
+       Buffer m;
+       OM_uint32 major;
+       u_int len;
+
+       buffer_init(&m);
+       buffer_put_string(&m, in->value, in->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
+
+       major = buffer_get_int(&m);
+       out->value = buffer_get_string(&m, &len);
+       out->length = len;
+       if (flags)
+               *flags = buffer_get_int(&m);
+
+       buffer_free(&m);
+
+       return (major);
+}
+
+OM_uint32
+mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+{
+       Buffer m;
+       OM_uint32 major;
+
+       buffer_init(&m);
+       buffer_put_string(&m, gssbuf->value, gssbuf->length);
+       buffer_put_string(&m, gssmic->value, gssmic->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSCHECKMIC,
+           &m);
+
+       major = buffer_get_int(&m);
+       buffer_free(&m);
+       return(major);
+}
+
+int
+mm_ssh_gssapi_userok(char *user)
+{
+       Buffer m;
+       int authenticated = 0;
+
+       buffer_init(&m);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
+                                 &m);
+
+       authenticated = buffer_get_int(&m);
+
+       buffer_free(&m);
+       debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
+       return (authenticated);
+}
+#endif /* GSSAPI */
+
+#ifdef JPAKE
+void
+mm_auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s,
+    char **hash_scheme, char **salt)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd,
+           MONITOR_REQ_JPAKE_GET_PWDATA, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_JPAKE_GET_PWDATA", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_JPAKE_GET_PWDATA, &m);
+
+       *hash_scheme = buffer_get_string(&m, NULL);
+       *salt = buffer_get_string(&m, NULL);
+
+       buffer_free(&m);
+}
+
+void
+mm_jpake_step1(struct modp_group *grp,
+    u_char **id, u_int *id_len,
+    BIGNUM **priv1, BIGNUM **priv2, BIGNUM **g_priv1, BIGNUM **g_priv2,
+    u_char **priv1_proof, u_int *priv1_proof_len,
+    u_char **priv2_proof, u_int *priv2_proof_len)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       mm_request_send(pmonitor->m_recvfd,
+           MONITOR_REQ_JPAKE_STEP1, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_JPAKE_STEP1", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_JPAKE_STEP1, &m);
+
+       if ((*priv1 = BN_new()) == NULL ||
+           (*priv2 = BN_new()) == NULL ||
+           (*g_priv1 = BN_new()) == NULL ||
+           (*g_priv2 = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       *id = buffer_get_string(&m, id_len);
+       /* priv1 and priv2 are, well, private */
+       buffer_get_bignum2(&m, *g_priv1);
+       buffer_get_bignum2(&m, *g_priv2);
+       *priv1_proof = buffer_get_string(&m, priv1_proof_len);
+       *priv2_proof = buffer_get_string(&m, priv2_proof_len);
+
+       buffer_free(&m);
+}
+
+void
+mm_jpake_step2(struct modp_group *grp, BIGNUM *s,
+    BIGNUM *mypub1, BIGNUM *theirpub1, BIGNUM *theirpub2, BIGNUM *mypriv2,
+    const u_char *theirid, u_int theirid_len,
+    const u_char *myid, u_int myid_len,
+    const u_char *theirpub1_proof, u_int theirpub1_proof_len,
+    const u_char *theirpub2_proof, u_int theirpub2_proof_len,
+    BIGNUM **newpub,
+    u_char **newpub_exponent_proof, u_int *newpub_exponent_proof_len)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       /* monitor already has all bignums except theirpub1, theirpub2 */
+       buffer_put_bignum2(&m, theirpub1);
+       buffer_put_bignum2(&m, theirpub2);
+       /* monitor already knows our id */
+       buffer_put_string(&m, theirid, theirid_len);
+       buffer_put_string(&m, theirpub1_proof, theirpub1_proof_len);
+       buffer_put_string(&m, theirpub2_proof, theirpub2_proof_len);
+
+       mm_request_send(pmonitor->m_recvfd,
+           MONITOR_REQ_JPAKE_STEP2, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_JPAKE_STEP2", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_JPAKE_STEP2, &m);
+
+       if ((*newpub = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       buffer_get_bignum2(&m, *newpub);
+       *newpub_exponent_proof = buffer_get_string(&m,
+           newpub_exponent_proof_len);
+
+       buffer_free(&m);
+}
+
+void
+mm_jpake_key_confirm(struct modp_group *grp, BIGNUM *s, BIGNUM *step2_val,
+    BIGNUM *mypriv2, BIGNUM *mypub1, BIGNUM *mypub2,
+    BIGNUM *theirpub1, BIGNUM *theirpub2,
+    const u_char *my_id, u_int my_id_len,
+    const u_char *their_id, u_int their_id_len,
+    const u_char *sess_id, u_int sess_id_len,
+    const u_char *theirpriv2_s_proof, u_int theirpriv2_s_proof_len,
+    BIGNUM **k,
+    u_char **confirm_hash, u_int *confirm_hash_len)
+{
+       Buffer m;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       /* monitor already has all bignums except step2_val */
+       buffer_put_bignum2(&m, step2_val);
+       /* monitor already knows all the ids */
+       buffer_put_string(&m, theirpriv2_s_proof, theirpriv2_s_proof_len);
+
+       mm_request_send(pmonitor->m_recvfd,
+           MONITOR_REQ_JPAKE_KEY_CONFIRM, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_JPAKE_KEY_CONFIRM", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_JPAKE_KEY_CONFIRM, &m);
+
+       /* 'k' is sensitive and stays in the monitor */
+       *confirm_hash = buffer_get_string(&m, confirm_hash_len);
+
+       buffer_free(&m);
+}
+
+int
+mm_jpake_check_confirm(const BIGNUM *k,
+    const u_char *peer_id, u_int peer_id_len,
+    const u_char *sess_id, u_int sess_id_len,
+    const u_char *peer_confirm_hash, u_int peer_confirm_hash_len)
+{
+       Buffer m;
+       int success = 0;
+
+       debug3("%s entering", __func__);
+
+       buffer_init(&m);
+       /* k is dummy in slave, ignored */
+       /* monitor knows all the ids */
+       buffer_put_string(&m, peer_confirm_hash, peer_confirm_hash_len);
+       mm_request_send(pmonitor->m_recvfd,
+           MONITOR_REQ_JPAKE_CHECK_CONFIRM, &m);
+
+       debug3("%s: waiting for MONITOR_ANS_JPAKE_CHECK_CONFIRM", __func__);
+       mm_request_receive_expect(pmonitor->m_recvfd,
+           MONITOR_ANS_JPAKE_CHECK_CONFIRM, &m);
+
+       success = buffer_get_int(&m);
+       buffer_free(&m);
+
+       debug3("%s: success = %d", __func__, success);
+       return success;
+}
+#endif /* JPAKE */
diff --git a/monitor_wrap.h b/monitor_wrap.h
new file mode 100644 (file)
index 0000000..de2d16f
--- /dev/null
@@ -0,0 +1,130 @@
+/* $OpenBSD: monitor_wrap.h,v 1.22 2009/03/05 07:18:19 djm Exp $ */
+
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 _MM_WRAP_H_
+#define _MM_WRAP_H_
+
+extern int use_privsep;
+#define PRIVSEP(x)     (use_privsep ? mm_##x : x)
+
+enum mm_keytype {MM_NOKEY, MM_HOSTKEY, MM_USERKEY, MM_RSAHOSTKEY, MM_RSAUSERKEY};
+
+struct monitor;
+struct mm_master;
+struct Authctxt;
+
+int mm_is_monitor(void);
+DH *mm_choose_dh(int, int, int);
+int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int);
+void mm_inform_authserv(char *, char *);
+struct passwd *mm_getpwnamallow(const char *);
+char *mm_auth2_read_banner(void);
+int mm_auth_password(struct Authctxt *, char *);
+int mm_key_allowed(enum mm_keytype, char *, char *, Key *);
+int mm_user_key_allowed(struct passwd *, Key *);
+int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *);
+int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *);
+int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
+int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
+int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
+BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+
+#ifdef GSSAPI
+OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
+   gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+int mm_ssh_gssapi_userok(char *user);
+OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+#endif
+
+#ifdef USE_PAM
+void mm_start_pam(struct Authctxt *);
+u_int mm_do_pam_account(void);
+void *mm_sshpam_init_ctx(struct Authctxt *);
+int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_sshpam_respond(void *, u_int, char **);
+void mm_sshpam_free_ctx(void *);
+#endif
+
+#ifdef SSH_AUDIT_EVENTS
+#include "audit.h"
+void mm_audit_event(ssh_audit_event_t);
+void mm_audit_run_command(const char *);
+#endif
+
+struct Session;
+void mm_terminate(void);
+int mm_pty_allocate(int *, int *, char *, size_t);
+void mm_session_pty_cleanup2(struct Session *);
+
+/* SSHv1 interfaces */
+void mm_ssh1_session_id(u_char *);
+int mm_ssh1_session_key(BIGNUM *);
+
+/* Key export functions */
+struct Newkeys *mm_newkeys_from_blob(u_char *, int);
+int mm_newkeys_to_blob(int, u_char **, u_int *);
+
+void monitor_apply_keystate(struct monitor *);
+void mm_get_keystate(struct monitor *);
+void mm_send_keystate(struct monitor*);
+
+/* bsdauth */
+int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_bsdauth_respond(void *, u_int, char **);
+
+/* skey */
+int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
+int mm_skey_respond(void *, u_int, char **);
+
+/* jpake */
+struct modp_group;
+void mm_auth2_jpake_get_pwdata(struct Authctxt *, BIGNUM **, char **, char **);
+void mm_jpake_step1(struct modp_group *, u_char **, u_int *,
+    BIGNUM **, BIGNUM **, BIGNUM **, BIGNUM **,
+    u_char **, u_int *, u_char **, u_int *);
+void mm_jpake_step2(struct modp_group *, BIGNUM *,
+    BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
+    const u_char *, u_int, const u_char *, u_int,
+    const u_char *, u_int, const u_char *, u_int,
+    BIGNUM **, u_char **, u_int *);
+void mm_jpake_key_confirm(struct modp_group *, BIGNUM *, BIGNUM *,
+    BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *,
+    const u_char *, u_int, const u_char *, u_int,
+    const u_char *, u_int, const u_char *, u_int,
+    BIGNUM **, u_char **, u_int *);
+int mm_jpake_check_confirm(const BIGNUM *,
+    const u_char *, u_int, const u_char *, u_int, const u_char *, u_int);
+
+
+/* zlib allocation hooks */
+
+void *mm_zalloc(struct mm_master *, u_int, u_int);
+void mm_zfree(struct mm_master *, void *);
+void mm_init_compression(struct mm_master *);
+
+#endif /* _MM_WRAP_H_ */
diff --git a/msg.c b/msg.c
new file mode 100644 (file)
index 0000000..cd5f98c
--- /dev/null
+++ b/msg.c
@@ -0,0 +1,89 @@
+/* $OpenBSD: msg.c,v 1.15 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2002 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 <sys/types.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "buffer.h"
+#include "log.h"
+#include "atomicio.h"
+#include "msg.h"
+#include "misc.h"
+
+int
+ssh_msg_send(int fd, u_char type, Buffer *m)
+{
+       u_char buf[5];
+       u_int mlen = buffer_len(m);
+
+       debug3("ssh_msg_send: type %u", (unsigned int)type & 0xff);
+
+       put_u32(buf, mlen + 1);
+       buf[4] = type;          /* 1st byte of payload is mesg-type */
+       if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) {
+               error("ssh_msg_send: write");
+               return (-1);
+       }
+       if (atomicio(vwrite, fd, buffer_ptr(m), mlen) != mlen) {
+               error("ssh_msg_send: write");
+               return (-1);
+       }
+       return (0);
+}
+
+int
+ssh_msg_recv(int fd, Buffer *m)
+{
+       u_char buf[4];
+       u_int msg_len;
+
+       debug3("ssh_msg_recv entering");
+
+       if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) {
+               if (errno != EPIPE)
+                       error("ssh_msg_recv: read: header");
+               return (-1);
+       }
+       msg_len = get_u32(buf);
+       if (msg_len > 256 * 1024) {
+               error("ssh_msg_recv: read: bad msg_len %u", msg_len);
+               return (-1);
+       }
+       buffer_clear(m);
+       buffer_append_space(m, msg_len);
+       if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
+               error("ssh_msg_recv: read: %s", strerror(errno));
+               return (-1);
+       }
+       return (0);
+}
diff --git a/msg.h b/msg.h
new file mode 100644 (file)
index 0000000..b0cb9b5
--- /dev/null
+++ b/msg.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: msg.h,v 1.4 2006/03/25 22:22:43 djm Exp $ */
+/*
+ * Copyright (c) 2002 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_MSG_H
+#define SSH_MSG_H
+
+int     ssh_msg_send(int, u_char, Buffer *);
+int     ssh_msg_recv(int, Buffer *);
+
+#endif
diff --git a/mux.c b/mux.c
new file mode 100644 (file)
index 0000000..e370462
--- /dev/null
+++ b/mux.c
@@ -0,0 +1,1912 @@
+/* $OpenBSD: mux.c,v 1.24 2011/01/13 21:54:53 djm Exp $ */
+/*
+ * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ssh session multiplexing support */
+
+/*
+ * TODO:
+ *   - Better signalling from master to slave, especially passing of
+ *      error messages
+ *   - Better fall-back from mux slave error to new connection.
+ *   - ExitOnForwardingFailure
+ *   - Maybe extension mechanisms for multi-X11/multi-agent forwarding
+ *   - Support ~^Z in mux slaves.
+ *   - Inspect or control sessions in master.
+ *   - If we ever support the "signal" channel request, send signals on
+ *     sessions in master.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+# endif
+#endif
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "ssh.h"
+#include "ssh2.h"
+#include "pathnames.h"
+#include "misc.h"
+#include "match.h"
+#include "buffer.h"
+#include "channels.h"
+#include "msg.h"
+#include "packet.h"
+#include "monitor_fdpass.h"
+#include "sshpty.h"
+#include "key.h"
+#include "readconf.h"
+#include "clientloop.h"
+
+/* from ssh.c */
+extern int tty_flag;
+extern int force_tty_flag;
+extern Options options;
+extern int stdin_null_flag;
+extern char *host;
+extern int subsystem_flag;
+extern Buffer command;
+extern volatile sig_atomic_t quit_pending;
+extern char *stdio_forward_host;
+extern int stdio_forward_port;
+
+/* Context for session open confirmation callback */
+struct mux_session_confirm_ctx {
+       u_int want_tty;
+       u_int want_subsys;
+       u_int want_x_fwd;
+       u_int want_agent_fwd;
+       Buffer cmd;
+       char *term;
+       struct termios tio;
+       char **env;
+       u_int rid;
+};
+
+/* Context for global channel callback */
+struct mux_channel_confirm_ctx {
+       u_int cid;      /* channel id */
+       u_int rid;      /* request id */
+       int fid;        /* forward id */
+};
+
+/* fd to control socket */
+int muxserver_sock = -1;
+
+/* client request id */
+u_int muxclient_request_id = 0;
+
+/* Multiplexing control command */
+u_int muxclient_command = 0;
+
+/* Set when signalled. */
+static volatile sig_atomic_t muxclient_terminate = 0;
+
+/* PID of multiplex server */
+static u_int muxserver_pid = 0;
+
+static Channel *mux_listener_channel = NULL;
+
+struct mux_master_state {
+       int hello_rcvd;
+};
+
+/* mux protocol messages */
+#define MUX_MSG_HELLO          0x00000001
+#define MUX_C_NEW_SESSION      0x10000002
+#define MUX_C_ALIVE_CHECK      0x10000004
+#define MUX_C_TERMINATE                0x10000005
+#define MUX_C_OPEN_FWD         0x10000006
+#define MUX_C_CLOSE_FWD                0x10000007
+#define MUX_C_NEW_STDIO_FWD    0x10000008
+#define MUX_S_OK               0x80000001
+#define MUX_S_PERMISSION_DENIED        0x80000002
+#define MUX_S_FAILURE          0x80000003
+#define MUX_S_EXIT_MESSAGE     0x80000004
+#define MUX_S_ALIVE            0x80000005
+#define MUX_S_SESSION_OPENED   0x80000006
+#define MUX_S_REMOTE_PORT      0x80000007
+
+/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */
+#define MUX_FWD_LOCAL   1
+#define MUX_FWD_REMOTE  2
+#define MUX_FWD_DYNAMIC 3
+
+static void mux_session_confirm(int, int, void *);
+
+static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
+static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
+
+static const struct {
+       u_int type;
+       int (*handler)(u_int, Channel *, Buffer *, Buffer *);
+} mux_master_handlers[] = {
+       { MUX_MSG_HELLO, process_mux_master_hello },
+       { MUX_C_NEW_SESSION, process_mux_new_session },
+       { MUX_C_ALIVE_CHECK, process_mux_alive_check },
+       { MUX_C_TERMINATE, process_mux_terminate },
+       { MUX_C_OPEN_FWD, process_mux_open_fwd },
+       { MUX_C_CLOSE_FWD, process_mux_close_fwd },
+       { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd },
+       { 0, NULL }
+};
+
+/* Cleanup callback fired on closure of mux slave _session_ channel */
+/* ARGSUSED */
+static void
+mux_master_session_cleanup_cb(int cid, void *unused)
+{
+       Channel *cc, *c = channel_by_id(cid);
+
+       debug3("%s: entering for channel %d", __func__, cid);
+       if (c == NULL)
+               fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
+       if (c->ctl_chan != -1) {
+               if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+                       fatal("%s: channel %d missing control channel %d",
+                           __func__, c->self, c->ctl_chan);
+               c->ctl_chan = -1;
+               cc->remote_id = -1;
+               chan_rcvd_oclose(cc);
+       }
+       channel_cancel_cleanup(c->self);
+}
+
+/* Cleanup callback fired on closure of mux slave _control_ channel */
+/* ARGSUSED */
+static void
+mux_master_control_cleanup_cb(int cid, void *unused)
+{
+       Channel *sc, *c = channel_by_id(cid);
+
+       debug3("%s: entering for channel %d", __func__, cid);
+       if (c == NULL)
+               fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
+       if (c->remote_id != -1) {
+               if ((sc = channel_by_id(c->remote_id)) == NULL)
+                       fatal("%s: channel %d missing session channel %d",
+                           __func__, c->self, c->remote_id);
+               c->remote_id = -1;
+               sc->ctl_chan = -1;
+               if (sc->type != SSH_CHANNEL_OPEN) {
+                       debug2("%s: channel %d: not open", __func__, sc->self);
+                       chan_mark_dead(sc);
+               } else {
+                       if (sc->istate == CHAN_INPUT_OPEN)
+                               chan_read_failed(sc);
+                       if (sc->ostate == CHAN_OUTPUT_OPEN)
+                               chan_write_failed(sc);
+               }
+       }
+       channel_cancel_cleanup(c->self);
+}
+
+/* Check mux client environment variables before passing them to mux master. */
+static int
+env_permitted(char *env)
+{
+       int i, ret;
+       char name[1024], *cp;
+
+       if ((cp = strchr(env, '=')) == NULL || cp == env)
+               return 0;
+       ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
+       if (ret <= 0 || (size_t)ret >= sizeof(name)) {
+               error("env_permitted: name '%.100s...' too long", env);
+               return 0;
+       }
+
+       for (i = 0; i < options.num_send_env; i++)
+               if (match_pattern(name, options.send_env[i]))
+                       return 1;
+
+       return 0;
+}
+
+/* Mux master protocol message handlers */
+
+static int
+process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       u_int ver;
+       struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
+
+       if (state == NULL)
+               fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self);
+       if (state->hello_rcvd) {
+               error("%s: HELLO received twice", __func__);
+               return -1;
+       }
+       if (buffer_get_int_ret(&ver, m) != 0) {
+ malf:
+               error("%s: malformed message", __func__);
+               return -1;
+       }
+       if (ver != SSHMUX_VER) {
+               error("Unsupported multiplexing protocol version %d "
+                   "(expected %d)", ver, SSHMUX_VER);
+               return -1;
+       }
+       debug2("%s: channel %d slave version %u", __func__, c->self, ver);
+
+       /* No extensions are presently defined */
+       while (buffer_len(m) > 0) {
+               char *name = buffer_get_string_ret(m, NULL);
+               char *value = buffer_get_string_ret(m, NULL);
+
+               if (name == NULL || value == NULL) {
+                       if (name != NULL)
+                               xfree(name);
+                       goto malf;
+               }
+               debug2("Unrecognised slave extension \"%s\"", name);
+               xfree(name);
+               xfree(value);
+       }
+       state->hello_rcvd = 1;
+       return 0;
+}
+
+static int
+process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       Channel *nc;
+       struct mux_session_confirm_ctx *cctx;
+       char *reserved, *cmd, *cp;
+       u_int i, j, len, env_len, escape_char, window, packetmax;
+       int new_fd[3];
+
+       /* Reply for SSHMUX_COMMAND_OPEN */
+       cctx = xcalloc(1, sizeof(*cctx));
+       cctx->term = NULL;
+       cctx->rid = rid;
+       cmd = reserved = NULL;
+       if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&cctx->want_tty, m) != 0 ||
+           buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 ||
+           buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 ||
+           buffer_get_int_ret(&cctx->want_subsys, m) != 0 ||
+           buffer_get_int_ret(&escape_char, m) != 0 ||
+           (cctx->term = buffer_get_string_ret(m, &len)) == NULL ||
+           (cmd = buffer_get_string_ret(m, &len)) == NULL) {
+ malf:
+               if (cmd != NULL)
+                       xfree(cmd);
+               if (reserved != NULL)
+                       xfree(reserved);
+               if (cctx->term != NULL)
+                       xfree(cctx->term);
+               error("%s: malformed message", __func__);
+               return -1;
+       }
+       xfree(reserved);
+       reserved = NULL;
+
+       cctx->env = NULL;
+       env_len = 0;
+       while (buffer_len(m) > 0) {
+#define MUX_MAX_ENV_VARS       4096
+               if ((cp = buffer_get_string_ret(m, &len)) == NULL) {
+                       xfree(cmd);
+                       goto malf;
+               }
+               if (!env_permitted(cp)) {
+                       xfree(cp);
+                       continue;
+               }
+               cctx->env = xrealloc(cctx->env, env_len + 2,
+                   sizeof(*cctx->env));
+               cctx->env[env_len++] = cp;
+               cctx->env[env_len] = NULL;
+               if (env_len > MUX_MAX_ENV_VARS) {
+                       error(">%d environment variables received, ignoring "
+                           "additional", MUX_MAX_ENV_VARS);
+                       break;
+               }
+       }
+
+       debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, "
+           "term \"%s\", cmd \"%s\", env %u", __func__, c->self,
+           cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd,
+           cctx->want_subsys, cctx->term, cmd, env_len);
+
+       buffer_init(&cctx->cmd);
+       buffer_append(&cctx->cmd, cmd, strlen(cmd));
+       xfree(cmd);
+       cmd = NULL;
+
+       /* Gather fds from client */
+       for(i = 0; i < 3; i++) {
+               if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
+                       error("%s: failed to receive fd %d from slave",
+                           __func__, i);
+                       for (j = 0; j < i; j++)
+                               close(new_fd[j]);
+                       for (j = 0; j < env_len; j++)
+                               xfree(cctx->env[j]);
+                       if (env_len > 0)
+                               xfree(cctx->env);
+                       xfree(cctx->term);
+                       buffer_free(&cctx->cmd);
+                       xfree(cctx);
+
+                       /* prepare reply */
+                       buffer_put_int(r, MUX_S_FAILURE);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r,
+                           "did not receive file descriptors");
+                       return -1;
+               }
+       }
+
+       debug3("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
+           new_fd[0], new_fd[1], new_fd[2]);
+
+       /* XXX support multiple child sessions in future */
+       if (c->remote_id != -1) {
+               debug2("%s: session already open", __func__);
+               /* prepare reply */
+               buffer_put_int(r, MUX_S_FAILURE);
+               buffer_put_int(r, rid);
+               buffer_put_cstring(r, "Multiple sessions not supported");
+ cleanup:
+               close(new_fd[0]);
+               close(new_fd[1]);
+               close(new_fd[2]);
+               xfree(cctx->term);
+               if (env_len != 0) {
+                       for (i = 0; i < env_len; i++)
+                               xfree(cctx->env[i]);
+                       xfree(cctx->env);
+               }
+               buffer_free(&cctx->cmd);
+               return 0;
+       }
+
+       if (options.control_master == SSHCTL_MASTER_ASK ||
+           options.control_master == SSHCTL_MASTER_AUTO_ASK) {
+               if (!ask_permission("Allow shared connection to %s? ", host)) {
+                       debug2("%s: session refused by user", __func__);
+                       /* prepare reply */
+                       buffer_put_int(r, MUX_S_PERMISSION_DENIED);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r, "Permission denied");
+                       goto cleanup;
+               }
+       }
+
+       /* Try to pick up ttymodes from client before it goes raw */
+       if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
+               error("%s: tcgetattr: %s", __func__, strerror(errno));
+
+       /* enable nonblocking unless tty */
+       if (!isatty(new_fd[0]))
+               set_nonblock(new_fd[0]);
+       if (!isatty(new_fd[1]))
+               set_nonblock(new_fd[1]);
+       if (!isatty(new_fd[2]))
+               set_nonblock(new_fd[2]);
+
+       window = CHAN_SES_WINDOW_DEFAULT;
+       packetmax = CHAN_SES_PACKET_DEFAULT;
+       if (cctx->want_tty) {
+               window >>= 1;
+               packetmax >>= 1;
+       }
+
+       nc = channel_new("session", SSH_CHANNEL_OPENING,
+           new_fd[0], new_fd[1], new_fd[2], window, packetmax,
+           CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
+
+       nc->ctl_chan = c->self;         /* link session -> control channel */
+       c->remote_id = nc->self;        /* link control -> session channel */
+
+       if (cctx->want_tty && escape_char != 0xffffffff) {
+               channel_register_filter(nc->self,
+                   client_simple_escape_filter, NULL,
+                   client_filter_cleanup,
+                   client_new_escape_filter_ctx((int)escape_char));
+       }
+
+       debug2("%s: channel_new: %d linked to control channel %d",
+           __func__, nc->self, nc->ctl_chan);
+
+       channel_send_open(nc->self);
+       channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
+       c->mux_pause = 1; /* stop handling messages until open_confirm done */
+       channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
+
+       /* reply is deferred, sent by mux_session_confirm */
+       return 0;
+}
+
+static int
+process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       debug2("%s: channel %d: alive check", __func__, c->self);
+
+       /* prepare reply */
+       buffer_put_int(r, MUX_S_ALIVE);
+       buffer_put_int(r, rid);
+       buffer_put_int(r, (u_int)getpid());
+
+       return 0;
+}
+
+static int
+process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       debug2("%s: channel %d: terminate request", __func__, c->self);
+
+       if (options.control_master == SSHCTL_MASTER_ASK ||
+           options.control_master == SSHCTL_MASTER_AUTO_ASK) {
+               if (!ask_permission("Terminate shared connection to %s? ",
+                   host)) {
+                       debug2("%s: termination refused by user", __func__);
+                       buffer_put_int(r, MUX_S_PERMISSION_DENIED);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r, "Permission denied");
+                       return 0;
+               }
+       }
+
+       quit_pending = 1;
+       buffer_put_int(r, MUX_S_OK);
+       buffer_put_int(r, rid);
+       /* XXX exit happens too soon - message never makes it to client */
+       return 0;
+}
+
+static char *
+format_forward(u_int ftype, Forward *fwd)
+{
+       char *ret;
+
+       switch (ftype) {
+       case MUX_FWD_LOCAL:
+               xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d",
+                   (fwd->listen_host == NULL) ?
+                   (options.gateway_ports ? "*" : "LOCALHOST") :
+                   fwd->listen_host, fwd->listen_port,
+                   fwd->connect_host, fwd->connect_port);
+               break;
+       case MUX_FWD_DYNAMIC:
+               xasprintf(&ret, "dynamic forward %.200s:%d -> *",
+                   (fwd->listen_host == NULL) ?
+                   (options.gateway_ports ? "*" : "LOCALHOST") :
+                    fwd->listen_host, fwd->listen_port);
+               break;
+       case MUX_FWD_REMOTE:
+               xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d",
+                   (fwd->listen_host == NULL) ?
+                   "LOCALHOST" : fwd->listen_host,
+                   fwd->listen_port,
+                   fwd->connect_host, fwd->connect_port);
+               break;
+       default:
+               fatal("%s: unknown forward type %u", __func__, ftype);
+       }
+       return ret;
+}
+
+static int
+compare_host(const char *a, const char *b)
+{
+       if (a == NULL && b == NULL)
+               return 1;
+       if (a == NULL || b == NULL)
+               return 0;
+       return strcmp(a, b) == 0;
+}
+
+static int
+compare_forward(Forward *a, Forward *b)
+{
+       if (!compare_host(a->listen_host, b->listen_host))
+               return 0;
+       if (a->listen_port != b->listen_port)
+               return 0;
+       if (!compare_host(a->connect_host, b->connect_host))
+               return 0;
+       if (a->connect_port != b->connect_port)
+               return 0;
+
+       return 1;
+}
+
+static void
+mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+{
+       struct mux_channel_confirm_ctx *fctx = ctxt;
+       char *failmsg = NULL;
+       Forward *rfwd;
+       Channel *c;
+       Buffer out;
+
+       if ((c = channel_by_id(fctx->cid)) == NULL) {
+               /* no channel for reply */
+               error("%s: unknown channel", __func__);
+               return;
+       }
+       buffer_init(&out);
+       if (fctx->fid >= options.num_remote_forwards) {
+               xasprintf(&failmsg, "unknown forwarding id %d", fctx->fid);
+               goto fail;
+       }
+       rfwd = &options.remote_forwards[fctx->fid];
+       debug("%s: %s for: listen %d, connect %s:%d", __func__,
+           type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
+           rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+       if (type == SSH2_MSG_REQUEST_SUCCESS) {
+               if (rfwd->listen_port == 0) {
+                       rfwd->allocated_port = packet_get_int();
+                       logit("Allocated port %u for mux remote forward"
+                           " to %s:%d", rfwd->allocated_port,
+                           rfwd->connect_host, rfwd->connect_port);
+                       buffer_put_int(&out, MUX_S_REMOTE_PORT);
+                       buffer_put_int(&out, fctx->rid);
+                       buffer_put_int(&out, rfwd->allocated_port);
+               } else {
+                       buffer_put_int(&out, MUX_S_OK);
+                       buffer_put_int(&out, fctx->rid);
+               }
+               goto out;
+       } else {
+               xasprintf(&failmsg, "remote port forwarding failed for "
+                   "listen port %d", rfwd->listen_port);
+       }
+ fail:
+       error("%s: %s", __func__, failmsg);
+       buffer_put_int(&out, MUX_S_FAILURE);
+       buffer_put_int(&out, fctx->rid);
+       buffer_put_cstring(&out, failmsg);
+       xfree(failmsg);
+ out:
+       buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
+       buffer_free(&out);
+       if (c->mux_pause <= 0)
+               fatal("%s: mux_pause %d", __func__, c->mux_pause);
+       c->mux_pause = 0; /* start processing messages again */
+}
+
+static int
+process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       Forward fwd;
+       char *fwd_desc = NULL;
+       u_int ftype;
+       int i, ret = 0, freefwd = 1;
+
+       fwd.listen_host = fwd.connect_host = NULL;
+       if (buffer_get_int_ret(&ftype, m) != 0 ||
+           (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
+           (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&fwd.connect_port, m) != 0) {
+               error("%s: malformed message", __func__);
+               ret = -1;
+               goto out;
+       }
+
+       if (*fwd.listen_host == '\0') {
+               xfree(fwd.listen_host);
+               fwd.listen_host = NULL;
+       }
+       if (*fwd.connect_host == '\0') {
+               xfree(fwd.connect_host);
+               fwd.connect_host = NULL;
+       }
+
+       debug2("%s: channel %d: request %s", __func__, c->self,
+           (fwd_desc = format_forward(ftype, &fwd)));
+
+       if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE &&
+           ftype != MUX_FWD_DYNAMIC) {
+               logit("%s: invalid forwarding type %u", __func__, ftype);
+ invalid:
+               if (fwd.listen_host)
+                       xfree(fwd.listen_host);
+               if (fwd.connect_host)
+                       xfree(fwd.connect_host);
+               buffer_put_int(r, MUX_S_FAILURE);
+               buffer_put_int(r, rid);
+               buffer_put_cstring(r, "Invalid forwarding request");
+               return 0;
+       }
+       if (fwd.listen_port >= 65536) {
+               logit("%s: invalid listen port %u", __func__,
+                   fwd.listen_port);
+               goto invalid;
+       }
+       if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC &&
+           ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
+               logit("%s: invalid connect port %u", __func__,
+                   fwd.connect_port);
+               goto invalid;
+       }
+       if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) {
+               logit("%s: missing connect host", __func__);
+               goto invalid;
+       }
+
+       /* Skip forwards that have already been requested */
+       switch (ftype) {
+       case MUX_FWD_LOCAL:
+       case MUX_FWD_DYNAMIC:
+               for (i = 0; i < options.num_local_forwards; i++) {
+                       if (compare_forward(&fwd,
+                           options.local_forwards + i)) {
+ exists:
+                               debug2("%s: found existing forwarding",
+                                   __func__);
+                               buffer_put_int(r, MUX_S_OK);
+                               buffer_put_int(r, rid);
+                               goto out;
+                       }
+               }
+               break;
+       case MUX_FWD_REMOTE:
+               for (i = 0; i < options.num_remote_forwards; i++) {
+                       if (compare_forward(&fwd,
+                           options.remote_forwards + i)) {
+                               if (fwd.listen_port != 0)
+                                       goto exists;
+                               debug2("%s: found allocated port",
+                                   __func__);
+                               buffer_put_int(r, MUX_S_REMOTE_PORT);
+                               buffer_put_int(r, rid);
+                               buffer_put_int(r,
+                                   options.remote_forwards[i].allocated_port);
+                               goto out;
+                       }
+               }
+               break;
+       }
+
+       if (options.control_master == SSHCTL_MASTER_ASK ||
+           options.control_master == SSHCTL_MASTER_AUTO_ASK) {
+               if (!ask_permission("Open %s on %s?", fwd_desc, host)) {
+                       debug2("%s: forwarding refused by user", __func__);
+                       buffer_put_int(r, MUX_S_PERMISSION_DENIED);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r, "Permission denied");
+                       goto out;
+               }
+       }
+
+       if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
+               if (channel_setup_local_fwd_listener(fwd.listen_host,
+                   fwd.listen_port, fwd.connect_host, fwd.connect_port,
+                   options.gateway_ports) < 0) {
+ fail:
+                       logit("slave-requested %s failed", fwd_desc);
+                       buffer_put_int(r, MUX_S_FAILURE);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r, "Port forwarding failed");
+                       goto out;
+               }
+               add_local_forward(&options, &fwd);
+               freefwd = 0;
+       } else {
+               struct mux_channel_confirm_ctx *fctx;
+
+               if (channel_request_remote_forwarding(fwd.listen_host,
+                   fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0)
+                       goto fail;
+               add_remote_forward(&options, &fwd);
+               fctx = xcalloc(1, sizeof(*fctx));
+               fctx->cid = c->self;
+               fctx->rid = rid;
+               fctx->fid = options.num_remote_forwards - 1;
+               client_register_global_confirm(mux_confirm_remote_forward,
+                   fctx);
+               freefwd = 0;
+               c->mux_pause = 1; /* wait for mux_confirm_remote_forward */
+               /* delayed reply in mux_confirm_remote_forward */
+               goto out;
+       }
+       buffer_put_int(r, MUX_S_OK);
+       buffer_put_int(r, rid);
+ out:
+       if (fwd_desc != NULL)
+               xfree(fwd_desc);
+       if (freefwd) {
+               if (fwd.listen_host != NULL)
+                       xfree(fwd.listen_host);
+               if (fwd.connect_host != NULL)
+                       xfree(fwd.connect_host);
+       }
+       return ret;
+}
+
+static int
+process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       Forward fwd;
+       char *fwd_desc = NULL;
+       u_int ftype;
+       int ret = 0;
+
+       fwd.listen_host = fwd.connect_host = NULL;
+       if (buffer_get_int_ret(&ftype, m) != 0 ||
+           (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&fwd.listen_port, m) != 0 ||
+           (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&fwd.connect_port, m) != 0) {
+               error("%s: malformed message", __func__);
+               ret = -1;
+               goto out;
+       }
+
+       if (*fwd.listen_host == '\0') {
+               xfree(fwd.listen_host);
+               fwd.listen_host = NULL;
+       }
+       if (*fwd.connect_host == '\0') {
+               xfree(fwd.connect_host);
+               fwd.connect_host = NULL;
+       }
+
+       debug2("%s: channel %d: request %s", __func__, c->self,
+           (fwd_desc = format_forward(ftype, &fwd)));
+
+       /* XXX implement this */
+       buffer_put_int(r, MUX_S_FAILURE);
+       buffer_put_int(r, rid);
+       buffer_put_cstring(r, "unimplemented");
+
+ out:
+       if (fwd_desc != NULL)
+               xfree(fwd_desc);
+       if (fwd.listen_host != NULL)
+               xfree(fwd.listen_host);
+       if (fwd.connect_host != NULL)
+               xfree(fwd.connect_host);
+
+       return ret;
+}
+
+static int
+process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
+{
+       Channel *nc;
+       char *reserved, *chost;
+       u_int cport, i, j;
+       int new_fd[2];
+
+       chost = reserved = NULL;
+       if ((reserved = buffer_get_string_ret(m, NULL)) == NULL ||
+          (chost = buffer_get_string_ret(m, NULL)) == NULL ||
+           buffer_get_int_ret(&cport, m) != 0) {
+               if (reserved != NULL)
+                       xfree(reserved);
+               if (chost != NULL)
+                       xfree(chost);
+               error("%s: malformed message", __func__);
+               return -1;
+       }
+       xfree(reserved);
+
+       debug2("%s: channel %d: request stdio fwd to %s:%u",
+           __func__, c->self, chost, cport);
+
+       /* Gather fds from client */
+       for(i = 0; i < 2; i++) {
+               if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) {
+                       error("%s: failed to receive fd %d from slave",
+                           __func__, i);
+                       for (j = 0; j < i; j++)
+                               close(new_fd[j]);
+                       xfree(chost);
+
+                       /* prepare reply */
+                       buffer_put_int(r, MUX_S_FAILURE);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r,
+                           "did not receive file descriptors");
+                       return -1;
+               }
+       }
+
+       debug3("%s: got fds stdin %d, stdout %d", __func__,
+           new_fd[0], new_fd[1]);
+
+       /* XXX support multiple child sessions in future */
+       if (c->remote_id != -1) {
+               debug2("%s: session already open", __func__);
+               /* prepare reply */
+               buffer_put_int(r, MUX_S_FAILURE);
+               buffer_put_int(r, rid);
+               buffer_put_cstring(r, "Multiple sessions not supported");
+ cleanup:
+               close(new_fd[0]);
+               close(new_fd[1]);
+               xfree(chost);
+               return 0;
+       }
+
+       if (options.control_master == SSHCTL_MASTER_ASK ||
+           options.control_master == SSHCTL_MASTER_AUTO_ASK) {
+               if (!ask_permission("Allow forward to %s:%u? ",
+                   chost, cport)) {
+                       debug2("%s: stdio fwd refused by user", __func__);
+                       /* prepare reply */
+                       buffer_put_int(r, MUX_S_PERMISSION_DENIED);
+                       buffer_put_int(r, rid);
+                       buffer_put_cstring(r, "Permission denied");
+                       goto cleanup;
+               }
+       }
+
+       /* enable nonblocking unless tty */
+       if (!isatty(new_fd[0]))
+               set_nonblock(new_fd[0]);
+       if (!isatty(new_fd[1]))
+               set_nonblock(new_fd[1]);
+
+       nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
+
+       nc->ctl_chan = c->self;         /* link session -> control channel */
+       c->remote_id = nc->self;        /* link control -> session channel */
+
+       debug2("%s: channel_new: %d linked to control channel %d",
+           __func__, nc->self, nc->ctl_chan);
+
+       channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
+
+       /* prepare reply */
+       /* XXX defer until channel confirmed */
+       buffer_put_int(r, MUX_S_SESSION_OPENED);
+       buffer_put_int(r, rid);
+       buffer_put_int(r, nc->self);
+
+       return 0;
+}
+
+/* Channel callbacks fired on read/write from mux slave fd */
+static int
+mux_master_read_cb(Channel *c)
+{
+       struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
+       Buffer in, out;
+       void *ptr;
+       u_int type, rid, have, i;
+       int ret = -1;
+
+       /* Setup ctx and  */
+       if (c->mux_ctx == NULL) {
+               state = xcalloc(1, sizeof(*state));
+               c->mux_ctx = state;
+               channel_register_cleanup(c->self,
+                   mux_master_control_cleanup_cb, 0);
+
+               /* Send hello */
+               buffer_init(&out);
+               buffer_put_int(&out, MUX_MSG_HELLO);
+               buffer_put_int(&out, SSHMUX_VER);
+               /* no extensions */
+               buffer_put_string(&c->output, buffer_ptr(&out),
+                   buffer_len(&out));
+               buffer_free(&out);
+               debug3("%s: channel %d: hello sent", __func__, c->self);
+               return 0;
+       }
+
+       buffer_init(&in);
+       buffer_init(&out);
+
+       /* Channel code ensures that we receive whole packets */
+       if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
+ malf:
+               error("%s: malformed message", __func__);
+               goto out;
+       }
+       buffer_append(&in, ptr, have);
+
+       if (buffer_get_int_ret(&type, &in) != 0)
+               goto malf;
+       debug3("%s: channel %d packet type 0x%08x len %u",
+           __func__, c->self, type, buffer_len(&in));
+
+       if (type == MUX_MSG_HELLO)
+               rid = 0;
+       else {
+               if (!state->hello_rcvd) {
+                       error("%s: expected MUX_MSG_HELLO(0x%08x), "
+                           "received 0x%08x", __func__, MUX_MSG_HELLO, type);
+                       goto out;
+               }
+               if (buffer_get_int_ret(&rid, &in) != 0)
+                       goto malf;
+       }
+
+       for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
+               if (type == mux_master_handlers[i].type) {
+                       ret = mux_master_handlers[i].handler(rid, c, &in, &out);
+                       break;
+               }
+       }
+       if (mux_master_handlers[i].handler == NULL) {
+               error("%s: unsupported mux message 0x%08x", __func__, type);
+               buffer_put_int(&out, MUX_S_FAILURE);
+               buffer_put_int(&out, rid);
+               buffer_put_cstring(&out, "unsupported request");
+               ret = 0;
+       }
+       /* Enqueue reply packet */
+       if (buffer_len(&out) != 0) {
+               buffer_put_string(&c->output, buffer_ptr(&out),
+                   buffer_len(&out));
+       }
+ out:
+       buffer_free(&in);
+       buffer_free(&out);
+       return ret;
+}
+
+void
+mux_exit_message(Channel *c, int exitval)
+{
+       Buffer m;
+       Channel *mux_chan;
+
+       debug3("%s: channel %d: exit message, evitval %d", __func__, c->self,
+           exitval);
+
+       if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
+               fatal("%s: channel %d missing mux channel %d",
+                   __func__, c->self, c->ctl_chan);
+
+       /* Append exit message packet to control socket output queue */
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_S_EXIT_MESSAGE);
+       buffer_put_int(&m, c->self);
+       buffer_put_int(&m, exitval);
+
+       buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
+       buffer_free(&m);
+}
+
+/* Prepare a mux master to listen on a Unix domain socket. */
+void
+muxserver_listen(void)
+{
+       struct sockaddr_un addr;
+       socklen_t sun_len;
+       mode_t old_umask;
+       char *orig_control_path = options.control_path;
+       char rbuf[16+1];
+       u_int i, r;
+
+       if (options.control_path == NULL ||
+           options.control_master == SSHCTL_MASTER_NO)
+               return;
+
+       debug("setting up multiplex master socket");
+
+       /*
+        * Use a temporary path before listen so we can pseudo-atomically
+        * establish the listening socket in its final location to avoid
+        * other processes racing in between bind() and listen() and hitting
+        * an unready socket.
+        */
+       for (i = 0; i < sizeof(rbuf) - 1; i++) {
+               r = arc4random_uniform(26+26+10);
+               rbuf[i] = (r < 26) ? 'a' + r :
+                   (r < 26*2) ? 'A' + r - 26 :
+                   '0' + r - 26 - 26;
+       }
+       rbuf[sizeof(rbuf) - 1] = '\0';
+       options.control_path = NULL;
+       xasprintf(&options.control_path, "%s.%s", orig_control_path, rbuf);
+       debug3("%s: temporary control path %s", __func__, options.control_path);
+
+       memset(&addr, '\0', sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       sun_len = offsetof(struct sockaddr_un, sun_path) +
+           strlen(options.control_path) + 1;
+
+       if (strlcpy(addr.sun_path, options.control_path,
+           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+               fatal("ControlPath too long");
+
+       if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+               fatal("%s socket(): %s", __func__, strerror(errno));
+
+       old_umask = umask(0177);
+       if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) {
+               muxserver_sock = -1;
+               if (errno == EINVAL || errno == EADDRINUSE) {
+                       error("ControlSocket %s already exists, "
+                           "disabling multiplexing", options.control_path);
+ disable_mux_master:
+                       close(muxserver_sock);
+                       muxserver_sock = -1;
+                       xfree(options.control_path);
+                       options.control_path = NULL;
+                       options.control_master = SSHCTL_MASTER_NO;
+                       return;
+               } else
+                       fatal("%s bind(): %s", __func__, strerror(errno));
+       }
+       umask(old_umask);
+
+       if (listen(muxserver_sock, 64) == -1)
+               fatal("%s listen(): %s", __func__, strerror(errno));
+
+       /* Now atomically "move" the mux socket into position */
+       if (link(options.control_path, orig_control_path) != 0) {
+               if (errno != EEXIST) {
+                       fatal("%s: link mux listener %s => %s: %s", __func__, 
+                           options.control_path, orig_control_path,
+                           strerror(errno));
+               }
+               error("ControlSocket %s already exists, disabling multiplexing",
+                   orig_control_path);
+               xfree(orig_control_path);
+               unlink(options.control_path);
+               goto disable_mux_master;
+       }
+       unlink(options.control_path);
+       xfree(options.control_path);
+       options.control_path = orig_control_path;
+
+       set_nonblock(muxserver_sock);
+
+       mux_listener_channel = channel_new("mux listener",
+           SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
+           0, options.control_path, 1);
+       mux_listener_channel->mux_rcb = mux_master_read_cb;
+       debug3("%s: mux listener channel %d fd %d", __func__,
+           mux_listener_channel->self, mux_listener_channel->sock);
+}
+
+/* Callback on open confirmation in mux master for a mux client session. */
+static void
+mux_session_confirm(int id, int success, void *arg)
+{
+       struct mux_session_confirm_ctx *cctx = arg;
+       const char *display;
+       Channel *c, *cc;
+       int i;
+       Buffer reply;
+
+       if (cctx == NULL)
+               fatal("%s: cctx == NULL", __func__);
+       if ((c = channel_by_id(id)) == NULL)
+               fatal("%s: no channel for id %d", __func__, id);
+       if ((cc = channel_by_id(c->ctl_chan)) == NULL)
+               fatal("%s: channel %d lacks control channel %d", __func__,
+                   id, c->ctl_chan);
+
+       if (!success) {
+               debug3("%s: sending failure reply", __func__);
+               /* prepare reply */
+               buffer_init(&reply);
+               buffer_put_int(&reply, MUX_S_FAILURE);
+               buffer_put_int(&reply, cctx->rid);
+               buffer_put_cstring(&reply, "Session open refused by peer");
+               goto done;
+       }
+
+       display = getenv("DISPLAY");
+       if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
+               char *proto, *data;
+
+               /* Get reasonable local authentication information. */
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted, options.forward_x11_timeout,
+                   &proto, &data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
+               x11_request_forwarding_with_spoofing(id, display, proto, data);
+               /* XXX wait for reply */
+       }
+
+       if (cctx->want_agent_fwd && options.forward_agent) {
+               debug("Requesting authentication agent forwarding.");
+               channel_request_start(id, "auth-agent-req@openssh.com", 0);
+               packet_send();
+       }
+
+       client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
+           cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
+
+       debug3("%s: sending success reply", __func__);
+       /* prepare reply */
+       buffer_init(&reply);
+       buffer_put_int(&reply, MUX_S_SESSION_OPENED);
+       buffer_put_int(&reply, cctx->rid);
+       buffer_put_int(&reply, c->self);
+
+ done:
+       /* Send reply */
+       buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
+       buffer_free(&reply);
+
+       if (cc->mux_pause <= 0)
+               fatal("%s: mux_pause %d", __func__, cc->mux_pause);
+       cc->mux_pause = 0; /* start processing messages again */
+       c->open_confirm_ctx = NULL;
+       buffer_free(&cctx->cmd);
+       xfree(cctx->term);
+       if (cctx->env != NULL) {
+               for (i = 0; cctx->env[i] != NULL; i++)
+                       xfree(cctx->env[i]);
+               xfree(cctx->env);
+       }
+       xfree(cctx);
+}
+
+/* ** Multiplexing client support */
+
+/* Exit signal handler */
+static void
+control_client_sighandler(int signo)
+{
+       muxclient_terminate = signo;
+}
+
+/*
+ * Relay signal handler - used to pass some signals from mux client to
+ * mux master.
+ */
+static void
+control_client_sigrelay(int signo)
+{
+       int save_errno = errno;
+
+       if (muxserver_pid > 1)
+               kill(muxserver_pid, signo);
+
+       errno = save_errno;
+}
+
+static int
+mux_client_read(int fd, Buffer *b, u_int need)
+{
+       u_int have;
+       ssize_t len;
+       u_char *p;
+       struct pollfd pfd;
+
+       pfd.fd = fd;
+       pfd.events = POLLIN;
+       p = buffer_append_space(b, need);
+       for (have = 0; have < need; ) {
+               if (muxclient_terminate) {
+                       errno = EINTR;
+                       return -1;
+               }
+               len = read(fd, p + have, need - have);
+               if (len < 0) {
+                       switch (errno) {
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+                       case EWOULDBLOCK:
+#endif
+                       case EAGAIN:
+                               (void)poll(&pfd, 1, -1);
+                               /* FALLTHROUGH */
+                       case EINTR:
+                               continue;
+                       default:
+                               return -1;
+                       }
+               }
+               if (len == 0) {
+                       errno = EPIPE;
+                       return -1;
+               }
+               have += (u_int)len;
+       }
+       return 0;
+}
+
+static int
+mux_client_write_packet(int fd, Buffer *m)
+{
+       Buffer queue;
+       u_int have, need;
+       int oerrno, len;
+       u_char *ptr;
+       struct pollfd pfd;
+
+       pfd.fd = fd;
+       pfd.events = POLLOUT;
+       buffer_init(&queue);
+       buffer_put_string(&queue, buffer_ptr(m), buffer_len(m));
+
+       need = buffer_len(&queue);
+       ptr = buffer_ptr(&queue);
+
+       for (have = 0; have < need; ) {
+               if (muxclient_terminate) {
+                       buffer_free(&queue);
+                       errno = EINTR;
+                       return -1;
+               }
+               len = write(fd, ptr + have, need - have);
+               if (len < 0) {
+                       switch (errno) {
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+                       case EWOULDBLOCK:
+#endif
+                       case EAGAIN:
+                               (void)poll(&pfd, 1, -1);
+                               /* FALLTHROUGH */
+                       case EINTR:
+                               continue;
+                       default:
+                               oerrno = errno;
+                               buffer_free(&queue);
+                               errno = oerrno;
+                               return -1;
+                       }
+               }
+               if (len == 0) {
+                       buffer_free(&queue);
+                       errno = EPIPE;
+                       return -1;
+               }
+               have += (u_int)len;
+       }
+       buffer_free(&queue);
+       return 0;
+}
+
+static int
+mux_client_read_packet(int fd, Buffer *m)
+{
+       Buffer queue;
+       u_int need, have;
+       void *ptr;
+       int oerrno;
+
+       buffer_init(&queue);
+       if (mux_client_read(fd, &queue, 4) != 0) {
+               if ((oerrno = errno) == EPIPE)
+               debug3("%s: read header failed: %s", __func__, strerror(errno));
+               errno = oerrno;
+               return -1;
+       }
+       need = get_u32(buffer_ptr(&queue));
+       if (mux_client_read(fd, &queue, need) != 0) {
+               oerrno = errno;
+               debug3("%s: read body failed: %s", __func__, strerror(errno));
+               errno = oerrno;
+               return -1;
+       }
+       ptr = buffer_get_string_ptr(&queue, &have);
+       buffer_append(m, ptr, have);
+       buffer_free(&queue);
+       return 0;
+}
+
+static int
+mux_client_hello_exchange(int fd)
+{
+       Buffer m;
+       u_int type, ver;
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_MSG_HELLO);
+       buffer_put_int(&m, SSHMUX_VER);
+       /* no extensions */
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       buffer_clear(&m);
+
+       /* Read their HELLO */
+       if (mux_client_read_packet(fd, &m) != 0) {
+               buffer_free(&m);
+               return -1;
+       }
+
+       type = buffer_get_int(&m);
+       if (type != MUX_MSG_HELLO)
+               fatal("%s: expected HELLO (%u) received %u",
+                   __func__, MUX_MSG_HELLO, type);
+       ver = buffer_get_int(&m);
+       if (ver != SSHMUX_VER)
+               fatal("Unsupported multiplexing protocol version %d "
+                   "(expected %d)", ver, SSHMUX_VER);
+       debug2("%s: master version %u", __func__, ver);
+       /* No extensions are presently defined */
+       while (buffer_len(&m) > 0) {
+               char *name = buffer_get_string(&m, NULL);
+               char *value = buffer_get_string(&m, NULL);
+
+               debug2("Unrecognised master extension \"%s\"", name);
+               xfree(name);
+               xfree(value);
+       }
+       buffer_free(&m);
+       return 0;
+}
+
+static u_int
+mux_client_request_alive(int fd)
+{
+       Buffer m;
+       char *e;
+       u_int pid, type, rid;
+
+       debug3("%s: entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_C_ALIVE_CHECK);
+       buffer_put_int(&m, muxclient_request_id);
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       buffer_clear(&m);
+
+       /* Read their reply */
+       if (mux_client_read_packet(fd, &m) != 0) {
+               buffer_free(&m);
+               return 0;
+       }
+
+       type = buffer_get_int(&m);
+       if (type != MUX_S_ALIVE) {
+               e = buffer_get_string(&m, NULL);
+               fatal("%s: master returned error: %s", __func__, e);
+       }
+
+       if ((rid = buffer_get_int(&m)) != muxclient_request_id)
+               fatal("%s: out of sequence reply: my id %u theirs %u",
+                   __func__, muxclient_request_id, rid);
+       pid = buffer_get_int(&m);
+       buffer_free(&m);
+
+       debug3("%s: done pid = %u", __func__, pid);
+
+       muxclient_request_id++;
+
+       return pid;
+}
+
+static void
+mux_client_request_terminate(int fd)
+{
+       Buffer m;
+       char *e;
+       u_int type, rid;
+
+       debug3("%s: entering", __func__);
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_C_TERMINATE);
+       buffer_put_int(&m, muxclient_request_id);
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       buffer_clear(&m);
+
+       /* Read their reply */
+       if (mux_client_read_packet(fd, &m) != 0) {
+               /* Remote end exited already */
+               if (errno == EPIPE) {
+                       buffer_free(&m);
+                       return;
+               }
+               fatal("%s: read from master failed: %s",
+                   __func__, strerror(errno));
+       }
+
+       type = buffer_get_int(&m);
+       if ((rid = buffer_get_int(&m)) != muxclient_request_id)
+               fatal("%s: out of sequence reply: my id %u theirs %u",
+                   __func__, muxclient_request_id, rid);
+       switch (type) {
+       case MUX_S_OK:
+               break;
+       case MUX_S_PERMISSION_DENIED:
+               e = buffer_get_string(&m, NULL);
+               fatal("Master refused termination request: %s", e);
+       case MUX_S_FAILURE:
+               e = buffer_get_string(&m, NULL);
+               fatal("%s: termination request failed: %s", __func__, e);
+       default:
+               fatal("%s: unexpected response from master 0x%08x",
+                   __func__, type);
+       }
+       buffer_free(&m);
+       muxclient_request_id++;
+}
+
+static int
+mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
+{
+       Buffer m;
+       char *e, *fwd_desc;
+       u_int type, rid;
+
+       fwd_desc = format_forward(ftype, fwd);
+       debug("Requesting %s", fwd_desc);
+       xfree(fwd_desc);
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_C_OPEN_FWD);
+       buffer_put_int(&m, muxclient_request_id);
+       buffer_put_int(&m, ftype);
+       buffer_put_cstring(&m,
+           fwd->listen_host == NULL ? "" : fwd->listen_host);
+       buffer_put_int(&m, fwd->listen_port);
+       buffer_put_cstring(&m,
+           fwd->connect_host == NULL ? "" : fwd->connect_host);
+       buffer_put_int(&m, fwd->connect_port);
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       buffer_clear(&m);
+
+       /* Read their reply */
+       if (mux_client_read_packet(fd, &m) != 0) {
+               buffer_free(&m);
+               return -1;
+       }
+
+       type = buffer_get_int(&m);
+       if ((rid = buffer_get_int(&m)) != muxclient_request_id)
+               fatal("%s: out of sequence reply: my id %u theirs %u",
+                   __func__, muxclient_request_id, rid);
+       switch (type) {
+       case MUX_S_OK:
+               break;
+       case MUX_S_REMOTE_PORT:
+               fwd->allocated_port = buffer_get_int(&m);
+               logit("Allocated port %u for remote forward to %s:%d",
+                   fwd->allocated_port,
+                   fwd->connect_host ? fwd->connect_host : "",
+                   fwd->connect_port);
+               if (muxclient_command == SSHMUX_COMMAND_FORWARD)
+                       fprintf(stdout, "%u\n", fwd->allocated_port);
+               break;
+       case MUX_S_PERMISSION_DENIED:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               error("Master refused forwarding request: %s", e);
+               return -1;
+       case MUX_S_FAILURE:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               error("%s: forwarding request failed: %s", __func__, e);
+               return -1;
+       default:
+               fatal("%s: unexpected response from master 0x%08x",
+                   __func__, type);
+       }
+       buffer_free(&m);
+
+       muxclient_request_id++;
+       return 0;
+}
+
+static int
+mux_client_request_forwards(int fd)
+{
+       int i;
+
+       debug3("%s: requesting forwardings: %d local, %d remote", __func__,
+           options.num_local_forwards, options.num_remote_forwards);
+
+       /* XXX ExitOnForwardingFailure */
+       for (i = 0; i < options.num_local_forwards; i++) {
+               if (mux_client_request_forward(fd,
+                   options.local_forwards[i].connect_port == 0 ?
+                   MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
+                   options.local_forwards + i) != 0)
+                       return -1;
+       }
+       for (i = 0; i < options.num_remote_forwards; i++) {
+               if (mux_client_request_forward(fd, MUX_FWD_REMOTE,
+                   options.remote_forwards + i) != 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static int
+mux_client_request_session(int fd)
+{
+       Buffer m;
+       char *e, *term;
+       u_int i, rid, sid, esid, exitval, type, exitval_seen;
+       extern char **environ;
+       int devnull;
+
+       debug3("%s: entering", __func__);
+
+       if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
+               error("%s: master alive request failed", __func__);
+               return -1;
+       }
+
+       signal(SIGPIPE, SIG_IGN);
+
+       if (stdin_null_flag) {
+               if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+                       fatal("open(/dev/null): %s", strerror(errno));
+               if (dup2(devnull, STDIN_FILENO) == -1)
+                       fatal("dup2: %s", strerror(errno));
+               if (devnull > STDERR_FILENO)
+                       close(devnull);
+       }
+
+       term = getenv("TERM");
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_C_NEW_SESSION);
+       buffer_put_int(&m, muxclient_request_id);
+       buffer_put_cstring(&m, ""); /* reserved */
+       buffer_put_int(&m, tty_flag);
+       buffer_put_int(&m, options.forward_x11);
+       buffer_put_int(&m, options.forward_agent);
+       buffer_put_int(&m, subsystem_flag);
+       buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ?
+           0xffffffff : (u_int)options.escape_char);
+       buffer_put_cstring(&m, term == NULL ? "" : term);
+       buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command));
+
+       if (options.num_send_env > 0 && environ != NULL) {
+               /* Pass environment */
+               for (i = 0; environ[i] != NULL; i++) {
+                       if (env_permitted(environ[i])) {
+                               buffer_put_cstring(&m, environ[i]);
+                       }
+               }
+       }
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       /* Send the stdio file descriptors */
+       if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
+           mm_send_fd(fd, STDOUT_FILENO) == -1 ||
+           mm_send_fd(fd, STDERR_FILENO) == -1)
+               fatal("%s: send fds failed", __func__);
+
+       debug3("%s: session request sent", __func__);
+
+       /* Read their reply */
+       buffer_clear(&m);
+       if (mux_client_read_packet(fd, &m) != 0) {
+               error("%s: read from master failed: %s",
+                   __func__, strerror(errno));
+               buffer_free(&m);
+               return -1;
+       }
+
+       type = buffer_get_int(&m);
+       if ((rid = buffer_get_int(&m)) != muxclient_request_id)
+               fatal("%s: out of sequence reply: my id %u theirs %u",
+                   __func__, muxclient_request_id, rid);
+       switch (type) {
+       case MUX_S_SESSION_OPENED:
+               sid = buffer_get_int(&m);
+               debug("%s: master session id: %u", __func__, sid);
+               break;
+       case MUX_S_PERMISSION_DENIED:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               error("Master refused session request: %s", e);
+               return -1;
+       case MUX_S_FAILURE:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               error("%s: session request failed: %s", __func__, e);
+               return -1;
+       default:
+               buffer_free(&m);
+               error("%s: unexpected response from master 0x%08x",
+                   __func__, type);
+               return -1;
+       }
+       muxclient_request_id++;
+
+       signal(SIGHUP, control_client_sighandler);
+       signal(SIGINT, control_client_sighandler);
+       signal(SIGTERM, control_client_sighandler);
+       signal(SIGWINCH, control_client_sigrelay);
+
+       if (tty_flag)
+               enter_raw_mode(force_tty_flag);
+
+       /*
+        * Stick around until the controlee closes the client_fd.
+        * Before it does, it is expected to write an exit message.
+        * This process must read the value and wait for the closure of
+        * the client_fd; if this one closes early, the multiplex master will
+        * terminate early too (possibly losing data).
+        */
+       for (exitval = 255, exitval_seen = 0;;) {
+               buffer_clear(&m);
+               if (mux_client_read_packet(fd, &m) != 0)
+                       break;
+               type = buffer_get_int(&m);
+               if (type != MUX_S_EXIT_MESSAGE) {
+                       e = buffer_get_string(&m, NULL);
+                       fatal("%s: master returned error: %s", __func__, e);
+               }
+               if ((esid = buffer_get_int(&m)) != sid)
+                       fatal("%s: exit on unknown session: my id %u theirs %u",
+                           __func__, sid, esid);
+               debug("%s: master session id: %u", __func__, sid);
+               if (exitval_seen)
+                       fatal("%s: exitval sent twice", __func__);
+               exitval = buffer_get_int(&m);
+               exitval_seen = 1;
+       }
+
+       close(fd);
+       leave_raw_mode(force_tty_flag);
+
+       if (muxclient_terminate) {
+               debug2("Exiting on signal %d", muxclient_terminate);
+               exitval = 255;
+       } else if (!exitval_seen) {
+               debug2("Control master terminated unexpectedly");
+               exitval = 255;
+       } else
+               debug2("Received exit status from master %d", exitval);
+
+       if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
+               fprintf(stderr, "Shared connection to %s closed.\r\n", host);
+
+       exit(exitval);
+}
+
+static int
+mux_client_request_stdio_fwd(int fd)
+{
+       Buffer m;
+       char *e;
+       u_int type, rid, sid;
+       int devnull;
+
+       debug3("%s: entering", __func__);
+
+       if ((muxserver_pid = mux_client_request_alive(fd)) == 0) {
+               error("%s: master alive request failed", __func__);
+               return -1;
+       }
+
+       signal(SIGPIPE, SIG_IGN);
+
+       if (stdin_null_flag) {
+               if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+                       fatal("open(/dev/null): %s", strerror(errno));
+               if (dup2(devnull, STDIN_FILENO) == -1)
+                       fatal("dup2: %s", strerror(errno));
+               if (devnull > STDERR_FILENO)
+                       close(devnull);
+       }
+
+       buffer_init(&m);
+       buffer_put_int(&m, MUX_C_NEW_STDIO_FWD);
+       buffer_put_int(&m, muxclient_request_id);
+       buffer_put_cstring(&m, ""); /* reserved */
+       buffer_put_cstring(&m, stdio_forward_host);
+       buffer_put_int(&m, stdio_forward_port);
+
+       if (mux_client_write_packet(fd, &m) != 0)
+               fatal("%s: write packet: %s", __func__, strerror(errno));
+
+       /* Send the stdio file descriptors */
+       if (mm_send_fd(fd, STDIN_FILENO) == -1 ||
+           mm_send_fd(fd, STDOUT_FILENO) == -1)
+               fatal("%s: send fds failed", __func__);
+
+       debug3("%s: stdio forward request sent", __func__);
+
+       /* Read their reply */
+       buffer_clear(&m);
+
+       if (mux_client_read_packet(fd, &m) != 0) {
+               error("%s: read from master failed: %s",
+                   __func__, strerror(errno));
+               buffer_free(&m);
+               return -1;
+       }
+
+       type = buffer_get_int(&m);
+       if ((rid = buffer_get_int(&m)) != muxclient_request_id)
+               fatal("%s: out of sequence reply: my id %u theirs %u",
+                   __func__, muxclient_request_id, rid);
+       switch (type) {
+       case MUX_S_SESSION_OPENED:
+               sid = buffer_get_int(&m);
+               debug("%s: master session id: %u", __func__, sid);
+               break;
+       case MUX_S_PERMISSION_DENIED:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               fatal("Master refused stdio forwarding request: %s", e);
+       case MUX_S_FAILURE:
+               e = buffer_get_string(&m, NULL);
+               buffer_free(&m);
+               fatal("%s: stdio forwarding request failed: %s", __func__, e);
+       default:
+               buffer_free(&m);
+               error("%s: unexpected response from master 0x%08x",
+                   __func__, type);
+               return -1;
+       }
+       muxclient_request_id++;
+
+       signal(SIGHUP, control_client_sighandler);
+       signal(SIGINT, control_client_sighandler);
+       signal(SIGTERM, control_client_sighandler);
+       signal(SIGWINCH, control_client_sigrelay);
+
+       /*
+        * Stick around until the controlee closes the client_fd.
+        */
+       buffer_clear(&m);
+       if (mux_client_read_packet(fd, &m) != 0) {
+               if (errno == EPIPE ||
+                   (errno == EINTR && muxclient_terminate != 0))
+                       return 0;
+               fatal("%s: mux_client_read_packet: %s",
+                   __func__, strerror(errno));
+       }
+       fatal("%s: master returned unexpected message %u", __func__, type);
+}
+
+/* Multiplex client main loop. */
+void
+muxclient(const char *path)
+{
+       struct sockaddr_un addr;
+       socklen_t sun_len;
+       int sock;
+       u_int pid;
+
+       if (muxclient_command == 0) {
+               if (stdio_forward_host != NULL)
+                       muxclient_command = SSHMUX_COMMAND_STDIO_FWD;
+               else
+                       muxclient_command = SSHMUX_COMMAND_OPEN;
+       }
+
+       switch (options.control_master) {
+       case SSHCTL_MASTER_AUTO:
+       case SSHCTL_MASTER_AUTO_ASK:
+               debug("auto-mux: Trying existing master");
+               /* FALLTHROUGH */
+       case SSHCTL_MASTER_NO:
+               break;
+       default:
+               return;
+       }
+
+       memset(&addr, '\0', sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       sun_len = offsetof(struct sockaddr_un, sun_path) +
+           strlen(path) + 1;
+
+       if (strlcpy(addr.sun_path, path,
+           sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+               fatal("ControlPath too long");
+
+       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+               fatal("%s socket(): %s", __func__, strerror(errno));
+
+       if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) {
+               switch (muxclient_command) {
+               case SSHMUX_COMMAND_OPEN:
+               case SSHMUX_COMMAND_STDIO_FWD:
+                       break;
+               default:
+                       fatal("Control socket connect(%.100s): %s", path,
+                           strerror(errno));
+               }
+               if (errno == ECONNREFUSED &&
+                   options.control_master != SSHCTL_MASTER_NO) {
+                       debug("Stale control socket %.100s, unlinking", path);
+                       unlink(path);
+               } else if (errno == ENOENT) {
+                       debug("Control socket \"%.100s\" does not exist", path);
+               } else {
+                       error("Control socket connect(%.100s): %s", path,
+                           strerror(errno));
+               }
+               close(sock);
+               return;
+       }
+       set_nonblock(sock);
+
+       if (mux_client_hello_exchange(sock) != 0) {
+               error("%s: master hello exchange failed", __func__);
+               close(sock);
+               return;
+       }
+
+       switch (muxclient_command) {
+       case SSHMUX_COMMAND_ALIVE_CHECK:
+               if ((pid = mux_client_request_alive(sock)) == 0)
+                       fatal("%s: master alive check failed", __func__);
+               fprintf(stderr, "Master running (pid=%d)\r\n", pid);
+               exit(0);
+       case SSHMUX_COMMAND_TERMINATE:
+               mux_client_request_terminate(sock);
+               fprintf(stderr, "Exit request sent.\r\n");
+               exit(0);
+       case SSHMUX_COMMAND_FORWARD:
+               if (mux_client_request_forwards(sock) != 0)
+                       fatal("%s: master forward request failed", __func__);
+               exit(0);
+       case SSHMUX_COMMAND_OPEN:
+               if (mux_client_request_forwards(sock) != 0) {
+                       error("%s: master forward request failed", __func__);
+                       return;
+               }
+               mux_client_request_session(sock);
+               return;
+       case SSHMUX_COMMAND_STDIO_FWD:
+               mux_client_request_stdio_fwd(sock);
+               exit(0);
+       default:
+               fatal("unrecognised muxclient_command %d", muxclient_command);
+       }
+}
diff --git a/myproposal.h b/myproposal.h
new file mode 100644 (file)
index 0000000..2c43607
--- /dev/null
@@ -0,0 +1,97 @@
+/* $OpenBSD: myproposal.h,v 1.27 2010/09/01 22:42:13 djm 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 <openssl/opensslv.h>
+
+#ifdef OPENSSL_HAS_ECC
+# define KEX_ECDH_METHODS \
+       "ecdh-sha2-nistp256," \
+       "ecdh-sha2-nistp384," \
+       "ecdh-sha2-nistp521,"
+# define HOSTKEY_ECDSA_CERT_METHODS \
+       "ecdsa-sha2-nistp256-cert-v01@openssh.com," \
+       "ecdsa-sha2-nistp384-cert-v01@openssh.com," \
+       "ecdsa-sha2-nistp521-cert-v01@openssh.com,"
+# define HOSTKEY_ECDSA_METHODS \
+       "ecdsa-sha2-nistp256," \
+       "ecdsa-sha2-nistp384," \
+       "ecdsa-sha2-nistp521,"
+#else
+# define KEX_ECDH_METHODS
+# define HOSTKEY_ECDSA_CERT_METHODS
+# define HOSTKEY_ECDSA_METHODS
+#endif
+
+/* Old OpenSSL doesn't support what we need for DHGEX-sha256 */
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+# define KEX_SHA256_METHODS \
+       "diffie-hellman-group-exchange-sha256,"
+#else
+# define KEX_SHA256_METHODS
+#endif
+
+# define KEX_DEFAULT_KEX \
+       KEX_ECDH_METHODS \
+       KEX_SHA256_METHODS \
+       "diffie-hellman-group-exchange-sha1," \
+       "diffie-hellman-group14-sha1," \
+       "diffie-hellman-group1-sha1"
+
+#define        KEX_DEFAULT_PK_ALG      \
+       HOSTKEY_ECDSA_CERT_METHODS \
+       "ssh-rsa-cert-v01@openssh.com," \
+       "ssh-dss-cert-v01@openssh.com," \
+       "ssh-rsa-cert-v00@openssh.com," \
+       "ssh-dss-cert-v00@openssh.com," \
+       HOSTKEY_ECDSA_METHODS \
+       "ssh-rsa," \
+       "ssh-dss"
+
+#define        KEX_DEFAULT_ENCRYPT \
+       "aes128-ctr,aes192-ctr,aes256-ctr," \
+       "arcfour256,arcfour128," \
+       "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \
+       "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se"
+#define        KEX_DEFAULT_MAC \
+       "hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160," \
+       "hmac-ripemd160@openssh.com," \
+       "hmac-sha1-96,hmac-md5-96"
+#define        KEX_DEFAULT_COMP        "none,zlib@openssh.com,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/nchan.c b/nchan.c
new file mode 100644 (file)
index 0000000..20f6a2f
--- /dev/null
+++ b/nchan.c
@@ -0,0 +1,531 @@
+/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */
+/*
+ * Copyright (c) 1999, 2000, 2001, 2002 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "openbsd-compat/sys-queue.h"
+#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
+ */
+/*
+ * 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 *);
+static void    chan_send_eow2(Channel *);
+
+/* helper */
+static void    chan_shutdown_write(Channel *);
+static void    chan_shutdown_read(Channel *);
+
+static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
+static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
+
+static void
+chan_set_istate(Channel *c, u_int next)
+{
+       if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED)
+               fatal("chan_set_istate: bad state %d -> %d", c->istate, next);
+       debug2("channel %d: input %s -> %s", c->self, istates[c->istate],
+           istates[next]);
+       c->istate = next;
+}
+static void
+chan_set_ostate(Channel *c, u_int next)
+{
+       if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED)
+               fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next);
+       debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate],
+           ostates[next]);
+       c->ostate = next;
+}
+
+/*
+ * SSH1 specific implementation of event functions
+ */
+
+static void
+chan_rcvd_oclose1(Channel *c)
+{
+       debug2("channel %d: rcvd oclose", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_WAIT_OCLOSE:
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       case CHAN_INPUT_OPEN:
+               chan_shutdown_read(c);
+               chan_send_ieof1(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       case CHAN_INPUT_WAIT_DRAIN:
+               /* both local read_failed and remote write_failed  */
+               chan_send_ieof1(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       default:
+               error("channel %d: protocol error: rcvd_oclose for istate %d",
+                   c->self, c->istate);
+               return;
+       }
+}
+void
+chan_read_failed(Channel *c)
+{
+       debug2("channel %d: read failed", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               chan_shutdown_read(c);
+               chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
+               break;
+       default:
+               error("channel %d: chan_read_failed for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+void
+chan_ibuf_empty(Channel *c)
+{
+       debug2("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:
+               if (compat20) {
+                       if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
+                               chan_send_eof2(c);
+                       chan_set_istate(c, CHAN_INPUT_CLOSED);
+               } else {
+                       chan_send_ieof1(c);
+                       chan_set_istate(c, 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)
+{
+       debug2("channel %d: rcvd ieof", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
+               break;
+       case CHAN_OUTPUT_WAIT_IEOF:
+               chan_set_ostate(c, 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)
+{
+       debug2("channel %d: write failed", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+               chan_shutdown_write(c);
+               chan_send_oclose1(c);
+               chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
+               break;
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               chan_shutdown_write(c);
+               chan_send_oclose1(c);
+               chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
+               break;
+       default:
+               error("channel %d: chan_write_failed for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+void
+chan_obuf_empty(Channel *c)
+{
+       debug2("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:
+               chan_shutdown_write(c);
+               if (!compat20)
+                       chan_send_oclose1(c);
+               chan_set_ostate(c, 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)
+{
+       debug2("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)
+{
+       debug2("channel %d: send oclose", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               buffer_clear(&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_close2(Channel *c)
+{
+       debug2("channel %d: rcvd close", c->self);
+       if (!(c->flags & CHAN_LOCAL)) {
+               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 */
+               chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
+               chan_set_istate(c, 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
+                */
+               chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
+               break;
+       }
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               chan_shutdown_read(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       case CHAN_INPUT_WAIT_DRAIN:
+               if (!(c->flags & CHAN_LOCAL))
+                       chan_send_eof2(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       }
+}
+
+void
+chan_rcvd_eow(Channel *c)
+{
+       debug2("channel %d: rcvd eow", c->self);
+       switch (c->istate) {
+       case CHAN_INPUT_OPEN:
+               chan_shutdown_read(c);
+               chan_set_istate(c, CHAN_INPUT_CLOSED);
+               break;
+       }
+}
+static void
+chan_rcvd_eof2(Channel *c)
+{
+       debug2("channel %d: rcvd eof", c->self);
+       c->flags |= CHAN_EOF_RCVD;
+       if (c->ostate == CHAN_OUTPUT_OPEN)
+               chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
+}
+static void
+chan_write_failed2(Channel *c)
+{
+       debug2("channel %d: write failed", c->self);
+       switch (c->ostate) {
+       case CHAN_OUTPUT_OPEN:
+       case CHAN_OUTPUT_WAIT_DRAIN:
+               chan_shutdown_write(c);
+               if (strcmp(c->ctype, "session") == 0)
+                       chan_send_eow2(c);
+               chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
+               break;
+       default:
+               error("channel %d: chan_write_failed for ostate %d",
+                   c->self, c->ostate);
+               break;
+       }
+}
+static void
+chan_send_eof2(Channel *c)
+{
+       debug2("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();
+               c->flags |= CHAN_EOF_SENT;
+               break;
+       default:
+               error("channel %d: cannot send eof for istate %d",
+                   c->self, c->istate);
+               break;
+       }
+}
+static void
+chan_send_close2(Channel *c)
+{
+       debug2("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;
+       }
+}
+static void
+chan_send_eow2(Channel *c)
+{
+       debug2("channel %d: send eow", c->self);
+       if (c->ostate == CHAN_OUTPUT_CLOSED) {
+               error("channel %d: must not sent eow on closed output",
+                   c->self);
+               return;
+       }
+       if (!(datafellows & SSH_NEW_OPENSSH))
+               return;
+       packet_start(SSH2_MSG_CHANNEL_REQUEST);
+       packet_put_int(c->remote_id);
+       packet_put_cstring("eow@openssh.com");
+       packet_put_char(0);
+       packet_send();
+}
+
+/* shared */
+
+void
+chan_rcvd_ieof(Channel *c)
+{
+       if (compat20)
+               chan_rcvd_eof2(c);
+       else
+               chan_rcvd_ieof1(c);
+       if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
+           buffer_len(&c->output) == 0 &&
+           !CHANNEL_EFD_OUTPUT_ACTIVE(c))
+               chan_obuf_empty(c);
+}
+void
+chan_rcvd_oclose(Channel *c)
+{
+       if (compat20)
+               chan_rcvd_close2(c);
+       else
+               chan_rcvd_oclose1(c);
+}
+void
+chan_write_failed(Channel *c)
+{
+       if (compat20)
+               chan_write_failed2(c);
+       else
+               chan_write_failed1(c);
+}
+
+void
+chan_mark_dead(Channel *c)
+{
+       c->type = SSH_CHANNEL_ZOMBIE;
+}
+
+int
+chan_is_dead(Channel *c, int do_send)
+{
+       if (c->type == SSH_CHANNEL_ZOMBIE) {
+               debug2("channel %d: zombie", c->self);
+               return 1;
+       }
+       if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
+               return 0;
+       if (!compat20) {
+               debug2("channel %d: is dead", c->self);
+               return 1;
+       }
+       if ((datafellows & SSH_BUG_EXTEOF) &&
+           c->extended_usage == CHAN_EXTENDED_WRITE &&
+           c->efd != -1 &&
+           buffer_len(&c->extended) > 0) {
+               debug2("channel %d: active efd: %d len %d",
+                   c->self, c->efd, buffer_len(&c->extended));
+               return 0;
+       }
+       if (c->flags & CHAN_LOCAL) {
+               debug2("channel %d: is dead (local)", c->self);
+               return 1;
+       }               
+       if (!(c->flags & CHAN_CLOSE_SENT)) {
+               if (do_send) {
+                       chan_send_close2(c);
+               } else {
+                       /* channel would be dead if we sent a close */
+                       if (c->flags & CHAN_CLOSE_RCVD) {
+                               debug2("channel %d: almost dead",
+                                   c->self);
+                               return 1;
+                       }
+               }
+       }
+       if ((c->flags & CHAN_CLOSE_SENT) &&
+           (c->flags & CHAN_CLOSE_RCVD)) {
+               debug2("channel %d: is dead", c->self);
+               return 1;
+       }
+       return 0;
+}
+
+/* helper */
+static void
+chan_shutdown_write(Channel *c)
+{
+       buffer_clear(&c->output);
+       if (compat20 && c->type == SSH_CHANNEL_LARVAL)
+               return;
+       /* shutdown failure is allowed if write failed already */
+       debug2("channel %d: close_write", c->self);
+       if (c->sock != -1) {
+               if (shutdown(c->sock, SHUT_WR) < 0)
+                       debug2("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)
+                       logit("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;
+       debug2("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)
+                       logit("channel %d: chan_shutdown_read: "
+                           "close() failed for fd %d: %.100s",
+                           c->self, c->rfd, strerror(errno));
+       }
+}
diff --git a/nchan.ms b/nchan.ms
new file mode 100644 (file)
index 0000000..5757601
--- /dev/null
+++ b/nchan.ms
@@ -0,0 +1,99 @@
+.\"    $OpenBSD: nchan.ms,v 1.8 2003/11/21 11:57:03 djm 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/nchan2.ms b/nchan2.ms
new file mode 100644 (file)
index 0000000..7001504
--- /dev/null
+++ b/nchan2.ms
@@ -0,0 +1,88 @@
+.\"    $OpenBSD: nchan2.ms,v 1.4 2008/05/15 23:52:24 djm 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 ||" "rcvd EOW/" "shutdown_read" with .e at last arrow.c
+ellipse wid .9*ellipsewid ht .9*ellipseht at S4
+arrow "start" "" from S1.w+(-0.5,0) to S1.w
+.PE
+.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" "send EOW" with .sw at last arrow.c
+arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
+arrow from S1.s to S2.n
+box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
+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/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
new file mode 100644 (file)
index 0000000..41b22d8
--- /dev/null
@@ -0,0 +1,42 @@
+# $Id: Makefile.in,v 1.46 2010/10/07 11:19:24 djm Exp $
+
+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 basename.o bindresvport.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o timingsafe_bcmp.o vis.o
+
+COMPAT=bsd-arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o
+
+PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
+
+.c.o:
+       $(CC) $(CFLAGS) $(CPPFLAGS) -c $<
+
+all: libopenbsd-compat.a
+
+$(COMPAT): ../config.h
+$(OPENBSD): ../config.h
+$(PORTS): ../config.h
+
+libopenbsd-compat.a:  $(COMPAT) $(OPENBSD) $(PORTS)
+       $(AR) rv $@ $(COMPAT) $(OPENBSD) $(PORTS)
+       $(RANLIB) $@
+
+clean:
+       rm -f *.o *.a core 
+
+distclean: clean
+       rm -f Makefile *~
diff --git a/openbsd-compat/base64.c b/openbsd-compat/base64.c
new file mode 100644 (file)
index 0000000..9e74667
--- /dev/null
@@ -0,0 +1,315 @@
+/*     $OpenBSD: base64.c,v 1.5 2006/10/21 09:55:03 otto 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/base64.c */
+
+#include "includes.h"
+
+#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON))
+
+#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"
+
+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.
+   */
+
+#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) 
+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];
+       u_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;
+
+               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);
+
+               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);
+}
+#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */
+
+#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)
+
+/* 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)
+{
+       u_int tarindex, state;
+       int 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_PTON) && !defined(HAVE___B64_PTON) */
+#endif 
diff --git a/openbsd-compat/base64.h b/openbsd-compat/base64.h
new file mode 100644 (file)
index 0000000..732c6b3
--- /dev/null
@@ -0,0 +1,65 @@
+/* $Id: base64.h,v 1.6 2003/08/29 16:59:52 mouring 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.
+ */
+
+#ifndef _BSD_BASE64_H
+#define _BSD_BASE64_H
+
+#include "includes.h"
+
+#ifndef HAVE___B64_NTOP
+# ifndef HAVE_B64_NTOP
+int b64_ntop(u_char const *src, size_t srclength, char *target, 
+    size_t targsize);
+# endif /* !HAVE_B64_NTOP */
+# define __b64_ntop(a,b,c,d) b64_ntop(a,b,c,d)
+#endif /* HAVE___B64_NTOP */
+
+#ifndef HAVE___B64_PTON
+# ifndef HAVE_B64_PTON
+int b64_pton(char const *src, u_char *target, size_t targsize);
+# endif /* !HAVE_B64_PTON */
+# define __b64_pton(a,b,c) b64_pton(a,b,c)
+#endif /* HAVE___B64_PTON */
+
+#endif /* _BSD_BASE64_H */
diff --git a/openbsd-compat/basename.c b/openbsd-compat/basename.c
new file mode 100644 (file)
index 0000000..ffa5c89
--- /dev/null
@@ -0,0 +1,67 @@
+/*     $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $     */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/basename.c */
+
+#include "includes.h"
+#ifndef HAVE_BASENAME
+#include <errno.h>
+#include <string.h>
+
+char *
+basename(const char *path)
+{
+       static char bname[MAXPATHLEN];
+       size_t len;
+       const char *endp, *startp;
+
+       /* Empty or NULL string gets treated as "." */
+       if (path == NULL || *path == '\0') {
+               bname[0] = '.';
+               bname[1] = '\0';
+               return (bname);
+       }
+
+       /* Strip any trailing slashes */
+       endp = path + strlen(path) - 1;
+       while (endp > path && *endp == '/')
+               endp--;
+
+       /* All slashes becomes "/" */
+       if (endp == path && *endp == '/') {
+               bname[0] = '/';
+               bname[1] = '\0';
+               return (bname);
+       }
+
+       /* Find the start of the base */
+       startp = endp;
+       while (startp > path && *(startp - 1) != '/')
+               startp--;
+
+       len = endp - startp + 1;
+       if (len >= sizeof(bname)) {
+               errno = ENAMETOOLONG;
+               return (NULL);
+       }
+       memcpy(bname, startp, len);
+       bname[len] = '\0';
+       return (bname);
+}
+
+#endif /* !defined(HAVE_BASENAME) */
diff --git a/openbsd-compat/bindresvport.c b/openbsd-compat/bindresvport.c
new file mode 100644 (file)
index 0000000..c89f214
--- /dev/null
@@ -0,0 +1,118 @@
+/* This file has be substantially modified from the original OpenBSD source */
+
+/*     $OpenBSD: bindresvport.c,v 1.17 2005/12/21 01:40:22 millert Exp $       */
+
+/*
+ * Copyright 1996, Jason Downs.  All rights reserved.
+ * Copyright 1998, Theo de Raadt.  All rights reserved.
+ * Copyright 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/rpc/bindresvport.c */
+
+#include "includes.h"
+
+#ifndef HAVE_BINDRESVPORT_SA
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.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(int sd, struct sockaddr *sa)
+{
+       int error, af;
+       struct sockaddr_storage myaddr;
+       struct sockaddr_in *in;
+       struct sockaddr_in6 *in6;
+       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) {
+               in = (struct sockaddr_in *)sa;
+               salen = sizeof(struct sockaddr_in);
+               portp = &in->sin_port;
+       } else if (af == AF_INET6) {
+               in6 = (struct sockaddr_in6 *)sa;
+               salen = sizeof(struct sockaddr_in6);
+               portp = &in6->sin6_port;
+       } else {
+               errno = EPFNOSUPPORT;
+               return (-1);
+       }
+       sa->sa_family = af;
+
+       port = ntohs(*portp);
+       if (port == 0)
+               port = arc4random_uniform(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/openbsd-compat/bsd-arc4random.c b/openbsd-compat/bsd-arc4random.c
new file mode 100644 (file)
index 0000000..d7c5862
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1999,2000,2004 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "log.h"
+
+#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];
+       int i;
+
+       memset(&rc4, 0, sizeof(rc4));
+       if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0)
+               fatal("Couldn't obtain random bytes (error %ld)",
+                   ERR_get_error());
+       RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
+
+       /*
+        * Discard early keystream, as per recommendations in:
+        * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
+        */
+       for(i = 0; i <= 256; i += sizeof(rand_buf))
+               RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
+
+       memset(rand_buf, 0, sizeof(rand_buf));
+
+       rc4_ready = REKEY_BYTES;
+}
+#endif /* !HAVE_ARC4RANDOM */
+
+#ifndef HAVE_ARC4RANDOM_BUF
+void
+arc4random_buf(void *_buf, size_t n)
+{
+       size_t i;
+       u_int32_t r = 0;
+       char *buf = (char *)_buf;
+
+       for (i = 0; i < n; i++) {
+               if (i % 4 == 0)
+                       r = arc4random();
+               buf[i] = r & 0xff;
+               r >>= 8;
+       }
+       i = r = 0;
+}
+#endif /* !HAVE_ARC4RANDOM_BUF */
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound).  This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+u_int32_t
+arc4random_uniform(u_int32_t upper_bound)
+{
+       u_int32_t r, min;
+
+       if (upper_bound < 2)
+               return 0;
+
+#if (ULONG_MAX > 0xffffffffUL)
+       min = 0x100000000UL % upper_bound;
+#else
+       /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+       if (upper_bound > 0x80000000)
+               min = 1 + ~upper_bound;         /* 2**32 - upper_bound */
+       else {
+               /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+               min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+       }
+#endif
+
+       /*
+        * This could theoretically loop forever but each retry has
+        * p > 0.5 (worst case, usually far better) of selecting a
+        * number inside the range we need, so it should rarely need
+        * to re-roll.
+        */
+       for (;;) {
+               r = arc4random();
+               if (r >= min)
+                       break;
+       }
+
+       return r % upper_bound;
+}
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
diff --git a/openbsd-compat/bsd-asprintf.c b/openbsd-compat/bsd-asprintf.c
new file mode 100644 (file)
index 0000000..3368195
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.
+ *
+ * Based originally on asprintf.c from OpenBSD:
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_VASPRINTF
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#ifndef VA_COPY
+# ifdef HAVE_VA_COPY
+#  define VA_COPY(dest, src) va_copy(dest, src)
+# else
+#  ifdef HAVE___VA_COPY
+#   define VA_COPY(dest, src) __va_copy(dest, src)
+#  else
+#   define VA_COPY(dest, src) (dest) = (src)
+#  endif
+# endif
+#endif
+
+#define INIT_SZ        128
+
+int
+vasprintf(char **str, const char *fmt, va_list ap)
+{
+       int ret = -1;
+       va_list ap2;
+       char *string, *newstr;
+       size_t len;
+
+       VA_COPY(ap2, ap);
+       if ((string = malloc(INIT_SZ)) == NULL)
+               goto fail;
+
+       ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+       if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
+               *str = string;
+       } else if (ret == INT_MAX || ret < 0) { /* Bad length */
+               free(string);
+               goto fail;
+       } else {        /* bigger than initial, realloc allowing for nul */
+               len = (size_t)ret + 1;
+               if ((newstr = realloc(string, len)) == NULL) {
+                       free(string);
+                       goto fail;
+               } else {
+                       va_end(ap2);
+                       VA_COPY(ap2, ap);
+                       ret = vsnprintf(newstr, len, fmt, ap2);
+                       if (ret >= 0 && (size_t)ret < len) {
+                               *str = newstr;
+                       } else { /* failed with realloc'ed string, give up */
+                               free(newstr);
+                               goto fail;
+                       }
+               }
+       }
+       va_end(ap2);
+       return (ret);
+
+fail:
+       *str = NULL;
+       errno = ENOMEM;
+       va_end(ap2);
+       return (-1);
+}
+#endif
+
+#ifndef HAVE_ASPRINTF
+int asprintf(char **str, const char *fmt, ...)
+{
+       va_list ap;
+       int ret;
+       
+       *str = NULL;
+       va_start(ap, fmt);
+       ret = vasprintf(str, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+#endif
diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c
new file mode 100644 (file)
index 0000000..9380b33
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_CLOSEFROM
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdio.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <limits.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#ifndef OPEN_MAX
+# define OPEN_MAX      256
+#endif
+
+#if 0
+__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
+#endif /* lint */
+
+/*
+ * Close all file descriptors greater than or equal to lowfd.
+ */
+#ifdef HAVE_FCNTL_CLOSEM
+void
+closefrom(int lowfd)
+{
+    (void) fcntl(lowfd, F_CLOSEM, 0);
+}
+#else
+void
+closefrom(int lowfd)
+{
+    long fd, maxfd;
+#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
+    char fdpath[PATH_MAX], *endp;
+    struct dirent *dent;
+    DIR *dirp;
+    int len;
+
+    /* Check for a /proc/$$/fd directory. */
+    len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
+    if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
+       while ((dent = readdir(dirp)) != NULL) {
+           fd = strtol(dent->d_name, &endp, 10);
+           if (dent->d_name != endp && *endp == '\0' &&
+               fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
+               (void) close((int) fd);
+       }
+       (void) closedir(dirp);
+    } else
+#endif
+    {
+       /*
+        * Fall back on sysconf() or getdtablesize().  We avoid checking
+        * resource limits since it is possible to open a file descriptor
+        * and then drop the rlimit such that it is below the open fd.
+        */
+#ifdef HAVE_SYSCONF
+       maxfd = sysconf(_SC_OPEN_MAX);
+#else
+       maxfd = getdtablesize();
+#endif /* HAVE_SYSCONF */
+       if (maxfd < 0)
+           maxfd = OPEN_MAX;
+
+       for (fd = lowfd; fd < maxfd; fd++)
+           (void) close((int) fd);
+    }
+}
+#endif /* !HAVE_FCNTL_CLOSEM */
+#endif /* HAVE_CLOSEFROM */
diff --git a/openbsd-compat/bsd-cray.c b/openbsd-compat/bsd-cray.c
new file mode 100644 (file)
index 0000000..f1bbd7d
--- /dev/null
@@ -0,0 +1,817 @@
+/* 
+ * $Id: bsd-cray.c,v 1.17 2007/08/15 09:17:43 dtucker Exp $
+ *
+ * bsd-cray.c
+ *
+ * Copyright (c) 2002, Cray Inc.  (Wendy Palm <wendyp@cray.com>)
+ * Significant portions provided by 
+ *          Wayne Schroeder, SDSC <schroeder@sdsc.edu>
+ *          William Jones, UTexas <jones@tacc.utexas.edu>
+ *
+ * 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.
+ *
+ * Created: Apr 22 16.34:00 2002 wp
+ *
+ * This file contains functions required for proper execution
+ * on UNICOS systems.
+ *
+ */
+#ifdef _UNICOS
+
+#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/tfm.h>
+#include <sys/usrv.h>
+#include <sys/sysv.h>
+#include <sys/sectab.h>
+#include <sys/secstat.h>
+#include <sys/stat.h>
+#include <sys/session.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ia.h>
+#include <urm.h>
+#include "ssh.h"
+
+#include "includes.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))
+
+# 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 AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+#include "log.h"
+#include "servconf.h"
+#include "bsd-cray.h"
+
+#define MAXACID 80
+
+extern ServerOptions options;
+
+char cray_tmpdir[TPATHSIZ + 1];                    /* job TMPDIR path */
+
+struct sysv sysv;      /* system security structure */
+struct usrv usrv;      /* user security structure */
+
+/*
+ * 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 *);
+void cray_login_failure(char *, int);
+int cray_setup(uid_t, char *, const char *);
+int cray_access_denied(char *);
+
+void
+cray_login_failure(char *username, int errcode)
+{
+       struct udb *ueptr;              /* UDB pointer for username */
+       ia_failure_t fsent;             /* ia_failure structure */
+       ia_failure_ret_t fret;          /* ia_failure return stuff */
+       struct jtab jtab;               /* job table structure */
+       int jid = 0;                    /* job id */
+
+       if ((jid = getjtab(&jtab)) < 0)
+               debug("cray_login_failure(): getjtab error");
+
+       getsysudb();
+       if ((ueptr = getudbnam(username)) == UDB_NULL)
+               debug("cray_login_failure(): getudbname() returned NULL");
+       endudb();
+
+       memset(&fsent, '\0', sizeof(fsent));
+       fsent.revision = 0;
+       fsent.uname = username;
+       fsent.host = (char *)get_canonical_hostname(options.use_dns);
+       fsent.ttyn = "sshd";
+       fsent.caller = IA_SSHD;
+       fsent.flags = IA_INTERACTIVE;
+       fsent.ueptr = ueptr;
+       fsent.jid = jid;
+       fsent.errcode = errcode;
+       fsent.pwdp = NULL;
+       fsent.exitcode = 0;     /* dont exit in ia_failure() */
+
+       fret.revision = 0;
+       fret.normal = 0;
+
+       /*
+        * Call ia_failure because of an login failure.
+        */
+       ia_failure(&fsent, &fret);
+}
+
+/*
+ *  Cray access denied
+ */
+int
+cray_access_denied(char *username)
+{
+       struct udb *ueptr;              /* UDB pointer for username */
+       int errcode;                    /* IA errorcode */
+
+       errcode = 0;
+       getsysudb();
+       if ((ueptr = getudbnam(username)) == UDB_NULL)
+               debug("cray_login_failure(): getudbname() returned NULL");
+       endudb();
+
+       if (ueptr != NULL && ueptr->ue_disabled)
+               errcode = IA_DISABLED;
+       if (errcode)
+               cray_login_failure(username, errcode);
+
+       return (errcode);
+}
+
+/*
+ * record_failed_login: generic "login failed" interface function
+ */
+void
+record_failed_login(const char *user, const char *hostname, const char *ttyname)
+{
+       cray_login_failure((char *)user, IA_UDBERR);
+}
+
+int
+cray_setup (uid_t uid, char *username, const char *command)
+{
+       extern struct udb *getudb();
+       extern char *setlimits();
+
+       int err;                        /* error return */
+       time_t system_time;             /* current system clock */
+       time_t expiration_time;         /* password expiration time */
+       int maxattempts;                /* maximum no. of failed login attempts */
+       int SecureSys;                  /* unicos security flag */
+       int minslevel = 0;              /* system minimum security level */
+       int i, j;
+       int valid_acct = -1;            /* flag for reading valid acct */
+       char acct_name[MAXACID] = { "" }; /* used to read acct name */
+       struct jtab jtab;               /* Job table struct */
+       struct udb ue;                  /* udb entry for logging-in user */
+       struct udb *up;                 /* pointer to UDB entry */
+       struct secstat secinfo;         /* file  security attributes */
+       struct servprov init_info;      /* used for sesscntl() call */
+       int jid;                        /* job ID */
+       int pid;                        /* process ID */
+       char *sr;                       /* status return from setlimits() */
+       char *ttyn = NULL;              /* ttyname or command name*/
+       char hostname[MAXHOSTNAMELEN];
+       /* passwd stuff for ia_user */
+       passwd_t pwdacm, pwddialup, pwdudb, pwdwal, pwddce;
+       ia_user_ret_t uret;             /* stuff returned from ia_user */
+       ia_user_t usent;                /* ia_user main structure */
+       int ia_rcode;                   /* ia_user return code */
+       ia_failure_t fsent;             /* ia_failure structure */
+       ia_failure_ret_t fret;          /* ia_failure return stuff */
+       ia_success_t ssent;             /* ia_success structure */
+       ia_success_ret_t sret;          /* ia_success return stuff */
+       int ia_mlsrcode;                /* ia_mlsuser return code */
+       int secstatrc;                  /* [f]secstat return code */
+
+       if (SecureSys = (int)sysconf(_SC_CRAY_SECURE_SYS)) {
+               getsysv(&sysv, sizeof(struct sysv));
+               minslevel = sysv.sy_minlvl;
+               if (getusrv(&usrv) < 0)
+                       fatal("getusrv() failed, errno = %d", errno);
+       }
+       hostname[0] = '\0';
+       strlcpy(hostname,
+          (char *)get_canonical_hostname(options.use_dns),
+          MAXHOSTNAMELEN);
+       /*
+        *  Fetch user's UDB entry.
+        */
+       getsysudb();
+       if ((up = getudbnam(username)) == UDB_NULL)
+               fatal("cannot fetch user's UDB entry");
+
+       /*
+        *  Prevent any possible fudging so perform a data
+        *  safety check and compare the supplied uid against
+        *  the udb's uid.
+        */
+       if (up->ue_uid != uid)
+               fatal("IA uid missmatch");
+       endudb();
+
+       if ((jid = getjtab(&jtab)) < 0) {
+               debug("getjtab");
+               return(-1);
+       }
+       pid = getpid();
+       ttyn = ttyname(0);
+       if (SecureSys) {
+               if (ttyn != NULL)
+                       secstatrc = secstat(ttyn, &secinfo);
+               else
+                       secstatrc = fsecstat(1, &secinfo);
+
+               if (secstatrc == 0)
+                       debug("[f]secstat() successful");
+               else
+                       fatal("[f]secstat() error, rc = %d", secstatrc);
+       }
+       if ((ttyn == NULL) && ((char *)command != NULL))
+               ttyn = (char *)command;
+       /*
+        *  Initialize all structures to call ia_user
+        */
+       usent.revision = 0;
+       usent.uname = username;
+       usent.host = hostname;
+       usent.ttyn = ttyn;
+       usent.caller = IA_SSHD; 
+       usent.pswdlist = &pwdacm;
+       usent.ueptr = &ue;
+       usent.flags = IA_INTERACTIVE | IA_FFLAG;
+       pwdacm.atype = IA_SECURID;
+       pwdacm.pwdp = NULL;
+       pwdacm.next = &pwdudb;
+
+       pwdudb.atype = IA_UDB;
+       pwdudb.pwdp = NULL;
+       pwdudb.next = &pwddce;
+
+       pwddce.atype = IA_DCE;
+       pwddce.pwdp = NULL;
+       pwddce.next = &pwddialup;
+
+       pwddialup.atype = IA_DIALUP;
+       pwddialup.pwdp = NULL;
+       /* pwddialup.next = &pwdwal; */
+       pwddialup.next = NULL;
+
+       pwdwal.atype = IA_WAL;
+       pwdwal.pwdp = NULL;
+       pwdwal.next = NULL;
+
+       uret.revision = 0;
+       uret.pswd = NULL;
+       uret.normal = 0;
+
+       ia_rcode = ia_user(&usent, &uret);
+       switch (ia_rcode) {
+       /*
+        *  These are acceptable return codes from ia_user()
+        */
+       case IA_UDBWEEK:        /* Password Expires in 1 week */
+               expiration_time = ue.ue_pwage.time + ue.ue_pwage.maxage;
+               printf ("WARNING - your current password will expire %s\n",
+               ctime((const time_t *)&expiration_time));
+               break;
+       case IA_UDBEXPIRED:
+               if (ttyname(0) != NULL) {
+                       /* Force a password change */
+                       printf("Your password has expired; Choose a new one.\n");
+                       execl("/bin/passwd", "passwd", username, 0);
+                       exit(9);
+                       }
+               break;
+       case IA_NORMAL:         /* Normal Return Code */
+               break;
+       case IA_BACKDOOR:
+               /* XXX: can we memset it to zero here so save some of this */
+               strlcpy(ue.ue_name, "root", sizeof(ue.ue_name));
+               strlcpy(ue.ue_dir, "/", sizeof(ue.ue_dir));
+               strlcpy(ue.ue_shell, "/bin/sh", sizeof(ue.ue_shell));
+
+               ue.ue_passwd[0] = '\0';
+               ue.ue_age[0] = '\0';
+               ue.ue_comment[0] = '\0';
+               ue.ue_loghost[0] = '\0';
+               ue.ue_logline[0] = '\0';
+
+               ue.ue_uid = -1;
+               ue.ue_nice[UDBRC_INTER] = 0;
+
+               for (i = 0; i < MAXVIDS; i++)
+                       ue.ue_gids[i] = 0;
+
+               ue.ue_logfails = 0;
+               ue.ue_minlvl = ue.ue_maxlvl = ue.ue_deflvl = minslevel;
+               ue.ue_defcomps = 0;
+               ue.ue_comparts = 0;
+               ue.ue_permits = 0;
+               ue.ue_trap = 0;
+               ue.ue_disabled = 0;
+               ue.ue_logtime = 0;
+               break;
+       case IA_CONSOLE:        /* Superuser not from Console */
+       case IA_TRUSTED:        /* Trusted user */
+               if (options.permit_root_login > PERMIT_NO)
+                       break;  /* Accept root login */
+       default:
+       /*
+        *  These are failed return codes from ia_user()
+        */
+               switch (ia_rcode) 
+               {
+               case IA_BADAUTH:
+                       printf("Bad authorization, access denied.\n");
+                       break;
+               case IA_DISABLED:
+                       printf("Your login has been disabled. Contact the system ");
+                       printf("administrator for assistance.\n");
+                       break;
+               case IA_GETSYSV:
+                       printf("getsysv() failed - errno = %d\n", errno);
+                       break;
+               case IA_MAXLOGS:
+                       printf("Maximum number of failed login attempts exceeded.\n");
+                       printf("Access denied.\n");
+                       break;
+               case IA_UDBPWDNULL:
+                       if (SecureSys)
+                               printf("NULL Password not allowed on MLS systems.\n");
+                       break;
+               default:
+                       break;
+               }
+
+               /*
+                *  Authentication failed.
+                */
+               printf("sshd: Login incorrect, (0%o)\n",
+                   ia_rcode-IA_ERRORCODE);
+
+               /*
+                *  Initialize structure for ia_failure
+                *  which will exit.
+                */
+               fsent.revision = 0;
+               fsent.uname = username;
+               fsent.host = hostname;
+               fsent.ttyn = ttyn;
+               fsent.caller = IA_SSHD;
+               fsent.flags = IA_INTERACTIVE;
+               fsent.ueptr = &ue;
+               fsent.jid = jid;
+               fsent.errcode = ia_rcode;
+               fsent.pwdp = uret.pswd;
+               fsent.exitcode = 1;
+
+               fret.revision = 0;
+               fret.normal = 0;
+
+               /*
+               *  Call ia_failure because of an IA failure.
+               *  There is no return because ia_failure exits.
+               */
+               ia_failure(&fsent, &fret);
+
+               exit(1); 
+       }
+
+       ia_mlsrcode = IA_NORMAL;
+       if (SecureSys) {
+               debug("calling ia_mlsuser()");
+               ia_mlsrcode = ia_mlsuser(&ue, &secinfo, &usrv, NULL, 0);
+       }
+       if (ia_mlsrcode != IA_NORMAL) {
+               printf("sshd: Login incorrect, (0%o)\n",
+                   ia_mlsrcode-IA_ERRORCODE);
+               /*
+                *  Initialize structure for ia_failure
+                *  which will exit.
+                */
+               fsent.revision = 0;
+               fsent.uname = username;
+               fsent.host = hostname;
+               fsent.ttyn = ttyn;
+               fsent.caller = IA_SSHD;
+               fsent.flags = IA_INTERACTIVE;
+               fsent.ueptr = &ue;
+               fsent.jid  = jid;
+               fsent.errcode = ia_mlsrcode;
+               fsent.pwdp = uret.pswd;
+               fsent.exitcode = 1;
+               fret.revision = 0;
+               fret.normal = 0;
+
+               /*
+                *  Call ia_failure because of an IA failure.
+                *  There is no return because ia_failure exits.
+                */
+               ia_failure(&fsent,&fret);
+               exit(1); 
+       }
+
+       /* Provide login status information */
+       if (options.print_lastlog && ue.ue_logtime != 0) {
+               printf("Last successful login was : %.*s ", 19,
+                   (char *)ctime(&ue.ue_logtime));
+
+               if (*ue.ue_loghost != '\0') {
+                       printf("from %.*s\n", sizeof(ue.ue_loghost),
+                           ue.ue_loghost);
+               } else {
+                       printf("on %.*s\n", sizeof(ue.ue_logline),
+                           ue.ue_logline);
+               }
+
+               if (SecureSys && (ue.ue_logfails != 0)) {
+                       printf("  followed by %d failed attempts\n",
+                           ue.ue_logfails);
+               }
+       }
+
+       /*
+        * Call ia_success to process successful I/A.
+        */
+       ssent.revision = 0;
+       ssent.uname = username;
+       ssent.host = hostname;
+       ssent.ttyn = ttyn;
+       ssent.caller = IA_SSHD;
+       ssent.flags = IA_INTERACTIVE;
+       ssent.ueptr = &ue;
+       ssent.jid = jid;
+       ssent.errcode = ia_rcode;
+       ssent.us = NULL;
+       ssent.time = 1; /* Set ue_logtime */
+
+       sret.revision = 0;
+       sret.normal = 0;
+
+       ia_success(&ssent, &sret);
+
+       /*
+        * Query for account, iff > 1 valid acid & askacid permbit
+        */
+       if (((ue.ue_permbits & PERMBITS_ACCTID) ||
+           (ue.ue_acids[0] >= 0) && (ue.ue_acids[1] >= 0)) &&
+           ue.ue_permbits & PERMBITS_ASKACID) {
+               if (ttyname(0) != NULL) {
+                       debug("cray_setup: ttyname true case, %.100s", ttyname);
+                       while (valid_acct == -1) {
+                               printf("Account (? for available accounts)"
+                                   " [%s]: ", acid2nam(ue.ue_acids[0]));
+                               fgets(acct_name, MAXACID, stdin);
+                               switch (acct_name[0]) {
+                               case EOF:
+                                       exit(0);
+                                       break;
+                               case '\0':
+                                       valid_acct = ue.ue_acids[0];
+                                       strlcpy(acct_name, acid2nam(valid_acct), MAXACID);
+                                       break;
+                               case '?':
+                                       /* Print the list 3 wide */
+                                       for (i = 0, j = 0; i < MAXVIDS; i++) {
+                                               if (ue.ue_acids[i] == -1) {
+                                                       printf("\n");
+                                                       break;
+                                               }
+                                               if (++j == 4) {
+                                                       j = 1;
+                                                       printf("\n");
+                                               }
+                                               printf(" %s",
+                                                   acid2nam(ue.ue_acids[i]));
+                                       }
+                                       if (ue.ue_permbits & PERMBITS_ACCTID) {
+                                               printf("\"acctid\" permbit also allows"
+                                                   " you to select any valid "
+                                                   "account name.\n");
+                                       }
+                                       printf("\n");
+                                       break;
+                               default:
+                                       valid_acct = nam2acid(acct_name);
+                                       if (valid_acct == -1) 
+                                               printf(
+                                                   "Account id not found for"
+                                                   " account name \"%s\"\n\n",
+                                                   acct_name);
+                                       break;
+                               }
+                               /*
+                                * If an account was given, search the user's
+                                * acids array to verify they can use this account.
+                                */
+                               if ((valid_acct != -1) &&
+                                   !(ue.ue_permbits & PERMBITS_ACCTID)) {
+                                       for (i = 0; i < MAXVIDS; i++) {
+                                               if (ue.ue_acids[i] == -1)
+                                                       break;
+                                               if (valid_acct == ue.ue_acids[i])
+                                                       break;
+                                       }
+                                       if (i == MAXVIDS ||
+                                           ue.ue_acids[i] == -1) {
+                                               fprintf(stderr, "Cannot set"
+                                                   " account name to "
+                                                   "\"%s\", permission "
+                                                   "denied\n\n", acct_name);
+                                               valid_acct = -1;
+                                       }
+                               }
+                       }
+               } else {
+                       /*
+                        * The client isn't connected to a terminal and can't
+                        * respond to an acid prompt.  Use default acid.
+                        */
+                       debug("cray_setup: ttyname false case, %.100s",
+                           ttyname);
+                       valid_acct = ue.ue_acids[0];
+               }
+       } else {
+               /*
+                * The user doesn't have the askacid permbit set or
+                * only has one valid account to use.
+                */
+               valid_acct = ue.ue_acids[0];
+       }
+       if (acctid(0, valid_acct) < 0) {
+               printf ("Bad account id: %d\n", valid_acct);
+               exit(1);
+       }
+
+       /* 
+        * Now set shares, quotas, limits, including CPU time for the 
+        * (interactive) job and process, and set up permissions 
+        * (for chown etc), etc.
+        */
+       if (setshares(ue.ue_uid, valid_acct, printf, 0, 0)) {
+               printf("Unable to give %d shares to <%s>(%d/%d)\n",
+                   ue.ue_shares, ue.ue_name, ue.ue_uid, valid_acct);
+               exit(1);
+       }
+
+       sr = setlimits(username, C_PROC, pid, UDBRC_INTER);
+       if (sr != NULL) {
+               debug("%.200s", sr);
+               exit(1);
+       }
+       sr = setlimits(username, C_JOB, jid, UDBRC_INTER);
+       if (sr != NULL) {
+               debug("%.200s", sr);
+               exit(1);
+       }
+       /*
+        * Place the service provider information into
+        * the session table (Unicos) or job table (Unicos/mk).
+        * There exist double defines for the job/session table in
+        * unicos/mk (jtab.h) so no need for a compile time switch.
+        */
+       memset(&init_info, '\0', sizeof(init_info));
+       init_info.s_sessinit.si_id = URM_SPT_LOGIN;
+       init_info.s_sessinit.si_pid = getpid();
+       init_info.s_sessinit.si_sid = jid;
+       sesscntl(0, S_SETSERVPO, (int)&init_info);
+
+       /*
+        * Set user and controlling tty security attributes.
+        */
+       if (SecureSys) {
+               if (setusrv(&usrv) == -1) {
+                       debug("setusrv() failed, errno = %d",errno);
+                       exit(1);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * 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();
+
+       /*
+        * 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("Setting MLS labels.");;
+
+       if (sysconf(_SC_CRAY_SECURE_MAC)) {
+               usrv.sv_minlvl = SYSLOW;
+               usrv.sv_actlvl = SYSHIGH;
+               usrv.sv_maxlvl = SYSHIGH;
+       } else {
+               usrv.sv_minlvl = sysv.sy_minlvl;
+               usrv.sv_actlvl = sysv.sy_minlvl;
+               usrv.sv_maxlvl = sysv.sy_maxlvl;
+       }       
+       usrv.sv_actcmp = 0;
+       usrv.sv_valcmp = sysv.sy_valcmp;
+
+       usrv.sv_intcat = TFM_SYSTEM;
+       usrv.sv_valcat |= (TFM_SYSTEM | TFM_SYSFILE);
+
+       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) {
+               /* XXX use atomicio */
+               while (read(fd, (char *)&utmp, sizeof(utmp)) == sizeof(utmp)) {
+                       if (pid == utmp.ut_pid) {
+                               ut->ut_jid = utmp.ut_jid;
+                               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);
+       } else
+               fatal("Unable to open utmp file");
+}
+
+/*
+ * tmpdir support.
+ */
+
+/*
+ * find and delete jobs tmpdir.
+ */
+void
+cray_delete_tmpdir(char *login, int jid, uid_t uid)
+{
+       static char jtmp[TPATHSIZ];
+       struct stat statbuf;
+       int child, c, 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;
+
+       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 /* UNICOS */
+
+#ifdef _UNICOSMP
+#include <pwd.h>
+/*
+ * Set job id and create tmpdir directory.
+ */
+void
+cray_init_job(struct passwd *pw)
+{
+       initrm_silent(pw->pw_uid);
+       return;
+}
+#endif /* _UNICOSMP */
diff --git a/openbsd-compat/bsd-cray.h b/openbsd-compat/bsd-cray.h
new file mode 100644 (file)
index 0000000..774eceb
--- /dev/null
@@ -0,0 +1,61 @@
+/* $Id: bsd-cray.h,v 1.12 2005/02/02 06:10:11 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2002, Cray Inc.  (Wendy Palm <wendyp@cray.com>)
+ * Significant portions provided by 
+ *          Wayne Schroeder, SDSC <schroeder@sdsc.edu>
+ *          William Jones, UTexas <jones@tacc.utexas.edu>
+ *
+ * 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.
+ *
+ * Created: Apr 22 16.34:00 2002 wp
+ *
+ * This file contains functions required for proper execution
+ * on UNICOS systems.
+ *
+ */
+
+#ifndef _BSD_CRAY_H
+#define _BSD_CRAY_H
+
+#ifdef _UNICOS
+
+void cray_init_job(struct passwd *);
+void cray_job_termination_handler(int);
+void cray_login_failure(char *, int );
+int cray_access_denied(char *);
+extern char cray_tmpdir[];
+
+#define CUSTOM_FAILED_LOGIN 1
+
+#ifndef IA_SSHD
+# define IA_SSHD IA_LOGIN
+#endif
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN  64
+#endif
+#ifndef _CRAYT3E
+# define TIOCGPGRP (tIOC|20)
+#endif
+
+#endif /* UNICOS */
+
+#endif /* _BSD_CRAY_H */
diff --git a/openbsd-compat/bsd-cygwin_util.c b/openbsd-compat/bsd-cygwin_util.c
new file mode 100644 (file)
index 0000000..e9fa3a0
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2000, 2001, Corinna Vinschen <vinschen@cygnus.com>
+ *
+ * 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.
+ *
+ * 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"
+
+#ifdef HAVE_CYGWIN
+
+#if defined(open) && open == binary_open
+# undef open
+#endif
+#if defined(pipe) && open == binary_pipe
+# undef pipe
+#endif
+
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <windows.h>
+
+#include "xmalloc.h"
+
+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_ntsec(const char *filename)
+{
+       return (pathconf(filename, _PC_POSIX_PERMISSIONS));
+}
+
+#define NL(x) x, (sizeof (x) - 1)
+#define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0]))
+
+static struct wenv {
+       const char *name;
+       size_t namelen;
+} wenv_arr[] = {
+       { NL("ALLUSERSPROFILE=") },
+       { NL("COMPUTERNAME=") },
+       { NL("COMSPEC=") },
+       { NL("CYGWIN=") },
+       { NL("OS=") },
+       { NL("PATH=") },
+       { NL("PATHEXT=") },
+       { NL("SYSTEMDRIVE=") },
+       { NL("SYSTEMROOT=") },
+       { NL("WINDIR=") }
+};
+
+char **
+fetch_windows_environment(void)
+{
+       char **e, **p;
+       unsigned int i, idx = 0;
+
+       p = xcalloc(WENV_SIZ + 1, sizeof(char *));
+       for (e = environ; *e != NULL; ++e) {
+               for (i = 0; i < WENV_SIZ; ++i) {
+                       if (!strncmp(*e, wenv_arr[i].name, wenv_arr[i].namelen))
+                               p[idx++] = *e;
+               }
+       }
+       p[idx] = NULL;
+       return p;
+}
+
+void
+free_windows_environment(char **p)
+{
+       xfree(p);
+}
+
+#endif /* HAVE_CYGWIN */
diff --git a/openbsd-compat/bsd-cygwin_util.h b/openbsd-compat/bsd-cygwin_util.h
new file mode 100644 (file)
index 0000000..39b8eb7
--- /dev/null
@@ -0,0 +1,54 @@
+/* $Id: bsd-cygwin_util.h,v 1.12 2009/03/08 00:40:28 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2000, 2001, Corinna Vinschen <vinschen@cygnus.com>
+ *
+ * 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.
+ *
+ * Created: Sat Sep 02 12:17:00 2000 cv
+ *
+ * This file contains functions for forcing opened file descriptors to
+ * binary mode on Windows systems.
+ */
+
+#ifndef _BSD_CYGWIN_UTIL_H
+#define _BSD_CYGWIN_UTIL_H
+
+#ifdef HAVE_CYGWIN
+
+#undef ERROR
+
+#include <windows.h>
+#include <sys/cygwin.h>
+#include <io.h>
+
+int binary_open(const char *, int , ...);
+int binary_pipe(int fd[2]);
+int check_ntsec(const char *);
+char **fetch_windows_environment(void);
+void free_windows_environment(char **);
+
+#define open binary_open
+#define pipe binary_pipe
+
+#endif /* HAVE_CYGWIN */
+
+#endif /* _BSD_CYGWIN_UTIL_H */
diff --git a/openbsd-compat/bsd-getpeereid.c b/openbsd-compat/bsd-getpeereid.c
new file mode 100644 (file)
index 0000000..5f7e677
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2002,2004 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#if !defined(HAVE_GETPEEREID)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <unistd.h>
+
+#if defined(SO_PEERCRED)
+int
+getpeereid(int s, uid_t *euid, gid_t *gid)
+{
+       struct ucred cred;
+       socklen_t len = sizeof(cred);
+
+       if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
+               return (-1);
+       *euid = cred.uid;
+       *gid = cred.gid;
+
+       return (0);
+}
+#elif defined(HAVE_GETPEERUCRED)
+
+#ifdef HAVE_UCRED_H
+# include <ucred.h>
+#endif
+
+int
+getpeereid(int s, uid_t *euid, gid_t *gid)
+{
+       ucred_t *ucred = NULL;
+
+       if (getpeerucred(s, &ucred) == -1)
+               return (-1);
+       if ((*euid = ucred_geteuid(ucred)) == -1)
+               return (-1);
+       if ((*gid = ucred_getrgid(ucred)) == -1)
+               return (-1);
+
+       ucred_free(ucred);
+
+       return (0);
+}
+#else
+int
+getpeereid(int s, uid_t *euid, gid_t *gid)
+{
+       *euid = geteuid();
+       *gid = getgid();
+
+       return (0);
+}
+#endif /* defined(SO_PEERCRED) */
+
+#endif /* !defined(HAVE_GETPEEREID) */
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
new file mode 100644 (file)
index 0000000..3ef373f
--- /dev/null
@@ -0,0 +1,249 @@
+
+/*
+ * Copyright (c) 1999-2004 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <string.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+
+#ifndef HAVE___PROGNAME
+char *__progname;
+#endif
+
+/*
+ * NB. duplicate __progname in case it is an alias for argv[0]
+ * Otherwise it may get clobbered by setproctitle()
+ */
+char *ssh_get_progname(char *argv0)
+{
+#ifdef HAVE___PROGNAME
+       extern char *__progname;
+
+       return xstrdup(__progname);
+#else
+       char *p;
+
+       if (argv0 == NULL)
+               return ("unknown");     /* XXX */
+       p = strrchr(argv0, '/');
+       if (p == NULL)
+               p = argv0;
+       else
+               p++;
+
+       return (xstrdup(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]);
+
+       return ("unlisted error");
+}
+#endif
+
+#ifndef HAVE_UTIMES
+int utimes(char *filename, struct timeval *tvp)
+{
+       struct utimbuf ub;
+
+       ub.actime = tvp[0].tv_sec;
+       ub.modtime = tvp[1].tv_sec;
+       
+       return (utime(filename, &ub));
+}
+#endif 
+
+#ifndef HAVE_TRUNCATE
+int truncate(const char *path, off_t length)
+{
+       int fd, ret, saverrno;
+
+       fd = open(path, O_WRONLY);
+       if (fd < 0)
+               return (-1);
+
+       ret = ftruncate(fd, length);
+       saverrno = errno;
+       close(fd);
+       if (ret == -1)
+               errno = saverrno;
+
+       return(ret);
+}
+#endif /* HAVE_TRUNCATE */
+
+#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP)
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+       int rc, saverrno;
+       extern int errno;
+       struct timeval tstart, tstop, tremain, time2wait;
+
+       TIMESPEC_TO_TIMEVAL(&time2wait, req)
+       (void) gettimeofday(&tstart, NULL);
+       rc = select(0, NULL, NULL, NULL, &time2wait);
+       if (rc == -1) {
+               saverrno = errno;
+               (void) gettimeofday (&tstop, NULL);
+               errno = saverrno;
+               tremain.tv_sec = time2wait.tv_sec - 
+                       (tstop.tv_sec - tstart.tv_sec);
+               tremain.tv_usec = time2wait.tv_usec - 
+                       (tstop.tv_usec - tstart.tv_usec);
+               tremain.tv_sec += tremain.tv_usec / 1000000L;
+               tremain.tv_usec %= 1000000L;
+       } else {
+               tremain.tv_sec = 0;
+               tremain.tv_usec = 0;
+       }
+       if (rem != NULL)
+               TIMEVAL_TO_TIMESPEC(&tremain, rem)
+
+       return(rc);
+}
+#endif
+
+#ifndef HAVE_TCGETPGRP
+pid_t
+tcgetpgrp(int fd)
+{
+       int ctty_pgrp;
+
+       if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1)
+               return(-1);
+       else
+               return(ctty_pgrp);
+}
+#endif /* HAVE_TCGETPGRP */
+
+#ifndef HAVE_TCSENDBREAK
+int
+tcsendbreak(int fd, int duration)
+{
+# if defined(TIOCSBRK) && defined(TIOCCBRK)
+       struct timeval sleepytime;
+
+       sleepytime.tv_sec = 0;
+       sleepytime.tv_usec = 400000;
+       if (ioctl(fd, TIOCSBRK, 0) == -1)
+               return (-1);
+       (void)select(0, 0, 0, 0, &sleepytime);
+       if (ioctl(fd, TIOCCBRK, 0) == -1)
+               return (-1);
+       return (0);
+# else
+       return -1;
+# endif
+}
+#endif /* HAVE_TCSENDBREAK */
+
+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;
+#ifdef 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
+       #undef signal
+       return (signal(sig, act));
+#endif
+}
+
+#ifndef HAVE_STRDUP
+char *
+strdup(const char *str)
+{
+       size_t len;
+       char *cp;
+
+       len = strlen(str) + 1;
+       cp = malloc(len);
+       if (cp != NULL)
+               return(memcpy(cp, str, len));
+       return NULL;
+}
+#endif
+
+#ifndef HAVE_ISBLANK
+int isblank(int c)
+{
+       return (c == ' ' || c == '\t');
+}
+#endif
diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h
new file mode 100644 (file)
index 0000000..e70c3f9
--- /dev/null
@@ -0,0 +1,102 @@
+/* $Id: bsd-misc.h,v 1.19 2010/11/08 22:26:23 tim Exp $ */
+
+/*
+ * Copyright (c) 1999-2004 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BSD_MISC_H
+#define _BSD_MISC_H
+
+#include "includes.h"
+
+char *ssh_get_progname(char *);
+
+#ifndef HAVE_SETSID
+#define setsid() setpgrp(0, getpid())
+#endif /* !HAVE_SETSID */
+
+#ifndef HAVE_SETENV
+int setenv(const char *, const char *, int);
+#endif /* !HAVE_SETENV */
+
+#ifndef HAVE_SETLOGIN
+int setlogin(const char *);
+#endif /* !HAVE_SETLOGIN */
+
+#ifndef HAVE_INNETGR
+int innetgr(const char *, const char *, const char *, const char *);
+#endif /* HAVE_INNETGR */
+
+#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID)
+int seteuid(uid_t);
+#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */
+
+#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID)
+int setegid(uid_t);
+#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */
+
+#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR)
+const char *strerror(int);
+#endif 
+
+
+#ifndef HAVE_UTIMES
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+       long tv_sec;
+       long tv_usec;
+}
+#endif /* HAVE_STRUCT_TIMEVAL */
+
+int utimes(char *, struct timeval *);
+#endif /* HAVE_UTIMES */
+
+#ifndef HAVE_TRUNCATE
+int truncate (const char *, off_t);
+#endif /* HAVE_TRUNCATE */
+
+#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP)
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+       time_t  tv_sec;
+       long    tv_nsec;
+};
+#endif
+int nanosleep(const struct timespec *, struct timespec *);
+#endif
+
+#ifndef HAVE_TCGETPGRP
+pid_t tcgetpgrp(int);
+#endif
+
+#ifndef HAVE_TCSENDBREAK
+int tcsendbreak(int, int);
+#endif
+
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *);
+#endif
+
+/* wrapper for signal interface */
+typedef void (*mysig_t)(int);
+mysig_t mysignal(int sig, mysig_t act);
+
+#define signal(a,b) mysignal(a,b)
+
+#ifndef HAVE_ISBLANK
+int    isblank(int);
+#endif
+
+#endif /* _BSD_MISC_H */
diff --git a/openbsd-compat/bsd-nextstep.c b/openbsd-compat/bsd-nextstep.c
new file mode 100644 (file)
index 0000000..8195af8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000,2001 Ben Lindstrom.  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 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/openbsd-compat/bsd-nextstep.h b/openbsd-compat/bsd-nextstep.h
new file mode 100644 (file)
index 0000000..ca5b4b5
--- /dev/null
@@ -0,0 +1,59 @@
+/* $Id: bsd-nextstep.h,v 1.9 2003/08/29 16:59:52 mouring Exp $ */
+
+/*
+ * Copyright (c) 2000,2001 Ben Lindstrom.  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 _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 *);
+#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 *, const char *, const char *, const char *);
+
+/* TERMCAP */
+int tcgetattr(int, struct termios *);
+int tcsetattr(int, int, const struct termios *);
+int tcsetpgrp(int, pid_t);
+speed_t cfgetospeed(const struct termios *);
+speed_t cfgetispeed(const struct termios *);
+int cfsetospeed(struct termios *, int);
+int cfsetispeed(struct termios *, int);
+#endif /* HAVE_NEXT */
+#endif /* _NEXT_POSIX_H */
diff --git a/openbsd-compat/bsd-openpty.c b/openbsd-compat/bsd-openpty.c
new file mode 100644 (file)
index 0000000..9777eb5
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Please note: this implementation of openpty() is far from complete.
+ * it is just enough for portable OpenSSH's needs.
+ */
+
+/*
+ * Copyright (c) 2004 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * 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"
+#if !defined(HAVE_OPENPTY)
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif /* HAVE_UTIL_H */
+
+#ifdef HAVE_PTY_H
+# include <pty.h>
+#endif
+#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
+# include <sys/stropts.h>
+#endif
+
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+int
+openpty(int *amaster, int *aslave, char *name, struct termios *termp,
+   struct winsize *winp)
+{
+#if defined(HAVE__GETPTY)
+       /*
+        * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
+        * pty's automagically when needed
+        */
+       char *slave;
+
+       if ((slave = _getpty(amaster, O_RDWR, 0622, 0)) == NULL)
+               return (-1);
+
+       /* Open the slave side. */
+       if ((*aslave = open(slave, O_RDWR | O_NOCTTY)) == -1) {
+               close(*amaster);
+               return (-1);
+       }
+       return (0);
+
+#elif 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;
+
+       if ((ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1)
+               return (-1);
+
+       /* XXX: need to close ptm on error? */
+       old_signal = signal(SIGCHLD, SIG_DFL);
+       if (grantpt(ptm) < 0)
+               return (-1);
+       signal(SIGCHLD, old_signal);
+
+       if (unlockpt(ptm) < 0)
+               return (-1);
+
+       if ((pts = ptsname(ptm)) == NULL)
+               return (-1);
+       *amaster = ptm;
+
+       /* Open the slave side. */
+       if ((*aslave = open(pts, O_RDWR | O_NOCTTY)) == -1) {
+               close(*amaster);
+               return (-1);
+       }
+
+       /*
+        * Try to push the appropriate streams modules, as described 
+        * in Solaris pts(7).
+        */
+       ioctl(*aslave, I_PUSH, "ptem");
+       ioctl(*aslave, I_PUSH, "ldterm");
+# ifndef __hpux
+       ioctl(*aslave, I_PUSH, "ttcompat");
+# endif /* __hpux */
+
+       return (0);
+
+#elif defined(HAVE_DEV_PTS_AND_PTC)
+       /* AIX-style pty code. */
+       const char *ttname;
+
+       if ((*amaster = open("/dev/ptc", O_RDWR | O_NOCTTY)) == -1)
+               return (-1);
+       if ((ttname = ttyname(*amaster)) == NULL)
+               return (-1);
+       if ((*aslave = open(ttname, O_RDWR | O_NOCTTY)) == -1) {
+               close(*amaster);
+               return (-1);
+       }
+       return (0);
+
+#elif defined(_UNICOS)
+       char ptbuf[64], ttbuf[64];
+       int i;
+       int highpty;
+
+       highpty = 128;
+#ifdef _SC_CRAY_NPTY
+       if ((highpty = sysconf(_SC_CRAY_NPTY)) == -1)
+               highpty = 128;
+#endif /* _SC_CRAY_NPTY */
+
+       for (i = 0; i < highpty; i++) {
+               snprintf(ptbuf, sizeof(ptbuf), "/dev/pty/%03d", i);
+               snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%03d", i);
+               if ((*amaster = open(ptbuf, O_RDWR|O_NOCTTY)) == -1)
+                       continue;
+               /* Open the slave side. */
+               if ((*aslave = open(ttbuf, O_RDWR|O_NOCTTY)) == -1) {
+                       close(*amaster);
+                       return (-1);
+               }
+               return (0);
+       }
+       return (-1);
+
+#else
+       /* BSD-style pty code. */
+       char ptbuf[64], ttbuf[64];
+       int i;
+       const char *ptymajors = "pqrstuvwxyzabcdefghijklmno"
+           "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       const char *ptyminors = "0123456789abcdef";
+       int num_minors = strlen(ptyminors);
+       int num_ptys = strlen(ptymajors) * num_minors;
+       struct termios tio;
+
+       for (i = 0; i < num_ptys; i++) {
+               snprintf(ptbuf, sizeof(ptbuf), "/dev/pty%c%c", 
+                   ptymajors[i / num_minors], ptyminors[i % num_minors]);
+               snprintf(ttbuf, sizeof(ttbuf), "/dev/tty%c%c",
+                   ptymajors[i / num_minors], ptyminors[i % num_minors]);
+
+               if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) {
+                       /* Try SCO style naming */
+                       snprintf(ptbuf, sizeof(ptbuf), "/dev/ptyp%d", i);
+                       snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%d", i);
+                       if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1)
+                               continue;
+               }
+
+               /* Open the slave side. */
+               if ((*aslave = open(ttbuf, O_RDWR | O_NOCTTY)) == -1) {
+                       close(*amaster);
+                       return (-1);
+               }
+               /* set tty modes to a sane state for broken clients */
+               if (tcgetattr(*amaster, &tio) != -1) {
+                       tio.c_lflag |= (ECHO | ISIG | ICANON);
+                       tio.c_oflag |= (OPOST | ONLCR);
+                       tio.c_iflag |= ICRNL;
+                       tcsetattr(*amaster, TCSANOW, &tio);
+               }
+
+               return (0);
+       }
+       return (-1);
+#endif
+}
+
+#endif /* !defined(HAVE_OPENPTY) */
+
diff --git a/openbsd-compat/bsd-poll.c b/openbsd-compat/bsd-poll.c
new file mode 100644 (file)
index 0000000..f899d7a
--- /dev/null
@@ -0,0 +1,119 @@
+/* $Id: bsd-poll.c,v 1.4 2008/08/29 21:32:38 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au).
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+#if !defined(HAVE_POLL)
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include "bsd-poll.h"
+
+/*
+ * A minimal implementation of poll(2), built on top of select(2).
+ *
+ * Only supports POLLIN and POLLOUT flags in pfd.events, and POLLIN, POLLOUT
+ * and POLLERR flags in revents.
+ *
+ * Supports pfd.fd = -1 meaning "unused" although it's not standard.
+ */
+
+int
+poll(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+       nfds_t i;
+       int saved_errno, ret, fd, maxfd = 0;
+       fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL;
+       size_t nmemb;
+       struct timeval tv, *tvp = NULL;
+
+       for (i = 0; i < nfds; i++) {
+               fd = fds[i].fd;
+               if (fd >= FD_SETSIZE) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               maxfd = MAX(maxfd, fd);
+       }
+
+       nmemb = howmany(maxfd + 1 , NFDBITS);
+       if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL ||
+           (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL ||
+           (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) {
+               saved_errno = ENOMEM;
+               ret = -1;
+               goto out;
+       }
+
+       /* populate event bit vectors for the events we're interested in */
+       for (i = 0; i < nfds; i++) {
+               fd = fds[i].fd;
+               if (fd == -1)
+                       continue;
+               if (fds[i].events & POLLIN) {
+                       FD_SET(fd, readfds);
+                       FD_SET(fd, exceptfds);
+               }
+               if (fds[i].events & POLLOUT) {
+                       FD_SET(fd, writefds);
+                       FD_SET(fd, exceptfds);
+               }
+       }
+
+       /* poll timeout is msec, select is timeval (sec + usec) */
+       if (timeout >= 0) {
+               tv.tv_sec = timeout / 1000;
+               tv.tv_usec = (timeout % 1000) * 1000;
+               tvp = &tv;
+       }
+
+       ret = select(maxfd + 1, readfds, writefds, exceptfds, tvp);
+       saved_errno = errno;
+
+       /* scan through select results and set poll() flags */
+       for (i = 0; i < nfds; i++) {
+               fd = fds[i].fd;
+               fds[i].revents = 0;
+               if (fd == -1)
+                       continue;
+               if (FD_ISSET(fd, readfds)) {
+                       fds[i].revents |= POLLIN;
+               }
+               if (FD_ISSET(fd, writefds)) {
+                       fds[i].revents |= POLLOUT;
+               }
+               if (FD_ISSET(fd, exceptfds)) {
+                       fds[i].revents |= POLLERR;
+               }
+       }
+
+out:
+       if (readfds != NULL)
+               free(readfds);
+       if (writefds != NULL)
+               free(writefds);
+       if (exceptfds != NULL)
+               free(exceptfds);
+       if (ret == -1)
+               errno = saved_errno;
+       return ret;
+}
+#endif
diff --git a/openbsd-compat/bsd-poll.h b/openbsd-compat/bsd-poll.h
new file mode 100644 (file)
index 0000000..dcbb9ca
--- /dev/null
@@ -0,0 +1,61 @@
+/*     $OpenBSD: poll.h,v 1.11 2003/12/10 23:10:08 millert Exp $ */
+
+/*
+ * Copyright (c) 1996 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 ORIGINAL: sys/sys/poll.h */
+
+#if !defined(HAVE_POLL) && !defined(HAVE_POLL_H)
+#ifndef        _COMPAT_POLL_H_
+#define        _COMPAT_POLL_H_
+
+typedef struct pollfd {
+       int     fd;
+       short   events;
+       short   revents;
+} pollfd_t;
+
+typedef unsigned int   nfds_t;
+
+#define        POLLIN          0x0001
+#define        POLLOUT         0x0004
+#define        POLLERR         0x0008
+#if 0
+/* the following are currently not implemented */
+#define        POLLPRI         0x0002
+#define        POLLHUP         0x0010
+#define        POLLNVAL        0x0020
+#define        POLLRDNORM      0x0040
+#define POLLNORM       POLLRDNORM
+#define POLLWRNORM      POLLOUT
+#define        POLLRDBAND      0x0080
+#define        POLLWRBAND      0x0100
+#endif
+
+#define INFTIM         (-1)    /* not standard */
+
+int   poll(struct pollfd *, nfds_t, int);
+#endif /* !_COMPAT_POLL_H_ */
+#endif /* !HAVE_POLL_H */
diff --git a/openbsd-compat/bsd-snprintf.c b/openbsd-compat/bsd-snprintf.c
new file mode 100644 (file)
index 0000000..41d2be2
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * Copyright Patrick Powell 1995
+ * This code is based on code written by Patrick Powell (papowell@astart.com)
+ * It may be used for any purpose as long as this notice remains intact
+ * on all source code distributions
+ */
+
+/**************************************************************
+ * 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.
+ *
+ *  Andrew Tridgell (tridge@samba.org) Oct 1998
+ *    fixed handling of %.0f
+ *    added test for HAVE_LONG_DOUBLE
+ *
+ * tridge@samba.org, idra@samba.org, April 2001
+ *    got rid of fcvt code (twas buggy and made testing harder)
+ *    added C99 semantics
+ *
+ * date: 2002/12/19 19:56:31;  author: herb;  state: Exp;  lines: +2 -0
+ * actually print args for %g and %e
+ * 
+ * date: 2002/06/03 13:37:52;  author: jmcd;  state: Exp;  lines: +8 -0
+ * Since includes.h isn't included here, VA_COPY has to be defined here.  I don't
+ * see any include file that is guaranteed to be here, so I'm defining it
+ * locally.  Fixes AIX and Solaris builds.
+ * 
+ * date: 2002/06/03 03:07:24;  author: tridge;  state: Exp;  lines: +5 -13
+ * put the ifdef for HAVE_VA_COPY in one place rather than in lots of
+ * functions
+ * 
+ * date: 2002/05/17 14:51:22;  author: jmcd;  state: Exp;  lines: +21 -4
+ * Fix usage of va_list passed as an arg.  Use __va_copy before using it
+ * when it exists.
+ * 
+ * date: 2002/04/16 22:38:04;  author: idra;  state: Exp;  lines: +20 -14
+ * Fix incorrect zpadlen handling in fmtfp.
+ * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it.
+ * few mods to make it easier to compile the tests.
+ * addedd the "Ollie" test to the floating point ones.
+ *
+ * Martin Pool (mbp@samba.org) April 2003
+ *    Remove NO_CONFIG_H so that the test case can be built within a source
+ *    tree with less trouble.
+ *    Remove unnecessary SAFE_FREE() definition.
+ *
+ * Martin Pool (mbp@samba.org) May 2003
+ *    Put in a prototype for dummy_snprintf() to quiet compiler warnings.
+ *
+ *    Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even
+ *    if the C library has some snprintf functions already.
+ *
+ * Damien Miller (djm@mindrot.org) Jan 2007
+ *    Fix integer overflows in return value.
+ *    Make formatting quite a bit faster by inlining dopr_outch()
+ *
+ **************************************************************/
+
+#include "includes.h"
+
+#if defined(BROKEN_SNPRINTF)           /* For those with broken snprintf() */
+# undef HAVE_SNPRINTF
+# undef HAVE_VSNPRINTF
+#endif
+
+#ifndef VA_COPY
+# ifdef HAVE_VA_COPY
+#  define VA_COPY(dest, src) va_copy(dest, src)
+# else
+#  ifdef HAVE___VA_COPY
+#   define VA_COPY(dest, src) __va_copy(dest, src)
+#  else
+#   define VA_COPY(dest, src) (dest) = (src)
+#  endif
+# endif
+#endif
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#ifdef HAVE_LONG_DOUBLE
+# define LDOUBLE long double
+#else
+# define LDOUBLE double
+#endif
+
+#ifdef HAVE_LONG_LONG
+# define LLONG long long
+#else
+# define LLONG long
+#endif
+
+/*
+ * 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_LLONG   4
+
+#define char_to_int(p) ((p)- '0')
+#ifndef MAX
+# define MAX(p,q) (((p) >= (q)) ? (p) : (q))
+#endif
+
+#define DOPR_OUTCH(buf, pos, buflen, thechar) \
+       do { \
+               if (pos + 1 >= INT_MAX) { \
+                       errno = ERANGE; \
+                       return -1; \
+               } \
+               if (pos < buflen) \
+                       buf[pos] = thechar; \
+               (pos)++; \
+       } while (0)
+
+static int dopr(char *buffer, size_t maxlen, const char *format, 
+    va_list args_in);
+static int fmtstr(char *buffer, size_t *currlen, size_t maxlen,
+    char *value, int flags, int min, int max);
+static int fmtint(char *buffer, size_t *currlen, size_t maxlen,
+    LLONG value, int base, int min, int max, int flags);
+static int fmtfp(char *buffer, size_t *currlen, size_t maxlen,
+    LDOUBLE fvalue, int min, int max, int flags);
+
+static int
+dopr(char *buffer, size_t maxlen, const char *format, va_list args_in)
+{
+       char ch;
+       LLONG value;
+       LDOUBLE fvalue;
+       char *strvalue;
+       int min;
+       int max;
+       int state;
+       int flags;
+       int cflags;
+       size_t currlen;
+       va_list args;
+
+       VA_COPY(args, args_in);
+       
+       state = DP_S_DEFAULT;
+       currlen = flags = cflags = min = 0;
+       max = -1;
+       ch = *format++;
+       
+       while (state != DP_S_DONE) {
+               if (ch == '\0') 
+                       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') {        /* It's a long long */
+                                       cflags = DP_C_LLONG;
+                                       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_LLONG)
+                                       value = va_arg (args, LLONG);
+                               else
+                                       value = va_arg (args, int);
+                               if (fmtint(buffer, &currlen, maxlen,
+                                   value, 10, min, max, flags) == -1)
+                                       return -1;
+                               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 = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (long)va_arg (args, unsigned LLONG);
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   8, min, max, flags) == -1)
+                                       return -1;
+                               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 = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (LLONG)va_arg (args, unsigned LLONG);
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   10, min, max, flags) == -1)
+                                       return -1;
+                               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 = (long)va_arg (args, unsigned long int);
+                               else if (cflags == DP_C_LLONG)
+                                       value = (LLONG)va_arg (args, unsigned LLONG);
+                               else
+                                       value = (long)va_arg (args, unsigned int);
+                               if (fmtint(buffer, &currlen, maxlen, value,
+                                   16, min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'f':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'E':
+                               flags |= DP_F_UP;
+                       case 'e':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'G':
+                               flags |= DP_F_UP;
+                       case 'g':
+                               if (cflags == DP_C_LDOUBLE)
+                                       fvalue = va_arg (args, LDOUBLE);
+                               else
+                                       fvalue = va_arg (args, double);
+                               if (fmtfp(buffer, &currlen, maxlen, fvalue,
+                                   min, max, flags) == -1)
+                                       return -1;
+                               break;
+                       case 'c':
+                               DOPR_OUTCH(buffer, currlen, maxlen,
+                                   va_arg (args, int));
+                               break;
+                       case 's':
+                               strvalue = va_arg (args, char *);
+                               if (!strvalue) strvalue = "(NULL)";
+                               if (max == -1) {
+                                       max = strlen(strvalue);
+                               }
+                               if (min > 0 && max >= 0 && min > max) max = min;
+                               if (fmtstr(buffer, &currlen, maxlen,
+                                   strvalue, flags, min, max) == -1)
+                                       return -1;
+                               break;
+                       case 'p':
+                               strvalue = va_arg (args, void *);
+                               if (fmtint(buffer, &currlen, maxlen,
+                                   (long) strvalue, 16, min, max, flags) == -1)
+                                       return -1;
+                               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 = (long int)currlen;
+                               } else if (cflags == DP_C_LLONG) {
+                                       LLONG *num;
+                                       num = va_arg (args, LLONG *);
+                                       *num = (LLONG)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 (maxlen != 0) {
+               if (currlen < maxlen - 1) 
+                       buffer[currlen] = '\0';
+               else if (maxlen > 0) 
+                       buffer[maxlen - 1] = '\0';
+       }
+       
+       return currlen < INT_MAX ? (int)currlen : -1;
+}
+
+static int
+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;
+
+#ifdef DEBUG_SNPRINTF
+       printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value);
+#endif
+       if (value == 0) {
+               value = "<NULL>";
+       }
+
+       for (strln = 0; strln < max && 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);
+               *value++;
+               ++cnt;
+       }
+       while ((padlen < 0) && (cnt < max)) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++padlen;
+               ++cnt;
+       }
+       return 0;
+}
+
+/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
+
+static int
+fmtint(char *buffer, size_t *currlen, size_t maxlen,
+                   LLONG value, int base, int min, int max, int flags)
+{
+       int signvalue = 0;
+       unsigned LLONG uvalue;
+       char convert[20];
+       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 */
+
+#ifdef DEBUG_SNPRINTF
+       printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
+              zpadlen, spadlen, min, max, place);
+#endif
+
+       /* 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) {
+               --place;
+               DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]);
+       }
+  
+       /* Left Justified spaces */
+       while (spadlen < 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++spadlen;
+       }
+       return 0;
+}
+
+static LDOUBLE abs_val(LDOUBLE value)
+{
+       LDOUBLE result = value;
+
+       if (value < 0)
+               result = -value;
+       
+       return result;
+}
+
+static LDOUBLE POW10(int val)
+{
+       LDOUBLE result = 1;
+       
+       while (val) {
+               result *= 10;
+               val--;
+       }
+  
+       return result;
+}
+
+static LLONG ROUND(LDOUBLE value)
+{
+       LLONG intpart;
+
+       intpart = (LLONG)value;
+       value = value - intpart;
+       if (value >= 0.5) intpart++;
+       
+       return intpart;
+}
+
+/* a replacement for modf that doesn't need the math library. Should
+   be portable, but slow */
+static double my_modf(double x0, double *iptr)
+{
+       int i;
+       long l;
+       double x = x0;
+       double f = 1.0;
+
+       for (i=0;i<100;i++) {
+               l = (long)x;
+               if (l <= (x+1) && l >= (x-1)) break;
+               x *= 0.1;
+               f *= 10.0;
+       }
+
+       if (i == 100) {
+               /*
+                * yikes! the number is beyond what we can handle.
+                * What do we do?
+                */
+               (*iptr) = 0;
+               return 0;
+       }
+
+       if (i != 0) {
+               double i2;
+               double ret;
+
+               ret = my_modf(x0-l*f, &i2);
+               (*iptr) = l*f + i2;
+               return ret;
+       } 
+
+       (*iptr) = l;
+       return x - (*iptr);
+}
+
+
+static int
+fmtfp (char *buffer, size_t *currlen, size_t maxlen,
+    LDOUBLE fvalue, int min, int max, int flags)
+{
+       int signvalue = 0;
+       double ufvalue;
+       char iconvert[311];
+       char fconvert[311];
+       int iplace = 0;
+       int fplace = 0;
+       int padlen = 0; /* amount to pad */
+       int zpadlen = 0; 
+       int caps = 0;
+       int idx;
+       double intpart;
+       double fracpart;
+       double temp;
+  
+       /* 
+        * 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 = ' ';
+               }
+       }
+
+#if 0
+       if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
+#endif
+
+#if 0
+        if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */
+#endif
+
+       /* 
+        * Sorry, we only support 16 digits past the decimal because of our 
+        * conversion method
+        */
+       if (max > 16)
+               max = 16;
+
+       /* We "cheat" by converting the fractional part to integer by
+        * multiplying by a factor of 10
+        */
+
+       temp = ufvalue;
+       my_modf(temp, &intpart);
+
+       fracpart = ROUND((POW10(max)) * (ufvalue - intpart));
+       
+       if (fracpart >= POW10(max)) {
+               intpart++;
+               fracpart -= POW10(max);
+       }
+
+       /* Convert integer part */
+       do {
+               temp = intpart*0.1;
+               my_modf(temp, &intpart);
+               idx = (int) ((temp -intpart +0.05)* 10.0);
+               /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
+               /* printf ("%llf, %f, %x\n", temp, intpart, idx); */
+               iconvert[iplace++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+       } while (intpart && (iplace < 311));
+       if (iplace == 311) iplace--;
+       iconvert[iplace] = 0;
+
+       /* Convert fractional part */
+       if (fracpart)
+       {
+               do {
+                       temp = fracpart*0.1;
+                       my_modf(temp, &fracpart);
+                       idx = (int) ((temp -fracpart +0.05)* 10.0);
+                       /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
+                       /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
+                       fconvert[fplace++] =
+                       (caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
+               } while(fracpart && (fplace < 311));
+               if (fplace == 311) 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) {
+               --iplace;
+               DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]);
+       }
+
+#ifdef DEBUG_SNPRINTF
+       printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
+#endif
+
+       /*
+        * Decimal point.  This should probably use locale to find the correct
+        * char to print out.
+        */
+       if (max > 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, '.');
+               
+               while (zpadlen > 0) {
+                       DOPR_OUTCH(buffer, *currlen, maxlen, '0');
+                       --zpadlen;
+               }
+
+               while (fplace > 0) {
+                       --fplace;
+                       DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]);
+               }
+       }
+
+       while (padlen < 0) {
+               DOPR_OUTCH(buffer, *currlen, maxlen, ' ');
+               ++padlen;
+       }
+       return 0;
+}
+#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */
+
+#if !defined(HAVE_VSNPRINTF)
+int
+vsnprintf (char *str, size_t count, const char *fmt, va_list args)
+{
+       return dopr(str, count, fmt, args);
+}
+#endif
+
+#if !defined(HAVE_SNPRINTF)
+int
+snprintf(char *str, size_t count, SNPRINTF_CONST char *fmt, ...)
+{
+       size_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(str, count, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+#endif
diff --git a/openbsd-compat/bsd-statvfs.c b/openbsd-compat/bsd-statvfs.c
new file mode 100644 (file)
index 0000000..844d5b4
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Id: bsd-statvfs.c,v 1.1 2008/06/08 17:32:29 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2008 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <errno.h>
+
+#ifndef HAVE_STATVFS
+int statvfs(const char *path, struct statvfs *buf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
+
+#ifndef HAVE_FSTATVFS
+int fstatvfs(int fd, struct statvfs *buf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+#endif
diff --git a/openbsd-compat/bsd-statvfs.h b/openbsd-compat/bsd-statvfs.h
new file mode 100644 (file)
index 0000000..da215ff
--- /dev/null
@@ -0,0 +1,68 @@
+/* $Id: bsd-statvfs.h,v 1.1 2008/06/08 17:32:29 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2008 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#ifndef HAVE_STATVFS
+
+#ifndef HAVE_FSBLKCNT_T
+typedef unsigned long fsblkcnt_t;
+#endif
+#ifndef HAVE_FSFILCNT_T
+typedef unsigned long fsfilcnt_t;
+#endif
+
+#ifndef ST_RDONLY
+#define ST_RDONLY      1
+#endif
+#ifndef ST_NOSUID
+#define ST_NOSUID      2
+#endif
+
+       /* as defined in IEEE Std 1003.1, 2004 Edition */
+struct statvfs {
+       unsigned long f_bsize;  /* File system block size. */
+       unsigned long f_frsize; /* Fundamental file system block size. */
+       fsblkcnt_t f_blocks;    /* Total number of blocks on file system in */
+                               /* units of f_frsize. */
+       fsblkcnt_t    f_bfree;  /* Total number of free blocks. */
+       fsblkcnt_t    f_bavail; /* Number of free blocks available to  */
+                               /* non-privileged process.  */
+       fsfilcnt_t    f_files;  /* Total number of file serial numbers. */
+       fsfilcnt_t    f_ffree;  /* Total number of free file serial numbers. */
+       fsfilcnt_t    f_favail; /* Number of file serial numbers available to */
+                               /* non-privileged process. */
+       unsigned long f_fsid;   /* File system ID. */
+       unsigned long f_flag;   /* BBit mask of f_flag values. */
+       unsigned long f_namemax;/*  Maximum filename length. */
+};
+#endif
+
+#ifndef HAVE_STATVFS
+int statvfs(const char *, struct statvfs *);
+#endif
+
+#ifndef HAVE_FSTATVFS
+int fstatvfs(int, struct statvfs *);
+#endif
diff --git a/openbsd-compat/bsd-waitpid.c b/openbsd-compat/bsd-waitpid.c
new file mode 100644 (file)
index 0000000..40e6ffa
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000 Ben Lindstrom.  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"
+
+#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);
+               }
+               /* wait4() wants pid=0 for indiscriminate wait. */
+               pid = 0;
+       }
+        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/openbsd-compat/bsd-waitpid.h b/openbsd-compat/bsd-waitpid.h
new file mode 100644 (file)
index 0000000..2d853db
--- /dev/null
@@ -0,0 +1,51 @@
+/* $Id: bsd-waitpid.h,v 1.5 2003/08/29 16:59:52 mouring Exp $ */
+
+/*
+ * Copyright (c) 2000 Ben Lindstrom.  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 _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, int *, int);
+
+#endif /* !HAVE_WAITPID */
+#endif /* _BSD_WAITPID_H */
diff --git a/openbsd-compat/charclass.h b/openbsd-compat/charclass.h
new file mode 100644 (file)
index 0000000..91f5174
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * $OpenBSD: charclass.h,v 1.1 2008/10/01 23:04:13 millert Exp $
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/charclass.h */
+
+/*
+ * POSIX character class support for fnmatch() and glob().
+ */
+static struct cclass {
+       const char *name;
+       int (*isctype)(int);
+} cclasses[] = {
+       { "alnum",      isalnum },
+       { "alpha",      isalpha },
+       { "blank",      isblank },
+       { "cntrl",      iscntrl },
+       { "digit",      isdigit },
+       { "graph",      isgraph },
+       { "lower",      islower },
+       { "print",      isprint },
+       { "punct",      ispunct },
+       { "space",      isspace },
+       { "upper",      isupper },
+       { "xdigit",     isxdigit },
+       { NULL,         NULL }
+};
+
+#define NCCLASSES      (sizeof(cclasses) / sizeof(cclasses[0]) - 1)
diff --git a/openbsd-compat/daemon.c b/openbsd-compat/daemon.c
new file mode 100644 (file)
index 0000000..3efe14c
--- /dev/null
@@ -0,0 +1,82 @@
+/*     $OpenBSD: daemon.c,v 1.6 2005/08/08 08:05:33 espie 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */
+
+#include "includes.h"
+
+#ifndef HAVE_DAEMON
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+int
+daemon(int nochdir, int noclose)
+{
+       int fd;
+
+       switch (fork()) {
+       case -1:
+               return (-1);
+       case 0:
+               break;
+       default:
+               _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/openbsd-compat/dirname.c b/openbsd-compat/dirname.c
new file mode 100644 (file)
index 0000000..30fcb49
--- /dev/null
@@ -0,0 +1,72 @@
+/*     $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $      */
+
+/*
+ * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/dirname.c */
+
+#include "includes.h"
+#ifndef HAVE_DIRNAME
+
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+
+char *
+dirname(const char *path)
+{
+       static char dname[MAXPATHLEN];
+       size_t len;
+       const char *endp;
+
+       /* Empty or NULL string gets treated as "." */
+       if (path == NULL || *path == '\0') {
+               dname[0] = '.';
+               dname[1] = '\0';
+               return (dname);
+       }
+
+       /* Strip any 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) {
+               dname[0] = *endp == '/' ? '/' : '.';
+               dname[1] = '\0';
+               return (dname);
+       } else {
+               /* Move forward past the separating slashes */
+               do {
+                       endp--;
+               } while (endp > path && *endp == '/');
+       }
+
+       len = endp - path + 1;
+       if (len >= sizeof(dname)) {
+               errno = ENAMETOOLONG;
+               return (NULL);
+       }
+       memcpy(dname, path, len);
+       dname[len] = '\0';
+       return (dname);
+}
+#endif
diff --git a/openbsd-compat/fake-rfc2553.c b/openbsd-compat/fake-rfc2553.c
new file mode 100644 (file)
index 0000000..096d9e0
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
+ * Copyright (C) 1999 WIDE Project.  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. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Pseudo-implementation of RFC2553 name / address resolution functions
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For example, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#include "includes.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.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)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+       struct hostent *hp;
+       char tmpserv[16];
+
+       if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET)
+               return (EAI_FAMILY);
+       if (serv != NULL) {
+               snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
+               if (strlcpy(serv, tmpserv, servlen) >= servlen)
+                       return (EAI_MEMORY);
+       }
+
+       if (host != NULL) {
+               if (flags & NI_NUMERICHOST) {
+                       if (strlcpy(host, inet_ntoa(sin->sin_addr),
+                           hostlen) >= hostlen)
+                               return (EAI_MEMORY);
+                       else
+                               return (0);
+               } else {
+                       hp = gethostbyaddr((char *)&sin->sin_addr, 
+                           sizeof(struct in_addr), AF_INET);
+                       if (hp == NULL)
+                               return (EAI_NODATA);
+                       
+                       if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+                               return (EAI_MEMORY);
+                       else
+                               return (0);
+               }
+       }
+       return (0);
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+#ifndef HAVE_GAI_STRERROR
+#ifdef HAVE_CONST_GAI_STRERROR_PROTO
+const char *
+#else
+char *
+#endif
+gai_strerror(int err)
+{
+       switch (err) {
+       case EAI_NODATA:
+               return ("no address associated with name");
+       case EAI_MEMORY:
+               return ("memory allocation failure.");
+       case EAI_NONAME:
+               return ("nodename nor servname provided, or not known");
+       case EAI_FAMILY:
+               return ("ai_family not supported");
+       default:
+               return ("unknown/invalid error.");
+       }
+}    
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+       struct addrinfo *next;
+
+       for(; ai != NULL;) {
+               next = ai->ai_next;
+               free(ai);
+               ai = next;
+       }
+}
+#endif /* !HAVE_FREEADDRINFO */
+
+#ifndef HAVE_GETADDRINFO
+static struct
+addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
+{
+       struct addrinfo *ai;
+
+       ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
+       if (ai == NULL)
+               return (NULL);
+       
+       memset(ai, '\0', sizeof(*ai) + 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;
+       
+       /* XXX: the following is not generally correct, but does what we want */
+       if (hints->ai_socktype)
+               ai->ai_socktype = hints->ai_socktype;
+       else
+               ai->ai_socktype = SOCK_STREAM;
+
+       if (hints->ai_protocol)
+               ai->ai_protocol = hints->ai_protocol;
+
+       return (ai);
+}
+
+int
+getaddrinfo(const char *hostname, const char *servname, 
+    const struct addrinfo *hints, struct addrinfo **res)
+{
+       struct hostent *hp;
+       struct servent *sp;
+       struct in_addr in;
+       int i;
+       long int port;
+       u_long addr;
+
+       port = 0;
+       if (hints && hints->ai_family != AF_UNSPEC &&
+           hints->ai_family != AF_INET)
+               return (EAI_FAMILY);
+       if (servname != NULL) {
+               char *cp;
+
+               port = strtol(servname, &cp, 10);
+               if (port > 0 && port <= 65535 && *cp == '\0')
+                       port = htons(port);
+               else if ((sp = getservbyname(servname, NULL)) != NULL)
+                       port = sp->s_port;
+               else
+                       port = 0;
+       }
+
+       if (hints && hints->ai_flags & AI_PASSIVE) {
+               addr = htonl(0x00000000);
+               if (hostname && inet_aton(hostname, &in) != 0)
+                       addr = in.s_addr;
+               *res = malloc_ai(port, addr, hints);
+               if (*res == NULL) 
+                       return (EAI_MEMORY);
+               return (0);
+       }
+               
+       if (!hostname) {
+               *res = malloc_ai(port, htonl(0x7f000001), hints);
+               if (*res == NULL) 
+                       return (EAI_MEMORY);
+               return (0);
+       }
+       
+       if (inet_aton(hostname, &in)) {
+               *res = malloc_ai(port, in.s_addr, hints);
+               if (*res == NULL) 
+                       return (EAI_MEMORY);
+               return (0);
+       }
+       
+       /* Don't try DNS if AI_NUMERICHOST is set */
+       if (hints && hints->ai_flags & AI_NUMERICHOST)
+               return (EAI_NONAME);
+       
+       hp = gethostbyname(hostname);
+       if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+               struct addrinfo *cur, *prev;
+
+               cur = prev = *res = NULL;
+               for (i = 0; hp->h_addr_list[i]; i++) {
+                       struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
+
+                       cur = malloc_ai(port, in->s_addr, hints);
+                       if (cur == NULL) {
+                               if (*res != NULL)
+                                       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/openbsd-compat/fake-rfc2553.h b/openbsd-compat/fake-rfc2553.h
new file mode 100644 (file)
index 0000000..3e9090f
--- /dev/null
@@ -0,0 +1,175 @@
+/* $Id: fake-rfc2553.h,v 1.16 2008/07/14 11:37:37 djm Exp $ */
+
+/*
+ * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
+ * Copyright (C) 1999 WIDE Project.  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. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Pseudo-implementation of RFC2553 name / address resolution functions
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For example, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#ifndef _FAKE_RFC2553_H
+#define _FAKE_RFC2553_H
+
+#include "includes.h"
+#include <sys/types.h>
+#if defined(HAVE_NETDB_H)
+# include <netdb.h>
+#endif
+
+/*
+ * First, socket and INET6 related definitions 
+ */
+#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;
+       u_int32_t       sin6_scope_id;
+};
+#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+/*
+ * Next, RFC2553 name / address resolution API
+ */
+
+#ifndef NI_NUMERICHOST
+# define NI_NUMERICHOST    (1)
+#endif
+#ifndef NI_NAMEREQD
+# define NI_NAMEREQD       (1<<1)
+#endif
+#ifndef NI_NUMERICSERV
+# define NI_NUMERICSERV    (1<<2)
+#endif
+
+#ifndef AI_PASSIVE
+# define AI_PASSIVE            (1)
+#endif
+#ifndef AI_CANONNAME
+# define AI_CANONNAME          (1<<1)
+#endif
+#ifndef AI_NUMERICHOST
+# define AI_NUMERICHOST                (1<<2)
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif /* !NI_MAXSERV */
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif /* !NI_MAXHOST */
+
+#ifndef EAI_NODATA
+# define EAI_NODATA    (INT_MAX - 1)
+#endif
+#ifndef EAI_MEMORY
+# define EAI_MEMORY    (INT_MAX - 2)
+#endif
+#ifndef EAI_NONAME
+# define EAI_NONAME    (INT_MAX - 3)
+#endif
+#ifndef EAI_SYSTEM
+# define EAI_SYSTEM    (INT_MAX - 4)
+#endif
+#ifndef EAI_FAMILY
+# define EAI_FAMILY    (INT_MAX - 5)
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+       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
+#ifdef getaddrinfo
+# undef getaddrinfo
+#endif
+#define getaddrinfo(a,b,c,d)   (ssh_getaddrinfo(a,b,c,d))
+int getaddrinfo(const char *, const char *, 
+    const struct addrinfo *, struct addrinfo **);
+#endif /* !HAVE_GETADDRINFO */
+
+#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
+#define gai_strerror(a)                (_ssh_compat_gai_strerror(a))
+char *gai_strerror(int);
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+#define freeaddrinfo(a)                (ssh_freeaddrinfo(a))
+void freeaddrinfo(struct addrinfo *);
+#endif /* !HAVE_FREEADDRINFO */
+
+#ifndef HAVE_GETNAMEINFO
+#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g))
+int getnameinfo(const struct sockaddr *, size_t, char *, size_t, 
+    char *, size_t, int);
+#endif /* !HAVE_GETNAMEINFO */
+
+#endif /* !_FAKE_RFC2553_H */
+
diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c
new file mode 100644 (file)
index 0000000..edd682a
--- /dev/null
@@ -0,0 +1,274 @@
+/*     $OpenBSD: fmt_scaled.c,v 1.9 2007/03/20 03:42:52 tedu Exp $     */
+
+/*
+ * Copyright (c) 2001, 2002, 2003 Ian F. Darwin.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libutil/fmt_scaled.c */
+
+/*
+ * fmt_scaled: Format numbers scaled for human comprehension
+ * scan_scaled: Scan numbers in this format.
+ *
+ * "Human-readable" output uses 4 digits max, and puts a unit suffix at
+ * the end.  Makes output compact and easy-to-read esp. on huge disks.
+ * Formatting code was originally in OpenBSD "df", converted to library routine.
+ * Scanning code written for OpenBSD libutil.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_FMT_SCALED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+typedef enum {
+       NONE = 0, KILO = 1, MEGA = 2, GIGA = 3, TERA = 4, PETA = 5, EXA = 6
+} unit_type;
+
+/* These three arrays MUST be in sync!  XXX make a struct */
+static unit_type units[] = { NONE, KILO, MEGA, GIGA, TERA, PETA, EXA };
+static char scale_chars[] = "BKMGTPE";
+static long long scale_factors[] = {
+       1LL,
+       1024LL,
+       1024LL*1024,
+       1024LL*1024*1024,
+       1024LL*1024*1024*1024,
+       1024LL*1024*1024*1024*1024,
+       1024LL*1024*1024*1024*1024*1024,
+};
+#define        SCALE_LENGTH (sizeof(units)/sizeof(units[0]))
+
+#define MAX_DIGITS (SCALE_LENGTH * 3)  /* XXX strlen(sprintf("%lld", -1)? */
+
+/** Convert the given input string "scaled" into numeric in "result".
+ * Return 0 on success, -1 and errno set on error.
+ */
+int
+scan_scaled(char *scaled, long long *result)
+{
+       char *p = scaled;
+       int sign = 0;
+       unsigned int i, ndigits = 0, fract_digits = 0;
+       long long scale_fact = 1, whole = 0, fpart = 0;
+
+       /* Skip leading whitespace */
+       while (isascii(*p) && isspace(*p))
+               ++p;
+
+       /* Then at most one leading + or - */
+       while (*p == '-' || *p == '+') {
+               if (*p == '-') {
+                       if (sign) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       sign = -1;
+                       ++p;
+               } else if (*p == '+') {
+                       if (sign) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       sign = +1;
+                       ++p;
+               }
+       }
+
+       /* Main loop: Scan digits, find decimal point, if present.
+        * We don't allow exponentials, so no scientific notation
+        * (but note that E for Exa might look like e to some!).
+        * Advance 'p' to end, to get scale factor.
+        */
+       for (; isascii(*p) && (isdigit(*p) || *p=='.'); ++p) {
+               if (*p == '.') {
+                       if (fract_digits > 0) { /* oops, more than one '.' */
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       fract_digits = 1;
+                       continue;
+               }
+
+               i = (*p) - '0';                 /* whew! finally a digit we can use */
+               if (fract_digits > 0) {
+                       if (fract_digits >= MAX_DIGITS-1)
+                               /* ignore extra fractional digits */
+                               continue;
+                       fract_digits++;         /* for later scaling */
+                       fpart *= 10;
+                       fpart += i;
+               } else {                                /* normal digit */
+                       if (++ndigits >= MAX_DIGITS) {
+                               errno = ERANGE;
+                               return -1;
+                       }
+                       whole *= 10;
+                       whole += i;
+               }
+       }
+
+       if (sign) {
+               whole *= sign;
+               fpart *= sign;
+       }
+
+       /* If no scale factor given, we're done. fraction is discarded. */
+       if (!*p) {
+               *result = whole;
+               return 0;
+       }
+
+       /* Validate scale factor, and scale whole and fraction by it. */
+       for (i = 0; i < SCALE_LENGTH; i++) {
+
+               /** Are we there yet? */
+               if (*p == scale_chars[i] ||
+                       *p == tolower(scale_chars[i])) {
+
+                       /* If it ends with alphanumerics after the scale char, bad. */
+                       if (isalnum(*(p+1))) {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       scale_fact = scale_factors[i];
+
+                       /* scale whole part */
+                       whole *= scale_fact;
+
+                       /* truncate fpart so it does't overflow.
+                        * then scale fractional part.
+                        */
+                       while (fpart >= LLONG_MAX / scale_fact) {
+                               fpart /= 10;
+                               fract_digits--;
+                       }
+                       fpart *= scale_fact;
+                       if (fract_digits > 0) {
+                               for (i = 0; i < fract_digits -1; i++)
+                                       fpart /= 10;
+                       }
+                       whole += fpart;
+                       *result = whole;
+                       return 0;
+               }
+       }
+       errno = ERANGE;
+       return -1;
+}
+
+/* Format the given "number" into human-readable form in "result".
+ * Result must point to an allocated buffer of length FMT_SCALED_STRSIZE.
+ * Return 0 on success, -1 and errno set if error.
+ */
+int
+fmt_scaled(long long number, char *result)
+{
+       long long abval, fract = 0;
+       unsigned int i;
+       unit_type unit = NONE;
+
+       abval = (number < 0LL) ? -number : number;      /* no long long_abs yet */
+
+       /* Not every negative long long has a positive representation.
+        * Also check for numbers that are just too darned big to format
+        */
+       if (abval < 0 || abval / 1024 >= scale_factors[SCALE_LENGTH-1]) {
+               errno = ERANGE;
+               return -1;
+       }
+
+       /* scale whole part; get unscaled fraction */
+       for (i = 0; i < SCALE_LENGTH; i++) {
+               if (abval/1024 < scale_factors[i]) {
+                       unit = units[i];
+                       fract = (i == 0) ? 0 : abval % scale_factors[i];
+                       number /= scale_factors[i];
+                       if (i > 0)
+                               fract /= scale_factors[i - 1];
+                       break;
+               }
+       }
+
+       fract = (10 * fract + 512) / 1024;
+       /* if the result would be >= 10, round main number */
+       if (fract == 10) {
+               if (number >= 0)
+                       number++;
+               else
+                       number--;
+               fract = 0;
+       }
+
+       if (number == 0)
+               strlcpy(result, "0B", FMT_SCALED_STRSIZE);
+       else if (unit == NONE || number >= 100 || number <= -100) {
+               if (fract >= 5) {
+                       if (number >= 0)
+                               number++;
+                       else
+                               number--;
+               }
+               (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld%c",
+                       number, scale_chars[unit]);
+       } else
+               (void)snprintf(result, FMT_SCALED_STRSIZE, "%lld.%1lld%c",
+                       number, fract, scale_chars[unit]);
+
+       return 0;
+}
+
+#ifdef MAIN
+/*
+ * This is the original version of the program in the man page.
+ * Copy-and-paste whatever you need from it.
+ */
+int
+main(int argc, char **argv)
+{
+       char *cinput = "1.5K", buf[FMT_SCALED_STRSIZE];
+       long long ninput = 10483892, result;
+
+       if (scan_scaled(cinput, &result) == 0)
+               printf("\"%s\" -> %lld\n", cinput, result);
+       else
+               perror(cinput);
+
+       if (fmt_scaled(ninput, buf) == 0)
+               printf("%lld -> \"%s\"\n", ninput, buf);
+       else
+               fprintf(stderr, "%lld invalid (%s)\n", ninput, strerror(errno));
+
+       return 0;
+}
+#endif
+
+#endif /* HAVE_FMT_SCALED */
diff --git a/openbsd-compat/getcwd.c b/openbsd-compat/getcwd.c
new file mode 100644 (file)
index 0000000..711cb9c
--- /dev/null
@@ -0,0 +1,240 @@
+/*     $OpenBSD: getcwd.c,v 1.14 2005/08/08 08:05:34 espie Exp $ */
+/*
+ * 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.
+ * 3. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/getcwd.c */
+
+#include "includes.h"
+
+#if !defined(HAVE_GETCWD)
+
+#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)
+{
+       struct dirent *dp;
+       DIR *dir = NULL;
+       dev_t dev;
+       ino_t ino;
+       int first;
+       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 = MAXPATHLEN)) == NULL)
+                       return (NULL);
+               ept = pt + ptsize;
+       }
+       bpt = ept - 1;
+       *bpt = '\0';
+
+       /*
+        * Allocate bytes 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 = MAXPATHLEN)) == NULL)
+               goto err;
+       eup = up + upsize;
+       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 NUL.
+                */
+               if (bup + 3  + MAXNAMLEN + 1 >= eup) {
+                       char *nup;
+
+                       if ((nup = realloc(up, upsize *= 2)) == NULL)
+                               goto err;
+                       bup = nup + (bup - up);
+                       up = nup;
+                       eup = up + upsize;
+               }
+               *bup++ = '.';
+               *bup++ = '.';
+               *bup = '\0';
+
+               /* Open and stat parent directory. */
+               if (!(dir = opendir(up)) || fstat(dirfd(dir), &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;
+                               memcpy(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;
+                       char *npt;
+
+                       if (!ptsize) {
+                               errno = ERANGE;
+                               goto err;
+                       }
+                       len = ept - bpt;
+                       if ((npt = realloc(pt, ptsize *= 2)) == NULL)
+                               goto err;
+                       bpt = npt + (bpt - pt);
+                       pt = npt;
+                       ept = pt + ptsize;
+                       memmove(ept - len, bpt, len);
+                       bpt = ept - len;
+               }
+               if (!first)
+                       *--bpt = '/';
+               bpt -= dp->d_namlen;
+               memcpy(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:
+       save_errno = errno;
+
+       if (ptsize)
+               free(pt);
+       free(up);
+       if (dir)
+               (void)closedir(dir);
+
+       errno = save_errno;
+
+       return (NULL);
+}
+
+#endif /* !defined(HAVE_GETCWD) */
diff --git a/openbsd-compat/getgrouplist.c b/openbsd-compat/getgrouplist.c
new file mode 100644 (file)
index 0000000..a57d7d3
--- /dev/null
@@ -0,0 +1,95 @@
+/*     $OpenBSD: getgrouplist.c,v 1.12 2005/08/08 08:05:34 espie 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/getgrouplist.c */
+
+#include "includes.h"
+
+#ifndef HAVE_GETGROUPLIST
+
+/*
+ * get credential
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <grp.h>
+
+int
+getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
+{
+       struct group *grp;
+       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/openbsd-compat/getopt.c b/openbsd-compat/getopt.c
new file mode 100644 (file)
index 0000000..5450e43
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
+
+#include "includes.h"
+#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int    BSDopterr = 1,          /* if error message should be printed */
+       BSDoptind = 1,          /* index into parent argv vector */
+       BSDoptopt,              /* character checked for validity */
+       BSDoptreset;            /* reset getopt */
+char   *BSDoptarg;             /* 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 (ostr == NULL)
+               return (-1);
+
+       if (BSDoptreset || !*place) {           /* update scanning pointer */
+               BSDoptreset = 0;
+               if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
+                       place = EMSG;
+                       return (-1);
+               }
+               if (place[1] && *++place == '-') {      /* found "--" */
+                       ++BSDoptind;
+                       place = EMSG;
+                       return (-1);
+               }
+       }                                       /* option letter okay? */
+       if ((BSDoptopt = (int)*place++) == (int)':' ||
+           !(oli = strchr(ostr, BSDoptopt))) {
+               /*
+                * if the user didn't specify '-' as an option,
+                * assume it means -1.
+                */
+               if (BSDoptopt == (int)'-')
+                       return (-1);
+               if (!*place)
+                       ++BSDoptind;
+               if (BSDopterr && *ostr != ':')
+                       (void)fprintf(stderr,
+                           "%s: illegal option -- %c\n", __progname, BSDoptopt);
+               return (BADCH);
+       }
+       if (*++oli != ':') {                    /* don't need argument */
+               BSDoptarg = NULL;
+               if (!*place)
+                       ++BSDoptind;
+       }
+       else {                                  /* need an argument */
+               if (*place)                     /* no white space */
+                       BSDoptarg = place;
+               else if (nargc <= ++BSDoptind) {        /* no arg */
+                       place = EMSG;
+                       if (*ostr == ':')
+                               return (BADARG);
+                       if (BSDopterr)
+                               (void)fprintf(stderr,
+                                   "%s: option requires an argument -- %c\n",
+                                   __progname, BSDoptopt);
+                       return (BADCH);
+               }
+               else                            /* white space */
+                       BSDoptarg = nargv[BSDoptind];
+               place = EMSG;
+               ++BSDoptind;
+       }
+       return (BSDoptopt);                     /* dump back option letter */
+}
+
+#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */
diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c
new file mode 100644 (file)
index 0000000..9887667
--- /dev/null
@@ -0,0 +1,610 @@
+/* $OpenBSD: getrrsetbyname.c,v 1.11 2007/10/11 18:36:41 jakob Exp $ */
+
+/*
+ * Copyright (c) 2001 Jakob Schlyter. 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.
+ */
+
+/*
+ * Portions Copyright (c) 1999-2001 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */
+
+#include "includes.h"
+
+#ifndef HAVE_GETRRSETBYNAME
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "getrrsetbyname.h"
+
+#if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO
+extern int h_errno;
+#endif
+
+/* We don't need multithread support here */
+#ifdef _THREAD_PRIVATE
+# undef _THREAD_PRIVATE
+#endif
+#define _THREAD_PRIVATE(a,b,c) (c)
+
+#ifndef HAVE__RES_EXTERN
+struct __res_state _res;
+#endif
+
+/* Necessary functions and macros */
+
+/*
+ * Inline versions of get/put short/long.  Pointer is advanced.
+ *
+ * These macros demonstrate the property of C whereby it can be
+ * portable or it can be elegant but rarely both.
+ */
+
+#ifndef INT32SZ
+# define INT32SZ       4
+#endif
+#ifndef INT16SZ
+# define INT16SZ       2
+#endif
+
+#ifndef GETSHORT
+#define GETSHORT(s, cp) { \
+       register u_char *t_cp = (u_char *)(cp); \
+       (s) = ((u_int16_t)t_cp[0] << 8) \
+           | ((u_int16_t)t_cp[1]) \
+           ; \
+       (cp) += INT16SZ; \
+}
+#endif
+
+#ifndef GETLONG
+#define GETLONG(l, cp) { \
+       register u_char *t_cp = (u_char *)(cp); \
+       (l) = ((u_int32_t)t_cp[0] << 24) \
+           | ((u_int32_t)t_cp[1] << 16) \
+           | ((u_int32_t)t_cp[2] << 8) \
+           | ((u_int32_t)t_cp[3]) \
+           ; \
+       (cp) += INT32SZ; \
+}
+#endif
+
+/*
+ * Routines to insert/extract short/long's.
+ */
+
+#ifndef HAVE__GETSHORT
+static u_int16_t
+_getshort(msgp)
+       register const u_char *msgp;
+{
+       register u_int16_t u;
+
+       GETSHORT(u, msgp);
+       return (u);
+}
+#elif defined(HAVE_DECL__GETSHORT) && (HAVE_DECL__GETSHORT == 0)
+u_int16_t _getshort(register const u_char *);
+#endif
+
+#ifndef HAVE__GETLONG
+static u_int32_t
+_getlong(msgp)
+       register const u_char *msgp;
+{
+       register u_int32_t u;
+
+       GETLONG(u, msgp);
+       return (u);
+}
+#elif defined(HAVE_DECL__GETLONG) && (HAVE_DECL__GETLONG == 0)
+u_int32_t _getlong(register const u_char *);
+#endif
+
+/* ************** */
+
+#define ANSWER_BUFFER_SIZE 0xffff
+
+struct dns_query {
+       char                    *name;
+       u_int16_t               type;
+       u_int16_t               class;
+       struct dns_query        *next;
+};
+
+struct dns_rr {
+       char                    *name;
+       u_int16_t               type;
+       u_int16_t               class;
+       u_int16_t               ttl;
+       u_int16_t               size;
+       void                    *rdata;
+       struct dns_rr           *next;
+};
+
+struct dns_response {
+       HEADER                  header;
+       struct dns_query        *query;
+       struct dns_rr           *answer;
+       struct dns_rr           *authority;
+       struct dns_rr           *additional;
+};
+
+static struct dns_response *parse_dns_response(const u_char *, int);
+static struct dns_query *parse_dns_qsection(const u_char *, int,
+    const u_char **, int);
+static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
+    int);
+
+static void free_dns_query(struct dns_query *);
+static void free_dns_rr(struct dns_rr *);
+static void free_dns_response(struct dns_response *);
+
+static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
+
+int
+getrrsetbyname(const char *hostname, unsigned int rdclass,
+    unsigned int rdtype, unsigned int flags,
+    struct rrsetinfo **res)
+{
+       struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
+       int result;
+       struct rrsetinfo *rrset = NULL;
+       struct dns_response *response = NULL;
+       struct dns_rr *rr;
+       struct rdatainfo *rdata;
+       int length;
+       unsigned int index_ans, index_sig;
+       u_char answer[ANSWER_BUFFER_SIZE];
+
+       /* check for invalid class and type */
+       if (rdclass > 0xffff || rdtype > 0xffff) {
+               result = ERRSET_INVAL;
+               goto fail;
+       }
+
+       /* don't allow queries of class or type ANY */
+       if (rdclass == 0xff || rdtype == 0xff) {
+               result = ERRSET_INVAL;
+               goto fail;
+       }
+
+       /* don't allow flags yet, unimplemented */
+       if (flags) {
+               result = ERRSET_INVAL;
+               goto fail;
+       }
+
+       /* initialize resolver */
+       if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
+               result = ERRSET_FAIL;
+               goto fail;
+       }
+
+#ifdef DEBUG
+       _resp->options |= RES_DEBUG;
+#endif /* DEBUG */
+
+#ifdef RES_USE_DNSSEC
+       /* turn on DNSSEC if EDNS0 is configured */
+       if (_resp->options & RES_USE_EDNS0)
+               _resp->options |= RES_USE_DNSSEC;
+#endif /* RES_USE_DNSEC */
+
+       /* make query */
+       length = res_query(hostname, (signed int) rdclass, (signed int) rdtype,
+           answer, sizeof(answer));
+       if (length < 0) {
+               switch(h_errno) {
+               case HOST_NOT_FOUND:
+                       result = ERRSET_NONAME;
+                       goto fail;
+               case NO_DATA:
+                       result = ERRSET_NODATA;
+                       goto fail;
+               default:
+                       result = ERRSET_FAIL;
+                       goto fail;
+               }
+       }
+
+       /* parse result */
+       response = parse_dns_response(answer, length);
+       if (response == NULL) {
+               result = ERRSET_FAIL;
+               goto fail;
+       }
+
+       if (response->header.qdcount != 1) {
+               result = ERRSET_FAIL;
+               goto fail;
+       }
+
+       /* initialize rrset */
+       rrset = calloc(1, sizeof(struct rrsetinfo));
+       if (rrset == NULL) {
+               result = ERRSET_NOMEMORY;
+               goto fail;
+       }
+       rrset->rri_rdclass = response->query->class;
+       rrset->rri_rdtype = response->query->type;
+       rrset->rri_ttl = response->answer->ttl;
+       rrset->rri_nrdatas = response->header.ancount;
+
+#ifdef HAVE_HEADER_AD
+       /* check for authenticated data */
+       if (response->header.ad == 1)
+               rrset->rri_flags |= RRSET_VALIDATED;
+#endif
+
+       /* copy name from answer section */
+       rrset->rri_name = strdup(response->answer->name);
+       if (rrset->rri_name == NULL) {
+               result = ERRSET_NOMEMORY;
+               goto fail;
+       }
+
+       /* count answers */
+       rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
+           rrset->rri_rdtype);
+       rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
+           T_RRSIG);
+
+       /* allocate memory for answers */
+       rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
+           sizeof(struct rdatainfo));
+       if (rrset->rri_rdatas == NULL) {
+               result = ERRSET_NOMEMORY;
+               goto fail;
+       }
+
+       /* allocate memory for signatures */
+       if (rrset->rri_nsigs > 0) {
+               rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
+               if (rrset->rri_sigs == NULL) {
+                       result = ERRSET_NOMEMORY;
+                       goto fail;
+               }
+       }
+
+       /* copy answers & signatures */
+       for (rr = response->answer, index_ans = 0, index_sig = 0;
+           rr; rr = rr->next) {
+
+               rdata = NULL;
+
+               if (rr->class == rrset->rri_rdclass &&
+                   rr->type  == rrset->rri_rdtype)
+                       rdata = &rrset->rri_rdatas[index_ans++];
+
+               if (rr->class == rrset->rri_rdclass &&
+                   rr->type  == T_RRSIG)
+                       rdata = &rrset->rri_sigs[index_sig++];
+
+               if (rdata) {
+                       rdata->rdi_length = rr->size;
+                       rdata->rdi_data   = malloc(rr->size);
+
+                       if (rdata->rdi_data == NULL) {
+                               result = ERRSET_NOMEMORY;
+                               goto fail;
+                       }
+                       memcpy(rdata->rdi_data, rr->rdata, rr->size);
+               }
+       }
+       free_dns_response(response);
+
+       *res = rrset;
+       return (ERRSET_SUCCESS);
+
+fail:
+       if (rrset != NULL)
+               freerrset(rrset);
+       if (response != NULL)
+               free_dns_response(response);
+       return (result);
+}
+
+void
+freerrset(struct rrsetinfo *rrset)
+{
+       u_int16_t i;
+
+       if (rrset == NULL)
+               return;
+
+       if (rrset->rri_rdatas) {
+               for (i = 0; i < rrset->rri_nrdatas; i++) {
+                       if (rrset->rri_rdatas[i].rdi_data == NULL)
+                               break;
+                       free(rrset->rri_rdatas[i].rdi_data);
+               }
+               free(rrset->rri_rdatas);
+       }
+
+       if (rrset->rri_sigs) {
+               for (i = 0; i < rrset->rri_nsigs; i++) {
+                       if (rrset->rri_sigs[i].rdi_data == NULL)
+                               break;
+                       free(rrset->rri_sigs[i].rdi_data);
+               }
+               free(rrset->rri_sigs);
+       }
+
+       if (rrset->rri_name)
+               free(rrset->rri_name);
+       free(rrset);
+}
+
+/*
+ * DNS response parsing routines
+ */
+static struct dns_response *
+parse_dns_response(const u_char *answer, int size)
+{
+       struct dns_response *resp;
+       const u_char *cp;
+
+       /* allocate memory for the response */
+       resp = calloc(1, sizeof(*resp));
+       if (resp == NULL)
+               return (NULL);
+
+       /* initialize current pointer */
+       cp = answer;
+
+       /* copy header */
+       memcpy(&resp->header, cp, HFIXEDSZ);
+       cp += HFIXEDSZ;
+
+       /* fix header byte order */
+       resp->header.qdcount = ntohs(resp->header.qdcount);
+       resp->header.ancount = ntohs(resp->header.ancount);
+       resp->header.nscount = ntohs(resp->header.nscount);
+       resp->header.arcount = ntohs(resp->header.arcount);
+
+       /* there must be at least one query */
+       if (resp->header.qdcount < 1) {
+               free_dns_response(resp);
+               return (NULL);
+       }
+
+       /* parse query section */
+       resp->query = parse_dns_qsection(answer, size, &cp,
+           resp->header.qdcount);
+       if (resp->header.qdcount && resp->query == NULL) {
+               free_dns_response(resp);
+               return (NULL);
+       }
+
+       /* parse answer section */
+       resp->answer = parse_dns_rrsection(answer, size, &cp,
+           resp->header.ancount);
+       if (resp->header.ancount && resp->answer == NULL) {
+               free_dns_response(resp);
+               return (NULL);
+       }
+
+       /* parse authority section */
+       resp->authority = parse_dns_rrsection(answer, size, &cp,
+           resp->header.nscount);
+       if (resp->header.nscount && resp->authority == NULL) {
+               free_dns_response(resp);
+               return (NULL);
+       }
+
+       /* parse additional section */
+       resp->additional = parse_dns_rrsection(answer, size, &cp,
+           resp->header.arcount);
+       if (resp->header.arcount && resp->additional == NULL) {
+               free_dns_response(resp);
+               return (NULL);
+       }
+
+       return (resp);
+}
+
+static struct dns_query *
+parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
+{
+       struct dns_query *head, *curr, *prev;
+       int i, length;
+       char name[MAXDNAME];
+
+       for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
+
+               /* allocate and initialize struct */
+               curr = calloc(1, sizeof(struct dns_query));
+               if (curr == NULL) {
+                       free_dns_query(head);
+                       return (NULL);
+               }
+               if (head == NULL)
+                       head = curr;
+               if (prev != NULL)
+                       prev->next = curr;
+
+               /* name */
+               length = dn_expand(answer, answer + size, *cp, name,
+                   sizeof(name));
+               if (length < 0) {
+                       free_dns_query(head);
+                       return (NULL);
+               }
+               curr->name = strdup(name);
+               if (curr->name == NULL) {
+                       free_dns_query(head);
+                       return (NULL);
+               }
+               *cp += length;
+
+               /* type */
+               curr->type = _getshort(*cp);
+               *cp += INT16SZ;
+
+               /* class */
+               curr->class = _getshort(*cp);
+               *cp += INT16SZ;
+       }
+
+       return (head);
+}
+
+static struct dns_rr *
+parse_dns_rrsection(const u_char *answer, int size, const u_char **cp,
+    int count)
+{
+       struct dns_rr *head, *curr, *prev;
+       int i, length;
+       char name[MAXDNAME];
+
+       for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
+
+               /* allocate and initialize struct */
+               curr = calloc(1, sizeof(struct dns_rr));
+               if (curr == NULL) {
+                       free_dns_rr(head);
+                       return (NULL);
+               }
+               if (head == NULL)
+                       head = curr;
+               if (prev != NULL)
+                       prev->next = curr;
+
+               /* name */
+               length = dn_expand(answer, answer + size, *cp, name,
+                   sizeof(name));
+               if (length < 0) {
+                       free_dns_rr(head);
+                       return (NULL);
+               }
+               curr->name = strdup(name);
+               if (curr->name == NULL) {
+                       free_dns_rr(head);
+                       return (NULL);
+               }
+               *cp += length;
+
+               /* type */
+               curr->type = _getshort(*cp);
+               *cp += INT16SZ;
+
+               /* class */
+               curr->class = _getshort(*cp);
+               *cp += INT16SZ;
+
+               /* ttl */
+               curr->ttl = _getlong(*cp);
+               *cp += INT32SZ;
+
+               /* rdata size */
+               curr->size = _getshort(*cp);
+               *cp += INT16SZ;
+
+               /* rdata itself */
+               curr->rdata = malloc(curr->size);
+               if (curr->rdata == NULL) {
+                       free_dns_rr(head);
+                       return (NULL);
+               }
+               memcpy(curr->rdata, *cp, curr->size);
+               *cp += curr->size;
+       }
+
+       return (head);
+}
+
+static void
+free_dns_query(struct dns_query *p)
+{
+       if (p == NULL)
+               return;
+
+       if (p->name)
+               free(p->name);
+       free_dns_query(p->next);
+       free(p);
+}
+
+static void
+free_dns_rr(struct dns_rr *p)
+{
+       if (p == NULL)
+               return;
+
+       if (p->name)
+               free(p->name);
+       if (p->rdata)
+               free(p->rdata);
+       free_dns_rr(p->next);
+       free(p);
+}
+
+static void
+free_dns_response(struct dns_response *p)
+{
+       if (p == NULL)
+               return;
+
+       free_dns_query(p->query);
+       free_dns_rr(p->answer);
+       free_dns_rr(p->authority);
+       free_dns_rr(p->additional);
+       free(p);
+}
+
+static int
+count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
+{
+       int n = 0;
+
+       while(p) {
+               if (p->class == class && p->type == type)
+                       n++;
+               p = p->next;
+       }
+
+       return (n);
+}
+
+#endif /* !defined(HAVE_GETRRSETBYNAME) */
diff --git a/openbsd-compat/getrrsetbyname.h b/openbsd-compat/getrrsetbyname.h
new file mode 100644 (file)
index 0000000..1283f55
--- /dev/null
@@ -0,0 +1,110 @@
+/* OPENBSD BASED ON : include/netdb.h */
+
+/* $OpenBSD: getrrsetbyname.c,v 1.4 2001/08/16 18:16:43 ho Exp $ */
+
+/*
+ * Copyright (c) 2001 Jakob Schlyter. 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.
+ */
+
+/*
+ * Portions Copyright (c) 1999-2001 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.
+ */
+
+#ifndef _GETRRSETBYNAME_H
+#define _GETRRSETBYNAME_H
+
+#include "includes.h"
+
+#ifndef HAVE_GETRRSETBYNAME
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+
+#ifndef HFIXEDSZ
+#define HFIXEDSZ 12
+#endif
+
+#ifndef T_RRSIG
+#define T_RRSIG 46
+#endif
+
+/*
+ * Flags for getrrsetbyname()
+ */
+#ifndef RRSET_VALIDATED
+# define RRSET_VALIDATED       1
+#endif
+
+/*
+ * Return codes for getrrsetbyname()
+ */
+#ifndef ERRSET_SUCCESS
+# define ERRSET_SUCCESS                0
+# define ERRSET_NOMEMORY       1
+# define ERRSET_FAIL           2
+# define ERRSET_INVAL          3
+# define ERRSET_NONAME         4
+# define ERRSET_NODATA         5
+#endif
+
+struct rdatainfo {
+       unsigned int            rdi_length;     /* length of data */
+       unsigned char           *rdi_data;      /* record data */
+};
+
+struct rrsetinfo {
+       unsigned int            rri_flags;      /* RRSET_VALIDATED ... */
+       unsigned int            rri_rdclass;    /* class number */
+       unsigned int            rri_rdtype;     /* RR type number */
+       unsigned int            rri_ttl;        /* time to live */
+       unsigned int            rri_nrdatas;    /* size of rdatas array */
+       unsigned int            rri_nsigs;      /* size of sigs array */
+       char                    *rri_name;      /* canonical name */
+       struct rdatainfo        *rri_rdatas;    /* individual records */
+       struct rdatainfo        *rri_sigs;      /* individual signatures */
+};
+
+int            getrrsetbyname(const char *, unsigned int, unsigned int, unsigned int, struct rrsetinfo **);
+void           freerrset(struct rrsetinfo *);
+
+#endif /* !defined(HAVE_GETRRSETBYNAME) */
+
+#endif /* _GETRRSETBYNAME_H */
diff --git a/openbsd-compat/glob.c b/openbsd-compat/glob.c
new file mode 100644 (file)
index 0000000..0341225
--- /dev/null
@@ -0,0 +1,1014 @@
+/*     $OpenBSD: glob.c,v 1.35 2011/01/12 01:53:14 djm 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/glob.c */
+
+/*
+ * 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
+    !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
+    !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
+    defined(BROKEN_GLOB)
+
+#include "charclass.h"
+
+#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        M_CLASS         META(':')
+#define        ismeta(c)       (((c)&M_QUOTE) != 0)
+
+#define        GLOB_LIMIT_MALLOC       65536
+#define        GLOB_LIMIT_STAT         128
+#define        GLOB_LIMIT_READDIR      16384
+
+struct glob_lim {
+       size_t  glim_malloc;
+       size_t  glim_stat;
+       size_t  glim_readdir;
+};
+
+static int      compare(const void *, const void *);
+static int      g_Ctoc(const Char *, char *, u_int);
+static int      g_lstat(Char *, struct stat *, glob_t *);
+static DIR     *g_opendir(Char *, glob_t *);
+static Char    *g_strchr(const Char *, int);
+static int      g_strncmp(const Char *, const char *, size_t);
+static int      g_stat(Char *, struct stat *, glob_t *);
+static int      glob0(const Char *, glob_t *, struct glob_lim *);
+static int      glob1(Char *, Char *, glob_t *, struct glob_lim *);
+static int      glob2(Char *, Char *, Char *, Char *, Char *, Char *,
+                   glob_t *, struct glob_lim *);
+static int      glob3(Char *, Char *, Char *, Char *, Char *,
+                   Char *, Char *, glob_t *, struct glob_lim *);
+static int      globextend(const Char *, glob_t *, struct glob_lim *,
+                   struct stat *);
+static const Char *
+                globtilde(const Char *, Char *, size_t, glob_t *);
+static int      globexp1(const Char *, glob_t *, struct glob_lim *);
+static int      globexp2(const Char *, const Char *, glob_t *,
+                   struct glob_lim *);
+static int      match(Char *, Char *, Char *);
+#ifdef DEBUG
+static void     qprintf(const char *, Char *);
+#endif
+
+int
+glob(const char *pattern, int flags, int (*errfunc)(const char *, int),
+    glob_t *pglob)
+{
+       const u_char *patnext;
+       int c;
+       Char *bufnext, *bufend, patbuf[MAXPATHLEN];
+       struct glob_lim limit = { 0, 0, 0 };
+
+       patnext = (u_char *) pattern;
+       if (!(flags & GLOB_APPEND)) {
+               pglob->gl_pathc = 0;
+               pglob->gl_pathv = NULL;
+               pglob->gl_statv = NULL;
+               if (!(flags & GLOB_DOOFFS))
+                       pglob->gl_offs = 0;
+       }
+       pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+       pglob->gl_errfunc = errfunc;
+       pglob->gl_matchc = 0;
+
+       if (pglob->gl_offs < 0 || pglob->gl_pathc < 0 ||
+           pglob->gl_offs >= INT_MAX || pglob->gl_pathc >= INT_MAX ||
+           pglob->gl_pathc >= INT_MAX - pglob->gl_offs - 1)
+               return GLOB_NOSPACE;
+
+       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, &limit);
+       else
+               return glob0(patbuf, pglob, &limit);
+}
+
+/*
+ * 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(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
+{
+       const Char* ptr = pattern;
+
+       /* Protect a single {}, for find(1), like csh */
+       if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+               return glob0(pattern, pglob, limitp);
+
+       if ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
+               return globexp2(ptr, pattern, pglob, limitp);
+
+       return glob0(pattern, pglob, limitp);
+}
+
+
+/*
+ * 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(const Char *ptr, const Char *pattern, glob_t *pglob,
+    struct glob_lim *limitp)
+{
+       int     i, rv;
+       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)
+               return glob0(patbuf, pglob, limitp);
+
+       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, limitp);
+                               if (rv && rv != GLOB_NOMATCH)
+                                       return rv;
+
+                               /* move after the comma, to the next string */
+                               pl = pm + 1;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(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;
+}
+
+static int
+g_strncmp(const Char *s1, const char *s2, size_t n)
+{
+       int rv = 0;
+
+       while (n--) {
+               rv = *(Char *)s1 - *(const unsigned char *)s2++;
+               if (rv)
+                       break;
+               if (*s1++ == '\0')
+                       break;
+       }
+       return rv;
+}
+
+static int
+g_charclass(const Char **patternp, Char **bufnextp)
+{
+       const Char *pattern = *patternp + 1;
+       Char *bufnext = *bufnextp;
+       const Char *colon;
+       struct cclass *cc;
+       size_t len;
+
+       if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
+               return 1;       /* not a character class */
+
+       len = (size_t)(colon - pattern);
+       for (cc = cclasses; cc->name != NULL; cc++) {
+               if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
+                       break;
+       }
+       if (cc->name == NULL)
+               return -1;      /* invalid character class */
+       *bufnext++ = M_CLASS;
+       *bufnext++ = (Char)(cc - &cclasses[0]);
+       *bufnextp = bufnext;
+       *patternp += len + 3;
+
+       return 0;
+}
+
+/*
+ * 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(const Char *pattern, glob_t *pglob, struct glob_lim *limitp)
+{
+       const Char *qpatnext;
+       int c, err, oldpathc;
+       Char *bufnext, patbuf[MAXPATHLEN];
+
+       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(qpatnext+1, RBRACKET) == NULL) {
+                               *bufnext++ = LBRACKET;
+                               if (c == NOT)
+                                       --qpatnext;
+                               break;
+                       }
+                       *bufnext++ = M_SET;
+                       if (c == NOT)
+                               *bufnext++ = M_NOT;
+                       c = *qpatnext++;
+                       do {
+                               if (c == LBRACKET && *qpatnext == ':') {
+                                       do {
+                                               err = g_charclass(&qpatnext,
+                                                   &bufnext);
+                                               if (err)
+                                                       break;
+                                               c = *qpatnext++;
+                                       } while (c == LBRACKET && *qpatnext == ':');
+                                       if (err == -1 &&
+                                           !(pglob->gl_flags & GLOB_NOCHECK))
+                                               return GLOB_NOMATCH;
+                                       if (c == RBRACKET)
+                                               break;
+                               }
+                               *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, limitp)) != 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, limitp, NULL));
+               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(const void *p, const void *q)
+{
+       return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *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(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
+    Char *pattern, Char *pattern_last, glob_t *pglob, struct glob_lim *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_LIMIT) &&
+                           limitp->glim_stat++ >= GLOB_LIMIT_STAT) {
+                               errno = 0;
+                               *pathend++ = SEP;
+                               *pathend = EOS;
+                               return(GLOB_NOSPACE);
+                       }
+
+                       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, &sb));
+               }
+
+               /* 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, p, pattern_last,
+                           pglob, limitp));
+       }
+       /* NOTREACHED */
+}
+
+static int
+glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
+    Char *pattern, Char *restpattern, Char *restpattern_last, glob_t *pglob,
+    struct glob_lim *limitp)
+{
+       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)(void *);
+
+       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 = (struct dirent *(*)(void *))readdir;
+       while ((dp = (*readdirfunc)(dirp))) {
+               u_char *sc;
+               Char *dc;
+
+               if ((pglob->gl_flags & GLOB_LIMIT) &&
+                   limitp->glim_readdir++ >= GLOB_LIMIT_READDIR) {
+                       errno = 0;
+                       *pathend++ = SEP;
+                       *pathend = EOS;
+                       return(GLOB_NOSPACE);
+               }
+
+               /* 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 accommodate 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(const Char *path, glob_t *pglob, struct glob_lim *limitp,
+    struct stat *sb)
+{
+       char **pathv;
+       ssize_t i;
+       size_t newn, len;
+       char *copy = NULL;
+       const Char *p;
+       struct stat **statv;
+
+       newn = 2 + pglob->gl_pathc + pglob->gl_offs;
+       if (pglob->gl_offs >= INT_MAX ||
+           pglob->gl_pathc >= INT_MAX ||
+           newn >= INT_MAX ||
+           SIZE_MAX / sizeof(*pathv) <= newn ||
+           SIZE_MAX / sizeof(*statv) <= newn) {
+ nospace:
+               for (i = pglob->gl_offs; i < (ssize_t)(newn - 2); i++) {
+                       if (pglob->gl_pathv && pglob->gl_pathv[i])
+                               free(pglob->gl_pathv[i]);
+                       if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0 &&
+                           pglob->gl_pathv && pglob->gl_pathv[i])
+                               free(pglob->gl_statv[i]);
+               }
+               if (pglob->gl_pathv) {
+                       free(pglob->gl_pathv);
+                       pglob->gl_pathv = NULL;
+               }
+               if (pglob->gl_statv) {
+                       free(pglob->gl_statv);
+                       pglob->gl_statv = NULL;
+               }
+               return(GLOB_NOSPACE);
+       }
+
+       pathv = realloc(pglob->gl_pathv, newn * sizeof(*pathv));
+       if (pathv == NULL)
+               goto 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;
+
+       if ((pglob->gl_flags & GLOB_KEEPSTAT) != 0) {
+               statv = realloc(pglob->gl_statv, newn * sizeof(*statv));
+               if (statv == NULL)
+                       goto nospace;
+               if (pglob->gl_statv == NULL && pglob->gl_offs > 0) {
+                       /* first time around -- clear initial gl_offs items */
+                       statv += pglob->gl_offs;
+                       for (i = pglob->gl_offs; --i >= 0; )
+                               *--statv = NULL;
+               }
+               pglob->gl_statv = statv;
+               if (sb == NULL)
+                       statv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+               else {
+                       limitp->glim_malloc += sizeof(**statv);
+                       if ((pglob->gl_flags & GLOB_LIMIT) &&
+                           limitp->glim_malloc >= GLOB_LIMIT_MALLOC) {
+                               errno = 0;
+                               return(GLOB_NOSPACE);
+                       }
+                       if ((statv[pglob->gl_offs + pglob->gl_pathc] =
+                           malloc(sizeof(**statv))) == NULL)
+                               goto copy_error;
+                       memcpy(statv[pglob->gl_offs + pglob->gl_pathc], sb,
+                           sizeof(*sb));
+               }
+               statv[pglob->gl_offs + pglob->gl_pathc + 1] = NULL;
+       }
+
+       for (p = path; *p++;)
+               ;
+       len = (size_t)(p - path);
+       limitp->glim_malloc += 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) &&
+           (newn * sizeof(*pathv)) + limitp->glim_malloc >
+           GLOB_LIMIT_MALLOC) {
+               errno = 0;
+               return(GLOB_NOSPACE);
+       }
+ copy_error:
+       return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames.  Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(Char *name, Char *pat, Char *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 ((c & M_MASK) == M_CLASS) {
+                                       Char idx = *pat & M_MASK;
+                                       if (idx < NCCLASSES &&
+                                           cclasses[idx].isctype(k))
+                                               ok = 1;
+                                       ++pat;
+                               }
+                               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(glob_t *pglob)
+{
+       int i;
+       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;
+       }
+       if (pglob->gl_statv != NULL) {
+               for (i = 0; i < pglob->gl_pathc; i++) {
+                       if (pglob->gl_statv[i] != NULL)
+                               free(pglob->gl_statv[i]);
+               }
+               free(pglob->gl_statv);
+               pglob->gl_statv = NULL;
+       }
+}
+
+static DIR *
+g_opendir(Char *str, glob_t *pglob)
+{
+       char buf[MAXPATHLEN];
+
+       if (!*str)
+               strlcpy(buf, ".", sizeof 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(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(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(const Char *str, int ch)
+{
+       do {
+               if (*str == ch)
+                       return ((Char *)str);
+       } while (*str++);
+       return (NULL);
+}
+
+static int
+g_Ctoc(const Char *str, char *buf, u_int len)
+{
+
+       while (len--) {
+               if ((*buf++ = *str++) == EOS)
+                       return (0);
+       }
+       return (1);
+}
+
+#ifdef DEBUG
+static void
+qprintf(const char *str, Char *s)
+{
+       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) || !defined(GLOB_HAS_GL_STATV) */
diff --git a/openbsd-compat/glob.h b/openbsd-compat/glob.h
new file mode 100644 (file)
index 0000000..f8a7fa5
--- /dev/null
@@ -0,0 +1,103 @@
+/*     $OpenBSD: glob.h,v 1.11 2010/09/24 13:32:55 djm 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. 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
+ */
+
+/* OPENBSD ORIGINAL: include/glob.h */
+
+#if !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC) || \
+    !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOB_HAS_GL_STATV) || \
+    !defined(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
+    defined(BROKEN_GLOB)
+
+#ifndef _GLOB_H_
+#define        _GLOB_H_
+
+#include <sys/stat.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. */
+       struct stat **gl_statv; /* Stat entries corresponding to gl_pathv */
+                               /* Copy of errfunc parameter to glob. */
+       int (*gl_errfunc)(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)(void *);
+       struct dirent *(*gl_readdir)(void *);   
+       void *(*gl_opendir)(const char *);
+       int (*gl_lstat)(const char *, struct stat *);
+       int (*gl_stat)(const char *, struct stat *);
+} glob_t;
+
+#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_NOESCAPE   0x1000  /* Disable backslash escaping. */
+
+#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_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_LIMIT     0x2000  /* Limit pattern match output to ARG_MAX */
+#define        GLOB_KEEPSTAT   0x4000  /* Retain stat data for paths in gl_statv. */
+#define GLOB_ABEND     GLOB_ABORTED /* backward compatibility */
+
+int    glob(const char *, int, int (*)(const char *, int), glob_t *);
+void   globfree(glob_t *);
+
+#endif /* !_GLOB_H_ */
+
+#endif /* !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC)  ||
+         !defined(GLOB_HAS_GL_MATCHC) || !defined(GLOH_HAS_GL_STATV) */
+
diff --git a/openbsd-compat/inet_aton.c b/openbsd-compat/inet_aton.c
new file mode 100644 (file)
index 0000000..130597e
--- /dev/null
@@ -0,0 +1,179 @@
+/*     $OpenBSD: inet_addr.c,v 1.9 2005/08/06 20:30:03 espie Exp $     */
+
+/*
+ * 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. 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--
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/inet_addr.c */
+
+#include "includes.h"
+
+#if !defined(HAVE_INET_ATON)
+
+#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(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)
+{
+       u_int32_t val;
+       int base, n;
+       char c;
+       u_int parts[4];
+       u_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/openbsd-compat/inet_ntoa.c b/openbsd-compat/inet_ntoa.c
new file mode 100644 (file)
index 0000000..0eb7b3b
--- /dev/null
@@ -0,0 +1,59 @@
+/*     $OpenBSD: inet_ntoa.c,v 1.6 2005/08/06 20:30:03 espie Exp $ */
+/*
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/inet_ntoa.c */
+
+#include "includes.h"
+
+#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
+
+/*
+ * 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>
+
+char *
+inet_ntoa(struct in_addr in)
+{
+       static char b[18];
+       char *p;
+
+       p = (char *)&in;
+#define        UC(b)   (((int)b)&0xff)
+       (void)snprintf(b, sizeof(b),
+           "%u.%u.%u.%u", 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/openbsd-compat/inet_ntop.c b/openbsd-compat/inet_ntop.c
new file mode 100644 (file)
index 0000000..e7ca4b7
--- /dev/null
@@ -0,0 +1,211 @@
+/*     $OpenBSD: inet_ntop.c,v 1.7 2005/08/06 20:30:03 espie 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */
+
+#include "includes.h"
+
+#ifndef HAVE_INET_NTOP
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#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(const u_char *src, char *dst, size_t size);
+static const char *inet_ntop6(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(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(const u_char *src, char *dst, size_t size)
+{
+       static const char fmt[] = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+       int l;
+
+       l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
+       if (l <= 0 || l >= size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strlcpy(dst, tmp, size);
+       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(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"];
+       char *tp, *ep;
+       struct { int base, len; } best, cur;
+       u_int words[IN6ADDRSZ / INT16SZ];
+       int i;
+       int advance;
+
+       /*
+        * 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;
+       ep = tmp + sizeof(tmp);
+       for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; 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) {
+                               if (tp + 1 >= ep)
+                                       return (NULL);
+                               *tp++ = ':';
+                       }
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0) {
+                       if (tp + 1 >= ep)
+                               return (NULL);
+                       *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, (size_t)(ep - tp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               advance = snprintf(tp, ep - tp, "%x", words[i]);
+               if (advance <= 0 || advance >= ep - tp)
+                       return (NULL);
+               tp += advance;
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
+               if (tp + 1 >= ep)
+                       return (NULL);
+               *tp++ = ':';
+       }
+       if (tp + 1 >= ep)
+               return (NULL);
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strlcpy(dst, tmp, size);
+       return (dst);
+}
+
+#endif /* !HAVE_INET_NTOP */
diff --git a/openbsd-compat/mktemp.c b/openbsd-compat/mktemp.c
new file mode 100644 (file)
index 0000000..2285c84
--- /dev/null
@@ -0,0 +1,178 @@
+/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
+/* Changes: Removed mktemp */
+
+/*     $OpenBSD: mktemp.c,v 1.19 2005/08/08 08:05:36 espie Exp $ */
+/*
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdio/mktemp.c */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
+
+static int _gettemp(char *, int *, int, int);
+
+int
+mkstemps(char *path, int slen)
+{
+       int fd;
+
+       return (_gettemp(path, &fd, 0, slen) ? fd : -1);
+}
+
+int
+mkstemp(char *path)
+{
+       int fd;
+
+       return (_gettemp(path, &fd, 0, 0) ? fd : -1);
+}
+
+char *
+mkdtemp(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 rval;
+       pid_t pid;
+
+       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 >= path && *trv == 'X' && pid != 0) {
+               *trv-- = (pid % 10) + '0';
+               pid /= 10;
+       }
+       while (trv >= path && *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 /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
new file mode 100644 (file)
index 0000000..77c5ed2
--- /dev/null
@@ -0,0 +1,238 @@
+/* $Id: openbsd-compat.h,v 1.51 2010/10/07 10:25:29 djm Exp $ */
+
+/*
+ * Copyright (c) 1999-2003 Damien Miller.  All rights reserved.
+ * Copyright (c) 2003 Ben Lindstrom. All rights reserved.
+ * Copyright (c) 2002 Tim Rice.  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 _OPENBSD_COMPAT_H
+#define _OPENBSD_COMPAT_H
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+
+#include <sys/socket.h>
+
+/* OpenBSD function replacements */
+#include "base64.h"
+#include "sigact.h"
+#include "glob.h"
+#include "readpassphrase.h"
+#include "vis.h"
+#include "getrrsetbyname.h"
+#include "sha2.h"
+
+#ifndef HAVE_BASENAME
+char *basename(const char *path);
+#endif
+
+#ifndef HAVE_BINDRESVPORT_SA
+int bindresvport_sa(int sd, struct sockaddr *sa);
+#endif
+
+#ifndef HAVE_CLOSEFROM
+void closefrom(int);
+#endif
+
+#ifndef HAVE_GETCWD
+char *getcwd(char *pt, size_t size);
+#endif 
+
+#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
+char *realpath(const char *path, char *resolved);
+#endif 
+
+#ifndef HAVE_RRESVPORT_AF
+int rresvport_af(int *alport, sa_family_t af);
+#endif
+
+#ifndef HAVE_STRLCPY
+/* #include <sys/types.h> XXX Still needed? */
+size_t strlcpy(char *dst, const char *src, size_t siz);
+#endif
+
+#ifndef HAVE_STRLCAT
+/* #include <sys/types.h> XXX Still needed? */
+size_t strlcat(char *dst, const char *src, size_t siz);
+#endif 
+
+#ifndef HAVE_SETENV
+int setenv(register const char *name, register const char *value, int rewrite);
+#endif
+
+#ifndef HAVE_STRMODE
+void strmode(int mode, char *p);
+#endif
+
+#ifndef HAVE_STRPTIME
+#include  <time.h>
+char *strptime(const char *buf, const char *fmt, struct tm *tm);
+#endif
+
+#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
+int mkstemps(char *path, int slen);
+int mkstemp(char *path);
+char *mkdtemp(char *path);
+#endif 
+
+#ifndef HAVE_DAEMON
+int daemon(int nochdir, int noclose);
+#endif 
+
+#ifndef HAVE_DIRNAME
+char *dirname(const char *path);
+#endif
+
+#ifndef HAVE_FMT_SCALED
+#define        FMT_SCALED_STRSIZE      7
+int    fmt_scaled(long long number, char *result);
+#endif
+
+#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA)
+char *inet_ntoa(struct in_addr in);
+#endif
+
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+#endif
+
+#ifndef HAVE_INET_ATON
+int inet_aton(const char *cp, struct in_addr *addr);
+#endif 
+
+#ifndef HAVE_STRSEP
+char *strsep(char **stringp, const char *delim);
+#endif
+
+#ifndef HAVE_SETPROCTITLE
+void setproctitle(const char *fmt, ...);
+void compat_init_setproctitle(int argc, char *argv[]);
+#endif
+
+#ifndef HAVE_GETGROUPLIST
+/* #include <grp.h> XXXX Still needed ? */
+int getgrouplist(const char *, gid_t, gid_t *, int *);
+#endif
+
+#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
+int BSDgetopt(int argc, char * const *argv, const char *opts);
+#endif
+
+#if defined(HAVE_DECL_WRITEV) && HAVE_DECL_WRITEV == 0
+# include <sys/types.h>
+# include <sys/uio.h>
+int writev(int, struct iovec *, int);
+#endif
+
+/* Home grown routines */
+#include "bsd-misc.h"
+#include "bsd-statvfs.h"
+#include "bsd-waitpid.h"
+#include "bsd-poll.h"
+
+#ifndef HAVE_GETPEEREID
+int getpeereid(int , uid_t *, gid_t *);
+#endif 
+
+#ifndef HAVE_ARC4RANDOM
+unsigned int arc4random(void);
+void arc4random_stir(void);
+#endif /* !HAVE_ARC4RANDOM */
+
+#ifndef HAVE_ARC4RANDOM_BUF
+void arc4random_buf(void *, size_t);
+#endif
+
+#ifndef HAVE_ARC4RANDOM_UNIFORM
+u_int32_t arc4random_uniform(u_int32_t);
+#endif
+
+#ifndef HAVE_ASPRINTF
+int asprintf(char **, const char *, ...);
+#endif 
+
+#ifndef HAVE_OPENPTY
+# include <sys/ioctl.h>        /* for struct winsize */
+int openpty(int *, int *, char *, struct termios *, struct winsize *);
+#endif /* HAVE_OPENPTY */
+
+/* #include <sys/types.h> XXX needed? For size_t */
+
+#ifndef HAVE_SNPRINTF
+int snprintf(char *, size_t, SNPRINTF_CONST char *, ...);
+#endif 
+
+#ifndef HAVE_STRTOLL
+long long strtoll(const char *, char **, int);
+#endif
+
+#ifndef HAVE_STRTONUM
+long long strtonum(const char *, long long, long long, const char **);
+#endif
+
+#if !defined(HAVE_VASPRINTF) || !defined(HAVE_VSNPRINTF)
+# include <stdarg.h>
+#endif
+
+#ifndef HAVE_VASPRINTF
+int vasprintf(char **, const char *, va_list);
+#endif
+
+#ifndef HAVE_VSNPRINTF
+int vsnprintf(char *, size_t, const char *, va_list);
+#endif
+
+#ifndef HAVE_USER_FROM_UID
+char *user_from_uid(uid_t, int);
+#endif
+
+#ifndef HAVE_GROUP_FROM_GID
+char *group_from_gid(gid_t, int);
+#endif
+
+#ifndef HAVE_TIMINGSAFE_BCMP
+int timingsafe_bcmp(const void *, const void *, size_t);
+#endif
+
+void *xmmap(size_t size);
+char *xcrypt(const char *password, const char *salt);
+char *shadow_pw(struct passwd *pw);
+
+/* rfc2553 socket API replacements */
+#include "fake-rfc2553.h"
+
+/* Routines for a single OS platform */
+#include "bsd-cray.h"
+#include "bsd-cygwin_util.h"
+
+#include "port-aix.h"
+#include "port-irix.h"
+#include "port-linux.h"
+#include "port-solaris.h"
+#include "port-tun.h"
+#include "port-uw.h"
+
+#endif /* _OPENBSD_COMPAT_H */
diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c
new file mode 100644 (file)
index 0000000..b617fdf
--- /dev/null
@@ -0,0 +1,146 @@
+/* $Id: openssl-compat.c,v 1.13 2011/01/21 22:37:06 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef USE_OPENSSL_ENGINE
+# include <openssl/engine.h>
+# include <openssl/conf.h>
+#endif
+
+#ifndef HAVE_RSA_GET_DEFAULT_METHOD
+# include <openssl/rsa.h>
+#endif
+
+#include "log.h"
+
+#define SSH_DONT_OVERLOAD_OPENSSL_FUNCS
+#include "openssl-compat.h"
+
+#ifdef SSH_OLD_EVP
+int
+ssh_EVP_CipherInit(EVP_CIPHER_CTX *evp, const EVP_CIPHER *type,
+    unsigned char *key, unsigned char *iv, int enc)
+{
+       EVP_CipherInit(evp, type, key, iv, enc);
+       return 1;
+}
+
+int
+ssh_EVP_Cipher(EVP_CIPHER_CTX *evp, char *dst, char *src, int len)
+{
+       EVP_Cipher(evp, dst, src, len);
+       return 1;
+}
+
+int
+ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *evp)
+{
+       EVP_CIPHER_CTX_cleanup(evp);
+       return 1;
+}
+#endif
+
+#ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
+int
+ssh_EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, unsigned int cnt)
+{
+       EVP_DigestUpdate(ctx, d, cnt);
+       return 1;
+}
+#endif
+
+#ifndef HAVE_BN_IS_PRIME_EX
+int
+BN_is_prime_ex(const BIGNUM *p, int nchecks, BN_CTX *ctx, void *cb)
+{
+       if (cb != NULL)
+               fatal("%s: callback args not supported", __func__);
+       return BN_is_prime(p, nchecks, NULL, ctx, NULL);
+}
+#endif
+
+#ifndef HAVE_RSA_GENERATE_KEY_EX
+int
+RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *bn_e, void *cb)
+{
+       RSA *new_rsa, tmp_rsa;
+       unsigned long e;
+
+       if (cb != NULL)
+               fatal("%s: callback args not supported", __func__);
+       e = BN_get_word(bn_e);
+       if (e == 0xffffffffL)
+               fatal("%s: value of e too large", __func__);
+       new_rsa = RSA_generate_key(bits, e, NULL, NULL);
+       if (new_rsa == NULL)
+               return 0;
+       /* swap rsa/new_rsa then free new_rsa */
+       tmp_rsa = *rsa;
+       *rsa = *new_rsa;
+       *new_rsa = tmp_rsa;
+       RSA_free(new_rsa);
+       return 1;
+}
+#endif
+
+#ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
+int
+DSA_generate_parameters_ex(DSA *dsa, int bits, const unsigned char *seed,
+    int seed_len, int *counter_ret, unsigned long *h_ret, void *cb)
+{
+       DSA *new_dsa, tmp_dsa;
+
+       if (cb != NULL)
+               fatal("%s: callback args not supported", __func__);
+       new_dsa = DSA_generate_parameters(bits, (unsigned char *)seed, seed_len,
+           counter_ret, h_ret, NULL, NULL);
+       if (new_dsa == NULL)
+               return 0;
+       /* swap dsa/new_dsa then free new_dsa */
+       tmp_dsa = *dsa;
+       *dsa = *new_dsa;
+       *new_dsa = tmp_dsa;
+       DSA_free(new_dsa);
+       return 1;
+}
+#endif
+
+#ifndef HAVE_RSA_GET_DEFAULT_METHOD
+RSA_METHOD *
+RSA_get_default_method(void)
+{
+       return RSA_PKCS1_SSLeay();
+}
+#endif
+
+#ifdef USE_OPENSSL_ENGINE
+void
+ssh_SSLeay_add_all_algorithms(void)
+{
+       SSLeay_add_all_algorithms();
+
+       /* Enable use of crypto hardware */
+       ENGINE_load_builtin_engines();
+       ENGINE_register_all_complete();
+       OPENSSL_config(NULL);
+}
+#endif
diff --git a/openbsd-compat/openssl-compat.h b/openbsd-compat/openssl-compat.h
new file mode 100644 (file)
index 0000000..6d4f3f2
--- /dev/null
@@ -0,0 +1,134 @@
+/* $Id: openssl-compat.h,v 1.18 2011/01/21 22:37:06 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2005 Darren Tucker <dtucker@zip.com.au>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+
+/* Only in 0.9.8 */
+#ifndef OPENSSL_DSA_MAX_MODULUS_BITS
+# define OPENSSL_DSA_MAX_MODULUS_BITS        10000
+#endif
+#ifndef OPENSSL_RSA_MAX_MODULUS_BITS
+# define OPENSSL_RSA_MAX_MODULUS_BITS        16384
+#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
+
+#if OPENSSL_VERSION_NUMBER < 0x00906000L
+# define SSH_OLD_EVP
+# define EVP_CIPHER_CTX_get_app_data(e)                ((e)->app_data)
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x1000000fL
+# define LIBCRYPTO_EVP_INL_TYPE unsigned int
+#else
+# define LIBCRYPTO_EVP_INL_TYPE size_t
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x00907000L) || defined(OPENSSL_LOBOTOMISED_AES)
+# define USE_BUILTIN_RIJNDAEL
+#endif
+
+#ifdef USE_BUILTIN_RIJNDAEL
+# include "rijndael.h"
+# define AES_KEY rijndael_ctx
+# define AES_BLOCK_SIZE 16
+# define AES_encrypt(a, b, c)          rijndael_encrypt(c, a, b)
+# define AES_set_encrypt_key(a, b, c)  rijndael_set_key(c, (char *)a, b, 1)
+# define EVP_aes_128_cbc evp_rijndael
+# define EVP_aes_192_cbc evp_rijndael
+# define EVP_aes_256_cbc evp_rijndael
+extern const EVP_CIPHER *evp_rijndael(void);
+extern void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int);
+#endif
+
+#if !defined(EVP_CTRL_SET_ACSS_MODE)
+# if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+#  define USE_CIPHER_ACSS 1
+extern const EVP_CIPHER *evp_acss(void);
+#  define EVP_acss evp_acss
+# else
+#  define EVP_acss NULL
+# endif
+#endif
+
+/* OpenSSL 0.9.8e returns cipher key len not context key len */
+#if (OPENSSL_VERSION_NUMBER == 0x0090805fL)
+# define EVP_CIPHER_CTX_key_length(c) ((c)->key_len)
+#endif
+
+#ifndef HAVE_RSA_GET_DEFAULT_METHOD
+RSA_METHOD *RSA_get_default_method(void);
+#endif
+
+/*
+ * We overload some of the OpenSSL crypto functions with ssh_* equivalents
+ * which cater for older and/or less featureful OpenSSL version.
+ *
+ * In order for the compat library to call the real functions, it must
+ * define SSH_DONT_OVERLOAD_OPENSSL_FUNCS before including this file and
+ * implement the ssh_* equivalents.
+ */
+#ifndef SSH_DONT_OVERLOAD_OPENSSL_FUNCS
+
+# ifdef SSH_OLD_EVP
+#  ifdef EVP_Cipher
+#   undef EVP_Cipher
+#  endif
+#  define EVP_CipherInit(a,b,c,d,e)    ssh_EVP_CipherInit((a),(b),(c),(d),(e))
+#  define EVP_Cipher(a,b,c,d)          ssh_EVP_Cipher((a),(b),(c),(d))
+#  define EVP_CIPHER_CTX_cleanup(a)    ssh_EVP_CIPHER_CTX_cleanup((a))
+# endif /* SSH_OLD_EVP */
+
+# ifdef OPENSSL_EVP_DIGESTUPDATE_VOID
+#  define EVP_DigestUpdate(a,b,c)      ssh_EVP_DigestUpdate((a),(b),(c))
+#  endif
+
+# ifdef USE_OPENSSL_ENGINE
+#  ifdef SSLeay_add_all_algorithms
+#   undef SSLeay_add_all_algorithms
+#  endif
+#  define SSLeay_add_all_algorithms()  ssh_SSLeay_add_all_algorithms()
+# endif
+
+# ifndef HAVE_BN_IS_PRIME_EX
+int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, void *);
+# endif
+
+# ifndef HAVE_DSA_GENERATE_PARAMETERS_EX
+int DSA_generate_parameters_ex(DSA *, int, const unsigned char *, int, int *,
+    unsigned long *, void *);
+# endif
+
+# ifndef HAVE_RSA_GENERATE_KEY_EX
+int RSA_generate_key_ex(RSA *, int, BIGNUM *, void *);
+# endif
+
+int ssh_EVP_CipherInit(EVP_CIPHER_CTX *, const EVP_CIPHER *, unsigned char *,
+    unsigned char *, int);
+int ssh_EVP_Cipher(EVP_CIPHER_CTX *, char *, char *, int);
+int ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *);
+void ssh_SSLeay_add_all_algorithms(void);
+#endif /* SSH_DONT_OVERLOAD_OPENSSL_FUNCS */
+
diff --git a/openbsd-compat/port-aix.c b/openbsd-compat/port-aix.c
new file mode 100644 (file)
index 0000000..0bdefbf
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ *
+ * Copyright (c) 2001 Gert Doering.  All rights reserved.
+ * Copyright (c) 2003,2004,2005,2006 Darren Tucker.  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 "buffer.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "ssh.h"
+#include "log.h"
+
+#ifdef _AIX
+
+#include <errno.h>
+#if defined(HAVE_NETDB_H)
+# include <netdb.h>
+#endif
+#include <uinfo.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#ifdef WITH_AIXAUTHENTICATE
+# include <login.h>
+# include <userpw.h>
+# if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG)
+#  include <sys/audit.h>
+# endif
+# include <usersec.h>
+#endif
+
+#include "port-aix.h"
+
+static char *lastlogin_msg = NULL;
+
+# ifdef HAVE_SETAUTHDB
+static char old_registry[REGISTRY_SIZE] = "";
+# endif
+
+/*
+ * 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
+ *
+ * NOTE: TTY= should be set, but since no one uses it and it's hard to
+ * acquire due to privsep code.  We will just drop support.
+ */
+void
+aix_usrinfo(struct passwd *pw)
+{
+       u_int i;
+       size_t len;
+       char *cp;
+
+       len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
+       cp = xmalloc(len);
+
+       i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0',
+           pw->pw_name, '\0');
+       if (usrinfo(SETUINFO, cp, i) == -1)
+               fatal("Couldn't set usrinfo: %s", strerror(errno));
+       debug3("AIX/UsrInfo: set len %d", i);
+
+       xfree(cp);
+}
+
+# ifdef WITH_AIXAUTHENTICATE
+/*
+ * Remove embedded newlines in string (if any).
+ * Used before logging messages returned by AIX authentication functions
+ * so the message is logged on one line.
+ */
+void
+aix_remove_embedded_newlines(char *p)
+{
+       if (p == NULL)
+               return;
+
+       for (; *p; p++) {
+               if (*p == '\n')
+                       *p = ' ';
+       }
+       /* Remove trailing whitespace */
+       if (*--p == ' ')
+               *p = '\0';
+}
+
+/*
+ * Test specifically for the case where SYSTEM == NONE and AUTH1 contains
+ * anything other than NONE or SYSTEM, which indicates that the admin has
+ * configured the account for purely AUTH1-type authentication.
+ *
+ * Since authenticate() doesn't check AUTH1, and sshd can't sanely support
+ * AUTH1 itself, in such a case authenticate() will allow access without
+ * authentation, which is almost certainly not what the admin intends.
+ *
+ * (The native tools, eg login, will process the AUTH1 list in addition to
+ * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods
+ * have been deprecated since AIX 4.2.x and would be very difficult for sshd
+ * to support.
+ *
+ * Returns 0 if an unsupportable combination is found, 1 otherwise.
+ */
+static int
+aix_valid_authentications(const char *user)
+{
+       char *auth1, *sys, *p;
+       int valid = 1;
+
+       if (getuserattr((char *)user, S_AUTHSYSTEM, &sys, SEC_CHAR) != 0) {
+               logit("Can't retrieve attribute SYSTEM for %s: %.100s",
+                   user, strerror(errno));
+               return 0;
+       }
+
+       debug3("AIX SYSTEM attribute %s", sys);
+       if (strcmp(sys, "NONE") != 0)
+               return 1;       /* not "NONE", so is OK */
+
+       if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) {
+               logit("Can't retrieve attribute auth1 for %s: %.100s",
+                   user, strerror(errno));
+               return 0;
+       }
+
+       p = auth1;
+       /* A SEC_LIST is concatenated strings, ending with two NULs. */
+       while (p[0] != '\0' && p[1] != '\0') {
+               debug3("AIX auth1 attribute list member %s", p);
+               if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) {
+                       logit("Account %s has unsupported auth1 value '%s'",
+                           user, p);
+                       valid = 0;
+               }
+               p += strlen(p) + 1;
+       }
+
+       return (valid);
+}
+
+/*
+ * Do authentication via AIX's authenticate routine.  We loop until the
+ * reenter parameter is 0, but normally authenticate is called only once.
+ *
+ * Note: this function returns 1 on success, whereas AIX's authenticate()
+ * returns 0.
+ */
+int
+sys_auth_passwd(Authctxt *ctxt, const char *password)
+{
+       char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name;
+       int authsuccess = 0, expired, reenter, result;
+
+       do {
+               result = authenticate((char *)name, (char *)password, &reenter,
+                   &authmsg);
+               aix_remove_embedded_newlines(authmsg);  
+               debug3("AIX/authenticate result %d, authmsg %.100s", result,
+                   authmsg);
+       } while (reenter);
+
+       if (!aix_valid_authentications(name))
+               result = -1;
+
+       if (result == 0) {
+               authsuccess = 1;
+
+               /*
+                * Record successful login.  We don't have a pty yet, so just
+                * label the line as "ssh"
+                */
+               aix_setauthdb(name);
+
+               /*
+                * Check if the user's password is expired.
+                */
+               expired = passwdexpired(name, &msg);
+               if (msg && *msg) {
+                       buffer_append(ctxt->loginmsg, msg, strlen(msg));
+                       aix_remove_embedded_newlines(msg);
+               }
+               debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
+
+               switch (expired) {
+               case 0: /* password not expired */
+                       break;
+               case 1: /* expired, password change required */
+                       ctxt->force_pwchange = 1;
+                       break;
+               default: /* user can't change(2) or other error (-1) */
+                       logit("Password can't be changed for user %s: %.100s",
+                           name, msg);
+                       if (msg)
+                               xfree(msg);
+                       authsuccess = 0;
+               }
+
+               aix_restoreauthdb();
+       }
+
+       if (authmsg != NULL)
+               xfree(authmsg);
+
+       return authsuccess;
+}
+
+/*
+ * Check if specified account is permitted to log in.
+ * Returns 1 if login is allowed, 0 if not allowed.
+ */
+int
+sys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg)
+{
+       char *msg = NULL;
+       int result, permitted = 0;
+       struct stat st;
+
+       /*
+        * Don't perform checks for root account (PermitRootLogin controls
+        * logins via ssh) or if running as non-root user (since
+        * loginrestrictions will always fail due to insufficient privilege).
+        */
+       if (pw->pw_uid == 0 || geteuid() != 0) {
+               debug3("%s: not checking", __func__);
+               return 1;
+       }
+
+       result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg);
+       if (result == 0)
+               permitted = 1;
+       /*
+        * If restricted because /etc/nologin exists, the login will be denied
+        * in session.c after the nologin message is sent, so allow for now
+        * and do not append the returned message.
+        */
+       if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0)
+               permitted = 1;
+       else if (msg != NULL)
+               buffer_append(loginmsg, msg, strlen(msg));
+       if (msg == NULL)
+               msg = xstrdup("(none)");
+       aix_remove_embedded_newlines(msg);
+       debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg);
+
+       if (!permitted)
+               logit("Login restricted for %s: %.100s", pw->pw_name, msg);
+       xfree(msg);
+       return permitted;
+}
+
+int
+sys_auth_record_login(const char *user, const char *host, const char *ttynm,
+    Buffer *loginmsg)
+{
+       char *msg = NULL;
+       int success = 0;
+
+       aix_setauthdb(user);
+       if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) {
+               success = 1;
+               if (msg != NULL) {
+                       debug("AIX/loginsuccess: msg %s", msg);
+                       if (lastlogin_msg == NULL)
+                               lastlogin_msg = msg;
+               }
+       }
+       aix_restoreauthdb();
+       return (success);
+}
+
+char *
+sys_auth_get_lastlogin_msg(const char *user, uid_t uid)
+{
+       char *msg = lastlogin_msg;
+
+       lastlogin_msg = NULL;
+       return msg;
+}
+
+#  ifdef CUSTOM_FAILED_LOGIN
+/*
+ * record_failed_login: generic "login failed" interface function
+ */
+void
+record_failed_login(const char *user, const char *hostname, const char *ttyname)
+{
+       if (geteuid() != 0)
+               return;
+
+       aix_setauthdb(user);
+#   ifdef AIX_LOGINFAILED_4ARG
+       loginfailed((char *)user, (char *)hostname, (char *)ttyname,
+           AUDIT_FAIL_AUTH);
+#   else
+       loginfailed((char *)user, (char *)hostname, (char *)ttyname);
+#   endif
+       aix_restoreauthdb();
+}
+#  endif /* CUSTOM_FAILED_LOGIN */
+
+/*
+ * If we have setauthdb, retrieve the password registry for the user's
+ * account then feed it to setauthdb.  This will mean that subsequent AIX auth
+ * functions will only use the specified loadable module.  If we don't have
+ * setauthdb this is a no-op.
+ */
+void
+aix_setauthdb(const char *user)
+{
+#  ifdef HAVE_SETAUTHDB
+       char *registry;
+
+       if (setuserdb(S_READ) == -1) {
+               debug3("%s: Could not open userdb to read", __func__);
+               return;
+       }
+       
+       if (getuserattr((char *)user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
+               if (setauthdb(registry, old_registry) == 0)
+                       debug3("AIX/setauthdb set registry '%s'", registry);
+               else 
+                       debug3("AIX/setauthdb set registry '%s' failed: %s",
+                           registry, strerror(errno));
+       } else
+               debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
+                   strerror(errno));
+       enduserdb();
+#  endif /* HAVE_SETAUTHDB */
+}
+
+/*
+ * Restore the user's registry settings from old_registry.
+ * Note that if the first aix_setauthdb fails, setauthdb("") is still safe
+ * (it restores the system default behaviour).  If we don't have setauthdb,
+ * this is a no-op.
+ */
+void
+aix_restoreauthdb(void)
+{
+#  ifdef HAVE_SETAUTHDB
+       if (setauthdb(old_registry, NULL) == 0)
+               debug3("%s: restoring old registry '%s'", __func__,
+                   old_registry);
+       else
+               debug3("%s: failed to restore old registry %s", __func__,
+                   old_registry);
+#  endif /* HAVE_SETAUTHDB */
+}
+
+# endif /* WITH_AIXAUTHENTICATE */
+
+# ifdef USE_AIX_KRB_NAME
+/*
+ * aix_krb5_get_principal_name: returns the user's kerberos client principal name if
+ * configured, otherwise NULL.  Caller must free returned string.
+ */
+char *
+aix_krb5_get_principal_name(char *pw_name)
+{
+       char *authname = NULL, *authdomain = NULL, *principal = NULL;
+
+       setuserdb(S_READ);
+       if (getuserattr(pw_name, S_AUTHDOMAIN, &authdomain, SEC_CHAR) != 0)
+               debug("AIX getuserattr S_AUTHDOMAIN: %s", strerror(errno));
+       if (getuserattr(pw_name, S_AUTHNAME, &authname, SEC_CHAR) != 0)
+               debug("AIX getuserattr S_AUTHNAME: %s", strerror(errno));
+
+       if (authdomain != NULL)
+               xasprintf(&principal, "%s@%s", authname ? authname : pw_name, authdomain);
+       else if (authname != NULL)
+               principal = xstrdup(authname);
+       enduserdb();
+       return principal;
+}
+# endif /* USE_AIX_KRB_NAME */
+
+# if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO)
+# undef getnameinfo
+/*
+ * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros
+ * IPv6 address into its textual representation ("::"), so we wrap it
+ * with a function that will.
+ */
+int
+sshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
+    size_t hostlen, char *serv, size_t servlen, int flags)
+{
+       struct sockaddr_in6 *sa6;
+       u_int32_t *a6;
+
+       if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) &&
+           sa->sa_family == AF_INET6) {
+               sa6 = (struct sockaddr_in6 *)sa;
+               a6 = sa6->sin6_addr.u6_addr.u6_addr32;
+
+               if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
+                       strlcpy(host, "::", hostlen);
+                       snprintf(serv, servlen, "%d", sa6->sin6_port);
+                       return 0;
+               }
+       }
+       return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+}
+# endif /* AIX_GETNAMEINFO_HACK */
+
+# if defined(USE_GETGRSET)
+#  include <stdlib.h>
+int
+getgrouplist(const char *user, gid_t pgid, gid_t *groups, int *grpcnt)
+{
+       char *cp, *grplist, *grp;
+       gid_t gid;
+       int ret = 0, ngroups = 0, maxgroups;
+       long l;
+
+       maxgroups = *grpcnt;
+
+       if ((cp = grplist = getgrset(user)) == NULL)
+               return -1;
+
+       /* handle zero-length case */
+       if (maxgroups <= 0) {
+               *grpcnt = 0;
+               return -1;
+       }
+
+       /* copy primary group */
+       groups[ngroups++] = pgid;
+
+       /* copy each entry from getgrset into group list */
+       while ((grp = strsep(&grplist, ",")) != NULL) {
+               l = strtol(grp, NULL, 10);
+               if (ngroups >= maxgroups || l == LONG_MIN || l == LONG_MAX) {
+                       ret = -1;
+                       goto out;
+               }
+               gid = (gid_t)l;
+               if (gid == pgid)
+                       continue;       /* we have already added primary gid */
+               groups[ngroups++] = gid;
+       }
+out:
+       free(cp);
+       *grpcnt = ngroups;
+       return ret;
+}
+# endif        /* USE_GETGRSET */
+
+#endif /* _AIX */
diff --git a/openbsd-compat/port-aix.h b/openbsd-compat/port-aix.h
new file mode 100644 (file)
index 0000000..53e4e88
--- /dev/null
@@ -0,0 +1,127 @@
+/* $Id: port-aix.h,v 1.32 2009/12/20 23:49:22 dtucker Exp $ */
+
+/*
+ *
+ * Copyright (c) 2001 Gert Doering.  All rights reserved.
+ * Copyright (c) 2004,2005,2006 Darren Tucker.  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.
+ */
+
+#ifdef _AIX
+
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#include "buffer.h"
+
+/* These should be in the system headers but are not. */
+int usrinfo(int, char *, int);
+#if defined(HAVE_DECL_SETAUTHDB) && (HAVE_DECL_SETAUTHDB == 0)
+int setauthdb(const char *, char *);
+#endif
+/* these may or may not be in the headers depending on the version */
+#if defined(HAVE_DECL_AUTHENTICATE) && (HAVE_DECL_AUTHENTICATE == 0)
+int authenticate(char *, char *, int *, char **);
+#endif
+#if defined(HAVE_DECL_LOGINFAILED) && (HAVE_DECL_LOGINFAILED == 0)
+int loginfailed(char *, char *, char *);
+#endif
+#if defined(HAVE_DECL_LOGINRESTRICTIONS) && (HAVE_DECL_LOGINRESTRICTIONS == 0)
+int loginrestrictions(char *, int, char *, char **);
+#endif
+#if defined(HAVE_DECL_LOGINSUCCESS) && (HAVE_DECL_LOGINSUCCESS == 0)
+int loginsuccess(char *, char *, char *, char **);
+#endif
+#if defined(HAVE_DECL_PASSWDEXPIRED) && (HAVE_DECL_PASSWDEXPIRED == 0)
+int passwdexpired(char *, char **);
+#endif
+
+/* Some versions define r_type in the above headers, which causes a conflict */
+#ifdef r_type
+# undef r_type
+#endif
+
+/* AIX 4.2.x doesn't have nanosleep but does have nsleep which is equivalent */
+#if !defined(HAVE_NANOSLEEP) && defined(HAVE_NSLEEP)
+# define nanosleep(a,b) nsleep(a,b)
+#endif
+
+/* For struct timespec on AIX 4.2.x */
+#ifdef HAVE_SYS_TIMERS_H
+# include <sys/timers.h>
+#endif
+
+/* for setpcred and friends */
+#ifdef HAVE_USERSEC_H
+# include <usersec.h>
+#endif
+
+/*
+ * According to the setauthdb man page, AIX password registries must be 15
+ * chars or less plus terminating NUL.
+ */
+#ifdef HAVE_SETAUTHDB
+# define REGISTRY_SIZE 16
+#endif
+
+void aix_usrinfo(struct passwd *);
+
+#ifdef WITH_AIXAUTHENTICATE
+# define CUSTOM_SYS_AUTH_PASSWD 1
+# define CUSTOM_SYS_AUTH_ALLOWED_USER 1
+int sys_auth_allowed_user(struct passwd *, Buffer *);
+# define CUSTOM_SYS_AUTH_RECORD_LOGIN 1
+int sys_auth_record_login(const char *, const char *, const char *, Buffer *);
+# define CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
+char *sys_auth_get_lastlogin_msg(const char *, uid_t);
+# define CUSTOM_FAILED_LOGIN 1
+# if defined(S_AUTHDOMAIN)  && defined (S_AUTHNAME)
+# define USE_AIX_KRB_NAME
+char *aix_krb5_get_principal_name(char *);
+# endif
+#endif
+
+void aix_setauthdb(const char *);
+void aix_restoreauthdb(void);
+void aix_remove_embedded_newlines(char *);
+
+#if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_GETADDRINFO)
+# ifdef getnameinfo
+#  undef getnameinfo
+# endif
+int sshaix_getnameinfo(const struct sockaddr *, size_t, char *, size_t,
+    char *, size_t, int);
+# define getnameinfo(a,b,c,d,e,f,g) (sshaix_getnameinfo(a,b,c,d,e,f,g))
+#endif
+
+/*
+ * We use getgrset in preference to multiple getgrent calls for efficiency
+ * plus it supports NIS and LDAP groups.
+ */
+#if !defined(HAVE_GETGROUPLIST) && defined(HAVE_GETGRSET)
+# define HAVE_GETGROUPLIST
+# define USE_GETGRSET
+int getgrouplist(const char *, gid_t, gid_t *, int *);
+#endif
+
+#endif /* _AIX */
diff --git a/openbsd-compat/port-irix.c b/openbsd-compat/port-irix.c
new file mode 100644 (file)
index 0000000..ba751a5
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2000 Denis Parker.  All rights reserved.
+ * Copyright (c) 2000 Michael Stone.  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"
+
+#if defined(WITH_IRIX_PROJECT) || \
+    defined(WITH_IRIX_JOBS) || \
+    defined(WITH_IRIX_ARRAY)
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.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 */
+
+void
+irix_setusercontext(struct passwd *pw)
+{
+#ifdef WITH_IRIX_PROJECT
+        prid_t projid;
+#endif
+#ifdef WITH_IRIX_JOBS
+        jid_t jid = 0;
+#elif defined(WITH_IRIX_ARRAY)
+        int jid = 0;
+#endif
+
+#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  && 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 */
+}
+
+
+#endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
diff --git a/openbsd-compat/port-irix.h b/openbsd-compat/port-irix.h
new file mode 100644 (file)
index 0000000..67c4863
--- /dev/null
@@ -0,0 +1,39 @@
+/* $Id: port-irix.h,v 1.4 2003/08/29 16:59:52 mouring Exp $ */
+
+/*
+ * Copyright (c) 2000 Denis Parker.  All rights reserved.
+ * Copyright (c) 2000 Michael Stone.  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 _PORT_IRIX_H
+#define _PORT_IRIX_H
+
+#if defined(WITH_IRIX_PROJECT) || \
+    defined(WITH_IRIX_JOBS) || \
+    defined(WITH_IRIX_ARRAY)
+
+void irix_setusercontext(struct passwd *pw);
+
+#endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
+
+#endif /* ! _PORT_IRIX_H */
diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c
new file mode 100644 (file)
index 0000000..ede533f
--- /dev/null
@@ -0,0 +1,298 @@
+/* $Id: port-linux.c,v 1.11.4.2 2011/02/04 00:43:08 djm Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Walsh <dwalsh@redhat.com>
+ * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Linux-specific portability code - just SELinux support at present
+ */
+
+#include "includes.h"
+
+#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST)
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "log.h"
+#include "xmalloc.h"
+#include "port-linux.h"
+
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#include <selinux/flask.h>
+#include <selinux/get_context_list.h>
+
+/* Wrapper around is_selinux_enabled() to log its return value once only */
+int
+ssh_selinux_enabled(void)
+{
+       static int enabled = -1;
+
+       if (enabled == -1) {
+               enabled = (is_selinux_enabled() == 1);
+               debug("SELinux support %s", enabled ? "enabled" : "disabled");
+       }
+
+       return (enabled);
+}
+
+/* Return the default security context for the given username */
+static security_context_t
+ssh_selinux_getctxbyname(char *pwname)
+{
+       security_context_t sc;
+       char *sename = NULL, *lvl = NULL;
+       int r;
+
+#ifdef HAVE_GETSEUSERBYNAME
+       if (getseuserbyname(pwname, &sename, &lvl) != 0)
+               return NULL;
+#else
+       sename = pwname;
+       lvl = NULL;
+#endif
+
+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL
+       r = get_default_context_with_level(sename, lvl, NULL, &sc);
+#else
+       r = get_default_context(sename, NULL, &sc);
+#endif
+
+       if (r != 0) {
+               switch (security_getenforce()) {
+               case -1:
+                       fatal("%s: ssh_selinux_getctxbyname: "
+                           "security_getenforce() failed", __func__);
+               case 0:
+                       error("%s: Failed to get default SELinux security "
+                           "context for %s", __func__, pwname);
+                       break;
+               default:
+                       fatal("%s: Failed to get default SELinux security "
+                           "context for %s (in enforcing mode)",
+                           __func__, pwname);
+               }
+       }
+
+#ifdef HAVE_GETSEUSERBYNAME
+       if (sename != NULL)
+               xfree(sename);
+       if (lvl != NULL)
+               xfree(lvl);
+#endif
+
+       return (sc);
+}
+
+/* Set the execution context to the default for the specified user */
+void
+ssh_selinux_setup_exec_context(char *pwname)
+{
+       security_context_t user_ctx = NULL;
+
+       if (!ssh_selinux_enabled())
+               return;
+
+       debug3("%s: setting execution context", __func__);
+
+       user_ctx = ssh_selinux_getctxbyname(pwname);
+       if (setexeccon(user_ctx) != 0) {
+               switch (security_getenforce()) {
+               case -1:
+                       fatal("%s: security_getenforce() failed", __func__);
+               case 0:
+                       error("%s: Failed to set SELinux execution "
+                           "context for %s", __func__, pwname);
+                       break;
+               default:
+                       fatal("%s: Failed to set SELinux execution context "
+                           "for %s (in enforcing mode)", __func__, pwname);
+               }
+       }
+       if (user_ctx != NULL)
+               freecon(user_ctx);
+
+       debug3("%s: done", __func__);
+}
+
+/* Set the TTY context for the specified user */
+void
+ssh_selinux_setup_pty(char *pwname, const char *tty)
+{
+       security_context_t new_tty_ctx = NULL;
+       security_context_t user_ctx = NULL;
+       security_context_t old_tty_ctx = NULL;
+
+       if (!ssh_selinux_enabled())
+               return;
+
+       debug3("%s: setting TTY context on %s", __func__, tty);
+
+       user_ctx = ssh_selinux_getctxbyname(pwname);
+
+       /* XXX: should these calls fatal() upon failure in enforcing mode? */
+
+       if (getfilecon(tty, &old_tty_ctx) == -1) {
+               error("%s: getfilecon: %s", __func__, strerror(errno));
+               goto out;
+       }
+
+       if (security_compute_relabel(user_ctx, old_tty_ctx,
+           SECCLASS_CHR_FILE, &new_tty_ctx) != 0) {
+               error("%s: security_compute_relabel: %s",
+                   __func__, strerror(errno));
+               goto out;
+       }
+
+       if (setfilecon(tty, new_tty_ctx) != 0)
+               error("%s: setfilecon: %s", __func__, strerror(errno));
+ out:
+       if (new_tty_ctx != NULL)
+               freecon(new_tty_ctx);
+       if (old_tty_ctx != NULL)
+               freecon(old_tty_ctx);
+       if (user_ctx != NULL)
+               freecon(user_ctx);
+       debug3("%s: done", __func__);
+}
+
+void
+ssh_selinux_change_context(const char *newname)
+{
+       int len, newlen;
+       char *oldctx, *newctx, *cx;
+
+       if (!ssh_selinux_enabled())
+               return;
+
+       if (getcon((security_context_t *)&oldctx) < 0) {
+               logit("%s: getcon failed with %s", __func__, strerror (errno));
+               return;
+       }
+       if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) ==
+           NULL) {
+               logit ("%s: unparseable context %s", __func__, oldctx);
+               return;
+       }
+
+       newlen = strlen(oldctx) + strlen(newname) + 1;
+       newctx = xmalloc(newlen);
+       len = cx - oldctx + 1;
+       memcpy(newctx, oldctx, len);
+       strlcpy(newctx + len, newname, newlen - len);
+       if ((cx = index(cx + 1, ':')))
+               strlcat(newctx, cx, newlen);
+       debug3("%s: setting context from '%s' to '%s'", __func__, oldctx,
+           newctx);
+       if (setcon(newctx) < 0)
+               logit("%s: setcon failed with %s", __func__, strerror (errno));
+       xfree(oldctx);
+       xfree(newctx);
+}
+
+void
+ssh_selinux_setfscreatecon(const char *path)
+{
+       security_context_t context;
+
+       if (!ssh_selinux_enabled())
+               return;
+       if (path == NULL)
+               setfscreatecon(NULL);
+               return;
+       }
+       if (matchpathcon(path, 0700, &context) == 0)
+               setfscreatecon(context);
+}
+
+#endif /* WITH_SELINUX */
+
+#ifdef LINUX_OOM_ADJUST
+/*
+ * The magic "don't kill me" values, old and new, as documented in eg:
+ * http://lxr.linux.no/#linux+v2.6.32/Documentation/filesystems/proc.txt
+ * http://lxr.linux.no/#linux+v2.6.36/Documentation/filesystems/proc.txt
+ */
+
+static int oom_adj_save = INT_MIN;
+static char *oom_adj_path = NULL;
+struct {
+       char *path;
+       int value;
+} oom_adjust[] = {
+       {"/proc/self/oom_score_adj", -1000},    /* kernels >= 2.6.36 */
+       {"/proc/self/oom_adj", -17},            /* kernels <= 2.6.35 */
+       {NULL, 0},
+};
+
+/*
+ * Tell the kernel's out-of-memory killer to avoid sshd.
+ * Returns the previous oom_adj value or zero.
+ */
+void
+oom_adjust_setup(void)
+{
+       int i, value;
+       FILE *fp;
+
+       debug3("%s", __func__);
+        for (i = 0; oom_adjust[i].path != NULL; i++) {
+               oom_adj_path = oom_adjust[i].path;
+               value = oom_adjust[i].value;
+               if ((fp = fopen(oom_adj_path, "r+")) != NULL) {
+                       if (fscanf(fp, "%d", &oom_adj_save) != 1)
+                               verbose("error reading %s: %s", oom_adj_path,
+                                   strerror(errno));
+                       else {
+                               rewind(fp);
+                               if (fprintf(fp, "%d\n", value) <= 0)
+                                       verbose("error writing %s: %s",
+                                          oom_adj_path, strerror(errno));
+                               else
+                                       verbose("Set %s from %d to %d",
+                                          oom_adj_path, oom_adj_save, value);
+                       }
+                       fclose(fp);
+                       return;
+               }
+       }
+       oom_adj_path = NULL;
+}
+
+/* Restore the saved OOM adjustment */
+void
+oom_adjust_restore(void)
+{
+       FILE *fp;
+
+       debug3("%s", __func__);
+       if (oom_adj_save == INT_MIN || oom_adj_path == NULL ||
+           (fp = fopen(oom_adj_path, "w")) == NULL)
+               return;
+
+       if (fprintf(fp, "%d\n", oom_adj_save) <= 0)
+               verbose("error writing %s: %s", oom_adj_path, strerror(errno));
+       else
+               verbose("Set %s to %d", oom_adj_path, oom_adj_save);
+
+       fclose(fp);
+       return;
+}
+#endif /* LINUX_OOM_ADJUST */
+#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */
diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h
new file mode 100644 (file)
index 0000000..c2f6184
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id: port-linux.h,v 1.4.10.1 2011/02/04 00:42:21 djm Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PORT_LINUX_H
+#define _PORT_LINUX_H
+
+#ifdef WITH_SELINUX
+int ssh_selinux_enabled(void);
+void ssh_selinux_setup_pty(char *, const char *);
+void ssh_selinux_setup_exec_context(char *);
+void ssh_selinux_change_context(const char *);
+void ssh_selinux_setfscreatecon(const char *);
+#endif
+
+#ifdef LINUX_OOM_ADJUST
+void oom_adjust_restore(void);
+void oom_adjust_setup(void);
+#endif
+
+#endif /* ! _PORT_LINUX_H */
diff --git a/openbsd-compat/port-solaris.c b/openbsd-compat/port-solaris.c
new file mode 100644 (file)
index 0000000..25382f1
--- /dev/null
@@ -0,0 +1,229 @@
+/* $Id: port-solaris.c,v 1.4 2010/11/05 01:03:05 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2006 Chad Mynhier.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#include "includes.h"
+
+#ifdef USE_SOLARIS_PROCESS_CONTRACTS
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libcontract.h>
+#include <sys/contract/process.h>
+#include <sys/ctfs.h>
+
+#include "log.h"
+
+#define CT_TEMPLATE    CTFS_ROOT "/process/template"
+#define CT_LATEST      CTFS_ROOT "/process/latest"
+
+static int tmpl_fd = -1;
+
+/* Lookup the latest process contract */
+static ctid_t
+get_active_process_contract_id(void)
+{
+       int stat_fd;
+       ctid_t ctid = -1;
+       ct_stathdl_t stathdl;
+
+       if ((stat_fd = open64(CT_LATEST, O_RDONLY)) == -1) {
+               error("%s: Error opening 'latest' process "
+                   "contract: %s", __func__, strerror(errno));
+               return -1;
+       }
+       if (ct_status_read(stat_fd, CTD_COMMON, &stathdl) != 0) {
+               error("%s: Error reading process contract "
+                   "status: %s", __func__, strerror(errno));
+               goto out;
+       }
+       if ((ctid = ct_status_get_id(stathdl)) < 0) {
+               error("%s: Error getting process contract id: %s",
+                   __func__, strerror(errno));
+               goto out;
+       }
+
+       ct_status_free(stathdl);
+ out:
+       close(stat_fd);
+       return ctid;
+}
+
+void
+solaris_contract_pre_fork(void)
+{
+       if ((tmpl_fd = open64(CT_TEMPLATE, O_RDWR)) == -1) {
+               error("%s: open %s: %s", __func__,
+                   CT_TEMPLATE, strerror(errno));
+               return;
+       }
+
+       debug2("%s: setting up process contract template on fd %d",
+           __func__, tmpl_fd);
+
+       /* First we set the template parameters and event sets. */
+       if (ct_pr_tmpl_set_param(tmpl_fd, CT_PR_PGRPONLY) != 0) {
+               error("%s: Error setting process contract parameter set "
+                   "(pgrponly): %s", __func__, strerror(errno));
+               goto fail;
+       }
+       if (ct_pr_tmpl_set_fatal(tmpl_fd, CT_PR_EV_HWERR) != 0) {
+               error("%s: Error setting process contract template "
+                   "fatal events: %s", __func__, strerror(errno));
+               goto fail;
+       }
+       if (ct_tmpl_set_critical(tmpl_fd, 0) != 0) {
+               error("%s: Error setting process contract template "
+                   "critical events: %s", __func__, strerror(errno));
+               goto fail;
+       }
+       if (ct_tmpl_set_informative(tmpl_fd, CT_PR_EV_HWERR) != 0) {
+               error("%s: Error setting process contract template "
+                   "informative events: %s", __func__, strerror(errno));
+               goto fail;
+       }
+
+       /* Now make this the active template for this process. */
+       if (ct_tmpl_activate(tmpl_fd) != 0) {
+               error("%s: Error activating process contract "
+                   "template: %s", __func__, strerror(errno));
+               goto fail;
+       }
+       return;
+
+ fail:
+       if (tmpl_fd != -1) {
+               close(tmpl_fd);
+               tmpl_fd = -1;
+       }
+}
+
+void
+solaris_contract_post_fork_child()
+{
+       debug2("%s: clearing process contract template on fd %d",
+           __func__, tmpl_fd);
+
+       /* Clear the active template. */
+       if (ct_tmpl_clear(tmpl_fd) != 0)
+               error("%s: Error clearing active process contract "
+                   "template: %s", __func__, strerror(errno));
+
+       close(tmpl_fd);
+       tmpl_fd = -1;
+}
+
+void
+solaris_contract_post_fork_parent(pid_t pid)
+{
+       ctid_t ctid;
+       char ctl_path[256];
+       int r, ctl_fd = -1, stat_fd = -1;
+
+       debug2("%s: clearing template (fd %d)", __func__, tmpl_fd);
+
+       if (tmpl_fd == -1)
+               return;
+
+       /* First clear the active template. */
+       if ((r = ct_tmpl_clear(tmpl_fd)) != 0)
+               error("%s: Error clearing active process contract "
+                   "template: %s", __func__, strerror(errno));
+
+       close(tmpl_fd);
+       tmpl_fd = -1;
+
+       /*
+        * If either the fork didn't succeed (pid < 0), or clearing
+        * th active contract failed (r != 0), then we have nothing
+        * more do.
+        */
+       if (r != 0 || pid <= 0)
+               return;
+
+       /* Now lookup and abandon the contract we've created. */
+       ctid = get_active_process_contract_id();
+
+       debug2("%s: abandoning contract id %ld", __func__, ctid);
+
+       snprintf(ctl_path, sizeof(ctl_path),
+           CTFS_ROOT "/process/%ld/ctl", ctid);
+       if ((ctl_fd = open64(ctl_path, O_WRONLY)) < 0) {
+               error("%s: Error opening process contract "
+                   "ctl file: %s", __func__, strerror(errno));
+               goto fail;
+       }
+       if (ct_ctl_abandon(ctl_fd) < 0) {
+               error("%s: Error abandoning process contract: %s",
+                   __func__, strerror(errno));
+               goto fail;
+       }
+       close(ctl_fd);
+       return;
+
+ fail:
+       if (tmpl_fd != -1) {
+               close(tmpl_fd);
+               tmpl_fd = -1;
+       }
+       if (stat_fd != -1)
+               close(stat_fd);
+       if (ctl_fd != -1)
+               close(ctl_fd);
+}
+#endif
+
+#ifdef USE_SOLARIS_PROJECTS
+#include <sys/task.h>
+#include <project.h>
+
+/*
+ * Get/set solaris default project.
+ * If we fail, just run along gracefully.
+ */
+void
+solaris_set_default_project(struct passwd *pw)
+{
+       struct project  *defaultproject;
+       struct project   tempproject;
+       char buf[1024];
+
+       /* get default project, if we fail just return gracefully  */
+       if ((defaultproject = getdefaultproj(pw->pw_name, &tempproject, &buf,
+           sizeof(buf))) > 0) {
+               /* set default project */
+               if (setproject(defaultproject->pj_name, pw->pw_name,
+                   TASK_NORMAL) != 0)
+                       debug("setproject(%s): %s", defaultproject->pj_name,
+                           strerror(errno));
+       } else {
+               /* debug on getdefaultproj() error */
+               debug("getdefaultproj(%s): %s", pw->pw_name, strerror(errno));
+       }
+}
+#endif /* USE_SOLARIS_PROJECTS */
diff --git a/openbsd-compat/port-solaris.h b/openbsd-compat/port-solaris.h
new file mode 100644 (file)
index 0000000..cd442e7
--- /dev/null
@@ -0,0 +1,30 @@
+/* $Id: port-solaris.h,v 1.2 2010/11/05 01:03:05 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2006 Chad Mynhier.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PORT_SOLARIS_H
+
+#include <sys/types.h>
+
+#include <pwd.h>
+
+void solaris_contract_pre_fork(void);
+void solaris_contract_post_fork_child(void);
+void solaris_contract_post_fork_parent(pid_t pid);
+void solaris_set_default_project(struct passwd *);
+
+#endif
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
new file mode 100644 (file)
index 0000000..0d756f7
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netinet/ip.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "log.h"
+#include "misc.h"
+#include "buffer.h"
+#include "channels.h"
+
+/*
+ * This is the portable version of the SSH tunnel forwarding, it
+ * uses some preprocessor definitions for various platform-specific
+ * settings.
+ *
+ * SSH_TUN_LINUX       Use the (newer) Linux tun/tap device
+ * SSH_TUN_FREEBSD     Use the FreeBSD tun/tap device
+ * SSH_TUN_COMPAT_AF   Translate the OpenBSD address family
+ * SSH_TUN_PREPEND_AF  Prepend/remove the address family
+ */
+
+/*
+ * System-specific tunnel open function
+ */
+
+#if defined(SSH_TUN_LINUX)
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+int
+sys_tun_open(int tun, int mode)
+{
+       struct ifreq ifr;
+       int fd = -1;
+       const char *name = NULL;
+
+       if ((fd = open("/dev/net/tun", O_RDWR)) == -1) {
+               debug("%s: failed to open tunnel control interface: %s",
+                   __func__, strerror(errno));
+               return (-1);
+       }
+
+       bzero(&ifr, sizeof(ifr));       
+
+       if (mode == SSH_TUNMODE_ETHERNET) {
+               ifr.ifr_flags = IFF_TAP;
+               name = "tap%d";
+       } else {
+               ifr.ifr_flags = IFF_TUN;
+               name = "tun%d";
+       }
+       ifr.ifr_flags |= IFF_NO_PI;
+
+       if (tun != SSH_TUNID_ANY) {
+               if (tun > SSH_TUNID_MAX) {
+                       debug("%s: invalid tunnel id %x: %s", __func__,
+                           tun, strerror(errno));
+                       goto failed;
+               }
+               snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), name, tun);
+       }
+
+       if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
+               debug("%s: failed to configure tunnel (mode %d): %s", __func__,
+                   mode, strerror(errno));
+               goto failed;
+       }
+
+       if (tun == SSH_TUNID_ANY)
+               debug("%s: tunnel mode %d fd %d", __func__, mode, fd);
+       else
+               debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd);
+
+       return (fd);
+
+ failed:
+       close(fd);
+       return (-1);
+}
+#endif /* SSH_TUN_LINUX */
+
+#ifdef SSH_TUN_FREEBSD
+#include <sys/socket.h>
+#include <net/if.h>
+
+#ifdef HAVE_NET_IF_TUN_H
+#include <net/if_tun.h>
+#endif
+
+int
+sys_tun_open(int tun, int mode)
+{
+       struct ifreq ifr;
+       char name[100];
+       int fd = -1, sock, flag;
+       const char *tunbase = "tun";
+
+       if (mode == SSH_TUNMODE_ETHERNET) {
+#ifdef SSH_TUN_NO_L2
+               debug("%s: no layer 2 tunnelling support", __func__);
+               return (-1);
+#else
+               tunbase = "tap";
+#endif
+       }
+
+       /* Open the tunnel device */
+       if (tun <= SSH_TUNID_MAX) {
+               snprintf(name, sizeof(name), "/dev/%s%d", tunbase, tun);
+               fd = open(name, O_RDWR);
+       } else if (tun == SSH_TUNID_ANY) {
+               for (tun = 100; tun >= 0; tun--) {
+                       snprintf(name, sizeof(name), "/dev/%s%d",
+                           tunbase, tun);
+                       if ((fd = open(name, O_RDWR)) >= 0)
+                               break;
+               }
+       } else {
+               debug("%s: invalid tunnel %u\n", __func__, tun);
+               return (-1);
+       }
+
+       if (fd < 0) {
+               debug("%s: %s open failed: %s", __func__, name,
+                   strerror(errno));
+               return (-1);
+       }
+
+       /* Turn on tunnel headers */
+       flag = 1;
+#if defined(TUNSIFHEAD) && !defined(SSH_TUN_PREPEND_AF)
+       if (mode != SSH_TUNMODE_ETHERNET &&
+           ioctl(fd, TUNSIFHEAD, &flag) == -1) {
+               debug("%s: ioctl(%d, TUNSIFHEAD, 1): %s", __func__, fd,
+                   strerror(errno));
+               close(fd);
+       }
+#endif
+
+       debug("%s: %s mode %d fd %d", __func__, name, mode, fd);
+
+       /* Set the tunnel device operation mode */
+       snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun);
+       if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
+               goto failed;
+
+       if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)
+               goto failed;
+       if ((ifr.ifr_flags & IFF_UP) == 0) {
+               ifr.ifr_flags |= IFF_UP;
+               if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1)
+                       goto failed;
+       }
+
+       close(sock);
+       return (fd);
+
+ failed:
+       if (fd >= 0)
+               close(fd);
+       if (sock >= 0)
+               close(sock);
+       debug("%s: failed to set %s mode %d: %s", __func__, name,
+           mode, strerror(errno));
+       return (-1);
+}
+#endif /* SSH_TUN_FREEBSD */
+
+/*
+ * System-specific channel filters
+ */
+
+#if defined(SSH_TUN_FILTER)
+#define OPENBSD_AF_INET                2
+#define OPENBSD_AF_INET6       24
+
+int
+sys_tun_infilter(struct Channel *c, char *buf, int len)
+{
+#if defined(SSH_TUN_PREPEND_AF)
+       char rbuf[CHAN_RBUF];
+       struct ip *iph;
+#endif
+       u_int32_t *af;
+       char *ptr = buf;
+
+#if defined(SSH_TUN_PREPEND_AF)
+       if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
+               return (-1);
+       ptr = (char *)&rbuf[0];
+       bcopy(buf, ptr + sizeof(u_int32_t), len);
+       len += sizeof(u_int32_t);
+       af = (u_int32_t *)ptr;
+
+       iph = (struct ip *)(ptr + sizeof(u_int32_t));
+       switch (iph->ip_v) {
+       case 6:
+               *af = AF_INET6;
+               break;
+       case 4:
+       default:
+               *af = AF_INET;
+               break;
+       }
+#endif
+
+#if defined(SSH_TUN_COMPAT_AF)
+       if (len < (int)sizeof(u_int32_t))
+               return (-1);
+
+       af = (u_int32_t *)ptr;
+       if (*af == htonl(AF_INET6))
+               *af = htonl(OPENBSD_AF_INET6);
+       else
+               *af = htonl(OPENBSD_AF_INET);
+#endif
+
+       buffer_put_string(&c->input, ptr, len);
+       return (0);
+}
+
+u_char *
+sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
+{
+       u_char *buf;
+       u_int32_t *af;
+
+       *data = buffer_get_string(&c->output, dlen);
+       if (*dlen < sizeof(*af))
+               return (NULL);
+       buf = *data;
+
+#if defined(SSH_TUN_PREPEND_AF)
+       *dlen -= sizeof(u_int32_t);
+       buf = *data + sizeof(u_int32_t);
+#elif defined(SSH_TUN_COMPAT_AF)
+       af = ntohl(*(u_int32_t *)buf);
+       if (*af == OPENBSD_AF_INET6)
+               *af = htonl(AF_INET6);
+       else
+               *af = htonl(AF_INET);
+#endif
+
+       return (buf);
+}
+#endif /* SSH_TUN_FILTER */
diff --git a/openbsd-compat/port-tun.h b/openbsd-compat/port-tun.h
new file mode 100644 (file)
index 0000000..c53df01
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PORT_TUN_H
+#define _PORT_TUN_H
+
+struct Channel;
+
+#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
+# define CUSTOM_SYS_TUN_OPEN
+int      sys_tun_open(int, int);
+#endif
+
+#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
+# define SSH_TUN_FILTER
+int     sys_tun_infilter(struct Channel *, char *, int);
+u_char *sys_tun_outfilter(struct Channel *, u_char **, u_int *);
+#endif
+
+#endif
diff --git a/openbsd-compat/port-uw.c b/openbsd-compat/port-uw.c
new file mode 100644 (file)
index 0000000..b1fbfa2
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2005 The SCO Group. All rights reserved.
+ * Copyright (c) 2005 Tim Rice. 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"
+
+#if defined(HAVE_LIBIAF)  &&  !defined(HAVE_SECUREWARE)
+#include <sys/types.h>
+#ifdef HAVE_CRYPT_H
+# include <crypt.h>
+#endif
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "packet.h"
+#include "buffer.h"
+#include "key.h"
+#include "auth-options.h"
+#include "log.h"
+#include "servconf.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "ssh.h"
+
+int nischeck(char *);
+
+int
+sys_auth_passwd(Authctxt *authctxt, const char *password)
+{
+       struct passwd *pw = authctxt->pw;
+       char *salt;
+       int result;
+
+       /* Just use the supplied fake password if authctxt is invalid */
+       char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
+
+       /* Check for users with no password. */
+       if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
+               return (1);
+
+       /* Encrypt the candidate password using the proper salt. */
+       salt = (pw_password[0] && pw_password[1]) ? pw_password : "xx";
+
+       /*
+        * Authentication is accepted if the encrypted passwords
+        * are identical.
+        */
+#ifdef UNIXWARE_LONG_PASSWORDS
+       if (!nischeck(pw->pw_name)) {
+               result = ((strcmp(bigcrypt(password, salt), pw_password) == 0)
+               ||  (strcmp(osr5bigcrypt(password, salt), pw_password) == 0));
+       }
+       else
+#endif /* UNIXWARE_LONG_PASSWORDS */
+               result = (strcmp(xcrypt(password, salt), pw_password) == 0);
+
+#ifdef USE_LIBIAF
+       if (authctxt->valid)
+               free(pw_password);
+#endif
+       return(result);
+}
+
+#ifdef UNIXWARE_LONG_PASSWORDS
+int
+nischeck(char *namep)
+{
+       char password_file[] = "/etc/passwd";
+       FILE *fd;
+       struct passwd *ent = NULL;
+
+       if ((fd = fopen (password_file, "r")) == NULL) {
+               /*
+                * If the passwd file has dissapeared we are in a bad state.
+                * However, returning 0 will send us back through the
+                * authentication scheme that has checked the ia database for
+                * passwords earlier.
+                */
+               return(0);
+       }
+
+       /*
+        * fgetpwent() only reads from password file, so we know for certain
+        * that the user is local.
+        */
+       while (ent = fgetpwent(fd)) {
+               if (strcmp (ent->pw_name, namep) == 0) {
+                       /* Local user */
+                       fclose (fd);
+                       return(0);
+               }
+       }
+
+       fclose (fd);
+       return (1);
+}
+
+#endif /* UNIXWARE_LONG_PASSWORDS */
+
+/*
+       NOTE: ia_get_logpwd() allocates memory for arg 2
+       functions that call shadow_pw() will need to free
+ */
+
+#ifdef USE_LIBIAF
+char *
+get_iaf_password(struct passwd *pw)
+{
+       char *pw_password = NULL;
+
+       uinfo_t uinfo;
+       if (!ia_openinfo(pw->pw_name,&uinfo)) {
+               ia_get_logpwd(uinfo, &pw_password);
+               if (pw_password == NULL)
+                       fatal("ia_get_logpwd: Unable to get the shadow passwd");
+               ia_closeinfo(uinfo);
+               return pw_password;
+       }
+       else
+               fatal("ia_openinfo: Unable to open the shadow passwd file");
+}
+#endif /* USE_LIBIAF */
+#endif /* HAVE_LIBIAF and not HAVE_SECUREWARE */
+
diff --git a/openbsd-compat/port-uw.h b/openbsd-compat/port-uw.h
new file mode 100644 (file)
index 0000000..263d8b5
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005 Tim Rice.  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_LIBIAF
+char * get_iaf_password(struct passwd *pw);
+#endif
+
diff --git a/openbsd-compat/pwcache.c b/openbsd-compat/pwcache.c
new file mode 100644 (file)
index 0000000..5a8b788
--- /dev/null
@@ -0,0 +1,114 @@
+/*     $OpenBSD: pwcache.c,v 1.9 2005/08/08 08:05:34 espie Exp $ */
+/*
+ * Copyright (c) 1989, 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/pwcache.c */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define        NCACHE  64                      /* power of 2 */
+#define        MASK    (NCACHE - 1)            /* bits to store with */
+
+#ifndef HAVE_USER_FROM_UID
+char *
+user_from_uid(uid_t uid, int nouser)
+{
+       static struct ncache {
+               uid_t   uid;
+               char    *name;
+       } c_uid[NCACHE];
+       static int pwopen;
+       static char nbuf[15];           /* 32 bits == 10 digits */
+       struct passwd *pw;
+       struct ncache *cp;
+
+       cp = c_uid + (uid & MASK);
+       if (cp->uid != uid || cp->name == NULL) {
+               if (pwopen == 0) {
+#ifdef HAVE_SETPASSENT
+                       setpassent(1);
+#endif
+                       pwopen = 1;
+               }
+               if ((pw = getpwuid(uid)) == NULL) {
+                       if (nouser)
+                               return (NULL);
+                       (void)snprintf(nbuf, sizeof(nbuf), "%u", uid);
+               }
+               cp->uid = uid;
+               if (cp->name != NULL)
+                       free(cp->name);
+               cp->name = strdup(pw ? pw->pw_name : nbuf);
+       }
+       return (cp->name);
+}
+#endif
+
+#ifndef HAVE_GROUP_FROM_GID
+char *
+group_from_gid(gid_t gid, int nogroup)
+{
+       static struct ncache {
+               gid_t   gid;
+               char    *name;
+       } c_gid[NCACHE];
+       static int gropen;
+       static char nbuf[15];           /* 32 bits == 10 digits */
+       struct group *gr;
+       struct ncache *cp;
+
+       cp = c_gid + (gid & MASK);
+       if (cp->gid != gid || cp->name == NULL) {
+               if (gropen == 0) {
+#ifdef HAVE_SETGROUPENT
+                       setgroupent(1);
+#endif
+                       gropen = 1;
+               }
+               if ((gr = getgrgid(gid)) == NULL) {
+                       if (nogroup)
+                               return (NULL);
+                       (void)snprintf(nbuf, sizeof(nbuf), "%u", gid);
+               }
+               cp->gid = gid;
+               if (cp->name != NULL)
+                       free(cp->name);
+               cp->name = strdup(gr ? gr->gr_name : nbuf);
+       }
+       return (cp->name);
+}
+#endif
diff --git a/openbsd-compat/readpassphrase.c b/openbsd-compat/readpassphrase.c
new file mode 100644 (file)
index 0000000..62b6d0d
--- /dev/null
@@ -0,0 +1,205 @@
+/*     $OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $     */
+
+/*
+ * Copyright (c) 2000-2002, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */
+
+#include "includes.h"
+
+#ifndef HAVE_READPASSPHRASE
+
+#include <termios.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <readpassphrase.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.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
+
+static volatile sig_atomic_t signo[_NSIG];
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+       ssize_t nr;
+       int input, output, save_errno, i, need_restart;
+       char ch, *p, *end;
+       struct termios term, oterm;
+       struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
+       struct sigaction savetstp, savettin, savettou, savepipe;
+
+       /* I suppose we could alloc on demand in this case (XXX). */
+       if (bufsiz == 0) {
+               errno = EINVAL;
+               return(NULL);
+       }
+
+restart:
+       for (i = 0; i < _NSIG; i++)
+               signo[i] = 0;
+       nr = -1;
+       save_errno = 0;
+       need_restart = 0;
+       /*
+        * Read and write to /dev/tty if available.  If not, read from
+        * stdin and write to stderr unless a tty is required.
+        */
+       if ((flags & RPP_STDIN) ||
+           (input = output = open(_PATH_TTY, O_RDWR)) == -1) {
+               if (flags & RPP_REQUIRE_TTY) {
+                       errno = ENOTTY;
+                       return(NULL);
+               }
+               input = STDIN_FILENO;
+               output = STDERR_FILENO;
+       }
+
+       /*
+        * Catch signals that would otherwise cause the user to end
+        * up with echo turned off in the shell.  Don't worry about
+        * things like SIGXCPU and SIGVTALRM for now.
+        */
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = 0;                /* don't restart system calls */
+       sa.sa_handler = handler;
+       (void)sigaction(SIGALRM, &sa, &savealrm);
+       (void)sigaction(SIGHUP, &sa, &savehup);
+       (void)sigaction(SIGINT, &sa, &saveint);
+       (void)sigaction(SIGPIPE, &sa, &savepipe);
+       (void)sigaction(SIGQUIT, &sa, &savequit);
+       (void)sigaction(SIGTERM, &sa, &saveterm);
+       (void)sigaction(SIGTSTP, &sa, &savetstp);
+       (void)sigaction(SIGTTIN, &sa, &savettin);
+       (void)sigaction(SIGTTOU, &sa, &savettou);
+
+       /* Turn off echo if possible. */
+       if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
+               memcpy(&term, &oterm, sizeof(term));
+               if (!(flags & RPP_ECHO_ON))
+                       term.c_lflag &= ~(ECHO | ECHONL);
+#ifdef VSTATUS
+               if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
+                       term.c_cc[VSTATUS] = _POSIX_VDISABLE;
+#endif
+               (void)tcsetattr(input, _T_FLUSH, &term);
+       } else {
+               memset(&term, 0, sizeof(term));
+               term.c_lflag |= ECHO;
+               memset(&oterm, 0, sizeof(oterm));
+               oterm.c_lflag |= ECHO;
+       }
+
+       /* No I/O if we are already backgrounded. */
+       if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) {
+               if (!(flags & RPP_STDIN))
+                       (void)write(output, prompt, strlen(prompt));
+               end = buf + bufsiz - 1;
+               p = buf;
+               while ((nr = 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 = (char)tolower(ch);
+                                       if ((flags & RPP_FORCEUPPER))
+                                               ch = (char)toupper(ch);
+                               }
+                               *p++ = ch;
+                       }
+               }
+               *p = '\0';
+               save_errno = errno;
+               if (!(term.c_lflag & ECHO))
+                       (void)write(output, "\n", 1);
+       }
+
+       /* Restore old terminal settings and signals. */
+       if (memcmp(&term, &oterm, sizeof(term)) != 0) {
+               while (tcsetattr(input, _T_FLUSH, &oterm) == -1 &&
+                   errno == EINTR)
+                       continue;
+       }
+       (void)sigaction(SIGALRM, &savealrm, NULL);
+       (void)sigaction(SIGHUP, &savehup, NULL);
+       (void)sigaction(SIGINT, &saveint, NULL);
+       (void)sigaction(SIGQUIT, &savequit, NULL);
+       (void)sigaction(SIGPIPE, &savepipe, NULL);
+       (void)sigaction(SIGTERM, &saveterm, NULL);
+       (void)sigaction(SIGTSTP, &savetstp, NULL);
+       (void)sigaction(SIGTTIN, &savettin, NULL);
+       (void)sigaction(SIGTTOU, &savettou, NULL);
+       if (input != STDIN_FILENO)
+               (void)close(input);
+
+       /*
+        * If we were interrupted by a signal, resend it to ourselves
+        * now that we have restored the signal handlers.
+        */
+       for (i = 0; i < _NSIG; i++) {
+               if (signo[i]) {
+                       kill(getpid(), i);
+                       switch (i) {
+                       case SIGTSTP:
+                       case SIGTTIN:
+                       case SIGTTOU:
+                               need_restart = 1;
+                       }
+               }
+       }
+       if (need_restart)
+               goto restart;
+
+       if (save_errno)
+               errno = save_errno;
+       return(nr == -1 ? NULL : buf);
+}
+
+#if 0
+char *
+getpass(const char *prompt)
+{
+       static char buf[_PASSWORD_LEN + 1];
+
+       return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
+}
+#endif
+
+static void handler(int s)
+{
+
+       signo[s] = 1;
+}
+#endif /* HAVE_READPASSPHRASE */
diff --git a/openbsd-compat/readpassphrase.h b/openbsd-compat/readpassphrase.h
new file mode 100644 (file)
index 0000000..5fd7c5d
--- /dev/null
@@ -0,0 +1,44 @@
+/*     $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $      */
+
+/*
+ * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Sponsored in part by the Defense Advanced Research Projects
+ * Agency (DARPA) and Air Force Research Laboratory, Air Force
+ * Materiel Command, USAF, under agreement number F39502-99-1-0512.
+ */
+
+/* OPENBSD ORIGINAL: include/readpassphrase.h */
+
+#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. */
+#define RPP_STDIN       0x20           /* Read from stdin, not /dev/tty */
+
+char * readpassphrase(const char *, char *, size_t, int);
+
+#endif /* HAVE_READPASSPHRASE */
+
+#endif /* !_READPASSPHRASE_H_ */
diff --git a/openbsd-compat/realpath.c b/openbsd-compat/realpath.c
new file mode 100644 (file)
index 0000000..b6120d0
--- /dev/null
@@ -0,0 +1,197 @@
+/*     $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+/*
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+ *
+ * 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 names of the authors 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 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 AUTHOR 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */
+
+#include "includes.h"
+
+#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * char *realpath(const char *path, char resolved[PATH_MAX]);
+ *
+ * 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[PATH_MAX])
+{
+       struct stat sb;
+       char *p, *q, *s;
+       size_t left_len, resolved_len;
+       unsigned symlinks;
+       int serrno, slen;
+       char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
+
+       serrno = errno;
+       symlinks = 0;
+       if (path[0] == '/') {
+               resolved[0] = '/';
+               resolved[1] = '\0';
+               if (path[1] == '\0')
+                       return (resolved);
+               resolved_len = 1;
+               left_len = strlcpy(left, path + 1, sizeof(left));
+       } else {
+               if (getcwd(resolved, PATH_MAX) == NULL) {
+                       strlcpy(resolved, ".", PATH_MAX);
+                       return (NULL);
+               }
+               resolved_len = strlen(resolved);
+               left_len = strlcpy(left, path, sizeof(left));
+       }
+       if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
+               errno = ENAMETOOLONG;
+               return (NULL);
+       }
+
+       /*
+        * Iterate over path components in `left'.
+        */
+       while (left_len != 0) {
+               /*
+                * Extract the next path component and adjust `left'
+                * and its length.
+                */
+               p = strchr(left, '/');
+               s = p ? p : left + left_len;
+               if (s - left >= sizeof(next_token)) {
+                       errno = ENAMETOOLONG;
+                       return (NULL);
+               }
+               memcpy(next_token, left, s - left);
+               next_token[s - left] = '\0';
+               left_len -= s - left;
+               if (p != NULL)
+                       memmove(left, s + 1, left_len + 1);
+               if (resolved[resolved_len - 1] != '/') {
+                       if (resolved_len + 1 >= PATH_MAX) {
+                               errno = ENAMETOOLONG;
+                               return (NULL);
+                       }
+                       resolved[resolved_len++] = '/';
+                       resolved[resolved_len] = '\0';
+               }
+               if (next_token[0] == '\0')
+                       continue;
+               else if (strcmp(next_token, ".") == 0)
+                       continue;
+               else if (strcmp(next_token, "..") == 0) {
+                       /*
+                        * Strip the last path component except when we have
+                        * single "/"
+                        */
+                       if (resolved_len > 1) {
+                               resolved[resolved_len - 1] = '\0';
+                               q = strrchr(resolved, '/') + 1;
+                               *q = '\0';
+                               resolved_len = q - resolved;
+                       }
+                       continue;
+               }
+
+               /*
+                * Append the next path component and lstat() it. If
+                * lstat() fails we still can return successfully if
+                * there are no more path components left.
+                */
+               resolved_len = strlcat(resolved, next_token, PATH_MAX);
+               if (resolved_len >= PATH_MAX) {
+                       errno = ENAMETOOLONG;
+                       return (NULL);
+               }
+               if (lstat(resolved, &sb) != 0) {
+                       if (errno == ENOENT && p == NULL) {
+                               errno = serrno;
+                               return (resolved);
+                       }
+                       return (NULL);
+               }
+               if (S_ISLNK(sb.st_mode)) {
+                       if (symlinks++ > MAXSYMLINKS) {
+                               errno = ELOOP;
+                               return (NULL);
+                       }
+                       slen = readlink(resolved, symlink, sizeof(symlink) - 1);
+                       if (slen < 0)
+                               return (NULL);
+                       symlink[slen] = '\0';
+                       if (symlink[0] == '/') {
+                               resolved[1] = 0;
+                               resolved_len = 1;
+                       } else if (resolved_len > 1) {
+                               /* Strip the last path component. */
+                               resolved[resolved_len - 1] = '\0';
+                               q = strrchr(resolved, '/') + 1;
+                               *q = '\0';
+                               resolved_len = q - resolved;
+                       }
+
+                       /*
+                        * If there are any path components left, then
+                        * append them to symlink. The result is placed
+                        * in `left'.
+                        */
+                       if (p != NULL) {
+                               if (symlink[slen - 1] != '/') {
+                                       if (slen + 1 >= sizeof(symlink)) {
+                                               errno = ENAMETOOLONG;
+                                               return (NULL);
+                                       }
+                                       symlink[slen] = '/';
+                                       symlink[slen + 1] = 0;
+                               }
+                               left_len = strlcat(symlink, left, sizeof(left));
+                               if (left_len >= sizeof(left)) {
+                                       errno = ENAMETOOLONG;
+                                       return (NULL);
+                               }
+                       }
+                       left_len = strlcpy(left, symlink, sizeof(left));
+               }
+       }
+
+       /*
+        * Remove trailing slash except when the resolved pathname
+        * is a single "/".
+        */
+       if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
+               resolved[resolved_len - 1] = '\0';
+       return (resolved);
+}
+#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */
diff --git a/openbsd-compat/regress/Makefile.in b/openbsd-compat/regress/Makefile.in
new file mode 100644 (file)
index 0000000..bcf214b
--- /dev/null
@@ -0,0 +1,38 @@
+# $Id: Makefile.in,v 1.4 2006/08/19 09:12:14 dtucker Exp $
+
+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@
+EXEEXT=@EXEEXT@
+LIBCOMPAT=../libopenbsd-compat.a
+LIBS=@LIBS@
+LDFLAGS=@LDFLAGS@ $(LIBCOMPAT)
+
+TESTPROGS=closefromtest$(EXEEXT) snprintftest$(EXEEXT) strduptest$(EXEEXT) \
+       strtonumtest$(EXEEXT)
+
+all:   t-exec ${OTHERTESTS}
+
+%$(EXEEXT):    %.c
+       $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< $(LIBCOMPAT) $(LIBS)
+
+t-exec:        $(TESTPROGS)
+       @echo running compat regress tests
+       @for TEST in ""$?; do \
+               echo "run test $${TEST}" ... 1>&2; \
+               ./$${TEST}$(EXEEXT) || exit $$? ; \
+       done
+       @echo finished compat regress tests
+
+clean:
+       rm -f *.o *.a core $(TESTPROGS) valid.out
+
+distclean: clean
+       rm -f Makefile *~
diff --git a/openbsd-compat/regress/closefromtest.c b/openbsd-compat/regress/closefromtest.c
new file mode 100644 (file)
index 0000000..145b09d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006 Darren Tucker
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define NUM_OPENS 10
+
+void
+fail(char *msg)
+{
+       fprintf(stderr, "closefrom: %s\n", msg);
+       exit(1);
+}
+
+int
+main(void)
+{
+       int i, max, fds[NUM_OPENS];
+       char buf[512];
+
+       for (i = 0; i < NUM_OPENS; i++)
+               if ((fds[i] = open("/dev/null", O_RDONLY)) == -1)
+                       exit(0);        /* can't test */
+       max = i - 1;
+
+       /* should close last fd only */
+       closefrom(fds[max]);
+       if (close(fds[max]) != -1)
+               fail("failed to close highest fd");
+
+       /* make sure we can still use remaining descriptors */
+       for (i = 0; i < max; i++)
+               if (read(fds[i], buf, sizeof(buf)) == -1)
+                       fail("closed descriptors it should not have");
+
+       /* should close all fds */
+       closefrom(fds[0]);
+       for (i = 0; i < NUM_OPENS; i++)
+               if (close(fds[i]) != -1)
+                       fail("failed to close from lowest fd");
+       return 0;
+}
diff --git a/openbsd-compat/regress/snprintftest.c b/openbsd-compat/regress/snprintftest.c
new file mode 100644 (file)
index 0000000..4ca63e1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005 Darren Tucker
+ * Copyright (c) 2005 Damien Miller
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BUFSZ 2048
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+static int failed = 0;
+
+static void
+fail(const char *m)
+{
+       fprintf(stderr, "snprintftest: %s\n", m);
+       failed = 1;
+}
+
+int x_snprintf(char *str, size_t count, const char *fmt, ...)
+{
+       size_t ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = vsnprintf(str, count, fmt, ap);
+       va_end(ap);
+       return ret;
+}
+
+int
+main(void)
+{
+       char b[5];
+       char *src;
+
+       snprintf(b,5,"123456789");
+       if (b[4] != '\0')
+               fail("snprintf does not correctly terminate long strings");
+
+       /* check for read overrun on unterminated string */
+       if ((src = malloc(BUFSZ)) == NULL) {
+               fail("malloc failed");
+       } else {
+               memset(src, 'a', BUFSZ);
+               snprintf(b, sizeof(b), "%.*s", 1, src);
+               if (strcmp(b, "a") != 0)
+                       fail("failed with length limit '%%.s'");
+       }
+
+       /* check that snprintf and vsnprintf return sane values */
+       if (snprintf(b, 1, "%s %d", "hello", 12345) != 11)
+               fail("snprintf does not return required length");
+       if (x_snprintf(b, 1, "%s %d", "hello", 12345) != 11)
+               fail("vsnprintf does not return required length");
+
+       return failed;
+}
diff --git a/openbsd-compat/regress/strduptest.c b/openbsd-compat/regress/strduptest.c
new file mode 100644 (file)
index 0000000..7f6d779
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005 Darren Tucker
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+static int fail = 0;
+
+void
+test(const char *a)
+{
+       char *b;
+
+       b = strdup(a);
+       if (b == 0) {
+               fail = 1;
+               return;
+       }
+       if (strcmp(a, b) != 0)
+               fail = 1;
+       free(b);
+}
+
+int
+main(void)
+{
+       test("");
+       test("a");
+       test("\0");
+       test("abcdefghijklmnopqrstuvwxyz");
+       return fail;
+}
diff --git a/openbsd-compat/regress/strtonumtest.c b/openbsd-compat/regress/strtonumtest.c
new file mode 100644 (file)
index 0000000..50ca5bd
--- /dev/null
@@ -0,0 +1,80 @@
+/*     $OpenBSD: strtonumtest.c,v 1.1 2004/08/03 20:38:36 otto Exp $   */
+/*
+ * Copyright (c) 2004 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: regress/lib/libc/strtonum/strtonumtest.c */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* LLONG_MAX is known as LONGLONG_MAX on AIX */
+#if defined(LONGLONG_MAX) && !defined(LLONG_MAX)
+# define LLONG_MAX LONGLONG_MAX
+# define LLONG_MIN LONGLONG_MIN
+#endif
+
+/* LLONG_MAX is known as LONG_LONG_MAX on HP-UX */
+#if defined(LONG_LONG_MAX) && !defined(LLONG_MAX)
+# define LLONG_MAX LONG_LONG_MAX
+# define LLONG_MIN LONG_LONG_MIN
+#endif
+
+long long strtonum(const char *, long long, long long, const char **);
+
+int fail;
+
+void
+test(const char *p, long long lb, long long ub, int ok)
+{
+       long long val;
+       const char *q;
+
+       val = strtonum(p, lb, ub, &q);
+       if (ok && q != NULL) {
+               fprintf(stderr, "%s [%lld-%lld] ", p, lb, ub);
+               fprintf(stderr, "NUMBER NOT ACCEPTED %s\n", q);
+               fail = 1;
+       } else if (!ok && q == NULL) {
+               fprintf(stderr, "%s [%lld-%lld] %lld ", p, lb, ub, val);
+               fprintf(stderr, "NUMBER ACCEPTED\n");
+               fail = 1;
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       test("1", 0, 10, 1);
+       test("0", -2, 5, 1);
+       test("0", 2, 5, 0);
+       test("0", 2, LLONG_MAX, 0);
+       test("-2", 0, LLONG_MAX, 0);
+       test("0", -5, LLONG_MAX, 1);
+       test("-3", -3, LLONG_MAX, 1);
+       test("-9223372036854775808", LLONG_MIN, LLONG_MAX, 1);
+       test("9223372036854775807", LLONG_MIN, LLONG_MAX, 1);
+       test("-9223372036854775809", LLONG_MIN, LLONG_MAX, 0);
+       test("9223372036854775808", LLONG_MIN, LLONG_MAX, 0);
+       test("1000000000000000000000000", LLONG_MIN, LLONG_MAX, 0);
+       test("-1000000000000000000000000", LLONG_MIN, LLONG_MAX, 0);
+       test("-2", 10, -1, 0);
+       test("-2", -10, -1, 1);
+       test("-20", -10, -1, 0);
+       test("20", -10, -1, 0);
+
+       return (fail);
+}
+
diff --git a/openbsd-compat/rresvport.c b/openbsd-compat/rresvport.c
new file mode 100644 (file)
index 0000000..1cd61e5
--- /dev/null
@@ -0,0 +1,108 @@
+/* $OpenBSD: rresvport.c,v 1.9 2005/11/10 10:00:17 espie Exp $ */
+/*
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/net/rresvport.c */
+
+#include "includes.h"
+
+#ifndef HAVE_RRESVPORT_AF
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if 0
+int
+rresvport(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/openbsd-compat/setenv.c b/openbsd-compat/setenv.c
new file mode 100644 (file)
index 0000000..e2a8b6d
--- /dev/null
@@ -0,0 +1,145 @@
+/*     $OpenBSD: setenv.c,v 1.9 2005/08/08 08:05:37 espie Exp $ */
+/*
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/setenv.c */
+
+#include "includes.h"
+#if !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV)
+
+#include <stdlib.h>
+#include <string.h>
+
+extern char **environ;
+
+/* OpenSSH Portable: __findenv is from getenv.c rev 1.8, made static */
+/*
+ * __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.
+ */
+static char *
+__findenv(const char *name, size_t *offset)
+{
+       extern char **environ;
+       int len, i;
+       const char *np;
+       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);
+}
+
+#ifndef HAVE_SETENV
+/*
+ * setenv --
+ *     Set the value of the environmental variable "name" to be
+ *     "value".  If rewrite is set, replace any current value.
+ */
+int
+setenv(const char *name, const char *value, int rewrite)
+{
+       static char **lastenv;                  /* last value of environ */
+       char *C;
+       size_t l_value, offset;
+
+       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 */
+               size_t cnt;
+               char **P;
+
+               for (P = environ; *P != NULL; P++)
+                       ;
+               cnt = P - environ;
+               P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2));
+               if (!P)
+                       return (-1);
+               if (lastenv != environ)
+                       memcpy(P, environ, cnt * sizeof(char *));
+               lastenv = environ = P;
+               offset = cnt;
+               environ[cnt + 1] = NULL;
+       }
+       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);
+}
+#endif /* HAVE_SETENV */
+
+#ifndef HAVE_UNSETENV
+/*
+ * unsetenv(name) --
+ *     Delete environmental variable "name".
+ */
+void
+unsetenv(const char *name)
+{
+       char **P;
+       size_t offset;
+
+       while (__findenv(name, &offset))        /* if set multiple times */
+               for (P = &environ[offset];; ++P)
+                       if (!(*P = *(P + 1)))
+                               break;
+}
+#endif /* HAVE_UNSETENV */
+
+#endif /* !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) */
diff --git a/openbsd-compat/setproctitle.c b/openbsd-compat/setproctitle.c
new file mode 100644 (file)
index 0000000..2965f68
--- /dev/null
@@ -0,0 +1,164 @@
+/* Based on conf.c from UCB sendmail 8.8.8 */
+
+/*
+ * Copyright 2003 Damien Miller
+ * Copyright (c) 1983, 1995-1997 Eric P. Allman
+ * 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. 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_SETPROCTITLE
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_SYS_PSTAT_H
+#include <sys/pstat.h>
+#endif
+#include <string.h>
+
+#include <vis.h>
+
+#define SPT_NONE       0       /* don't use it at all */
+#define SPT_PSTAT      1       /* use pstat(PSTAT_SETCMD, ...) */
+#define SPT_REUSEARGV  2       /* cover argv with title information */
+
+#ifndef SPT_TYPE
+# define SPT_TYPE      SPT_NONE
+#endif
+
+#ifndef SPT_PADCHAR
+# define SPT_PADCHAR   '\0'
+#endif
+
+#if SPT_TYPE == SPT_REUSEARGV
+static char *argv_start = NULL;
+static size_t argv_env_len = 0;
+#endif
+
+#endif /* HAVE_SETPROCTITLE */
+
+void
+compat_init_setproctitle(int argc, char *argv[])
+{
+#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV
+       extern char **environ;
+       char *lastargv = NULL;
+       char **envp = environ;
+       int i;
+
+       /*
+        * NB: This assumes that argv has already been copied out of the
+        * way. This is true for sshd, but may not be true for other 
+        * programs. Beware.
+        */
+
+       if (argc == 0 || argv[0] == NULL)
+               return;
+
+       /* Fail if we can't allocate room for the new environment */
+       for (i = 0; envp[i] != NULL; i++)
+               ;
+       if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) {
+               environ = envp; /* put it back */
+               return;
+       }
+
+       /*
+        * Find the last argv string or environment variable within 
+        * our process memory area.
+        */
+       for (i = 0; i < argc; i++) {
+               if (lastargv == NULL || lastargv + 1 == argv[i])
+                       lastargv = argv[i] + strlen(argv[i]);
+       }
+       for (i = 0; envp[i] != NULL; i++) {
+               if (lastargv + 1 == envp[i])
+                       lastargv = envp[i] + strlen(envp[i]);
+       }
+
+       argv[1] = NULL;
+       argv_start = argv[0];
+       argv_env_len = lastargv - argv[0] - 1;
+
+       /* 
+        * Copy environment 
+        * XXX - will truncate env on strdup fail
+        */
+       for (i = 0; envp[i] != NULL; i++)
+               environ[i] = strdup(envp[i]);
+       environ[i] = NULL;
+#endif /* SPT_REUSEARGV */
+}
+
+#ifndef HAVE_SETPROCTITLE
+void
+setproctitle(const char *fmt, ...)
+{
+#if SPT_TYPE != SPT_NONE
+       va_list ap;
+       char buf[1024], ptitle[1024];
+       size_t len;
+       extern char *__progname;
+#if SPT_TYPE == SPT_PSTAT
+       union pstun pst;
+#endif
+
+#if SPT_TYPE == SPT_REUSEARGV
+       if (argv_env_len <= 0)
+               return;
+#endif
+
+       strlcpy(buf, __progname, sizeof(buf));
+
+       va_start(ap, fmt);
+       if (fmt != NULL) {
+               len = strlcat(buf, ": ", sizeof(buf));
+               if (len < sizeof(buf))
+                       vsnprintf(buf + len, sizeof(buf) - len , fmt, ap);
+       }
+       va_end(ap);
+       strnvis(ptitle, buf, sizeof(ptitle),
+           VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL);
+
+#if SPT_TYPE == SPT_PSTAT
+       pst.pst_command = ptitle;
+       pstat(PSTAT_SETCMD, pst, strlen(ptitle), 0, 0);
+#elif SPT_TYPE == SPT_REUSEARGV
+/*     debug("setproctitle: copy \"%s\" into len %d", 
+           buf, argv_env_len); */
+       len = strlcpy(argv_start, ptitle, argv_env_len);
+       for(; len < argv_env_len; len++)
+               argv_start[len] = SPT_PADCHAR;
+#endif
+
+#endif /* SPT_NONE */
+}
+
+#endif /* HAVE_SETPROCTITLE */
diff --git a/openbsd-compat/sha2.c b/openbsd-compat/sha2.c
new file mode 100755 (executable)
index 0000000..cf8e0ad
--- /dev/null
@@ -0,0 +1,882 @@
+/*     $OpenBSD: sha2.c,v 1.11 2005/08/08 08:05:35 espie Exp $ */
+
+/*
+ * FILE:       sha2.c
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ * 
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * 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. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 OR CONTRIBUTOR(S) 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.
+ *
+ * $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/hash/sha2.c */
+
+#include "includes.h"
+
+#include <openssl/opensslv.h>
+
+#if !defined(HAVE_EVP_SHA256) && !defined(HAVE_SHA256_UPDATE) && \
+    (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+#include <sys/types.h>
+#include <string.h>
+#include "sha2.h"
+
+/*
+ * UNROLLED TRANSFORM LOOP NOTE:
+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform
+ * loop version for the hash transform rounds (defined using macros
+ * later in this file).  Either define on the command line, for example:
+ *
+ *   cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c
+ *
+ * or define below:
+ *
+ *   #define SHA2_UNROLL_TRANSFORM
+ *
+ */
+
+/*** SHA-256/384/512 Machine Architecture Definitions *****************/
+/*
+ * BYTE_ORDER NOTE:
+ *
+ * Please make sure that your system defines BYTE_ORDER.  If your
+ * architecture is little-endian, make sure it also defines
+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are
+ * equivilent.
+ *
+ * If your system does not define the above, then you can do so by
+ * hand like this:
+ *
+ *   #define LITTLE_ENDIAN 1234
+ *   #define BIG_ENDIAN    4321
+ *
+ * And for little-endian machines, add:
+ *
+ *   #define BYTE_ORDER LITTLE_ENDIAN 
+ *
+ * Or for big-endian machines:
+ *
+ *   #define BYTE_ORDER BIG_ENDIAN
+ *
+ * The FreeBSD machine this was written on defines BYTE_ORDER
+ * appropriately by including <sys/types.h> (which in turn includes
+ * <machine/endian.h> where the appropriate definitions are actually
+ * made).
+ */
+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN)
+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN
+#endif
+
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+/* NOTE: Most of these are in sha2.h */
+#define SHA256_SHORT_BLOCK_LENGTH      (SHA256_BLOCK_LENGTH - 8)
+#define SHA384_SHORT_BLOCK_LENGTH      (SHA384_BLOCK_LENGTH - 16)
+#define SHA512_SHORT_BLOCK_LENGTH      (SHA512_BLOCK_LENGTH - 16)
+
+/*** ENDIAN SPECIFIC COPY MACROS **************************************/
+#define BE_8_TO_32(dst, cp) do {                                       \
+       (dst) = (u_int32_t)(cp)[3] | ((u_int32_t)(cp)[2] << 8) |        \
+           ((u_int32_t)(cp)[1] << 16) | ((u_int32_t)(cp)[0] << 24);    \
+} while(0)
+
+#define BE_8_TO_64(dst, cp) do {                                       \
+       (dst) = (u_int64_t)(cp)[7] | ((u_int64_t)(cp)[6] << 8) |        \
+           ((u_int64_t)(cp)[5] << 16) | ((u_int64_t)(cp)[4] << 24) |   \
+           ((u_int64_t)(cp)[3] << 32) | ((u_int64_t)(cp)[2] << 40) |   \
+           ((u_int64_t)(cp)[1] << 48) | ((u_int64_t)(cp)[0] << 56);    \
+} while (0)
+
+#define BE_64_TO_8(cp, src) do {                                       \
+       (cp)[0] = (src) >> 56;                                          \
+        (cp)[1] = (src) >> 48;                                         \
+       (cp)[2] = (src) >> 40;                                          \
+       (cp)[3] = (src) >> 32;                                          \
+       (cp)[4] = (src) >> 24;                                          \
+       (cp)[5] = (src) >> 16;                                          \
+       (cp)[6] = (src) >> 8;                                           \
+       (cp)[7] = (src);                                                \
+} while (0)
+
+#define BE_32_TO_8(cp, src) do {                                       \
+       (cp)[0] = (src) >> 24;                                          \
+       (cp)[1] = (src) >> 16;                                          \
+       (cp)[2] = (src) >> 8;                                           \
+       (cp)[3] = (src);                                                \
+} while (0)
+
+/*
+ * Macro for incrementally adding the unsigned 64-bit integer n to the
+ * unsigned 128-bit integer (represented using a two-element array of
+ * 64-bit words):
+ */
+#define ADDINC128(w,n) do {                                            \
+       (w)[0] += (u_int64_t)(n);                                       \
+       if ((w)[0] < (n)) {                                             \
+               (w)[1]++;                                               \
+       }                                                               \
+} while (0)
+
+/*** THE SIX LOGICAL FUNCTIONS ****************************************/
+/*
+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions:
+ *
+ *   NOTE:  The naming of R and S appears backwards here (R is a SHIFT and
+ *   S is a ROTATION) because the SHA-256/384/512 description document
+ *   (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this
+ *   same "backwards" definition.
+ */
+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */
+#define R(b,x)                 ((x) >> (b))
+/* 32-bit Rotate-right (used in SHA-256): */
+#define S32(b,x)       (((x) >> (b)) | ((x) << (32 - (b))))
+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */
+#define S64(b,x)       (((x) >> (b)) | ((x) << (64 - (b))))
+
+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */
+#define Ch(x,y,z)      (((x) & (y)) ^ ((~(x)) & (z)))
+#define Maj(x,y,z)     (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+
+/* Four of six logical functions used in SHA-256: */
+#define Sigma0_256(x)  (S32(2,  (x)) ^ S32(13, (x)) ^ S32(22, (x)))
+#define Sigma1_256(x)  (S32(6,  (x)) ^ S32(11, (x)) ^ S32(25, (x)))
+#define sigma0_256(x)  (S32(7,  (x)) ^ S32(18, (x)) ^ R(3 ,   (x)))
+#define sigma1_256(x)  (S32(17, (x)) ^ S32(19, (x)) ^ R(10,   (x)))
+
+/* Four of six logical functions used in SHA-384 and SHA-512: */
+#define Sigma0_512(x)  (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x)))
+#define Sigma1_512(x)  (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x)))
+#define sigma0_512(x)  (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7,   (x)))
+#define sigma1_512(x)  (S64(19, (x)) ^ S64(61, (x)) ^ R( 6,   (x)))
+
+
+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/
+/* Hash constant words K for SHA-256: */
+const static u_int32_t K256[64] = {
+       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
+       0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
+       0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
+       0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
+       0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
+       0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
+       0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
+       0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
+       0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
+       0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
+       0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
+       0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
+       0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Initial hash value H for SHA-256: */
+const static u_int32_t sha256_initial_hash_value[8] = {
+       0x6a09e667UL,
+       0xbb67ae85UL,
+       0x3c6ef372UL,
+       0xa54ff53aUL,
+       0x510e527fUL,
+       0x9b05688cUL,
+       0x1f83d9abUL,
+       0x5be0cd19UL
+};
+
+/* Hash constant words K for SHA-384 and SHA-512: */
+const static u_int64_t K512[80] = {
+       0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
+       0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+       0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+       0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+       0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
+       0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+       0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
+       0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+       0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+       0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+       0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
+       0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+       0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
+       0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+       0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+       0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+       0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
+       0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+       0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
+       0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+       0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+       0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+       0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
+       0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+       0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
+       0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+       0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+       0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+       0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
+       0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+       0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
+       0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+       0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+       0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+       0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
+       0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+       0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
+       0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+       0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+       0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
+};
+
+/* Initial hash value H for SHA-384 */
+const static u_int64_t sha384_initial_hash_value[8] = {
+       0xcbbb9d5dc1059ed8ULL,
+       0x629a292a367cd507ULL,
+       0x9159015a3070dd17ULL,
+       0x152fecd8f70e5939ULL,
+       0x67332667ffc00b31ULL,
+       0x8eb44a8768581511ULL,
+       0xdb0c2e0d64f98fa7ULL,
+       0x47b5481dbefa4fa4ULL
+};
+
+/* Initial hash value H for SHA-512 */
+const static u_int64_t sha512_initial_hash_value[8] = {
+       0x6a09e667f3bcc908ULL,
+       0xbb67ae8584caa73bULL,
+       0x3c6ef372fe94f82bULL,
+       0xa54ff53a5f1d36f1ULL,
+       0x510e527fade682d1ULL,
+       0x9b05688c2b3e6c1fULL,
+       0x1f83d9abfb41bd6bULL,
+       0x5be0cd19137e2179ULL
+};
+
+
+/*** SHA-256: *********************************************************/
+void
+SHA256_Init(SHA256_CTX *context)
+{
+       if (context == NULL)
+               return;
+       memcpy(context->state, sha256_initial_hash_value,
+           sizeof(sha256_initial_hash_value));
+       memset(context->buffer, 0, sizeof(context->buffer));
+       context->bitcount = 0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-256 round macros: */
+
+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) do {                             \
+       BE_8_TO_32(W256[j], data);                                          \
+       data += 4;                                                          \
+       T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] + W256[j]; \
+       (d) += T1;                                                          \
+       (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c));                    \
+       j++;                                                                \
+} while(0)
+
+#define ROUND256(a,b,c,d,e,f,g,h) do {                                     \
+       s0 = W256[(j+1)&0x0f];                                              \
+       s0 = sigma0_256(s0);                                                \
+       s1 = W256[(j+14)&0x0f];                                             \
+       s1 = sigma1_256(s1);                                                \
+       T1 = (h) + Sigma1_256((e)) + Ch((e), (f), (g)) + K256[j] +          \
+            (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);                  \
+       (d) += T1;                                                          \
+       (h) = T1 + Sigma0_256((a)) + Maj((a), (b), (c));                    \
+       j++;                                                                \
+} while(0)
+
+void
+SHA256_Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH])
+{
+       u_int32_t       a, b, c, d, e, f, g, h, s0, s1;
+       u_int32_t       T1, W256[16];
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       f = state[5];
+       g = state[6];
+       h = state[7];
+
+       j = 0;
+       do {
+               /* Rounds 0 to 15 (unrolled): */
+               ROUND256_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND256_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND256_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND256_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND256_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND256_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND256_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND256_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds up to 63: */
+       do {
+               ROUND256(a,b,c,d,e,f,g,h);
+               ROUND256(h,a,b,c,d,e,f,g);
+               ROUND256(g,h,a,b,c,d,e,f);
+               ROUND256(f,g,h,a,b,c,d,e);
+               ROUND256(e,f,g,h,a,b,c,d);
+               ROUND256(d,e,f,g,h,a,b,c);
+               ROUND256(c,d,e,f,g,h,a,b);
+               ROUND256(b,c,d,e,f,g,h,a);
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       state[5] += f;
+       state[6] += g;
+       state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void
+SHA256_Transform(u_int32_t state[8], const u_int8_t data[SHA256_BLOCK_LENGTH])
+{
+       u_int32_t       a, b, c, d, e, f, g, h, s0, s1;
+       u_int32_t       T1, T2, W256[16];
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       f = state[5];
+       g = state[6];
+       h = state[7];
+
+       j = 0;
+       do {
+               BE_8_TO_32(W256[j], data);
+               data += 4;
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j];
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W256[(j+1)&0x0f];
+               s0 = sigma0_256(s0);
+               s1 = W256[(j+14)&0x0f]; 
+               s1 = sigma1_256(s1);
+
+               /* Apply the SHA-256 compression function to update a..h */
+               T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + 
+                    (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0);
+               T2 = Sigma0_256(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 64);
+
+       /* Compute the current intermediate hash value */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       state[5] += f;
+       state[6] += g;
+       state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void
+SHA256_Update(SHA256_CTX *context, const u_int8_t *data, size_t len)
+{
+       size_t  freespace, usedspace;
+
+       /* Calling with no data is valid (we do nothing) */
+       if (len == 0)
+               return;
+
+       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA256_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       memcpy(&context->buffer[usedspace], data, freespace);
+                       context->bitcount += freespace << 3;
+                       len -= freespace;
+                       data += freespace;
+                       SHA256_Transform(context->state, context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       memcpy(&context->buffer[usedspace], data, len);
+                       context->bitcount += len << 3;
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA256_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA256_Transform(context->state, data);
+               context->bitcount += SHA256_BLOCK_LENGTH << 3;
+               len -= SHA256_BLOCK_LENGTH;
+               data += SHA256_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               memcpy(context->buffer, data, len);
+               context->bitcount += len << 3;
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void
+SHA256_Pad(SHA256_CTX *context)
+{
+       unsigned int    usedspace;
+
+       usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               context->buffer[usedspace++] = 0x80;
+
+               if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       memset(&context->buffer[usedspace], 0,
+                           SHA256_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA256_BLOCK_LENGTH) {
+                               memset(&context->buffer[usedspace], 0,
+                                   SHA256_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA256_Transform(context->state, context->buffer);
+
+                       /* Prepare for last transform: */
+                       memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+               }
+       } else {
+               /* Set-up for the last transform: */
+               memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *context->buffer = 0x80;
+       }
+       /* Store the length of input data (in bits) in big endian format: */
+       BE_64_TO_8(&context->buffer[SHA256_SHORT_BLOCK_LENGTH],
+           context->bitcount);
+
+       /* Final transform: */
+       SHA256_Transform(context->state, context->buffer);
+
+       /* Clean up: */
+       usedspace = 0;
+}
+
+void
+SHA256_Final(u_int8_t digest[SHA256_DIGEST_LENGTH], SHA256_CTX *context)
+{
+       SHA256_Pad(context);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != NULL) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               int     i;
+
+               /* Convert TO host byte order */
+               for (i = 0; i < 8; i++)
+                       BE_32_TO_8(digest + i * 4, context->state[i]);
+#else
+               memcpy(digest, context->state, SHA256_DIGEST_LENGTH);
+#endif
+               memset(context, 0, sizeof(*context));
+       }
+}
+
+
+/*** SHA-512: *********************************************************/
+void
+SHA512_Init(SHA512_CTX *context)
+{
+       if (context == NULL)
+               return;
+       memcpy(context->state, sha512_initial_hash_value,
+           sizeof(sha512_initial_hash_value));
+       memset(context->buffer, 0, sizeof(context->buffer));
+       context->bitcount[0] = context->bitcount[1] =  0;
+}
+
+#ifdef SHA2_UNROLL_TRANSFORM
+
+/* Unrolled SHA-512 round macros: */
+
+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) do {                             \
+       BE_8_TO_64(W512[j], data);                                          \
+       data += 8;                                                          \
+       T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] + W512[j]; \
+       (d) += T1;                                                          \
+       (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c));                    \
+       j++;                                                                \
+} while(0)
+
+
+#define ROUND512(a,b,c,d,e,f,g,h) do {                                     \
+       s0 = W512[(j+1)&0x0f];                                              \
+       s0 = sigma0_512(s0);                                                \
+       s1 = W512[(j+14)&0x0f];                                             \
+       s1 = sigma1_512(s1);                                                \
+       T1 = (h) + Sigma1_512((e)) + Ch((e), (f), (g)) + K512[j] +          \
+             (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);                 \
+       (d) += T1;                                                          \
+       (h) = T1 + Sigma0_512((a)) + Maj((a), (b), (c));                    \
+       j++;                                                                \
+} while(0)
+
+void
+SHA512_Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH])
+{
+       u_int64_t       a, b, c, d, e, f, g, h, s0, s1;
+       u_int64_t       T1, W512[16];
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       f = state[5];
+       g = state[6];
+       h = state[7];
+
+       j = 0;
+       do {
+               /* Rounds 0 to 15 (unrolled): */
+               ROUND512_0_TO_15(a,b,c,d,e,f,g,h);
+               ROUND512_0_TO_15(h,a,b,c,d,e,f,g);
+               ROUND512_0_TO_15(g,h,a,b,c,d,e,f);
+               ROUND512_0_TO_15(f,g,h,a,b,c,d,e);
+               ROUND512_0_TO_15(e,f,g,h,a,b,c,d);
+               ROUND512_0_TO_15(d,e,f,g,h,a,b,c);
+               ROUND512_0_TO_15(c,d,e,f,g,h,a,b);
+               ROUND512_0_TO_15(b,c,d,e,f,g,h,a);
+       } while (j < 16);
+
+       /* Now for the remaining rounds up to 79: */
+       do {
+               ROUND512(a,b,c,d,e,f,g,h);
+               ROUND512(h,a,b,c,d,e,f,g);
+               ROUND512(g,h,a,b,c,d,e,f);
+               ROUND512(f,g,h,a,b,c,d,e);
+               ROUND512(e,f,g,h,a,b,c,d);
+               ROUND512(d,e,f,g,h,a,b,c);
+               ROUND512(c,d,e,f,g,h,a,b);
+               ROUND512(b,c,d,e,f,g,h,a);
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       state[5] += f;
+       state[6] += g;
+       state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = 0;
+}
+
+#else /* SHA2_UNROLL_TRANSFORM */
+
+void
+SHA512_Transform(u_int64_t state[8], const u_int8_t data[SHA512_BLOCK_LENGTH])
+{
+       u_int64_t       a, b, c, d, e, f, g, h, s0, s1;
+       u_int64_t       T1, T2, W512[16];
+       int             j;
+
+       /* Initialize registers with the prev. intermediate value */
+       a = state[0];
+       b = state[1];
+       c = state[2];
+       d = state[3];
+       e = state[4];
+       f = state[5];
+       g = state[6];
+       h = state[7];
+
+       j = 0;
+       do {
+               BE_8_TO_64(W512[j], data);
+               data += 8;
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j];
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 16);
+
+       do {
+               /* Part of the message block expansion: */
+               s0 = W512[(j+1)&0x0f];
+               s0 = sigma0_512(s0);
+               s1 = W512[(j+14)&0x0f];
+               s1 =  sigma1_512(s1);
+
+               /* Apply the SHA-512 compression function to update a..h */
+               T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] +
+                    (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0);
+               T2 = Sigma0_512(a) + Maj(a, b, c);
+               h = g;
+               g = f;
+               f = e;
+               e = d + T1;
+               d = c;
+               c = b;
+               b = a;
+               a = T1 + T2;
+
+               j++;
+       } while (j < 80);
+
+       /* Compute the current intermediate hash value */
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+       state[4] += e;
+       state[5] += f;
+       state[6] += g;
+       state[7] += h;
+
+       /* Clean up */
+       a = b = c = d = e = f = g = h = T1 = T2 = 0;
+}
+
+#endif /* SHA2_UNROLL_TRANSFORM */
+
+void
+SHA512_Update(SHA512_CTX *context, const u_int8_t *data, size_t len)
+{
+       size_t  freespace, usedspace;
+
+       /* Calling with no data is valid (we do nothing) */
+       if (len == 0)
+               return;
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Calculate how much free space is available in the buffer */
+               freespace = SHA512_BLOCK_LENGTH - usedspace;
+
+               if (len >= freespace) {
+                       /* Fill the buffer completely and process it */
+                       memcpy(&context->buffer[usedspace], data, freespace);
+                       ADDINC128(context->bitcount, freespace << 3);
+                       len -= freespace;
+                       data += freespace;
+                       SHA512_Transform(context->state, context->buffer);
+               } else {
+                       /* The buffer is not yet full */
+                       memcpy(&context->buffer[usedspace], data, len);
+                       ADDINC128(context->bitcount, len << 3);
+                       /* Clean up: */
+                       usedspace = freespace = 0;
+                       return;
+               }
+       }
+       while (len >= SHA512_BLOCK_LENGTH) {
+               /* Process as many complete blocks as we can */
+               SHA512_Transform(context->state, data);
+               ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
+               len -= SHA512_BLOCK_LENGTH;
+               data += SHA512_BLOCK_LENGTH;
+       }
+       if (len > 0) {
+               /* There's left-overs, so save 'em */
+               memcpy(context->buffer, data, len);
+               ADDINC128(context->bitcount, len << 3);
+       }
+       /* Clean up: */
+       usedspace = freespace = 0;
+}
+
+void
+SHA512_Pad(SHA512_CTX *context)
+{
+       unsigned int    usedspace;
+
+       usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
+       if (usedspace > 0) {
+               /* Begin padding with a 1 bit: */
+               context->buffer[usedspace++] = 0x80;
+
+               if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
+                       /* Set-up for the last transform: */
+                       memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace);
+               } else {
+                       if (usedspace < SHA512_BLOCK_LENGTH) {
+                               memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
+                       }
+                       /* Do second-to-last transform: */
+                       SHA512_Transform(context->state, context->buffer);
+
+                       /* And set-up for the last transform: */
+                       memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2);
+               }
+       } else {
+               /* Prepare for final transform: */
+               memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH);
+
+               /* Begin padding with a 1 bit: */
+               *context->buffer = 0x80;
+       }
+       /* Store the length of input data (in bits) in big endian format: */
+       BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH],
+           context->bitcount[1]);
+       BE_64_TO_8(&context->buffer[SHA512_SHORT_BLOCK_LENGTH + 8],
+           context->bitcount[0]);
+
+       /* Final transform: */
+       SHA512_Transform(context->state, context->buffer);
+
+       /* Clean up: */
+       usedspace = 0;
+}
+
+void
+SHA512_Final(u_int8_t digest[SHA512_DIGEST_LENGTH], SHA512_CTX *context)
+{
+       SHA512_Pad(context);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != NULL) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               int     i;
+
+               /* Convert TO host byte order */
+               for (i = 0; i < 8; i++)
+                       BE_64_TO_8(digest + i * 8, context->state[i]);
+#else
+               memcpy(digest, context->state, SHA512_DIGEST_LENGTH);
+#endif
+               memset(context, 0, sizeof(*context));
+       }
+}
+
+
+#if 0
+/*** SHA-384: *********************************************************/
+void
+SHA384_Init(SHA384_CTX *context)
+{
+       if (context == NULL)
+               return;
+       memcpy(context->state, sha384_initial_hash_value,
+           sizeof(sha384_initial_hash_value));
+       memset(context->buffer, 0, sizeof(context->buffer));
+       context->bitcount[0] = context->bitcount[1] = 0;
+}
+
+__weak_alias(SHA384_Transform, SHA512_Transform);
+__weak_alias(SHA384_Update, SHA512_Update);
+__weak_alias(SHA384_Pad, SHA512_Pad);
+
+void
+SHA384_Final(u_int8_t digest[SHA384_DIGEST_LENGTH], SHA384_CTX *context)
+{
+       SHA384_Pad(context);
+
+       /* If no digest buffer is passed, we don't bother doing this: */
+       if (digest != NULL) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+               int     i;
+
+               /* Convert TO host byte order */
+               for (i = 0; i < 6; i++)
+                       BE_64_TO_8(digest + i * 8, context->state[i]);
+#else
+               memcpy(digest, context->state, SHA384_DIGEST_LENGTH);
+#endif
+       }
+
+       /* Zero out state data */
+       memset(context, 0, sizeof(*context));
+}
+#endif
+
+#endif /* !defined(HAVE_EVP_SHA256) && !defined(HAVE_SHA256_UPDATE) && \
+    (OPENSSL_VERSION_NUMBER >= 0x00907000L) */
diff --git a/openbsd-compat/sha2.h b/openbsd-compat/sha2.h
new file mode 100755 (executable)
index 0000000..821f2dd
--- /dev/null
@@ -0,0 +1,133 @@
+/*     $OpenBSD: sha2.h,v 1.6 2004/06/22 01:57:30 jfb Exp $    */
+
+/*
+ * FILE:       sha2.h
+ * AUTHOR:     Aaron D. Gifford <me@aarongifford.com>
+ * 
+ * Copyright (c) 2000-2001, Aaron D. Gifford
+ * 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. Neither the name of the copyright holder nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``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 OR CONTRIBUTOR(S) 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.
+ *
+ * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $
+ */
+
+/* OPENBSD ORIGINAL: include/sha2.h */
+
+#ifndef _SSHSHA2_H
+#define _SSHSHA2_H
+
+#include "includes.h"
+
+#include <openssl/opensslv.h>
+
+#if !defined(HAVE_EVP_SHA256) && !defined(HAVE_SHA256_UPDATE) && \
+    (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+
+/*** SHA-256/384/512 Various Length Definitions ***********************/
+#define SHA256_BLOCK_LENGTH            64
+#define SHA256_DIGEST_LENGTH           32
+#define SHA256_DIGEST_STRING_LENGTH    (SHA256_DIGEST_LENGTH * 2 + 1)
+#define SHA384_BLOCK_LENGTH            128
+#define SHA384_DIGEST_LENGTH           48
+#define SHA384_DIGEST_STRING_LENGTH    (SHA384_DIGEST_LENGTH * 2 + 1)
+#define SHA512_BLOCK_LENGTH            128
+#define SHA512_DIGEST_LENGTH           64
+#define SHA512_DIGEST_STRING_LENGTH    (SHA512_DIGEST_LENGTH * 2 + 1)
+
+
+/*** SHA-256/384/512 Context Structures *******************************/
+typedef struct _SHA256_CTX {
+       u_int32_t       state[8];
+       u_int64_t       bitcount;
+       u_int8_t        buffer[SHA256_BLOCK_LENGTH];
+} SHA256_CTX;
+typedef struct _SHA512_CTX {
+       u_int64_t       state[8];
+       u_int64_t       bitcount[2];
+       u_int8_t        buffer[SHA512_BLOCK_LENGTH];
+} SHA512_CTX;
+
+#if 0
+typedef SHA512_CTX SHA384_CTX;
+#endif
+
+void SHA256_Init(SHA256_CTX *);
+void SHA256_Transform(u_int32_t state[8], const u_int8_t [SHA256_BLOCK_LENGTH]);
+void SHA256_Update(SHA256_CTX *, const u_int8_t *, size_t)
+       __attribute__((__bounded__(__string__,2,3)));
+void SHA256_Pad(SHA256_CTX *);
+void SHA256_Final(u_int8_t [SHA256_DIGEST_LENGTH], SHA256_CTX *)
+       __attribute__((__bounded__(__minbytes__,1,SHA256_DIGEST_LENGTH)));
+char *SHA256_End(SHA256_CTX *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH)));
+char *SHA256_File(const char *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH)));
+char *SHA256_FileChunk(const char *, char *, off_t, off_t)
+       __attribute__((__bounded__(__minbytes__,2,SHA256_DIGEST_STRING_LENGTH)));
+char *SHA256_Data(const u_int8_t *, size_t, char *)
+       __attribute__((__bounded__(__string__,1,2)))
+       __attribute__((__bounded__(__minbytes__,3,SHA256_DIGEST_STRING_LENGTH)));
+
+#if 0
+void SHA384_Init(SHA384_CTX *);
+void SHA384_Transform(u_int64_t state[8], const u_int8_t [SHA384_BLOCK_LENGTH]);
+void SHA384_Update(SHA384_CTX *, const u_int8_t *, size_t)
+       __attribute__((__bounded__(__string__,2,3)));
+void SHA384_Pad(SHA384_CTX *);
+void SHA384_Final(u_int8_t [SHA384_DIGEST_LENGTH], SHA384_CTX *)
+       __attribute__((__bounded__(__minbytes__,1,SHA384_DIGEST_LENGTH)));
+char *SHA384_End(SHA384_CTX *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH)));
+char *SHA384_File(const char *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH)));
+char *SHA384_FileChunk(const char *, char *, off_t, off_t)
+       __attribute__((__bounded__(__minbytes__,2,SHA384_DIGEST_STRING_LENGTH)));
+char *SHA384_Data(const u_int8_t *, size_t, char *)
+       __attribute__((__bounded__(__string__,1,2)))
+       __attribute__((__bounded__(__minbytes__,3,SHA384_DIGEST_STRING_LENGTH)));
+#endif /* 0 */
+
+void SHA512_Init(SHA512_CTX *);
+void SHA512_Transform(u_int64_t state[8], const u_int8_t [SHA512_BLOCK_LENGTH]);
+void SHA512_Update(SHA512_CTX *, const u_int8_t *, size_t)
+       __attribute__((__bounded__(__string__,2,3)));
+void SHA512_Pad(SHA512_CTX *);
+void SHA512_Final(u_int8_t [SHA512_DIGEST_LENGTH], SHA512_CTX *)
+       __attribute__((__bounded__(__minbytes__,1,SHA512_DIGEST_LENGTH)));
+char *SHA512_End(SHA512_CTX *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH)));
+char *SHA512_File(const char *, char *)
+       __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH)));
+char *SHA512_FileChunk(const char *, char *, off_t, off_t)
+       __attribute__((__bounded__(__minbytes__,2,SHA512_DIGEST_STRING_LENGTH)));
+char *SHA512_Data(const u_int8_t *, size_t, char *)
+       __attribute__((__bounded__(__string__,1,2)))
+       __attribute__((__bounded__(__minbytes__,3,SHA512_DIGEST_STRING_LENGTH)));
+
+#endif /* !defined(HAVE_EVP_SHA256) && !defined(HAVE_SHA256_UPDATE) && \
+    (OPENSSL_VERSION_NUMBER >= 0x00907000L) */
+
+#endif /* _SSHSHA2_H */
diff --git a/openbsd-compat/sigact.c b/openbsd-compat/sigact.c
new file mode 100644 (file)
index 0000000..d67845c
--- /dev/null
@@ -0,0 +1,132 @@
+/*     $OpenBSD: sigaction.c,v 1.4 2001/01/22 18:01:48 millert Exp $   */
+
+/****************************************************************************
+ * Copyright (c) 1998,2000 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>                         *
+ ****************************************************************************/
+
+/* OPENBSD ORIGINAL: lib/libcurses/base/sigaction.c */
+
+#include "includes.h"
+#include <errno.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 ? &sigact->sv : NULL,
+           osigact ? &osigact->sv : NULL);
+}
+
+int
+sigemptyset (sigset_t *mask)
+{
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+       *mask = 0;
+       return 0;
+}
+
+int
+sigprocmask (int mode, sigset_t *mask, sigset_t *omask)
+{
+       sigset_t current = sigsetmask(0);
+
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       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)
+{
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+       return sigpause(*mask);
+}
+
+int
+sigdelset (sigset_t *mask, int sig)
+{
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+       *mask &= ~sigmask(sig);
+       return 0;
+}
+
+int
+sigaddset (sigset_t *mask, int sig)
+{
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+       *mask |= sigmask(sig);
+       return 0;
+}
+
+int
+sigismember (sigset_t *mask, int sig)
+{
+       if (!mask) {
+               errno = EINVAL;
+               return -1;
+       }
+       return (*mask & sigmask(sig)) != 0;
+}
+
+#endif
diff --git a/openbsd-compat/sigact.h b/openbsd-compat/sigact.h
new file mode 100644 (file)
index 0000000..db96d0a
--- /dev/null
@@ -0,0 +1,90 @@
+/*     $OpenBSD: SigAction.h,v 1.3 2001/01/22 18:01:32 millert Exp $   */
+
+/****************************************************************************
+ * Copyright (c) 1998,2000 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.6 2000/12/10 02:36:10 tom Exp $
+ *
+ * This file exists to handle non-POSIX systems which don't have <unistd.h>,
+ * and usually no sigaction() nor <termios.h>
+ */
+
+/* OPENBSD ORIGINAL: lib/libcurses/SigAction.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/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c
new file mode 100644 (file)
index 0000000..bcc1b61
--- /dev/null
@@ -0,0 +1,62 @@
+/*     $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $      */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
+
+#include "includes.h"
+#ifndef HAVE_STRLCAT
+
+#include <sys/types.h>
+#include <string.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(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       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/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c
new file mode 100644 (file)
index 0000000..679a5b2
--- /dev/null
@@ -0,0 +1,58 @@
+/*     $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $      */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
+
+#include "includes.h"
+#ifndef HAVE_STRLCPY
+
+#include <sys/types.h>
+#include <string.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(char *dst, const char *src, size_t siz)
+{
+       char *d = dst;
+       const char *s = src;
+       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/openbsd-compat/strmode.c b/openbsd-compat/strmode.c
new file mode 100644 (file)
index 0000000..4a81614
--- /dev/null
@@ -0,0 +1,148 @@
+/*     $OpenBSD: strmode.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
+/*-
+ * 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strmode.c */
+
+#include "includes.h"
+#ifndef HAVE_STRMODE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+
+/* XXX mode should be mode_t */
+
+void
+strmode(int mode, 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
+       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/openbsd-compat/strptime.c b/openbsd-compat/strptime.c
new file mode 100644 (file)
index 0000000..d8d83d9
--- /dev/null
@@ -0,0 +1,401 @@
+/*     $OpenBSD: strptime.c,v 1.12 2008/06/26 05:42:05 ray Exp $ */
+/*     $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $    */
+
+/*-
+ * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Klaus Klein.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/time/strptime.c */
+
+#include "includes.h"
+
+#ifndef HAVE_STRPTIME
+
+#define TM_YEAR_BASE 1900      /* from tzfile.h */
+
+#include <ctype.h>
+#include <locale.h>
+#include <string.h>
+#include <time.h>
+
+/* #define     _ctloc(x)               (_CurrentTimeLocale->x) */
+
+/*
+ * We do not implement alternate representations. However, we always
+ * check whether a given modifier is allowed for a certain conversion.
+ */
+#define _ALT_E                 0x01
+#define _ALT_O                 0x02
+#define        _LEGAL_ALT(x)           { if (alt_format & ~(x)) return (0); }
+
+
+static int _conv_num(const unsigned char **, int *, int, int);
+static char *_strptime(const char *, const char *, struct tm *, int);
+
+
+char *
+strptime(const char *buf, const char *fmt, struct tm *tm)
+{
+       return(_strptime(buf, fmt, tm, 1));
+}
+
+static char *
+_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize)
+{
+       unsigned char c;
+       const unsigned char *bp;
+       size_t len;
+       int alt_format, i;
+       static int century, relyear;
+
+       if (initialize) {
+               century = TM_YEAR_BASE;
+               relyear = -1;
+       }
+
+       bp = (unsigned char *)buf;
+       while ((c = *fmt) != '\0') {
+               /* Clear `alternate' modifier prior to new conversion. */
+               alt_format = 0;
+
+               /* Eat up white-space. */
+               if (isspace(c)) {
+                       while (isspace(*bp))
+                               bp++;
+
+                       fmt++;
+                       continue;
+               }
+                               
+               if ((c = *fmt++) != '%')
+                       goto literal;
+
+
+again:         switch (c = *fmt++) {
+               case '%':       /* "%%" is converted to "%". */
+literal:
+               if (c != *bp++)
+                       return (NULL);
+
+               break;
+
+               /*
+                * "Alternative" modifiers. Just set the appropriate flag
+                * and start over again.
+                */
+               case 'E':       /* "%E?" alternative conversion modifier. */
+                       _LEGAL_ALT(0);
+                       alt_format |= _ALT_E;
+                       goto again;
+
+               case 'O':       /* "%O?" alternative conversion modifier. */
+                       _LEGAL_ALT(0);
+                       alt_format |= _ALT_O;
+                       goto again;
+                       
+               /*
+                * "Complex" conversion rules, implemented through recursion.
+                */
+#if 0
+               case 'c':       /* Date and time, using the locale's format. */
+                       _LEGAL_ALT(_ALT_E);
+                       if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0)))
+                               return (NULL);
+                       break;
+#endif
+               case 'D':       /* The date as "%m/%d/%y". */
+                       _LEGAL_ALT(0);
+                       if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0)))
+                               return (NULL);
+                       break;
+       
+               case 'R':       /* The time as "%H:%M". */
+                       _LEGAL_ALT(0);
+                       if (!(bp = _strptime(bp, "%H:%M", tm, 0)))
+                               return (NULL);
+                       break;
+
+               case 'r':       /* The time as "%I:%M:%S %p". */
+                       _LEGAL_ALT(0);
+                       if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0)))
+                               return (NULL);
+                       break;
+
+               case 'T':       /* The time as "%H:%M:%S". */
+                       _LEGAL_ALT(0);
+                       if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0)))
+                               return (NULL);
+                       break;
+#if 0
+               case 'X':       /* The time, using the locale's format. */
+                       _LEGAL_ALT(_ALT_E);
+                       if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))
+                               return (NULL);
+                       break;
+
+               case 'x':       /* The date, using the locale's format. */
+                       _LEGAL_ALT(_ALT_E);
+                       if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0)))
+                               return (NULL);
+                       break;
+#endif
+               /*
+                * "Elementary" conversion rules.
+                */
+#if 0
+               case 'A':       /* The day of week, using the locale's form. */
+               case 'a':
+                       _LEGAL_ALT(0);
+                       for (i = 0; i < 7; i++) {
+                               /* Full name. */
+                               len = strlen(_ctloc(day[i]));
+                               if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
+                                       break;
+
+                               /* Abbreviated name. */
+                               len = strlen(_ctloc(abday[i]));
+                               if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
+                                       break;
+                       }
+
+                       /* Nothing matched. */
+                       if (i == 7)
+                               return (NULL);
+
+                       tm->tm_wday = i;
+                       bp += len;
+                       break;
+
+               case 'B':       /* The month, using the locale's form. */
+               case 'b':
+               case 'h':
+                       _LEGAL_ALT(0);
+                       for (i = 0; i < 12; i++) {
+                               /* Full name. */
+                               len = strlen(_ctloc(mon[i]));
+                               if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
+                                       break;
+
+                               /* Abbreviated name. */
+                               len = strlen(_ctloc(abmon[i]));
+                               if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
+                                       break;
+                       }
+
+                       /* Nothing matched. */
+                       if (i == 12)
+                               return (NULL);
+
+                       tm->tm_mon = i;
+                       bp += len;
+                       break;
+#endif
+
+               case 'C':       /* The century number. */
+                       _LEGAL_ALT(_ALT_E);
+                       if (!(_conv_num(&bp, &i, 0, 99)))
+                               return (NULL);
+
+                       century = i * 100;
+                       break;
+
+               case 'd':       /* The day of month. */
+               case 'e':
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
+                               return (NULL);
+                       break;
+
+               case 'k':       /* The hour (24-hour clock representation). */
+                       _LEGAL_ALT(0);
+                       /* FALLTHROUGH */
+               case 'H':
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
+                               return (NULL);
+                       break;
+
+               case 'l':       /* The hour (12-hour clock representation). */
+                       _LEGAL_ALT(0);
+                       /* FALLTHROUGH */
+               case 'I':
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
+                               return (NULL);
+                       break;
+
+               case 'j':       /* The day of year. */
+                       _LEGAL_ALT(0);
+                       if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
+                               return (NULL);
+                       tm->tm_yday--;
+                       break;
+
+               case 'M':       /* The minute. */
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
+                               return (NULL);
+                       break;
+
+               case 'm':       /* The month. */
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
+                               return (NULL);
+                       tm->tm_mon--;
+                       break;
+
+#if 0
+               case 'p':       /* The locale's equivalent of AM/PM. */
+                       _LEGAL_ALT(0);
+                       /* AM? */
+                       len = strlen(_ctloc(am_pm[0]));
+                       if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) {
+                               if (tm->tm_hour > 12)   /* i.e., 13:00 AM ?! */
+                                       return (NULL);
+                               else if (tm->tm_hour == 12)
+                                       tm->tm_hour = 0;
+
+                               bp += len;
+                               break;
+                       }
+                       /* PM? */
+                       len = strlen(_ctloc(am_pm[1]));
+                       if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) {
+                               if (tm->tm_hour > 12)   /* i.e., 13:00 PM ?! */
+                                       return (NULL);
+                               else if (tm->tm_hour < 12)
+                                       tm->tm_hour += 12;
+
+                               bp += len;
+                               break;
+                       }
+
+                       /* Nothing matched. */
+                       return (NULL);
+#endif
+               case 'S':       /* The seconds. */
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
+                               return (NULL);
+                       break;
+
+               case 'U':       /* The week of year, beginning on sunday. */
+               case 'W':       /* The week of year, beginning on monday. */
+                       _LEGAL_ALT(_ALT_O);
+                       /*
+                        * XXX This is bogus, as we can not assume any valid
+                        * information present in the tm structure at this
+                        * point to calculate a real value, so just check the
+                        * range for now.
+                        */
+                        if (!(_conv_num(&bp, &i, 0, 53)))
+                               return (NULL);
+                        break;
+
+               case 'w':       /* The day of week, beginning on sunday. */
+                       _LEGAL_ALT(_ALT_O);
+                       if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
+                               return (NULL);
+                       break;
+
+               case 'Y':       /* The year. */
+                       _LEGAL_ALT(_ALT_E);
+                       if (!(_conv_num(&bp, &i, 0, 9999)))
+                               return (NULL);
+
+                       relyear = -1;
+                       tm->tm_year = i - TM_YEAR_BASE;
+                       break;
+
+               case 'y':       /* The year within the century (2 digits). */
+                       _LEGAL_ALT(_ALT_E | _ALT_O);
+                       if (!(_conv_num(&bp, &relyear, 0, 99)))
+                               return (NULL);
+                       break;
+
+               /*
+                * Miscellaneous conversions.
+                */
+               case 'n':       /* Any kind of white-space. */
+               case 't':
+                       _LEGAL_ALT(0);
+                       while (isspace(*bp))
+                               bp++;
+                       break;
+
+
+               default:        /* Unknown/unsupported conversion. */
+                       return (NULL);
+               }
+
+
+       }
+
+       /*
+        * We need to evaluate the two digit year spec (%y)
+        * last as we can get a century spec (%C) at any time.
+        */
+       if (relyear != -1) {
+               if (century == TM_YEAR_BASE) {
+                       if (relyear <= 68)
+                               tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
+                       else
+                               tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
+               } else {
+                       tm->tm_year = relyear + century - TM_YEAR_BASE;
+               }
+       }
+
+       return ((char *)bp);
+}
+
+
+static int
+_conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
+{
+       int result = 0;
+       int rulim = ulim;
+
+       if (**buf < '0' || **buf > '9')
+               return (0);
+
+       /* we use rulim to break out of the loop when we run out of digits */
+       do {
+               result *= 10;
+               result += *(*buf)++ - '0';
+               rulim /= 10;
+       } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
+
+       if (result < llim || result > ulim)
+               return (0);
+
+       *dest = result;
+       return (1);
+}
+
+#endif /* HAVE_STRPTIME */
+
diff --git a/openbsd-compat/strsep.c b/openbsd-compat/strsep.c
new file mode 100644 (file)
index 0000000..b36eb8f
--- /dev/null
@@ -0,0 +1,79 @@
+/*     $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */
+
+#include "includes.h"
+
+#if !defined(HAVE_STRSEP)
+
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * 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)
+{
+       char *s;
+       const char *spanp;
+       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/openbsd-compat/strtoll.c b/openbsd-compat/strtoll.c
new file mode 100644 (file)
index 0000000..f629303
--- /dev/null
@@ -0,0 +1,148 @@
+/* $OpenBSD: strtoll.c,v 1.6 2005/11/10 10:00:17 espie Exp $ */
+/*-
+ * Copyright (c) 1992 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/strtoll.c */
+
+#include "includes.h"
+#ifndef HAVE_STRTOLL
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to a long long.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+long long
+strtoll(const char *nptr, char **endptr, int base)
+{
+       const char *s;
+       long long acc, cutoff;
+       int c;
+       int neg, any, cutlim;
+
+       /*
+        * Skip white space and pick up leading +/- sign if any.
+        * If base is 0, allow 0x for hex and 0 for octal, else
+        * assume decimal; if base is already 16, allow 0x.
+        */
+       s = nptr;
+       do {
+               c = (unsigned char) *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else {
+               neg = 0;
+               if (c == '+')
+                       c = *s++;
+       }
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       /*
+        * Compute the cutoff value between legal numbers and illegal
+        * numbers.  That is the largest legal value, divided by the
+        * base.  An input number that is greater than this value, if
+        * followed by a legal input character, is too big.  One that
+        * is equal to this value may be valid or not; the limit
+        * between valid and invalid numbers is then based on the last
+        * digit.  For instance, if the range for long longs is
+        * [-9223372036854775808..9223372036854775807] and the input base
+        * is 10, cutoff will be set to 922337203685477580 and cutlim to
+        * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+        * accumulated a value > 922337203685477580, or equal but the
+        * next digit is > 7 (or 8), the number is too big, and we will
+        * return a range error.
+        *
+        * Set any if any `digits' consumed; make it negative to indicate
+        * overflow.
+        */
+       cutoff = neg ? LLONG_MIN : LLONG_MAX;
+       cutlim = cutoff % base;
+       cutoff /= base;
+       if (neg) {
+               if (cutlim > 0) {
+                       cutlim -= base;
+                       cutoff += 1;
+               }
+               cutlim = -cutlim;
+       }
+       for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0)
+                       continue;
+               if (neg) {
+                       if (acc < cutoff || (acc == cutoff && c > cutlim)) {
+                               any = -1;
+                               acc = LLONG_MIN;
+                               errno = ERANGE;
+                       } else {
+                               any = 1;
+                               acc *= base;
+                               acc -= c;
+                       }
+               } else {
+                       if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+                               any = -1;
+                               acc = LLONG_MAX;
+                               errno = ERANGE;
+                       } else {
+                               any = 1;
+                               acc *= base;
+                               acc += c;
+                       }
+               }
+       }
+       if (endptr != 0)
+               *endptr = (char *) (any ? s - 1 : nptr);
+       return (acc);
+}
+#endif /* HAVE_STRTOLL */
diff --git a/openbsd-compat/strtonum.c b/openbsd-compat/strtonum.c
new file mode 100644 (file)
index 0000000..87f2f24
--- /dev/null
@@ -0,0 +1,72 @@
+/*     $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $    */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/strtonum.c */
+
+#include "includes.h"
+
+#ifndef HAVE_STRTONUM
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+
+#define INVALID        1
+#define TOOSMALL       2
+#define TOOLARGE       3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+       long long ll = 0;
+       char *ep;
+       int error = 0;
+       struct errval {
+               const char *errstr;
+               int err;
+       } ev[4] = {
+               { NULL,         0 },
+               { "invalid",    EINVAL },
+               { "too small",  ERANGE },
+               { "too large",  ERANGE },
+       };
+
+       ev[0].err = errno;
+       errno = 0;
+       if (minval > maxval)
+               error = INVALID;
+       else {
+               ll = strtoll(numstr, &ep, 10);
+               if (numstr == ep || *ep != '\0')
+                       error = INVALID;
+               else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+                       error = TOOSMALL;
+               else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+                       error = TOOLARGE;
+       }
+       if (errstrp != NULL)
+               *errstrp = ev[error].errstr;
+       errno = ev[error].err;
+       if (error)
+               ll = 0;
+
+       return (ll);
+}
+
+#endif /* HAVE_STRTONUM */
diff --git a/openbsd-compat/strtoul.c b/openbsd-compat/strtoul.c
new file mode 100644 (file)
index 0000000..8219c83
--- /dev/null
@@ -0,0 +1,108 @@
+/*     $OpenBSD: strtoul.c,v 1.7 2005/08/08 08:05:37 espie Exp $ */
+/*
+ * Copyright (c) 1990 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/strtoul.c */
+
+#include "includes.h"
+#ifndef HAVE_STRTOUL
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char *nptr, char **endptr, int base)
+{
+       const char *s;
+       unsigned long acc, cutoff;
+       int c;
+       int neg, any, cutlim;
+
+       /*
+        * See strtol for comments as to the logic used.
+        */
+       s = nptr;
+       do {
+               c = (unsigned char) *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else {
+               neg = 0;
+               if (c == '+')
+                       c = *s++;
+       }
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       cutoff = ULONG_MAX / (unsigned long)base;
+       cutlim = ULONG_MAX % (unsigned long)base;
+       for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0)
+                       continue;
+               if (acc > cutoff || acc == cutoff && c > cutlim) {
+                       any = -1;
+                       acc = ULONG_MAX;
+                       errno = ERANGE;
+               } else {
+                       any = 1;
+                       acc *= (unsigned long)base;
+                       acc += c;
+               }
+       }
+       if (neg && any > 0)
+               acc = -acc;
+       if (endptr != 0)
+               *endptr = (char *) (any ? s - 1 : nptr);
+       return (acc);
+}
+#endif /* !HAVE_STRTOUL */
diff --git a/openbsd-compat/sys-queue.h b/openbsd-compat/sys-queue.h
new file mode 100644 (file)
index 0000000..5cf0587
--- /dev/null
@@ -0,0 +1,612 @@
+/*     $OpenBSD: queue.h,v 1.32 2007/04/30 18:42:34 pedro 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. 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
+ */
+
+/* OPENBSD ORIGINAL: sys/sys/queue.h */
+
+#ifndef        _FAKE_QUEUE_H_
+#define        _FAKE_QUEUE_H_
+
+/*
+ * Require for OS/X and other platforms that have old/broken/incomplete
+ * <sys/queue.h>.
+ */
+#undef SLIST_HEAD
+#undef SLIST_HEAD_INITIALIZER
+#undef SLIST_ENTRY
+#undef SLIST_FOREACH_PREVPTR
+#undef SLIST_FIRST
+#undef SLIST_END
+#undef SLIST_EMPTY
+#undef SLIST_NEXT
+#undef SLIST_FOREACH
+#undef SLIST_INIT
+#undef SLIST_INSERT_AFTER
+#undef SLIST_INSERT_HEAD
+#undef SLIST_REMOVE_HEAD
+#undef SLIST_REMOVE
+#undef SLIST_REMOVE_NEXT
+#undef LIST_HEAD
+#undef LIST_HEAD_INITIALIZER
+#undef LIST_ENTRY
+#undef LIST_FIRST
+#undef LIST_END
+#undef LIST_EMPTY
+#undef LIST_NEXT
+#undef LIST_FOREACH
+#undef LIST_INIT
+#undef LIST_INSERT_AFTER
+#undef LIST_INSERT_BEFORE
+#undef LIST_INSERT_HEAD
+#undef LIST_REMOVE
+#undef LIST_REPLACE
+#undef SIMPLEQ_HEAD
+#undef SIMPLEQ_HEAD_INITIALIZER
+#undef SIMPLEQ_ENTRY
+#undef SIMPLEQ_FIRST
+#undef SIMPLEQ_END
+#undef SIMPLEQ_EMPTY
+#undef SIMPLEQ_NEXT
+#undef SIMPLEQ_FOREACH
+#undef SIMPLEQ_INIT
+#undef SIMPLEQ_INSERT_HEAD
+#undef SIMPLEQ_INSERT_TAIL
+#undef SIMPLEQ_INSERT_AFTER
+#undef SIMPLEQ_REMOVE_HEAD
+#undef TAILQ_HEAD
+#undef TAILQ_HEAD_INITIALIZER
+#undef TAILQ_ENTRY
+#undef TAILQ_FIRST
+#undef TAILQ_END
+#undef TAILQ_NEXT
+#undef TAILQ_LAST
+#undef TAILQ_PREV
+#undef TAILQ_EMPTY
+#undef TAILQ_FOREACH
+#undef TAILQ_FOREACH_REVERSE
+#undef TAILQ_INIT
+#undef TAILQ_INSERT_HEAD
+#undef TAILQ_INSERT_TAIL
+#undef TAILQ_INSERT_AFTER
+#undef TAILQ_INSERT_BEFORE
+#undef TAILQ_REMOVE
+#undef TAILQ_REPLACE
+#undef CIRCLEQ_HEAD
+#undef CIRCLEQ_HEAD_INITIALIZER
+#undef CIRCLEQ_ENTRY
+#undef CIRCLEQ_FIRST
+#undef CIRCLEQ_LAST
+#undef CIRCLEQ_END
+#undef CIRCLEQ_NEXT
+#undef CIRCLEQ_PREV
+#undef CIRCLEQ_EMPTY
+#undef CIRCLEQ_FOREACH
+#undef CIRCLEQ_FOREACH_REVERSE
+#undef CIRCLEQ_INIT
+#undef CIRCLEQ_INSERT_AFTER
+#undef CIRCLEQ_INSERT_BEFORE
+#undef CIRCLEQ_INSERT_HEAD
+#undef CIRCLEQ_INSERT_TAIL
+#undef CIRCLEQ_REMOVE
+#undef CIRCLEQ_REPLACE
+
+/*
+ * 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.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * 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))
+
+#define        SLIST_FOREACH_PREVPTR(var, varp, head, field)                   \
+       for ((varp) = &SLIST_FIRST((head));                             \
+           ((var) = *(varp)) != SLIST_END(head);                       \
+           (varp) = &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_NEXT(head, elm, field) do {                        \
+       (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;  \
+} while (0)
+
+#define        SLIST_REMOVE_HEAD(head, field) do {                             \
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {                      \
+       if ((head)->slh_first == (elm)) {                               \
+               SLIST_REMOVE_HEAD((head), field);                       \
+       } else {                                                        \
+               struct type *curelm = (head)->slh_first;                \
+                                                                       \
+               while (curelm->field.sle_next != (elm))                 \
+                       curelm = curelm->field.sle_next;                \
+               curelm->field.sle_next =                                \
+                   curelm->field.sle_next->field.sle_next;             \
+               _Q_INVALIDATE((elm)->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;                   \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((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);                                \
+       _Q_INVALIDATE((elm)->field.le_prev);                            \
+       _Q_INVALIDATE((elm)->field.le_next);                            \
+} 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, field) do {                  \
+       if (((head)->sqh_first = (head)->sqh_first->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, headname, field)              \
+       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;                 \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((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);                               \
+       _Q_INVALIDATE((elm)->field.tqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.tqe_next);                           \
+} 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;                              \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((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);        \
+       _Q_INVALIDATE((elm)->field.cqe_prev);                           \
+       _Q_INVALIDATE((elm)->field.cqe_next);                           \
+} while (0)
+
+#endif /* !_FAKE_QUEUE_H_ */
diff --git a/openbsd-compat/sys-tree.h b/openbsd-compat/sys-tree.h
new file mode 100644 (file)
index 0000000..d4949b5
--- /dev/null
@@ -0,0 +1,679 @@
+/*     $OpenBSD: tree.h,v 1.10 2007/10/29 23:49:41 djm Exp $   */
+/*
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 ORIGINAL: sys/sys/tree.h */
+
+#ifndef        _SYS_TREE_H_
+#define        _SYS_TREE_H_
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure.  Every operation
+ * on the tree causes a splay to happen.  The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree.  On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n).  The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute.  It fulfills a set of conditions:
+ *     - every search path from the root to a leaf consists of the
+ *       same number of black nodes,
+ *     - each red node (except for the root) has a black parent,
+ *     - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *sph_root; /* root of the tree */                   \
+}
+
+#define SPLAY_INITIALIZER(root)                                                \
+       { NULL }
+
+#define SPLAY_INIT(root) do {                                          \
+       (root)->sph_root = NULL;                                        \
+} while (0)
+
+#define SPLAY_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *spe_left; /* left element */                       \
+       struct type *spe_right; /* right element */                     \
+}
+
+#define SPLAY_LEFT(elm, field)         (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field)                (elm)->field.spe_right
+#define SPLAY_ROOT(head)               (head)->sph_root
+#define SPLAY_EMPTY(head)              (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do {                      \
+       SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field);  \
+       SPLAY_RIGHT(tmp, field) = (head)->sph_root;                     \
+       (head)->sph_root = tmp;                                         \
+} while (0)
+       
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do {                       \
+       SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field);  \
+       SPLAY_LEFT(tmp, field) = (head)->sph_root;                      \
+       (head)->sph_root = tmp;                                         \
+} while (0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do {                          \
+       SPLAY_LEFT(tmp, field) = (head)->sph_root;                      \
+       tmp = (head)->sph_root;                                         \
+       (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);         \
+} while (0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do {                         \
+       SPLAY_RIGHT(tmp, field) = (head)->sph_root;                     \
+       tmp = (head)->sph_root;                                         \
+       (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);        \
+} while (0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do {            \
+       SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+       SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
+       SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+       SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp)                                \
+void name##_SPLAY(struct name *, struct type *);                       \
+void name##_SPLAY_MINMAX(struct name *, int);                          \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *);                \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *);                \
+                                                                       \
+/* Finds the node with the same key as elm */                          \
+static __inline struct type *                                          \
+name##_SPLAY_FIND(struct name *head, struct type *elm)                 \
+{                                                                      \
+       if (SPLAY_EMPTY(head))                                          \
+               return(NULL);                                           \
+       name##_SPLAY(head, elm);                                        \
+       if ((cmp)(elm, (head)->sph_root) == 0)                          \
+               return (head->sph_root);                                \
+       return (NULL);                                                  \
+}                                                                      \
+                                                                       \
+static __inline struct type *                                          \
+name##_SPLAY_NEXT(struct name *head, struct type *elm)                 \
+{                                                                      \
+       name##_SPLAY(head, elm);                                        \
+       if (SPLAY_RIGHT(elm, field) != NULL) {                          \
+               elm = SPLAY_RIGHT(elm, field);                          \
+               while (SPLAY_LEFT(elm, field) != NULL) {                \
+                       elm = SPLAY_LEFT(elm, field);                   \
+               }                                                       \
+       } else                                                          \
+               elm = NULL;                                             \
+       return (elm);                                                   \
+}                                                                      \
+                                                                       \
+static __inline struct type *                                          \
+name##_SPLAY_MIN_MAX(struct name *head, int val)                       \
+{                                                                      \
+       name##_SPLAY_MINMAX(head, val);                                 \
+        return (SPLAY_ROOT(head));                                     \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp)                         \
+struct type *                                                          \
+name##_SPLAY_INSERT(struct name *head, struct type *elm)               \
+{                                                                      \
+    if (SPLAY_EMPTY(head)) {                                           \
+           SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL;    \
+    } else {                                                           \
+           int __comp;                                                 \
+           name##_SPLAY(head, elm);                                    \
+           __comp = (cmp)(elm, (head)->sph_root);                      \
+           if(__comp < 0) {                                            \
+                   SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
+                   SPLAY_RIGHT(elm, field) = (head)->sph_root;         \
+                   SPLAY_LEFT((head)->sph_root, field) = NULL;         \
+           } else if (__comp > 0) {                                    \
+                   SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
+                   SPLAY_LEFT(elm, field) = (head)->sph_root;          \
+                   SPLAY_RIGHT((head)->sph_root, field) = NULL;        \
+           } else                                                      \
+                   return ((head)->sph_root);                          \
+    }                                                                  \
+    (head)->sph_root = (elm);                                          \
+    return (NULL);                                                     \
+}                                                                      \
+                                                                       \
+struct type *                                                          \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm)               \
+{                                                                      \
+       struct type *__tmp;                                             \
+       if (SPLAY_EMPTY(head))                                          \
+               return (NULL);                                          \
+       name##_SPLAY(head, elm);                                        \
+       if ((cmp)(elm, (head)->sph_root) == 0) {                        \
+               if (SPLAY_LEFT((head)->sph_root, field) == NULL) {      \
+                       (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
+               } else {                                                \
+                       __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+                       (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
+                       name##_SPLAY(head, elm);                        \
+                       SPLAY_RIGHT((head)->sph_root, field) = __tmp;   \
+               }                                                       \
+               return (elm);                                           \
+       }                                                               \
+       return (NULL);                                                  \
+}                                                                      \
+                                                                       \
+void                                                                   \
+name##_SPLAY(struct name *head, struct type *elm)                      \
+{                                                                      \
+       struct type __node, *__left, *__right, *__tmp;                  \
+       int __comp;                                                     \
+\
+       SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+       __left = __right = &__node;                                     \
+\
+       while ((__comp = (cmp)(elm, (head)->sph_root))) {               \
+               if (__comp < 0) {                                       \
+                       __tmp = SPLAY_LEFT((head)->sph_root, field);    \
+                       if (__tmp == NULL)                              \
+                               break;                                  \
+                       if ((cmp)(elm, __tmp) < 0){                     \
+                               SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+                               if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+                                       break;                          \
+                       }                                               \
+                       SPLAY_LINKLEFT(head, __right, field);           \
+               } else if (__comp > 0) {                                \
+                       __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+                       if (__tmp == NULL)                              \
+                               break;                                  \
+                       if ((cmp)(elm, __tmp) > 0){                     \
+                               SPLAY_ROTATE_LEFT(head, __tmp, field);  \
+                               if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+                                       break;                          \
+                       }                                               \
+                       SPLAY_LINKRIGHT(head, __left, field);           \
+               }                                                       \
+       }                                                               \
+       SPLAY_ASSEMBLE(head, &__node, __left, __right, field);          \
+}                                                                      \
+                                                                       \
+/* Splay with either the minimum or the maximum element                        \
+ * Used to find minimum or maximum element in tree.                    \
+ */                                                                    \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{                                                                      \
+       struct type __node, *__left, *__right, *__tmp;                  \
+\
+       SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
+       __left = __right = &__node;                                     \
+\
+       while (1) {                                                     \
+               if (__comp < 0) {                                       \
+                       __tmp = SPLAY_LEFT((head)->sph_root, field);    \
+                       if (__tmp == NULL)                              \
+                               break;                                  \
+                       if (__comp < 0){                                \
+                               SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+                               if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
+                                       break;                          \
+                       }                                               \
+                       SPLAY_LINKLEFT(head, __right, field);           \
+               } else if (__comp > 0) {                                \
+                       __tmp = SPLAY_RIGHT((head)->sph_root, field);   \
+                       if (__tmp == NULL)                              \
+                               break;                                  \
+                       if (__comp > 0) {                               \
+                               SPLAY_ROTATE_LEFT(head, __tmp, field);  \
+                               if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
+                                       break;                          \
+                       }                                               \
+                       SPLAY_LINKRIGHT(head, __left, field);           \
+               }                                                       \
+       }                                                               \
+       SPLAY_ASSEMBLE(head, &__node, __left, __right, field);          \
+}
+
+#define SPLAY_NEGINF   -1
+#define SPLAY_INF      1
+
+#define SPLAY_INSERT(name, x, y)       name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y)       name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y)         name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y)         name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x)             (SPLAY_EMPTY(x) ? NULL  \
+                                       : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x)             (SPLAY_EMPTY(x) ? NULL  \
+                                       : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head)                                   \
+       for ((x) = SPLAY_MIN(name, head);                               \
+            (x) != NULL;                                               \
+            (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type)                                            \
+struct name {                                                          \
+       struct type *rbh_root; /* root of the tree */                   \
+}
+
+#define RB_INITIALIZER(root)                                           \
+       { NULL }
+
+#define RB_INIT(root) do {                                             \
+       (root)->rbh_root = NULL;                                        \
+} while (0)
+
+#define RB_BLACK       0
+#define RB_RED         1
+#define RB_ENTRY(type)                                                 \
+struct {                                                               \
+       struct type *rbe_left;          /* left element */              \
+       struct type *rbe_right;         /* right element */             \
+       struct type *rbe_parent;        /* parent element */            \
+       int rbe_color;                  /* node color */                \
+}
+
+#define RB_LEFT(elm, field)            (elm)->field.rbe_left
+#define RB_RIGHT(elm, field)           (elm)->field.rbe_right
+#define RB_PARENT(elm, field)          (elm)->field.rbe_parent
+#define RB_COLOR(elm, field)           (elm)->field.rbe_color
+#define RB_ROOT(head)                  (head)->rbh_root
+#define RB_EMPTY(head)                 (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do {                                        \
+       RB_PARENT(elm, field) = parent;                                 \
+       RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL;              \
+       RB_COLOR(elm, field) = RB_RED;                                  \
+} while (0)
+
+#define RB_SET_BLACKRED(black, red, field) do {                                \
+       RB_COLOR(black, field) = RB_BLACK;                              \
+       RB_COLOR(red, field) = RB_RED;                                  \
+} while (0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do {                     \
+       (tmp) = RB_RIGHT(elm, field);                                   \
+       if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) {             \
+               RB_PARENT(RB_LEFT(tmp, field), field) = (elm);          \
+       }                                                               \
+       RB_AUGMENT(elm);                                                \
+       if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) {          \
+               if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))     \
+                       RB_LEFT(RB_PARENT(elm, field), field) = (tmp);  \
+               else                                                    \
+                       RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+       } else                                                          \
+               (head)->rbh_root = (tmp);                               \
+       RB_LEFT(tmp, field) = (elm);                                    \
+       RB_PARENT(elm, field) = (tmp);                                  \
+       RB_AUGMENT(tmp);                                                \
+       if ((RB_PARENT(tmp, field)))                                    \
+               RB_AUGMENT(RB_PARENT(tmp, field));                      \
+} while (0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do {                    \
+       (tmp) = RB_LEFT(elm, field);                                    \
+       if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) {             \
+               RB_PARENT(RB_RIGHT(tmp, field), field) = (elm);         \
+       }                                                               \
+       RB_AUGMENT(elm);                                                \
+       if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) {          \
+               if ((elm) == RB_LEFT(RB_PARENT(elm, field), field))     \
+                       RB_LEFT(RB_PARENT(elm, field), field) = (tmp);  \
+               else                                                    \
+                       RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+       } else                                                          \
+               (head)->rbh_root = (tmp);                               \
+       RB_RIGHT(tmp, field) = (elm);                                   \
+       RB_PARENT(elm, field) = (tmp);                                  \
+       RB_AUGMENT(tmp);                                                \
+       if ((RB_PARENT(tmp, field)))                                    \
+               RB_AUGMENT(RB_PARENT(tmp, field));                      \
+} while (0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp)                           \
+void name##_RB_INSERT_COLOR(struct name *, struct type *);     \
+void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+struct type *name##_RB_REMOVE(struct name *, struct type *);           \
+struct type *name##_RB_INSERT(struct name *, struct type *);           \
+struct type *name##_RB_FIND(struct name *, struct type *);             \
+struct type *name##_RB_NEXT(struct type *);                            \
+struct type *name##_RB_MINMAX(struct name *, int);                     
+
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp)                            \
+void                                                                   \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm)            \
+{                                                                      \
+       struct type *parent, *gparent, *tmp;                            \
+       while ((parent = RB_PARENT(elm, field)) &&                      \
+           RB_COLOR(parent, field) == RB_RED) {                        \
+               gparent = RB_PARENT(parent, field);                     \
+               if (parent == RB_LEFT(gparent, field)) {                \
+                       tmp = RB_RIGHT(gparent, field);                 \
+                       if (tmp && RB_COLOR(tmp, field) == RB_RED) {    \
+                               RB_COLOR(tmp, field) = RB_BLACK;        \
+                               RB_SET_BLACKRED(parent, gparent, field);\
+                               elm = gparent;                          \
+                               continue;                               \
+                       }                                               \
+                       if (RB_RIGHT(parent, field) == elm) {           \
+                               RB_ROTATE_LEFT(head, parent, tmp, field);\
+                               tmp = parent;                           \
+                               parent = elm;                           \
+                               elm = tmp;                              \
+                       }                                               \
+                       RB_SET_BLACKRED(parent, gparent, field);        \
+                       RB_ROTATE_RIGHT(head, gparent, tmp, field);     \
+               } else {                                                \
+                       tmp = RB_LEFT(gparent, field);                  \
+                       if (tmp && RB_COLOR(tmp, field) == RB_RED) {    \
+                               RB_COLOR(tmp, field) = RB_BLACK;        \
+                               RB_SET_BLACKRED(parent, gparent, field);\
+                               elm = gparent;                          \
+                               continue;                               \
+                       }                                               \
+                       if (RB_LEFT(parent, field) == elm) {            \
+                               RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                               tmp = parent;                           \
+                               parent = elm;                           \
+                               elm = tmp;                              \
+                       }                                               \
+                       RB_SET_BLACKRED(parent, gparent, field);        \
+                       RB_ROTATE_LEFT(head, gparent, tmp, field);      \
+               }                                                       \
+       }                                                               \
+       RB_COLOR(head->rbh_root, field) = RB_BLACK;                     \
+}                                                                      \
+                                                                       \
+void                                                                   \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
+{                                                                      \
+       struct type *tmp;                                               \
+       while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) &&     \
+           elm != RB_ROOT(head)) {                                     \
+               if (RB_LEFT(parent, field) == elm) {                    \
+                       tmp = RB_RIGHT(parent, field);                  \
+                       if (RB_COLOR(tmp, field) == RB_RED) {           \
+                               RB_SET_BLACKRED(tmp, parent, field);    \
+                               RB_ROTATE_LEFT(head, parent, tmp, field);\
+                               tmp = RB_RIGHT(parent, field);          \
+                       }                                               \
+                       if ((RB_LEFT(tmp, field) == NULL ||             \
+                           RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+                           (RB_RIGHT(tmp, field) == NULL ||            \
+                           RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+                               RB_COLOR(tmp, field) = RB_RED;          \
+                               elm = parent;                           \
+                               parent = RB_PARENT(elm, field);         \
+                       } else {                                        \
+                               if (RB_RIGHT(tmp, field) == NULL ||     \
+                                   RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
+                                       struct type *oleft;             \
+                                       if ((oleft = RB_LEFT(tmp, field)))\
+                                               RB_COLOR(oleft, field) = RB_BLACK;\
+                                       RB_COLOR(tmp, field) = RB_RED;  \
+                                       RB_ROTATE_RIGHT(head, tmp, oleft, field);\
+                                       tmp = RB_RIGHT(parent, field);  \
+                               }                                       \
+                               RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+                               RB_COLOR(parent, field) = RB_BLACK;     \
+                               if (RB_RIGHT(tmp, field))               \
+                                       RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
+                               RB_ROTATE_LEFT(head, parent, tmp, field);\
+                               elm = RB_ROOT(head);                    \
+                               break;                                  \
+                       }                                               \
+               } else {                                                \
+                       tmp = RB_LEFT(parent, field);                   \
+                       if (RB_COLOR(tmp, field) == RB_RED) {           \
+                               RB_SET_BLACKRED(tmp, parent, field);    \
+                               RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                               tmp = RB_LEFT(parent, field);           \
+                       }                                               \
+                       if ((RB_LEFT(tmp, field) == NULL ||             \
+                           RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
+                           (RB_RIGHT(tmp, field) == NULL ||            \
+                           RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
+                               RB_COLOR(tmp, field) = RB_RED;          \
+                               elm = parent;                           \
+                               parent = RB_PARENT(elm, field);         \
+                       } else {                                        \
+                               if (RB_LEFT(tmp, field) == NULL ||      \
+                                   RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
+                                       struct type *oright;            \
+                                       if ((oright = RB_RIGHT(tmp, field)))\
+                                               RB_COLOR(oright, field) = RB_BLACK;\
+                                       RB_COLOR(tmp, field) = RB_RED;  \
+                                       RB_ROTATE_LEFT(head, tmp, oright, field);\
+                                       tmp = RB_LEFT(parent, field);   \
+                               }                                       \
+                               RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
+                               RB_COLOR(parent, field) = RB_BLACK;     \
+                               if (RB_LEFT(tmp, field))                \
+                                       RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
+                               RB_ROTATE_RIGHT(head, parent, tmp, field);\
+                               elm = RB_ROOT(head);                    \
+                               break;                                  \
+                       }                                               \
+               }                                                       \
+       }                                                               \
+       if (elm)                                                        \
+               RB_COLOR(elm, field) = RB_BLACK;                        \
+}                                                                      \
+                                                                       \
+struct type *                                                          \
+name##_RB_REMOVE(struct name *head, struct type *elm)                  \
+{                                                                      \
+       struct type *child, *parent, *old = elm;                        \
+       int color;                                                      \
+       if (RB_LEFT(elm, field) == NULL)                                \
+               child = RB_RIGHT(elm, field);                           \
+       else if (RB_RIGHT(elm, field) == NULL)                          \
+               child = RB_LEFT(elm, field);                            \
+       else {                                                          \
+               struct type *left;                                      \
+               elm = RB_RIGHT(elm, field);                             \
+               while ((left = RB_LEFT(elm, field)))                    \
+                       elm = left;                                     \
+               child = RB_RIGHT(elm, field);                           \
+               parent = RB_PARENT(elm, field);                         \
+               color = RB_COLOR(elm, field);                           \
+               if (child)                                              \
+                       RB_PARENT(child, field) = parent;               \
+               if (parent) {                                           \
+                       if (RB_LEFT(parent, field) == elm)              \
+                               RB_LEFT(parent, field) = child;         \
+                       else                                            \
+                               RB_RIGHT(parent, field) = child;        \
+                       RB_AUGMENT(parent);                             \
+               } else                                                  \
+                       RB_ROOT(head) = child;                          \
+               if (RB_PARENT(elm, field) == old)                       \
+                       parent = elm;                                   \
+               (elm)->field = (old)->field;                            \
+               if (RB_PARENT(old, field)) {                            \
+                       if (RB_LEFT(RB_PARENT(old, field), field) == old)\
+                               RB_LEFT(RB_PARENT(old, field), field) = elm;\
+                       else                                            \
+                               RB_RIGHT(RB_PARENT(old, field), field) = elm;\
+                       RB_AUGMENT(RB_PARENT(old, field));              \
+               } else                                                  \
+                       RB_ROOT(head) = elm;                            \
+               RB_PARENT(RB_LEFT(old, field), field) = elm;            \
+               if (RB_RIGHT(old, field))                               \
+                       RB_PARENT(RB_RIGHT(old, field), field) = elm;   \
+               if (parent) {                                           \
+                       left = parent;                                  \
+                       do {                                            \
+                               RB_AUGMENT(left);                       \
+                       } while ((left = RB_PARENT(left, field)));      \
+               }                                                       \
+               goto color;                                             \
+       }                                                               \
+       parent = RB_PARENT(elm, field);                                 \
+       color = RB_COLOR(elm, field);                                   \
+       if (child)                                                      \
+               RB_PARENT(child, field) = parent;                       \
+       if (parent) {                                                   \
+               if (RB_LEFT(parent, field) == elm)                      \
+                       RB_LEFT(parent, field) = child;                 \
+               else                                                    \
+                       RB_RIGHT(parent, field) = child;                \
+               RB_AUGMENT(parent);                                     \
+       } else                                                          \
+               RB_ROOT(head) = child;                                  \
+color:                                                                 \
+       if (color == RB_BLACK)                                          \
+               name##_RB_REMOVE_COLOR(head, parent, child);            \
+       return (old);                                                   \
+}                                                                      \
+                                                                       \
+/* Inserts a node into the RB tree */                                  \
+struct type *                                                          \
+name##_RB_INSERT(struct name *head, struct type *elm)                  \
+{                                                                      \
+       struct type *tmp;                                               \
+       struct type *parent = NULL;                                     \
+       int comp = 0;                                                   \
+       tmp = RB_ROOT(head);                                            \
+       while (tmp) {                                                   \
+               parent = tmp;                                           \
+               comp = (cmp)(elm, parent);                              \
+               if (comp < 0)                                           \
+                       tmp = RB_LEFT(tmp, field);                      \
+               else if (comp > 0)                                      \
+                       tmp = RB_RIGHT(tmp, field);                     \
+               else                                                    \
+                       return (tmp);                                   \
+       }                                                               \
+       RB_SET(elm, parent, field);                                     \
+       if (parent != NULL) {                                           \
+               if (comp < 0)                                           \
+                       RB_LEFT(parent, field) = elm;                   \
+               else                                                    \
+                       RB_RIGHT(parent, field) = elm;                  \
+               RB_AUGMENT(parent);                                     \
+       } else                                                          \
+               RB_ROOT(head) = elm;                                    \
+       name##_RB_INSERT_COLOR(head, elm);                              \
+       return (NULL);                                                  \
+}                                                                      \
+                                                                       \
+/* Finds the node with the same key as elm */                          \
+struct type *                                                          \
+name##_RB_FIND(struct name *head, struct type *elm)                    \
+{                                                                      \
+       struct type *tmp = RB_ROOT(head);                               \
+       int comp;                                                       \
+       while (tmp) {                                                   \
+               comp = cmp(elm, tmp);                                   \
+               if (comp < 0)                                           \
+                       tmp = RB_LEFT(tmp, field);                      \
+               else if (comp > 0)                                      \
+                       tmp = RB_RIGHT(tmp, field);                     \
+               else                                                    \
+                       return (tmp);                                   \
+       }                                                               \
+       return (NULL);                                                  \
+}                                                                      \
+                                                                       \
+struct type *                                                          \
+name##_RB_NEXT(struct type *elm)                                       \
+{                                                                      \
+       if (RB_RIGHT(elm, field)) {                                     \
+               elm = RB_RIGHT(elm, field);                             \
+               while (RB_LEFT(elm, field))                             \
+                       elm = RB_LEFT(elm, field);                      \
+       } else {                                                        \
+               if (RB_PARENT(elm, field) &&                            \
+                   (elm == RB_LEFT(RB_PARENT(elm, field), field)))     \
+                       elm = RB_PARENT(elm, field);                    \
+               else {                                                  \
+                       while (RB_PARENT(elm, field) &&                 \
+                           (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
+                               elm = RB_PARENT(elm, field);            \
+                       elm = RB_PARENT(elm, field);                    \
+               }                                                       \
+       }                                                               \
+       return (elm);                                                   \
+}                                                                      \
+                                                                       \
+struct type *                                                          \
+name##_RB_MINMAX(struct name *head, int val)                           \
+{                                                                      \
+       struct type *tmp = RB_ROOT(head);                               \
+       struct type *parent = NULL;                                     \
+       while (tmp) {                                                   \
+               parent = tmp;                                           \
+               if (val < 0)                                            \
+                       tmp = RB_LEFT(tmp, field);                      \
+               else                                                    \
+                       tmp = RB_RIGHT(tmp, field);                     \
+       }                                                               \
+       return (parent);                                                \
+}
+
+#define RB_NEGINF      -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y)  name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y)  name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y)    name##_RB_FIND(x, y)
+#define RB_NEXT(name, x, y)    name##_RB_NEXT(y)
+#define RB_MIN(name, x)                name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x)                name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head)                                      \
+       for ((x) = RB_MIN(name, head);                                  \
+            (x) != NULL;                                               \
+            (x) = name##_RB_NEXT(x))
+
+#endif /* _SYS_TREE_H_ */
diff --git a/openbsd-compat/timingsafe_bcmp.c b/openbsd-compat/timingsafe_bcmp.c
new file mode 100644 (file)
index 0000000..7e28c0e
--- /dev/null
@@ -0,0 +1,34 @@
+/*     $OpenBSD: timingsafe_bcmp.c,v 1.1 2010/09/24 13:33:00 matthew Exp $     */
+/*
+ * Copyright (c) 2010 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/timingsafe_bcmp.c */
+
+#include "includes.h"
+#ifndef HAVE_TIMINGSAFE_BCMP
+
+int
+timingsafe_bcmp(const void *b1, const void *b2, size_t n)
+{
+       const unsigned char *p1 = b1, *p2 = b2;
+       int ret = 0;
+
+       for (; n > 0; n--)
+               ret |= *p1++ ^ *p2++;
+       return (ret != 0);
+}
+
+#endif /* TIMINGSAFE_BCMP */
diff --git a/openbsd-compat/vis.c b/openbsd-compat/vis.c
new file mode 100644 (file)
index 0000000..3a087b3
--- /dev/null
@@ -0,0 +1,225 @@
+/*     $OpenBSD: vis.c,v 1.19 2005/09/01 17:15:49 millert Exp $ */
+/*-
+ * Copyright (c) 1989, 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. 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.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */
+
+#include "includes.h"
+#if !defined(HAVE_STRNVIS)
+
+#include <ctype.h>
+#include <string.h>
+
+#include "vis.h"
+
+#define        isoctal(c)      (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
+#define        isvisible(c)                                                    \
+       (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) &&            \
+       (((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') ||      \
+               (flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) ||     \
+       ((flag & VIS_SP) == 0 && (c) == ' ') ||                         \
+       ((flag & VIS_TAB) == 0 && (c) == '\t') ||                       \
+       ((flag & VIS_NL) == 0 && (c) == '\n') ||                        \
+       ((flag & VIS_SAFE) && ((c) == '\b' ||                           \
+               (c) == '\007' || (c) == '\r' ||                         \
+               isgraph((u_char)(c)))))
+
+/*
+ * vis - visually encode characters
+ */
+char *
+vis(char *dst, int c, int flag, int nextc)
+{
+       if (isvisible(c)) {
+               *dst++ = c;
+               if (c == '\\' && (flag & VIS_NOSLASH) == 0)
+                       *dst++ = '\\';
+               *dst = '\0';
+               return (dst);
+       }
+
+       if (flag & VIS_CSTYLE) {
+               switch(c) {
+               case '\n':
+                       *dst++ = '\\';
+                       *dst++ = 'n';
+                       goto done;
+               case '\r':
+                       *dst++ = '\\';
+                       *dst++ = 'r';
+                       goto done;
+               case '\b':
+                       *dst++ = '\\';
+                       *dst++ = 'b';
+                       goto done;
+               case '\a':
+                       *dst++ = '\\';
+                       *dst++ = 'a';
+                       goto done;
+               case '\v':
+                       *dst++ = '\\';
+                       *dst++ = 'v';
+                       goto done;
+               case '\t':
+                       *dst++ = '\\';
+                       *dst++ = 't';
+                       goto done;
+               case '\f':
+                       *dst++ = '\\';
+                       *dst++ = 'f';
+                       goto done;
+               case ' ':
+                       *dst++ = '\\';
+                       *dst++ = 's';
+                       goto done;
+               case '\0':
+                       *dst++ = '\\';
+                       *dst++ = '0';
+                       if (isoctal(nextc)) {
+                               *dst++ = '0';
+                               *dst++ = '0';
+                       }
+                       goto done;
+               }
+       }
+       if (((c & 0177) == ' ') || (flag & VIS_OCTAL) ||
+           ((flag & VIS_GLOB) && (c == '*' || c == '?' || c == '[' || c == '#'))) {
+               *dst++ = '\\';
+               *dst++ = ((u_char)c >> 6 & 07) + '0';
+               *dst++ = ((u_char)c >> 3 & 07) + '0';
+               *dst++ = ((u_char)c & 07) + '0';
+               goto done;
+       }
+       if ((flag & VIS_NOSLASH) == 0)
+               *dst++ = '\\';
+       if (c & 0200) {
+               c &= 0177;
+               *dst++ = 'M';
+       }
+       if (iscntrl((u_char)c)) {
+               *dst++ = '^';
+               if (c == 0177)
+                       *dst++ = '?';
+               else
+                       *dst++ = c + '@';
+       } else {
+               *dst++ = '-';
+               *dst++ = c;
+       }
+done:
+       *dst = '\0';
+       return (dst);
+}
+
+/*
+ * strvis, strnvis, strvisx - visually encode characters from src into dst
+ *     
+ *     Dst must be 4 times the size of src to account for possible
+ *     expansion.  The length of dst, not including the trailing NULL,
+ *     is returned. 
+ *
+ *     Strnvis will write no more than siz-1 bytes (and will NULL terminate).
+ *     The number of bytes needed to fully encode the string is returned.
+ *
+ *     Strvisx encodes exactly len bytes from src into dst.
+ *     This is useful for encoding a block of data.
+ */
+int
+strvis(char *dst, const char *src, int flag)
+{
+       char c;
+       char *start;
+
+       for (start = dst; (c = *src);)
+               dst = vis(dst, c, flag, *++src);
+       *dst = '\0';
+       return (dst - start);
+}
+
+int
+strnvis(char *dst, const char *src, size_t siz, int flag)
+{
+       char *start, *end;
+       char tbuf[5];
+       int c, i;
+
+       i = 0;
+       for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
+               if (isvisible(c)) {
+                       i = 1;
+                       *dst++ = c;
+                       if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
+                               /* need space for the extra '\\' */
+                               if (dst < end)
+                                       *dst++ = '\\';
+                               else {
+                                       dst--;
+                                       i = 2;
+                                       break;
+                               }
+                       }
+                       src++;
+               } else {
+                       i = vis(tbuf, c, flag, *++src) - tbuf;
+                       if (dst + i <= end) {
+                               memcpy(dst, tbuf, i);
+                               dst += i;
+                       } else {
+                               src--;
+                               break;
+                       }
+               }
+       }
+       if (siz > 0)
+               *dst = '\0';
+       if (dst + i > end) {
+               /* adjust return value for truncation */
+               while ((c = *src))
+                       dst += vis(tbuf, c, flag, *++src) - tbuf;
+       }
+       return (dst - start);
+}
+
+int
+strvisx(char *dst, const char *src, size_t len, int flag)
+{
+       char c;
+       char *start;
+
+       for (start = dst; len > 1; len--) {
+               c = *src;
+               dst = vis(dst, c, flag, *++src);
+       }
+       if (len)
+               dst = vis(dst, *src, flag, '\0');
+       *dst = '\0';
+       return (dst - start);
+}
+
+#endif
diff --git a/openbsd-compat/vis.h b/openbsd-compat/vis.h
new file mode 100644 (file)
index 0000000..3898a9e
--- /dev/null
@@ -0,0 +1,95 @@
+/*     $OpenBSD: vis.h,v 1.11 2005/08/09 19:38:31 millert Exp $        */
+/*     $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $      */
+
+/*-
+ * 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. 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.
+ *
+ *     @(#)vis.h       5.9 (Berkeley) 4/3/91
+ */
+
+/* OPENBSD ORIGINAL: include/vis.h */
+
+#include "includes.h"
+#if !defined(HAVE_STRNVIS)
+
+#ifndef _VIS_H_
+#define        _VIS_H_
+
+#include <sys/types.h>
+#include <limits.h>
+
+/*
+ * to select alternate encoding format
+ */
+#define        VIS_OCTAL       0x01    /* use octal \ddd format */
+#define        VIS_CSTYLE      0x02    /* use \[nrft0..] where appropriate */
+
+/*
+ * to alter set of characters encoded (default is to encode all
+ * non-graphic except space, tab, and newline).
+ */
+#define        VIS_SP          0x04    /* also encode space */
+#define        VIS_TAB         0x08    /* also encode tab */
+#define        VIS_NL          0x10    /* also encode newline */
+#define        VIS_WHITE       (VIS_SP | VIS_TAB | VIS_NL)
+#define        VIS_SAFE        0x20    /* only encode "unsafe" characters */
+
+/*
+ * other
+ */
+#define        VIS_NOSLASH     0x40    /* inhibit printing '\' */
+#define        VIS_GLOB        0x100   /* encode glob(3) magics and '#' */
+
+/*
+ * unvis return codes
+ */
+#define        UNVIS_VALID      1      /* character valid */
+#define        UNVIS_VALIDPUSH  2      /* character valid, push back passed char */
+#define        UNVIS_NOCHAR     3      /* valid sequence, no character produced */
+#define        UNVIS_SYNBAD    -1      /* unrecognized escape sequence */
+#define        UNVIS_ERROR     -2      /* decoder in unknown state (unrecoverable) */
+
+/*
+ * unvis flags
+ */
+#define        UNVIS_END       1       /* no more characters */
+
+char   *vis(char *, int, int, int);
+int    strvis(char *, const char *, int);
+int    strnvis(char *, const char *, size_t, int)
+               __attribute__ ((__bounded__(__string__,1,3)));
+int    strvisx(char *, const char *, size_t, int)
+               __attribute__ ((__bounded__(__string__,1,3)));
+int    strunvis(char *, const char *);
+int    unvis(char *, char, int *, int);
+ssize_t strnunvis(char *, const char *, size_t)
+               __attribute__ ((__bounded__(__string__,1,3)));
+
+#endif /* !_VIS_H_ */
+
+#endif /* !HAVE_STRNVIS */
diff --git a/openbsd-compat/xcrypt.c b/openbsd-compat/xcrypt.c
new file mode 100644 (file)
index 0000000..6291e28
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2003 Ben Lindstrom.  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 <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+
+# if defined(HAVE_CRYPT_H) && !defined(HAVE_SECUREWARE)
+#  include <crypt.h>
+# endif
+
+# ifdef __hpux
+#  include <hpsecurity.h>
+#  include <prot.h>
+# endif
+
+# ifdef HAVE_SECUREWARE
+#  include <sys/security.h>
+#  include <sys/audit.h>
+#  include <prot.h>
+# endif 
+
+# 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 
+
+char *
+xcrypt(const char *password, const char *salt)
+{
+       char *crypted;
+
+# ifdef HAVE_MD5_PASSWORDS
+        if (is_md5_salt(salt))
+                crypted = md5_crypt(password, salt);
+        else
+                crypted = crypt(password, salt);
+# elif defined(__hpux) && !defined(HAVE_SECUREWARE)
+       if (iscomsec())
+                crypted = bigcrypt(password, salt);
+        else
+                crypted = crypt(password, salt);
+# elif defined(HAVE_SECUREWARE)
+        crypted = bigcrypt(password, salt);
+# else
+        crypted = crypt(password, salt);
+# endif 
+
+       return crypted;
+}
+
+/*
+ * Handle shadowed password systems in a cleaner way for portable
+ * version.
+ */
+
+char *
+shadow_pw(struct passwd *pw)
+{
+       char *pw_password = pw->pw_passwd;
+
+# if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW)
+       struct spwd *spw = getspnam(pw->pw_name);
+
+       if (spw != NULL)
+               pw_password = spw->sp_pwdp;
+# endif
+
+#ifdef USE_LIBIAF
+       return(get_iaf_password(pw));
+#endif
+
+# if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW)
+       struct passwd_adjunct *spw;
+       if (issecure() && (spw = getpwanam(pw->pw_name)) != NULL)
+               pw_password = spw->pwa_passwd;
+# elif defined(HAVE_SECUREWARE)
+       struct pr_passwd *spw = getprpwnam(pw->pw_name);
+
+       if (spw != NULL)
+               pw_password = spw->ufld.fd_encrypt;
+# endif
+
+       return pw_password;
+}
diff --git a/openbsd-compat/xmmap.c b/openbsd-compat/xmmap.c
new file mode 100644 (file)
index 0000000..04c6bab
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2002 Tim Rice.  All rights reserved.
+ * MAP_FAILED code by Solar Designer.
+ * 
+ * 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: xmmap.c,v 1.15 2009/02/16 04:21:40 djm Exp $ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/stat.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "log.h"
+
+void *
+xmmap(size_t size)
+{
+#ifdef HAVE_MMAP
+       void *address;
+
+# ifdef MAP_ANON
+       address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED,
+           -1, (off_t)0);
+# else
+       address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED,
+           open("/dev/zero", O_RDWR), (off_t)0);
+# endif
+
+#define MM_SWAP_TEMPLATE "/var/run/sshd.mm.XXXXXXXX"
+       if (address == (void *)MAP_FAILED) {
+               char tmpname[sizeof(MM_SWAP_TEMPLATE)] = MM_SWAP_TEMPLATE;
+               int tmpfd;
+               mode_t old_umask;
+
+               old_umask = umask(0177);
+               tmpfd = mkstemp(tmpname);
+               umask(old_umask);
+               if (tmpfd == -1)
+                       fatal("mkstemp(\"%s\"): %s",
+                           MM_SWAP_TEMPLATE, strerror(errno));
+               unlink(tmpname);
+               if (ftruncate(tmpfd, size) != 0)
+                       fatal("%s: ftruncate: %s", __func__, strerror(errno));
+               address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED,
+                   tmpfd, (off_t)0);
+               close(tmpfd);
+       }
+
+       return (address);
+#else
+       fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported",
+           __func__);
+#endif /* HAVE_MMAP */
+
+}
+
diff --git a/openssh.xml.in b/openssh.xml.in
new file mode 100644 (file)
index 0000000..8afe1d3
--- /dev/null
@@ -0,0 +1,90 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+<!--
+    Copyright (c) 2006 Chad Mynhier.
+
+    Permission to use, copy, modify, and distribute this software for any
+    purpose with or without fee is hereby granted, provided that the above
+    copyright notice and this permission notice appear in all copies.
+
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<service_bundle type='manifest' name='OpenSSH server'>
+
+    <service
+        name='site/__SYSVINIT_NAME__'
+        type='service'
+        version='1'>
+
+<!--
+       We default to disabled so administrator can decide to enable or not.
+-->
+        <create_default_instance enabled='false'/>
+
+        <single_instance/>
+
+        <dependency
+            name='filesystem-local'
+            grouping='require_all'
+            restart_on='none'
+            type='service'>
+            <service_fmri value='svc:/system/filesystem/local'/>
+        </dependency>
+
+        <dependency
+            name='network'
+            grouping='require_all'
+            restart_on='none'
+            type='service'>
+            <service_fmri value='svc:/milestone/network'/>
+        </dependency>
+
+        <dependent
+            name='multi-user-server'
+            restart_on='none'
+            grouping='optional_all'>
+            <service_fmri value='svc:/milestone/multi-user-server'/>
+        </dependent>
+
+        <exec_method
+            name='start'
+            type='method'
+            exec='__SMF_METHOD_DIR__/__SYSVINIT_NAME__ start'
+            timeout_seconds='60'>
+            <method_context/>
+        </exec_method>
+
+        <exec_method
+            name='stop'
+            type='method'
+            exec=':kill'
+            timeout_seconds='60'>
+            <method_context/>
+        </exec_method>
+
+        <property_group
+            name='startd'
+            type='framework'>
+            <propval name='ignore_error' type='astring' value='core,signal'/>
+        </property_group>
+
+        <template>
+            <common_name>
+                <loctext xml:lang='C'>OpenSSH server</loctext>
+            </common_name>
+            <documentation>
+                <manpage
+                    title='sshd'
+                    section='1M'
+                    manpath='@prefix@/man'/>
+            </documentation>
+        </template>
+    </service>
+</service_bundle>
diff --git a/opensshd.init.in b/opensshd.init.in
new file mode 100755 (executable)
index 0000000..0db60ca
--- /dev/null
@@ -0,0 +1,88 @@
+#!@STARTUP_SCRIPT_SHELL@
+# Donated code that was put under PD license.
+#
+# Stripped PRNGd out of it for the time being.
+
+umask 022
+
+CAT=@CAT@
+KILL=@KILL@
+
+prefix=@prefix@
+sysconfdir=@sysconfdir@
+piddir=@piddir@
+
+SSHD=$prefix/sbin/sshd
+PIDFILE=$piddir/sshd.pid
+PidFile=`grep "^PidFile" ${sysconfdir}/sshd_config | tr "=" " " | awk '{print $2}'`
+[ X$PidFile = X ]  ||  PIDFILE=$PidFile
+SSH_KEYGEN=$prefix/bin/ssh-keygen
+HOST_KEY_RSA1=$sysconfdir/ssh_host_key
+HOST_KEY_DSA=$sysconfdir/ssh_host_dsa_key
+HOST_KEY_RSA=$sysconfdir/ssh_host_rsa_key
+@COMMENT_OUT_ECC@HOST_KEY_ECDSA=$sysconfdir/ssh_host_ecdsa_key
+
+
+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
+@COMMENT_OUT_ECC@    if [ ! -f $HOST_KEY_ECDSA ]; then
+@COMMENT_OUT_ECC@      ${SSH_KEYGEN} -t ecdsa -f ${HOST_KEY_ECDSA} -N ""
+@COMMENT_OUT_ECC@    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"
+    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/packet.c b/packet.c
new file mode 100644 (file)
index 0000000..b4e01f7
--- /dev/null
+++ b/packet.c
@@ -0,0 +1,1960 @@
+/* $OpenBSD: packet.c,v 1.172 2010/11/13 23:27:50 djm Exp $ */
+/*
+ * 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"
+#include <sys/types.h>
+#include "openbsd-compat/sys-queue.h"
+#include <sys/param.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "packet.h"
+#include "crc32.h"
+#include "compress.h"
+#include "deattack.h"
+#include "channels.h"
+#include "compat.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include "mac.h"
+#include "log.h"
+#include "canohost.h"
+#include "misc.h"
+#include "ssh.h"
+#include "roaming.h"
+
+#ifdef PACKET_DEBUG
+#define DBG(x) x
+#else
+#define DBG(x)
+#endif
+
+#define PACKET_MAX_SIZE (256 * 1024)
+
+struct packet_state {
+       u_int32_t seqnr;
+       u_int32_t packets;
+       u_int64_t blocks;
+       u_int64_t bytes;
+};
+
+struct packet {
+       TAILQ_ENTRY(packet) next;
+       u_char type;
+       Buffer payload;
+};
+
+struct session_state {
+       /*
+        * 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.
+        */
+       int connection_in;
+       int connection_out;
+
+       /* Protocol flags for the remote side. */
+       u_int remote_protocol_flags;
+
+       /* Encryption context for receiving data.  Only used for decryption. */
+       CipherContext receive_context;
+
+       /* Encryption context for sending data.  Only used for encryption. */
+       CipherContext send_context;
+
+       /* Buffer for raw input data from the socket. */
+       Buffer input;
+
+       /* Buffer for raw output data going to the socket. */
+       Buffer output;
+
+       /* Buffer for the partial outgoing packet being constructed. */
+       Buffer outgoing_packet;
+
+       /* Buffer for the incoming packet currently being processed. */
+       Buffer incoming_packet;
+
+       /* Scratch buffer for packet compression/decompression. */
+       Buffer compression_buffer;
+       int compression_buffer_ready;
+
+       /*
+        * Flag indicating whether packet compression/decompression is
+        * enabled.
+        */
+       int packet_compression;
+
+       /* default maximum packet size */
+       u_int max_packet_size;
+
+       /* Flag indicating whether this module has been initialized. */
+       int initialized;
+
+       /* Set to true if the connection is interactive. */
+       int interactive_mode;
+
+       /* Set to true if we are the server side. */
+       int server_side;
+
+       /* Set to true if we are authenticated. */
+       int after_authentication;
+
+       int keep_alive_timeouts;
+
+       /* The maximum time that we will wait to send or receive a packet */
+       int packet_timeout_ms;
+
+       /* Session key information for Encryption and MAC */
+       Newkeys *newkeys[MODE_MAX];
+       struct packet_state p_read, p_send;
+
+       u_int64_t max_blocks_in, max_blocks_out;
+       u_int32_t rekey_limit;
+
+       /* Session key for protocol v1 */
+       u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
+       u_int ssh1_keylen;
+
+       /* roundup current message to extra_pad bytes */
+       u_char extra_pad;
+
+       /* XXX discard incoming data after MAC error */
+       u_int packet_discard;
+       Mac *packet_discard_mac;
+
+       /* Used in packet_read_poll2() */
+       u_int packlen;
+
+       /* Used in packet_send2 */
+       int rekeying;
+
+       /* Used in packet_set_interactive */
+       int set_interactive_called;
+
+       /* Used in packet_set_maxsize */
+       int set_maxsize_called;
+
+       TAILQ_HEAD(, packet) outgoing;
+};
+
+static struct session_state *active_state, *backup_state;
+
+static struct session_state *
+alloc_session_state(void)
+{
+       struct session_state *s = xcalloc(1, sizeof(*s));
+
+       s->connection_in = -1;
+       s->connection_out = -1;
+       s->max_packet_size = 32768;
+       s->packet_timeout_ms = -1;
+       return s;
+}
+
+/*
+ * 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'");
+       if (active_state == NULL)
+               active_state = alloc_session_state();
+       active_state->connection_in = fd_in;
+       active_state->connection_out = fd_out;
+       cipher_init(&active_state->send_context, none, (const u_char *)"",
+           0, NULL, 0, CIPHER_ENCRYPT);
+       cipher_init(&active_state->receive_context, none, (const u_char *)"",
+           0, NULL, 0, CIPHER_DECRYPT);
+       active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL;
+       if (!active_state->initialized) {
+               active_state->initialized = 1;
+               buffer_init(&active_state->input);
+               buffer_init(&active_state->output);
+               buffer_init(&active_state->outgoing_packet);
+               buffer_init(&active_state->incoming_packet);
+               TAILQ_INIT(&active_state->outgoing);
+               active_state->p_send.packets = active_state->p_read.packets = 0;
+       }
+}
+
+void
+packet_set_timeout(int timeout, int count)
+{
+       if (timeout == 0 || count == 0) {
+               active_state->packet_timeout_ms = -1;
+               return;
+       }
+       if ((INT_MAX / 1000) / count < timeout)
+               active_state->packet_timeout_ms = INT_MAX;
+       else
+               active_state->packet_timeout_ms = timeout * count * 1000;
+}
+
+static void
+packet_stop_discard(void)
+{
+       if (active_state->packet_discard_mac) {
+               char buf[1024];
+               
+               memset(buf, 'a', sizeof(buf));
+               while (buffer_len(&active_state->incoming_packet) <
+                   PACKET_MAX_SIZE)
+                       buffer_append(&active_state->incoming_packet, buf,
+                           sizeof(buf));
+               (void) mac_compute(active_state->packet_discard_mac,
+                   active_state->p_read.seqnr,
+                   buffer_ptr(&active_state->incoming_packet),
+                   PACKET_MAX_SIZE);
+       }
+       logit("Finished discarding for %.200s", get_remote_ipaddr());
+       cleanup_exit(255);
+}
+
+static void
+packet_start_discard(Enc *enc, Mac *mac, u_int packet_length, u_int discard)
+{
+       if (enc == NULL || !cipher_is_cbc(enc->cipher))
+               packet_disconnect("Packet corrupt");
+       if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled)
+               active_state->packet_discard_mac = mac;
+       if (buffer_len(&active_state->input) >= discard)
+               packet_stop_discard();
+       active_state->packet_discard = discard -
+           buffer_len(&active_state->input);
+}
+
+/* Returns 1 if remote host is connected via socket, 0 if not. */
+
+int
+packet_connection_is_on_socket(void)
+{
+       struct sockaddr_storage from, to;
+       socklen_t fromlen, tolen;
+
+       /* filedescriptors in and out are the same, so it's a socket */
+       if (active_state->connection_in == active_state->connection_out)
+               return 1;
+       fromlen = sizeof(from);
+       memset(&from, 0, sizeof(from));
+       if (getpeername(active_state->connection_in, (struct sockaddr *)&from,
+           &fromlen) < 0)
+               return 0;
+       tolen = sizeof(to);
+       memset(&to, 0, sizeof(to));
+       if (getpeername(active_state->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;
+}
+
+/*
+ * Exports an IV from the CipherContext required to export the key
+ * state back from the unprivileged child to the privileged parent
+ * process.
+ */
+
+void
+packet_get_keyiv(int mode, u_char *iv, u_int len)
+{
+       CipherContext *cc;
+
+       if (mode == MODE_OUT)
+               cc = &active_state->send_context;
+       else
+               cc = &active_state->receive_context;
+
+       cipher_get_keyiv(cc, iv, len);
+}
+
+int
+packet_get_keycontext(int mode, u_char *dat)
+{
+       CipherContext *cc;
+
+       if (mode == MODE_OUT)
+               cc = &active_state->send_context;
+       else
+               cc = &active_state->receive_context;
+
+       return (cipher_get_keycontext(cc, dat));
+}
+
+void
+packet_set_keycontext(int mode, u_char *dat)
+{
+       CipherContext *cc;
+
+       if (mode == MODE_OUT)
+               cc = &active_state->send_context;
+       else
+               cc = &active_state->receive_context;
+
+       cipher_set_keycontext(cc, dat);
+}
+
+int
+packet_get_keyiv_len(int mode)
+{
+       CipherContext *cc;
+
+       if (mode == MODE_OUT)
+               cc = &active_state->send_context;
+       else
+               cc = &active_state->receive_context;
+
+       return (cipher_get_keyiv_len(cc));
+}
+
+void
+packet_set_iv(int mode, u_char *dat)
+{
+       CipherContext *cc;
+
+       if (mode == MODE_OUT)
+               cc = &active_state->send_context;
+       else
+               cc = &active_state->receive_context;
+
+       cipher_set_keyiv(cc, dat);
+}
+
+int
+packet_get_ssh1_cipher(void)
+{
+       return (cipher_get_number(active_state->receive_context.cipher));
+}
+
+void
+packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks,
+    u_int32_t *packets, u_int64_t *bytes)
+{
+       struct packet_state *state;
+
+       state = (mode == MODE_IN) ?
+           &active_state->p_read : &active_state->p_send;
+       if (seqnr)
+               *seqnr = state->seqnr;
+       if (blocks)
+               *blocks = state->blocks;
+       if (packets)
+               *packets = state->packets;
+       if (bytes)
+               *bytes = state->bytes;
+}
+
+void
+packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets,
+    u_int64_t bytes)
+{
+       struct packet_state *state;
+
+       state = (mode == MODE_IN) ?
+           &active_state->p_read : &active_state->p_send;
+       state->seqnr = seqnr;
+       state->blocks = blocks;
+       state->packets = packets;
+       state->bytes = bytes;
+}
+
+/* returns 1 if connection is via ipv4 */
+
+int
+packet_connection_is_ipv4(void)
+{
+       struct sockaddr_storage to;
+       socklen_t tolen = sizeof(to);
+
+       memset(&to, 0, sizeof(to));
+       if (getsockname(active_state->connection_out, (struct sockaddr *)&to,
+           &tolen) < 0)
+               return 0;
+       if (to.ss_family == AF_INET)
+               return 1;
+#ifdef IPV4_IN_IPV6
+       if (to.ss_family == AF_INET6 &&
+           IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr))
+               return 1;
+#endif
+       return 0;
+}
+
+/* Sets the connection into non-blocking mode. */
+
+void
+packet_set_nonblocking(void)
+{
+       /* Set the socket into non-blocking mode. */
+       set_nonblock(active_state->connection_in);
+
+       if (active_state->connection_out != active_state->connection_in)
+               set_nonblock(active_state->connection_out);
+}
+
+/* Returns the socket used for reading. */
+
+int
+packet_get_connection_in(void)
+{
+       return active_state->connection_in;
+}
+
+/* Returns the descriptor used for writing. */
+
+int
+packet_get_connection_out(void)
+{
+       return active_state->connection_out;
+}
+
+/* Closes the connection and clears and frees internal data structures. */
+
+void
+packet_close(void)
+{
+       if (!active_state->initialized)
+               return;
+       active_state->initialized = 0;
+       if (active_state->connection_in == active_state->connection_out) {
+               shutdown(active_state->connection_out, SHUT_RDWR);
+               close(active_state->connection_out);
+       } else {
+               close(active_state->connection_in);
+               close(active_state->connection_out);
+       }
+       buffer_free(&active_state->input);
+       buffer_free(&active_state->output);
+       buffer_free(&active_state->outgoing_packet);
+       buffer_free(&active_state->incoming_packet);
+       if (active_state->compression_buffer_ready) {
+               buffer_free(&active_state->compression_buffer);
+               buffer_compress_uninit();
+       }
+       cipher_cleanup(&active_state->send_context);
+       cipher_cleanup(&active_state->receive_context);
+}
+
+/* Sets remote side protocol flags. */
+
+void
+packet_set_protocol_flags(u_int protocol_flags)
+{
+       active_state->remote_protocol_flags = protocol_flags;
+}
+
+/* Returns the remote protocol flags set earlier by the above function. */
+
+u_int
+packet_get_protocol_flags(void)
+{
+       return active_state->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 (active_state->compression_buffer_ready == 1)
+               return;
+       active_state->compression_buffer_ready = 1;
+       buffer_init(&active_state->compression_buffer);
+}
+
+void
+packet_start_compression(int level)
+{
+       if (active_state->packet_compression && !compat20)
+               fatal("Compression already enabled.");
+       active_state->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);
+       if (keylen > SSH_SESSION_KEY_LENGTH)
+               fatal("packet_set_encryption_key: keylen too big: %d", keylen);
+       memcpy(active_state->ssh1_key, key, keylen);
+       active_state->ssh1_keylen = keylen;
+       cipher_init(&active_state->send_context, cipher, key, keylen, NULL,
+           0, CIPHER_ENCRYPT);
+       cipher_init(&active_state->receive_context, cipher, key, keylen, NULL,
+           0, CIPHER_DECRYPT);
+}
+
+u_int
+packet_get_encryption_key(u_char *key)
+{
+       if (key == NULL)
+               return (active_state->ssh1_keylen);
+       memcpy(key, active_state->ssh1_key, active_state->ssh1_keylen);
+       return (active_state->ssh1_keylen);
+}
+
+/* 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(&active_state->outgoing_packet);
+       buffer_append(&active_state->outgoing_packet, buf, len);
+}
+
+/* Append payload. */
+void
+packet_put_char(int value)
+{
+       char ch = value;
+
+       buffer_append(&active_state->outgoing_packet, &ch, 1);
+}
+
+void
+packet_put_int(u_int value)
+{
+       buffer_put_int(&active_state->outgoing_packet, value);
+}
+
+void
+packet_put_int64(u_int64_t value)
+{
+       buffer_put_int64(&active_state->outgoing_packet, value);
+}
+
+void
+packet_put_string(const void *buf, u_int len)
+{
+       buffer_put_string(&active_state->outgoing_packet, buf, len);
+}
+
+void
+packet_put_cstring(const char *str)
+{
+       buffer_put_cstring(&active_state->outgoing_packet, str);
+}
+
+void
+packet_put_raw(const void *buf, u_int len)
+{
+       buffer_append(&active_state->outgoing_packet, buf, len);
+}
+
+void
+packet_put_bignum(BIGNUM * value)
+{
+       buffer_put_bignum(&active_state->outgoing_packet, value);
+}
+
+void
+packet_put_bignum2(BIGNUM * value)
+{
+       buffer_put_bignum2(&active_state->outgoing_packet, value);
+}
+
+#ifdef OPENSSL_HAS_ECC
+void
+packet_put_ecpoint(const EC_GROUP *curve, const EC_POINT *point)
+{
+       buffer_put_ecpoint(&active_state->outgoing_packet, curve, point);
+}
+#endif
+
+/*
+ * Finalizes and sends the packet.  If the encryption key has been set,
+ * encrypts the packet before sending.
+ */
+
+static void
+packet_send1(void)
+{
+       u_char buf[8], *cp;
+       int i, padding, len;
+       u_int checksum;
+       u_int32_t rnd = 0;
+
+       /*
+        * If using packet compression, compress the payload of the outgoing
+        * packet.
+        */
+       if (active_state->packet_compression) {
+               buffer_clear(&active_state->compression_buffer);
+               /* Skip padding. */
+               buffer_consume(&active_state->outgoing_packet, 8);
+               /* padding */
+               buffer_append(&active_state->compression_buffer,
+                   "\0\0\0\0\0\0\0\0", 8);
+               buffer_compress(&active_state->outgoing_packet,
+                   &active_state->compression_buffer);
+               buffer_clear(&active_state->outgoing_packet);
+               buffer_append(&active_state->outgoing_packet,
+                   buffer_ptr(&active_state->compression_buffer),
+                   buffer_len(&active_state->compression_buffer));
+       }
+       /* Compute packet length without padding (add checksum, remove padding). */
+       len = buffer_len(&active_state->outgoing_packet) + 4 - 8;
+
+       /* Insert padding. Initialized to zero in packet_start1() */
+       padding = 8 - len % 8;
+       if (!active_state->send_context.plaintext) {
+               cp = buffer_ptr(&active_state->outgoing_packet);
+               for (i = 0; i < padding; i++) {
+                       if (i % 4 == 0)
+                               rnd = arc4random();
+                       cp[7 - i] = rnd & 0xff;
+                       rnd >>= 8;
+               }
+       }
+       buffer_consume(&active_state->outgoing_packet, 8 - padding);
+
+       /* Add check bytes. */
+       checksum = ssh_crc32(buffer_ptr(&active_state->outgoing_packet),
+           buffer_len(&active_state->outgoing_packet));
+       put_u32(buf, checksum);
+       buffer_append(&active_state->outgoing_packet, buf, 4);
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "packet_send plain: ");
+       buffer_dump(&active_state->outgoing_packet);
+#endif
+
+       /* Append to output. */
+       put_u32(buf, len);
+       buffer_append(&active_state->output, buf, 4);
+       cp = buffer_append_space(&active_state->output,
+           buffer_len(&active_state->outgoing_packet));
+       cipher_crypt(&active_state->send_context, cp,
+           buffer_ptr(&active_state->outgoing_packet),
+           buffer_len(&active_state->outgoing_packet));
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "encrypted: ");
+       buffer_dump(&active_state->output);
+#endif
+       active_state->p_send.packets++;
+       active_state->p_send.bytes += len +
+           buffer_len(&active_state->outgoing_packet);
+       buffer_clear(&active_state->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.
+        */
+}
+
+void
+set_newkeys(int mode)
+{
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+       CipherContext *cc;
+       u_int64_t *max_blocks;
+       int crypt_type;
+
+       debug2("set_newkeys: mode %d", mode);
+
+       if (mode == MODE_OUT) {
+               cc = &active_state->send_context;
+               crypt_type = CIPHER_ENCRYPT;
+               active_state->p_send.packets = active_state->p_send.blocks = 0;
+               max_blocks = &active_state->max_blocks_out;
+       } else {
+               cc = &active_state->receive_context;
+               crypt_type = CIPHER_DECRYPT;
+               active_state->p_read.packets = active_state->p_read.blocks = 0;
+               max_blocks = &active_state->max_blocks_in;
+       }
+       if (active_state->newkeys[mode] != NULL) {
+               debug("set_newkeys: rekeying");
+               cipher_cleanup(cc);
+               enc  = &active_state->newkeys[mode]->enc;
+               mac  = &active_state->newkeys[mode]->mac;
+               comp = &active_state->newkeys[mode]->comp;
+               mac_clear(mac);
+               xfree(enc->name);
+               xfree(enc->iv);
+               xfree(enc->key);
+               xfree(mac->name);
+               xfree(mac->key);
+               xfree(comp->name);
+               xfree(active_state->newkeys[mode]);
+       }
+       active_state->newkeys[mode] = kex_get_newkeys(mode);
+       if (active_state->newkeys[mode] == NULL)
+               fatal("newkeys: no keys for mode %d", mode);
+       enc  = &active_state->newkeys[mode]->enc;
+       mac  = &active_state->newkeys[mode]->mac;
+       comp = &active_state->newkeys[mode]->comp;
+       if (mac_init(mac) == 0)
+               mac->enabled = 1;
+       DBG(debug("cipher_init_context: %d", mode));
+       cipher_init(cc, enc->cipher, enc->key, enc->key_len,
+           enc->iv, enc->block_size, crypt_type);
+       /* Deleting the keys does not gain extra security */
+       /* memset(enc->iv,  0, enc->block_size);
+          memset(enc->key, 0, enc->key_len);
+          memset(mac->key, 0, mac->key_len); */
+       if ((comp->type == COMP_ZLIB ||
+           (comp->type == COMP_DELAYED &&
+            active_state->after_authentication)) && comp->enabled == 0) {
+               packet_init_compression();
+               if (mode == MODE_OUT)
+                       buffer_compress_init_send(6);
+               else
+                       buffer_compress_init_recv();
+               comp->enabled = 1;
+       }
+       /*
+        * The 2^(blocksize*2) limit is too expensive for 3DES,
+        * blowfish, etc, so enforce a 1GB limit for small blocksizes.
+        */
+       if (enc->block_size >= 16)
+               *max_blocks = (u_int64_t)1 << (enc->block_size*2);
+       else
+               *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;
+       if (active_state->rekey_limit)
+               *max_blocks = MIN(*max_blocks,
+                   active_state->rekey_limit / enc->block_size);
+}
+
+/*
+ * Delayed compression for SSH2 is enabled after authentication:
+ * This happens on the server side after a SSH2_MSG_USERAUTH_SUCCESS is sent,
+ * and on the client side after a SSH2_MSG_USERAUTH_SUCCESS is received.
+ */
+static void
+packet_enable_delayed_compress(void)
+{
+       Comp *comp = NULL;
+       int mode;
+
+       /*
+        * Remember that we are past the authentication step, so rekeying
+        * with COMP_DELAYED will turn on compression immediately.
+        */
+       active_state->after_authentication = 1;
+       for (mode = 0; mode < MODE_MAX; mode++) {
+               /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */
+               if (active_state->newkeys[mode] == NULL)
+                       continue;
+               comp = &active_state->newkeys[mode]->comp;
+               if (comp && !comp->enabled && comp->type == COMP_DELAYED) {
+                       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_wrapped(void)
+{
+       u_char type, *cp, *macbuf = NULL;
+       u_char padlen, pad;
+       u_int packet_length = 0;
+       u_int i, len;
+       u_int32_t rnd = 0;
+       Enc *enc   = NULL;
+       Mac *mac   = NULL;
+       Comp *comp = NULL;
+       int block_size;
+
+       if (active_state->newkeys[MODE_OUT] != NULL) {
+               enc  = &active_state->newkeys[MODE_OUT]->enc;
+               mac  = &active_state->newkeys[MODE_OUT]->mac;
+               comp = &active_state->newkeys[MODE_OUT]->comp;
+       }
+       block_size = enc ? enc->block_size : 8;
+
+       cp = buffer_ptr(&active_state->outgoing_packet);
+       type = cp[5];
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "plain:     ");
+       buffer_dump(&active_state->outgoing_packet);
+#endif
+
+       if (comp && comp->enabled) {
+               len = buffer_len(&active_state->outgoing_packet);
+               /* skip header, compress only payload */
+               buffer_consume(&active_state->outgoing_packet, 5);
+               buffer_clear(&active_state->compression_buffer);
+               buffer_compress(&active_state->outgoing_packet,
+                   &active_state->compression_buffer);
+               buffer_clear(&active_state->outgoing_packet);
+               buffer_append(&active_state->outgoing_packet, "\0\0\0\0\0", 5);
+               buffer_append(&active_state->outgoing_packet,
+                   buffer_ptr(&active_state->compression_buffer),
+                   buffer_len(&active_state->compression_buffer));
+               DBG(debug("compression: raw %d compressed %d", len,
+                   buffer_len(&active_state->outgoing_packet)));
+       }
+
+       /* sizeof (packet_len + pad_len + payload) */
+       len = buffer_len(&active_state->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 (active_state->extra_pad) {
+               /* will wrap if extra_pad+padlen > 255 */
+               active_state->extra_pad =
+                   roundup(active_state->extra_pad, block_size);
+               pad = active_state->extra_pad -
+                   ((len + padlen) % active_state->extra_pad);
+               debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)",
+                   pad, len, padlen, active_state->extra_pad);
+               padlen += pad;
+               active_state->extra_pad = 0;
+       }
+       cp = buffer_append_space(&active_state->outgoing_packet, padlen);
+       if (enc && !active_state->send_context.plaintext) {
+               /* random padding */
+               for (i = 0; i < padlen; i++) {
+                       if (i % 4 == 0)
+                               rnd = arc4random();
+                       cp[i] = rnd & 0xff;
+                       rnd >>= 8;
+               }
+       } else {
+               /* clear padding */
+               memset(cp, 0, padlen);
+       }
+       /* packet_length includes payload, padding and padding length field */
+       packet_length = buffer_len(&active_state->outgoing_packet) - 4;
+       cp = buffer_ptr(&active_state->outgoing_packet);
+       put_u32(cp, packet_length);
+       cp[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, active_state->p_send.seqnr,
+                   buffer_ptr(&active_state->outgoing_packet),
+                   buffer_len(&active_state->outgoing_packet));
+               DBG(debug("done calc MAC out #%d", active_state->p_send.seqnr));
+       }
+       /* encrypt packet and append to output buffer. */
+       cp = buffer_append_space(&active_state->output,
+           buffer_len(&active_state->outgoing_packet));
+       cipher_crypt(&active_state->send_context, cp,
+           buffer_ptr(&active_state->outgoing_packet),
+           buffer_len(&active_state->outgoing_packet));
+       /* append unencrypted MAC */
+       if (mac && mac->enabled)
+               buffer_append(&active_state->output, macbuf, mac->mac_len);
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "encrypted: ");
+       buffer_dump(&active_state->output);
+#endif
+       /* increment sequence number for outgoing packets */
+       if (++active_state->p_send.seqnr == 0)
+               logit("outgoing seqnr wraps around");
+       if (++active_state->p_send.packets == 0)
+               if (!(datafellows & SSH_BUG_NOREKEY))
+                       fatal("XXX too many packets with same key");
+       active_state->p_send.blocks += (packet_length + 4) / block_size;
+       active_state->p_send.bytes += packet_length + 4;
+       buffer_clear(&active_state->outgoing_packet);
+
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_OUT);
+       else if (type == SSH2_MSG_USERAUTH_SUCCESS && active_state->server_side)
+               packet_enable_delayed_compress();
+}
+
+static void
+packet_send2(void)
+{
+       struct packet *p;
+       u_char type, *cp;
+
+       cp = buffer_ptr(&active_state->outgoing_packet);
+       type = cp[5];
+
+       /* during rekeying we can only send key exchange messages */
+       if (active_state->rekeying) {
+               if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&
+                   (type <= SSH2_MSG_TRANSPORT_MAX))) {
+                       debug("enqueue packet: %u", type);
+                       p = xmalloc(sizeof(*p));
+                       p->type = type;
+                       memcpy(&p->payload, &active_state->outgoing_packet,
+                           sizeof(Buffer));
+                       buffer_init(&active_state->outgoing_packet);
+                       TAILQ_INSERT_TAIL(&active_state->outgoing, p, next);
+                       return;
+               }
+       }
+
+       /* rekeying starts with sending KEXINIT */
+       if (type == SSH2_MSG_KEXINIT)
+               active_state->rekeying = 1;
+
+       packet_send2_wrapped();
+
+       /* after a NEWKEYS message we can send the complete queue */
+       if (type == SSH2_MSG_NEWKEYS) {
+               active_state->rekeying = 0;
+               while ((p = TAILQ_FIRST(&active_state->outgoing))) {
+                       type = p->type;
+                       debug("dequeue packet: %u", type);
+                       buffer_free(&active_state->outgoing_packet);
+                       memcpy(&active_state->outgoing_packet, &p->payload,
+                           sizeof(Buffer));
+                       TAILQ_REMOVE(&active_state->outgoing, p, next);
+                       xfree(p);
+                       packet_send2_wrapped();
+               }
+       }
+}
+
+void
+packet_send(void)
+{
+       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_seqnr(u_int32_t *seqnr_p)
+{
+       int type, len, ret, ms_remain, cont;
+       fd_set *setp;
+       char buf[8192];
+       struct timeval timeout, start, *timeoutp = NULL;
+
+       DBG(debug("packet_read()"));
+
+       setp = (fd_set *)xcalloc(howmany(active_state->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_seqnr(seqnr_p);
+               if (!compat20 && (
+                   type == SSH_SMSG_SUCCESS
+                   || type == SSH_SMSG_FAILURE
+                   || type == SSH_CMSG_EOF
+                   || type == SSH_CMSG_EXIT_CONFIRMATION))
+                       packet_check_eom();
+               /* 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(active_state->connection_in + 1,
+                   NFDBITS) * sizeof(fd_mask));
+               FD_SET(active_state->connection_in, setp);
+
+               if (active_state->packet_timeout_ms > 0) {
+                       ms_remain = active_state->packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
+               /* Wait for some data to arrive. */
+               for (;;) {
+                       if (active_state->packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(active_state->connection_in + 1, setp,
+                           NULL, NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (active_state->packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to read", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
+               /* Read data from the socket. */
+               do {
+                       cont = 0;
+                       len = roaming_read(active_state->connection_in, buf,
+                           sizeof(buf), &cont);
+               } while (len == 0 && cont);
+               if (len == 0) {
+                       logit("Connection closed by %.200s", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
+               if (len < 0)
+                       fatal("Read from socket failed: %.100s", strerror(errno));
+               /* Append it to the buffer. */
+               packet_process_incoming(buf, len);
+       }
+       /* NOTREACHED */
+}
+
+int
+packet_read(void)
+{
+       return packet_read_seqnr(NULL);
+}
+
+/*
+ * 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 expected_type)
+{
+       int type;
+
+       type = packet_read();
+       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.
+ */
+
+static int
+packet_read_poll1(void)
+{
+       u_int len, padded_len;
+       u_char *cp, type;
+       u_int checksum, stored_checksum;
+
+       /* Check if input size is less than minimum packet size. */
+       if (buffer_len(&active_state->input) < 4 + 8)
+               return SSH_MSG_NONE;
+       /* Get length of incoming packet. */
+       cp = buffer_ptr(&active_state->input);
+       len = get_u32(cp);
+       if (len < 1 + 2 + 2 || len > 256 * 1024)
+               packet_disconnect("Bad packet length %u.", len);
+       padded_len = (len + 8) & ~7;
+
+       /* Check if the packet has been entirely received. */
+       if (buffer_len(&active_state->input) < 4 + padded_len)
+               return SSH_MSG_NONE;
+
+       /* The entire packet is in buffer. */
+
+       /* Consume packet length. */
+       buffer_consume(&active_state->input, 4);
+
+       /*
+        * Cryptographic attack detector for ssh
+        * (C)1998 CORE-SDI, Buenos Aires Argentina
+        * Ariel Futoransky(futo@core-sdi.com)
+        */
+       if (!active_state->receive_context.plaintext) {
+               switch (detect_attack(buffer_ptr(&active_state->input),
+                   padded_len)) {
+               case DEATTACK_DETECTED:
+                       packet_disconnect("crc32 compensation attack: "
+                           "network attack detected");
+               case DEATTACK_DOS_DETECTED:
+                       packet_disconnect("deattack denial of "
+                           "service detected");
+               }
+       }
+
+       /* Decrypt data to incoming_packet. */
+       buffer_clear(&active_state->incoming_packet);
+       cp = buffer_append_space(&active_state->incoming_packet, padded_len);
+       cipher_crypt(&active_state->receive_context, cp,
+           buffer_ptr(&active_state->input), padded_len);
+
+       buffer_consume(&active_state->input, padded_len);
+
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read_poll plain: ");
+       buffer_dump(&active_state->incoming_packet);
+#endif
+
+       /* Compute packet checksum. */
+       checksum = ssh_crc32(buffer_ptr(&active_state->incoming_packet),
+           buffer_len(&active_state->incoming_packet) - 4);
+
+       /* Skip padding. */
+       buffer_consume(&active_state->incoming_packet, 8 - len % 8);
+
+       /* Test check bytes. */
+       if (len != buffer_len(&active_state->incoming_packet))
+               packet_disconnect("packet_read_poll1: len %d != buffer_len %d.",
+                   len, buffer_len(&active_state->incoming_packet));
+
+       cp = (u_char *)buffer_ptr(&active_state->incoming_packet) + len - 4;
+       stored_checksum = get_u32(cp);
+       if (checksum != stored_checksum)
+               packet_disconnect("Corrupted check bytes on input.");
+       buffer_consume_end(&active_state->incoming_packet, 4);
+
+       if (active_state->packet_compression) {
+               buffer_clear(&active_state->compression_buffer);
+               buffer_uncompress(&active_state->incoming_packet,
+                   &active_state->compression_buffer);
+               buffer_clear(&active_state->incoming_packet);
+               buffer_append(&active_state->incoming_packet,
+                   buffer_ptr(&active_state->compression_buffer),
+                   buffer_len(&active_state->compression_buffer));
+       }
+       active_state->p_read.packets++;
+       active_state->p_read.bytes += padded_len + 4;
+       type = buffer_get_char(&active_state->incoming_packet);
+       if (type < SSH_MSG_MIN || type > SSH_MSG_MAX)
+               packet_disconnect("Invalid ssh1 packet type: %d", type);
+       return type;
+}
+
+static int
+packet_read_poll2(u_int32_t *seqnr_p)
+{
+       u_int padlen, need;
+       u_char *macbuf, *cp, type;
+       u_int maclen, block_size;
+       Enc *enc   = NULL;
+       Mac *mac   = NULL;
+       Comp *comp = NULL;
+
+       if (active_state->packet_discard)
+               return SSH_MSG_NONE;
+
+       if (active_state->newkeys[MODE_IN] != NULL) {
+               enc  = &active_state->newkeys[MODE_IN]->enc;
+               mac  = &active_state->newkeys[MODE_IN]->mac;
+               comp = &active_state->newkeys[MODE_IN]->comp;
+       }
+       maclen = mac && mac->enabled ? mac->mac_len : 0;
+       block_size = enc ? enc->block_size : 8;
+
+       if (active_state->packlen == 0) {
+               /*
+                * check if input size is less than the cipher block size,
+                * decrypt first block and extract length of incoming packet
+                */
+               if (buffer_len(&active_state->input) < block_size)
+                       return SSH_MSG_NONE;
+               buffer_clear(&active_state->incoming_packet);
+               cp = buffer_append_space(&active_state->incoming_packet,
+                   block_size);
+               cipher_crypt(&active_state->receive_context, cp,
+                   buffer_ptr(&active_state->input), block_size);
+               cp = buffer_ptr(&active_state->incoming_packet);
+               active_state->packlen = get_u32(cp);
+               if (active_state->packlen < 1 + 4 ||
+                   active_state->packlen > PACKET_MAX_SIZE) {
+#ifdef PACKET_DEBUG
+                       buffer_dump(&active_state->incoming_packet);
+#endif
+                       logit("Bad packet length %u.", active_state->packlen);
+                       packet_start_discard(enc, mac, active_state->packlen,
+                           PACKET_MAX_SIZE);
+                       return SSH_MSG_NONE;
+               }
+               DBG(debug("input: packet len %u", active_state->packlen+4));
+               buffer_consume(&active_state->input, block_size);
+       }
+       /* we have a partial packet of block_size bytes */
+       need = 4 + active_state->packlen - block_size;
+       DBG(debug("partial packet %d, need %d, maclen %d", block_size,
+           need, maclen));
+       if (need % block_size != 0) {
+               logit("padding error: need %d block %d mod %d",
+                   need, block_size, need % block_size);
+               packet_start_discard(enc, mac, active_state->packlen,
+                   PACKET_MAX_SIZE - block_size);
+               return SSH_MSG_NONE;
+       }
+       /*
+        * check if the entire packet has been received and
+        * decrypt into incoming_packet
+        */
+       if (buffer_len(&active_state->input) < need + maclen)
+               return SSH_MSG_NONE;
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read_poll enc/full: ");
+       buffer_dump(&active_state->input);
+#endif
+       cp = buffer_append_space(&active_state->incoming_packet, need);
+       cipher_crypt(&active_state->receive_context, cp,
+           buffer_ptr(&active_state->input), need);
+       buffer_consume(&active_state->input, need);
+       /*
+        * compute MAC over seqnr and packet,
+        * increment sequence number for incoming packet
+        */
+       if (mac && mac->enabled) {
+               macbuf = mac_compute(mac, active_state->p_read.seqnr,
+                   buffer_ptr(&active_state->incoming_packet),
+                   buffer_len(&active_state->incoming_packet));
+               if (timingsafe_bcmp(macbuf, buffer_ptr(&active_state->input),
+                   mac->mac_len) != 0) {
+                       logit("Corrupted MAC on input.");
+                       if (need > PACKET_MAX_SIZE)
+                               fatal("internal error need %d", need);
+                       packet_start_discard(enc, mac, active_state->packlen,
+                           PACKET_MAX_SIZE - need);
+                       return SSH_MSG_NONE;
+               }
+                               
+               DBG(debug("MAC #%d ok", active_state->p_read.seqnr));
+               buffer_consume(&active_state->input, mac->mac_len);
+       }
+       /* XXX now it's safe to use fatal/packet_disconnect */
+       if (seqnr_p != NULL)
+               *seqnr_p = active_state->p_read.seqnr;
+       if (++active_state->p_read.seqnr == 0)
+               logit("incoming seqnr wraps around");
+       if (++active_state->p_read.packets == 0)
+               if (!(datafellows & SSH_BUG_NOREKEY))
+                       fatal("XXX too many packets with same key");
+       active_state->p_read.blocks += (active_state->packlen + 4) / block_size;
+       active_state->p_read.bytes += active_state->packlen + 4;
+
+       /* get padlen */
+       cp = buffer_ptr(&active_state->incoming_packet);
+       padlen = cp[4];
+       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(&active_state->incoming_packet, 4 + 1);
+       buffer_consume_end(&active_state->incoming_packet, padlen);
+
+       DBG(debug("input: len before de-compress %d",
+           buffer_len(&active_state->incoming_packet)));
+       if (comp && comp->enabled) {
+               buffer_clear(&active_state->compression_buffer);
+               buffer_uncompress(&active_state->incoming_packet,
+                   &active_state->compression_buffer);
+               buffer_clear(&active_state->incoming_packet);
+               buffer_append(&active_state->incoming_packet,
+                   buffer_ptr(&active_state->compression_buffer),
+                   buffer_len(&active_state->compression_buffer));
+               DBG(debug("input: len after de-compress %d",
+                   buffer_len(&active_state->incoming_packet)));
+       }
+       /*
+        * get packet type, implies consume.
+        * return length of payload (without type field)
+        */
+       type = buffer_get_char(&active_state->incoming_packet);
+       if (type < SSH2_MSG_MIN || type >= SSH2_MSG_LOCAL_MIN)
+               packet_disconnect("Invalid ssh2 packet type: %d", type);
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_IN);
+       else if (type == SSH2_MSG_USERAUTH_SUCCESS &&
+           !active_state->server_side)
+               packet_enable_delayed_compress();
+#ifdef PACKET_DEBUG
+       fprintf(stderr, "read/plain[%d]:\r\n", type);
+       buffer_dump(&active_state->incoming_packet);
+#endif
+       /* reset for next packet */
+       active_state->packlen = 0;
+       return type;
+}
+
+int
+packet_read_poll_seqnr(u_int32_t *seqnr_p)
+{
+       u_int reason, seqnr;
+       u_char type;
+       char *msg;
+
+       for (;;) {
+               if (compat20) {
+                       type = packet_read_poll2(seqnr_p);
+                       if (type) {
+                               active_state->keep_alive_timeouts = 0;
+                               DBG(debug("received packet type %d", type));
+                       }
+                       switch (type) {
+                       case SSH2_MSG_IGNORE:
+                               debug3("Received 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);
+                               logit("Received disconnect from %s: %u: %.400s",
+                                   get_remote_ipaddr(), reason, msg);
+                               xfree(msg);
+                               cleanup_exit(255);
+                               break;
+                       case SSH2_MSG_UNIMPLEMENTED:
+                               seqnr = packet_get_int();
+                               debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
+                                   seqnr);
+                               break;
+                       default:
+                               return type;
+                       }
+               } else {
+                       type = packet_read_poll1();
+                       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);
+                               logit("Received disconnect from %s: %.400s",
+                                   get_remote_ipaddr(), msg);
+                               cleanup_exit(255);
+                               break;
+                       default:
+                               if (type)
+                                       DBG(debug("received packet type %d", type));
+                               return type;
+                       }
+               }
+       }
+}
+
+int
+packet_read_poll(void)
+{
+       return packet_read_poll_seqnr(NULL);
+}
+
+/*
+ * 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)
+{
+       if (active_state->packet_discard) {
+               active_state->keep_alive_timeouts = 0; /* ?? */
+               if (len >= active_state->packet_discard)
+                       packet_stop_discard();
+               active_state->packet_discard -= len;
+               return;
+       }
+       buffer_append(&active_state->input, buf, len);
+}
+
+/* Returns a character from the packet. */
+
+u_int
+packet_get_char(void)
+{
+       char ch;
+
+       buffer_get(&active_state->incoming_packet, &ch, 1);
+       return (u_char) ch;
+}
+
+/* Returns an integer from the packet data. */
+
+u_int
+packet_get_int(void)
+{
+       return buffer_get_int(&active_state->incoming_packet);
+}
+
+/* Returns an 64 bit integer from the packet data. */
+
+u_int64_t
+packet_get_int64(void)
+{
+       return buffer_get_int64(&active_state->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)
+{
+       buffer_get_bignum(&active_state->incoming_packet, value);
+}
+
+void
+packet_get_bignum2(BIGNUM * value)
+{
+       buffer_get_bignum2(&active_state->incoming_packet, value);
+}
+
+#ifdef OPENSSL_HAS_ECC
+void
+packet_get_ecpoint(const EC_GROUP *curve, EC_POINT *point)
+{
+       buffer_get_ecpoint(&active_state->incoming_packet, curve, point);
+}
+#endif
+
+void *
+packet_get_raw(u_int *length_ptr)
+{
+       u_int bytes = buffer_len(&active_state->incoming_packet);
+
+       if (length_ptr != NULL)
+               *length_ptr = bytes;
+       return buffer_ptr(&active_state->incoming_packet);
+}
+
+int
+packet_remaining(void)
+{
+       return buffer_len(&active_state->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.
+ */
+
+void *
+packet_get_string(u_int *length_ptr)
+{
+       return buffer_get_string(&active_state->incoming_packet, length_ptr);
+}
+
+void *
+packet_get_string_ptr(u_int *length_ptr)
+{
+       return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr);
+}
+
+/* Ensures the returned string has no embedded \0 characters in it. */
+char *
+packet_get_cstring(u_int *length_ptr)
+{
+       return buffer_get_cstring(&active_state->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);
+
+       /* Display the error locally */
+       logit("Disconnecting: %.100s", buf);
+
+       /* 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();
+       cleanup_exit(255);
+}
+
+/* Checks if there is any buffered output, and tries to write some of the output. */
+
+void
+packet_write_poll(void)
+{
+       int len = buffer_len(&active_state->output);
+       int cont;
+
+       if (len > 0) {
+               cont = 0;
+               len = roaming_write(active_state->connection_out,
+                   buffer_ptr(&active_state->output), len, &cont);
+               if (len == -1) {
+                       if (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK)
+                               return;
+                       fatal("Write failed: %.100s", strerror(errno));
+               }
+               if (len == 0 && !cont)
+                       fatal("Write connection closed");
+               buffer_consume(&active_state->output, len);
+       }
+}
+
+/*
+ * Calls packet_write_poll repeatedly until all pending output data has been
+ * written.
+ */
+
+void
+packet_write_wait(void)
+{
+       fd_set *setp;
+       int ret, ms_remain;
+       struct timeval start, timeout, *timeoutp = NULL;
+
+       setp = (fd_set *)xcalloc(howmany(active_state->connection_out + 1,
+           NFDBITS), sizeof(fd_mask));
+       packet_write_poll();
+       while (packet_have_data_to_write()) {
+               memset(setp, 0, howmany(active_state->connection_out + 1,
+                   NFDBITS) * sizeof(fd_mask));
+               FD_SET(active_state->connection_out, setp);
+
+               if (active_state->packet_timeout_ms > 0) {
+                       ms_remain = active_state->packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
+               for (;;) {
+                       if (active_state->packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(active_state->connection_out + 1,
+                           NULL, setp, NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (active_state->packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to write", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
+               packet_write_poll();
+       }
+       xfree(setp);
+}
+
+/* Returns true if there is buffered data to write to the connection. */
+
+int
+packet_have_data_to_write(void)
+{
+       return buffer_len(&active_state->output) != 0;
+}
+
+/* Returns true if there is not too much data to write to the connection. */
+
+int
+packet_not_very_much_data_to_write(void)
+{
+       if (active_state->interactive_mode)
+               return buffer_len(&active_state->output) < 16384;
+       else
+               return buffer_len(&active_state->output) < 128 * 1024;
+}
+
+static void
+packet_set_tos(int tos)
+{
+#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
+       if (!packet_connection_is_on_socket() ||
+           !packet_connection_is_ipv4())
+               return;
+       debug3("%s: set IP_TOS 0x%02x", __func__, tos);
+       if (setsockopt(active_state->connection_in, IPPROTO_IP, IP_TOS, &tos,
+           sizeof(tos)) < 0)
+               error("setsockopt IP_TOS %d: %.100s:",
+                   tos, strerror(errno));
+#endif
+}
+
+/* Informs that the current session is interactive.  Sets IP flags for that. */
+
+void
+packet_set_interactive(int interactive, int qos_interactive, int qos_bulk)
+{
+       if (active_state->set_interactive_called)
+               return;
+       active_state->set_interactive_called = 1;
+
+       /* Record that we are in interactive mode. */
+       active_state->interactive_mode = interactive;
+
+       /* Only set socket options if using a socket.  */
+       if (!packet_connection_is_on_socket())
+               return;
+       set_nodelay(active_state->connection_in);
+       packet_set_tos(interactive ? qos_interactive : qos_bulk);
+}
+
+/* Returns true if the current connection is interactive. */
+
+int
+packet_is_interactive(void)
+{
+       return active_state->interactive_mode;
+}
+
+int
+packet_set_maxsize(u_int s)
+{
+       if (active_state->set_maxsize_called) {
+               logit("packet_set_maxsize: called twice: old %d new %d",
+                   active_state->max_packet_size, s);
+               return -1;
+       }
+       if (s < 4 * 1024 || s > 1024 * 1024) {
+               logit("packet_set_maxsize: bad size %d", s);
+               return -1;
+       }
+       active_state->set_maxsize_called = 1;
+       debug("packet_set_maxsize: setting to %d", s);
+       active_state->max_packet_size = s;
+       return s;
+}
+
+int
+packet_inc_alive_timeouts(void)
+{
+       return ++active_state->keep_alive_timeouts;
+}
+
+void
+packet_set_alive_timeouts(int ka)
+{
+       active_state->keep_alive_timeouts = ka;
+}
+
+u_int
+packet_get_maxsize(void)
+{
+       return active_state->max_packet_size;
+}
+
+/* roundup current message to pad bytes */
+void
+packet_add_padding(u_char pad)
+{
+       active_state->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 rnd = 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)
+                       rnd = arc4random();
+               packet_put_char((u_char)rnd & 0xff);
+               rnd >>= 8;
+       }
+}
+
+#define MAX_PACKETS    (1U<<31)
+int
+packet_need_rekeying(void)
+{
+       if (datafellows & SSH_BUG_NOREKEY)
+               return 0;
+       return
+           (active_state->p_send.packets > MAX_PACKETS) ||
+           (active_state->p_read.packets > MAX_PACKETS) ||
+           (active_state->max_blocks_out &&
+               (active_state->p_send.blocks > active_state->max_blocks_out)) ||
+           (active_state->max_blocks_in &&
+               (active_state->p_read.blocks > active_state->max_blocks_in));
+}
+
+void
+packet_set_rekey_limit(u_int32_t bytes)
+{
+       active_state->rekey_limit = bytes;
+}
+
+void
+packet_set_server(void)
+{
+       active_state->server_side = 1;
+}
+
+void
+packet_set_authenticated(void)
+{
+       active_state->after_authentication = 1;
+}
+
+void *
+packet_get_input(void)
+{
+       return (void *)&active_state->input;
+}
+
+void *
+packet_get_output(void)
+{
+       return (void *)&active_state->output;
+}
+
+void *
+packet_get_newkeys(int mode)
+{
+       return (void *)active_state->newkeys[mode];
+}
+
+/*
+ * Save the state for the real connection, and use a separate state when
+ * resuming a suspended connection.
+ */
+void
+packet_backup_state(void)
+{
+       struct session_state *tmp;
+
+       close(active_state->connection_in);
+       active_state->connection_in = -1;
+       close(active_state->connection_out);
+       active_state->connection_out = -1;
+       if (backup_state)
+               tmp = backup_state;
+       else
+               tmp = alloc_session_state();
+       backup_state = active_state;
+       active_state = tmp;
+}
+
+/*
+ * Swap in the old state when resuming a connecion.
+ */
+void
+packet_restore_state(void)
+{
+       struct session_state *tmp;
+       void *buf;
+       u_int len;
+
+       tmp = backup_state;
+       backup_state = active_state;
+       active_state = tmp;
+       active_state->connection_in = backup_state->connection_in;
+       backup_state->connection_in = -1;
+       active_state->connection_out = backup_state->connection_out;
+       backup_state->connection_out = -1;
+       len = buffer_len(&backup_state->input);
+       if (len > 0) {
+               buf = buffer_ptr(&backup_state->input);
+               buffer_append(&active_state->input, buf, len);
+               buffer_clear(&backup_state->input);
+               add_recv_bytes(len);
+       }
+}
diff --git a/packet.h b/packet.h
new file mode 100644 (file)
index 0000000..d516aae
--- /dev/null
+++ b/packet.h
@@ -0,0 +1,128 @@
+/* $OpenBSD: packet.h,v 1.55 2010/11/13 23:27:50 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#ifndef PACKET_H
+#define PACKET_H
+
+#include <termios.h>
+
+#include <openssl/bn.h>
+#ifdef OPENSSL_HAS_ECC
+#include <openssl/ec.h>
+#endif
+
+void     packet_set_connection(int, int);
+void     packet_set_timeout(int, int);
+void     packet_set_nonblocking(void);
+int      packet_get_connection_in(void);
+int      packet_get_connection_out(void);
+void     packet_close(void);
+void    packet_set_encryption_key(const u_char *, u_int, int);
+u_int   packet_get_encryption_key(u_char *);
+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, int);
+int      packet_is_interactive(void);
+void     packet_set_server(void);
+void     packet_set_authenticated(void);
+
+void     packet_start(u_char);
+void     packet_put_char(int ch);
+void     packet_put_int(u_int value);
+void     packet_put_int64(u_int64_t value);
+void     packet_put_bignum(BIGNUM * value);
+void     packet_put_bignum2(BIGNUM * value);
+#ifdef OPENSSL_HAS_ECC
+void     packet_put_ecpoint(const EC_GROUP *, const EC_POINT *);
+#endif
+void     packet_put_string(const void *buf, u_int len);
+void     packet_put_cstring(const char *str);
+void     packet_put_raw(const void *buf, u_int len);
+void     packet_send(void);
+
+int      packet_read(void);
+void     packet_read_expect(int type);
+int      packet_read_poll(void);
+void     packet_process_incoming(const char *buf, u_int len);
+int      packet_read_seqnr(u_int32_t *seqnr_p);
+int      packet_read_poll_seqnr(u_int32_t *seqnr_p);
+
+u_int   packet_get_char(void);
+u_int   packet_get_int(void);
+u_int64_t packet_get_int64(void);
+void     packet_get_bignum(BIGNUM * value);
+void     packet_get_bignum2(BIGNUM * value);
+#ifdef OPENSSL_HAS_ECC
+void    packet_get_ecpoint(const EC_GROUP *, EC_POINT *);
+#endif
+void   *packet_get_raw(u_int *length_ptr);
+void   *packet_get_string(u_int *length_ptr);
+char   *packet_get_cstring(u_int *length_ptr);
+void   *packet_get_string_ptr(u_int *length_ptr);
+void     packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void     packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+
+void    set_newkeys(int mode);
+int     packet_get_keyiv_len(int);
+void    packet_get_keyiv(int, u_char *, u_int);
+int     packet_get_keycontext(int, u_char *);
+void    packet_set_keycontext(int, u_char *);
+void    packet_get_state(int, u_int32_t *, u_int64_t *, u_int32_t *, u_int64_t *);
+void    packet_set_state(int, u_int32_t, u_int64_t, u_int32_t, u_int64_t);
+int     packet_get_ssh1_cipher(void);
+void    packet_set_iv(int, u_char *);
+void   *packet_get_newkeys(int);
+
+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 *);
+
+void    packet_set_alive_timeouts(int);
+int     packet_inc_alive_timeouts(void);
+int     packet_set_maxsize(u_int);
+u_int   packet_get_maxsize(void);
+
+/* don't allow remaining bytes after the end of the message */
+#define packet_check_eom() \
+do { \
+       int _len = packet_remaining(); \
+       if (_len > 0) { \
+               logit("Packet integrity error (%d bytes remaining) at %s:%d", \
+                   _len ,__FILE__, __LINE__); \
+               packet_disconnect("Packet integrity error."); \
+       } \
+} while (0)
+
+int     packet_need_rekeying(void);
+void    packet_set_rekey_limit(u_int32_t);
+
+void    packet_backup_state(void);
+void    packet_restore_state(void);
+
+void   *packet_get_input(void);
+void   *packet_get_output(void);
+
+#endif                         /* PACKET_H */
diff --git a/pathnames.h b/pathnames.h
new file mode 100644 (file)
index 0000000..e2dd49a
--- /dev/null
@@ -0,0 +1,181 @@
+/* $OpenBSD: pathnames.h,v 1.20 2010/08/31 11:54:45 djm 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 ETCDIR                         "/etc"
+
+#ifndef SSHDIR
+#define SSHDIR                         ETCDIR "/ssh"
+#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      SSHDIR "/ssh_known_hosts"
+/* backward compat for protocol 2 */
+#define _PATH_SSH_SYSTEM_HOSTFILE2     SSHDIR "/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       SSHDIR "/sshd_config"
+#define _PATH_HOST_CONFIG_FILE         SSHDIR "/ssh_config"
+#define _PATH_HOST_KEY_FILE            SSHDIR "/ssh_host_key"
+#define _PATH_HOST_DSA_KEY_FILE                SSHDIR "/ssh_host_dsa_key"
+#define _PATH_HOST_ECDSA_KEY_FILE      SSHDIR "/ssh_host_ecdsa_key"
+#define _PATH_HOST_RSA_KEY_FILE                SSHDIR "/ssh_host_rsa_key"
+#define _PATH_DH_MODULI                        SSHDIR "/moduli"
+/* Backwards compatibility */
+#define _PATH_DH_PRIMES                        SSHDIR "/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_ECDSA      ".ssh/id_ecdsa"
+#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            SSHDIR "/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          SSHDIR "/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
+
+/* Location of ssh-keysign for hostbased authentication */
+#ifndef _PATH_SSH_KEY_SIGN
+#define _PATH_SSH_KEY_SIGN             "/usr/libexec/ssh-keysign"
+#endif
+
+/* Location of ssh-pkcs11-helper to support keys in tokens */
+#ifndef _PATH_SSH_PKCS11_HELPER
+#define _PATH_SSH_PKCS11_HELPER                "/usr/libexec/ssh-pkcs11-helper"
+#endif
+
+/* xauth for X11 forwarding */
+#ifndef _PATH_XAUTH
+#define _PATH_XAUTH                    "/usr/X11R6/bin/xauth"
+#endif
+
+/* UNIX domain socket for X11 server; displaynum will replace %u */
+#ifndef _PATH_UNIX_X
+#define _PATH_UNIX_X "/tmp/.X11-unix/X%u"
+#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
+
+/* chroot directory for unprivileged user when UsePrivilegeSeparation=yes */
+#ifndef _PATH_PRIVSEP_CHROOT_DIR
+#define _PATH_PRIVSEP_CHROOT_DIR       "/var/empty"
+#endif
+
+/* for passwd change */
+#ifndef _PATH_PASSWD_PROG
+#define _PATH_PASSWD_PROG             "/usr/bin/passwd"
+#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 */
diff --git a/pkcs11.h b/pkcs11.h
new file mode 100644 (file)
index 0000000..2cde5b3
--- /dev/null
+++ b/pkcs11.h
@@ -0,0 +1,1357 @@
+/* $OpenBSD: pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */
+/* pkcs11.h
+   Copyright 2006, 2007 g10 Code GmbH
+   Copyright 2006 Andreas Jellinghaus
+
+   This file is free software; as a special exception the author gives
+   unlimited permission to copy and/or distribute it, with or without
+   modifications, as long as this notice is preserved.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+   PURPOSE.  */
+
+/* Please submit changes back to the Scute project at
+   http://www.scute.org/ (or send them to marcus@g10code.com), so that
+   they can be picked up by other projects from there as well.  */
+
+/* This file is a modified implementation of the PKCS #11 standard by
+   RSA Security Inc.  It is mostly a drop-in replacement, with the
+   following change:
+
+   This header file does not require any macro definitions by the user
+   (like CK_DEFINE_FUNCTION etc).  In fact, it defines those macros
+   for you (if useful, some are missing, let me know if you need
+   more).
+
+   There is an additional API available that does comply better to the
+   GNU coding standard.  It can be switched on by defining
+   CRYPTOKI_GNU before including this header file.  For this, the
+   following changes are made to the specification:
+
+   All structure types are changed to a "struct ck_foo" where CK_FOO
+   is the type name in PKCS #11.
+
+   All non-structure types are changed to ck_foo_t where CK_FOO is the
+   lowercase version of the type name in PKCS #11.  The basic types
+   (CK_ULONG et al.) are removed without substitute.
+
+   All members of structures are modified in the following way: Type
+   indication prefixes are removed, and underscore characters are
+   inserted before words.  Then the result is lowercased.
+
+   Note that function names are still in the original case, as they
+   need for ABI compatibility.
+
+   CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute.  Use
+   <stdbool.h>.
+
+   If CRYPTOKI_COMPAT is defined before including this header file,
+   then none of the API changes above take place, and the API is the
+   one defined by the PKCS #11 standard.  */
+
+#ifndef PKCS11_H
+#define PKCS11_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* The version of cryptoki we implement.  The revision is changed with
+   each modification of this file.  If you do not use the "official"
+   version of this file, please consider deleting the revision macro
+   (you may use a macro with a different name to keep track of your
+   versions).  */
+#define CRYPTOKI_VERSION_MAJOR         2
+#define CRYPTOKI_VERSION_MINOR         20
+#define CRYPTOKI_VERSION_REVISION      6
+
+
+/* Compatibility interface is default, unless CRYPTOKI_GNU is
+   given.  */
+#ifndef CRYPTOKI_GNU
+#ifndef CRYPTOKI_COMPAT
+#define CRYPTOKI_COMPAT 1
+#endif
+#endif
+
+/* System dependencies.  */
+
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+
+/* There is a matching pop below.  */
+#pragma pack(push, cryptoki, 1)
+
+#ifdef CRYPTOKI_EXPORTS
+#define CK_SPEC __declspec(dllexport)
+#else
+#define CK_SPEC __declspec(dllimport)
+#endif
+
+#else
+
+#define CK_SPEC
+
+#endif
+
+
+#ifdef CRYPTOKI_COMPAT
+  /* If we are in compatibility mode, switch all exposed names to the
+     PKCS #11 variant.  There are corresponding #undefs below.  */
+
+#define ck_flags_t CK_FLAGS
+#define ck_version _CK_VERSION
+
+#define ck_info _CK_INFO
+#define cryptoki_version cryptokiVersion
+#define manufacturer_id manufacturerID
+#define library_description libraryDescription
+#define library_version libraryVersion
+
+#define ck_notification_t CK_NOTIFICATION
+#define ck_slot_id_t CK_SLOT_ID
+
+#define ck_slot_info _CK_SLOT_INFO
+#define slot_description slotDescription
+#define hardware_version hardwareVersion
+#define firmware_version firmwareVersion
+
+#define ck_token_info _CK_TOKEN_INFO
+#define serial_number serialNumber
+#define max_session_count ulMaxSessionCount
+#define session_count ulSessionCount
+#define max_rw_session_count ulMaxRwSessionCount
+#define rw_session_count ulRwSessionCount
+#define max_pin_len ulMaxPinLen
+#define min_pin_len ulMinPinLen
+#define total_public_memory ulTotalPublicMemory
+#define free_public_memory ulFreePublicMemory
+#define total_private_memory ulTotalPrivateMemory
+#define free_private_memory ulFreePrivateMemory
+#define utc_time utcTime
+
+#define ck_session_handle_t CK_SESSION_HANDLE
+#define ck_user_type_t CK_USER_TYPE
+#define ck_state_t CK_STATE
+
+#define ck_session_info _CK_SESSION_INFO
+#define slot_id slotID
+#define device_error ulDeviceError
+
+#define ck_object_handle_t CK_OBJECT_HANDLE
+#define ck_object_class_t CK_OBJECT_CLASS
+#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE
+#define ck_key_type_t CK_KEY_TYPE
+#define ck_certificate_type_t CK_CERTIFICATE_TYPE
+#define ck_attribute_type_t CK_ATTRIBUTE_TYPE
+
+#define ck_attribute _CK_ATTRIBUTE
+#define value pValue
+#define value_len ulValueLen
+
+#define ck_date _CK_DATE
+
+#define ck_mechanism_type_t CK_MECHANISM_TYPE
+
+#define ck_mechanism _CK_MECHANISM
+#define parameter pParameter
+#define parameter_len ulParameterLen
+
+#define ck_mechanism_info _CK_MECHANISM_INFO
+#define min_key_size ulMinKeySize
+#define max_key_size ulMaxKeySize
+
+#define ck_rv_t CK_RV
+#define ck_notify_t CK_NOTIFY
+
+#define ck_function_list _CK_FUNCTION_LIST
+
+#define ck_createmutex_t CK_CREATEMUTEX
+#define ck_destroymutex_t CK_DESTROYMUTEX
+#define ck_lockmutex_t CK_LOCKMUTEX
+#define ck_unlockmutex_t CK_UNLOCKMUTEX
+
+#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS
+#define create_mutex CreateMutex
+#define destroy_mutex DestroyMutex
+#define lock_mutex LockMutex
+#define unlock_mutex UnlockMutex
+#define reserved pReserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+
+typedef unsigned long ck_flags_t;
+
+struct ck_version
+{
+  unsigned char major;
+  unsigned char minor;
+};
+
+
+struct ck_info
+{
+  struct ck_version cryptoki_version;
+  unsigned char manufacturer_id[32];
+  ck_flags_t flags;
+  unsigned char library_description[32];
+  struct ck_version library_version;
+};
+
+
+typedef unsigned long ck_notification_t;
+
+#define CKN_SURRENDER  (0)
+
+
+typedef unsigned long ck_slot_id_t;
+
+
+struct ck_slot_info
+{
+  unsigned char slot_description[64];
+  unsigned char manufacturer_id[32];
+  ck_flags_t flags;
+  struct ck_version hardware_version;
+  struct ck_version firmware_version;
+};
+
+
+#define CKF_TOKEN_PRESENT      (1 << 0)
+#define CKF_REMOVABLE_DEVICE   (1 << 1)
+#define CKF_HW_SLOT            (1 << 2)
+#define CKF_ARRAY_ATTRIBUTE    (1 << 30)
+
+
+struct ck_token_info
+{
+  unsigned char label[32];
+  unsigned char manufacturer_id[32];
+  unsigned char model[16];
+  unsigned char serial_number[16];
+  ck_flags_t flags;
+  unsigned long max_session_count;
+  unsigned long session_count;
+  unsigned long max_rw_session_count;
+  unsigned long rw_session_count;
+  unsigned long max_pin_len;
+  unsigned long min_pin_len;
+  unsigned long total_public_memory;
+  unsigned long free_public_memory;
+  unsigned long total_private_memory;
+  unsigned long free_private_memory;
+  struct ck_version hardware_version;
+  struct ck_version firmware_version;
+  unsigned char utc_time[16];
+};
+
+
+#define CKF_RNG                                        (1 << 0)
+#define CKF_WRITE_PROTECTED                    (1 << 1)
+#define CKF_LOGIN_REQUIRED                     (1 << 2)
+#define CKF_USER_PIN_INITIALIZED               (1 << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED             (1 << 5)
+#define CKF_CLOCK_ON_TOKEN                     (1 << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH      (1 << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS             (1 << 9)
+#define CKF_TOKEN_INITIALIZED                  (1 << 10)
+#define CKF_SECONDARY_AUTHENTICATION           (1 << 11)
+#define CKF_USER_PIN_COUNT_LOW                 (1 << 16)
+#define CKF_USER_PIN_FINAL_TRY                 (1 << 17)
+#define CKF_USER_PIN_LOCKED                    (1 << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED             (1 << 19)
+#define CKF_SO_PIN_COUNT_LOW                   (1 << 20)
+#define CKF_SO_PIN_FINAL_TRY                   (1 << 21)
+#define CKF_SO_PIN_LOCKED                      (1 << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED               (1 << 23)
+
+#define CK_UNAVAILABLE_INFORMATION     ((unsigned long) -1)
+#define CK_EFFECTIVELY_INFINITE                (0)
+
+
+typedef unsigned long ck_session_handle_t;
+
+#define CK_INVALID_HANDLE      (0)
+
+
+typedef unsigned long ck_user_type_t;
+
+#define CKU_SO                 (0)
+#define CKU_USER               (1)
+#define CKU_CONTEXT_SPECIFIC   (2)
+
+
+typedef unsigned long ck_state_t;
+
+#define CKS_RO_PUBLIC_SESSION  (0)
+#define CKS_RO_USER_FUNCTIONS  (1)
+#define CKS_RW_PUBLIC_SESSION  (2)
+#define CKS_RW_USER_FUNCTIONS  (3)
+#define CKS_RW_SO_FUNCTIONS    (4)
+
+
+struct ck_session_info
+{
+  ck_slot_id_t slot_id;
+  ck_state_t state;
+  ck_flags_t flags;
+  unsigned long device_error;
+};
+
+#define CKF_RW_SESSION         (1 << 1)
+#define CKF_SERIAL_SESSION     (1 << 2)
+
+
+typedef unsigned long ck_object_handle_t;
+
+
+typedef unsigned long ck_object_class_t;
+
+#define CKO_DATA               (0)
+#define CKO_CERTIFICATE                (1)
+#define CKO_PUBLIC_KEY         (2)
+#define CKO_PRIVATE_KEY                (3)
+#define CKO_SECRET_KEY         (4)
+#define CKO_HW_FEATURE         (5)
+#define CKO_DOMAIN_PARAMETERS  (6)
+#define CKO_MECHANISM          (7)
+#define CKO_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_hw_feature_type_t;
+
+#define CKH_MONOTONIC_COUNTER  (1)
+#define CKH_CLOCK              (2)
+#define CKH_USER_INTERFACE     (3)
+#define CKH_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_key_type_t;
+
+#define CKK_RSA                        (0)
+#define CKK_DSA                        (1)
+#define CKK_DH                 (2)
+#define CKK_ECDSA              (3)
+#define CKK_EC                 (3)
+#define CKK_X9_42_DH           (4)
+#define CKK_KEA                        (5)
+#define CKK_GENERIC_SECRET     (0x10)
+#define CKK_RC2                        (0x11)
+#define CKK_RC4                        (0x12)
+#define CKK_DES                        (0x13)
+#define CKK_DES2               (0x14)
+#define CKK_DES3               (0x15)
+#define CKK_CAST               (0x16)
+#define CKK_CAST3              (0x17)
+#define CKK_CAST128            (0x18)
+#define CKK_RC5                        (0x19)
+#define CKK_IDEA               (0x1a)
+#define CKK_SKIPJACK           (0x1b)
+#define CKK_BATON              (0x1c)
+#define CKK_JUNIPER            (0x1d)
+#define CKK_CDMF               (0x1e)
+#define CKK_AES                        (0x1f)
+#define CKK_BLOWFISH           (0x20)
+#define CKK_TWOFISH            (0x21)
+#define CKK_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+typedef unsigned long ck_certificate_type_t;
+
+#define CKC_X_509              (0)
+#define CKC_X_509_ATTR_CERT    (1)
+#define CKC_WTLS               (2)
+#define CKC_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_attribute_type_t;
+
+#define CKA_CLASS                      (0)
+#define CKA_TOKEN                      (1)
+#define CKA_PRIVATE                    (2)
+#define CKA_LABEL                      (3)
+#define CKA_APPLICATION                        (0x10)
+#define CKA_VALUE                      (0x11)
+#define CKA_OBJECT_ID                  (0x12)
+#define CKA_CERTIFICATE_TYPE           (0x80)
+#define CKA_ISSUER                     (0x81)
+#define CKA_SERIAL_NUMBER              (0x82)
+#define CKA_AC_ISSUER                  (0x83)
+#define CKA_OWNER                      (0x84)
+#define CKA_ATTR_TYPES                 (0x85)
+#define CKA_TRUSTED                    (0x86)
+#define CKA_CERTIFICATE_CATEGORY       (0x87)
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN  (0x88)
+#define CKA_URL                                (0x89)
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a)
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY  (0x8b)
+#define CKA_CHECK_VALUE                        (0x90)
+#define CKA_KEY_TYPE                   (0x100)
+#define CKA_SUBJECT                    (0x101)
+#define CKA_ID                         (0x102)
+#define CKA_SENSITIVE                  (0x103)
+#define CKA_ENCRYPT                    (0x104)
+#define CKA_DECRYPT                    (0x105)
+#define CKA_WRAP                       (0x106)
+#define CKA_UNWRAP                     (0x107)
+#define CKA_SIGN                       (0x108)
+#define CKA_SIGN_RECOVER               (0x109)
+#define CKA_VERIFY                     (0x10a)
+#define CKA_VERIFY_RECOVER             (0x10b)
+#define CKA_DERIVE                     (0x10c)
+#define CKA_START_DATE                 (0x110)
+#define CKA_END_DATE                   (0x111)
+#define CKA_MODULUS                    (0x120)
+#define CKA_MODULUS_BITS               (0x121)
+#define CKA_PUBLIC_EXPONENT            (0x122)
+#define CKA_PRIVATE_EXPONENT           (0x123)
+#define CKA_PRIME_1                    (0x124)
+#define CKA_PRIME_2                    (0x125)
+#define CKA_EXPONENT_1                 (0x126)
+#define CKA_EXPONENT_2                 (0x127)
+#define CKA_COEFFICIENT                        (0x128)
+#define CKA_PRIME                      (0x130)
+#define CKA_SUBPRIME                   (0x131)
+#define CKA_BASE                       (0x132)
+#define CKA_PRIME_BITS                 (0x133)
+#define CKA_SUB_PRIME_BITS             (0x134)
+#define CKA_VALUE_BITS                 (0x160)
+#define CKA_VALUE_LEN                  (0x161)
+#define CKA_EXTRACTABLE                        (0x162)
+#define CKA_LOCAL                      (0x163)
+#define CKA_NEVER_EXTRACTABLE          (0x164)
+#define CKA_ALWAYS_SENSITIVE           (0x165)
+#define CKA_KEY_GEN_MECHANISM          (0x166)
+#define CKA_MODIFIABLE                 (0x170)
+#define CKA_ECDSA_PARAMS               (0x180)
+#define CKA_EC_PARAMS                  (0x180)
+#define CKA_EC_POINT                   (0x181)
+#define CKA_SECONDARY_AUTH             (0x200)
+#define CKA_AUTH_PIN_FLAGS             (0x201)
+#define CKA_ALWAYS_AUTHENTICATE                (0x202)
+#define CKA_WRAP_WITH_TRUSTED          (0x210)
+#define CKA_HW_FEATURE_TYPE            (0x300)
+#define CKA_RESET_ON_INIT              (0x301)
+#define CKA_HAS_RESET                  (0x302)
+#define CKA_PIXEL_X                    (0x400)
+#define CKA_PIXEL_Y                    (0x401)
+#define CKA_RESOLUTION                 (0x402)
+#define CKA_CHAR_ROWS                  (0x403)
+#define CKA_CHAR_COLUMNS               (0x404)
+#define CKA_COLOR                      (0x405)
+#define CKA_BITS_PER_PIXEL             (0x406)
+#define CKA_CHAR_SETS                  (0x480)
+#define CKA_ENCODING_METHODS           (0x481)
+#define CKA_MIME_TYPES                 (0x482)
+#define CKA_MECHANISM_TYPE             (0x500)
+#define CKA_REQUIRED_CMS_ATTRIBUTES    (0x501)
+#define CKA_DEFAULT_CMS_ATTRIBUTES     (0x502)
+#define CKA_SUPPORTED_CMS_ATTRIBUTES   (0x503)
+#define CKA_WRAP_TEMPLATE              (CKF_ARRAY_ATTRIBUTE | 0x211)
+#define CKA_UNWRAP_TEMPLATE            (CKF_ARRAY_ATTRIBUTE | 0x212)
+#define CKA_ALLOWED_MECHANISMS         (CKF_ARRAY_ATTRIBUTE | 0x600)
+#define CKA_VENDOR_DEFINED             ((unsigned long) (1 << 31))
+
+
+struct ck_attribute
+{
+  ck_attribute_type_t type;
+  void *value;
+  unsigned long value_len;
+};
+
+
+struct ck_date
+{
+  unsigned char year[4];
+  unsigned char month[2];
+  unsigned char day[2];
+};
+
+
+typedef unsigned long ck_mechanism_type_t;
+
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      (0)
+#define CKM_RSA_PKCS                   (1)
+#define CKM_RSA_9796                   (2)
+#define CKM_RSA_X_509                  (3)
+#define CKM_MD2_RSA_PKCS               (4)
+#define CKM_MD5_RSA_PKCS               (5)
+#define CKM_SHA1_RSA_PKCS              (6)
+#define CKM_RIPEMD128_RSA_PKCS         (7)
+#define CKM_RIPEMD160_RSA_PKCS         (8)
+#define CKM_RSA_PKCS_OAEP              (9)
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     (0xa)
+#define CKM_RSA_X9_31                  (0xb)
+#define CKM_SHA1_RSA_X9_31             (0xc)
+#define CKM_RSA_PKCS_PSS               (0xd)
+#define CKM_SHA1_RSA_PKCS_PSS          (0xe)
+#define CKM_DSA_KEY_PAIR_GEN           (0x10)
+#define        CKM_DSA                         (0x11)
+#define CKM_DSA_SHA1                   (0x12)
+#define CKM_DH_PKCS_KEY_PAIR_GEN       (0x20)
+#define CKM_DH_PKCS_DERIVE             (0x21)
+#define        CKM_X9_42_DH_KEY_PAIR_GEN       (0x30)
+#define CKM_X9_42_DH_DERIVE            (0x31)
+#define CKM_X9_42_DH_HYBRID_DERIVE     (0x32)
+#define CKM_X9_42_MQV_DERIVE           (0x33)
+#define CKM_SHA256_RSA_PKCS            (0x40)
+#define CKM_SHA384_RSA_PKCS            (0x41)
+#define CKM_SHA512_RSA_PKCS            (0x42)
+#define CKM_SHA256_RSA_PKCS_PSS                (0x43)
+#define CKM_SHA384_RSA_PKCS_PSS                (0x44)
+#define CKM_SHA512_RSA_PKCS_PSS                (0x45)
+#define CKM_RC2_KEY_GEN                        (0x100)
+#define CKM_RC2_ECB                    (0x101)
+#define        CKM_RC2_CBC                     (0x102)
+#define        CKM_RC2_MAC                     (0x103)
+#define CKM_RC2_MAC_GENERAL            (0x104)
+#define CKM_RC2_CBC_PAD                        (0x105)
+#define CKM_RC4_KEY_GEN                        (0x110)
+#define CKM_RC4                                (0x111)
+#define CKM_DES_KEY_GEN                        (0x120)
+#define CKM_DES_ECB                    (0x121)
+#define CKM_DES_CBC                    (0x122)
+#define CKM_DES_MAC                    (0x123)
+#define CKM_DES_MAC_GENERAL            (0x124)
+#define CKM_DES_CBC_PAD                        (0x125)
+#define CKM_DES2_KEY_GEN               (0x130)
+#define CKM_DES3_KEY_GEN               (0x131)
+#define CKM_DES3_ECB                   (0x132)
+#define CKM_DES3_CBC                   (0x133)
+#define CKM_DES3_MAC                   (0x134)
+#define CKM_DES3_MAC_GENERAL           (0x135)
+#define CKM_DES3_CBC_PAD               (0x136)
+#define CKM_CDMF_KEY_GEN               (0x140)
+#define CKM_CDMF_ECB                   (0x141)
+#define CKM_CDMF_CBC                   (0x142)
+#define CKM_CDMF_MAC                   (0x143)
+#define CKM_CDMF_MAC_GENERAL           (0x144)
+#define CKM_CDMF_CBC_PAD               (0x145)
+#define CKM_MD2                                (0x200)
+#define CKM_MD2_HMAC                   (0x201)
+#define CKM_MD2_HMAC_GENERAL           (0x202)
+#define CKM_MD5                                (0x210)
+#define CKM_MD5_HMAC                   (0x211)
+#define CKM_MD5_HMAC_GENERAL           (0x212)
+#define CKM_SHA_1                      (0x220)
+#define CKM_SHA_1_HMAC                 (0x221)
+#define CKM_SHA_1_HMAC_GENERAL         (0x222)
+#define CKM_RIPEMD128                  (0x230)
+#define CKM_RIPEMD128_HMAC             (0x231)
+#define CKM_RIPEMD128_HMAC_GENERAL     (0x232)
+#define CKM_RIPEMD160                  (0x240)
+#define CKM_RIPEMD160_HMAC             (0x241)
+#define CKM_RIPEMD160_HMAC_GENERAL     (0x242)
+#define CKM_SHA256                     (0x250)
+#define CKM_SHA256_HMAC                        (0x251)
+#define CKM_SHA256_HMAC_GENERAL                (0x252)
+#define CKM_SHA384                     (0x260)
+#define CKM_SHA384_HMAC                        (0x261)
+#define CKM_SHA384_HMAC_GENERAL                (0x262)
+#define CKM_SHA512                     (0x270)
+#define CKM_SHA512_HMAC                        (0x271)
+#define CKM_SHA512_HMAC_GENERAL                (0x272)
+#define CKM_CAST_KEY_GEN               (0x300)
+#define CKM_CAST_ECB                   (0x301)
+#define CKM_CAST_CBC                   (0x302)
+#define CKM_CAST_MAC                   (0x303)
+#define CKM_CAST_MAC_GENERAL           (0x304)
+#define CKM_CAST_CBC_PAD               (0x305)
+#define CKM_CAST3_KEY_GEN              (0x310)
+#define CKM_CAST3_ECB                  (0x311)
+#define CKM_CAST3_CBC                  (0x312)
+#define CKM_CAST3_MAC                  (0x313)
+#define CKM_CAST3_MAC_GENERAL          (0x314)
+#define CKM_CAST3_CBC_PAD              (0x315)
+#define CKM_CAST5_KEY_GEN              (0x320)
+#define CKM_CAST128_KEY_GEN            (0x320)
+#define CKM_CAST5_ECB                  (0x321)
+#define CKM_CAST128_ECB                        (0x321)
+#define CKM_CAST5_CBC                  (0x322)
+#define CKM_CAST128_CBC                        (0x322)
+#define CKM_CAST5_MAC                  (0x323)
+#define        CKM_CAST128_MAC                 (0x323)
+#define CKM_CAST5_MAC_GENERAL          (0x324)
+#define CKM_CAST128_MAC_GENERAL                (0x324)
+#define CKM_CAST5_CBC_PAD              (0x325)
+#define CKM_CAST128_CBC_PAD            (0x325)
+#define CKM_RC5_KEY_GEN                        (0x330)
+#define CKM_RC5_ECB                    (0x331)
+#define CKM_RC5_CBC                    (0x332)
+#define CKM_RC5_MAC                    (0x333)
+#define CKM_RC5_MAC_GENERAL            (0x334)
+#define CKM_RC5_CBC_PAD                        (0x335)
+#define CKM_IDEA_KEY_GEN               (0x340)
+#define CKM_IDEA_ECB                   (0x341)
+#define        CKM_IDEA_CBC                    (0x342)
+#define CKM_IDEA_MAC                   (0x343)
+#define CKM_IDEA_MAC_GENERAL           (0x344)
+#define CKM_IDEA_CBC_PAD               (0x345)
+#define CKM_GENERIC_SECRET_KEY_GEN     (0x350)
+#define CKM_CONCATENATE_BASE_AND_KEY   (0x360)
+#define CKM_CONCATENATE_BASE_AND_DATA  (0x362)
+#define CKM_CONCATENATE_DATA_AND_BASE  (0x363)
+#define CKM_XOR_BASE_AND_DATA          (0x364)
+#define CKM_EXTRACT_KEY_FROM_KEY       (0x365)
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    (0x370)
+#define CKM_SSL3_MASTER_KEY_DERIVE     (0x371)
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    (0x372)
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  (0x373)
+#define CKM_TLS_PRE_MASTER_KEY_GEN     (0x374)
+#define CKM_TLS_MASTER_KEY_DERIVE      (0x375)
+#define CKM_TLS_KEY_AND_MAC_DERIVE     (0x376)
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   (0x377)
+#define CKM_SSL3_MD5_MAC               (0x380)
+#define CKM_SSL3_SHA1_MAC              (0x381)
+#define CKM_MD5_KEY_DERIVATION         (0x390)
+#define CKM_MD2_KEY_DERIVATION         (0x391)
+#define CKM_SHA1_KEY_DERIVATION                (0x392)
+#define CKM_PBE_MD2_DES_CBC            (0x3a0)
+#define CKM_PBE_MD5_DES_CBC            (0x3a1)
+#define CKM_PBE_MD5_CAST_CBC           (0x3a2)
+#define CKM_PBE_MD5_CAST3_CBC          (0x3a3)
+#define CKM_PBE_MD5_CAST5_CBC          (0x3a4)
+#define CKM_PBE_MD5_CAST128_CBC                (0x3a4)
+#define CKM_PBE_SHA1_CAST5_CBC         (0x3a5)
+#define CKM_PBE_SHA1_CAST128_CBC       (0x3a5)
+#define CKM_PBE_SHA1_RC4_128           (0x3a6)
+#define CKM_PBE_SHA1_RC4_40            (0x3a7)
+#define CKM_PBE_SHA1_DES3_EDE_CBC      (0x3a8)
+#define CKM_PBE_SHA1_DES2_EDE_CBC      (0x3a9)
+#define CKM_PBE_SHA1_RC2_128_CBC       (0x3aa)
+#define CKM_PBE_SHA1_RC2_40_CBC                (0x3ab)
+#define CKM_PKCS5_PBKD2                        (0x3b0)
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    (0x3c0)
+#define CKM_KEY_WRAP_LYNKS             (0x400)
+#define CKM_KEY_WRAP_SET_OAEP          (0x401)
+#define CKM_SKIPJACK_KEY_GEN           (0x1000)
+#define CKM_SKIPJACK_ECB64             (0x1001)
+#define CKM_SKIPJACK_CBC64             (0x1002)
+#define CKM_SKIPJACK_OFB64             (0x1003)
+#define CKM_SKIPJACK_CFB64             (0x1004)
+#define CKM_SKIPJACK_CFB32             (0x1005)
+#define CKM_SKIPJACK_CFB16             (0x1006)
+#define CKM_SKIPJACK_CFB8              (0x1007)
+#define CKM_SKIPJACK_WRAP              (0x1008)
+#define CKM_SKIPJACK_PRIVATE_WRAP      (0x1009)
+#define CKM_SKIPJACK_RELAYX            (0x100a)
+#define CKM_KEA_KEY_PAIR_GEN           (0x1010)
+#define CKM_KEA_KEY_DERIVE             (0x1011)
+#define CKM_FORTEZZA_TIMESTAMP         (0x1020)
+#define CKM_BATON_KEY_GEN              (0x1030)
+#define CKM_BATON_ECB128               (0x1031)
+#define CKM_BATON_ECB96                        (0x1032)
+#define CKM_BATON_CBC128               (0x1033)
+#define CKM_BATON_COUNTER              (0x1034)
+#define CKM_BATON_SHUFFLE              (0x1035)
+#define CKM_BATON_WRAP                 (0x1036)
+#define CKM_ECDSA_KEY_PAIR_GEN         (0x1040)
+#define CKM_EC_KEY_PAIR_GEN            (0x1040)
+#define CKM_ECDSA                      (0x1041)
+#define CKM_ECDSA_SHA1                 (0x1042)
+#define CKM_ECDH1_DERIVE               (0x1050)
+#define CKM_ECDH1_COFACTOR_DERIVE      (0x1051)
+#define CKM_ECMQV_DERIVE               (0x1052)
+#define CKM_JUNIPER_KEY_GEN            (0x1060)
+#define CKM_JUNIPER_ECB128             (0x1061)
+#define CKM_JUNIPER_CBC128             (0x1062)
+#define CKM_JUNIPER_COUNTER            (0x1063)
+#define CKM_JUNIPER_SHUFFLE            (0x1064)
+#define CKM_JUNIPER_WRAP               (0x1065)
+#define CKM_FASTHASH                   (0x1070)
+#define CKM_AES_KEY_GEN                        (0x1080)
+#define CKM_AES_ECB                    (0x1081)
+#define CKM_AES_CBC                    (0x1082)
+#define CKM_AES_MAC                    (0x1083)
+#define CKM_AES_MAC_GENERAL            (0x1084)
+#define CKM_AES_CBC_PAD                        (0x1085)
+#define CKM_DSA_PARAMETER_GEN          (0x2000)
+#define CKM_DH_PKCS_PARAMETER_GEN      (0x2001)
+#define CKM_X9_42_DH_PARAMETER_GEN     (0x2002)
+#define CKM_VENDOR_DEFINED             ((unsigned long) (1 << 31))
+
+
+struct ck_mechanism
+{
+  ck_mechanism_type_t mechanism;
+  void *parameter;
+  unsigned long parameter_len;
+};
+
+
+struct ck_mechanism_info
+{
+  unsigned long min_key_size;
+  unsigned long max_key_size;
+  ck_flags_t flags;
+};
+
+#define CKF_HW                 (1 << 0)
+#define CKF_ENCRYPT            (1 << 8)
+#define CKF_DECRYPT            (1 << 9)
+#define CKF_DIGEST             (1 << 10)
+#define CKF_SIGN               (1 << 11)
+#define CKF_SIGN_RECOVER       (1 << 12)
+#define CKF_VERIFY             (1 << 13)
+#define CKF_VERIFY_RECOVER     (1 << 14)
+#define CKF_GENERATE           (1 << 15)
+#define CKF_GENERATE_KEY_PAIR  (1 << 16)
+#define CKF_WRAP               (1 << 17)
+#define CKF_UNWRAP             (1 << 18)
+#define CKF_DERIVE             (1 << 19)
+#define CKF_EXTENSION          ((unsigned long) (1 << 31))
+
+
+/* Flags for C_WaitForSlotEvent.  */
+#define CKF_DONT_BLOCK                         (1)
+
+
+typedef unsigned long ck_rv_t;
+
+
+typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session,
+                               ck_notification_t event, void *application);
+
+/* Forward reference.  */
+struct ck_function_list;
+
+#define _CK_DECLARE_FUNCTION(name, args)       \
+typedef ck_rv_t (*CK_ ## name) args;           \
+ck_rv_t CK_SPEC name args
+
+_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args));
+_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved));
+_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info));
+_CK_DECLARE_FUNCTION (C_GetFunctionList,
+                     (struct ck_function_list **function_list));
+
+_CK_DECLARE_FUNCTION (C_GetSlotList,
+                     (unsigned char token_present, ck_slot_id_t *slot_list,
+                      unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetSlotInfo,
+                     (ck_slot_id_t slot_id, struct ck_slot_info *info));
+_CK_DECLARE_FUNCTION (C_GetTokenInfo,
+                     (ck_slot_id_t slot_id, struct ck_token_info *info));
+_CK_DECLARE_FUNCTION (C_WaitForSlotEvent,
+                     (ck_flags_t flags, ck_slot_id_t *slot, void *reserved));
+_CK_DECLARE_FUNCTION (C_GetMechanismList,
+                     (ck_slot_id_t slot_id,
+                      ck_mechanism_type_t *mechanism_list,
+                      unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetMechanismInfo,
+                     (ck_slot_id_t slot_id, ck_mechanism_type_t type,
+                      struct ck_mechanism_info *info));
+_CK_DECLARE_FUNCTION (C_InitToken,
+                     (ck_slot_id_t slot_id, unsigned char *pin,
+                      unsigned long pin_len, unsigned char *label));
+_CK_DECLARE_FUNCTION (C_InitPIN,
+                     (ck_session_handle_t session, unsigned char *pin,
+                      unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_SetPIN,
+                     (ck_session_handle_t session, unsigned char *old_pin,
+                      unsigned long old_len, unsigned char *new_pin,
+                      unsigned long new_len));
+
+_CK_DECLARE_FUNCTION (C_OpenSession,
+                     (ck_slot_id_t slot_id, ck_flags_t flags,
+                      void *application, ck_notify_t notify,
+                      ck_session_handle_t *session));
+_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id));
+_CK_DECLARE_FUNCTION (C_GetSessionInfo,
+                     (ck_session_handle_t session,
+                      struct ck_session_info *info));
+_CK_DECLARE_FUNCTION (C_GetOperationState,
+                     (ck_session_handle_t session,
+                      unsigned char *operation_state,
+                      unsigned long *operation_state_len));
+_CK_DECLARE_FUNCTION (C_SetOperationState,
+                     (ck_session_handle_t session,
+                      unsigned char *operation_state,
+                      unsigned long operation_state_len,
+                      ck_object_handle_t encryption_key,
+                      ck_object_handle_t authentiation_key));
+_CK_DECLARE_FUNCTION (C_Login,
+                     (ck_session_handle_t session, ck_user_type_t user_type,
+                      unsigned char *pin, unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_CreateObject,
+                     (ck_session_handle_t session,
+                      struct ck_attribute *templ,
+                      unsigned long count, ck_object_handle_t *object));
+_CK_DECLARE_FUNCTION (C_CopyObject,
+                     (ck_session_handle_t session, ck_object_handle_t object,
+                      struct ck_attribute *templ, unsigned long count,
+                      ck_object_handle_t *new_object));
+_CK_DECLARE_FUNCTION (C_DestroyObject,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object));
+_CK_DECLARE_FUNCTION (C_GetObjectSize,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      unsigned long *size));
+_CK_DECLARE_FUNCTION (C_GetAttributeValue,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_SetAttributeValue,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjectsInit,
+                     (ck_session_handle_t session,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjects,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t *object,
+                      unsigned long max_object_count,
+                      unsigned long *object_count));
+_CK_DECLARE_FUNCTION (C_FindObjectsFinal,
+                     (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_EncryptInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Encrypt,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *encrypted_data,
+                      unsigned long *encrypted_data_len));
+_CK_DECLARE_FUNCTION (C_EncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_EncryptFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *last_encrypted_part,
+                      unsigned long *last_encrypted_part_len));
+
+_CK_DECLARE_FUNCTION (C_DecryptInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Decrypt,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_data,
+                      unsigned long encrypted_data_len,
+                      unsigned char *data, unsigned long *data_len));
+_CK_DECLARE_FUNCTION (C_DecryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part, unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_DecryptFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *last_part,
+                      unsigned long *last_part_len));
+
+_CK_DECLARE_FUNCTION (C_DigestInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism));
+_CK_DECLARE_FUNCTION (C_Digest,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *digest,
+                      unsigned long *digest_len));
+_CK_DECLARE_FUNCTION (C_DigestUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_DigestKey,
+                     (ck_session_handle_t session, ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_DigestFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *digest,
+                      unsigned long *digest_len));
+
+_CK_DECLARE_FUNCTION (C_SignInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Sign,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_SignFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignRecoverInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_SignRecover,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+
+_CK_DECLARE_FUNCTION (C_VerifyInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Verify,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_VerifyFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyRecoverInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_VerifyRecover,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long signature_len,
+                      unsigned char *data,
+                      unsigned long *data_len));
+
+_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part,
+                      unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_SignEncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part,
+                      unsigned long *part_len));
+
+_CK_DECLARE_FUNCTION (C_GenerateKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      struct ck_attribute *templ,
+                      unsigned long count,
+                      ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_GenerateKeyPair,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      struct ck_attribute *public_key_template,
+                      unsigned long public_key_attribute_count,
+                      struct ck_attribute *private_key_template,
+                      unsigned long private_key_attribute_count,
+                      ck_object_handle_t *public_key,
+                      ck_object_handle_t *private_key));
+_CK_DECLARE_FUNCTION (C_WrapKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t wrapping_key,
+                      ck_object_handle_t key,
+                      unsigned char *wrapped_key,
+                      unsigned long *wrapped_key_len));
+_CK_DECLARE_FUNCTION (C_UnwrapKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t unwrapping_key,
+                      unsigned char *wrapped_key,
+                      unsigned long wrapped_key_len,
+                      struct ck_attribute *templ,
+                      unsigned long attribute_count,
+                      ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_DeriveKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t base_key,
+                      struct ck_attribute *templ,
+                      unsigned long attribute_count,
+                      ck_object_handle_t *key));
+
+_CK_DECLARE_FUNCTION (C_SeedRandom,
+                     (ck_session_handle_t session, unsigned char *seed,
+                      unsigned long seed_len));
+_CK_DECLARE_FUNCTION (C_GenerateRandom,
+                     (ck_session_handle_t session,
+                      unsigned char *random_data,
+                      unsigned long random_len));
+
+_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session));
+
+
+struct ck_function_list
+{
+  struct ck_version version;
+  CK_C_Initialize C_Initialize;
+  CK_C_Finalize C_Finalize;
+  CK_C_GetInfo C_GetInfo;
+  CK_C_GetFunctionList C_GetFunctionList;
+  CK_C_GetSlotList C_GetSlotList;
+  CK_C_GetSlotInfo C_GetSlotInfo;
+  CK_C_GetTokenInfo C_GetTokenInfo;
+  CK_C_GetMechanismList C_GetMechanismList;
+  CK_C_GetMechanismInfo C_GetMechanismInfo;
+  CK_C_InitToken C_InitToken;
+  CK_C_InitPIN C_InitPIN;
+  CK_C_SetPIN C_SetPIN;
+  CK_C_OpenSession C_OpenSession;
+  CK_C_CloseSession C_CloseSession;
+  CK_C_CloseAllSessions C_CloseAllSessions;
+  CK_C_GetSessionInfo C_GetSessionInfo;
+  CK_C_GetOperationState C_GetOperationState;
+  CK_C_SetOperationState C_SetOperationState;
+  CK_C_Login C_Login;
+  CK_C_Logout C_Logout;
+  CK_C_CreateObject C_CreateObject;
+  CK_C_CopyObject C_CopyObject;
+  CK_C_DestroyObject C_DestroyObject;
+  CK_C_GetObjectSize C_GetObjectSize;
+  CK_C_GetAttributeValue C_GetAttributeValue;
+  CK_C_SetAttributeValue C_SetAttributeValue;
+  CK_C_FindObjectsInit C_FindObjectsInit;
+  CK_C_FindObjects C_FindObjects;
+  CK_C_FindObjectsFinal C_FindObjectsFinal;
+  CK_C_EncryptInit C_EncryptInit;
+  CK_C_Encrypt C_Encrypt;
+  CK_C_EncryptUpdate C_EncryptUpdate;
+  CK_C_EncryptFinal C_EncryptFinal;
+  CK_C_DecryptInit C_DecryptInit;
+  CK_C_Decrypt C_Decrypt;
+  CK_C_DecryptUpdate C_DecryptUpdate;
+  CK_C_DecryptFinal C_DecryptFinal;
+  CK_C_DigestInit C_DigestInit;
+  CK_C_Digest C_Digest;
+  CK_C_DigestUpdate C_DigestUpdate;
+  CK_C_DigestKey C_DigestKey;
+  CK_C_DigestFinal C_DigestFinal;
+  CK_C_SignInit C_SignInit;
+  CK_C_Sign C_Sign;
+  CK_C_SignUpdate C_SignUpdate;
+  CK_C_SignFinal C_SignFinal;
+  CK_C_SignRecoverInit C_SignRecoverInit;
+  CK_C_SignRecover C_SignRecover;
+  CK_C_VerifyInit C_VerifyInit;
+  CK_C_Verify C_Verify;
+  CK_C_VerifyUpdate C_VerifyUpdate;
+  CK_C_VerifyFinal C_VerifyFinal;
+  CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+  CK_C_VerifyRecover C_VerifyRecover;
+  CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+  CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+  CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+  CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+  CK_C_GenerateKey C_GenerateKey;
+  CK_C_GenerateKeyPair C_GenerateKeyPair;
+  CK_C_WrapKey C_WrapKey;
+  CK_C_UnwrapKey C_UnwrapKey;
+  CK_C_DeriveKey C_DeriveKey;
+  CK_C_SeedRandom C_SeedRandom;
+  CK_C_GenerateRandom C_GenerateRandom;
+  CK_C_GetFunctionStatus C_GetFunctionStatus;
+  CK_C_CancelFunction C_CancelFunction;
+  CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+};
+
+
+typedef ck_rv_t (*ck_createmutex_t) (void **mutex);
+typedef ck_rv_t (*ck_destroymutex_t) (void *mutex);
+typedef ck_rv_t (*ck_lockmutex_t) (void *mutex);
+typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex);
+
+
+struct ck_c_initialize_args
+{
+  ck_createmutex_t create_mutex;
+  ck_destroymutex_t destroy_mutex;
+  ck_lockmutex_t lock_mutex;
+  ck_unlockmutex_t unlock_mutex;
+  ck_flags_t flags;
+  void *reserved;
+};
+
+
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS     (1 << 0)
+#define CKF_OS_LOCKING_OK                      (1 << 1)
+
+#define CKR_OK                                 (0)
+#define CKR_CANCEL                             (1)
+#define CKR_HOST_MEMORY                                (2)
+#define CKR_SLOT_ID_INVALID                    (3)
+#define CKR_GENERAL_ERROR                      (5)
+#define CKR_FUNCTION_FAILED                    (6)
+#define CKR_ARGUMENTS_BAD                      (7)
+#define CKR_NO_EVENT                           (8)
+#define CKR_NEED_TO_CREATE_THREADS             (9)
+#define CKR_CANT_LOCK                          (0xa)
+#define CKR_ATTRIBUTE_READ_ONLY                        (0x10)
+#define CKR_ATTRIBUTE_SENSITIVE                        (0x11)
+#define CKR_ATTRIBUTE_TYPE_INVALID             (0x12)
+#define CKR_ATTRIBUTE_VALUE_INVALID            (0x13)
+#define CKR_DATA_INVALID                       (0x20)
+#define CKR_DATA_LEN_RANGE                     (0x21)
+#define CKR_DEVICE_ERROR                       (0x30)
+#define CKR_DEVICE_MEMORY                      (0x31)
+#define CKR_DEVICE_REMOVED                     (0x32)
+#define CKR_ENCRYPTED_DATA_INVALID             (0x40)
+#define CKR_ENCRYPTED_DATA_LEN_RANGE           (0x41)
+#define CKR_FUNCTION_CANCELED                  (0x50)
+#define CKR_FUNCTION_NOT_PARALLEL              (0x51)
+#define CKR_FUNCTION_NOT_SUPPORTED             (0x54)
+#define CKR_KEY_HANDLE_INVALID                 (0x60)
+#define CKR_KEY_SIZE_RANGE                     (0x62)
+#define CKR_KEY_TYPE_INCONSISTENT              (0x63)
+#define CKR_KEY_NOT_NEEDED                     (0x64)
+#define CKR_KEY_CHANGED                                (0x65)
+#define CKR_KEY_NEEDED                         (0x66)
+#define CKR_KEY_INDIGESTIBLE                   (0x67)
+#define CKR_KEY_FUNCTION_NOT_PERMITTED         (0x68)
+#define CKR_KEY_NOT_WRAPPABLE                  (0x69)
+#define CKR_KEY_UNEXTRACTABLE                  (0x6a)
+#define CKR_MECHANISM_INVALID                  (0x70)
+#define CKR_MECHANISM_PARAM_INVALID            (0x71)
+#define CKR_OBJECT_HANDLE_INVALID              (0x82)
+#define CKR_OPERATION_ACTIVE                   (0x90)
+#define CKR_OPERATION_NOT_INITIALIZED          (0x91)
+#define CKR_PIN_INCORRECT                      (0xa0)
+#define CKR_PIN_INVALID                                (0xa1)
+#define CKR_PIN_LEN_RANGE                      (0xa2)
+#define CKR_PIN_EXPIRED                                (0xa3)
+#define CKR_PIN_LOCKED                         (0xa4)
+#define CKR_SESSION_CLOSED                     (0xb0)
+#define CKR_SESSION_COUNT                      (0xb1)
+#define CKR_SESSION_HANDLE_INVALID             (0xb3)
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED     (0xb4)
+#define CKR_SESSION_READ_ONLY                  (0xb5)
+#define CKR_SESSION_EXISTS                     (0xb6)
+#define CKR_SESSION_READ_ONLY_EXISTS           (0xb7)
+#define CKR_SESSION_READ_WRITE_SO_EXISTS       (0xb8)
+#define CKR_SIGNATURE_INVALID                  (0xc0)
+#define CKR_SIGNATURE_LEN_RANGE                        (0xc1)
+#define CKR_TEMPLATE_INCOMPLETE                        (0xd0)
+#define CKR_TEMPLATE_INCONSISTENT              (0xd1)
+#define CKR_TOKEN_NOT_PRESENT                  (0xe0)
+#define CKR_TOKEN_NOT_RECOGNIZED               (0xe1)
+#define CKR_TOKEN_WRITE_PROTECTED              (0xe2)
+#define        CKR_UNWRAPPING_KEY_HANDLE_INVALID       (0xf0)
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE          (0xf1)
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT   (0xf2)
+#define CKR_USER_ALREADY_LOGGED_IN             (0x100)
+#define CKR_USER_NOT_LOGGED_IN                 (0x101)
+#define CKR_USER_PIN_NOT_INITIALIZED           (0x102)
+#define CKR_USER_TYPE_INVALID                  (0x103)
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN     (0x104)
+#define CKR_USER_TOO_MANY_TYPES                        (0x105)
+#define CKR_WRAPPED_KEY_INVALID                        (0x110)
+#define CKR_WRAPPED_KEY_LEN_RANGE              (0x112)
+#define CKR_WRAPPING_KEY_HANDLE_INVALID                (0x113)
+#define CKR_WRAPPING_KEY_SIZE_RANGE            (0x114)
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT     (0x115)
+#define CKR_RANDOM_SEED_NOT_SUPPORTED          (0x120)
+#define CKR_RANDOM_NO_RNG                      (0x121)
+#define CKR_DOMAIN_PARAMS_INVALID              (0x130)
+#define CKR_BUFFER_TOO_SMALL                   (0x150)
+#define CKR_SAVED_STATE_INVALID                        (0x160)
+#define CKR_INFORMATION_SENSITIVE              (0x170)
+#define CKR_STATE_UNSAVEABLE                   (0x180)
+#define CKR_CRYPTOKI_NOT_INITIALIZED           (0x190)
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED       (0x191)
+#define CKR_MUTEX_BAD                          (0x1a0)
+#define CKR_MUTEX_NOT_LOCKED                   (0x1a1)
+#define CKR_FUNCTION_REJECTED                  (0x200)
+#define CKR_VENDOR_DEFINED                     ((unsigned long) (1 << 31))
+
+
+
+/* Compatibility layer.  */
+
+#ifdef CRYPTOKI_COMPAT
+
+#undef CK_DEFINE_FUNCTION
+#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name
+
+/* For NULL.  */
+#include <stddef.h>
+
+typedef unsigned char CK_BYTE;
+typedef unsigned char CK_CHAR;
+typedef unsigned char CK_UTF8CHAR;
+typedef unsigned char CK_BBOOL;
+typedef unsigned long int CK_ULONG;
+typedef long int CK_LONG;
+typedef CK_BYTE *CK_BYTE_PTR;
+typedef CK_CHAR *CK_CHAR_PTR;
+typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR;
+typedef CK_ULONG *CK_ULONG_PTR;
+typedef void *CK_VOID_PTR;
+typedef void **CK_VOID_PTR_PTR;
+#define CK_FALSE 0
+#define CK_TRUE 1
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#endif
+
+typedef struct ck_version CK_VERSION;
+typedef struct ck_version *CK_VERSION_PTR;
+
+typedef struct ck_info CK_INFO;
+typedef struct ck_info *CK_INFO_PTR;
+
+typedef ck_slot_id_t *CK_SLOT_ID_PTR;
+
+typedef struct ck_slot_info CK_SLOT_INFO;
+typedef struct ck_slot_info *CK_SLOT_INFO_PTR;
+
+typedef struct ck_token_info CK_TOKEN_INFO;
+typedef struct ck_token_info *CK_TOKEN_INFO_PTR;
+
+typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR;
+
+typedef struct ck_session_info CK_SESSION_INFO;
+typedef struct ck_session_info *CK_SESSION_INFO_PTR;
+
+typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR;
+
+typedef ck_object_class_t *CK_OBJECT_CLASS_PTR;
+
+typedef struct ck_attribute CK_ATTRIBUTE;
+typedef struct ck_attribute *CK_ATTRIBUTE_PTR;
+
+typedef struct ck_date CK_DATE;
+typedef struct ck_date *CK_DATE_PTR;
+
+typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
+
+typedef struct ck_mechanism CK_MECHANISM;
+typedef struct ck_mechanism *CK_MECHANISM_PTR;
+
+typedef struct ck_mechanism_info CK_MECHANISM_INFO;
+typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR;
+
+typedef struct ck_function_list CK_FUNCTION_LIST;
+typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
+typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
+
+typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS;
+typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
+
+#define NULL_PTR NULL
+
+/* Delete the helper macros defined at the top of the file.  */
+#undef ck_flags_t
+#undef ck_version
+
+#undef ck_info
+#undef cryptoki_version
+#undef manufacturer_id
+#undef library_description
+#undef library_version
+
+#undef ck_notification_t
+#undef ck_slot_id_t
+
+#undef ck_slot_info
+#undef slot_description
+#undef hardware_version
+#undef firmware_version
+
+#undef ck_token_info
+#undef serial_number
+#undef max_session_count
+#undef session_count
+#undef max_rw_session_count
+#undef rw_session_count
+#undef max_pin_len
+#undef min_pin_len
+#undef total_public_memory
+#undef free_public_memory
+#undef total_private_memory
+#undef free_private_memory
+#undef utc_time
+
+#undef ck_session_handle_t
+#undef ck_user_type_t
+#undef ck_state_t
+
+#undef ck_session_info
+#undef slot_id
+#undef device_error
+
+#undef ck_object_handle_t
+#undef ck_object_class_t
+#undef ck_hw_feature_type_t
+#undef ck_key_type_t
+#undef ck_certificate_type_t
+#undef ck_attribute_type_t
+
+#undef ck_attribute
+#undef value
+#undef value_len
+
+#undef ck_date
+
+#undef ck_mechanism_type_t
+
+#undef ck_mechanism
+#undef parameter
+#undef parameter_len
+
+#undef ck_mechanism_info
+#undef min_key_size
+#undef max_key_size
+
+#undef ck_rv_t
+#undef ck_notify_t
+
+#undef ck_function_list
+
+#undef ck_createmutex_t
+#undef ck_destroymutex_t
+#undef ck_lockmutex_t
+#undef ck_unlockmutex_t
+
+#undef ck_c_initialize_args
+#undef create_mutex
+#undef destroy_mutex
+#undef lock_mutex
+#undef unlock_mutex
+#undef reserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+/* System dependencies.  */
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+#pragma pack(pop, cryptoki)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* PKCS11_H */
diff --git a/platform.c b/platform.c
new file mode 100644 (file)
index 0000000..a455472
--- /dev/null
@@ -0,0 +1,196 @@
+/* $Id: platform.c,v 1.18 2011/01/11 06:02:25 djm Exp $ */
+
+/*
+ * Copyright (c) 2006 Darren Tucker.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "auth-pam.h"
+#include "platform.h"
+
+#include "openbsd-compat/openbsd-compat.h"
+
+extern int use_privsep;
+extern ServerOptions options;
+
+void
+platform_pre_listen(void)
+{
+#ifdef LINUX_OOM_ADJUST
+       /* Adjust out-of-memory killer so listening process is not killed */
+       oom_adjust_setup();
+#endif
+}
+
+void
+platform_pre_fork(void)
+{
+#ifdef USE_SOLARIS_PROCESS_CONTRACTS
+       solaris_contract_pre_fork();
+#endif
+}
+
+void
+platform_post_fork_parent(pid_t child_pid)
+{
+#ifdef USE_SOLARIS_PROCESS_CONTRACTS
+       solaris_contract_post_fork_parent(child_pid);
+#endif
+}
+
+void
+platform_post_fork_child(void)
+{
+#ifdef USE_SOLARIS_PROCESS_CONTRACTS
+       solaris_contract_post_fork_child();
+#endif
+#ifdef LINUX_OOM_ADJUST
+       oom_adjust_restore();
+#endif
+}
+
+/* return 1 if we are running with privilege to swap UIDs, 0 otherwise */
+int
+platform_privileged_uidswap(void)
+{
+#ifdef HAVE_CYGWIN
+       /* uid 0 is not special on Cygwin so always try */
+       return 1;
+#else
+       return (getuid() == 0 || geteuid() == 0);
+#endif
+}
+
+/*
+ * This gets called before switching UIDs, and is called even when sshd is
+ * not running as root.
+ */
+void
+platform_setusercontext(struct passwd *pw)
+{
+#ifdef WITH_SELINUX
+       /* Cache selinux status for later use */
+       (void)ssh_selinux_enabled();
+#endif
+
+#ifdef USE_SOLARIS_PROJECTS
+       /* if solaris projects were detected, set the default now */
+       if (getuid() == 0 || geteuid() == 0)
+               solaris_set_default_project(pw);
+#endif
+
+#if defined(HAVE_LOGIN_CAP) && defined (__bsdi__)
+       if (getuid() == 0 || geteuid() == 0)
+               setpgid(0, 0);
+# endif
+
+#if defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
+       /*
+        * If we have both LOGIN_CAP and PAM, we want to establish creds
+        * before calling setusercontext (in session.c:do_setusercontext).
+        */
+       if (getuid() == 0 || geteuid() == 0) {
+               if (options.use_pam) {
+                       do_pam_setcred(use_privsep);
+               }
+       }
+# endif /* USE_PAM */
+
+#if !defined(HAVE_LOGIN_CAP) && defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
+       if (getuid() == 0 || geteuid() == 0) {
+               /* Sets login uid for accounting */
+               if (getluid() == -1 && setluid(pw->pw_uid) == -1)
+                       error("setluid: %s", strerror(errno));
+       }
+#endif
+}
+
+/*
+ * This gets called after we've established the user's groups, and is only
+ * called if sshd is running as root.
+ */
+void
+platform_setusercontext_post_groups(struct passwd *pw)
+{
+#if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM)
+       /*
+        * PAM credentials may take the form of supplementary groups.
+        * These will have been wiped by the above initgroups() call.
+        * Reestablish them here.
+        */
+       if (options.use_pam) {
+               do_pam_setcred(use_privsep);
+       }
+#endif /* USE_PAM */
+
+#if !defined(HAVE_LOGIN_CAP) && (defined(WITH_IRIX_PROJECT) || \
+    defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY))
+       irix_setusercontext(pw);
+#endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
+
+#ifdef _AIX
+       aix_usrinfo(pw);
+#endif /* _AIX */
+
+#if !defined(HAVE_LOGIN_CAP) && defined(USE_LIBIAF)
+       if (set_id(pw->pw_name) != 0) {
+               exit(1);
+       }
+# endif /* USE_LIBIAF */
+
+#ifdef HAVE_SETPCRED
+       /*
+        * If we have a chroot directory, we set all creds except real
+        * uid which we will need for chroot.  If we don't have a
+        * chroot directory, we don't override anything.
+        */
+       {
+               char **creds = NULL, *chroot_creds[] =
+                   { "REAL_USER=root", NULL };
+
+               if (options.chroot_directory != NULL &&
+                   strcasecmp(options.chroot_directory, "none") != 0)
+                       creds = chroot_creds;
+
+               if (setpcred(pw->pw_name, creds) == -1)
+                       fatal("Failed to set process credentials");
+       }
+#endif /* HAVE_SETPCRED */
+#ifdef WITH_SELINUX
+       ssh_selinux_setup_exec_context(pw->pw_name);
+#endif
+}
+
+char *
+platform_krb5_get_principal_name(const char *pw_name)
+{
+#ifdef USE_AIX_KRB_NAME
+       return aix_krb5_get_principal_name(pw_name);
+#else
+       return NULL;
+#endif
+}
diff --git a/platform.h b/platform.h
new file mode 100644 (file)
index 0000000..944d2c3
--- /dev/null
@@ -0,0 +1,33 @@
+/* $Id: platform.h,v 1.7 2010/11/05 03:47:01 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2006 Darren Tucker.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <pwd.h>
+
+void platform_pre_listen(void);
+void platform_pre_fork(void);
+void platform_post_fork_parent(pid_t child_pid);
+void platform_post_fork_child(void);
+int  platform_privileged_uidswap(void);
+void platform_setusercontext(struct passwd *);
+void platform_setusercontext_post_groups(struct passwd *);
+char *platform_get_krb5_client(const char *);
+char *platform_krb5_get_principal_name(const char *);
+
+
diff --git a/progressmeter.c b/progressmeter.c
new file mode 100644 (file)
index 0000000..0f95222
--- /dev/null
@@ -0,0 +1,305 @@
+/* $OpenBSD: progressmeter.c,v 1.37 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2003 Nils Nordman.  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 <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "progressmeter.h"
+#include "atomicio.h"
+#include "misc.h"
+
+#define DEFAULT_WINSIZE 80
+#define MAX_WINSIZE 512
+#define PADDING 1              /* padding between the progress indicators */
+#define UPDATE_INTERVAL 1      /* update the progress meter every second */
+#define STALL_TIME 5           /* we're stalled after this many seconds */
+
+/* determines whether we can output to the terminal */
+static int can_output(void);
+
+/* formats and inserts the specified size into the given buffer */
+static void format_size(char *, int, off_t);
+static void format_rate(char *, int, off_t);
+
+/* window resizing */
+static void sig_winch(int);
+static void setscreensize(void);
+
+/* updates the progressmeter to reflect the current state of the transfer */
+void refresh_progress_meter(void);
+
+/* signal handler for updating the progress meter */
+static void update_progress_meter(int);
+
+static time_t start;           /* start progress */
+static time_t last_update;     /* last progress update */
+static char *file;             /* name of the file being transferred */
+static off_t end_pos;          /* ending position of transfer */
+static off_t cur_pos;          /* transfer position as of last refresh */
+static volatile off_t *counter;        /* progress counter */
+static long stalled;           /* how long we have been stalled */
+static int bytes_per_second;   /* current speed in bytes per second */
+static int win_size;           /* terminal window size */
+static volatile sig_atomic_t win_resized; /* for window resizing */
+
+/* units for format_size */
+static const char unit[] = " KMGT";
+
+static int
+can_output(void)
+{
+       return (getpgrp() == tcgetpgrp(STDOUT_FILENO));
+}
+
+static void
+format_rate(char *buf, int size, off_t bytes)
+{
+       int i;
+
+       bytes *= 100;
+       for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++)
+               bytes = (bytes + 512) / 1024;
+       if (i == 0) {
+               i++;
+               bytes = (bytes + 512) / 1024;
+       }
+       snprintf(buf, size, "%3lld.%1lld%c%s",
+           (long long) (bytes + 5) / 100,
+           (long long) (bytes + 5) / 10 % 10,
+           unit[i],
+           i ? "B" : " ");
+}
+
+static void
+format_size(char *buf, int size, off_t bytes)
+{
+       int i;
+
+       for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++)
+               bytes = (bytes + 512) / 1024;
+       snprintf(buf, size, "%4lld%c%s",
+           (long long) bytes,
+           unit[i],
+           i ? "B" : " ");
+}
+
+void
+refresh_progress_meter(void)
+{
+       char buf[MAX_WINSIZE + 1];
+       time_t now;
+       off_t transferred;
+       double elapsed;
+       int percent;
+       off_t bytes_left;
+       int cur_speed;
+       int hours, minutes, seconds;
+       int i, len;
+       int file_len;
+
+       transferred = *counter - cur_pos;
+       cur_pos = *counter;
+       now = time(NULL);
+       bytes_left = end_pos - cur_pos;
+
+       if (bytes_left > 0)
+               elapsed = now - last_update;
+       else {
+               elapsed = now - start;
+               /* Calculate true total speed when done */
+               transferred = end_pos;
+               bytes_per_second = 0;
+       }
+
+       /* calculate speed */
+       if (elapsed != 0)
+               cur_speed = (transferred / elapsed);
+       else
+               cur_speed = transferred;
+
+#define AGE_FACTOR 0.9
+       if (bytes_per_second != 0) {
+               bytes_per_second = (bytes_per_second * AGE_FACTOR) +
+                   (cur_speed * (1.0 - AGE_FACTOR));
+       } else
+               bytes_per_second = cur_speed;
+
+       /* filename */
+       buf[0] = '\0';
+       file_len = win_size - 35;
+       if (file_len > 0) {
+               len = snprintf(buf, file_len + 1, "\r%s", file);
+               if (len < 0)
+                       len = 0;
+               if (len >= file_len + 1)
+                       len = file_len;
+               for (i = len; i < file_len; i++)
+                       buf[i] = ' ';
+               buf[file_len] = '\0';
+       }
+
+       /* percent of transfer done */
+       if (end_pos != 0)
+               percent = ((float)cur_pos / end_pos) * 100;
+       else
+               percent = 100;
+       snprintf(buf + strlen(buf), win_size - strlen(buf),
+           " %3d%% ", percent);
+
+       /* amount transferred */
+       format_size(buf + strlen(buf), win_size - strlen(buf),
+           cur_pos);
+       strlcat(buf, " ", win_size);
+
+       /* bandwidth usage */
+       format_rate(buf + strlen(buf), win_size - strlen(buf),
+           (off_t)bytes_per_second);
+       strlcat(buf, "/s ", win_size);
+
+       /* ETA */
+       if (!transferred)
+               stalled += elapsed;
+       else
+               stalled = 0;
+
+       if (stalled >= STALL_TIME)
+               strlcat(buf, "- stalled -", win_size);
+       else if (bytes_per_second == 0 && bytes_left)
+               strlcat(buf, "  --:-- ETA", win_size);
+       else {
+               if (bytes_left > 0)
+                       seconds = bytes_left / bytes_per_second;
+               else
+                       seconds = elapsed;
+
+               hours = seconds / 3600;
+               seconds -= hours * 3600;
+               minutes = seconds / 60;
+               seconds -= minutes * 60;
+
+               if (hours != 0)
+                       snprintf(buf + strlen(buf), win_size - strlen(buf),
+                           "%d:%02d:%02d", hours, minutes, seconds);
+               else
+                       snprintf(buf + strlen(buf), win_size - strlen(buf),
+                           "  %02d:%02d", minutes, seconds);
+
+               if (bytes_left > 0)
+                       strlcat(buf, " ETA", win_size);
+               else
+                       strlcat(buf, "    ", win_size);
+       }
+
+       atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1);
+       last_update = now;
+}
+
+/*ARGSUSED*/
+static void
+update_progress_meter(int ignore)
+{
+       int save_errno;
+
+       save_errno = errno;
+
+       if (win_resized) {
+               setscreensize();
+               win_resized = 0;
+       }
+       if (can_output())
+               refresh_progress_meter();
+
+       signal(SIGALRM, update_progress_meter);
+       alarm(UPDATE_INTERVAL);
+       errno = save_errno;
+}
+
+void
+start_progress_meter(char *f, off_t filesize, off_t *ctr)
+{
+       start = last_update = time(NULL);
+       file = f;
+       end_pos = filesize;
+       cur_pos = 0;
+       counter = ctr;
+       stalled = 0;
+       bytes_per_second = 0;
+
+       setscreensize();
+       if (can_output())
+               refresh_progress_meter();
+
+       signal(SIGALRM, update_progress_meter);
+       signal(SIGWINCH, sig_winch);
+       alarm(UPDATE_INTERVAL);
+}
+
+void
+stop_progress_meter(void)
+{
+       alarm(0);
+
+       if (!can_output())
+               return;
+
+       /* Ensure we complete the progress */
+       if (cur_pos != end_pos)
+               refresh_progress_meter();
+
+       atomicio(vwrite, STDOUT_FILENO, "\n", 1);
+}
+
+/*ARGSUSED*/
+static void
+sig_winch(int sig)
+{
+       win_resized = 1;
+}
+
+static void
+setscreensize(void)
+{
+       struct winsize winsize;
+
+       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
+           winsize.ws_col != 0) {
+               if (winsize.ws_col > MAX_WINSIZE)
+                       win_size = MAX_WINSIZE;
+               else
+                       win_size = winsize.ws_col;
+       } else
+               win_size = DEFAULT_WINSIZE;
+       win_size += 1;                                  /* trailing \0 */
+}
diff --git a/progressmeter.h b/progressmeter.h
new file mode 100644 (file)
index 0000000..10bab99
--- /dev/null
@@ -0,0 +1,27 @@
+/* $OpenBSD: progressmeter.h,v 1.2 2006/03/25 22:22:43 djm Exp $ */
+/*
+ * Copyright (c) 2002 Nils Nordman.  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   start_progress_meter(char *, off_t, off_t *);
+void   stop_progress_meter(void);
diff --git a/readconf.c b/readconf.c
new file mode 100644 (file)
index 0000000..eb4a8b9
--- /dev/null
@@ -0,0 +1,1422 @@
+/* $OpenBSD: readconf.c,v 1.190 2010/11/13 23:27:50 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "compat.h"
+#include "cipher.h"
+#include "pathnames.h"
+#include "log.h"
+#include "key.h"
+#include "readconf.h"
+#include "match.h"
+#include "misc.h"
+#include "buffer.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
+     User foo
+
+   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
+     PasswordAuthentication no
+
+   Host puukko.hut.fi
+     User t35124p
+     ProxyCommand ssh-proxy %h %p
+
+   Host *.fr
+     PublicKeyAuthentication no
+
+   Host *.su
+     Cipher none
+     PasswordAuthentication no
+
+   Host vpn.fake.com
+     Tunnel yes
+     TunnelDevice 3
+
+   # Defaults for various options
+   Host *
+     ForwardAgent no
+     ForwardX11 no
+     PasswordAuthentication yes
+     RSAAuthentication yes
+     RhostsRSAAuthentication yes
+     StrictHostKeyChecking yes
+     TcpKeepAlive no
+     IdentityFile ~/.ssh/identity
+     Port 22
+     EscapeChar ~
+
+*/
+
+/* Keyword tokens. */
+
+typedef enum {
+       oBadOption,
+       oForwardAgent, oForwardX11, oForwardX11Trusted, oForwardX11Timeout,
+       oGatewayPorts, oExitOnForwardFailure,
+       oPasswordAuthentication, oRSAAuthentication,
+       oChallengeResponseAuthentication, oXAuthLocation,
+       oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
+       oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
+       oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
+       oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
+       oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts,
+       oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
+       oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
+       oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
+       oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
+       oHostKeyAlgorithms, oBindAddress, oPKCS11Provider,
+       oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+       oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
+       oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+       oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
+       oSendEnv, oControlPath, oControlMaster, oControlPersist,
+       oHashKnownHosts,
+       oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+       oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
+       oKexAlgorithms, oIPQoS,
+       oDeprecated, oUnsupported
+} OpCodes;
+
+/* Textual representations of the tokens. */
+
+static struct {
+       const char *name;
+       OpCodes opcode;
+} keywords[] = {
+       { "forwardagent", oForwardAgent },
+       { "forwardx11", oForwardX11 },
+       { "forwardx11trusted", oForwardX11Trusted },
+       { "forwardx11timeout", oForwardX11Timeout },
+       { "exitonforwardfailure", oExitOnForwardFailure },
+       { "xauthlocation", oXAuthLocation },
+       { "gatewayports", oGatewayPorts },
+       { "useprivilegedport", oUsePrivilegedPort },
+       { "rhostsauthentication", oDeprecated },
+       { "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 */
+       { "kerberosauthentication", oUnsupported },
+       { "kerberostgtpassing", oUnsupported },
+       { "afstokenpassing", oUnsupported },
+#if defined(GSSAPI)
+       { "gssapiauthentication", oGssAuthentication },
+       { "gssapidelegatecredentials", oGssDelegateCreds },
+#else
+       { "gssapiauthentication", oUnsupported },
+       { "gssapidelegatecredentials", oUnsupported },
+#endif
+       { "fallbacktorsh", oDeprecated },
+       { "usersh", oDeprecated },
+       { "identityfile", oIdentityFile },
+       { "identityfile2", oIdentityFile },                     /* obsolete */
+       { "identitiesonly", oIdentitiesOnly },
+       { "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 },
+       { "globalknownhostsfile2", oGlobalKnownHostsFile2 },    /* obsolete */
+       { "userknownhostsfile", oUserKnownHostsFile },
+       { "userknownhostsfile2", oUserKnownHostsFile2 },        /* obsolete */
+       { "connectionattempts", oConnectionAttempts },
+       { "batchmode", oBatchMode },
+       { "checkhostip", oCheckHostIP },
+       { "stricthostkeychecking", oStrictHostKeyChecking },
+       { "compression", oCompression },
+       { "compressionlevel", oCompressionLevel },
+       { "tcpkeepalive", oTCPKeepAlive },
+       { "keepalive", oTCPKeepAlive },                         /* obsolete */
+       { "numberofpasswordprompts", oNumberOfPasswordPrompts },
+       { "loglevel", oLogLevel },
+       { "dynamicforward", oDynamicForward },
+       { "preferredauthentications", oPreferredAuthentications },
+       { "hostkeyalgorithms", oHostKeyAlgorithms },
+       { "bindaddress", oBindAddress },
+#ifdef ENABLE_PKCS11
+       { "smartcarddevice", oPKCS11Provider },
+       { "pkcs11provider", oPKCS11Provider },
+#else
+       { "smartcarddevice", oUnsupported },
+       { "pkcs11provider", oUnsupported },
+#endif
+       { "clearallforwardings", oClearAllForwardings },
+       { "enablesshkeysign", oEnableSSHKeysign },
+       { "verifyhostkeydns", oVerifyHostKeyDNS },
+       { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
+       { "rekeylimit", oRekeyLimit },
+       { "connecttimeout", oConnectTimeout },
+       { "addressfamily", oAddressFamily },
+       { "serveraliveinterval", oServerAliveInterval },
+       { "serveralivecountmax", oServerAliveCountMax },
+       { "sendenv", oSendEnv },
+       { "controlpath", oControlPath },
+       { "controlmaster", oControlMaster },
+       { "controlpersist", oControlPersist },
+       { "hashknownhosts", oHashKnownHosts },
+       { "tunnel", oTunnel },
+       { "tunneldevice", oTunnelDevice },
+       { "localcommand", oLocalCommand },
+       { "permitlocalcommand", oPermitLocalCommand },
+       { "visualhostkey", oVisualHostKey },
+       { "useroaming", oUseRoaming },
+#ifdef JPAKE
+       { "zeroknowledgepasswordauthentication",
+           oZeroKnowledgePasswordAuthentication },
+#else
+       { "zeroknowledgepasswordauthentication", oUnsupported },
+#endif
+       { "kexalgorithms", oKexAlgorithms },
+       { "ipqos", oIPQoS },
+
+       { NULL, oBadOption }
+};
+
+/*
+ * Adds a local TCP/IP port forward to options.  Never returns if there is an
+ * error.
+ */
+
+void
+add_local_forward(Options *options, const Forward *newfwd)
+{
+       Forward *fwd;
+#ifndef NO_IPPORT_RESERVED_CONCEPT
+       extern uid_t original_real_uid;
+       if (newfwd->listen_port < IPPORT_RESERVED && original_real_uid != 0)
+               fatal("Privileged ports can only be forwarded by root.");
+#endif
+       options->local_forwards = xrealloc(options->local_forwards,
+           options->num_local_forwards + 1,
+           sizeof(*options->local_forwards));
+       fwd = &options->local_forwards[options->num_local_forwards++];
+
+       fwd->listen_host = newfwd->listen_host;
+       fwd->listen_port = newfwd->listen_port;
+       fwd->connect_host = newfwd->connect_host;
+       fwd->connect_port = newfwd->connect_port;
+}
+
+/*
+ * Adds a remote TCP/IP port forward to options.  Never returns if there is
+ * an error.
+ */
+
+void
+add_remote_forward(Options *options, const Forward *newfwd)
+{
+       Forward *fwd;
+
+       options->remote_forwards = xrealloc(options->remote_forwards,
+           options->num_remote_forwards + 1,
+           sizeof(*options->remote_forwards));
+       fwd = &options->remote_forwards[options->num_remote_forwards++];
+
+       fwd->listen_host = newfwd->listen_host;
+       fwd->listen_port = newfwd->listen_port;
+       fwd->connect_host = newfwd->connect_host;
+       fwd->connect_port = newfwd->connect_port;
+       fwd->allocated_port = 0;
+}
+
+static void
+clear_forwardings(Options *options)
+{
+       int i;
+
+       for (i = 0; i < options->num_local_forwards; i++) {
+               if (options->local_forwards[i].listen_host != NULL)
+                       xfree(options->local_forwards[i].listen_host);
+               xfree(options->local_forwards[i].connect_host);
+       }
+       if (options->num_local_forwards > 0) {
+               xfree(options->local_forwards);
+               options->local_forwards = NULL;
+       }
+       options->num_local_forwards = 0;
+       for (i = 0; i < options->num_remote_forwards; i++) {
+               if (options->remote_forwards[i].listen_host != NULL)
+                       xfree(options->remote_forwards[i].listen_host);
+               xfree(options->remote_forwards[i].connect_host);
+       }
+       if (options->num_remote_forwards > 0) {
+               xfree(options->remote_forwards);
+               options->remote_forwards = NULL;
+       }
+       options->num_remote_forwards = 0;
+       options->tun_open = SSH_TUNMODE_NO;
+}
+
+/*
+ * 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.
+ */
+#define WHITESPACE " \t\r\n"
+
+int
+process_config_line(Options *options, const char *host,
+                   char *line, const char *filename, int linenum,
+                   int *activep)
+{
+       char *s, **charptr, *endofnumber, *keyword, *arg, *arg2, fwdarg[256];
+       int opcode, *intptr, value, value2, scale;
+       LogLevel *log_level_ptr;
+       long long orig, val64;
+       size_t len;
+       Forward fwd;
+
+       /* Strip trailing whitespace */
+       for (len = strlen(line) - 1; len > 0; len--) {
+               if (strchr(WHITESPACE, line[len]) == NULL)
+                       break;
+               line[len] = '\0';
+       }
+
+       s = line;
+       /* Get the keyword. (Each line is supposed to begin with a keyword). */
+       if ((keyword = strdelim(&s)) == NULL)
+               return 0;
+       /* 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 oConnectTimeout:
+               intptr = &options->connection_timeout;
+parse_time:
+               arg = strdelim(&s);
+               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 (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       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 oForwardX11Trusted:
+               intptr = &options->forward_x11_trusted;
+               goto parse_flag;
+       
+       case oForwardX11Timeout:
+               intptr = &options->forward_x11_timeout;
+               goto parse_time;
+
+       case oGatewayPorts:
+               intptr = &options->gateway_ports;
+               goto parse_flag;
+
+       case oExitOnForwardFailure:
+               intptr = &options->exit_on_forward_failure;
+               goto parse_flag;
+
+       case oUsePrivilegedPort:
+               intptr = &options->use_privileged_port;
+               goto parse_flag;
+
+       case oPasswordAuthentication:
+               intptr = &options->password_authentication;
+               goto parse_flag;
+
+       case oZeroKnowledgePasswordAuthentication:
+               intptr = &options->zero_knowledge_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;
+
+       case oGssAuthentication:
+               intptr = &options->gss_authentication;
+               goto parse_flag;
+
+       case oGssDelegateCreds:
+               intptr = &options->gss_deleg_creds;
+               goto parse_flag;
+
+       case oBatchMode:
+               intptr = &options->batch_mode;
+               goto parse_flag;
+
+       case oCheckHostIP:
+               intptr = &options->check_host_ip;
+               goto parse_flag;
+
+       case oVerifyHostKeyDNS:
+               intptr = &options->verify_host_key_dns;
+               goto parse_yesnoask;
+
+       case oStrictHostKeyChecking:
+               intptr = &options->strict_host_key_checking;
+parse_yesnoask:
+               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 oTCPKeepAlive:
+               intptr = &options->tcp_keep_alive;
+               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 oRekeyLimit:
+               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);
+               orig = val64 = strtoll(arg, &endofnumber, 10);
+               if (arg == endofnumber)
+                       fatal("%.200s line %d: Bad number.", filename, linenum);
+               switch (toupper(*endofnumber)) {
+               case '\0':
+                       scale = 1;
+                       break;
+               case 'K':
+                       scale = 1<<10;
+                       break;
+               case 'M':
+                       scale = 1<<20;
+                       break;
+               case 'G':
+                       scale = 1<<30;
+                       break;
+               default:
+                       fatal("%.200s line %d: Invalid RekeyLimit suffix",
+                           filename, linenum);
+               }
+               val64 *= scale;
+               /* detect integer wrap and too-large limits */
+               if ((val64 / scale) != orig || val64 > UINT_MAX)
+                       fatal("%.200s line %d: RekeyLimit too large",
+                           filename, linenum);
+               if (val64 < 16)
+                       fatal("%.200s line %d: RekeyLimit too small",
+                           filename, linenum);
+               if (*activep && options->rekey_limit == -1)
+                       options->rekey_limit = (u_int32_t)val64;
+               break;
+
+       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 oPKCS11Provider:
+               charptr = &options->pkcs11_provider;
+               goto parse_string;
+
+       case oProxyCommand:
+               charptr = &options->proxy_command;
+parse_command:
+               if (s == NULL)
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               len = strspn(s, WHITESPACE "=");
+               if (*activep && *charptr == NULL)
+                       *charptr = xstrdup(s + len);
+               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 oKexAlgorithms:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.",
+                           filename, linenum);
+               if (!kex_names_valid(arg))
+                       fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
+                           filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && options->kex_algorithms == NULL)
+                       options->kex_algorithms = 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:
+               log_level_ptr = &options->log_level;
+               arg = strdelim(&s);
+               value = log_level_number(arg);
+               if (value == SYSLOG_LEVEL_NOT_SET)
+                       fatal("%.200s line %d: unsupported log level '%s'",
+                           filename, linenum, arg ? arg : "<NONE>");
+               if (*activep && *log_level_ptr == SYSLOG_LEVEL_NOT_SET)
+                       *log_level_ptr = (LogLevel) value;
+               break;
+
+       case oLocalForward:
+       case oRemoteForward:
+       case oDynamicForward:
+               arg = strdelim(&s);
+               if (arg == NULL || *arg == '\0')
+                       fatal("%.200s line %d: Missing port argument.",
+                           filename, linenum);
+
+               if (opcode == oLocalForward ||
+                   opcode == oRemoteForward) {
+                       arg2 = strdelim(&s);
+                       if (arg2 == NULL || *arg2 == '\0')
+                               fatal("%.200s line %d: Missing target argument.",
+                                   filename, linenum);
+
+                       /* construct a string for parse_forward */
+                       snprintf(fwdarg, sizeof(fwdarg), "%s:%s", arg, arg2);
+               } else if (opcode == oDynamicForward) {
+                       strlcpy(fwdarg, arg, sizeof(fwdarg));
+               }
+
+               if (parse_forward(&fwd, fwdarg,
+                   opcode == oDynamicForward ? 1 : 0,
+                   opcode == oRemoteForward ? 1 : 0) == 0)
+                       fatal("%.200s line %d: Bad forwarding specification.",
+                           filename, linenum);
+
+               if (*activep) {
+                       if (opcode == oLocalForward ||
+                           opcode == oDynamicForward)
+                               add_local_forward(options, &fwd);
+                       else if (opcode == oRemoteForward)
+                               add_remote_forward(options, &fwd);
+               }
+               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;
+
+       case oAddressFamily:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing address family.",
+                           filename, linenum);
+               intptr = &options->address_family;
+               if (strcasecmp(arg, "inet") == 0)
+                       value = AF_INET;
+               else if (strcasecmp(arg, "inet6") == 0)
+                       value = AF_INET6;
+               else if (strcasecmp(arg, "any") == 0)
+                       value = AF_UNSPEC;
+               else
+                       fatal("Unsupported AddressFamily \"%s\"", arg);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oEnableSSHKeysign:
+               intptr = &options->enable_ssh_keysign;
+               goto parse_flag;
+
+       case oIdentitiesOnly:
+               intptr = &options->identities_only;
+               goto parse_flag;
+
+       case oServerAliveInterval:
+               intptr = &options->server_alive_interval;
+               goto parse_time;
+
+       case oServerAliveCountMax:
+               intptr = &options->server_alive_count_max;
+               goto parse_int;
+
+       case oSendEnv:
+               while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
+                       if (strchr(arg, '=') != NULL)
+                               fatal("%s line %d: Invalid environment name.",
+                                   filename, linenum);
+                       if (!*activep)
+                               continue;
+                       if (options->num_send_env >= MAX_SEND_ENV)
+                               fatal("%s line %d: too many send env.",
+                                   filename, linenum);
+                       options->send_env[options->num_send_env++] =
+                           xstrdup(arg);
+               }
+               break;
+
+       case oControlPath:
+               charptr = &options->control_path;
+               goto parse_string;
+
+       case oControlMaster:
+               intptr = &options->control_master;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing ControlMaster argument.",
+                           filename, linenum);
+               value = 0;      /* To avoid compiler warning... */
+               if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
+                       value = SSHCTL_MASTER_YES;
+               else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
+                       value = SSHCTL_MASTER_NO;
+               else if (strcmp(arg, "auto") == 0)
+                       value = SSHCTL_MASTER_AUTO;
+               else if (strcmp(arg, "ask") == 0)
+                       value = SSHCTL_MASTER_ASK;
+               else if (strcmp(arg, "autoask") == 0)
+                       value = SSHCTL_MASTER_AUTO_ASK;
+               else
+                       fatal("%.200s line %d: Bad ControlMaster argument.",
+                           filename, linenum);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case oControlPersist:
+               /* no/false/yes/true, or a time spec */
+               intptr = &options->control_persist;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing ControlPersist"
+                           " argument.", filename, linenum);
+               value = 0;
+               value2 = 0;     /* timeout */
+               if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0)
+                       value = 0;
+               else if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0)
+                       value = 1;
+               else if ((value2 = convtime(arg)) >= 0)
+                       value = 1;
+               else
+                       fatal("%.200s line %d: Bad ControlPersist argument.",
+                           filename, linenum);
+               if (*activep && *intptr == -1) {
+                       *intptr = value;
+                       options->control_persist_timeout = value2;
+               }
+               break;
+
+       case oHashKnownHosts:
+               intptr = &options->hash_known_hosts;
+               goto parse_flag;
+
+       case oTunnel:
+               intptr = &options->tun_open;
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: Missing yes/point-to-point/"
+                           "ethernet/no argument.", filename, linenum);
+               value = 0;      /* silence compiler */
+               if (strcasecmp(arg, "ethernet") == 0)
+                       value = SSH_TUNMODE_ETHERNET;
+               else if (strcasecmp(arg, "point-to-point") == 0)
+                       value = SSH_TUNMODE_POINTOPOINT;
+               else if (strcasecmp(arg, "yes") == 0)
+                       value = SSH_TUNMODE_DEFAULT;
+               else if (strcasecmp(arg, "no") == 0)
+                       value = SSH_TUNMODE_NO;
+               else
+                       fatal("%s line %d: Bad yes/point-to-point/ethernet/"
+                           "no argument: %s", filename, linenum, arg);
+               if (*activep)
+                       *intptr = value;
+               break;
+
+       case oTunnelDevice:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing argument.", filename, linenum);
+               value = a2tun(arg, &value2);
+               if (value == SSH_TUNID_ERR)
+                       fatal("%.200s line %d: Bad tun device.", filename, linenum);
+               if (*activep) {
+                       options->tun_local = value;
+                       options->tun_remote = value2;
+               }
+               break;
+
+       case oLocalCommand:
+               charptr = &options->local_command;
+               goto parse_command;
+
+       case oPermitLocalCommand:
+               intptr = &options->permit_local_command;
+               goto parse_flag;
+
+       case oVisualHostKey:
+               intptr = &options->visual_host_key;
+               goto parse_flag;
+
+       case oIPQoS:
+               arg = strdelim(&s);
+               if ((value = parse_ipqos(arg)) == -1)
+                       fatal("%s line %d: Bad IPQoS value: %s",
+                           filename, linenum, arg);
+               arg = strdelim(&s);
+               if (arg == NULL)
+                       value2 = value;
+               else if ((value2 = parse_ipqos(arg)) == -1)
+                       fatal("%s line %d: Bad IPQoS value: %s",
+                           filename, linenum, arg);
+               if (*activep) {
+                       options->ip_qos_interactive = value;
+                       options->ip_qos_bulk = value2;
+               }
+               break;
+
+       case oUseRoaming:
+               intptr = &options->use_roaming;
+               goto parse_flag;
+
+       case oDeprecated:
+               debug("%s line %d: Deprecated option \"%s\"",
+                   filename, linenum, keyword);
+               return 0;
+
+       case oUnsupported:
+               error("%s line %d: Unsupported option \"%s\"",
+                   filename, linenum, keyword);
+               return 0;
+
+       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,
+    int checkperm)
+{
+       FILE *f;
+       char line[1024];
+       int active, linenum;
+       int bad_options = 0;
+
+       if ((f = fopen(filename, "r")) == NULL)
+               return 0;
+
+       if (checkperm) {
+               struct stat sb;
+
+               if (fstat(fileno(f), &sb) == -1)
+                       fatal("fstat %s: %s", filename, strerror(errno));
+               if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
+                   (sb.st_mode & 022) != 0))
+                       fatal("Bad owner or permissions on %s", filename);
+       }
+
+       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->forward_x11_trusted = -1;
+       options->forward_x11_timeout = -1;
+       options->exit_on_forward_failure = -1;
+       options->xauth_location = NULL;
+       options->gateway_ports = -1;
+       options->use_privileged_port = -1;
+       options->rsa_authentication = -1;
+       options->pubkey_authentication = -1;
+       options->challenge_response_authentication = -1;
+       options->gss_authentication = -1;
+       options->gss_deleg_creds = -1;
+       options->password_authentication = -1;
+       options->kbd_interactive_authentication = -1;
+       options->kbd_interactive_devices = NULL;
+       options->rhosts_rsa_authentication = -1;
+       options->hostbased_authentication = -1;
+       options->batch_mode = -1;
+       options->check_host_ip = -1;
+       options->strict_host_key_checking = -1;
+       options->compression = -1;
+       options->tcp_keep_alive = -1;
+       options->compression_level = -1;
+       options->port = -1;
+       options->address_family = -1;
+       options->connection_attempts = -1;
+       options->connection_timeout = -1;
+       options->number_of_password_prompts = -1;
+       options->cipher = -1;
+       options->ciphers = NULL;
+       options->macs = NULL;
+       options->kex_algorithms = 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->local_forwards = NULL;
+       options->num_local_forwards = 0;
+       options->remote_forwards = NULL;
+       options->num_remote_forwards = 0;
+       options->clear_forwardings = -1;
+       options->log_level = SYSLOG_LEVEL_NOT_SET;
+       options->preferred_authentications = NULL;
+       options->bind_address = NULL;
+       options->pkcs11_provider = NULL;
+       options->enable_ssh_keysign = - 1;
+       options->no_host_authentication_for_localhost = - 1;
+       options->identities_only = - 1;
+       options->rekey_limit = - 1;
+       options->verify_host_key_dns = -1;
+       options->server_alive_interval = -1;
+       options->server_alive_count_max = -1;
+       options->num_send_env = 0;
+       options->control_path = NULL;
+       options->control_master = -1;
+       options->control_persist = -1;
+       options->control_persist_timeout = 0;
+       options->hash_known_hosts = -1;
+       options->tun_open = -1;
+       options->tun_local = -1;
+       options->tun_remote = -1;
+       options->local_command = NULL;
+       options->permit_local_command = -1;
+       options->use_roaming = -1;
+       options->visual_host_key = -1;
+       options->zero_knowledge_password_authentication = -1;
+       options->ip_qos_interactive = -1;
+       options->ip_qos_bulk = -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;
+       if (options->forward_x11_trusted == -1)
+               options->forward_x11_trusted = 0;
+       if (options->forward_x11_timeout == -1)
+               options->forward_x11_timeout = 1200;
+       if (options->exit_on_forward_failure == -1)
+               options->exit_on_forward_failure = 0;
+       if (options->xauth_location == NULL)
+               options->xauth_location = _PATH_XAUTH;
+       if (options->gateway_ports == -1)
+               options->gateway_ports = 0;
+       if (options->use_privileged_port == -1)
+               options->use_privileged_port = 0;
+       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 (options->gss_authentication == -1)
+               options->gss_authentication = 0;
+       if (options->gss_deleg_creds == -1)
+               options->gss_deleg_creds = 0;
+       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 = 0;
+       if (options->hostbased_authentication == -1)
+               options->hostbased_authentication = 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->tcp_keep_alive == -1)
+               options->tcp_keep_alive = 1;
+       if (options->compression_level == -1)
+               options->compression_level = 6;
+       if (options->port == -1)
+               options->port = 0;      /* Filled in ssh_connect. */
+       if (options->address_family == -1)
+               options->address_family = AF_UNSPEC;
+       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->kex_algorithms, default set in myproposals.h */
+       /* options->hostkeyalgorithms, default set in myproposals.h */
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = 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);
+#ifdef OPENSSL_HAS_ECC
+                       len = 2 + strlen(_PATH_SSH_CLIENT_ID_ECDSA) + 1;
+                       options->identity_files[options->num_identity_files] =
+                           xmalloc(len);
+                       snprintf(options->identity_files[options->num_identity_files++],
+                           len, "~/%.100s", _PATH_SSH_CLIENT_ID_ECDSA);
+#endif
+               }
+       }
+       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 == SYSLOG_LEVEL_NOT_SET)
+               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;
+       if (options->identities_only == -1)
+               options->identities_only = 0;
+       if (options->enable_ssh_keysign == -1)
+               options->enable_ssh_keysign = 0;
+       if (options->rekey_limit == -1)
+               options->rekey_limit = 0;
+       if (options->verify_host_key_dns == -1)
+               options->verify_host_key_dns = 0;
+       if (options->server_alive_interval == -1)
+               options->server_alive_interval = 0;
+       if (options->server_alive_count_max == -1)
+               options->server_alive_count_max = 3;
+       if (options->control_master == -1)
+               options->control_master = 0;
+       if (options->control_persist == -1) {
+               options->control_persist = 0;
+               options->control_persist_timeout = 0;
+       }
+       if (options->hash_known_hosts == -1)
+               options->hash_known_hosts = 0;
+       if (options->tun_open == -1)
+               options->tun_open = SSH_TUNMODE_NO;
+       if (options->tun_local == -1)
+               options->tun_local = SSH_TUNID_ANY;
+       if (options->tun_remote == -1)
+               options->tun_remote = SSH_TUNID_ANY;
+       if (options->permit_local_command == -1)
+               options->permit_local_command = 0;
+       if (options->use_roaming == -1)
+               options->use_roaming = 1;
+       if (options->visual_host_key == -1)
+               options->visual_host_key = 0;
+       if (options->zero_knowledge_password_authentication == -1)
+               options->zero_knowledge_password_authentication = 0;
+       if (options->ip_qos_interactive == -1)
+               options->ip_qos_interactive = IPTOS_LOWDELAY;
+       if (options->ip_qos_bulk == -1)
+               options->ip_qos_bulk = IPTOS_THROUGHPUT;
+       /* options->local_command should not be set by default */
+       /* options->proxy_command should not be set by default */
+       /* options->user will be set in the main program if appropriate */
+       /* 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 */
+}
+
+/*
+ * parse_forward
+ * parses a string containing a port forwarding specification of the form:
+ *   dynamicfwd == 0
+ *     [listenhost:]listenport:connecthost:connectport
+ *   dynamicfwd == 1
+ *     [listenhost:]listenport
+ * returns number of arguments parsed or zero on error
+ */
+int
+parse_forward(Forward *fwd, const char *fwdspec, int dynamicfwd, int remotefwd)
+{
+       int i;
+       char *p, *cp, *fwdarg[4];
+
+       memset(fwd, '\0', sizeof(*fwd));
+
+       cp = p = xstrdup(fwdspec);
+
+       /* skip leading spaces */
+       while (isspace(*cp))
+               cp++;
+
+       for (i = 0; i < 4; ++i)
+               if ((fwdarg[i] = hpdelim(&cp)) == NULL)
+                       break;
+
+       /* Check for trailing garbage */
+       if (cp != NULL)
+               i = 0;  /* failure */
+
+       switch (i) {
+       case 1:
+               fwd->listen_host = NULL;
+               fwd->listen_port = a2port(fwdarg[0]);
+               fwd->connect_host = xstrdup("socks");
+               break;
+
+       case 2:
+               fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
+               fwd->listen_port = a2port(fwdarg[1]);
+               fwd->connect_host = xstrdup("socks");
+               break;
+
+       case 3:
+               fwd->listen_host = NULL;
+               fwd->listen_port = a2port(fwdarg[0]);
+               fwd->connect_host = xstrdup(cleanhostname(fwdarg[1]));
+               fwd->connect_port = a2port(fwdarg[2]);
+               break;
+
+       case 4:
+               fwd->listen_host = xstrdup(cleanhostname(fwdarg[0]));
+               fwd->listen_port = a2port(fwdarg[1]);
+               fwd->connect_host = xstrdup(cleanhostname(fwdarg[2]));
+               fwd->connect_port = a2port(fwdarg[3]);
+               break;
+       default:
+               i = 0; /* failure */
+       }
+
+       xfree(p);
+
+       if (dynamicfwd) {
+               if (!(i == 1 || i == 2))
+                       goto fail_free;
+       } else {
+               if (!(i == 3 || i == 4))
+                       goto fail_free;
+               if (fwd->connect_port <= 0)
+                       goto fail_free;
+       }
+
+       if (fwd->listen_port < 0 || (!remotefwd && fwd->listen_port == 0))
+               goto fail_free;
+
+       if (fwd->connect_host != NULL &&
+           strlen(fwd->connect_host) >= NI_MAXHOST)
+               goto fail_free;
+       if (fwd->listen_host != NULL &&
+           strlen(fwd->listen_host) >= NI_MAXHOST)
+               goto fail_free;
+
+
+       return (i);
+
+ fail_free:
+       if (fwd->connect_host != NULL) {
+               xfree(fwd->connect_host);
+               fwd->connect_host = NULL;
+       }
+       if (fwd->listen_host != NULL) {
+               xfree(fwd->listen_host);
+               fwd->listen_host = NULL;
+       }
+       return (0);
+}
diff --git a/readconf.h b/readconf.h
new file mode 100644 (file)
index 0000000..ee160df
--- /dev/null
@@ -0,0 +1,154 @@
+/* $OpenBSD: readconf.h,v 1.88 2010/11/13 23:27:50 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#ifndef READCONF_H
+#define READCONF_H
+
+/* Data structure for representing a forwarding request. */
+
+typedef struct {
+       char     *listen_host;          /* Host (address) to listen on. */
+       int       listen_port;          /* Port to forward. */
+       char     *connect_host;         /* Host to connect. */
+       int       connect_port;         /* Port to connect on connect_host. */
+       int       allocated_port;       /* Dynamically allocated listen port */
+}       Forward;
+/* Data structure for representing option data. */
+
+#define MAX_SEND_ENV   256
+
+typedef struct {
+       int     forward_agent;  /* Forward authentication agent. */
+       int     forward_x11;    /* Forward X11 display. */
+       int     forward_x11_timeout;    /* Expiration for Cookies */
+       int     forward_x11_trusted;    /* Trust Forward X11 display. */
+       int     exit_on_forward_failure;        /* Exit if bind(2) fails for -L/-R */
+       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_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. */
+       int     gss_authentication;     /* Try GSS authentication */
+       int     gss_deleg_creds;        /* Delegate GSS credentials */
+       int     password_authentication;        /* Try password
+                                                * authentication. */
+       int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
+       char    *kbd_interactive_devices; /* Keyboard-interactive auth devices. */
+       int     zero_knowledge_password_authentication; /* Try jpake */
+       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     tcp_keep_alive; /* Set SO_KEEPALIVE. */
+       int     ip_qos_interactive;     /* IP ToS/DSCP/class for interactive */
+       int     ip_qos_bulk;            /* IP ToS/DSCP/class for bulk traffic */
+       LogLevel log_level;     /* Level for logging. */
+
+       int     port;           /* Port to connect. */
+       int     address_family;
+       int     connection_attempts;    /* Max attempts (seconds) before
+                                        * giving up */
+       int     connection_timeout;     /* Max time (seconds) before
+                                        * aborting connection attempt */
+       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. */
+       char   *kex_algorithms; /* SSH2 kex methods 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/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   *pkcs11_provider; /* PKCS#11 provider */
+       int     verify_host_key_dns;    /* Verify host key using DNS */
+
+       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;
+
+       /* Remote TCP/IP forward requests. */
+       int     num_remote_forwards;
+       Forward *remote_forwards;
+       int     clear_forwardings;
+
+       int     enable_ssh_keysign;
+       int64_t rekey_limit;
+       int     no_host_authentication_for_localhost;
+       int     identities_only;
+       int     server_alive_interval;
+       int     server_alive_count_max;
+
+       int     num_send_env;
+       char   *send_env[MAX_SEND_ENV];
+
+       char    *control_path;
+       int     control_master;
+       int     control_persist; /* ControlPersist flag */
+       int     control_persist_timeout; /* ControlPersist timeout (seconds) */
+
+       int     hash_known_hosts;
+
+       int     tun_open;       /* tun(4) */
+       int     tun_local;      /* force tun device (optional) */
+       int     tun_remote;     /* force tun device (optional) */
+
+       char    *local_command;
+       int     permit_local_command;
+       int     visual_host_key;
+
+       int     use_roaming;
+
+}       Options;
+
+#define SSHCTL_MASTER_NO       0
+#define SSHCTL_MASTER_YES      1
+#define SSHCTL_MASTER_AUTO     2
+#define SSHCTL_MASTER_ASK      3
+#define SSHCTL_MASTER_AUTO_ASK 4
+
+void     initialize_options(Options *);
+void     fill_default_options(Options *);
+int     read_config_file(const char *, const char *, Options *, int);
+int     parse_forward(Forward *, const char *, int, int);
+
+int
+process_config_line(Options *, const char *, char *, const char *, int, int *);
+
+void    add_local_forward(Options *, const Forward *);
+void    add_remote_forward(Options *, const Forward *);
+
+#endif                         /* READCONF_H */
diff --git a/readpass.c b/readpass.c
new file mode 100644 (file)
index 0000000..599c8ef
--- /dev/null
@@ -0,0 +1,193 @@
+/* $OpenBSD: readpass.c,v 1.48 2010/12/15 00:49:27 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "misc.h"
+#include "pathnames.h"
+#include "log.h"
+#include "ssh.h"
+#include "uidswap.h"
+
+static char *
+ssh_askpass(char *askpass, const char *msg)
+{
+       pid_t pid, ret;
+       size_t len;
+       char *pass;
+       int p[2], status;
+       char buf[1024];
+       void (*osigchld)(int);
+
+       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 NULL;
+       }
+       osigchld = signal(SIGCHLD, SIG_DFL);
+       if ((pid = fork()) < 0) {
+               error("ssh_askpass: fork: %s", strerror(errno));
+               signal(SIGCHLD, osigchld);
+               return NULL;
+       }
+       if (pid == 0) {
+               permanently_drop_suid(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 = 0;
+       do {
+               ssize_t r = read(p[0], buf + len, sizeof(buf) - 1 - len);
+
+               if (r == -1 && errno == EINTR)
+                       continue;
+               if (r <= 0)
+                       break;
+               len += r;
+       } while (sizeof(buf) - 1 - len > 0);
+       buf[len] = '\0';
+
+       close(p[0]);
+       while ((ret = waitpid(pid, &status, 0)) < 0)
+               if (errno != EINTR)
+                       break;
+       signal(SIGCHLD, osigchld);
+       if (ret == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+               memset(buf, 0, sizeof(buf));
+               return NULL;
+       }
+
+       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_USE_ASKPASS)
+               use_askpass = 1;
+       else if (flags & RP_ALLOW_STDIN) {
+               if (!isatty(STDIN_FILENO)) {
+                       debug("read_passphrase: stdin is not a tty");
+                       use_askpass = 1;
+               }
+       } else {
+               rppflags |= RPP_REQUIRE_TTY;
+               ttyfd = open(_PATH_TTY, O_RDWR);
+               if (ttyfd >= 0)
+                       close(ttyfd);
+               else {
+                       debug("read_passphrase: can't open %s: %s", _PATH_TTY,
+                           strerror(errno));
+                       use_askpass = 1;
+               }
+       }
+
+       if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL)
+               return (flags & RP_ALLOW_EOF) ? NULL : xstrdup("");
+
+       if (use_askpass && getenv("DISPLAY")) {
+               if (getenv(SSH_ASKPASS_ENV))
+                       askpass = getenv(SSH_ASKPASS_ENV);
+               else
+                       askpass = _PATH_SSH_ASKPASS_DEFAULT;
+               if ((ret = ssh_askpass(askpass, prompt)) == NULL)
+                       if (!(flags & RP_ALLOW_EOF))
+                               return xstrdup("");
+               return ret;
+       }
+
+       if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) {
+               if (flags & RP_ALLOW_EOF)
+                       return NULL;
+               return xstrdup("");
+       }
+
+       ret = xstrdup(buf);
+       memset(buf, 'x', sizeof buf);
+       return ret;
+}
+
+int
+ask_permission(const char *fmt, ...)
+{
+       va_list args;
+       char *p, prompt[1024];
+       int allowed = 0;
+
+       va_start(args, fmt);
+       vsnprintf(prompt, sizeof(prompt), fmt, args);
+       va_end(args);
+
+       p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF);
+       if (p != NULL) {
+               /*
+                * Accept empty responses and responses consisting
+                * of the word "yes" as affirmative.
+                */
+               if (*p == '\0' || *p == '\n' ||
+                   strcasecmp(p, "yes") == 0)
+                       allowed = 1;
+               xfree(p);
+       }
+
+       return (allowed);
+}
diff --git a/regress/Makefile b/regress/Makefile
new file mode 100644 (file)
index 0000000..f114c27
--- /dev/null
@@ -0,0 +1,156 @@
+#      $OpenBSD: Makefile,v 1.58 2011/01/06 22:46:21 djm Exp $
+
+REGRESS_TARGETS=       t1 t2 t3 t4 t5 t6 t7 t8 t9 t-exec
+tests:         $(REGRESS_TARGETS)
+
+# Interop tests are not run by default
+interop interop-tests: t-exec-interop
+
+clean:
+       for F in $(CLEANFILES); do rm -f $(OBJ)$$F; done
+       rm -rf $(OBJ).putty
+
+distclean:     clean
+
+LTESTS=        connect \
+               proxy-connect \
+               connect-privsep \
+               proto-version \
+               proto-mismatch \
+               exit-status \
+               envpass \
+               transfer \
+               banner \
+               rekey \
+               stderr-data \
+               stderr-after-eof \
+               broken-pipe \
+               try-ciphers \
+               yes-head \
+               login-timeout \
+               agent \
+               agent-getpeereid \
+               agent-timeout \
+               agent-ptrace \
+               keyscan \
+               keygen-change \
+               keygen-convert \
+               key-options \
+               scp \
+               sftp \
+               sftp-cmds \
+               sftp-badcmds \
+               sftp-batch \
+               sftp-glob \
+               reconfigure \
+               dynamic-forward \
+               forwarding \
+               multiplex \
+               reexec \
+               brokenkeys \
+               cfgmatch \
+               addrmatch \
+               localcommand \
+               forcecommand \
+               portnum \
+               keytype \
+               kextype \
+               cert-hostkey \
+               cert-userkey \
+               host-expand
+
+INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
+#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp
+
+#LTESTS=       cipher-speed
+
+USER!=         id -un
+CLEANFILES=    t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub copy.1 copy.2 \
+               t8.out t8.out.pub t9.out t9.out.pub \
+               authorized_keys_${USER} known_hosts pidfile \
+               ssh_config sshd_config.orig ssh_proxy sshd_config sshd_proxy \
+               rsa.pub rsa rsa1.pub rsa1 host.rsa host.rsa1 \
+               rsa-agent rsa-agent.pub rsa1-agent rsa1-agent.pub \
+               ls.copy banner.in banner.out empty.in \
+               scp-ssh-wrapper.scp ssh_proxy_envpass remote_pid \
+               sshd_proxy_bak rsa_ssh2_cr.prv rsa_ssh2_crnl.prv \
+               known_hosts-cert host_ca_key* cert_host_key* \
+               putty.rsa2 sshd_proxy_orig ssh_proxy_bak \
+               key.rsa-* key.dsa-* key.ecdsa-* \
+               authorized_principals_${USER} expect actual
+
+# Enable all malloc(3) randomisations and checks
+TEST_ENV=      "MALLOC_OPTIONS=AFGJPRX"
+
+TEST_SSH_SSHKEYGEN?=ssh-keygen
+
+t1:
+       ${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/rsa_ssh2.prv | diff - ${.CURDIR}/rsa_openssh.prv
+       tr '\n' '\r' <${.CURDIR}/rsa_ssh2.prv > ${.OBJDIR}/rsa_ssh2_cr.prv
+       ${TEST_SSH_SSHKEYGEN} -if ${.OBJDIR}/rsa_ssh2_cr.prv | diff - ${.CURDIR}/rsa_openssh.prv
+       awk '{print $$0 "\r"}' ${.CURDIR}/rsa_ssh2.prv > ${.OBJDIR}/rsa_ssh2_crnl.prv
+       ${TEST_SSH_SSHKEYGEN} -if ${.OBJDIR}/rsa_ssh2_crnl.prv | diff - ${.CURDIR}/rsa_openssh.prv
+
+t2:
+       cat ${.CURDIR}/rsa_openssh.prv > $(OBJ)/t2.out
+       chmod 600 $(OBJ)/t2.out
+       ${TEST_SSH_SSHKEYGEN} -yf $(OBJ)/t2.out | diff - ${.CURDIR}/rsa_openssh.pub
+
+t3:
+       ${TEST_SSH_SSHKEYGEN} -ef ${.CURDIR}/rsa_openssh.pub >$(OBJ)/t3.out
+       ${TEST_SSH_SSHKEYGEN} -if $(OBJ)/t3.out | diff - ${.CURDIR}/rsa_openssh.pub
+
+t4:
+       ${TEST_SSH_SSHKEYGEN} -lf ${.CURDIR}/rsa_openssh.pub |\
+               awk '{print $$2}' | diff - ${.CURDIR}/t4.ok
+
+t5:
+       ${TEST_SSH_SSHKEYGEN} -Bf ${.CURDIR}/rsa_openssh.pub |\
+               awk '{print $$2}' | diff - ${.CURDIR}/t5.ok
+
+t6:
+       ${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.prv > $(OBJ)/t6.out1
+       ${TEST_SSH_SSHKEYGEN} -if ${.CURDIR}/dsa_ssh2.pub > $(OBJ)/t6.out2
+       chmod 600 $(OBJ)/t6.out1
+       ${TEST_SSH_SSHKEYGEN} -yf $(OBJ)/t6.out1 | diff - $(OBJ)/t6.out2
+
+$(OBJ)/t7.out:
+       ${TEST_SSH_SSHKEYGEN} -q -t rsa -N '' -f $@
+
+t7: $(OBJ)/t7.out
+       ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t7.out > /dev/null
+       ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t7.out > /dev/null
+
+$(OBJ)/t8.out:
+       ${TEST_SSH_SSHKEYGEN} -q -t dsa -N '' -f $@
+
+t8: $(OBJ)/t8.out
+       ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t8.out > /dev/null
+       ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t8.out > /dev/null
+
+$(OBJ)/t9.out:
+       test "${TEST_SSH_ECC}" != yes || \
+       ${TEST_SSH_SSHKEYGEN} -q -t ecdsa -N '' -f $@
+
+t9: $(OBJ)/t9.out
+       test "${TEST_SSH_ECC}" != yes || \
+       ${TEST_SSH_SSHKEYGEN} -lf $(OBJ)/t9.out > /dev/null
+       test "${TEST_SSH_ECC}" != yes || \
+       ${TEST_SSH_SSHKEYGEN} -Bf $(OBJ)/t9.out > /dev/null
+
+t-exec:        ${LTESTS:=.sh}
+       @if [ "x$?" = "x" ]; then exit 0; fi; \
+       for TEST in ""$?; do \
+               echo "run test $${TEST}" ... 1>&2; \
+               (env SUDO="${SUDO}" TEST_ENV=${TEST_ENV} sh ${.CURDIR}/test-exec.sh ${.OBJDIR} ${.CURDIR}/$${TEST}) || exit $$?; \
+       done
+
+t-exec-interop:        ${INTEROP_TESTS:=.sh}
+       @if [ "x$?" = "x" ]; then exit 0; fi; \
+       for TEST in ""$?; do \
+               echo "run test $${TEST}" ... 1>&2; \
+               (env SUDO="${SUDO}" TEST_ENV=${TEST_ENV} sh ${.CURDIR}/test-exec.sh ${.OBJDIR} ${.CURDIR}/$${TEST}) || exit $$?; \
+       done
+
+# Not run by default
+interop: ${INTEROP_TARGETS}
diff --git a/regress/README.regress b/regress/README.regress
new file mode 100644 (file)
index 0000000..da9bb6a
--- /dev/null
@@ -0,0 +1,108 @@
+Overview.
+
+$ ./configure && make tests
+
+You'll see some progress info. A failure will cause either the make to
+abort or the driver script to report a "FATAL" failure.
+
+The test consists of 2 parts. The first is the file-based tests which is
+driven by the Makefile, and the second is a set of network or proxycommand
+based tests, which are driven by a driver script (test-exec.sh) which is
+called multiple times by the Makefile.
+
+Failures in the first part will cause the Makefile to return an error.
+Failures in the second part will print a "FATAL" message for the failed
+test and continue.
+
+OpenBSD has a system-wide regression test suite. OpenSSH Portable's test
+suite is based on OpenBSD's with modifications.
+
+
+Environment variables.
+
+SUDO: path to sudo command, if desired. Note that some systems (notably
+       systems using PAM) require sudo to execute some tests.
+TEST_SSH_TRACE: set to "yes" for verbose output from tests 
+TEST_SSH_QUIET: set to "yes" to suppress non-fatal output.
+TEST_SSH_x: path to "ssh" command under test, where x=SSH,SSHD,SSHAGENT,SSHADD
+       SSHKEYGEN,SSHKEYSCAN,SFTP,SFTPSERVER
+OBJ: used by test scripts to access build dir.
+TEST_SHELL: shell used for running the test scripts.
+TEST_SSH_PORT: TCP port to be used for the listening tests.
+TEST_SSH_SSH_CONFOPTS: Configuration directives to be added to ssh_config
+       before running each test.
+TEST_SSH_SSHD_CONFOTPS: Configuration directives to be added to sshd_config
+       before running each test.
+
+
+Individual tests.
+
+You can run an individual test from the top-level Makefile, eg:
+$ make tests LTESTS=agent-timeout
+
+If you need to manipulate the environment more you can invoke test-exec.sh
+directly if you set up the path to find the binaries under test and the
+test scripts themselves, for example:
+
+$ cd regress
+$ PATH=`pwd`/..:$PATH:. TEST_SHELL=/bin/sh sh test-exec.sh `pwd` \
+    agent-timeout.sh
+ok agent timeout test
+
+
+Files.
+
+test-exec.sh: the main test driver. Sets environment, creates config files
+and keys and runs the specified test.
+
+At the time of writing, the individual tests are:
+agent-timeout.sh:      agent timeout test
+agent.sh:              simple agent test
+broken-pipe.sh:                broken pipe test
+connect-privsep.sh:    proxy connect with privsep
+connect.sh:            simple connect
+exit-status.sh:                remote exit status
+forwarding.sh:         local and remote forwarding
+keygen-change.sh:      change passphrase for key
+keyscan.sh:            keyscan
+proto-mismatch.sh:     protocol version mismatch
+proto-version.sh:      sshd version with different protocol combinations
+proxy-connect.sh:      proxy connect
+sftp.sh:               basic sftp put/get
+ssh-com-client.sh:     connect with ssh.com client
+ssh-com-keygen.sh:     ssh.com key import
+ssh-com-sftp.sh:       basic sftp put/get with ssh.com server
+ssh-com.sh:            connect to ssh.com server
+stderr-after-eof.sh:   stderr data after eof
+stderr-data.sh:                stderr data transfer
+transfer.sh:           transfer data
+try-ciphers.sh:                try ciphers
+yes-head.sh:           yes pipe head
+
+
+Problems?
+
+Run the failing test with shell tracing (-x) turned on:
+$ PATH=`pwd`/..:$PATH:. sh -x test-exec.sh `pwd` agent-timeout.sh
+
+Failed tests can be difficult to diagnose. Suggestions:
+- run the individual test via ./test-exec.sh `pwd` [testname]
+- set LogLevel to VERBOSE in test-exec.sh and enable syslogging of
+  auth.debug (eg to /var/log/authlog).
+
+
+Known Issues.
+
+- If your build requires ssh-rand-helper regress tests will fail
+  unless ssh-rand-helper is in pre-installed (the path to
+  ssh-rand-helper is hard coded).
+
+- Similarly, if you do not have "scp" in your system's $PATH then the
+  multiplex scp tests will fail (since the system's shell startup scripts
+  will determine where the shell started by sshd will look for scp).
+
+- Recent GNU coreutils deprecate "head -[n]": this will cause the yes-head
+  test to fail.  The old behaviour can be restored by setting (and
+  exporting) _POSIX2_VERSION=199209 before running the tests.
+
+$Id: README.regress,v 1.11 2010/08/16 21:04:29 djm Exp $
diff --git a/regress/addrmatch.sh b/regress/addrmatch.sh
new file mode 100644 (file)
index 0000000..23ddd65
--- /dev/null
@@ -0,0 +1,45 @@
+#      $OpenBSD: addrmatch.sh,v 1.3 2010/02/09 04:57:36 djm Exp $
+#      Placed in the Public Domain.
+
+tid="address match"
+
+mv $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
+run_trial()
+{
+       user="$1"; addr="$2"; host="$3"; expected="$4"; descr="$5"
+
+       verbose "test $descr for $user $addr $host"
+       result=`${SSHD} -f $OBJ/sshd_proxy -T \
+           -C user=${user},addr=${addr},host=${host} | \
+           awk '/^passwordauthentication/ {print $2}'`
+       if [ "$result" != "$expected" ]; then
+               fail "failed for $user $addr $host: expected $expected, got $result"
+       fi
+}
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+cat >>$OBJ/sshd_proxy <<EOD
+PasswordAuthentication no
+Match Address 192.168.0.0/16,!192.168.30.0/24,10.0.0.0/8,host.example.com
+       PasswordAuthentication yes
+Match Address 1.1.1.1,::1,!::3,2000::/16
+       PasswordAuthentication yes
+EOD
+
+run_trial user 192.168.0.1 somehost yes                "permit, first entry"
+run_trial user 192.168.30.1 somehost no                "deny, negative match"
+run_trial user 19.0.0.1 somehost no            "deny, no match"
+run_trial user 10.255.255.254 somehost yes     "permit, list middle"
+run_trial user 192.168.30.1 192.168.0.1 no     "deny, faked IP in hostname"
+run_trial user 1.1.1.1 somehost.example.com yes        "permit, bare IP4 address"
+test "$TEST_SSH_IPV6" = "no" && exit
+run_trial user ::1 somehost.example.com         yes    "permit, bare IP6 address"
+run_trial user ::2 somehost.exaple.com no      "deny IPv6"
+run_trial user ::3 somehost no                 "deny IP6 negated"
+run_trial user ::4 somehost no                 "deny, IP6 no match"
+run_trial user 2000::1 somehost yes            "permit, IP6 network"
+run_trial user 2001::1 somehost no             "deny, IP6 network"
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+rm $OBJ/sshd_proxy_bak
diff --git a/regress/agent-getpeereid.sh b/regress/agent-getpeereid.sh
new file mode 100644 (file)
index 0000000..faf654c
--- /dev/null
@@ -0,0 +1,46 @@
+#      $OpenBSD: agent-getpeereid.sh,v 1.4 2007/11/25 15:35:09 jmc Exp $
+#      Placed in the Public Domain.
+
+tid="disallow agent attach from other uid"
+
+UNPRIV=nobody
+ASOCK=${OBJ}/agent
+SSH_AUTH_SOCK=/nonexistent
+
+if config_defined HAVE_GETPEEREID HAVE_GETPEERUCRED HAVE_SO_PEERCRED ; then
+       :
+else
+       echo "skipped (not supported on this platform)"
+       exit 0
+fi
+if [ -z "$SUDO" ]; then
+       echo "skipped: need SUDO to switch to uid $UNPRIV"
+       exit 0
+fi
+
+
+trace "start agent"
+eval `${SSHAGENT} -s -a ${ASOCK}` > /dev/null
+r=$?
+if [ $r -ne 0 ]; then
+       fail "could not start ssh-agent: exit code $r"
+else
+       chmod 644 ${SSH_AUTH_SOCK}
+
+       ssh-add -l > /dev/null 2>&1
+       r=$?
+       if [ $r -ne 1 ]; then
+               fail "ssh-add failed with $r != 1"
+       fi
+
+       < /dev/null ${SUDO} -S -u ${UNPRIV} ssh-add -l 2>/dev/null
+       r=$?
+       if [ $r -lt 2 ]; then
+               fail "ssh-add did not fail for ${UNPRIV}: $r < 2"
+       fi
+
+       trace "kill agent"
+       ${SSHAGENT} -k > /dev/null
+fi
+
+rm -f ${OBJ}/agent
diff --git a/regress/agent-pkcs11.sh b/regress/agent-pkcs11.sh
new file mode 100644 (file)
index 0000000..db33ab3
--- /dev/null
@@ -0,0 +1,69 @@
+#      $OpenBSD: agent-pkcs11.sh,v 1.1 2010/02/08 10:52:47 markus Exp $
+#      Placed in the Public Domain.
+
+tid="pkcs11 agent test"
+
+TEST_SSH_PIN=""
+TEST_SSH_PKCS11=/usr/local/lib/soft-pkcs11.so.0.0
+
+# setup environment for soft-pkcs11 token
+SOFTPKCS11RC=$OBJ/pkcs11.info
+export SOFTPKCS11RC
+# prevent ssh-agent from calling ssh-askpass
+SSH_ASKPASS=/usr/bin/true
+export SSH_ASKPASS
+unset DISPLAY
+
+# start command w/o tty, so ssh-add accepts pin from stdin
+notty() {
+       perl -e 'use POSIX; POSIX::setsid(); 
+           if (fork) { wait; exit($? >> 8); } else { exec(@ARGV) }' "$@"
+}
+
+trace "start agent"
+eval `${SSHAGENT} -s` > /dev/null
+r=$?
+if [ $r -ne 0 ]; then
+       fail "could not start ssh-agent: exit code $r"
+else
+       trace "generating key/cert"
+       rm -f $OBJ/pkcs11.key $OBJ/pkcs11.crt
+       openssl genrsa -out $OBJ/pkcs11.key 2048 > /dev/null 2>&1
+       chmod 600 $OBJ/pkcs11.key 
+       openssl req -key $OBJ/pkcs11.key -new -x509 \
+           -out $OBJ/pkcs11.crt -text -subj '/CN=pkcs11 test' > /dev/null
+       printf "a\ta\t$OBJ/pkcs11.crt\t$OBJ/pkcs11.key" > $SOFTPKCS11RC
+       # add to authorized keys
+       ${SSHKEYGEN} -y -f $OBJ/pkcs11.key > $OBJ/authorized_keys_$USER
+
+       trace "add pkcs11 key to agent"
+       echo ${TEST_SSH_PIN} | notty ${SSHADD} -s ${TEST_SSH_PKCS11} > /dev/null 2>&1
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh-add -s failed: exit code $r"
+       fi
+
+       trace "pkcs11 list via agent"
+       ${SSHADD} -l > /dev/null 2>&1
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh-add -l failed: exit code $r"
+       fi
+
+       trace "pkcs11 connect via agent"
+       ${SSH} -2 -F $OBJ/ssh_proxy somehost exit 5
+       r=$?
+       if [ $r -ne 5 ]; then
+               fail "ssh connect failed (exit code $r)"
+       fi
+
+       trace "remove pkcs11 keys"
+       echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh-add -e failed: exit code $r"
+       fi
+
+       trace "kill agent"
+       ${SSHAGENT} -k > /dev/null
+fi
diff --git a/regress/agent-ptrace.sh b/regress/agent-ptrace.sh
new file mode 100644 (file)
index 0000000..9f29464
--- /dev/null
@@ -0,0 +1,53 @@
+#      $OpenBSD: agent-ptrace.sh,v 1.1 2002/12/09 15:38:30 markus Exp $
+#      Placed in the Public Domain.
+
+tid="disallow agent ptrace attach"
+
+if have_prog uname ; then
+       case `uname` in
+       AIX|CYGWIN*|OSF1)
+               echo "skipped (not supported on this platform)"
+               exit 0
+               ;;
+       esac
+fi
+
+if have_prog gdb ; then
+       : ok
+else
+       echo "skipped (gdb not found)"
+       exit 0
+fi
+
+if test -z "$SUDO" ; then
+       echo "skipped (SUDO not set)"
+       exit 0
+else
+       $SUDO chown 0 ${SSHAGENT}
+       $SUDO chgrp 0 ${SSHAGENT}
+       $SUDO chmod 2755 ${SSHAGENT}
+fi
+
+trace "start agent"
+eval `${SSHAGENT} -s` > /dev/null
+r=$?
+if [ $r -ne 0 ]; then
+       fail "could not start ssh-agent: exit code $r"
+else
+       # ls -l ${SSH_AUTH_SOCK}
+       gdb ${SSHAGENT} ${SSH_AGENT_PID} > ${OBJ}/gdb.out 2>&1 << EOF
+               quit
+EOF
+       if [ $? -ne 0 ]; then
+               fail "gdb failed: exit code $?"
+       fi
+       egrep 'ptrace: Operation not permitted.|procfs:.*Permission denied.|ttrace.*Permission denied.|procfs:.*: Invalid argument.|Unable to access task ' >/dev/null ${OBJ}/gdb.out
+       r=$?
+       rm -f ${OBJ}/gdb.out
+       if [ $r -ne 0 ]; then
+               fail "ptrace succeeded?: exit code $r"
+       fi
+
+       trace "kill agent"
+       ${SSHAGENT} -k > /dev/null
+fi
diff --git a/regress/agent-timeout.sh b/regress/agent-timeout.sh
new file mode 100644 (file)
index 0000000..3a40e7a
--- /dev/null
@@ -0,0 +1,36 @@
+#      $OpenBSD: agent-timeout.sh,v 1.1 2002/06/06 00:38:40 markus Exp $
+#      Placed in the Public Domain.
+
+tid="agent timeout test"
+
+SSHAGENT_TIMEOUT=10
+
+trace "start agent"
+eval `${SSHAGENT} -s` > /dev/null
+r=$?
+if [ $r -ne 0 ]; then
+       fail "could not start ssh-agent: exit code $r"
+else
+       trace "add keys with timeout"
+       for t in rsa rsa1; do
+               ${SSHADD} -t ${SSHAGENT_TIMEOUT} $OBJ/$t > /dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh-add did succeed exit code 0"
+               fi
+       done
+       n=`${SSHADD} -l 2> /dev/null | wc -l`
+       trace "agent has $n keys"
+       if [ $n -ne 2 ]; then
+               fail "ssh-add -l did not return 2 keys: $n"
+       fi
+       trace "sleeping 2*${SSHAGENT_TIMEOUT} seconds"
+       sleep ${SSHAGENT_TIMEOUT}
+       sleep ${SSHAGENT_TIMEOUT}
+       ${SSHADD} -l 2> /dev/null | grep 'The agent has no identities.' >/dev/null
+       if [ $? -ne 0 ]; then
+               fail "ssh-add -l still returns keys after timeout"
+       fi
+
+       trace "kill agent"
+       ${SSHAGENT} -k > /dev/null
+fi
diff --git a/regress/agent.sh b/regress/agent.sh
new file mode 100644 (file)
index 0000000..094cf69
--- /dev/null
@@ -0,0 +1,75 @@
+#      $OpenBSD: agent.sh,v 1.7 2007/11/25 15:35:09 jmc Exp $
+#      Placed in the Public Domain.
+
+tid="simple agent test"
+
+SSH_AUTH_SOCK=/nonexistent ${SSHADD} -l > /dev/null 2>&1
+if [ $? -ne 2 ]; then
+       fail "ssh-add -l did not fail with exit code 2"
+fi
+
+trace "start agent"
+eval `${SSHAGENT} -s` > /dev/null
+r=$?
+if [ $r -ne 0 ]; then
+       fail "could not start ssh-agent: exit code $r"
+else
+       ${SSHADD} -l > /dev/null 2>&1
+       if [ $? -ne 1 ]; then
+               fail "ssh-add -l did not fail with exit code 1"
+       fi
+       trace "overwrite authorized keys"
+       echon > $OBJ/authorized_keys_$USER
+       for t in rsa rsa1; do
+               # generate user key for agent
+               rm -f $OBJ/$t-agent
+               ${SSHKEYGEN} -q -N '' -t $t -f $OBJ/$t-agent ||\
+                        fail "ssh-keygen for $t-agent failed"
+               # add to authorized keys
+               cat $OBJ/$t-agent.pub >> $OBJ/authorized_keys_$USER
+               # add privat key to agent
+               ${SSHADD} $OBJ/$t-agent > /dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh-add did succeed exit code 0"
+               fi
+       done
+       ${SSHADD} -l > /dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               fail "ssh-add -l failed: exit code $?"
+       fi
+       # the same for full pubkey output
+       ${SSHADD} -L > /dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               fail "ssh-add -L failed: exit code $?"
+       fi
+
+       trace "simple connect via agent"
+       for p in 1 2; do
+               ${SSH} -$p -F $OBJ/ssh_proxy somehost exit 5$p
+               if [ $? -ne 5$p ]; then
+                       fail "ssh connect with protocol $p failed (exit code $?)"
+               fi
+       done
+
+       trace "agent forwarding"
+       for p in 1 2; do
+               ${SSH} -A -$p -F $OBJ/ssh_proxy somehost ${SSHADD} -l > /dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh-add -l via agent fwd proto $p failed (exit code $?)"
+               fi
+               ${SSH} -A -$p -F $OBJ/ssh_proxy somehost \
+                       "${SSH} -$p -F $OBJ/ssh_proxy somehost exit 5$p"
+               if [ $? -ne 5$p ]; then
+                       fail "agent fwd proto $p failed (exit code $?)"
+               fi
+       done
+
+       trace "delete all agent keys"
+       ${SSHADD} -D > /dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               fail "ssh-add -D failed: exit code $?"
+       fi
+
+       trace "kill agent"
+       ${SSHAGENT} -k > /dev/null
+fi
diff --git a/regress/banner.sh b/regress/banner.sh
new file mode 100644 (file)
index 0000000..0b9c950
--- /dev/null
@@ -0,0 +1,44 @@
+#      $OpenBSD: banner.sh,v 1.2 2003/10/11 11:49:49 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="banner"
+echo "Banner $OBJ/banner.in" >> $OBJ/sshd_proxy
+
+rm -f $OBJ/banner.out $OBJ/banner.in $OBJ/empty.in
+touch $OBJ/empty.in
+
+trace "test missing banner file"
+verbose "test $tid: missing banner file"
+( ${SSH} -2 -F $OBJ/ssh_proxy otherhost true 2>$OBJ/banner.out && \
+       cmp $OBJ/empty.in $OBJ/banner.out ) || \
+       fail "missing banner file"
+
+for s in 0 10 100 1000 10000 100000 ; do
+       if [ "$s" = "0" ]; then
+               # create empty banner
+               touch $OBJ/banner.in
+       elif [ "$s" = "10" ]; then
+               # create 10-byte banner file
+               echo "abcdefghi" >$OBJ/banner.in
+       else
+               # increase size 10x
+               cp $OBJ/banner.in $OBJ/banner.out
+               for i in 0 1 2 3 4 5 6 7 8 ; do
+                       cat $OBJ/banner.out >> $OBJ/banner.in
+               done
+       fi
+
+       trace "test banner size $s"
+       verbose "test $tid: size $s"
+       ( ${SSH} -2 -F $OBJ/ssh_proxy otherhost true 2>$OBJ/banner.out && \
+               cmp $OBJ/banner.in $OBJ/banner.out ) || \
+               fail "banner size $s mismatch"
+done
+
+trace "test suppress banner (-q)"
+verbose "test $tid: suppress banner (-q)"
+( ${SSH} -q -2 -F $OBJ/ssh_proxy otherhost true 2>$OBJ/banner.out && \
+       cmp $OBJ/empty.in $OBJ/banner.out ) || \
+       fail "suppress banner (-q)"
+
+rm -f $OBJ/banner.out $OBJ/banner.in $OBJ/empty.in
diff --git a/regress/broken-pipe.sh b/regress/broken-pipe.sh
new file mode 100644 (file)
index 0000000..c08c849
--- /dev/null
@@ -0,0 +1,15 @@
+#      $OpenBSD: broken-pipe.sh,v 1.4 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="broken pipe test"
+
+for p in 1 2; do
+       trace "protocol $p"
+       for i in 1 2 3 4; do
+               ${SSH} -$p -F $OBJ/ssh_config_config nexthost echo $i 2> /dev/null | true
+               r=$?
+               if [ $r -ne 0 ]; then
+                       fail "broken pipe returns $r for protocol $p"
+               fi
+       done
+done
diff --git a/regress/brokenkeys.sh b/regress/brokenkeys.sh
new file mode 100644 (file)
index 0000000..3e70c34
--- /dev/null
@@ -0,0 +1,23 @@
+#      $OpenBSD: brokenkeys.sh,v 1.1 2004/10/29 23:59:22 djm Exp $
+#      Placed in the Public Domain.
+
+tid="broken keys"
+
+KEYS="$OBJ/authorized_keys_${USER}"
+
+start_sshd
+
+mv ${KEYS} ${KEYS}.bak
+
+# Truncated key
+echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEABTM= bad key" > $KEYS
+cat ${KEYS}.bak >> ${KEYS}
+cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER
+
+${SSH} -2 -F $OBJ/ssh_config somehost true
+if [ $? -ne 0 ]; then
+       fail "ssh connect with protocol $p failed"
+fi
+
+mv ${KEYS}.bak ${KEYS}
+
diff --git a/regress/bsd.regress.mk b/regress/bsd.regress.mk
new file mode 100644 (file)
index 0000000..9b8011a
--- /dev/null
@@ -0,0 +1,79 @@
+#      $OpenBSD: bsd.regress.mk,v 1.9 2002/02/17 01:10:15 marc Exp $
+# No man pages for regression tests.
+NOMAN=
+
+# No installation.
+install:
+
+# If REGRESSTARGETS is defined and PROG is not defined, set NOPROG
+.if defined(REGRESSTARGETS) && !defined(PROG)
+NOPROG=
+.endif
+
+.include <bsd.prog.mk>
+
+.MAIN: all
+all: regress
+
+# XXX - Need full path to REGRESSLOG, otherwise there will be much pain.
+
+REGRESSLOG?=/dev/null
+REGRESSNAME=${.CURDIR:S/${BSDSRCDIR}\/regress\///}
+
+.if defined(PROG) && !empty(PROG)
+run-regress-${PROG}: ${PROG}
+       ./${PROG}
+.endif
+
+.if !defined(REGRESSTARGETS)
+REGRESSTARGETS=run-regress-${PROG}
+.  if defined(REGRESSSKIP)
+REGRESSSKIPTARGETS=run-regress-${PROG}
+.  endif
+.endif
+
+REGRESSSKIPSLOW?=no
+
+#.if (${REGRESSSKIPSLOW:L} == "yes") && defined(REGRESSSLOWTARGETS)
+
+.if (${REGRESSSKIPSLOW} == "yes") && defined(REGRESSSLOWTARGETS)
+REGRESSSKIPTARGETS+=${REGRESSSLOWTARGETS}
+.endif
+
+.if defined(REGRESSROOTTARGETS)
+ROOTUSER!=id -g
+SUDO?=
+. if (${ROOTUSER} != 0) && empty(SUDO)
+REGRESSSKIPTARGETS+=${REGRESSROOTTARGETS}
+. endif
+.endif
+
+REGRESSSKIPTARGETS?=
+
+regress:
+.for RT in ${REGRESSTARGETS} 
+.  if ${REGRESSSKIPTARGETS:M${RT}}
+       @echo -n "SKIP " >> ${REGRESSLOG}
+.  else
+# XXX - we need a better method to see if a test fails due to timeout or just
+#       normal failure.
+.   if !defined(REGRESSMAXTIME)
+       @if cd ${.CURDIR} && ${MAKE} ${RT}; then \
+           echo -n "SUCCESS " >> ${REGRESSLOG} ; \
+       else \
+           echo -n "FAIL " >> ${REGRESSLOG} ; \
+           echo FAILED ; \
+       fi
+.   else
+       @if cd ${.CURDIR} && (ulimit -t ${REGRESSMAXTIME} ; ${MAKE} ${RT}); then \
+           echo -n "SUCCESS " >> ${REGRESSLOG} ; \
+       else \
+           echo -n "FAIL (possible timeout) " >> ${REGRESSLOG} ; \
+           echo FAILED ; \
+       fi
+.   endif
+.  endif
+       @echo ${REGRESSNAME}/${RT:S/^run-regress-//} >> ${REGRESSLOG}
+.endfor
+
+.PHONY: regress
diff --git a/regress/cert-hostkey.sh b/regress/cert-hostkey.sh
new file mode 100644 (file)
index 0000000..3b147b9
--- /dev/null
@@ -0,0 +1,256 @@
+#      $OpenBSD: cert-hostkey.sh,v 1.5 2010/08/31 12:24:09 djm Exp $
+#      Placed in the Public Domain.
+
+tid="certified host keys"
+
+# used to disable ECC based tests on platforms without ECC
+ecdsa=""
+if test "x$TEST_SSH_ECC" = "xyes"; then
+       ecdsa=ecdsa
+fi
+
+rm -f $OBJ/known_hosts-cert $OBJ/host_ca_key* $OBJ/cert_host_key*
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
+HOSTS='localhost-with-alias,127.0.0.1,::1'
+
+# Create a CA key and add it to known hosts
+${SSHKEYGEN} -q -N '' -t rsa  -f $OBJ/host_ca_key ||\
+       fail "ssh-keygen of host_ca_key failed"
+(
+       echon '@cert-authority '
+       echon "$HOSTS "
+       cat $OBJ/host_ca_key.pub
+) > $OBJ/known_hosts-cert
+
+# Generate and sign host keys
+for ktype in rsa dsa $ecdsa ; do 
+       verbose "$tid: sign host ${ktype} cert"
+       # Generate and sign a host key
+       ${SSHKEYGEN} -q -N '' -t ${ktype} \
+           -f $OBJ/cert_host_key_${ktype} || \
+               fail "ssh-keygen of cert_host_key_${ktype} failed"
+       ${SSHKEYGEN} -h -q -s $OBJ/host_ca_key \
+           -I "regress host key for $USER" \
+           -n $HOSTS $OBJ/cert_host_key_${ktype} ||
+               fail "couldn't sign cert_host_key_${ktype}"
+       # v00 ecdsa certs do not exist
+       test "${ktype}" = "ecdsa" && continue
+       cp $OBJ/cert_host_key_${ktype} $OBJ/cert_host_key_${ktype}_v00
+       cp $OBJ/cert_host_key_${ktype}.pub $OBJ/cert_host_key_${ktype}_v00.pub
+       ${SSHKEYGEN} -t v00 -h -q -s $OBJ/host_ca_key \
+           -I "regress host key for $USER" \
+           -n $HOSTS $OBJ/cert_host_key_${ktype}_v00 ||
+               fail "couldn't sign cert_host_key_${ktype}_v00"
+done
+
+# Basic connect tests
+for privsep in yes no ; do
+       for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00; do 
+               verbose "$tid: host ${ktype} cert connect privsep $privsep"
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/cert_host_key_${ktype}
+                       echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
+                       echo UsePrivilegeSeparation $privsep
+               ) > $OBJ/sshd_proxy
+
+               ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+                   -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+                       -F $OBJ/ssh_proxy somehost true
+               if [ $? -ne 0 ]; then
+                       fail "ssh cert connect failed"
+               fi
+       done
+done
+
+# Revoked certificates with key present
+(
+       echon '@cert-authority '
+       echon "$HOSTS "
+       cat $OBJ/host_ca_key.pub
+       echon '@revoked '
+       echon "* "
+       cat $OBJ/cert_host_key_rsa.pub
+       if test "x$TEST_SSH_ECC" = "xyes"; then
+               echon '@revoked '
+               echon "* "
+               cat $OBJ/cert_host_key_ecdsa.pub
+       fi
+       echon '@revoked '
+       echon "* "
+       cat $OBJ/cert_host_key_dsa.pub
+       echon '@revoked '
+       echon "* "
+       cat $OBJ/cert_host_key_rsa_v00.pub
+       echon '@revoked '
+       echon "* "
+       cat $OBJ/cert_host_key_dsa_v00.pub
+) > $OBJ/known_hosts-cert
+for privsep in yes no ; do
+       for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00; do 
+               verbose "$tid: host ${ktype} revoked cert privsep $privsep"
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/cert_host_key_${ktype}
+                       echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
+                       echo UsePrivilegeSeparation $privsep
+               ) > $OBJ/sshd_proxy
+
+               ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+                   -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+                       -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+       done
+done
+
+# Revoked CA
+(
+       echon '@cert-authority '
+       echon "$HOSTS "
+       cat $OBJ/host_ca_key.pub
+       echon '@revoked '
+       echon "* "
+       cat $OBJ/host_ca_key.pub
+) > $OBJ/known_hosts-cert
+for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00 ; do 
+       verbose "$tid: host ${ktype} revoked cert"
+       (
+               cat $OBJ/sshd_proxy_bak
+               echo HostKey $OBJ/cert_host_key_${ktype}
+               echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
+       ) > $OBJ/sshd_proxy
+       ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+           -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+               -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               fail "ssh cert connect succeeded unexpectedly"
+       fi
+done
+
+# Create a CA key and add it to known hosts
+(
+       echon '@cert-authority '
+       echon "$HOSTS "
+       cat $OBJ/host_ca_key.pub
+) > $OBJ/known_hosts-cert
+
+test_one() {
+       ident=$1
+       result=$2
+       sign_opts=$3
+
+       for kt in rsa rsa_v00 ; do
+               case $kt in
+               *_v00) args="-t v00" ;;
+               *) args="" ;;
+               esac
+
+               verbose "$tid: host cert connect $ident $kt expect $result"
+               ${SSHKEYGEN} -q -s $OBJ/host_ca_key \
+                   -I "regress host key for $USER" \
+                   $sign_opts $args \
+                   $OBJ/cert_host_key_${kt} ||
+                       fail "couldn't sign cert_host_key_${kt}"
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/cert_host_key_${kt}
+                       echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
+               ) > $OBJ/sshd_proxy
+       
+               ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+                   -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               rc=$?
+               if [ "x$result" = "xsuccess" ] ; then
+                       if [ $rc -ne 0 ]; then
+                               fail "ssh cert connect $ident failed unexpectedly"
+                       fi
+               else
+                       if [ $rc -eq 0 ]; then
+                               fail "ssh cert connect $ident succeeded unexpectedly"
+                       fi
+               fi
+       done
+}
+
+test_one "user-certificate"    failure "-n $HOSTS"
+test_one "empty principals"    success "-h"
+test_one "wrong principals"    failure "-h -n foo"
+test_one "cert not yet valid"  failure "-h -V20200101:20300101"
+test_one "cert expired"                failure "-h -V19800101:19900101"
+test_one "cert valid interval" success "-h -V-1w:+2w"
+test_one "cert has constraints"        failure "-h -Oforce-command=false"
+
+# Check downgrade of cert to raw key when no CA found
+for v in v01 v00 ;  do 
+       for ktype in rsa dsa $ecdsa ; do 
+               # v00 ecdsa certs do not exist.
+               test "${v}${ktype}" = "v00ecdsa" && continue
+               rm -f $OBJ/known_hosts-cert $OBJ/cert_host_key*
+               verbose "$tid: host ${ktype} ${v} cert downgrade to raw key"
+               # Generate and sign a host key
+               ${SSHKEYGEN} -q -N '' -t ${ktype} \
+                   -f $OBJ/cert_host_key_${ktype} || \
+                       fail "ssh-keygen of cert_host_key_${ktype} failed"
+               ${SSHKEYGEN} -t ${v} -h -q -s $OBJ/host_ca_key \
+                   -I "regress host key for $USER" \
+                   -n $HOSTS $OBJ/cert_host_key_${ktype} ||
+                       fail "couldn't sign cert_host_key_${ktype}"
+               (
+                       echon "$HOSTS "
+                       cat $OBJ/cert_host_key_${ktype}.pub
+               ) > $OBJ/known_hosts-cert
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/cert_host_key_${ktype}
+                       echo HostCertificate $OBJ/cert_host_key_${ktype}-cert.pub
+               ) > $OBJ/sshd_proxy
+               
+               ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+                   -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+                       -F $OBJ/ssh_proxy somehost true
+               if [ $? -ne 0 ]; then
+                       fail "ssh cert connect failed"
+               fi
+       done
+done
+
+# Wrong certificate
+(
+       echon '@cert-authority '
+       echon "$HOSTS "
+       cat $OBJ/host_ca_key.pub
+) > $OBJ/known_hosts-cert
+for v in v01 v00 ;  do 
+       for kt in rsa dsa $ecdsa ; do 
+               # v00 ecdsa certs do not exist.
+               test "${v}${ktype}" = "v00ecdsa" && continue
+               rm -f $OBJ/cert_host_key*
+               # Self-sign key
+               ${SSHKEYGEN} -q -N '' -t ${kt} \
+                   -f $OBJ/cert_host_key_${kt} || \
+                       fail "ssh-keygen of cert_host_key_${kt} failed"
+               ${SSHKEYGEN} -t ${v} -h -q -s $OBJ/cert_host_key_${kt} \
+                   -I "regress host key for $USER" \
+                   -n $HOSTS $OBJ/cert_host_key_${kt} ||
+                       fail "couldn't sign cert_host_key_${kt}"
+               verbose "$tid: host ${kt} connect wrong cert"
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/cert_host_key_${kt}
+                       echo HostCertificate $OBJ/cert_host_key_${kt}-cert.pub
+               ) > $OBJ/sshd_proxy
+       
+               ${SSH} -2 -oUserKnownHostsFile=$OBJ/known_hosts-cert \
+                   -oGlobalKnownHostsFile=$OBJ/known_hosts-cert \
+                       -F $OBJ/ssh_proxy -q somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect $ident succeeded unexpectedly"
+               fi
+       done
+done
+
+rm -f $OBJ/known_hosts-cert $OBJ/host_ca_key* $OBJ/cert_host_key*
diff --git a/regress/cert-userkey.sh b/regress/cert-userkey.sh
new file mode 100644 (file)
index 0000000..fcca370
--- /dev/null
@@ -0,0 +1,338 @@
+#      $OpenBSD: cert-userkey.sh,v 1.7 2010/08/31 12:24:09 djm Exp $
+#      Placed in the Public Domain.
+
+tid="certified user keys"
+
+# used to disable ECC based tests on platforms without ECC
+ecdsa=""
+if test "x$TEST_SSH_ECC" = "xyes"; then
+       ecdsa=ecdsa
+fi
+
+rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key*
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
+# Create a CA key
+${SSHKEYGEN} -q -N '' -t rsa  -f $OBJ/user_ca_key ||\
+       fail "ssh-keygen of user_ca_key failed"
+
+# Generate and sign user keys
+for ktype in rsa dsa $ecdsa ; do 
+       verbose "$tid: sign user ${ktype} cert"
+       ${SSHKEYGEN} -q -N '' -t ${ktype} \
+           -f $OBJ/cert_user_key_${ktype} || \
+               fail "ssh-keygen of cert_user_key_${ktype} failed"
+       ${SSHKEYGEN} -q -s $OBJ/user_ca_key -I \
+           "regress user key for $USER" \
+           -n ${USER},mekmitasdigoat $OBJ/cert_user_key_${ktype} ||
+               fail "couldn't sign cert_user_key_${ktype}"
+       # v00 ecdsa certs do not exist
+       test "{ktype}" = "ecdsa" && continue
+       cp $OBJ/cert_user_key_${ktype} $OBJ/cert_user_key_${ktype}_v00
+       cp $OBJ/cert_user_key_${ktype}.pub $OBJ/cert_user_key_${ktype}_v00.pub
+       ${SSHKEYGEN} -q -t v00 -s $OBJ/user_ca_key -I \
+           "regress user key for $USER" \
+           -n ${USER},mekmitasdigoat $OBJ/cert_user_key_${ktype}_v00 ||
+               fail "couldn't sign cert_user_key_${ktype}_v00"
+done
+
+# Test explicitly-specified principals
+for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00 ; do 
+       for privsep in yes no ; do
+               _prefix="${ktype} privsep $privsep"
+
+               # Setup for AuthorizedPrincipalsFile
+               rm -f $OBJ/authorized_keys_$USER
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo "UsePrivilegeSeparation $privsep"
+                       echo "AuthorizedPrincipalsFile " \
+                           "$OBJ/authorized_principals_%u"
+                       echo "TrustedUserCAKeys $OBJ/user_ca_key.pub"
+               ) > $OBJ/sshd_proxy
+
+               # Missing authorized_principals
+               verbose "$tid: ${_prefix} missing authorized_principals"
+               rm -f $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+
+               # Empty authorized_principals
+               verbose "$tid: ${_prefix} empty authorized_principals"
+               echo > $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+       
+               # Wrong authorized_principals
+               verbose "$tid: ${_prefix} wrong authorized_principals"
+               echo gregorsamsa > $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+
+               # Correct authorized_principals
+               verbose "$tid: ${_prefix} correct authorized_principals"
+               echo mekmitasdigoat > $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh cert connect failed"
+               fi
+
+               # authorized_principals with bad key option
+               verbose "$tid: ${_prefix} authorized_principals bad key opt"
+               echo 'blah mekmitasdigoat' > $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+
+               # authorized_principals with command=false
+               verbose "$tid: ${_prefix} authorized_principals command=false"
+               echo 'command="false" mekmitasdigoat' > \
+                   $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+
+
+               # authorized_principals with command=true
+               verbose "$tid: ${_prefix} authorized_principals command=true"
+               echo 'command="true" mekmitasdigoat' > \
+                   $OBJ/authorized_principals_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost false >/dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh cert connect failed"
+               fi
+
+               # Setup for principals= key option
+               rm -f $OBJ/authorized_principals_$USER
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo "UsePrivilegeSeparation $privsep"
+               ) > $OBJ/sshd_proxy
+
+               # Wrong principals list
+               verbose "$tid: ${_prefix} wrong principals key option"
+               (
+                       echon 'cert-authority,principals="gregorsamsa" '
+                       cat $OBJ/user_ca_key.pub
+               ) > $OBJ/authorized_keys_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpectedly"
+               fi
+
+               # Correct principals list
+               verbose "$tid: ${_prefix} correct principals key option"
+               (
+                       echon 'cert-authority,principals="mekmitasdigoat" '
+                       cat $OBJ/user_ca_key.pub
+               ) > $OBJ/authorized_keys_$USER
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                   -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "ssh cert connect failed"
+               fi
+       done
+done
+
+basic_tests() {
+       auth=$1
+       if test "x$auth" = "xauthorized_keys" ; then
+               # Add CA to authorized_keys
+               (
+                       echon 'cert-authority '
+                       cat $OBJ/user_ca_key.pub
+               ) > $OBJ/authorized_keys_$USER
+       else
+               echo > $OBJ/authorized_keys_$USER
+               extra_sshd="TrustedUserCAKeys $OBJ/user_ca_key.pub"
+       fi
+       
+       for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00 ; do 
+               for privsep in yes no ; do
+                       _prefix="${ktype} privsep $privsep $auth"
+                       # Simple connect
+                       verbose "$tid: ${_prefix} connect"
+                       (
+                               cat $OBJ/sshd_proxy_bak
+                               echo "UsePrivilegeSeparation $privsep"
+                               echo "$extra_sshd"
+                       ) > $OBJ/sshd_proxy
+       
+                       ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                           -F $OBJ/ssh_proxy somehost true
+                       if [ $? -ne 0 ]; then
+                               fail "ssh cert connect failed"
+                       fi
+
+                       # Revoked keys
+                       verbose "$tid: ${_prefix} revoked key"
+                       (
+                               cat $OBJ/sshd_proxy_bak
+                               echo "UsePrivilegeSeparation $privsep"
+                               echo "RevokedKeys $OBJ/cert_user_key_${ktype}.pub"
+                               echo "$extra_sshd"
+                       ) > $OBJ/sshd_proxy
+                       ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                           -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+                       if [ $? -eq 0 ]; then
+                               fail "ssh cert connect succeeded unexpecedly"
+                       fi
+               done
+       
+               # Revoked CA
+               verbose "$tid: ${ktype} $auth revoked CA key"
+               (
+                       cat $OBJ/sshd_proxy_bak
+                       echo "RevokedKeys $OBJ/user_ca_key.pub"
+                       echo "$extra_sshd"
+               ) > $OBJ/sshd_proxy
+               ${SSH} -2i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \
+                   somehost true >/dev/null 2>&1
+               if [ $? -eq 0 ]; then
+                       fail "ssh cert connect succeeded unexpecedly"
+               fi
+       done
+       
+       verbose "$tid: $auth CA does not authenticate"
+       (
+               cat $OBJ/sshd_proxy_bak
+               echo "$extra_sshd"
+       ) > $OBJ/sshd_proxy
+       verbose "$tid: ensure CA key does not authenticate user"
+       ${SSH} -2i $OBJ/user_ca_key \
+           -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               fail "ssh cert connect with CA key succeeded unexpectedly"
+       fi
+}
+
+basic_tests authorized_keys
+basic_tests TrustedUserCAKeys
+
+test_one() {
+       ident=$1
+       result=$2
+       sign_opts=$3
+       auth_choice=$4
+       auth_opt=$5
+
+       if test "x$auth_choice" = "x" ; then
+               auth_choice="authorized_keys TrustedUserCAKeys"
+       fi
+
+       for auth in $auth_choice ; do
+               for ktype in rsa rsa_v00 ; do
+                       case $ktype in
+                       *_v00) keyv="-t v00" ;;
+                       *) keyv="" ;;
+                       esac
+
+                       cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy
+                       if test "x$auth" = "xauthorized_keys" ; then
+                               # Add CA to authorized_keys
+                               (
+                                       echon "cert-authority${auth_opt} "
+                                       cat $OBJ/user_ca_key.pub
+                               ) > $OBJ/authorized_keys_$USER
+                       else
+                               echo > $OBJ/authorized_keys_$USER
+                               echo "TrustedUserCAKeys $OBJ/user_ca_key.pub" \
+                                   >> $OBJ/sshd_proxy
+                               if test "x$auth_opt" != "x" ; then
+                                       echo $auth_opt >> $OBJ/sshd_proxy
+                               fi
+                       fi
+                       
+                       verbose "$tid: $ident auth $auth expect $result $ktype"
+                       ${SSHKEYGEN} -q -s $OBJ/user_ca_key \
+                           -I "regress user key for $USER" \
+                           $sign_opts $keyv \
+                           $OBJ/cert_user_key_${ktype} ||
+                               fail "couldn't sign cert_user_key_${ktype}"
+
+                       ${SSH} -2i $OBJ/cert_user_key_${ktype} \
+                           -F $OBJ/ssh_proxy somehost true >/dev/null 2>&1
+                       rc=$?
+                       if [ "x$result" = "xsuccess" ] ; then
+                               if [ $rc -ne 0 ]; then
+                                       fail "$ident failed unexpectedly"
+                               fi
+                       else
+                               if [ $rc -eq 0 ]; then
+                                       fail "$ident succeeded unexpectedly"
+                               fi
+                       fi
+               done
+       done
+}
+
+test_one "correct principal"   success "-n ${USER}"
+test_one "host-certificate"    failure "-n ${USER} -h"
+test_one "wrong principals"    failure "-n foo"
+test_one "cert not yet valid"  failure "-n ${USER} -V20200101:20300101"
+test_one "cert expired"                failure "-n ${USER} -V19800101:19900101"
+test_one "cert valid interval" success "-n ${USER} -V-1w:+2w"
+test_one "wrong source-address"        failure "-n ${USER} -Osource-address=10.0.0.0/8"
+test_one "force-command"       failure "-n ${USER} -Oforce-command=false"
+
+# Behaviour is different here: TrustedUserCAKeys doesn't allow empty principals
+test_one "empty principals"    success "" authorized_keys
+test_one "empty principals"    failure "" TrustedUserCAKeys
+
+# Check explicitly-specified principals: an empty principals list in the cert
+# should always be refused.
+
+# AuthorizedPrincipalsFile
+rm -f $OBJ/authorized_keys_$USER
+echo mekmitasdigoat > $OBJ/authorized_principals_$USER
+test_one "AuthorizedPrincipalsFile principals" success "-n mekmitasdigoat" \
+    TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u"
+test_one "AuthorizedPrincipalsFile no principals" failure "" \
+    TrustedUserCAKeys "AuthorizedPrincipalsFile $OBJ/authorized_principals_%u"
+
+# principals= key option
+rm -f $OBJ/authorized_principals_$USER
+test_one "principals key option principals" success "-n mekmitasdigoat" \
+    authorized_keys ',principals="mekmitasdigoat"'
+test_one "principals key option no principals" failure "" \
+    authorized_keys ',principals="mekmitasdigoat"'
+
+# Wrong certificate
+cat $OBJ/sshd_proxy_bak > $OBJ/sshd_proxy
+for ktype in rsa dsa $ecdsa rsa_v00 dsa_v00 ; do 
+       case $ktype in
+       *_v00) args="-t v00" ;;
+       *) args="" ;;
+       esac
+       # Self-sign
+       ${SSHKEYGEN} $args -q -s $OBJ/cert_user_key_${ktype} -I \
+           "regress user key for $USER" \
+           -n $USER $OBJ/cert_user_key_${ktype} ||
+               fail "couldn't sign cert_user_key_${ktype}"
+       verbose "$tid: user ${ktype} connect wrong cert"
+       ${SSH} -2i $OBJ/cert_user_key_${ktype} -F $OBJ/ssh_proxy \
+           somehost true >/dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               fail "ssh cert connect $ident succeeded unexpectedly"
+       fi
+done
+
+rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key*
+rm -f $OBJ/authorized_principals_$USER
+
diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh
new file mode 100644 (file)
index 0000000..96badd5
--- /dev/null
@@ -0,0 +1,125 @@
+#      $OpenBSD: cfgmatch.sh,v 1.4 2006/12/13 08:36:36 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="sshd_config match"
+
+pidfile=$OBJ/remote_pid
+fwdport=3301
+fwd="-L $fwdport:127.0.0.1:$PORT"
+
+stop_client()
+{
+       pid=`cat $pidfile`
+       if [ ! -z "$pid" ]; then
+               kill $pid
+               sleep 1
+       fi
+}
+
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
+echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_config
+echo "Match Address 127.0.0.1" >>$OBJ/sshd_config
+echo "PermitOpen 127.0.0.1:$PORT" >>$OBJ/sshd_config
+
+echo "PermitOpen 127.0.0.1:1" >>$OBJ/sshd_proxy
+echo "Match Address 127.0.0.1" >>$OBJ/sshd_proxy
+echo "PermitOpen 127.0.0.1:$PORT" >>$OBJ/sshd_proxy
+
+start_sshd
+
+#set -x
+
+# Test Match + PermitOpen in sshd_config.  This should be permitted
+for p in 1 2; do
+       rm -f $pidfile
+       trace "match permitopen localhost proto $p"
+       ${SSH} -$p $fwd -F $OBJ/ssh_config -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "match permitopen proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true || \
+           fail "match permitopen permit proto $p"
+       stop_client
+done
+
+# Same but from different source.  This should not be permitted
+for p in 1 2; do
+       rm -f $pidfile
+       trace "match permitopen proxy proto $p"
+       ${SSH} -q -$p $fwd -F $OBJ/ssh_proxy -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "match permitopen proxy proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true && \
+           fail "match permitopen deny proto $p"
+       stop_client
+done
+
+# Retry previous with key option, should also be denied.
+echon 'permitopen="127.0.0.1:'$PORT'" ' >$OBJ/authorized_keys_$USER
+cat $OBJ/rsa.pub >> $OBJ/authorized_keys_$USER
+echon 'permitopen="127.0.0.1:'$PORT'" ' >>$OBJ/authorized_keys_$USER
+cat $OBJ/rsa1.pub >> $OBJ/authorized_keys_$USER
+for p in 1 2; do
+       rm -f $pidfile
+       trace "match permitopen proxy w/key opts proto $p"
+       ${SSH} -q -$p $fwd -F $OBJ/ssh_proxy -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "match permitopen w/key opt proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true && \
+           fail "match permitopen deny w/key opt proto $p"
+       stop_client
+done
+
+# Test both sshd_config and key options permitting the same dst/port pair.
+# Should be permitted.
+for p in 1 2; do
+       rm -f $pidfile
+       trace "match permitopen localhost proto $p"
+       ${SSH} -$p $fwd -F $OBJ/ssh_config -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "match permitopen proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true || \
+           fail "match permitopen permit proto $p"
+       stop_client
+done
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy
+echo "Match User $USER" >>$OBJ/sshd_proxy
+echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy
+
+# Test that a Match overrides a PermitOpen in the global section
+for p in 1 2; do
+       rm -f $pidfile
+       trace "match permitopen proxy w/key opts proto $p"
+       ${SSH} -q -$p $fwd -F $OBJ/ssh_proxy -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "match override permitopen proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true && \
+           fail "match override permitopen proto $p"
+       stop_client
+done
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "PermitOpen 127.0.0.1:1 127.0.0.1:$PORT 127.0.0.2:2" >>$OBJ/sshd_proxy
+echo "Match User NoSuchUser" >>$OBJ/sshd_proxy
+echo "PermitOpen 127.0.0.1:1 127.0.0.1:2" >>$OBJ/sshd_proxy
+
+# Test that a rule that doesn't match doesn't override, plus test a
+# PermitOpen entry that's not at the start of the list
+for p in 1 2; do
+       rm -f $pidfile
+       trace "nomatch permitopen proxy w/key opts proto $p"
+       ${SSH} -q -$p $fwd -F $OBJ/ssh_proxy -f somehost \
+           exec sh -c \'"echo \$\$ > $pidfile; exec sleep 100"\' >>$TEST_SSH_LOGFILE 2>&1 ||\
+           fail "nomatch override permitopen proto $p sshd failed"
+       sleep 1;
+       ${SSH} -q -$p -p $fwdport -F $OBJ/ssh_config somehost true || \
+           fail "nomatch override permitopen proto $p"
+       stop_client
+done
diff --git a/regress/cipher-speed.sh b/regress/cipher-speed.sh
new file mode 100644 (file)
index 0000000..85de6d5
--- /dev/null
@@ -0,0 +1,47 @@
+#      $OpenBSD: cipher-speed.sh,v 1.3 2007/06/07 19:41:46 pvalchev Exp $
+#      Placed in the Public Domain.
+
+tid="cipher speed"
+
+getbytes ()
+{
+       sed -n '/transferred/s/.*secs (\(.* bytes.sec\).*/\1/p'
+}
+
+tries="1 2"
+DATA=/bin/ls
+DATA=/bsd
+
+macs="hmac-sha1 hmac-md5 umac-64@openssh.com hmac-sha1-96 hmac-md5-96"
+ciphers="aes128-cbc 3des-cbc blowfish-cbc cast128-cbc 
+       arcfour128 arcfour256 arcfour aes192-cbc aes256-cbc aes128-ctr"
+
+for c in $ciphers; do for m in $macs; do
+       trace "proto 2 cipher $c mac $m"
+       for x in $tries; do
+               echon "$c/$m:\t"
+               ( ${SSH} -o 'compression no' \
+                       -F $OBJ/ssh_proxy -2 -m $m -c $c somehost \
+                       exec sh -c \'"dd of=/dev/null obs=32k"\' \
+               < ${DATA} ) 2>&1 | getbytes
+
+               if [ $? -ne 0 ]; then
+                       fail "ssh -2 failed with mac $m cipher $c"
+               fi
+       done
+done; done
+
+ciphers="3des blowfish"
+for c in $ciphers; do
+       trace "proto 1 cipher $c"
+       for x in $tries; do
+               echon "$c:\t"
+               ( ${SSH} -o 'compression no' \
+                       -F $OBJ/ssh_proxy -1 -c $c somehost \
+                       exec sh -c \'"dd of=/dev/null obs=32k"\' \
+               < ${DATA} ) 2>&1 | getbytes
+               if [ $? -ne 0 ]; then
+                       fail "ssh -1 failed with cipher $c"
+               fi
+       done
+done
diff --git a/regress/conch-ciphers.sh b/regress/conch-ciphers.sh
new file mode 100644 (file)
index 0000000..5b65cd9
--- /dev/null
@@ -0,0 +1,31 @@
+#      $OpenBSD: conch-ciphers.sh,v 1.2 2008/06/30 10:43:03 djm Exp $
+#      Placed in the Public Domain.
+
+tid="conch ciphers"
+
+DATA=/bin/ls
+COPY=${OBJ}/copy
+
+if test "x$REGRESS_INTEROP_CONCH" != "xyes" ; then
+       echo "conch interop tests not enabled"
+       exit 0
+fi
+
+start_sshd
+
+for c in aes256-ctr aes256-cbc aes192-ctr aes192-cbc aes128-ctr aes128-cbc \
+         cast128-cbc blowfish 3des-cbc ; do
+       verbose "$tid: cipher $c"
+       rm -f ${COPY}
+       # XXX the 2nd "cat" seems to be needed because of buggy FD handling
+       # in conch
+       ${CONCH} --identity $OBJ/rsa --port $PORT --user $USER  -e none \
+           --known-hosts $OBJ/known_hosts --notty --noagent --nox11 -n \
+           127.0.0.1 "cat ${DATA}" 2>/dev/null | cat > ${COPY}
+       if [ $? -ne 0 ]; then
+               fail "ssh cat $DATA failed"
+       fi
+       cmp ${DATA} ${COPY}             || fail "corrupted copy"
+done
+rm -f ${COPY}
+
diff --git a/regress/connect-privsep.sh b/regress/connect-privsep.sh
new file mode 100644 (file)
index 0000000..d23cadb
--- /dev/null
@@ -0,0 +1,13 @@
+#      $OpenBSD: connect-privsep.sh,v 1.1 2002/03/21 21:45:07 markus Exp $
+#      Placed in the Public Domain.
+
+tid="proxy connect with privsep"
+
+echo 'UsePrivilegeSeparation yes' >> $OBJ/sshd_proxy
+
+for p in 1 2; do
+       ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true
+       if [ $? -ne 0 ]; then
+               fail "ssh privsep+proxyconnect protocol $p failed"
+       fi
+done
diff --git a/regress/connect.sh b/regress/connect.sh
new file mode 100644 (file)
index 0000000..2186fa6
--- /dev/null
@@ -0,0 +1,13 @@
+#      $OpenBSD: connect.sh,v 1.4 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="simple connect"
+
+start_sshd
+
+for p in 1 2; do
+       ${SSH} -o "Protocol=$p" -F $OBJ/ssh_config somehost true
+       if [ $? -ne 0 ]; then
+               fail "ssh connect with protocol $p failed"
+       fi
+done
diff --git a/regress/dsa_ssh2.prv b/regress/dsa_ssh2.prv
new file mode 100644 (file)
index 0000000..c93b403
--- /dev/null
@@ -0,0 +1,14 @@
+---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
+Subject: ssh-keygen test
+Comment: "1024-bit dsa, Tue Jan 08 2002 22:00:23 +0100"
+P2/56wAAAgIAAAAmZGwtbW9kcHtzaWdue2RzYS1uaXN0LXNoYTF9LGRoe3BsYWlufX0AAA
+AEbm9uZQAAAcQAAAHAAAAAAAAABACwUfm3AxZTut3icBmwCcD48nY64HzuELlQ+vEqjIcR
+Lo49es/DQTeLNQ+kdKRCfouosGNv0WqxRtF0tUsWdXxS37oHGa4QPugBdHRd7YlZGZv8kg
+x7FsoepY7v7E683/97dv2zxL3AGagTEzWr7fl0yPexAaZoDvtQrrjX44BLmwAABACWQkvv
+MxnD8eFkS1konFfMJ1CkuRfTN34CBZ6dY7VTSGemy4QwtFdMKmoufD0eKgy3p5WOeWCYKt
+F4FhjHKZk/aaxFjjIbtkrnlvXg64QI11dSZyBN6/ViQkHPSkUDF+A6AAEhrNbQbAFSvao1
+kTvNtPCtL0AkUIduEMzGQfLCTAAAAKDeC043YVo9Zo0zAEeIA4uZh4LBCQAAA/9aj7Y5ik
+ehygJ4qTDSlVypsPuV+n59tMS0e2pfrSG87yf5r94AKBmJeho5OO6wYaXCxsVB7AFbSUD6
+75AK8mHF4v1/+7SWKk5f8xlMCMSPZ9K0+j/W1d/q2qkhnnDZolOHDomLA+U00i5ya/jnTV
+zyDPWLFpWK8u3xGBPAYX324gAAAKDHFvooRnaXdZbeWGTTqmgHB1GU9A==
+---- END SSH2 ENCRYPTED PRIVATE KEY ----
diff --git a/regress/dsa_ssh2.pub b/regress/dsa_ssh2.pub
new file mode 100644 (file)
index 0000000..215d73b
--- /dev/null
@@ -0,0 +1,13 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+Subject: ssh-keygen test
+Comment: "1024-bit dsa, Tue Jan 08 2002 22:00:23 +0100"
+AAAAB3NzaC1kc3MAAACBALBR+bcDFlO63eJwGbAJwPjydjrgfO4QuVD68SqMhxEujj16z8
+NBN4s1D6R0pEJ+i6iwY2/RarFG0XS1SxZ1fFLfugcZrhA+6AF0dF3tiVkZm/ySDHsWyh6l
+ju/sTrzf/3t2/bPEvcAZqBMTNavt+XTI97EBpmgO+1CuuNfjgEubAAAAFQDeC043YVo9Zo
+0zAEeIA4uZh4LBCQAAAIEAlkJL7zMZw/HhZEtZKJxXzCdQpLkX0zd+AgWenWO1U0hnpsuE
+MLRXTCpqLnw9HioMt6eVjnlgmCrReBYYxymZP2msRY4yG7ZK55b14OuECNdXUmcgTev1Yk
+JBz0pFAxfgOgABIazW0GwBUr2qNZE7zbTwrS9AJFCHbhDMxkHywkwAAACAWo+2OYpHocoC
+eKkw0pVcqbD7lfp+fbTEtHtqX60hvO8n+a/eACgZiXoaOTjusGGlwsbFQewBW0lA+u+QCv
+JhxeL9f/u0lipOX/MZTAjEj2fStPo/1tXf6tqpIZ5w2aJThw6JiwPlNNIucmv4501c8gz1
+ixaVivLt8RgTwGF99uI=
+---- END SSH2 PUBLIC KEY ----
diff --git a/regress/dynamic-forward.sh b/regress/dynamic-forward.sh
new file mode 100644 (file)
index 0000000..4674a7b
--- /dev/null
@@ -0,0 +1,50 @@
+#      $OpenBSD: dynamic-forward.sh,v 1.4 2004/06/22 22:55:56 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="dynamic forwarding"
+
+FWDPORT=`expr $PORT + 1`
+
+DATA=/bin/ls${EXEEXT}
+
+if have_prog nc && nc -h 2>&1 | grep "proxy address" >/dev/null; then
+       proxycmd="nc -x 127.0.0.1:$FWDPORT -X"
+elif have_prog connect; then
+       proxycmd="connect -S 127.0.0.1:$FWDPORT -"
+else
+       echo "skipped (no suitable ProxyCommand found)"
+       exit 0
+fi
+trace "will use ProxyCommand $proxycmd"
+
+start_sshd
+
+for p in 1 2; do
+       trace "start dynamic forwarding, fork to background"
+       ${SSH} -$p -F $OBJ/ssh_config -f -D $FWDPORT -q somehost \
+               exec sh -c \'"echo \$\$ > $OBJ/remote_pid; exec sleep 444"\'
+
+       for s in 4 5; do
+           for h in 127.0.0.1 localhost; do
+               trace "testing ssh protocol $p socks version $s host $h"
+               ${SSH} -F $OBJ/ssh_config \
+                       -o "ProxyCommand ${proxycmd}${s} $h $PORT" \
+                       somehost cat $DATA > $OBJ/ls.copy
+               test -f $OBJ/ls.copy     || fail "failed copy $DATA"
+               cmp $DATA $OBJ/ls.copy || fail "corrupted copy of $DATA"
+           done
+       done
+
+       if [ -f $OBJ/remote_pid ]; then
+               remote=`cat $OBJ/remote_pid`
+               trace "terminate remote shell, pid $remote"
+               if [ $remote -gt 1 ]; then
+                       kill -HUP $remote
+               fi
+       else
+               fail "no pid file: $OBJ/remote_pid"
+       fi
+
+       # Must allow time for connection tear-down
+       sleep 2
+done
diff --git a/regress/envpass.sh b/regress/envpass.sh
new file mode 100644 (file)
index 0000000..af7eafe
--- /dev/null
@@ -0,0 +1,60 @@
+#      $OpenBSD: envpass.sh,v 1.4 2005/03/04 08:48:46 djm Exp $
+#      Placed in the Public Domain.
+
+tid="environment passing"
+
+# NB accepted env vars are in test-exec.sh (_XXX_TEST_* and _XXX_TEST)
+
+# Prepare a custom config to test for a configuration parsing bug fixed in 4.0
+cat << EOF > $OBJ/ssh_proxy_envpass
+Host test-sendenv-confparse-bug
+       SendEnv *
+EOF
+cat $OBJ/ssh_proxy >> $OBJ/ssh_proxy_envpass
+
+trace "pass env, don't accept"
+verbose "test $tid: pass env, don't accept"
+_TEST_ENV=blah ${SSH} -oSendEnv="*" -F $OBJ/ssh_proxy_envpass otherhost \
+       sh << 'EOF'
+       test -z "$_TEST_ENV"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+       fail "environment found"
+fi
+
+trace "don't pass env, accept"
+verbose "test $tid: don't pass env, accept"
+_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -F $OBJ/ssh_proxy_envpass otherhost \
+       sh << 'EOF'
+       test -z "$_XXX_TEST_A" && test -z "$_XXX_TEST_B"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+       fail "environment found"
+fi
+
+trace "pass single env, accept single env"
+verbose "test $tid: pass single env, accept single env"
+_XXX_TEST=blah ${SSH} -oSendEnv="_XXX_TEST" -F $OBJ/ssh_proxy_envpass \
+    otherhost sh << 'EOF'
+       test X"$_XXX_TEST" = X"blah"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+       fail "environment not found"
+fi
+
+trace "pass multiple env, accept multiple env"
+verbose "test $tid: pass multiple env, accept multiple env"
+_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -oSendEnv="_XXX_TEST_*" \
+    -F $OBJ/ssh_proxy_envpass otherhost \
+       sh << 'EOF'
+       test X"$_XXX_TEST_A" = X"1" -a X"$_XXX_TEST_B" = X"2"
+EOF
+r=$?
+if [ $r -ne 0 ]; then
+       fail "environment not found"
+fi
+
+rm -f $OBJ/ssh_proxy_envpass
diff --git a/regress/exit-status.sh b/regress/exit-status.sh
new file mode 100644 (file)
index 0000000..56b78a6
--- /dev/null
@@ -0,0 +1,24 @@
+#      $OpenBSD: exit-status.sh,v 1.6 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="remote exit status"
+
+for p in 1 2; do
+       for s in 0 1 4 5 44; do
+               trace "proto $p status $s"
+               verbose "test $tid: proto $p status $s"
+               ${SSH} -$p -F $OBJ/ssh_proxy otherhost exit $s
+               r=$?
+               if [ $r -ne $s ]; then
+                       fail "exit code mismatch for protocol $p: $r != $s"
+               fi
+
+               # same with early close of stdout/err
+               ${SSH} -$p -F $OBJ/ssh_proxy -n otherhost \
+                       exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\'
+               r=$?
+               if [ $r -ne $s ]; then
+                       fail "exit code (with sleep) mismatch for protocol $p: $r != $s"
+               fi
+       done
+done
diff --git a/regress/forcecommand.sh b/regress/forcecommand.sh
new file mode 100644 (file)
index 0000000..99e51a6
--- /dev/null
@@ -0,0 +1,42 @@
+#      $OpenBSD: forcecommand.sh,v 1.1 2006/07/19 13:09:28 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="forced command"
+
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+
+echon 'command="true" ' >$OBJ/authorized_keys_$USER
+cat $OBJ/rsa.pub >> $OBJ/authorized_keys_$USER
+echon 'command="true" ' >>$OBJ/authorized_keys_$USER
+cat $OBJ/rsa1.pub >> $OBJ/authorized_keys_$USER
+
+for p in 1 2; do
+       trace "forced command in key option proto $p"
+       ${SSH} -$p -F $OBJ/ssh_proxy somehost false \ ||
+           fail "forced command in key proto $p"
+done
+
+echon 'command="false" ' >$OBJ/authorized_keys_$USER
+cat $OBJ/rsa.pub >> $OBJ/authorized_keys_$USER
+echon 'command="false" ' >>$OBJ/authorized_keys_$USER
+cat $OBJ/rsa1.pub >> $OBJ/authorized_keys_$USER
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "ForceCommand true" >> $OBJ/sshd_proxy
+
+for p in 1 2; do
+       trace "forced command in sshd_config overrides key option proto $p"
+       ${SSH} -$p -F $OBJ/ssh_proxy somehost false \ ||
+           fail "forced command in key proto $p"
+done
+
+cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
+echo "ForceCommand false" >> $OBJ/sshd_proxy
+echo "Match User $USER" >> $OBJ/sshd_proxy
+echo "    ForceCommand true" >> $OBJ/sshd_proxy
+
+for p in 1 2; do
+       trace "forced command with match proto $p"
+       ${SSH} -$p -F $OBJ/ssh_proxy somehost false \ ||
+           fail "forced command in key proto $p"
+done
diff --git a/regress/forwarding.sh b/regress/forwarding.sh
new file mode 100644 (file)
index 0000000..6dec991
--- /dev/null
@@ -0,0 +1,105 @@
+#      $OpenBSD: forwarding.sh,v 1.7 2010/01/11 02:53:44 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="local and remote forwarding"
+DATA=/bin/ls${EXEEXT}
+
+start_sshd
+
+base=33
+last=$PORT
+fwd=""
+for j in 0 1 2; do
+       for i in 0 1 2; do
+               a=$base$j$i
+               b=`expr $a + 50`
+               c=$last
+               # fwd chain: $a -> $b -> $c
+               fwd="$fwd -L$a:127.0.0.1:$b -R$b:127.0.0.1:$c"
+               last=$a
+       done
+done
+for p in 1 2; do
+       q=`expr 3 - $p`
+       trace "start forwarding, fork to background"
+       ${SSH} -$p -F $OBJ/ssh_config -f $fwd somehost sleep 10
+
+       trace "transfer over forwarded channels and check result"
+       ${SSH} -$q -F $OBJ/ssh_config -p$last -o 'ConnectionAttempts=4' \
+               somehost cat $DATA > $OBJ/ls.copy
+       test -f $OBJ/ls.copy                    || fail "failed copy $DATA"
+       cmp $DATA $OBJ/ls.copy                  || fail "corrupted copy of $DATA"
+
+       sleep 10
+done
+
+for p in 1 2; do
+for d in L R; do
+       trace "exit on -$d forward failure, proto $p"
+
+       # this one should succeed
+       ${SSH} -$p -F $OBJ/ssh_config \
+           -$d ${base}01:127.0.0.1:$PORT \
+           -$d ${base}02:127.0.0.1:$PORT \
+           -$d ${base}03:127.0.0.1:$PORT \
+           -$d ${base}04:127.0.0.1:$PORT \
+           -oExitOnForwardFailure=yes somehost true
+       if [ $? != 0 ]; then
+               fail "connection failed, should not"
+       else
+               # this one should fail
+               ${SSH} -q -$p -F $OBJ/ssh_config \
+                   -$d ${base}01:127.0.0.1:$PORT \
+                   -$d ${base}02:127.0.0.1:$PORT \
+                   -$d ${base}03:127.0.0.1:$PORT \
+                   -$d ${base}01:127.0.0.1:$PORT \
+                   -$d ${base}04:127.0.0.1:$PORT \
+                   -oExitOnForwardFailure=yes somehost true
+               r=$?
+               if [ $r != 255 ]; then
+                       fail "connection not termintated, but should ($r)"
+               fi
+       fi
+done
+done
+
+for p in 1 2; do
+       trace "simple clear forwarding proto $p"
+       ${SSH} -$p -F $OBJ/ssh_config -oClearAllForwardings=yes somehost true
+
+       trace "clear local forward proto $p"
+       ${SSH} -$p -f -F $OBJ/ssh_config -L ${base}01:127.0.0.1:$PORT \
+           -oClearAllForwardings=yes somehost sleep 10
+       if [ $? != 0 ]; then
+               fail "connection failed with cleared local forwarding"
+       else
+               # this one should fail
+               ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 true \
+                    2>${TEST_SSH_LOGFILE} && \
+                       fail "local forwarding not cleared"
+       fi
+       sleep 10
+       
+       trace "clear remote forward proto $p"
+       ${SSH} -$p -f -F $OBJ/ssh_config -R ${base}01:127.0.0.1:$PORT \
+           -oClearAllForwardings=yes somehost sleep 10
+       if [ $? != 0 ]; then
+               fail "connection failed with cleared remote forwarding"
+       else
+               # this one should fail
+               ${SSH} -$p -F $OBJ/ssh_config -p ${base}01 true \
+                    2>${TEST_SSH_LOGFILE} && \
+                       fail "remote forwarding not cleared"
+       fi
+       sleep 10
+done
+
+for p in 2; do
+       trace "stdio forwarding proto $p"
+       cmd="${SSH} -$p -F $OBJ/ssh_config"
+       $cmd -o "ProxyCommand $cmd -q -W localhost:$PORT somehost" \
+               somehost true
+       if [ $? != 0 ]; then
+               fail "stdio forwarding proto $p"
+       fi
+done
diff --git a/regress/host-expand.sh b/regress/host-expand.sh
new file mode 100644 (file)
index 0000000..a018836
--- /dev/null
@@ -0,0 +1,18 @@
+#      Placed in the Public Domain.
+
+tid="expand %h and %n"
+
+echo 'PermitLocalCommand yes' >> $OBJ/ssh_proxy
+printf 'LocalCommand printf "%%%%s\\n" "%%n" "%%h"\n' >> $OBJ/ssh_proxy
+
+cat >$OBJ/expect <<EOE
+somehost
+127.0.0.1
+EOE
+
+for p in 1 2; do
+       verbose "test $tid: proto $p"
+       ${SSH} -F $OBJ/ssh_proxy -$p somehost true >$OBJ/actual
+       diff $OBJ/expect $OBJ/actual || fail "$tid proto $p"
+done
+
diff --git a/regress/kextype.sh b/regress/kextype.sh
new file mode 100644 (file)
index 0000000..79c0817
--- /dev/null
@@ -0,0 +1,30 @@
+#      $OpenBSD: kextype.sh,v 1.1 2010/09/22 12:26:05 djm Exp $
+#      Placed in the Public Domain.
+
+tid="login with different key exchange algorithms"
+
+TIME=/usr/bin/time
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
+
+if test "$TEST_SSH_ECC" = "yes"; then
+       kextypes="ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521"
+fi
+if test "$TEST_SSH_SHA256" = "yes"; then
+       kextypes="$kextypes diffie-hellman-group-exchange-sha256"
+fi
+kextypes="$kextypes diffie-hellman-group-exchange-sha1"
+kextypes="$kextypes diffie-hellman-group14-sha1"
+kextypes="$kextypes diffie-hellman-group1-sha1"
+
+tries="1 2 3 4"
+for k in $kextypes; do 
+       verbose "kex $k"
+       for i in $tries; do
+               ${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true
+               if [ $? -ne 0 ]; then
+                       fail "ssh kex $k"
+               fi
+       done
+done
+
diff --git a/regress/key-options.sh b/regress/key-options.sh
new file mode 100644 (file)
index 0000000..f98d78b
--- /dev/null
@@ -0,0 +1,71 @@
+#      $OpenBSD: key-options.sh,v 1.2 2008/06/30 08:07:34 djm Exp $
+#      Placed in the Public Domain.
+
+tid="key options"
+
+origkeys="$OBJ/authkeys_orig"
+authkeys="$OBJ/authorized_keys_${USER}"
+cp $authkeys $origkeys
+
+# Test command= forced command
+for p in 1 2; do
+    for c in 'command="echo bar"' 'no-pty,command="echo bar"'; do
+       sed "s/.*/$c &/" $origkeys >$authkeys
+       verbose "key option proto $p $c"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost echo foo`
+       if [ "$r" = "foo" ]; then
+               fail "key option forced command not restricted"
+       fi
+       if [ "$r" != "bar" ]; then
+               fail "key option forced command not executed"
+       fi
+    done
+done
+
+# Test no-pty
+sed 's/.*/no-pty &/' $origkeys >$authkeys
+for p in 1 2; do
+       verbose "key option proto $p no-pty"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost tty`
+       if [ -f "$r" ]; then
+               fail "key option failed proto $p no-pty (pty $r)"
+       fi
+done
+
+# Test environment=
+echo 'PermitUserEnvironment yes' >> $OBJ/sshd_proxy
+sed 's/.*/environment="FOO=bar" &/' $origkeys >$authkeys
+for p in 1 2; do
+       verbose "key option proto $p environment"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost 'echo $FOO'`
+       if [ "$r" != "bar" ]; then
+               fail "key option environment not set"
+       fi
+done
+
+# Test from= restriction
+start_sshd
+for p in 1 2; do
+    for f in 127.0.0.1 '127.0.0.0\/8'; do
+       cat  $origkeys >$authkeys
+       ${SSH} -$p -q -F $OBJ/ssh_proxy somehost true
+       if [ $? -ne 0 ]; then
+               fail "key option proto $p failed without restriction"
+       fi
+
+       sed 's/.*/from="'"$f"'" &/' $origkeys >$authkeys
+       from=`head -1 $authkeys | cut -f1 -d ' '`
+       verbose "key option proto $p $from"
+       r=`${SSH} -$p -q -F $OBJ/ssh_proxy somehost 'echo true'`
+       if [ "$r" = "true" ]; then
+               fail "key option proto $p $from not restricted"
+       fi
+
+       r=`${SSH} -$p -q -F $OBJ/ssh_config somehost 'echo true'`
+       if [ "$r" != "true" ]; then
+               fail "key option proto $p $from not allowed but should be"
+       fi
+    done
+done
+
+rm -f "$origkeys"
diff --git a/regress/keygen-change.sh b/regress/keygen-change.sh
new file mode 100644 (file)
index 0000000..08d3590
--- /dev/null
@@ -0,0 +1,23 @@
+#      $OpenBSD: keygen-change.sh,v 1.2 2002/07/16 09:15:55 markus Exp $
+#      Placed in the Public Domain.
+
+tid="change passphrase for key"
+
+S1="secret1"
+S2="2secret"
+
+for t in rsa dsa rsa1; do
+       # generate user key for agent
+       trace "generating $t key"
+       rm -f $OBJ/$t-key
+       ${SSHKEYGEN} -q -N ${S1} -t $t -f $OBJ/$t-key
+       if [ $? -eq 0 ]; then
+               ${SSHKEYGEN} -p -P ${S1} -N ${S2} -f $OBJ/$t-key > /dev/null
+               if [ $? -ne 0 ]; then
+                       fail "ssh-keygen -p failed for $t-key"
+               fi
+       else
+               fail "ssh-keygen for $t-key failed"
+       fi
+       rm -f $OBJ/$t-key $OBJ/$t-key.pub
+done
diff --git a/regress/keygen-convert.sh b/regress/keygen-convert.sh
new file mode 100644 (file)
index 0000000..ad0e9c6
--- /dev/null
@@ -0,0 +1,33 @@
+#      $OpenBSD: keygen-convert.sh,v 1.1 2009/11/09 04:20:04 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="convert keys"
+
+for t in rsa dsa; do
+       # generate user key for agent
+       trace "generating $t key"
+       rm -f $OBJ/$t-key
+       ${SSHKEYGEN} -q -N "" -t $t -f $OBJ/$t-key
+
+       trace "export $t private to rfc4716 public"
+       ${SSHKEYGEN} -q -e -f $OBJ/$t-key >$OBJ/$t-key-rfc || \
+           fail "export $t private to rfc4716 public"
+
+       trace "export $t public to rfc4716 public"
+       ${SSHKEYGEN} -q -e -f $OBJ/$t-key.pub >$OBJ/$t-key-rfc.pub || \
+           fail "$t public to rfc4716 public"
+
+       cmp $OBJ/$t-key-rfc $OBJ/$t-key-rfc.pub || \
+           fail "$t rfc4716 exports differ between public and private"
+
+       trace "import $t rfc4716 public"
+       ${SSHKEYGEN} -q -i -f $OBJ/$t-key-rfc >$OBJ/$t-rfc-imported || \
+           fail "$t import rfc4716 public"
+
+       cut -f1,2 -d " " $OBJ/$t-key.pub >$OBJ/$t-key-nocomment.pub
+       cmp $OBJ/$t-key-nocomment.pub $OBJ/$t-rfc-imported || \
+           fail "$t imported differs from original"
+
+       rm -f $OBJ/$t-key $OBJ/$t-key.pub $OBJ/$t-key-rfc $OBJ/$t-key-rfc.pub \
+           $OBJ/$t-rfc-imported $OBJ/$t-key-nocomment.pub
+done
diff --git a/regress/keyscan.sh b/regress/keyscan.sh
new file mode 100644 (file)
index 0000000..33f14f0
--- /dev/null
@@ -0,0 +1,19 @@
+#      $OpenBSD: keyscan.sh,v 1.3 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="keyscan"
+
+# remove DSA hostkey
+rm -f ${OBJ}/host.dsa
+
+start_sshd
+
+for t in rsa1 rsa dsa; do
+       trace "keyscan type $t"
+       ${SSHKEYSCAN} -t $t -p $PORT 127.0.0.1 127.0.0.1 127.0.0.1 \
+               > /dev/null 2>&1
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh-keyscan -t $t failed with: $r"
+       fi
+done
diff --git a/regress/keytype.sh b/regress/keytype.sh
new file mode 100644 (file)
index 0000000..2cbf132
--- /dev/null
@@ -0,0 +1,55 @@
+#      $OpenBSD: keytype.sh,v 1.1 2010/09/02 16:12:55 markus Exp $
+#      Placed in the Public Domain.
+
+tid="login with different key types"
+
+TIME=`which time` 2>/dev/null
+if test ! -x "$TIME"; then
+       TIME=""
+fi
+
+cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
+cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak
+
+ktypes="dsa-1024 rsa-2048 rsa-3072"
+if test "$TEST_SSH_ECC" = "yes"; then
+       ktypes="$ktypes ecdsa-256 ecdsa-384 ecdsa-521"
+fi
+
+for kt in $ktypes; do 
+       rm -f $OBJ/key.$kt
+       bits=`echo ${kt} | awk -F- '{print $2}'`
+       type=`echo ${kt}  | awk -F- '{print $1}'`
+       printf "keygen $type, $bits bits:\t"
+       ${TIME} ${SSHKEYGEN} -b $bits -q -N '' -t $type  -f $OBJ/key.$kt ||\
+               fail "ssh-keygen for type $type, $bits bits failed"
+done
+
+tries="1 2 3"
+for ut in $ktypes; do 
+       htypes=$ut
+       #htypes=$ktypes
+       for ht in $htypes; do 
+               trace "ssh connect, userkey $ut, hostkey $ht"
+               (
+                       grep -v HostKey $OBJ/sshd_proxy_bak
+                       echo HostKey $OBJ/key.$ht 
+               ) > $OBJ/sshd_proxy
+               (
+                       grep -v IdentityFile $OBJ/ssh_proxy_bak
+                       echo IdentityFile $OBJ/key.$ut 
+               ) > $OBJ/ssh_proxy
+               (
+                       echon 'localhost-with-alias,127.0.0.1,::1 '
+                       cat $OBJ/key.$ht.pub
+               ) > $OBJ/known_hosts
+               cat $OBJ/key.$ut.pub > $OBJ/authorized_keys_$USER
+               for i in $tries; do
+                       printf "userkey $ut, hostkey ${ht}:\t"
+                       ${TIME} ${SSH} -F $OBJ/ssh_proxy 999.999.999.999 true
+                       if [ $? -ne 0 ]; then
+                               fail "ssh userkey $ut, hostkey $ht failed"
+                       fi
+               done
+       done
+done
diff --git a/regress/localcommand.sh b/regress/localcommand.sh
new file mode 100644 (file)
index 0000000..feade7a
--- /dev/null
@@ -0,0 +1,15 @@
+#      $OpenBSD: localcommand.sh,v 1.1 2007/10/29 06:57:13 dtucker Exp $
+#      Placed in the Public Domain.
+
+tid="localcommand"
+
+echo 'PermitLocalCommand yes' >> $OBJ/ssh_proxy
+echo 'LocalCommand echo foo' >> $OBJ/ssh_proxy
+
+for p in 1 2; do
+       verbose "test $tid: proto $p localcommand"
+       a=`${SSH} -F $OBJ/ssh_proxy -$p somehost true`
+       if [ "$a" != "foo" ] ; then
+               fail "$tid proto $p"
+       fi
+done
diff --git a/regress/login-timeout.sh b/regress/login-timeout.sh
new file mode 100644 (file)
index 0000000..55fbb32
--- /dev/null
@@ -0,0 +1,29 @@
+#      $OpenBSD: login-timeout.sh,v 1.4 2005/02/27 23:13:36 djm Exp $
+#      Placed in the Public Domain.
+
+tid="connect after login grace timeout"
+
+trace "test login grace with privsep"
+echo "LoginGraceTime 10s" >> $OBJ/sshd_config
+echo "MaxStartups 1" >> $OBJ/sshd_config
+start_sshd
+
+(echo SSH-2.0-fake; sleep 60) | telnet 127.0.0.1 ${PORT} >/dev/null 2>&1 & 
+sleep 15
+${SSH} -F $OBJ/ssh_config somehost true
+if [ $? -ne 0 ]; then
+       fail "ssh connect after login grace timeout failed with privsep"
+fi
+
+$SUDO kill `$SUDO cat $PIDFILE`
+
+trace "test login grace without privsep"
+echo "UsePrivilegeSeparation no" >> $OBJ/sshd_config
+start_sshd
+
+(echo SSH-2.0-fake; sleep 60) | telnet 127.0.0.1 ${PORT} >/dev/null 2>&1 & 
+sleep 15
+${SSH} -F $OBJ/ssh_config somehost true
+if [ $? -ne 0 ]; then
+       fail "ssh connect after login grace timeout failed without privsep"
+fi
diff --git a/regress/multiplex.sh b/regress/multiplex.sh
new file mode 100644 (file)
index 0000000..b94cdf0
--- /dev/null
@@ -0,0 +1,91 @@
+#      $OpenBSD: multiplex.sh,v 1.12 2009/05/05 07:51:36 dtucker Exp $
+#      Placed in the Public Domain.
+
+CTL=/tmp/openssh.regress.ctl-sock.$$
+
+tid="connection multiplexing"
+
+if config_defined DISABLE_FD_PASSING ; then
+       echo "skipped (not supported on this platform)"
+       exit 0
+fi
+
+DATA=/bin/ls${EXEEXT}
+COPY=$OBJ/ls.copy
+LOG=$TEST_SSH_LOGFILE
+
+start_sshd
+
+trace "start master, fork to background"
+${SSH} -Nn2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" somehost &
+MASTER_PID=$!
+
+# Wait for master to start and authenticate
+sleep 5
+
+verbose "test $tid: envpass"
+trace "env passing over multiplexed connection"
+_XXX_TEST=blah ${SSH} -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" -S$CTL otherhost sh << 'EOF'
+       test X"$_XXX_TEST" = X"blah"
+EOF
+if [ $? -ne 0 ]; then
+       fail "environment not found"
+fi
+
+verbose "test $tid: transfer"
+rm -f ${COPY}
+trace "ssh transfer over multiplexed connection and check result"
+${SSH} -F $OBJ/ssh_config -S$CTL otherhost cat ${DATA} > ${COPY}
+test -f ${COPY}                        || fail "ssh -Sctl: failed copy ${DATA}" 
+cmp ${DATA} ${COPY}            || fail "ssh -Sctl: corrupted copy of ${DATA}"
+
+rm -f ${COPY}
+trace "ssh transfer over multiplexed connection and check result"
+${SSH} -F $OBJ/ssh_config -S $CTL otherhost cat ${DATA} > ${COPY}
+test -f ${COPY}                        || fail "ssh -S ctl: failed copy ${DATA}" 
+cmp ${DATA} ${COPY}            || fail "ssh -S ctl: corrupted copy of ${DATA}"
+
+rm -f ${COPY}
+trace "sftp transfer over multiplexed connection and check result"
+echo "get ${DATA} ${COPY}" | \
+       ${SFTP} -S ${SSH} -F $OBJ/ssh_config -oControlPath=$CTL otherhost >$LOG 2>&1
+test -f ${COPY}                        || fail "sftp: failed copy ${DATA}" 
+cmp ${DATA} ${COPY}            || fail "sftp: corrupted copy of ${DATA}"
+
+rm -f ${COPY}
+trace "scp transfer over multiplexed connection and check result"
+${SCP} -S ${SSH} -F $OBJ/ssh_config -oControlPath=$CTL otherhost:${DATA} ${COPY} >$LOG 2>&1
+test -f ${COPY}                        || fail "scp: failed copy ${DATA}" 
+cmp ${DATA} ${COPY}            || fail "scp: corrupted copy of ${DATA}"
+
+rm -f ${COPY}
+
+for s in 0 1 4 5 44; do
+       trace "exit status $s over multiplexed connection"
+       verbose "test $tid: status $s"
+       ${SSH} -F $OBJ/ssh_config -S $CTL otherhost exit $s
+       r=$?
+       if [ $r -ne $s ]; then
+               fail "exit code mismatch for protocol $p: $r != $s"
+       fi
+
+       # same with early close of stdout/err
+       trace "exit status $s with early close over multiplexed connection"
+       ${SSH} -F $OBJ/ssh_config -S $CTL -n otherhost \
+                exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\'
+       r=$?
+       if [ $r -ne $s ]; then
+               fail "exit code (with sleep) mismatch for protocol $p: $r != $s"
+       fi
+done
+
+trace "test check command"
+${SSH} -F $OBJ/ssh_config -S $CTL -Ocheck otherhost || fail "check command failed" 
+
+trace "test exit command"
+${SSH} -F $OBJ/ssh_config -S $CTL -Oexit otherhost || fail "send exit command failed" 
+
+# Wait for master to exit
+sleep 2
+
+kill -0 $MASTER_PID >/dev/null 2>&1 && fail "exit command failed" 
diff --git a/regress/portnum.sh b/regress/portnum.sh
new file mode 100644 (file)
index 0000000..1de0680
--- /dev/null
@@ -0,0 +1,34 @@
+#      $OpenBSD: portnum.sh,v 1.1 2009/08/13 00:57:17 djm Exp $
+#      Placed in the Public Domain.
+
+tid="port number parsing"
+
+badport() {
+       port=$1
+       verbose "$tid: invalid port $port"
+       if ${SSH} -F $OBJ/ssh_proxy -p $port somehost true 2>/dev/null ; then
+               fail "$tid accepted invalid port $port"
+       fi
+}
+goodport() {
+       port=$1
+       verbose "$tid: valid port $port"
+       if ${SSH} -F $OBJ/ssh_proxy -p $port somehost true 2>/dev/null ; then
+               :
+       else
+               fail "$tid rejected valid port $port"
+       fi
+}
+
+badport 0
+badport 65536
+badport 131073
+badport 2000blah
+badport blah2000
+
+goodport 1
+goodport 22
+goodport 2222
+goodport 22222
+goodport 65535
+
diff --git a/regress/proto-mismatch.sh b/regress/proto-mismatch.sh
new file mode 100644 (file)
index 0000000..fb521f2
--- /dev/null
@@ -0,0 +1,19 @@
+#      $OpenBSD: proto-mismatch.sh,v 1.3 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="protocol version mismatch"
+
+mismatch ()
+{
+       server=$1
+       client=$2
+       banner=`echo ${client} | ${SSHD} -o "Protocol=${server}" -i -f ${OBJ}/sshd_proxy`
+       r=$?
+       trace "sshd prints ${banner}"
+       if [ $r -ne 255 ]; then
+               fail "sshd prints ${banner} and accepts connect with version ${client}"
+       fi
+}
+
+mismatch       2       SSH-1.5-HALLO
+mismatch       1       SSH-2.0-HALLO
diff --git a/regress/proto-version.sh b/regress/proto-version.sh
new file mode 100644 (file)
index 0000000..1651a69
--- /dev/null
@@ -0,0 +1,34 @@
+#      $OpenBSD: proto-version.sh,v 1.3 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="sshd version with different protocol combinations"
+
+# we just start sshd in inetd mode and check the banner
+check_version ()
+{
+       version=$1
+       expect=$2
+       banner=`echon | ${SSHD} -o "Protocol=${version}" -i -f ${OBJ}/sshd_proxy`
+       case ${banner} in
+       SSH-1.99-*)
+               proto=199
+               ;;
+       SSH-2.0-*)
+               proto=20
+               ;;
+       SSH-1.5-*)
+               proto=15
+               ;;
+       *)
+               proto=0
+               ;;
+       esac
+       if [ ${expect} -ne ${proto} ]; then
+               fail "wrong protocol version ${banner} for ${version}"
+       fi
+}
+
+check_version  2,1     199
+check_version  1,2     199
+check_version  2       20
+check_version  1       15
diff --git a/regress/proxy-connect.sh b/regress/proxy-connect.sh
new file mode 100644 (file)
index 0000000..6a36b25
--- /dev/null
@@ -0,0 +1,18 @@
+#      $OpenBSD: proxy-connect.sh,v 1.5 2002/12/09 15:28:46 markus Exp $
+#      Placed in the Public Domain.
+
+tid="proxy connect"
+
+for p in 1 2; do
+       ${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 true
+       if [ $? -ne 0 ]; then
+               fail "ssh proxyconnect protocol $p failed"
+       fi
+       SSH_CONNECTION=`${SSH} -$p -F $OBJ/ssh_proxy 999.999.999.999 'echo $SSH_CONNECTION'`
+       if [ $? -ne 0 ]; then
+               fail "ssh proxyconnect protocol $p failed"
+       fi
+       if [ "$SSH_CONNECTION" != "UNKNOWN 65535 UNKNOWN 65535" ]; then
+               fail "bad SSH_CONNECTION"
+       fi
+done
diff --git a/regress/putty-ciphers.sh b/regress/putty-ciphers.sh
new file mode 100644 (file)
index 0000000..928ea60
--- /dev/null
@@ -0,0 +1,29 @@
+#      $OpenBSD: putty-ciphers.sh,v 1.3 2008/11/10 02:06:35 djm Exp $
+#      Placed in the Public Domain.
+
+tid="putty ciphers"
+
+DATA=/bin/ls
+COPY=${OBJ}/copy
+
+if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
+       echo "putty interop tests not enabled"
+       exit 0
+fi
+
+for c in aes blowfish 3des arcfour aes128-ctr aes192-ctr aes256-ctr ; do
+       verbose "$tid: cipher $c"
+       cp ${OBJ}/.putty/sessions/localhost_proxy \
+           ${OBJ}/.putty/sessions/cipher_$c
+       echo "Cipher=$c" >> ${OBJ}/.putty/sessions/cipher_$c
+
+       rm -f ${COPY}
+       env HOME=$PWD ${PLINK} -load cipher_$c -batch -i putty.rsa2 \
+           127.0.0.1 cat ${DATA} > ${COPY}
+       if [ $? -ne 0 ]; then
+               fail "ssh cat $DATA failed"
+       fi
+       cmp ${DATA} ${COPY}             || fail "corrupted copy"
+done
+rm -f ${COPY}
+
diff --git a/regress/putty-kex.sh b/regress/putty-kex.sh
new file mode 100644 (file)
index 0000000..293885a
--- /dev/null
@@ -0,0 +1,26 @@
+#      $OpenBSD: putty-kex.sh,v 1.2 2008/06/30 10:31:11 djm Exp $
+#      Placed in the Public Domain.
+
+tid="putty KEX"
+
+DATA=/bin/ls
+COPY=${OBJ}/copy
+
+if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
+       echo "putty interop tests not enabled"
+       exit 0
+fi
+
+for k in dh-gex-sha1 dh-group1-sha1 dh-group14-sha1 ; do
+       verbose "$tid: kex $k"
+       cp ${OBJ}/.putty/sessions/localhost_proxy \
+           ${OBJ}/.putty/sessions/kex_$k
+       echo "KEX=$k" >> ${OBJ}/.putty/sessions/kex_$k
+
+       env HOME=$PWD ${PLINK} -load kex_$k -batch -i putty.rsa2 \
+           127.0.0.1 true
+       if [ $? -ne 0 ]; then
+               fail "KEX $k failed"
+       fi
+done
+
diff --git a/regress/putty-transfer.sh b/regress/putty-transfer.sh
new file mode 100644 (file)
index 0000000..9e1e155
--- /dev/null
@@ -0,0 +1,44 @@
+#      $OpenBSD: putty-transfer.sh,v 1.2 2008/06/30 10:31:11 djm Exp $
+#      Placed in the Public Domain.
+
+tid="putty transfer data"
+
+DATA=/bin/ls
+COPY=${OBJ}/copy
+
+if test "x$REGRESS_INTEROP_PUTTY" != "xyes" ; then
+       echo "putty interop tests not enabled"
+       exit 0
+fi
+
+# XXX support protocol 1 too
+for p in 2; do
+       for c in 0 1 ; do 
+       verbose "$tid: proto $p compression $c"
+               rm -f ${COPY}
+               cp ${OBJ}/.putty/sessions/localhost_proxy \
+                   ${OBJ}/.putty/sessions/compression_$c
+               echo "Compression=$c" >> ${OBJ}/.putty/sessions/kex_$k
+               env HOME=$PWD ${PLINK} -load compression_$c -batch \
+                   -i putty.rsa$p 127.0.0.1 cat ${DATA} > ${COPY}
+               if [ $? -ne 0 ]; then
+                       fail "ssh cat $DATA failed"
+               fi
+               cmp ${DATA} ${COPY}             || fail "corrupted copy"
+       
+               for s in 10 100 1k 32k 64k 128k 256k; do
+                       trace "proto $p compression $c dd-size ${s}"
+                       rm -f ${COPY}
+                       dd if=$DATA obs=${s} 2> /dev/null | \
+                               env HOME=$PWD ${PLINK} -load compression_$c \
+                                   -batch -i putty.rsa$p 127.0.0.1 \
+                                   "cat > ${COPY}"
+                       if [ $? -ne 0 ]; then
+                               fail "ssh cat $DATA failed"
+                       fi
+                       cmp $DATA ${COPY}       || fail "corrupted copy"
+               done
+       done
+done
+rm -f ${COPY}
+
diff --git a/regress/reconfigure.sh b/regress/reconfigure.sh
new file mode 100644 (file)
index 0000000..9fd2895
--- /dev/null
@@ -0,0 +1,36 @@
+#      $OpenBSD: reconfigure.sh,v 1.2 2003/06/21 09:14:05 markus Exp $
+#      Placed in the Public Domain.
+
+tid="simple connect after reconfigure"
+
+# we need the full path to sshd for -HUP
+case $SSHD in
+/*)
+       # full path is OK 
+       ;;
+*)
+       # otherwise make fully qualified
+       SSHD=$OBJ/$SSHD
+esac
+
+start_sshd
+
+PID=`$SUDO cat $PIDFILE`
+rm -f $PIDFILE
+$SUDO kill -HUP $PID
+
+trace "wait for sshd to restart"
+i=0;
+while [ ! -f $PIDFILE -a $i -lt 10 ]; do
+       i=`expr $i + 1`
+       sleep $i
+done
+
+test -f $PIDFILE || fatal "sshd did not restart"
+
+for p in 1 2; do
+       ${SSH} -o "Protocol=$p" -F $OBJ/ssh_config somehost true
+       if [ $? -ne 0 ]; then
+               fail "ssh connect with protocol $p failed after reconfigure"
+       fi
+done
diff --git a/regress/reexec.sh b/regress/reexec.sh
new file mode 100644 (file)
index 0000000..6edfc31
--- /dev/null
@@ -0,0 +1,72 @@
+#      $OpenBSD: reexec.sh,v 1.5 2004/10/08 02:01:50 djm Exp $
+#      Placed in the Public Domain.
+
+tid="reexec tests"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+SSHD_ORIG=$SSHD${EXEEXT}
+SSHD_COPY=$OBJ/sshd${EXEEXT}
+
+# Start a sshd and then delete it
+start_sshd_copy ()
+{
+       cp $SSHD_ORIG $SSHD_COPY
+       SSHD=$SSHD_COPY
+       start_sshd
+       SSHD=$SSHD_ORIG
+}
+
+# Do basic copy tests
+copy_tests ()
+{
+       rm -f ${COPY}
+       for p in 1 2; do
+               verbose "$tid: proto $p"
+               ${SSH} -nqo "Protocol=$p" -F $OBJ/ssh_config somehost \
+                   cat ${DATA} > ${COPY}
+               if [ $? -ne 0 ]; then
+                       fail "ssh cat $DATA failed"
+               fi
+               cmp ${DATA} ${COPY}             || fail "corrupted copy"
+               rm -f ${COPY}
+       done
+}
+
+verbose "test config passing"
+
+cp $OBJ/sshd_config $OBJ/sshd_config.orig
+start_sshd
+echo "InvalidXXX=no" >> $OBJ/sshd_config
+
+copy_tests
+
+$SUDO kill `$SUDO cat $PIDFILE`
+rm -f $PIDFILE
+
+cp $OBJ/sshd_config.orig $OBJ/sshd_config
+
+verbose "test reexec fallback"
+
+start_sshd_copy
+rm -f $SSHD_COPY
+
+copy_tests
+
+$SUDO kill `$SUDO cat $PIDFILE`
+rm -f $PIDFILE
+
+verbose "test reexec fallback without privsep"
+
+cp $OBJ/sshd_config.orig $OBJ/sshd_config
+echo "UsePrivilegeSeparation=no" >> $OBJ/sshd_config
+
+start_sshd_copy
+rm -f $SSHD_COPY
+
+copy_tests
+
+$SUDO kill `$SUDO cat $PIDFILE`
+rm -f $PIDFILE
+
+
diff --git a/regress/rekey.sh b/regress/rekey.sh
new file mode 100644 (file)
index 0000000..3c5f266
--- /dev/null
@@ -0,0 +1,32 @@
+#      $OpenBSD: rekey.sh,v 1.1 2003/03/28 13:58:28 markus Exp $
+#      Placed in the Public Domain.
+
+tid="rekey during transfer data"
+
+DATA=${OBJ}/data
+COPY=${OBJ}/copy
+LOG=${OBJ}/log
+
+rm -f ${COPY} ${LOG} ${DATA}
+touch ${DATA}
+dd if=/bin/ls${EXEEXT} of=${DATA} bs=1k seek=511 count=1 > /dev/null 2>&1
+
+for s in 16 1k 128k 256k; do
+       trace "rekeylimit ${s}"
+       rm -f ${COPY}
+       cat $DATA | \
+               ${SSH} -oCompression=no -oRekeyLimit=$s \
+                       -v -F $OBJ/ssh_proxy somehost "cat > ${COPY}" \
+               2> ${LOG}
+       if [ $? -ne 0 ]; then
+               fail "ssh failed"
+       fi
+       cmp $DATA ${COPY}               || fail "corrupted copy"
+       n=`grep 'NEWKEYS sent' ${LOG} | wc -l`
+       n=`expr $n - 1`
+       trace "$n rekeying(s)"
+       if [ $n -lt 1 ]; then
+               fail "no rekeying occured"
+       fi
+done
+rm -f ${COPY} ${LOG} ${DATA}
diff --git a/regress/rsa_openssh.prv b/regress/rsa_openssh.prv
new file mode 100644 (file)
index 0000000..2675555
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWgIBAAKBgQDsilwKcaKN6wSMNd1WgQ9+HRqQEkD0kCTVttrazGu0OhBU3Uko
++dFD1Ip0CxdXmN25JQWxOYF7h/Ocu8P3jzv3RTX87xKR0YzlXTLX+SLtF/ySebS3
+xWPrlfRUDhh03hR5V+8xxvvy9widPYKw/oItwGSueOsEq1LTczCDv2dAjQIDAQAB
+An8nH5VzvHkMbSqJ6eOYDsVwomRvYbH5IEaYl1x6VATITNvAu9kUdQ4NsSpuMc+7
+Jj9gKZvmO1y2YCKc0P/iO+i/eV0L+yQh1Rw18jQZll+12T+LZrKRav03YNvMx0gN
+wqWY48Kt6hv2/N/ebQzKRe79+D0t2cTh92hT7xENFLIBAkEBGnoGKFjAUkJCwO1V
+mzpUqMHpRZVOrqP9hUmPjzNJ5oBPFGe4+h1hoSRFOAzaNuZt8ssbqaLCkzB8bfzj
+qhZqAQJBANZekuUpp8iBLeLSagw5FkcPwPzq6zfExbhvsZXb8Bo/4SflNs4JHXwI
+7SD9Z8aJLvM4uQ/5M70lblDMQ40i3o0CQQDIJvBYBFL5tlOgakq/O7yi+wt0L5BZ
+9H79w5rCSAA0IHRoK/qI1urHiHC3f3vbbLk5UStfrqEaND/mm0shyNIBAkBLsYdC
+/ctt5Bc0wUGK4Vl5bBmj9LtrrMJ4FpBpLwj/69BwCuKoK9XKZ0h73p6XHveCEGRg
+PIlFX4MtaoLrwgU9AkBV2k4dgIws+X8YX65EsyyFjnlDqX4x0nSOjQB1msIKfHBr
+dh5XLDBTTCxnKhMJ0Yx/opgOvf09XHBFwaQntR5i
+-----END RSA PRIVATE KEY-----
diff --git a/regress/rsa_openssh.pub b/regress/rsa_openssh.pub
new file mode 100644 (file)
index 0000000..b504730
--- /dev/null
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDsilwKcaKN6wSMNd1WgQ9+HRqQEkD0kCTVttrazGu0OhBU3Uko+dFD1Ip0CxdXmN25JQWxOYF7h/Ocu8P3jzv3RTX87xKR0YzlXTLX+SLtF/ySebS3xWPrlfRUDhh03hR5V+8xxvvy9widPYKw/oItwGSueOsEq1LTczCDv2dAjQ==
diff --git a/regress/rsa_ssh2.prv b/regress/rsa_ssh2.prv
new file mode 100644 (file)
index 0000000..1ece3d7
--- /dev/null
@@ -0,0 +1,16 @@
+---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
+Subject: ssh-keygen test
+Comment: "1024-bit rsa, Sat Jun 23 2001 12:21:26 -0400"
+P2/56wAAAi4AAAA3aWYtbW9kbntzaWdue3JzYS1wa2NzMS1zaGExfSxlbmNyeXB0e3JzYS
+1wa2NzMXYyLW9hZXB9fQAAAARub25lAAAB3wAAAdsAAAARAQABAAAD9icflXO8eQxtKonp
+45gOxXCiZG9hsfkgRpiXXHpUBMhM28C72RR1Dg2xKm4xz7smP2Apm+Y7XLZgIpzQ/+I76L
+95XQv7JCHVHDXyNBmWX7XZP4tmspFq/Tdg28zHSA3CpZjjwq3qG/b8395tDMpF7v34PS3Z
+xOH3aFPvEQ0UsgEAAAQA7IpcCnGijesEjDXdVoEPfh0akBJA9JAk1bba2sxrtDoQVN1JKP
+nRQ9SKdAsXV5jduSUFsTmBe4fznLvD948790U1/O8SkdGM5V0y1/ki7Rf8knm0t8Vj65X0
+VA4YdN4UeVfvMcb78vcInT2CsP6CLcBkrnjrBKtS03Mwg79nQI0AAAH/VdpOHYCMLPl/GF
++uRLMshY55Q6l+MdJ0jo0AdZrCCnxwa3YeVywwU0wsZyoTCdGMf6KYDr39PVxwRcGkJ7Ue
+YgAAAgDWXpLlKafIgS3i0moMORZHD8D86us3xMW4b7GV2/AaP+En5TbOCR18CO0g/WfGiS
+7zOLkP+TO9JW5QzEONIt6NAAACAQEaegYoWMBSQkLA7VWbOlSowelFlU6uo/2FSY+PM0nm
+gE8UZ7j6HWGhJEU4DNo25m3yyxuposKTMHxt/OOqFmoB
+---- END SSH2 ENCRYPTED PRIVATE KEY ----
+---
diff --git a/regress/runtests.sh b/regress/runtests.sh
new file mode 100755 (executable)
index 0000000..9808eb8
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+TEST_SSH_SSH=../ssh
+TEST_SSH_SSHD=../sshd
+TEST_SSH_SSHAGENT=../ssh-agent
+TEST_SSH_SSHADD=../ssh-add
+TEST_SSH_SSHKEYGEN=../ssh-keygen
+TEST_SSH_SSHKEYSCAN=../ssh-keyscan
+TEST_SSH_SFTP=../sftp
+TEST_SSH_SFTPSERVER=../sftp-server
+
+pmake
+
diff --git a/regress/scp-ssh-wrapper.sh b/regress/scp-ssh-wrapper.sh
new file mode 100644 (file)
index 0000000..d1005a9
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#       $OpenBSD: scp-ssh-wrapper.sh,v 1.2 2005/12/14 04:36:39 dtucker Exp $
+#       Placed in the Public Domain.
+
+printname () {
+       NAME=$1
+       save_IFS=$IFS
+       IFS=/
+       set -- `echo "$NAME"`
+       IFS="$save_IFS"
+       while [ $# -ge 1 ] ; do
+               if [ "x$1" != "x" ]; then
+                       echo "D0755 0 $1"
+               fi
+               shift;
+       done
+}
+
+# Discard all but last argument.  We use arg later.
+while test "$1" != ""; do
+       arg="$1"
+       shift
+done
+
+BAD="../../../../../../../../../../../../../${DIR}/dotpathdir"
+
+case "$SCPTESTMODE" in
+badserver_0)
+       echo "D0755 0 /${DIR}/rootpathdir"
+       echo "C755 2 rootpathfile"
+       echo "X"
+       ;;
+badserver_1)
+       echo "D0755 0 $BAD"
+       echo "C755 2 file"
+       echo "X"
+       ;;
+badserver_2)
+       echo "D0755 0 $BAD"
+       echo "C755 2 file"
+       echo "X"
+       ;;
+badserver_3)
+       printname $BAD
+       echo "C755 2 file"
+       echo "X"
+       ;;
+badserver_4)
+       printname $BAD
+       echo "D0755 0 .."
+       echo "C755 2 file"
+       echo "X"
+       ;;
+*)
+       exec $arg
+       ;;
+esac
diff --git a/regress/scp.sh b/regress/scp.sh
new file mode 100644 (file)
index 0000000..c5d412d
--- /dev/null
@@ -0,0 +1,127 @@
+#      $OpenBSD: scp.sh,v 1.7 2006/01/31 10:36:33 djm Exp $
+#      Placed in the Public Domain.
+
+tid="scp"
+
+#set -x
+
+# Figure out if diff understands "-N"
+if diff -N ${SRC}/scp.sh ${SRC}/scp.sh 2>/dev/null; then
+       DIFFOPT="-rN"
+else
+       DIFFOPT="-r"
+fi
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+COPY2=${OBJ}/copy2
+DIR=${COPY}.dd
+DIR2=${COPY}.dd2
+
+SRC=`dirname ${SCRIPT}`
+cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.scp
+chmod 755 ${OBJ}/scp-ssh-wrapper.scp
+scpopts="-q -S ${OBJ}/scp-ssh-wrapper.scp"
+
+scpclean() {
+       rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2}
+       mkdir ${DIR} ${DIR2}
+}
+
+verbose "$tid: simple copy local file to local file"
+scpclean
+$SCP $scpopts ${DATA} ${COPY} || fail "copy failed"
+cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+verbose "$tid: simple copy local file to remote file"
+scpclean
+$SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed"
+cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+verbose "$tid: simple copy remote file to local file"
+scpclean
+$SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed"
+cmp ${DATA} ${COPY} || fail "corrupted copy"
+
+verbose "$tid: simple copy local file to remote dir"
+scpclean
+cp ${DATA} ${COPY}
+$SCP $scpopts ${COPY} somehost:${DIR} || fail "copy failed"
+cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+
+verbose "$tid: simple copy local file to local dir"
+scpclean
+cp ${DATA} ${COPY}
+$SCP $scpopts ${COPY} ${DIR} || fail "copy failed"
+cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+
+verbose "$tid: simple copy remote file to local dir"
+scpclean
+cp ${DATA} ${COPY}
+$SCP $scpopts somehost:${COPY} ${DIR} || fail "copy failed"
+cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
+
+verbose "$tid: recursive local dir to remote dir"
+scpclean
+rm -rf ${DIR2}
+cp ${DATA} ${DIR}/copy
+$SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed"
+diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+
+verbose "$tid: recursive local dir to local dir"
+scpclean
+rm -rf ${DIR2}
+cp ${DATA} ${DIR}/copy
+$SCP $scpopts -r ${DIR} ${DIR2} || fail "copy failed"
+diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+
+verbose "$tid: recursive remote dir to local dir"
+scpclean
+rm -rf ${DIR2}
+cp ${DATA} ${DIR}/copy
+$SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed"
+diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+
+verbose "$tid: shell metacharacters"
+scpclean
+(cd ${DIR} && \
+touch '`touch metachartest`' && \
+$SCP $scpopts *metachar* ${DIR2} 2>/dev/null; \
+[ ! -f metachartest ] ) || fail "shell metacharacters"
+
+if [ ! -z "$SUDO" ]; then
+       verbose "$tid: skipped file after scp -p with failed chown+utimes"
+       scpclean
+       cp -p ${DATA} ${DIR}/copy
+       cp -p ${DATA} ${DIR}/copy2
+       cp ${DATA} ${DIR2}/copy
+       chmod 660 ${DIR2}/copy
+       $SUDO chown root ${DIR2}/copy
+       $SCP -p $scpopts somehost:${DIR}/\* ${DIR2} >/dev/null 2>&1
+       $SUDO diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
+       $SUDO rm ${DIR2}/copy
+fi
+
+for i in 0 1 2 3 4; do
+       verbose "$tid: disallow bad server #$i"
+       SCPTESTMODE=badserver_$i
+       export DIR SCPTESTMODE
+       scpclean
+       $SCP $scpopts somehost:${DATA} ${DIR} >/dev/null 2>/dev/null
+       [ -d {$DIR}/rootpathdir ] && fail "allows dir relative to root dir"
+       [ -d ${DIR}/dotpathdir ] && fail "allows dir creation in non-recursive mode"
+
+       scpclean
+       $SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null
+       [ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir"
+done
+
+verbose "$tid: detect non-directory target"
+scpclean
+echo a > ${COPY}
+echo b > ${COPY2}
+$SCP $scpopts ${DATA} ${COPY} ${COPY2}
+cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target"
+
+scpclean
+rm -f ${OBJ}/scp-ssh-wrapper.scp
diff --git a/regress/sftp-badcmds.sh b/regress/sftp-badcmds.sh
new file mode 100644 (file)
index 0000000..08009f2
--- /dev/null
@@ -0,0 +1,67 @@
+#      $OpenBSD: sftp-badcmds.sh,v 1.4 2009/08/13 01:11:55 djm Exp $
+#      Placed in the Public Domain.
+
+tid="sftp invalid commands"
+
+DATA=/bin/ls${EXEEXT}
+DATA2=/bin/sh${EXEEXT}
+NONEXIST=/NONEXIST.$$
+COPY=${OBJ}/copy
+GLOBFILES=`(cd /bin;echo l*)`
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd
+
+rm -f ${COPY}
+verbose "$tid: get nonexistent"
+echo "get $NONEXIST $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "get nonexistent failed"
+test -f ${COPY} && fail "existing copy after get nonexistent"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob get to nonexistent directory"
+echo "get /bin/l* $NONEXIST" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get nonexistent failed"
+for x in $GLOBFILES; do
+        test -f ${COPY}.dd/$x && fail "existing copy after get nonexistent"
+done
+
+rm -f ${COPY}
+verbose "$tid: put nonexistent"
+echo "put $NONEXIST $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "put nonexistent failed"
+test -f ${COPY} && fail "existing copy after put nonexistent"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob put to nonexistent directory"
+echo "put /bin/l* ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "put nonexistent failed"
+for x in $GLOBFILES; do
+        test -f ${COPY}.dd/$x && fail "existing copy after nonexistent"
+done
+
+rm -f ${COPY}
+verbose "$tid: rename nonexistent"
+echo "rename $NONEXIST ${COPY}.1" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "rename nonexist failed"
+test -f ${COPY}.1 && fail "file exists after rename nonexistent"
+
+rm -rf ${COPY} ${COPY}.dd
+cp $DATA $COPY
+mkdir ${COPY}.dd
+verbose "$tid: rename target exists (directory)"
+echo "rename $COPY ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "rename target exists (directory) failed"
+test -f ${COPY} || fail "oldname missing after rename target exists (directory)"
+test -d ${COPY}.dd || fail "newname missing after rename target exists (directory)"
+cmp $DATA ${COPY} >/dev/null 2>&1 || fail "corrupted oldname after rename target exists (directory)"
+
+rm -f ${COPY}.dd/*
+rm -rf ${COPY}
+cp ${DATA2} ${COPY}
+verbose "$tid: glob put files to local file"
+echo "put /bin/l* $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 
+cmp ${DATA2} ${COPY} || fail "put successed when it should have failed"
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd
+
+
diff --git a/regress/sftp-batch.sh b/regress/sftp-batch.sh
new file mode 100644 (file)
index 0000000..a51ef07
--- /dev/null
@@ -0,0 +1,57 @@
+#      $OpenBSD: sftp-batch.sh,v 1.4 2009/08/13 01:11:55 djm Exp $
+#      Placed in the Public Domain.
+
+tid="sftp batchfile"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+BATCH=${OBJ}/sftp.bb
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${BATCH}.*
+
+cat << EOF > ${BATCH}.pass.1
+       get $DATA $COPY
+       put ${COPY} ${COPY}.1
+       rm ${COPY}
+       -put ${COPY} ${COPY}.2
+EOF
+
+cat << EOF > ${BATCH}.pass.2
+       # This is a comment
+
+       # That was a blank line
+       ls
+EOF
+
+cat << EOF > ${BATCH}.fail.1
+       get $DATA $COPY
+       put ${COPY} ${COPY}.3
+       rm ${COPY}.*
+       # The next command should fail
+       put ${COPY}.3 ${COPY}.4
+EOF
+
+cat << EOF > ${BATCH}.fail.2
+       # The next command should fail
+       jajajajaja
+EOF
+
+verbose "$tid: good commands"
+${SFTP} -b ${BATCH}.pass.1 -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "good commands failed"
+
+verbose "$tid: bad commands"
+${SFTP} -b ${BATCH}.fail.1 -D ${SFTPSERVER} >/dev/null 2>&1 \
+       && fail "bad commands succeeded"
+
+verbose "$tid: comments and blanks"
+${SFTP} -b ${BATCH}.pass.2 -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "comments & blanks failed"
+
+verbose "$tid: junk command"
+${SFTP} -b ${BATCH}.fail.2 -D ${SFTPSERVER} >/dev/null 2>&1 \
+       && fail "junk command succeeded"
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${BATCH}.*
+
+
diff --git a/regress/sftp-cmds.sh b/regress/sftp-cmds.sh
new file mode 100644 (file)
index 0000000..1c67b64
--- /dev/null
@@ -0,0 +1,248 @@
+#      $OpenBSD: sftp-cmds.sh,v 1.11 2010/12/04 00:21:19 djm Exp $
+#      Placed in the Public Domain.
+
+# XXX - TODO: 
+# - chmod / chown / chgrp
+# - -p flag for get & put
+
+tid="sftp commands"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+# test that these files are readable!
+for i in `(cd /bin;echo l*)`
+do
+       if [ -r $i ]; then
+               GLOBFILES="$GLOBFILES $i"
+       fi
+done
+
+if have_prog uname
+then
+       case `uname` in
+       CYGWIN*)
+               os=cygwin
+               ;;
+       *)
+               os=`uname`
+               ;;
+       esac
+else
+       os="unknown"
+fi
+
+# Path with embedded quote
+QUOTECOPY=${COPY}".\"blah\""
+QUOTECOPY_ARG=${COPY}'.\"blah\"'
+# File with spaces
+SPACECOPY="${COPY} this has spaces.txt"
+SPACECOPY_ARG="${COPY}\ this\ has\ spaces.txt"
+# File with glob metacharacters
+GLOBMETACOPY="${COPY} [metachar].txt"
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2 ${BATCH}.*
+mkdir ${COPY}.dd
+
+verbose "$tid: lls"
+(echo "lcd ${OBJ}" ; echo "lls") | ${SFTP} -D ${SFTPSERVER} 2>&1 | \
+       grep copy.dd >/dev/null 2>&1 || fail "lls failed"
+
+verbose "$tid: lls w/path"
+echo "lls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} 2>&1 | \
+       grep copy.dd >/dev/null 2>&1 || fail "lls w/path failed"
+
+verbose "$tid: ls"
+echo "ls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "ls failed"
+# XXX always successful
+
+verbose "$tid: shell"
+echo "!echo hi there" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "shell failed"
+# XXX always successful
+
+verbose "$tid: pwd"
+echo "pwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "pwd failed"
+# XXX always successful
+
+verbose "$tid: lpwd"
+echo "lpwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "lpwd failed"
+# XXX always successful
+
+verbose "$tid: quit"
+echo "quit" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "quit failed"
+# XXX always successful
+
+verbose "$tid: help"
+echo "help" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "help failed"
+# XXX always successful
+
+rm -f ${COPY}
+verbose "$tid: get"
+echo "get $DATA $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "get failed"
+cmp $DATA ${COPY} || fail "corrupted copy after get"
+
+rm -f ${COPY}
+verbose "$tid: get quoted"
+echo "get \"$DATA\" $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "get failed"
+cmp $DATA ${COPY} || fail "corrupted copy after get"
+
+if [ "$os" != "cygwin" ]; then
+rm -f ${QUOTECOPY}
+cp $DATA ${QUOTECOPY}
+verbose "$tid: get filename with quotes"
+echo "get \"$QUOTECOPY_ARG\" ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "get failed"
+cmp ${COPY} ${QUOTECOPY} || fail "corrupted copy after get with quotes"
+rm -f ${QUOTECOPY} ${COPY}
+fi
+
+rm -f "$SPACECOPY" ${COPY}
+cp $DATA "$SPACECOPY"
+verbose "$tid: get filename with spaces"
+echo "get ${SPACECOPY_ARG} ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get failed"
+cmp ${COPY} "$SPACECOPY" || fail "corrupted copy after get with spaces"
+
+rm -f "$GLOBMETACOPY" ${COPY}
+cp $DATA "$GLOBMETACOPY"
+verbose "$tid: get filename with glob metacharacters"
+echo "get \"${GLOBMETACOPY}\" ${COPY}" | \
+       ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "get failed"
+cmp ${COPY} "$GLOBMETACOPY" || \
+       fail "corrupted copy after get with glob metacharacters"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: get to directory"
+echo "get $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get failed"
+cmp $DATA ${COPY}.dd/`basename $DATA` || fail "corrupted copy after get"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob get to directory"
+echo "get /bin/l* ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get failed"
+for x in $GLOBFILES; do
+        cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get"
+done
+
+rm -f ${COPY}.dd/*
+verbose "$tid: get to local dir"
+(echo "lcd ${COPY}.dd"; echo "get $DATA" ) | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get failed"
+cmp $DATA ${COPY}.dd/`basename $DATA` || fail "corrupted copy after get"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob get to local dir"
+(echo "lcd ${COPY}.dd"; echo "get /bin/l*") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+        || fail "get failed"
+for x in $GLOBFILES; do
+        cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get"
+done
+
+rm -f ${COPY}
+verbose "$tid: put"
+echo "put $DATA $COPY" | \
+       ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
+cmp $DATA ${COPY} || fail "corrupted copy after put"
+
+if [ "$os" != "cygwin" ]; then
+rm -f ${QUOTECOPY}
+verbose "$tid: put filename with quotes"
+echo "put $DATA \"$QUOTECOPY_ARG\"" | \
+       ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
+cmp $DATA ${QUOTECOPY} || fail "corrupted copy after put with quotes"
+fi
+
+rm -f "$SPACECOPY"
+verbose "$tid: put filename with spaces"
+echo "put $DATA ${SPACECOPY_ARG}" | \
+       ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed"
+cmp $DATA "$SPACECOPY" || fail "corrupted copy after put with spaces"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: put to directory"
+echo "put $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "put failed"
+cmp $DATA ${COPY}.dd/`basename $DATA` || fail "corrupted copy after put"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob put to directory"
+echo "put /bin/l? ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "put failed"
+for x in $GLOBFILES; do
+       cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put"
+done
+
+rm -f ${COPY}.dd/*
+verbose "$tid: put to local dir"
+(echo "cd ${COPY}.dd"; echo "put $DATA") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "put failed"
+cmp $DATA ${COPY}.dd/`basename $DATA` || fail "corrupted copy after put"
+
+rm -f ${COPY}.dd/*
+verbose "$tid: glob put to local dir"
+(echo "cd ${COPY}.dd"; echo "put /bin/l?") | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "put failed"
+for x in $GLOBFILES; do
+        cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put"
+done
+
+verbose "$tid: rename"
+echo "rename $COPY ${COPY}.1" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "rename failed"
+test -f ${COPY}.1 || fail "missing file after rename"
+cmp $DATA ${COPY}.1 >/dev/null 2>&1 || fail "corrupted copy after rename"
+
+verbose "$tid: rename directory"
+echo "rename ${COPY}.dd ${COPY}.dd2" | \
+       ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || \
+       fail "rename directory failed"
+test -d ${COPY}.dd && fail "oldname exists after rename directory"
+test -d ${COPY}.dd2 || fail "missing newname after rename directory"
+
+verbose "$tid: ln"
+echo "ln ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln failed"
+test -f ${COPY}.2 || fail "missing file after ln"
+cmp ${COPY}.1 ${COPY}.2 || fail "created file is not equal after ln"
+
+verbose "$tid: ln -s"
+rm -f ${COPY}.2
+echo "ln -s ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln -s failed"
+test -h ${COPY}.2 || fail "missing file after ln -s"
+
+verbose "$tid: mkdir"
+echo "mkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "mkdir failed"
+test -d ${COPY}.dd || fail "missing directory after mkdir"
+
+# XXX do more here
+verbose "$tid: chdir"
+echo "chdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "chdir failed"
+
+verbose "$tid: rmdir"
+echo "rmdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "rmdir failed"
+test -d ${COPY}.1 && fail "present directory after rmdir"
+
+verbose "$tid: lmkdir"
+echo "lmkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "lmkdir failed"
+test -d ${COPY}.dd || fail "missing directory after lmkdir"
+
+# XXX do more here
+verbose "$tid: lchdir"
+echo "lchdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \
+       || fail "lchdir failed"
+
+rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2 ${BATCH}.*
+rm -rf ${QUOTECOPY} "$SPACECOPY" "$GLOBMETACOPY"
+
+
diff --git a/regress/sftp-glob.sh b/regress/sftp-glob.sh
new file mode 100644 (file)
index 0000000..8d4df2c
--- /dev/null
@@ -0,0 +1,75 @@
+#      $OpenBSD: sftp-glob.sh,v 1.4 2009/08/13 01:11:55 djm Exp $
+#      Placed in the Public Domain.
+
+tid="sftp glob"
+
+config_defined FILESYSTEM_NO_BACKSLASH && nobs="not supported on this platform"
+
+sftp_ls() {
+       target=$1
+       errtag=$2
+       expected=$3
+       unexpected=$4
+       skip=$5
+       if test "x$skip" != "x" ; then
+               verbose "$tid: $errtag (skipped: $skip)"
+               return
+       fi
+       verbose "$tid: $errtag"
+       printf "ls -l %s" "${target}" | \
+               ${SFTP} -b - -D ${SFTPSERVER} 2>/dev/null | \
+               grep -v "^sftp>" > ${RESULTS}
+       if [ $? -ne 0 ]; then
+               fail "$errtag failed"
+       fi
+       if test "x$expected" != "x" ; then
+           if fgrep "$expected" ${RESULTS} >/dev/null 2>&1 ; then
+               :
+           else
+               fail "$expected missing from $errtag results"
+           fi
+       fi
+       if test "x$unexpected" != "x" && \
+          fgrep "$unexpected" ${RESULTS} >/dev/null 2>&1 ; then
+               fail "$unexpected present in $errtag results"
+       fi
+       rm -f ${RESULTS}
+}
+
+BASE=${OBJ}/glob
+RESULTS=${OBJ}/results
+DIR=${BASE}/dir
+DATA=${DIR}/file
+
+GLOB1="${DIR}/g-wild*"
+GLOB2="${DIR}/g-wildx"
+QUOTE="${DIR}/g-quote\""
+SLASH="${DIR}/g-sl\\ash"
+ESLASH="${DIR}/g-slash\\"
+QSLASH="${DIR}/g-qs\\\""
+SPACE="${DIR}/g-q space"
+
+rm -rf ${BASE}
+mkdir -p ${DIR}
+touch "${DATA}" "${GLOB1}" "${GLOB2}" "${QUOTE}" "${SPACE}"
+test "x$nobs" = "x" && touch "${QSLASH}" "${ESLASH}" "${SLASH}"
+
+#       target                   message                expected     unexpected
+sftp_ls "${DIR}/fil*"            "file glob"            "${DATA}"    ""
+sftp_ls "${BASE}/d*"             "dir glob"             "`basename ${DATA}`" ""
+sftp_ls "${DIR}/g-wild\"*\""     "quoted glob"          "g-wild*"    "g-wildx"
+sftp_ls "${DIR}/g-wild\*"        "escaped glob"         "g-wild*"    "g-wildx"
+sftp_ls "${DIR}/g-quote\\\""     "escaped quote"        "g-quote\""  ""
+sftp_ls "\"${DIR}/g-quote\\\"\"" "quoted quote"         "g-quote\""  ""
+sftp_ls "'${DIR}/g-quote\"'"     "single-quoted quote"  "g-quote\""  ""
+sftp_ls "${DIR}/g-q\\ space"     "escaped space"        "g-q space"  ""
+sftp_ls "'${DIR}/g-q space'"     "quoted space"         "g-q space"  ""
+sftp_ls "${DIR}/g-sl\\\\ash"     "escaped slash"        "g-sl\\ash"  "" "$nobs"
+sftp_ls "'${DIR}/g-sl\\\\ash'"   "quoted slash"         "g-sl\\ash"  "" "$nobs"
+sftp_ls "${DIR}/g-slash\\\\"     "escaped slash at EOL" "g-slash\\"  "" "$nobs"
+sftp_ls "'${DIR}/g-slash\\\\'"   "quoted slash at EOL"  "g-slash\\"  "" "$nobs"
+sftp_ls "${DIR}/g-qs\\\\\\\""    "escaped slash+quote"  "g-qs\\\""   "" "$nobs"
+sftp_ls "'${DIR}/g-qs\\\\\"'"    "quoted slash+quote"   "g-qs\\\""   "" "$nobs"
+
+rm -rf ${BASE}
+
diff --git a/regress/sftp.sh b/regress/sftp.sh
new file mode 100644 (file)
index 0000000..f84fa6f
--- /dev/null
@@ -0,0 +1,35 @@
+#      $OpenBSD: sftp.sh,v 1.3 2009/08/13 01:11:55 djm Exp $
+#      Placed in the Public Domain.
+
+tid="basic sftp put/get"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+
+SFTPCMDFILE=${OBJ}/batch
+cat >$SFTPCMDFILE <<EOF
+version
+get $DATA ${COPY}.1
+put $DATA ${COPY}.2
+EOF
+
+BUFFERSIZE="5 1000 32000 64000"
+REQUESTS="1 2 10"
+
+for B in ${BUFFERSIZE}; do
+       for R in ${REQUESTS}; do
+                verbose "test $tid: buffer_size $B num_requests $R"
+               rm -f ${COPY}.1 ${COPY}.2
+               ${SFTP} -D ${SFTPSERVER} -B $B -R $R -b $SFTPCMDFILE \
+               > /dev/null 2>&1
+               r=$?
+               if [ $r -ne 0 ]; then
+                       fail "sftp failed with $r"
+               else 
+                       cmp $DATA ${COPY}.1 || fail "corrupted copy after get"
+                       cmp $DATA ${COPY}.2 || fail "corrupted copy after put"
+               fi
+       done
+done
+rm -f ${COPY}.1 ${COPY}.2                
+rm -f $SFTPCMDFILE
diff --git a/regress/ssh-com-client.sh b/regress/ssh-com-client.sh
new file mode 100644 (file)
index 0000000..324a0a7
--- /dev/null
@@ -0,0 +1,134 @@
+#      $OpenBSD: ssh-com-client.sh,v 1.6 2004/02/24 17:06:52 markus Exp $
+#      Placed in the Public Domain.
+
+tid="connect with ssh.com client"
+
+#TEST_COMBASE=/path/to/ssh/com/binaries
+if [ "X${TEST_COMBASE}" = "X" ]; then
+       fatal '$TEST_COMBASE is not set'
+fi
+
+VERSIONS="
+       2.1.0
+       2.2.0
+       2.3.0
+       2.3.1
+       2.4.0
+       3.0.0
+       3.1.0
+       3.2.0
+       3.2.2
+       3.2.3
+       3.2.5
+       3.2.9
+       3.2.9.1
+       3.3.0"
+
+# 2.0.10 2.0.12 2.0.13 don't like the test setup
+
+# setup authorized keys
+SRC=`dirname ${SCRIPT}`
+cp ${SRC}/dsa_ssh2.prv ${OBJ}/id.com
+chmod 600 ${OBJ}/id.com
+${SSHKEYGEN} -i -f ${OBJ}/id.com       > $OBJ/id.openssh
+chmod 600 ${OBJ}/id.openssh
+${SSHKEYGEN} -y -f ${OBJ}/id.openssh   > $OBJ/authorized_keys_$USER
+${SSHKEYGEN} -e -f ${OBJ}/id.openssh   > $OBJ/id.com.pub
+echo IdKey ${OBJ}/id.com > ${OBJ}/id.list
+
+# we need a DSA host key
+t=dsa
+rm -f                             ${OBJ}/$t ${OBJ}/$t.pub
+${SSHKEYGEN} -q -N '' -t $t -f   ${OBJ}/$t
+$SUDO cp $OBJ/$t $OBJ/host.$t
+echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
+
+# add hostkeys to known hosts
+mkdir -p ${OBJ}/${USER}/hostkeys
+HK=${OBJ}/${USER}/hostkeys/key_${PORT}_127.0.0.1
+${SSHKEYGEN} -e -f ${OBJ}/rsa.pub > ${HK}.ssh-rsa.pub
+${SSHKEYGEN} -e -f ${OBJ}/dsa.pub > ${HK}.ssh-dss.pub
+
+cat > ${OBJ}/ssh2_config << EOF
+*:
+       QuietMode                       yes
+       StrictHostKeyChecking           yes
+       Port                            ${PORT}
+       User                            ${USER}
+       Host                            127.0.0.1
+       IdentityFile                    ${OBJ}/id.list
+       RandomSeedFile                  ${OBJ}/random_seed
+        UserConfigDirectory             ${OBJ}/%U
+       AuthenticationSuccessMsg        no
+       BatchMode                       yes
+       ForwardX11                      no
+EOF
+
+# we need a real server (no ProxyConnect option)
+start_sshd
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+rm -f ${COPY}
+
+# go for it
+for v in ${VERSIONS}; do
+       ssh2=${TEST_COMBASE}/${v}/ssh2
+       if [ ! -x ${ssh2} ]; then
+               continue
+       fi
+       verbose "ssh2 ${v}"
+       key=ssh-dss
+       skipcat=0
+        case $v in
+        2.1.*|2.3.0)
+                skipcat=1
+                ;;
+        3.0.*)
+                key=ssh-rsa
+                ;;
+        esac
+       cp ${HK}.$key.pub ${HK}.pub
+
+       # check exit status
+       ${ssh2} -q -F ${OBJ}/ssh2_config somehost exit 42
+       r=$?
+        if [ $r -ne 42 ]; then
+                fail "ssh2 ${v} exit code test failed (got $r, expected 42)"
+        fi
+
+       # data transfer
+       rm -f ${COPY}
+       ${ssh2} -F ${OBJ}/ssh2_config somehost cat ${DATA} > ${COPY}
+        if [ $? -ne 0 ]; then
+                fail "ssh2 ${v} cat test (receive) failed"
+        fi
+       cmp ${DATA} ${COPY}     || fail "ssh2 ${v} cat test (receive) data mismatch"
+
+       # data transfer, again
+       if [ $skipcat -eq 0 ]; then
+               rm -f ${COPY}
+               cat ${DATA} | \
+                       ${ssh2} -F ${OBJ}/ssh2_config host "cat > ${COPY}"
+               if [ $? -ne 0 ]; then
+                       fail "ssh2 ${v} cat test (send) failed"
+               fi
+               cmp ${DATA} ${COPY}     || \
+                       fail "ssh2 ${v} cat test (send) data mismatch"
+       fi
+
+       # no stderr after eof
+       rm -f ${COPY}
+       ${ssh2} -F ${OBJ}/ssh2_config somehost \
+               exec sh -c \'"exec > /dev/null; sleep 1; echo bla 1>&2; exit 0"\' \
+               2> /dev/null
+        if [ $? -ne 0 ]; then
+                fail "ssh2 ${v} stderr test failed"
+        fi
+done
+
+rm -rf ${OBJ}/${USER}
+for i in ssh2_config random_seed dsa.pub dsa host.dsa \
+    id.list id.com id.com.pub id.openssh; do
+       rm -f ${OBJ}/$i
+done
diff --git a/regress/ssh-com-keygen.sh b/regress/ssh-com-keygen.sh
new file mode 100644 (file)
index 0000000..29b02d9
--- /dev/null
@@ -0,0 +1,74 @@
+#      $OpenBSD: ssh-com-keygen.sh,v 1.4 2004/02/24 17:06:52 markus Exp $
+#      Placed in the Public Domain.
+
+tid="ssh.com key import"
+
+#TEST_COMBASE=/path/to/ssh/com/binaries
+if [ "X${TEST_COMBASE}" = "X" ]; then
+       fatal '$TEST_COMBASE is not set'
+fi
+
+VERSIONS="
+       2.0.10
+       2.0.12
+       2.0.13
+       2.1.0
+       2.2.0
+       2.3.0
+       2.3.1
+       2.4.0
+       3.0.0
+       3.1.0
+       3.2.0
+       3.2.2
+       3.2.3
+       3.2.5
+       3.2.9
+       3.2.9.1
+       3.3.0"
+
+COMPRV=${OBJ}/comkey
+COMPUB=${COMPRV}.pub
+OPENSSHPRV=${OBJ}/opensshkey
+OPENSSHPUB=${OPENSSHPRV}.pub
+
+# go for it
+for v in ${VERSIONS}; do
+       keygen=${TEST_COMBASE}/${v}/ssh-keygen2
+       if [ ! -x ${keygen} ]; then
+               continue
+       fi
+       types="dss"
+        case $v in
+        2.3.1|3.*)
+                types="$types rsa"
+                ;;
+        esac
+       for t in $types; do
+               verbose "ssh-keygen $v/$t"
+               rm -f $COMPRV $COMPUB $OPENSSHPRV $OPENSSHPUB
+               ${keygen} -q -P -t $t ${COMPRV} > /dev/null 2>&1
+               if [ $? -ne 0 ]; then
+                       fail "${keygen} -t $t failed"
+                       continue
+               fi
+               ${SSHKEYGEN} -if ${COMPUB} > ${OPENSSHPUB}
+               if [ $? -ne 0 ]; then
+                       fail "import public key ($v/$t) failed"
+                       continue
+               fi
+               ${SSHKEYGEN} -if ${COMPRV} > ${OPENSSHPRV}
+               if [ $? -ne 0 ]; then
+                       fail "import private key ($v/$t) failed"
+                       continue
+               fi
+               chmod 600 ${OPENSSHPRV}
+               ${SSHKEYGEN} -yf ${OPENSSHPRV} |\
+                       diff - ${OPENSSHPUB}
+               if [ $? -ne 0 ]; then
+                       fail "public keys ($v/$t) differ"
+               fi
+       done
+done
+
+rm -f $COMPRV $COMPUB $OPENSSHPRV $OPENSSHPUB
diff --git a/regress/ssh-com-sftp.sh b/regress/ssh-com-sftp.sh
new file mode 100644 (file)
index 0000000..be6f4e0
--- /dev/null
@@ -0,0 +1,67 @@
+#      $OpenBSD: ssh-com-sftp.sh,v 1.6 2009/08/20 18:43:07 djm Exp $
+#      Placed in the Public Domain.
+
+tid="basic sftp put/get with ssh.com server"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+SFTPCMDFILE=${OBJ}/batch
+
+cat >$SFTPCMDFILE <<EOF
+version
+get $DATA ${COPY}.1
+put $DATA ${COPY}.2
+EOF
+
+BUFFERSIZE="5 1000 32000 64000"
+REQUESTS="1 2 10"
+
+#TEST_COMBASE=/path/to/ssh/com/binaries
+if [ "X${TEST_COMBASE}" = "X" ]; then
+       fatal '$TEST_COMBASE is not set'
+fi
+
+VERSIONS="
+       2.0.10
+       2.0.12
+       2.0.13
+       2.1.0
+       2.2.0
+       2.3.0
+       2.3.1
+       2.4.0
+       3.0.0
+       3.1.0
+       3.2.0
+       3.2.2
+       3.2.3
+       3.2.5
+       3.2.9
+       3.2.9.1
+       3.3.0"
+
+# go for it
+for v in ${VERSIONS}; do
+       server=${TEST_COMBASE}/${v}/sftp-server2
+       if [ ! -x ${server} ]; then
+               continue
+       fi
+       verbose "sftp-server $v"
+       for B in ${BUFFERSIZE}; do
+               for R in ${REQUESTS}; do
+                       verbose "test $tid: buffer_size $B num_requests $R"
+                       rm -f ${COPY}.1 ${COPY}.2
+                       ${SFTP} -D ${server} -B $B -R $R -b $SFTPCMDFILE \
+                       > /dev/null 2>&1
+                       r=$?
+                       if [ $r -ne 0 ]; then
+                               fail "sftp failed with $r"
+                       else                                
+                               cmp $DATA ${COPY}.1 || fail "corrupted copy after get"
+                               cmp $DATA ${COPY}.2 || fail "corrupted copy after put"
+                       fi
+               done
+       done
+done
+rm -f ${COPY}.1 ${COPY}.2                
+rm -f $SFTPCMDFILE
diff --git a/regress/ssh-com.sh b/regress/ssh-com.sh
new file mode 100644 (file)
index 0000000..7bcd85b
--- /dev/null
@@ -0,0 +1,119 @@
+#      $OpenBSD: ssh-com.sh,v 1.7 2004/02/24 17:06:52 markus Exp $
+#      Placed in the Public Domain.
+
+tid="connect to ssh.com server"
+
+#TEST_COMBASE=/path/to/ssh/com/binaries
+if [ "X${TEST_COMBASE}" = "X" ]; then
+       fatal '$TEST_COMBASE is not set'
+fi
+
+VERSIONS="
+       2.0.12
+       2.0.13
+       2.1.0
+       2.2.0
+       2.3.0
+       2.4.0
+       3.0.0
+       3.1.0
+       3.2.0
+       3.2.2
+       3.2.3
+       3.2.5
+       3.2.9
+       3.2.9.1
+       3.3.0"
+# 2.0.10 does not support UserConfigDirectory
+# 2.3.1 requires a config in $HOME/.ssh2
+
+SRC=`dirname ${SCRIPT}`
+
+# ssh.com
+cat << EOF > $OBJ/sshd2_config
+#*:
+       # Port and ListenAddress are not used.
+       QuietMode                       yes
+       Port                            4343
+       ListenAddress                   127.0.0.1
+       UserConfigDirectory             ${OBJ}/%U
+       Ciphers                         AnyCipher
+       PubKeyAuthentication            yes
+       #AllowedAuthentications         publickey
+       AuthorizationFile               authorization
+       HostKeyFile                     ${SRC}/dsa_ssh2.prv
+       PublicHostKeyFile               ${SRC}/dsa_ssh2.pub
+       RandomSeedFile                  ${OBJ}/random_seed
+       MaxConnections                  0 
+       PermitRootLogin                 yes
+       VerboseMode                     no
+       CheckMail                       no
+       Ssh1Compatibility               no
+EOF
+
+# create client config 
+sed "s/HostKeyAlias.*/HostKeyAlias ssh2-localhost-with-alias/" \
+       < $OBJ/ssh_config > $OBJ/ssh_config_com
+
+# we need a DSA key for
+rm -f                             ${OBJ}/dsa ${OBJ}/dsa.pub
+${SSHKEYGEN} -q -N '' -t dsa -f          ${OBJ}/dsa
+
+# setup userdir, try rsa first
+mkdir -p ${OBJ}/${USER}
+cp /dev/null ${OBJ}/${USER}/authorization
+for t in rsa dsa; do
+       ${SSHKEYGEN} -e -f ${OBJ}/$t.pub        >  ${OBJ}/${USER}/$t.com
+       echo Key $t.com                 >> ${OBJ}/${USER}/authorization
+       echo IdentityFile ${OBJ}/$t     >> ${OBJ}/ssh_config_com
+done
+
+# convert and append DSA hostkey
+(
+       echon 'ssh2-localhost-with-alias,127.0.0.1,::1 '
+       ${SSHKEYGEN} -if ${SRC}/dsa_ssh2.pub
+) >> $OBJ/known_hosts
+
+# go for it
+for v in ${VERSIONS}; do
+       sshd2=${TEST_COMBASE}/${v}/sshd2
+       if [ ! -x ${sshd2} ]; then
+               continue
+       fi
+       trace "sshd2 ${v}"
+       PROXY="proxycommand ${sshd2} -qif ${OBJ}/sshd2_config 2> /dev/null"
+       ${SSH} -qF ${OBJ}/ssh_config_com -o "${PROXY}" dummy exit 0
+        if [ $? -ne 0 ]; then
+                fail "ssh connect to sshd2 ${v} failed"
+        fi
+
+       ciphers="3des-cbc blowfish-cbc arcfour"
+       macs="hmac-md5"
+       case $v in
+       2.4.*)
+               ciphers="$ciphers cast128-cbc"
+               macs="$macs hmac-sha1 hmac-sha1-96 hmac-md5-96"
+               ;;
+       3.*)
+               ciphers="$ciphers aes128-cbc cast128-cbc"
+               macs="$macs hmac-sha1 hmac-sha1-96 hmac-md5-96"
+               ;;
+       esac
+       #ciphers="3des-cbc"
+       for m in $macs; do
+       for c in $ciphers; do
+               trace "sshd2 ${v} cipher $c mac $m"
+               verbose "test ${tid}: sshd2 ${v} cipher $c mac $m"
+               ${SSH} -c $c -m $m -qF ${OBJ}/ssh_config_com -o "${PROXY}" dummy exit 0
+               if [ $? -ne 0 ]; then
+                       fail "ssh connect to sshd2 ${v} with $c/$m failed"
+               fi
+       done
+       done
+done
+
+rm -rf ${OBJ}/${USER}
+for i in sshd_config_proxy ssh_config_proxy random_seed \
+       sshd2_config dsa.pub dsa ssh_config_com; do
+       rm -f ${OBJ}/$i
+done
diff --git a/regress/ssh2putty.sh b/regress/ssh2putty.sh
new file mode 100755 (executable)
index 0000000..691db16
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+#      $OpenBSD: ssh2putty.sh,v 1.2 2009/10/06 23:51:49 dtucker Exp $
+
+if test "x$1" = "x" -o "x$2" = "x" -o "x$3" = "x" ; then
+       echo "Usage: ssh2putty hostname port ssh-private-key"
+       exit 1
+fi
+
+HOST=$1
+PORT=$2
+KEYFILE=$3
+
+# XXX - support DSA keys too
+if grep "BEGIN RSA PRIVATE KEY" $KEYFILE >/dev/null 2>&1 ; then
+       :
+else
+       echo "Unsupported private key format"
+       exit 1
+fi
+
+public_exponent=`
+       openssl rsa -noout -text -in $KEYFILE | grep ^publicExponent | 
+       sed 's/.*(//;s/).*//'
+`
+test $? -ne 0 && exit 1
+
+modulus=`
+       openssl rsa -noout -modulus -in $KEYFILE | grep ^Modulus= | 
+       sed 's/^Modulus=/0x/' | tr A-Z a-z
+`
+test $? -ne 0 && exit 1
+
+echo "rsa2@$PORT:$HOST $public_exponent,$modulus"
+
diff --git a/regress/sshd-log-wrapper.sh b/regress/sshd-log-wrapper.sh
new file mode 100644 (file)
index 0000000..c7a5ef3
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+#       $OpenBSD: sshd-log-wrapper.sh,v 1.2 2005/02/27 11:40:30 dtucker Exp $
+#       Placed in the Public Domain.
+#
+# simple wrapper for sshd proxy mode to catch stderr output
+# sh sshd-log-wrapper.sh /path/to/sshd /path/to/logfile
+
+sshd=$1
+log=$2
+shift
+shift
+
+exec $sshd $@ -e 2>>$log
diff --git a/regress/stderr-after-eof.sh b/regress/stderr-after-eof.sh
new file mode 100644 (file)
index 0000000..05a5ea5
--- /dev/null
@@ -0,0 +1,40 @@
+#      $OpenBSD: stderr-after-eof.sh,v 1.1 2002/03/23 16:38:09 markus Exp $
+#      Placed in the Public Domain.
+
+tid="stderr data after eof"
+
+DATA=/etc/motd
+DATA=${OBJ}/data
+COPY=${OBJ}/copy
+
+if have_prog md5sum; then
+       CHECKSUM=md5sum
+elif have_prog openssl; then
+       CHECKSUM="openssl md5"
+elif have_prog cksum; then
+       CHECKSUM=cksum
+elif have_prog sum; then
+       CHECKSUM=sum
+else
+       fatal "No checksum program available, aborting $tid test"
+fi
+
+# setup data
+rm -f ${DATA} ${COPY}
+cp /dev/null ${DATA}
+for i in 1 2 3 4 5 6; do
+       (date;echo $i) | $CHECKSUM >> ${DATA}
+done
+
+${SSH} -2 -F $OBJ/ssh_proxy otherhost \
+       exec sh -c \'"exec > /dev/null; sleep 2; cat ${DATA} 1>&2 $s"\' \
+       2> ${COPY}
+r=$?
+if [ $r -ne 0 ]; then
+       fail "ssh failed with exit code $r"
+fi
+egrep 'Disconnecting: Received extended_data after EOF' ${COPY} &&
+       fail "ext data received after eof"
+cmp ${DATA} ${COPY}    || fail "stderr corrupt"
+
+rm -f ${DATA} ${COPY}
diff --git a/regress/stderr-data.sh b/regress/stderr-data.sh
new file mode 100644 (file)
index 0000000..1daf79b
--- /dev/null
@@ -0,0 +1,33 @@
+#      $OpenBSD: stderr-data.sh,v 1.2 2002/03/27 22:39:52 markus Exp $
+#      Placed in the Public Domain.
+
+tid="stderr data transfer"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+rm -f ${COPY}
+
+for n in '' -n; do
+for p in 1 2; do
+       verbose "test $tid: proto $p ($n)"
+       ${SSH} $n -$p -F $OBJ/ssh_proxy otherhost \
+               exec sh -c \'"exec > /dev/null; sleep 3; cat ${DATA} 1>&2 $s"\' \
+               2> ${COPY}
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh failed with exit code $r"
+       fi
+       cmp ${DATA} ${COPY}     || fail "stderr corrupt"
+       rm -f ${COPY}
+
+       ${SSH} $n -$p -F $OBJ/ssh_proxy otherhost \
+               exec sh -c \'"echo a; exec > /dev/null; sleep 3; cat ${DATA} 1>&2 $s"\' \
+               > /dev/null 2> ${COPY}
+       r=$?
+       if [ $r -ne 0 ]; then
+               fail "ssh failed with exit code $r"
+       fi
+       cmp ${DATA} ${COPY}     || fail "stderr corrupt"
+       rm -f ${COPY}
+done
+done
diff --git a/regress/t4.ok b/regress/t4.ok
new file mode 100644 (file)
index 0000000..8c4942b
--- /dev/null
@@ -0,0 +1 @@
+3b:dd:44:e9:49:18:84:95:f1:e7:33:6b:9d:93:b1:36
diff --git a/regress/t5.ok b/regress/t5.ok
new file mode 100644 (file)
index 0000000..bd622f3
--- /dev/null
@@ -0,0 +1 @@
+xokes-lylis-byleh-zebib-kalus-bihas-tevah-haroz-suhar-foved-noxex
diff --git a/regress/test-exec.sh b/regress/test-exec.sh
new file mode 100644 (file)
index 0000000..5c56aef
--- /dev/null
@@ -0,0 +1,397 @@
+#      $OpenBSD: test-exec.sh,v 1.37 2010/02/24 06:21:56 djm Exp $
+#      Placed in the Public Domain.
+
+#SUDO=sudo
+
+# Unbreak GNU head(1)
+_POSIX2_VERSION=199209
+export _POSIX2_VERSION
+
+case `uname -s 2>/dev/null` in
+OSF1*)
+       BIN_SH=xpg4
+       export BIN_SH
+       ;;
+esac
+
+if [ ! -z "$TEST_SSH_PORT" ]; then
+       PORT="$TEST_SSH_PORT"
+else
+       PORT=4242
+fi
+
+if [ -x /usr/ucb/whoami ]; then
+       USER=`/usr/ucb/whoami`
+elif whoami >/dev/null 2>&1; then
+       USER=`whoami`
+elif logname >/dev/null 2>&1; then
+       USER=`logname`
+else
+       USER=`id -un`
+fi
+
+OBJ=$1
+if [ "x$OBJ" = "x" ]; then
+       echo '$OBJ not defined'
+       exit 2
+fi
+if [ ! -d $OBJ ]; then
+       echo "not a directory: $OBJ"
+       exit 2
+fi
+SCRIPT=$2
+if [ "x$SCRIPT" = "x" ]; then
+       echo '$SCRIPT not defined'
+       exit 2
+fi
+if [ ! -f $SCRIPT ]; then
+       echo "not a file: $SCRIPT"
+       exit 2
+fi
+if $TEST_SHELL -n $SCRIPT; then
+       true
+else
+       echo "syntax error in $SCRIPT"
+       exit 2
+fi
+unset SSH_AUTH_SOCK
+
+SRC=`dirname ${SCRIPT}`
+
+# defaults
+SSH=ssh
+SSHD=sshd
+SSHAGENT=ssh-agent
+SSHADD=ssh-add
+SSHKEYGEN=ssh-keygen
+SSHKEYSCAN=ssh-keyscan
+SFTP=sftp
+SFTPSERVER=/usr/libexec/openssh/sftp-server
+SCP=scp
+
+# Interop testing
+PLINK=plink
+PUTTYGEN=puttygen
+CONCH=conch
+
+if [ "x$TEST_SSH_SSH" != "x" ]; then
+       SSH="${TEST_SSH_SSH}"
+fi
+if [ "x$TEST_SSH_SSHD" != "x" ]; then
+       SSHD="${TEST_SSH_SSHD}"
+fi
+if [ "x$TEST_SSH_SSHAGENT" != "x" ]; then
+       SSHAGENT="${TEST_SSH_SSHAGENT}"
+fi
+if [ "x$TEST_SSH_SSHADD" != "x" ]; then
+       SSHADD="${TEST_SSH_SSHADD}"
+fi
+if [ "x$TEST_SSH_SSHKEYGEN" != "x" ]; then
+       SSHKEYGEN="${TEST_SSH_SSHKEYGEN}"
+fi
+if [ "x$TEST_SSH_SSHKEYSCAN" != "x" ]; then
+       SSHKEYSCAN="${TEST_SSH_SSHKEYSCAN}"
+fi
+if [ "x$TEST_SSH_SFTP" != "x" ]; then
+       SFTP="${TEST_SSH_SFTP}"
+fi
+if [ "x$TEST_SSH_SFTPSERVER" != "x" ]; then
+       SFTPSERVER="${TEST_SSH_SFTPSERVER}"
+fi
+if [ "x$TEST_SSH_SCP" != "x" ]; then
+       SCP="${TEST_SSH_SCP}"
+fi
+if [ "x$TEST_SSH_PLINK" != "x" ]; then
+       # Find real binary, if it exists
+       case "${TEST_SSH_PLINK}" in
+       /*) PLINK="${TEST_SSH_PLINK}" ;;
+       *) PLINK=`which ${TEST_SSH_PLINK} 2>/dev/null` ;;
+       esac
+fi
+if [ "x$TEST_SSH_PUTTYGEN" != "x" ]; then
+       # Find real binary, if it exists
+       case "${TEST_SSH_PUTTYGEN}" in
+       /*) PUTTYGEN="${TEST_SSH_PUTTYGEN}" ;;
+       *) PUTTYGEN=`which ${TEST_SSH_PUTTYGEN} 2>/dev/null` ;;
+       esac
+fi
+if [ "x$TEST_SSH_CONCH" != "x" ]; then
+       # Find real binary, if it exists
+       case "${TEST_SSH_CONCH}" in
+       /*) CONCH="${TEST_SSH_CONCH}" ;;
+       *) CONCH=`which ${TEST_SSH_CONCH} 2>/dev/null` ;;
+       esac
+fi
+
+# Path to sshd must be absolute for rexec
+case "$SSHD" in
+/*) ;;
+*) SSHD=`which sshd` ;;
+esac
+
+if [ "x$TEST_SSH_LOGFILE" = "x" ]; then
+       TEST_SSH_LOGFILE=/dev/null
+fi
+
+# these should be used in tests
+export SSH SSHD SSHAGENT SSHADD SSHKEYGEN SSHKEYSCAN SFTP SFTPSERVER SCP
+#echo $SSH $SSHD $SSHAGENT $SSHADD $SSHKEYGEN $SSHKEYSCAN $SFTP $SFTPSERVER $SCP
+
+# helper
+echon()
+{
+       if [ "x`echo -n`" = "x" ]; then
+               echo -n "$@"
+       elif [ "x`echo '\c'`" = "x" ]; then
+               echo "$@\c"
+       else
+               fatal "Don't know how to echo without newline."
+       fi
+}
+
+have_prog()
+{
+       saved_IFS="$IFS"
+       IFS=":"
+       for i in $PATH
+       do
+               if [ -x $i/$1 ]; then
+                       IFS="$saved_IFS"
+                       return 0
+               fi
+       done
+       IFS="$saved_IFS"
+       return 1
+}
+
+cleanup ()
+{
+       if [ -f $PIDFILE ]; then
+               pid=`$SUDO cat $PIDFILE`
+               if [ "X$pid" = "X" ]; then
+                       echo no sshd running
+               else
+                       if [ $pid -lt 2 ]; then
+                               echo bad pid for ssh: $pid
+                       else
+                               $SUDO kill $pid
+                               trace "wait for sshd to exit"
+                               i=0;
+                               while [ -f $PIDFILE -a $i -lt 5 ]; do
+                                       i=`expr $i + 1`
+                                       sleep $i
+                               done
+                               test -f $PIDFILE && \
+                                   fatal "sshd didn't exit port $PORT pid $pid"
+                       fi
+               fi
+       fi
+}
+
+trace ()
+{
+       echo "trace: $@" >>$TEST_SSH_LOGFILE
+       if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
+               echo "$@"
+       fi
+}
+
+verbose ()
+{
+       echo "verbose: $@" >>$TEST_SSH_LOGFILE
+       if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
+               echo "$@"
+       fi
+}
+
+
+fail ()
+{
+       echo "FAIL: $@" >>$TEST_SSH_LOGFILE
+       RESULT=1
+       echo "$@"
+}
+
+fatal ()
+{
+       echo "FATAL: $@" >>$TEST_SSH_LOGFILE
+       echon "FATAL: "
+       fail "$@"
+       cleanup
+       exit $RESULT
+}
+
+# Check whether preprocessor symbols are defined in config.h.
+config_defined ()
+{
+       str=$1
+       while test "x$2" != "x" ; do
+               str="$str|$2"
+               shift
+       done
+       egrep "^#define.*($str)" ${BUILDDIR}/config.h >/dev/null 2>&1
+}
+
+RESULT=0
+PIDFILE=$OBJ/pidfile
+
+trap fatal 3 2
+
+# create server config
+cat << EOF > $OBJ/sshd_config
+       StrictModes             no
+       Port                    $PORT
+       Protocol                2,1
+       AddressFamily           inet
+       ListenAddress           127.0.0.1
+       #ListenAddress          ::1
+       PidFile                 $PIDFILE
+       AuthorizedKeysFile      $OBJ/authorized_keys_%u
+       LogLevel                VERBOSE
+       AcceptEnv               _XXX_TEST_*
+       AcceptEnv               _XXX_TEST
+       Subsystem       sftp    $SFTPSERVER
+EOF
+
+if [ ! -z "$TEST_SSH_SSHD_CONFOPTS" ]; then
+       trace "adding sshd_config option $TEST_SSH_SSHD_CONFOPTS"
+       echo "$TEST_SSH_SSHD_CONFOPTS" >> $OBJ/sshd_config
+fi
+
+# server config for proxy connects
+cp $OBJ/sshd_config $OBJ/sshd_proxy
+
+# allow group-writable directories in proxy-mode
+echo 'StrictModes no' >> $OBJ/sshd_proxy
+
+# create client config
+cat << EOF > $OBJ/ssh_config
+Host *
+       Protocol                2,1
+       Hostname                127.0.0.1
+       HostKeyAlias            localhost-with-alias
+       Port                    $PORT
+       User                    $USER
+       GlobalKnownHostsFile    $OBJ/known_hosts
+       UserKnownHostsFile      $OBJ/known_hosts
+       RSAAuthentication       yes
+       PubkeyAuthentication    yes
+       ChallengeResponseAuthentication no
+       HostbasedAuthentication no
+       PasswordAuthentication  no
+       BatchMode               yes
+       StrictHostKeyChecking   yes
+EOF
+
+if [ ! -z "$TEST_SSH_SSH_CONFOPTS" ]; then
+       trace "adding ssh_config option $TEST_SSH_SSHD_CONFOPTS"
+       echo "$TEST_SSH_SSH_CONFOPTS" >> $OBJ/ssh_config
+fi
+
+rm -f $OBJ/known_hosts $OBJ/authorized_keys_$USER
+
+trace "generate keys"
+for t in rsa rsa1; do
+       # generate user key
+       rm -f $OBJ/$t
+       ${SSHKEYGEN} -b 1024 -q -N '' -t $t  -f $OBJ/$t ||\
+               fail "ssh-keygen for $t failed"
+
+       # known hosts file for client
+       (
+               echon 'localhost-with-alias,127.0.0.1,::1 '
+               cat $OBJ/$t.pub
+       ) >> $OBJ/known_hosts
+
+       # setup authorized keys
+       cat $OBJ/$t.pub >> $OBJ/authorized_keys_$USER
+       echo IdentityFile $OBJ/$t >> $OBJ/ssh_config
+
+       # use key as host key, too
+       $SUDO cp $OBJ/$t $OBJ/host.$t
+       echo HostKey $OBJ/host.$t >> $OBJ/sshd_config
+
+       # don't use SUDO for proxy connect
+       echo HostKey $OBJ/$t >> $OBJ/sshd_proxy
+done
+chmod 644 $OBJ/authorized_keys_$USER
+
+# Activate Twisted Conch tests if the binary is present
+REGRESS_INTEROP_CONCH=no
+if test -x "$CONCH" ; then
+       REGRESS_INTEROP_CONCH=yes
+fi
+
+# If PuTTY is present and we are running a PuTTY test, prepare keys and
+# configuration
+REGRESS_INTEROP_PUTTY=no
+if test -x "$PUTTYGEN" -a -x "$PLINK" ; then
+       REGRESS_INTEROP_PUTTY=yes
+fi
+case "$SCRIPT" in
+*putty*)       ;;
+*)             REGRESS_INTEROP_PUTTY=no ;;
+esac
+
+if test "$REGRESS_INTEROP_PUTTY" = "yes" ; then
+       mkdir -p ${OBJ}/.putty
+
+       # Add a PuTTY key to authorized_keys
+       rm -f ${OBJ}/putty.rsa2
+       puttygen -t rsa -o ${OBJ}/putty.rsa2 < /dev/null > /dev/null
+       puttygen -O public-openssh ${OBJ}/putty.rsa2 \
+           >> $OBJ/authorized_keys_$USER
+
+       # Convert rsa2 host key to PuTTY format
+       ${SRC}/ssh2putty.sh 127.0.0.1 $PORT $OBJ/rsa > \
+           ${OBJ}/.putty/sshhostkeys
+       ${SRC}/ssh2putty.sh 127.0.0.1 22 $OBJ/rsa >> \
+           ${OBJ}/.putty/sshhostkeys
+
+       # Setup proxied session
+       mkdir -p ${OBJ}/.putty/sessions
+       rm -f ${OBJ}/.putty/sessions/localhost_proxy
+       echo "Hostname=127.0.0.1" >> ${OBJ}/.putty/sessions/localhost_proxy
+       echo "PortNumber=$PORT" >> ${OBJ}/.putty/sessions/localhost_proxy
+       echo "ProxyMethod=5" >> ${OBJ}/.putty/sessions/localhost_proxy
+       echo "ProxyTelnetCommand=sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSH_LOGFILE} -i -f $OBJ/sshd_proxy" >> ${OBJ}/.putty/sessions/localhost_proxy 
+
+       REGRESS_INTEROP_PUTTY=yes
+fi
+
+# create a proxy version of the client config
+(
+       cat $OBJ/ssh_config
+       echo proxycommand ${SUDO} sh ${SRC}/sshd-log-wrapper.sh ${SSHD} ${TEST_SSH_LOGFILE} -i -f $OBJ/sshd_proxy
+) > $OBJ/ssh_proxy
+
+# check proxy config
+${SSHD} -t -f $OBJ/sshd_proxy  || fatal "sshd_proxy broken"
+
+start_sshd ()
+{
+       # start sshd
+       $SUDO ${SSHD} -f $OBJ/sshd_config "$@" -t || fatal "sshd_config broken"
+       $SUDO ${SSHD} -f $OBJ/sshd_config -e "$@" >>$TEST_SSH_LOGFILE 2>&1
+
+       trace "wait for sshd"
+       i=0;
+       while [ ! -f $PIDFILE -a $i -lt 10 ]; do
+               i=`expr $i + 1`
+               sleep $i
+       done
+
+       test -f $PIDFILE || fatal "no sshd running on port $PORT"
+}
+
+# source test body
+. $SCRIPT
+
+# kill sshd
+cleanup
+if [ $RESULT -eq 0 ]; then
+       verbose ok $tid
+else
+       echo failed $tid
+fi
+exit $RESULT
diff --git a/regress/transfer.sh b/regress/transfer.sh
new file mode 100644 (file)
index 0000000..13ea367
--- /dev/null
@@ -0,0 +1,29 @@
+#      $OpenBSD: transfer.sh,v 1.1 2002/03/27 00:03:37 markus Exp $
+#      Placed in the Public Domain.
+
+tid="transfer data"
+
+DATA=/bin/ls${EXEEXT}
+COPY=${OBJ}/copy
+
+for p in 1 2; do
+       verbose "$tid: proto $p"
+       rm -f ${COPY}
+       ${SSH} -n -q -$p -F $OBJ/ssh_proxy somehost cat ${DATA} > ${COPY}
+       if [ $? -ne 0 ]; then
+               fail "ssh cat $DATA failed"
+       fi
+       cmp ${DATA} ${COPY}             || fail "corrupted copy"
+
+       for s in 10 100 1k 32k 64k 128k 256k; do
+               trace "proto $p dd-size ${s}"
+               rm -f ${COPY}
+               dd if=$DATA obs=${s} 2> /dev/null | \
+                       ${SSH} -q -$p -F $OBJ/ssh_proxy somehost "cat > ${COPY}"
+               if [ $? -ne 0 ]; then
+                       fail "ssh cat $DATA failed"
+               fi
+               cmp $DATA ${COPY}               || fail "corrupted copy"
+       done
+done
+rm -f ${COPY}
diff --git a/regress/try-ciphers.sh b/regress/try-ciphers.sh
new file mode 100644 (file)
index 0000000..ef776d2
--- /dev/null
@@ -0,0 +1,49 @@
+#      $OpenBSD: try-ciphers.sh,v 1.11 2007/06/07 19:41:46 pvalchev Exp $
+#      Placed in the Public Domain.
+
+tid="try ciphers"
+
+ciphers="aes128-cbc 3des-cbc blowfish-cbc cast128-cbc 
+       arcfour128 arcfour256 arcfour 
+       aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se
+       aes128-ctr aes192-ctr aes256-ctr"
+macs="hmac-sha1 hmac-md5 umac-64@openssh.com hmac-sha1-96 hmac-md5-96"
+
+for c in $ciphers; do
+       for m in $macs; do
+               trace "proto 2 cipher $c mac $m"
+               verbose "test $tid: proto 2 cipher $c mac $m"
+               ${SSH} -F $OBJ/ssh_proxy -2 -m $m -c $c somehost true
+               if [ $? -ne 0 ]; then
+                       fail "ssh -2 failed with mac $m cipher $c"
+               fi
+       done
+done
+
+ciphers="3des blowfish"
+for c in $ciphers; do
+       trace "proto 1 cipher $c"
+       verbose "test $tid: proto 1 cipher $c"
+       ${SSH} -F $OBJ/ssh_proxy -1 -c $c somehost true
+       if [ $? -ne 0 ]; then
+               fail "ssh -1 failed with cipher $c"
+       fi
+done
+
+if ${SSH} -oCiphers=acss@openssh.org 2>&1 | grep "Bad SSH2 cipher" >/dev/null
+then
+       :
+else
+
+echo "Ciphers acss@openssh.org" >> $OBJ/sshd_proxy
+c=acss@openssh.org
+for m in $macs; do
+       trace "proto 2 $c mac $m"
+       verbose "test $tid: proto 2 cipher $c mac $m"
+       ${SSH} -F $OBJ/ssh_proxy -2 -m $m -c $c somehost true
+       if [ $? -ne 0 ]; then
+               fail "ssh -2 failed with mac $m cipher $c"
+       fi
+done
+
+fi
diff --git a/regress/yes-head.sh b/regress/yes-head.sh
new file mode 100644 (file)
index 0000000..a8e6bc8
--- /dev/null
@@ -0,0 +1,15 @@
+#      $OpenBSD: yes-head.sh,v 1.4 2002/03/15 13:08:56 markus Exp $
+#      Placed in the Public Domain.
+
+tid="yes pipe head"
+
+for p in 1 2; do
+       lines=`${SSH} -$p -F $OBJ/ssh_proxy thishost 'sh -c "while true;do echo yes;done | _POSIX2_VERSION=199209 head -2000"' | (sleep 3 ; wc -l)`
+       if [ $? -ne 0 ]; then
+               fail "yes|head test failed"
+               lines = 0;
+       fi
+       if [ $lines -ne 2000 ]; then
+               fail "yes|head returns $lines lines instead of 2000"
+       fi
+done
diff --git a/rijndael.c b/rijndael.c
new file mode 100644 (file)
index 0000000..7432ea2
--- /dev/null
@@ -0,0 +1,1244 @@
+/*     $OpenBSD: rijndael.c,v 1.16 2004/06/23 00:39:38 mouring 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 "includes.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 do_encrypt)
+{
+       ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, bits);
+       if (do_encrypt) {
+               ctx->decrypt = 0;
+               memset(ctx->dk, 0, sizeof(ctx->dk));
+       } else {
+               ctx->decrypt = 1;
+               memcpy(ctx->dk, ctx->ek, sizeof(ctx->dk));
+               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/rijndael.h b/rijndael.h
new file mode 100644 (file)
index 0000000..c614bb1
--- /dev/null
@@ -0,0 +1,51 @@
+/*     $OpenBSD: rijndael.h,v 1.12 2001/12/19 07:18:56 deraadt 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/roaming.h b/roaming.h
new file mode 100644 (file)
index 0000000..6bb94cc
--- /dev/null
+++ b/roaming.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: roaming.h,v 1.5 2009/10/24 11:11:58 andreas Exp $ */
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ROAMING_H
+#define ROAMING_H
+
+#define DEFAULT_ROAMBUF 65536
+#define ROAMING_REQUEST "roaming@appgate.com"
+
+extern int roaming_enabled;
+extern int resume_in_progress;
+
+void   request_roaming(void);
+int    get_snd_buf_size(void);
+int    get_recv_buf_size(void);
+void   add_recv_bytes(u_int64_t);
+int    wait_for_roaming_reconnect(void);
+void   roaming_reply(int, u_int32_t, void *);
+void   set_out_buffer_size(size_t);
+ssize_t        roaming_write(int, const void *, size_t, int *);
+ssize_t        roaming_read(int, void *, size_t, int *);
+size_t roaming_atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+u_int64_t      get_recv_bytes(void);
+u_int64_t      get_sent_bytes(void);
+void   roam_set_bytes(u_int64_t, u_int64_t);
+void   resend_bytes(int, u_int64_t *);
+void   calculate_new_key(u_int64_t *, u_int64_t, u_int64_t);
+int    resume_kex(void);
+
+#endif /* ROAMING */
diff --git a/roaming_client.c b/roaming_client.c
new file mode 100644 (file)
index 0000000..cea8e73
--- /dev/null
@@ -0,0 +1,280 @@
+/* $OpenBSD: roaming_client.c,v 1.3 2010/01/18 01:50:27 dtucker Exp $ */
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include "openbsd-compat/sys-queue.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/crypto.h>
+#include <openssl/sha.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "channels.h"
+#include "cipher.h"
+#include "dispatch.h"
+#include "clientloop.h"
+#include "log.h"
+#include "match.h"
+#include "misc.h"
+#include "packet.h"
+#include "ssh.h"
+#include "key.h"
+#include "kex.h"
+#include "readconf.h"
+#include "roaming.h"
+#include "ssh2.h"
+#include "sshconnect.h"
+
+/* import */
+extern Options options;
+extern char *host;
+extern struct sockaddr_storage hostaddr;
+extern int session_resumed;
+
+static u_int32_t roaming_id;
+static u_int64_t cookie;
+static u_int64_t lastseenchall;
+static u_int64_t key1, key2, oldkey1, oldkey2;
+
+void
+roaming_reply(int type, u_int32_t seq, void *ctxt)
+{
+       if (type == SSH2_MSG_REQUEST_FAILURE) {
+               logit("Server denied roaming");
+               return;
+       }
+       verbose("Roaming enabled");
+       roaming_id = packet_get_int();
+       cookie = packet_get_int64();
+       key1 = oldkey1 = packet_get_int64();
+       key2 = oldkey2 = packet_get_int64();
+       set_out_buffer_size(packet_get_int() +  get_snd_buf_size());
+       roaming_enabled = 1;
+}
+
+void
+request_roaming(void)
+{
+       packet_start(SSH2_MSG_GLOBAL_REQUEST);
+       packet_put_cstring(ROAMING_REQUEST);
+       packet_put_char(1);
+       packet_put_int(get_recv_buf_size());
+       packet_send();
+       client_register_global_confirm(roaming_reply, NULL);
+}
+
+static void
+roaming_auth_required(void)
+{
+       u_char digest[SHA_DIGEST_LENGTH];
+       EVP_MD_CTX md;
+       Buffer b;
+       const EVP_MD *evp_md = EVP_sha1();
+       u_int64_t chall, oldchall;
+
+       chall = packet_get_int64();
+       oldchall = packet_get_int64();
+       if (oldchall != lastseenchall) {
+               key1 = oldkey1;
+               key2 = oldkey2;
+       }
+       lastseenchall = chall;
+
+       buffer_init(&b);
+       buffer_put_int64(&b, cookie);
+       buffer_put_int64(&b, chall);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestFinal(&md, digest, NULL);
+       buffer_free(&b);
+
+       packet_start(SSH2_MSG_KEX_ROAMING_AUTH);
+       packet_put_int64(key1 ^ get_recv_bytes());
+       packet_put_raw(digest, sizeof(digest));
+       packet_send();
+
+       oldkey1 = key1;
+       oldkey2 = key2;
+       calculate_new_key(&key1, cookie, chall);
+       calculate_new_key(&key2, cookie, chall);
+
+       debug("Received %llu bytes", (unsigned long long)get_recv_bytes());
+       debug("Sent roaming_auth packet");
+}
+
+int
+resume_kex(void)
+{
+       /*
+        * This should not happen - if the client sends the kex method
+        * resume@appgate.com then the kex is done in roaming_resume().
+        */
+       return 1;
+}
+
+static int
+roaming_resume(void)
+{
+       u_int64_t recv_bytes;
+       char *str = NULL, *kexlist = NULL, *c;
+       int i, type;
+       int timeout_ms = options.connection_timeout * 1000;
+       u_int len;
+       u_int32_t rnd = 0;
+
+       resume_in_progress = 1;
+
+       /* Exchange banners */
+       ssh_exchange_identification(timeout_ms);
+       packet_set_nonblocking();
+
+       /* Send a kexinit message with resume@appgate.com as only kex algo */
+       packet_start(SSH2_MSG_KEXINIT);
+       for (i = 0; i < KEX_COOKIE_LEN; i++) {
+               if (i % 4 == 0)
+                       rnd = arc4random();
+               packet_put_char(rnd & 0xff);
+               rnd >>= 8;
+       }
+       packet_put_cstring(KEX_RESUME);
+       for (i = 1; i < PROPOSAL_MAX; i++) {
+               /* kex algorithm added so start with i=1 and not 0 */
+               packet_put_cstring(""); /* Not used when we resume */
+       }
+       packet_put_char(1); /* first kex_packet follows */
+       packet_put_int(0); /* reserved */
+       packet_send();
+
+       /* Assume that resume@appgate.com will be accepted */
+       packet_start(SSH2_MSG_KEX_ROAMING_RESUME);
+       packet_put_int(roaming_id);
+       packet_send();
+
+       /* Read the server's kexinit and check for resume@appgate.com */
+       if ((type = packet_read()) != SSH2_MSG_KEXINIT) {
+               debug("expected kexinit on resume, got %d", type);
+               goto fail;
+       }
+       for (i = 0; i < KEX_COOKIE_LEN; i++)
+               (void)packet_get_char();
+       kexlist = packet_get_string(&len);
+       if (!kexlist
+           || (str = match_list(KEX_RESUME, kexlist, NULL)) == NULL) {
+               debug("server doesn't allow resume");
+               goto fail;
+       }
+       xfree(str);
+       for (i = 1; i < PROPOSAL_MAX; i++) {
+               /* kex algorithm taken care of so start with i=1 and not 0 */
+               xfree(packet_get_string(&len));
+       }
+       i = packet_get_char(); /* first_kex_packet_follows */
+       if (i && (c = strchr(kexlist, ',')))
+               *c = 0;
+       if (i && strcmp(kexlist, KEX_RESUME)) {
+               debug("server's kex guess (%s) was wrong, skipping", kexlist);
+               (void)packet_read(); /* Wrong guess - discard packet */
+       }
+
+       /*
+        * Read the ROAMING_AUTH_REQUIRED challenge from the server and
+        * send ROAMING_AUTH
+        */
+       if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED) {
+               debug("expected roaming_auth_required, got %d", type);
+               goto fail;
+       }
+       roaming_auth_required();
+
+       /* Read ROAMING_AUTH_OK from the server */
+       if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_OK) {
+               debug("expected roaming_auth_ok, got %d", type);
+               goto fail;
+       }
+       recv_bytes = packet_get_int64() ^ oldkey2;
+       debug("Peer received %llu bytes", (unsigned long long)recv_bytes);
+       resend_bytes(packet_get_connection_out(), &recv_bytes);
+
+       resume_in_progress = 0;
+
+       session_resumed = 1; /* Tell clientloop */
+
+       return 0;
+
+fail:
+       if (kexlist)
+               xfree(kexlist);
+       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());
+       }
+       return 1;
+}
+
+int
+wait_for_roaming_reconnect(void)
+{
+       static int reenter_guard = 0;
+       int timeout_ms = options.connection_timeout * 1000;
+       int c;
+
+       if (reenter_guard != 0)
+               fatal("Server refused resume, roaming timeout may be exceeded");
+       reenter_guard = 1;
+
+       fprintf(stderr, "[connection suspended, press return to resume]");
+       fflush(stderr);
+       packet_backup_state();
+       /* TODO Perhaps we should read from tty here */
+       while ((c = fgetc(stdin)) != EOF) {
+               if (c == 'Z' - 64) {
+                       kill(getpid(), SIGTSTP);
+                       continue;
+               }
+               if (c != '\n' && c != '\r')
+                       continue;
+
+               if (ssh_connect(host, &hostaddr, options.port,
+                   options.address_family, 1, &timeout_ms,
+                   options.tcp_keep_alive, options.use_privileged_port,
+                   options.proxy_command) == 0 && roaming_resume() == 0) {
+                       packet_restore_state();
+                       reenter_guard = 0;
+                       fprintf(stderr, "[connection resumed]\n");
+                       fflush(stderr);
+                       return 0;
+               }
+
+               fprintf(stderr, "[reconnect failed, press return to retry]");
+               fflush(stderr);
+       }
+       fprintf(stderr, "[exiting]\n");
+       fflush(stderr);
+       exit(0);
+}
diff --git a/roaming_common.c b/roaming_common.c
new file mode 100644 (file)
index 0000000..9adbe56
--- /dev/null
@@ -0,0 +1,244 @@
+/* $OpenBSD: roaming_common.c,v 1.8 2010/01/12 00:59:29 djm Exp $ */
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+#include "log.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "cipher.h"
+#include "buffer.h"
+#include "roaming.h"
+
+static size_t out_buf_size = 0;
+static char *out_buf = NULL;
+static size_t out_start;
+static size_t out_last;
+
+static u_int64_t write_bytes = 0;
+static u_int64_t read_bytes = 0;
+
+int roaming_enabled = 0;
+int resume_in_progress = 0;
+
+int
+get_snd_buf_size()
+{
+       int fd = packet_get_connection_out();
+       int optval;
+       socklen_t optvallen = sizeof(optval);
+
+       if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optvallen) != 0)
+               optval = DEFAULT_ROAMBUF;
+       return optval;
+}
+
+int
+get_recv_buf_size()
+{
+       int fd = packet_get_connection_in();
+       int optval;
+       socklen_t optvallen = sizeof(optval);
+
+       if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &optvallen) != 0)
+               optval = DEFAULT_ROAMBUF;
+       return optval;
+}
+
+void
+set_out_buffer_size(size_t size)
+{
+       /*
+        * The buffer size can only be set once and the buffer will live
+        * as long as the session lives.
+        */
+       if (out_buf == NULL) {
+               out_buf_size = size;
+               out_buf = xmalloc(size);
+               out_start = 0;
+               out_last = 0;
+       }
+}
+
+u_int64_t
+get_recv_bytes(void)
+{
+       return read_bytes;
+}
+
+void
+add_recv_bytes(u_int64_t num)
+{
+       read_bytes += num;
+}
+
+u_int64_t
+get_sent_bytes(void)
+{
+       return write_bytes;
+}
+
+void
+roam_set_bytes(u_int64_t sent, u_int64_t recvd)
+{
+       read_bytes = recvd;
+       write_bytes = sent;
+}
+
+static void
+buf_append(const char *buf, size_t count)
+{
+       if (count > out_buf_size) {
+               buf += count - out_buf_size;
+               count = out_buf_size;
+       }
+       if (count < out_buf_size - out_last) {
+               memcpy(out_buf + out_last, buf, count);
+               if (out_start > out_last)
+                       out_start += count;
+               out_last += count;
+       } else {
+               /* data will wrap */
+               size_t chunk = out_buf_size - out_last;
+               memcpy(out_buf + out_last, buf, chunk);
+               memcpy(out_buf, buf + chunk, count - chunk);
+               out_last = count - chunk;
+               out_start = out_last + 1;
+       }
+}
+
+ssize_t
+roaming_write(int fd, const void *buf, size_t count, int *cont)
+{
+       ssize_t ret;
+
+       ret = write(fd, buf, count);
+       if (ret > 0 && !resume_in_progress) {
+               write_bytes += ret;
+               if (out_buf_size > 0)
+                       buf_append(buf, ret);
+       }
+       if (out_buf_size > 0 &&
+           (ret == 0 || (ret == -1 && errno == EPIPE))) {
+               if (wait_for_roaming_reconnect() != 0) {
+                       ret = 0;
+                       *cont = 1;
+               } else {
+                       ret = -1;
+                       errno = EAGAIN;
+               }
+       }
+       return ret;
+}
+
+ssize_t
+roaming_read(int fd, void *buf, size_t count, int *cont)
+{
+       ssize_t ret = read(fd, buf, count);
+       if (ret > 0) {
+               if (!resume_in_progress) {
+                       read_bytes += ret;
+               }
+       } else if (out_buf_size > 0 &&
+           (ret == 0 || (ret == -1 && (errno == ECONNRESET
+           || errno == ECONNABORTED || errno == ETIMEDOUT
+           || errno == EHOSTUNREACH)))) {
+               debug("roaming_read failed for %d  ret=%ld  errno=%d",
+                   fd, (long)ret, errno);
+               ret = 0;
+               if (wait_for_roaming_reconnect() == 0)
+                       *cont = 1;
+       }
+       return ret;
+}
+
+size_t
+roaming_atomicio(ssize_t(*f)(int, void*, size_t), int fd, void *buf,
+    size_t count)
+{
+       size_t ret = atomicio(f, fd, buf, count);
+
+       if (f == vwrite && ret > 0 && !resume_in_progress) {
+               write_bytes += ret;
+       } else if (f == read && ret > 0 && !resume_in_progress) {
+               read_bytes += ret;
+       }
+       return ret;
+}
+
+void
+resend_bytes(int fd, u_int64_t *offset)
+{
+       size_t available, needed;
+
+       if (out_start < out_last)
+               available = out_last - out_start;
+       else
+               available = out_buf_size;
+       needed = write_bytes - *offset;
+       debug3("resend_bytes: resend %lu bytes from %llu",
+           (unsigned long)needed, (unsigned long long)*offset);
+       if (needed > available)
+               fatal("Needed to resend more data than in the cache");
+       if (out_last < needed) {
+               int chunkend = needed - out_last;
+               atomicio(vwrite, fd, out_buf + out_buf_size - chunkend,
+                   chunkend);
+               atomicio(vwrite, fd, out_buf, out_last);
+       } else {
+               atomicio(vwrite, fd, out_buf + (out_last - needed), needed);
+       }
+}
+
+/*
+ * Caclulate a new key after a reconnect
+ */
+void
+calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge)
+{
+       const EVP_MD *md = EVP_sha1();
+       EVP_MD_CTX ctx;
+       char hash[EVP_MAX_MD_SIZE];
+       Buffer b;
+
+       buffer_init(&b);
+       buffer_put_int64(&b, *key);
+       buffer_put_int64(&b, cookie);
+       buffer_put_int64(&b, challenge);
+
+       EVP_DigestInit(&ctx, md);
+       EVP_DigestUpdate(&ctx, buffer_ptr(&b), buffer_len(&b));
+       EVP_DigestFinal(&ctx, hash, NULL);
+
+       buffer_clear(&b);
+       buffer_append(&b, hash, EVP_MD_size(md));
+       *key = buffer_get_int64(&b);
+       buffer_free(&b);
+}
diff --git a/roaming_dummy.c b/roaming_dummy.c
new file mode 100644 (file)
index 0000000..45c4008
--- /dev/null
@@ -0,0 +1,61 @@
+/* $OpenBSD: roaming_dummy.c,v 1.3 2009/06/21 09:04:03 dtucker Exp $ */
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file is included in the client programs which should not
+ * support roaming.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "roaming.h"
+
+int resume_in_progress = 0;
+
+u_int64_t
+get_recv_bytes(void)
+{
+       return 0;
+}
+
+ssize_t
+roaming_write(int fd, const void *buf, size_t count, int *cont)
+{
+       return write(fd, buf, count);
+}
+
+ssize_t
+roaming_read(int fd, void *buf, size_t count, int *cont)
+{
+       if (cont)
+               *cont = 0;
+       return read(fd, buf, count);
+}
+
+void
+add_recv_bytes(u_int64_t num)
+{
+}
+
+int
+resume_kex(void)
+{
+       return 1;
+}
diff --git a/roaming_serv.c b/roaming_serv.c
new file mode 100644 (file)
index 0000000..511ca84
--- /dev/null
@@ -0,0 +1,31 @@
+/* $OpenBSD: roaming_serv.c,v 1.1 2009/10/24 11:18:23 andreas Exp $ */
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include "roaming.h"
+
+/*
+ * Wait for the roaming client to reconnect. Returns 0 if a connect ocurred.
+ */
+int
+wait_for_roaming_reconnect(void)
+{
+       return 1;
+}
diff --git a/rsa.c b/rsa.c
new file mode 100644 (file)
index 0000000..bec1d19
--- /dev/null
+++ b/rsa.c
@@ -0,0 +1,151 @@
+/* $OpenBSD: rsa.c,v 1.29 2006/11/06 21:25:28 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) 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"
+
+#include <sys/types.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "rsa.h"
+#include "log.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");
+
+       if (BN_bin2bn(outbuf, len, out) == NULL)
+               fatal("rsa_public_encrypt: BN_bin2bn failed");
+
+       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 {
+               if (BN_bin2bn(outbuf, len, out) == NULL)
+                       fatal("rsa_private_decrypt: BN_bin2bn failed");
+       }
+       memset(outbuf, 0, olen);
+       memset(inbuf, 0, ilen);
+       xfree(outbuf);
+       xfree(inbuf);
+       return len;
+}
+
+/* calculate p-1 and q-1 */
+void
+rsa_generate_additional_parameters(RSA *rsa)
+{
+       BIGNUM *aux;
+       BN_CTX *ctx;
+
+       if ((aux = BN_new()) == NULL)
+               fatal("rsa_generate_additional_parameters: BN_new failed");
+       if ((ctx = BN_CTX_new()) == NULL)
+               fatal("rsa_generate_additional_parameters: BN_CTX_new failed");
+
+       if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
+           (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
+           (BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
+           (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0))
+               fatal("rsa_generate_additional_parameters: BN_sub/mod failed");
+
+       BN_clear_free(aux);
+       BN_CTX_free(ctx);
+}
+
diff --git a/rsa.h b/rsa.h
new file mode 100644 (file)
index 0000000..b841ea4
--- /dev/null
+++ b/rsa.h
@@ -0,0 +1,26 @@
+/* $OpenBSD: rsa.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#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/schnorr.c b/schnorr.c
new file mode 100644 (file)
index 0000000..4d54d68
--- /dev/null
+++ b/schnorr.c
@@ -0,0 +1,675 @@
+/* $OpenBSD: schnorr.c,v 1.5 2010/12/03 23:49:26 djm Exp $ */
+/*
+ * Copyright (c) 2008 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Implementation of Schnorr signatures / zero-knowledge proofs, based on
+ * description in:
+ *     
+ * F. Hao, P. Ryan, "Password Authenticated Key Exchange by Juggling",
+ * 16th Workshop on Security Protocols, Cambridge, April 2008
+ *
+ * http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+
+#include "schnorr.h"
+
+#include "openbsd-compat/openssl-compat.h"
+
+/* #define SCHNORR_DEBUG */            /* Privacy-violating debugging */
+/* #define SCHNORR_MAIN */             /* Include main() selftest */
+
+#ifndef SCHNORR_DEBUG
+# define SCHNORR_DEBUG_BN(a)
+# define SCHNORR_DEBUG_BUF(a)
+#else
+# define SCHNORR_DEBUG_BN(a)   debug3_bn a
+# define SCHNORR_DEBUG_BUF(a)  debug3_buf a
+#endif /* SCHNORR_DEBUG */
+
+/*
+ * Calculate hash component of Schnorr signature H(g || g^v || g^x || id)
+ * using the hash function defined by "evp_md". Returns signature as
+ * bignum or NULL on error.
+ */
+static BIGNUM *
+schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g,
+    const EVP_MD *evp_md, const BIGNUM *g_v, const BIGNUM *g_x,
+    const u_char *id, u_int idlen)
+{
+       u_char *digest;
+       u_int digest_len;
+       BIGNUM *h;
+       Buffer b;
+       int success = -1;
+
+       if ((h = BN_new()) == NULL) {
+               error("%s: BN_new", __func__);
+               return NULL;
+       }
+
+       buffer_init(&b);
+
+       /* h = H(g || p || q || g^v || g^x || id) */
+       buffer_put_bignum2(&b, g);
+       buffer_put_bignum2(&b, p);
+       buffer_put_bignum2(&b, q);
+       buffer_put_bignum2(&b, g_v);
+       buffer_put_bignum2(&b, g_x);
+       buffer_put_string(&b, id, idlen);
+
+       SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
+           "%s: hashblob", __func__));
+       if (hash_buffer(buffer_ptr(&b), buffer_len(&b), evp_md,
+           &digest, &digest_len) != 0) {
+               error("%s: hash_buffer", __func__);
+               goto out;
+       }
+       if (BN_bin2bn(digest, (int)digest_len, h) == NULL) {
+               error("%s: BN_bin2bn", __func__);
+               goto out;
+       }
+       success = 0;
+       SCHNORR_DEBUG_BN((h, "%s: h = ", __func__));
+ out:
+       buffer_free(&b);
+       bzero(digest, digest_len);
+       xfree(digest);
+       digest_len = 0;
+       if (success == 0)
+               return h;
+       BN_clear_free(h);
+       return NULL;
+}
+
+/*
+ * Generate Schnorr signature to prove knowledge of private value 'x' used
+ * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g'
+ * using the hash function "evp_md".
+ * 'idlen' bytes from 'id' will be included in the signature hash as an anti-
+ * replay salt.
+ * 
+ * On success, 0 is returned. The signature values are returned as *e_p
+ * (g^v mod p) and *r_p (v - xh mod q). The caller must free these values.
+ * On failure, -1 is returned.
+ */
+int
+schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x,
+    const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p)
+{
+       int success = -1;
+       BIGNUM *h, *tmp, *v, *g_v, *r;
+       BN_CTX *bn_ctx;
+
+       SCHNORR_DEBUG_BN((x, "%s: x = ", __func__));
+       SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__));
+
+       /* Avoid degenerate cases: g^0 yields a spoofable signature */
+       if (BN_cmp(g_x, BN_value_one()) <= 0) {
+               error("%s: g_x < 1", __func__);
+               return -1;
+       }
+       if (BN_cmp(g_x, grp_p) >= 0) {
+               error("%s: g_x > g", __func__);
+               return -1;
+       }
+
+       h = g_v = r = tmp = v = NULL;
+       if ((bn_ctx = BN_CTX_new()) == NULL) {
+               error("%s: BN_CTX_new", __func__);
+               goto out;
+       }
+       if ((g_v = BN_new()) == NULL ||
+           (r = BN_new()) == NULL ||
+           (tmp = BN_new()) == NULL) {
+               error("%s: BN_new", __func__);
+               goto out;
+       }
+
+       /*
+        * v must be a random element of Zq, so 1 <= v < q
+        * we also exclude v = 1, since g^1 looks dangerous
+        */
+       if ((v = bn_rand_range_gt_one(grp_p)) == NULL) {
+               error("%s: bn_rand_range2", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((v, "%s: v = ", __func__));
+
+       /* g_v = g^v mod p */
+       if (BN_mod_exp(g_v, grp_g, v, grp_p, bn_ctx) == -1) {
+               error("%s: BN_mod_exp (g^v mod p)", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__));
+
+       /* h = H(g || g^v || g^x || id) */
+       if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, g_v, g_x,
+           id, idlen)) == NULL) {
+               error("%s: schnorr_hash failed", __func__);
+               goto out;
+       }
+
+       /* r = v - xh mod q */
+       if (BN_mod_mul(tmp, x, h, grp_q, bn_ctx) == -1) {
+               error("%s: BN_mod_mul (tmp = xv mod q)", __func__);
+               goto out;
+       }
+       if (BN_mod_sub(r, v, tmp, grp_q, bn_ctx) == -1) {
+               error("%s: BN_mod_mul (r = v - tmp)", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((g_v, "%s: e = ", __func__));
+       SCHNORR_DEBUG_BN((r, "%s: r = ", __func__));
+
+       *e_p = g_v;
+       *r_p = r;
+
+       success = 0;
+ out:
+       BN_CTX_free(bn_ctx);
+       if (h != NULL)
+               BN_clear_free(h);
+       if (v != NULL)
+               BN_clear_free(v);
+       BN_clear_free(tmp);
+
+       return success;
+}
+
+/*
+ * Generate Schnorr signature to prove knowledge of private value 'x' used
+ * in public exponent g^x, under group defined by 'grp_p', 'grp_q' and 'grp_g'
+ * using a SHA256 hash.
+ * 'idlen' bytes from 'id' will be included in the signature hash as an anti-
+ * replay salt.
+ * On success, 0 is returned and *siglen bytes of signature are returned in
+ * *sig (caller to free). Returns -1 on failure.
+ */
+int
+schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen,
+    u_char **sig, u_int *siglen)
+{
+       Buffer b;
+       BIGNUM *r, *e;
+
+       if (schnorr_sign(grp_p, grp_q, grp_g, EVP_sha256(),
+           x, g_x, id, idlen, &r, &e) != 0)
+               return -1;
+
+       /* Signature is (e, r) */
+       buffer_init(&b);
+       /* XXX sigtype-hash as string? */
+       buffer_put_bignum2(&b, e);
+       buffer_put_bignum2(&b, r);
+       *siglen = buffer_len(&b);
+       *sig = xmalloc(*siglen);
+       memcpy(*sig, buffer_ptr(&b), *siglen);
+       SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
+           "%s: sigblob", __func__));
+       buffer_free(&b);
+
+       BN_clear_free(r);
+       BN_clear_free(e);
+
+       return 0;
+}
+
+/*
+ * Verify Schnorr signature { r (v - xh mod q), e (g^v mod p) } against
+ * public exponent g_x (g^x) under group defined by 'grp_p', 'grp_q' and
+ * 'grp_g' using hash "evp_md".
+ * Signature hash will be salted with 'idlen' bytes from 'id'.
+ * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature.
+ */
+int
+schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen,
+    const BIGNUM *r, const BIGNUM *e)
+{
+       int success = -1;
+       BIGNUM *h = NULL, *g_xh = NULL, *g_r = NULL, *gx_q = NULL;
+       BIGNUM *expected = NULL;
+       BN_CTX *bn_ctx;
+
+       SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__));
+
+       /* Avoid degenerate cases: g^0 yields a spoofable signature */
+       if (BN_cmp(g_x, BN_value_one()) <= 0) {
+               error("%s: g_x <= 1", __func__);
+               return -1;
+       }
+       if (BN_cmp(g_x, grp_p) >= 0) {
+               error("%s: g_x >= p", __func__);
+               return -1;
+       }
+
+       h = g_xh = g_r = expected = NULL;
+       if ((bn_ctx = BN_CTX_new()) == NULL) {
+               error("%s: BN_CTX_new", __func__);
+               goto out;
+       }
+       if ((g_xh = BN_new()) == NULL ||
+           (g_r = BN_new()) == NULL ||
+           (gx_q = BN_new()) == NULL ||
+           (expected = BN_new()) == NULL) {
+               error("%s: BN_new", __func__);
+               goto out;
+       }
+
+       SCHNORR_DEBUG_BN((e, "%s: e = ", __func__));
+       SCHNORR_DEBUG_BN((r, "%s: r = ", __func__));
+
+       /* gx_q = (g^x)^q must === 1 mod p */
+       if (BN_mod_exp(gx_q, g_x, grp_q, grp_p, bn_ctx) == -1) {
+               error("%s: BN_mod_exp (g_x^q mod p)", __func__);
+               goto out;
+       }
+       if (BN_cmp(gx_q, BN_value_one()) != 0) {
+               error("%s: Invalid signature (g^x)^q != 1 mod p", __func__);
+               goto out;
+       }
+
+       SCHNORR_DEBUG_BN((g_xh, "%s: g_xh = ", __func__));
+       /* h = H(g || g^v || g^x || id) */
+       if ((h = schnorr_hash(grp_p, grp_q, grp_g, evp_md, e, g_x,
+           id, idlen)) == NULL) {
+               error("%s: schnorr_hash failed", __func__);
+               goto out;
+       }
+
+       /* g_xh = (g^x)^h */
+       if (BN_mod_exp(g_xh, g_x, h, grp_p, bn_ctx) == -1) {
+               error("%s: BN_mod_exp (g_x^h mod p)", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((g_xh, "%s: g_xh = ", __func__));
+
+       /* g_r = g^r */
+       if (BN_mod_exp(g_r, grp_g, r, grp_p, bn_ctx) == -1) {
+               error("%s: BN_mod_exp (g_x^h mod p)", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((g_r, "%s: g_r = ", __func__));
+
+       /* expected = g^r * g_xh */
+       if (BN_mod_mul(expected, g_r, g_xh, grp_p, bn_ctx) == -1) {
+               error("%s: BN_mod_mul (expected = g_r mod p)", __func__);
+               goto out;
+       }
+       SCHNORR_DEBUG_BN((expected, "%s: expected = ", __func__));
+
+       /* Check e == expected */
+       success = BN_cmp(expected, e) == 0;
+ out:
+       BN_CTX_free(bn_ctx);
+       if (h != NULL)
+               BN_clear_free(h);
+       if (gx_q != NULL)
+               BN_clear_free(gx_q);
+       if (g_xh != NULL)
+               BN_clear_free(g_xh);
+       if (g_r != NULL)
+               BN_clear_free(g_r);
+       if (expected != NULL)
+               BN_clear_free(expected);
+       return success;
+}
+
+/*
+ * Verify Schnorr signature 'sig' of length 'siglen' against public exponent
+ * g_x (g^x) under group defined by 'grp_p', 'grp_q' and 'grp_g' using a
+ * SHA256 hash.
+ * Signature hash will be salted with 'idlen' bytes from 'id'.
+ * Returns -1 on failure, 0 on incorrect signature or 1 on matching signature.
+ */
+int
+schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q,
+    const BIGNUM *grp_g,
+    const BIGNUM *g_x, const u_char *id, u_int idlen,
+    const u_char *sig, u_int siglen)
+{
+       Buffer b;
+       int ret = -1;
+       u_int rlen;
+       BIGNUM *r, *e;
+
+       e = r = NULL;
+       if ((e = BN_new()) == NULL ||
+           (r = BN_new()) == NULL) {
+               error("%s: BN_new", __func__);
+               goto out;
+       }
+
+       /* Extract g^v and r from signature blob */
+       buffer_init(&b);
+       buffer_append(&b, sig, siglen);
+       SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b),
+           "%s: sigblob", __func__));
+       buffer_get_bignum2(&b, e);
+       buffer_get_bignum2(&b, r);
+       rlen = buffer_len(&b);
+       buffer_free(&b);
+       if (rlen != 0) {
+               error("%s: remaining bytes in signature %d", __func__, rlen);
+               goto out;
+       }
+
+       ret = schnorr_verify(grp_p, grp_q, grp_g, EVP_sha256(),
+           g_x, id, idlen, r, e);
+ out:
+       BN_clear_free(e);
+       BN_clear_free(r);
+
+       return ret;
+}
+
+/* Helper functions */
+
+/*
+ * Generate uniformly distributed random number in range (1, high).
+ * Return number on success, NULL on failure.
+ */
+BIGNUM *
+bn_rand_range_gt_one(const BIGNUM *high)
+{
+       BIGNUM *r, *tmp;
+       int success = -1;
+
+       if ((tmp = BN_new()) == NULL) {
+               error("%s: BN_new", __func__);
+               return NULL;
+       }
+       if ((r = BN_new()) == NULL) {
+               error("%s: BN_new failed", __func__);
+               goto out;
+       }
+       if (BN_set_word(tmp, 2) != 1) {
+               error("%s: BN_set_word(tmp, 2)", __func__);
+               goto out;
+       }
+       if (BN_sub(tmp, high, tmp) == -1) {
+               error("%s: BN_sub failed (tmp = high - 2)", __func__);
+               goto out;
+       }
+       if (BN_rand_range(r, tmp) == -1) {
+               error("%s: BN_rand_range failed", __func__);
+               goto out;
+       }
+       if (BN_set_word(tmp, 2) != 1) {
+               error("%s: BN_set_word(tmp, 2)", __func__);
+               goto out;
+       }
+       if (BN_add(r, r, tmp) == -1) {
+               error("%s: BN_add failed (r = r + 2)", __func__);
+               goto out;
+       }
+       success = 0;
+ out:
+       BN_clear_free(tmp);
+       if (success == 0)
+               return r;
+       BN_clear_free(r);
+       return NULL;
+}
+
+/*
+ * Hash contents of buffer 'b' with hash 'md'. Returns 0 on success,
+ * with digest via 'digestp' (caller to free) and length via 'lenp'.
+ * Returns -1 on failure.
+ */
+int
+hash_buffer(const u_char *buf, u_int len, const EVP_MD *md,
+    u_char **digestp, u_int *lenp)
+{
+       u_char digest[EVP_MAX_MD_SIZE];
+       u_int digest_len;
+       EVP_MD_CTX evp_md_ctx;
+       int success = -1;
+
+       EVP_MD_CTX_init(&evp_md_ctx);
+
+       if (EVP_DigestInit_ex(&evp_md_ctx, md, NULL) != 1) {
+               error("%s: EVP_DigestInit_ex", __func__);
+               goto out;
+       }
+       if (EVP_DigestUpdate(&evp_md_ctx, buf, len) != 1) {
+               error("%s: EVP_DigestUpdate", __func__);
+               goto out;
+       }
+       if (EVP_DigestFinal_ex(&evp_md_ctx, digest, &digest_len) != 1) {
+               error("%s: EVP_DigestFinal_ex", __func__);
+               goto out;
+       }
+       *digestp = xmalloc(digest_len);
+       *lenp = digest_len;
+       memcpy(*digestp, digest, *lenp);
+       success = 0;
+ out:
+       EVP_MD_CTX_cleanup(&evp_md_ctx);
+       bzero(digest, sizeof(digest));
+       digest_len = 0;
+       return success;
+}
+
+/* print formatted string followed by bignum */
+void
+debug3_bn(const BIGNUM *n, const char *fmt, ...)
+{
+       char *out, *h;
+       va_list args;
+
+       out = NULL;
+       va_start(args, fmt);
+       vasprintf(&out, fmt, args);
+       va_end(args);
+       if (out == NULL)
+               fatal("%s: vasprintf failed", __func__);
+
+       if (n == NULL)
+               debug3("%s(null)", out);
+       else {
+               h = BN_bn2hex(n);
+               debug3("%s0x%s", out, h);
+               free(h);
+       }
+       free(out);
+}
+
+/* print formatted string followed by buffer contents in hex */
+void
+debug3_buf(const u_char *buf, u_int len, const char *fmt, ...)
+{
+       char *out, h[65];
+       u_int i, j;
+       va_list args;
+
+       out = NULL;
+       va_start(args, fmt);
+       vasprintf(&out, fmt, args);
+       va_end(args);
+       if (out == NULL)
+               fatal("%s: vasprintf failed", __func__);
+
+       debug3("%s length %u%s", out, len, buf == NULL ? " (null)" : "");
+       free(out);
+       if (buf == NULL)
+               return;
+
+       *h = '\0';
+       for (i = j = 0; i < len; i++) {
+               snprintf(h + j, sizeof(h) - j, "%02x", buf[i]);
+               j += 2;
+               if (j >= sizeof(h) - 1 || i == len - 1) {
+                       debug3("    %s", h);
+                       *h = '\0';
+                       j = 0;
+               }
+       }
+}
+
+/*
+ * Construct a MODP group from hex strings p (which must be a safe
+ * prime) and g, automatically calculating subgroup q as (p / 2)
+ */
+struct modp_group *
+modp_group_from_g_and_safe_p(const char *grp_g, const char *grp_p)
+{
+       struct modp_group *ret;
+
+       ret = xmalloc(sizeof(*ret));
+       ret->p = ret->q = ret->g = NULL;
+       if (BN_hex2bn(&ret->p, grp_p) == 0 ||
+           BN_hex2bn(&ret->g, grp_g) == 0)
+               fatal("%s: BN_hex2bn", __func__);
+       /* Subgroup order is p/2 (p is a safe prime) */
+       if ((ret->q = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       if (BN_rshift1(ret->q, ret->p) != 1)
+               fatal("%s: BN_rshift1", __func__);
+
+       return ret;
+}
+
+void
+modp_group_free(struct modp_group *grp)
+{
+       if (grp->g != NULL)
+               BN_clear_free(grp->g);
+       if (grp->p != NULL)
+               BN_clear_free(grp->p);
+       if (grp->q != NULL)
+               BN_clear_free(grp->q);
+       bzero(grp, sizeof(*grp));
+       xfree(grp);
+}
+
+/* main() function for self-test */
+
+#ifdef SCHNORR_MAIN
+static void
+schnorr_selftest_one(const BIGNUM *grp_p, const BIGNUM *grp_q,
+    const BIGNUM *grp_g, const BIGNUM *x)
+{
+       BIGNUM *g_x;
+       u_char *sig;
+       u_int siglen;
+       BN_CTX *bn_ctx;
+
+       if ((bn_ctx = BN_CTX_new()) == NULL)
+               fatal("%s: BN_CTX_new", __func__);
+       if ((g_x = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       if (BN_mod_exp(g_x, grp_g, x, grp_p, bn_ctx) == -1)
+               fatal("%s: g_x", __func__);
+       if (schnorr_sign_buf(grp_p, grp_q, grp_g, x, g_x, "junk", 4,
+           &sig, &siglen))
+               fatal("%s: schnorr_sign", __func__);
+       if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4,
+           sig, siglen) != 1)
+               fatal("%s: verify fail", __func__);
+       if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "JUNK", 4,
+           sig, siglen) != 0)
+               fatal("%s: verify should have failed (bad ID)", __func__);
+       sig[4] ^= 1;
+       if (schnorr_verify_buf(grp_p, grp_q, grp_g, g_x, "junk", 4,
+           sig, siglen) != 0)
+               fatal("%s: verify should have failed (bit error)", __func__);
+       xfree(sig);
+       BN_free(g_x);
+       BN_CTX_free(bn_ctx);
+}
+
+static void
+schnorr_selftest(void)
+{
+       BIGNUM *x;
+       struct modp_group *grp;
+       u_int i;
+       char *hh;
+
+       grp = jpake_default_group();
+       if ((x = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+       SCHNORR_DEBUG_BN((grp->p, "%s: grp->p = ", __func__));
+       SCHNORR_DEBUG_BN((grp->q, "%s: grp->q = ", __func__));
+       SCHNORR_DEBUG_BN((grp->g, "%s: grp->g = ", __func__));
+
+       /* [1, 20) */
+       for (i = 1; i < 20; i++) {
+               printf("x = %u\n", i);
+               fflush(stdout);
+               if (BN_set_word(x, i) != 1)
+                       fatal("%s: set x word", __func__);
+               schnorr_selftest_one(grp->p, grp->q, grp->g, x);
+       }
+
+       /* 100 x random [0, p) */
+       for (i = 0; i < 100; i++) {
+               if (BN_rand_range(x, grp->p) != 1)
+                       fatal("%s: BN_rand_range", __func__);
+               hh = BN_bn2hex(x);
+               printf("x = (random) 0x%s\n", hh);
+               free(hh);
+               fflush(stdout);
+               schnorr_selftest_one(grp->p, grp->q, grp->g, x);
+       }
+
+       /* [q-20, q) */
+       if (BN_set_word(x, 20) != 1)
+               fatal("%s: BN_set_word (x = 20)", __func__);
+       if (BN_sub(x, grp->q, x) != 1)
+               fatal("%s: BN_sub (q - x)", __func__);
+       for (i = 0; i < 19; i++) {
+               hh = BN_bn2hex(x);
+               printf("x = (q - %d) 0x%s\n", 20 - i, hh);
+               free(hh);
+               fflush(stdout);
+               schnorr_selftest_one(grp->p, grp->q, grp->g, x);
+               if (BN_add(x, x, BN_value_one()) != 1)
+                       fatal("%s: BN_add (x + 1)", __func__);
+       }
+       BN_free(x);
+}
+
+int
+main(int argc, char **argv)
+{
+       log_init(argv[0], SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_USER, 1);
+
+       schnorr_selftest();
+       return 0;
+}
+#endif
+
diff --git a/schnorr.h b/schnorr.h
new file mode 100644 (file)
index 0000000..9730b47
--- /dev/null
+++ b/schnorr.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: schnorr.h,v 1.1 2009/03/05 07:18:19 djm Exp $ */
+/*
+ * Copyright (c) 2009 Damien Miller.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SCHNORR_H
+#define SCHNORR_H
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+
+struct modp_group {
+       BIGNUM *p, *q, *g;
+};
+
+BIGNUM *bn_rand_range_gt_one(const BIGNUM *high);
+int hash_buffer(const u_char *, u_int, const EVP_MD *, u_char **, u_int *);
+void debug3_bn(const BIGNUM *, const char *, ...)
+    __attribute__((__nonnull__ (2)))
+    __attribute__((format(printf, 2, 3)));
+void debug3_buf(const u_char *, u_int, const char *, ...)
+    __attribute__((__nonnull__ (3)))
+    __attribute__((format(printf, 3, 4)));
+struct modp_group *modp_group_from_g_and_safe_p(const char *, const char *);
+void modp_group_free(struct modp_group *);
+
+/* Signature and verification functions */
+int
+schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const EVP_MD *evp_md, const BIGNUM *x, const BIGNUM *g_x,
+    const u_char *id, u_int idlen, BIGNUM **r_p, BIGNUM **e_p);
+int
+schnorr_sign_buf(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen,
+    u_char **sig, u_int *siglen);
+int
+schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g,
+    const EVP_MD *evp_md, const BIGNUM *g_x, const u_char *id, u_int idlen,
+    const BIGNUM *r, const BIGNUM *e);
+int
+schnorr_verify_buf(const BIGNUM *grp_p, const BIGNUM *grp_q,
+    const BIGNUM *grp_g,
+    const BIGNUM *g_x, const u_char *id, u_int idlen,
+    const u_char *sig, u_int siglen);
+
+#endif /* JPAKE_H */
+
diff --git a/scp.0 b/scp.0
new file mode 100644 (file)
index 0000000..72467c8
--- /dev/null
+++ b/scp.0
@@ -0,0 +1,156 @@
+SCP(1)                     OpenBSD Reference Manual                     SCP(1)
+
+NAME
+     scp - secure copy (remote file copy program)
+
+SYNOPSIS
+     scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
+         [-l limit] [-o ssh_option] [-P port] [-S program]
+         [[user@]host1:]file1 ... [[user@]host2:]file2
+
+DESCRIPTION
+     scp copies files between hosts on a network.  It uses ssh(1) for data
+     transfer, and uses the same authentication and provides the same security
+     as ssh(1).  Unlike rcp(1), scp will ask for passwords or passphrases if
+     they are needed for authentication.
+
+     File names may contain a user and host specification to indicate that the
+     file is to be copied to/from that host.  Local file names can be made
+     explicit using absolute or relative pathnames to avoid scp treating file
+     names containing `:' as host specifiers.  Copies between two remote hosts
+     are also permitted.
+
+     The options are as follows:
+
+     -1      Forces scp to use protocol 1.
+
+     -2      Forces scp to use protocol 2.
+
+     -3      Copies between two remote hosts are transferred through the local
+             host.  Without this option the data is copied directly between
+             the two remote hosts.  Note that this option disables the
+             progress meter.
+
+     -4      Forces scp to use IPv4 addresses only.
+
+     -6      Forces scp to use IPv6 addresses only.
+
+     -B      Selects batch mode (prevents asking for passwords or
+             passphrases).
+
+     -C      Compression enable.  Passes the -C flag to ssh(1) to enable
+             compression.
+
+     -c cipher
+             Selects the cipher to use for encrypting the data transfer.  This
+             option is directly passed to ssh(1).
+
+     -F ssh_config
+             Specifies an alternative per-user configuration file for ssh.
+             This option is directly passed to ssh(1).
+
+     -i identity_file
+             Selects the file from which the identity (private key) for public
+             key authentication is read.  This option is directly passed to
+             ssh(1).
+
+     -l limit
+             Limits the used bandwidth, specified in Kbit/s.
+
+     -o ssh_option
+             Can be used to pass options to ssh in the format used in
+             ssh_config(5).  This is useful for specifying options for which
+             there is no separate scp command-line flag.  For full details of
+             the options listed below, and their possible values, see
+             ssh_config(5).
+
+                   AddressFamily
+                   BatchMode
+                   BindAddress
+                   ChallengeResponseAuthentication
+                   CheckHostIP
+                   Cipher
+                   Ciphers
+                   Compression
+                   CompressionLevel
+                   ConnectionAttempts
+                   ConnectTimeout
+                   ControlMaster
+                   ControlPath
+                   GlobalKnownHostsFile
+                   GSSAPIAuthentication
+                   GSSAPIDelegateCredentials
+                   HashKnownHosts
+                   Host
+                   HostbasedAuthentication
+                   HostKeyAlgorithms
+                   HostKeyAlias
+                   HostName
+                   IdentityFile
+                   IdentitiesOnly
+                   IPQoS
+                   KbdInteractiveDevices
+                   KexAlgorithms
+                   LogLevel
+                   MACs
+                   NoHostAuthenticationForLocalhost
+                   NumberOfPasswordPrompts
+                   PasswordAuthentication
+                   PKCS11Provider
+                   Port
+                   PreferredAuthentications
+                   Protocol
+                   ProxyCommand
+                   PubkeyAuthentication
+                   RekeyLimit
+                   RhostsRSAAuthentication
+                   RSAAuthentication
+                   SendEnv
+                   ServerAliveInterval
+                   ServerAliveCountMax
+                   StrictHostKeyChecking
+                   TCPKeepAlive
+                   UsePrivilegedPort
+                   User
+                   UserKnownHostsFile
+                   VerifyHostKeyDNS
+
+     -P port
+             Specifies the port to connect to on the remote host.  Note that
+             this option is written with a capital `P', because -p is already
+             reserved for preserving the times and modes of the file in
+             rcp(1).
+
+     -p      Preserves modification times, access times, and modes from the
+             original file.
+
+     -q      Quiet mode: disables the progress meter as well as warning and
+             diagnostic messages from ssh(1).
+
+     -r      Recursively copy entire directories.  Note that scp follows
+             symbolic links encountered in the tree traversal.
+
+     -S program
+             Name of program to use for the encrypted connection.  The program
+             must understand ssh(1) options.
+
+     -v      Verbose mode.  Causes scp and ssh(1) to print debugging messages
+             about their progress.  This is helpful in debugging connection,
+             authentication, and configuration problems.
+
+EXIT STATUS
+     The scp utility exits 0 on success, and >0 if an error occurs.
+
+SEE ALSO
+     rcp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1),
+     ssh_config(5), sshd(8)
+
+HISTORY
+     scp is based on the rcp(1) program in BSD source code from the Regents of
+     the University of California.
+
+AUTHORS
+     Timo Rinne <tri@iki.fi>
+     Tatu Ylonen <ylo@cs.hut.fi>
+
+OpenBSD 4.9                    December 9, 2010                    OpenBSD 4.9
diff --git a/scp.1 b/scp.1
new file mode 100644 (file)
index 0000000..577dd52
--- /dev/null
+++ b/scp.1
@@ -0,0 +1,237 @@
+.\"
+.\" 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.56 2010/12/09 14:13:32 jmc Exp $
+.\"
+.Dd $Mdocdate: December 9 2010 $
+.Dt SCP 1
+.Os
+.Sh NAME
+.Nm scp
+.Nd secure copy (remote file copy program)
+.Sh SYNOPSIS
+.Nm scp
+.Bk -words
+.Op Fl 12346BCpqrv
+.Op Fl c Ar cipher
+.Op Fl F Ar ssh_config
+.Op Fl i Ar identity_file
+.Op Fl l Ar limit
+.Op Fl o Ar ssh_option
+.Op Fl P Ar port
+.Op Fl S Ar program
+.Sm off
+.Oo
+.Op Ar user No @
+.Ar host1 No :
+.Oc Ns Ar file1
+.Sm on
+.Ar ...
+.Sm off
+.Oo
+.Op Ar user No @
+.Ar host2 No :
+.Oc Ar file2
+.Sm on
+.Ek
+.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
+File names may contain a user and host specification to indicate
+that the file is to be copied to/from that host.
+Local file names can be made explicit using absolute or relative pathnames
+to avoid
+.Nm
+treating file names containing
+.Sq :\&
+as host specifiers.
+Copies between two remote hosts are also permitted.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 1
+Forces
+.Nm
+to use protocol 1.
+.It Fl 2
+Forces
+.Nm
+to use protocol 2.
+.It Fl 3
+Copies between two remote hosts are transferred through the local host.
+Without this option the data is copied directly between the two remote
+hosts.
+Note that this option disables the progress meter.
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl B
+Selects batch mode (prevents asking for passwords or passphrases).
+.It Fl C
+Compression enable.
+Passes the
+.Fl C
+flag to
+.Xr ssh 1
+to enable compression.
+.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 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 i Ar identity_file
+Selects the file from which the identity (private key) for public key
+authentication is read.
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl l Ar limit
+Limits the used bandwidth, specified in Kbit/s.
+.It Fl o Ar ssh_option
+Can be used to pass options to
+.Nm ssh
+in the format used in
+.Xr ssh_config 5 .
+This is useful for specifying options
+for which there is no separate
+.Nm scp
+command-line flag.
+For full details of the options listed below, and their possible values, see
+.Xr ssh_config 5 .
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It AddressFamily
+.It BatchMode
+.It BindAddress
+.It ChallengeResponseAuthentication
+.It CheckHostIP
+.It Cipher
+.It Ciphers
+.It Compression
+.It CompressionLevel
+.It ConnectionAttempts
+.It ConnectTimeout
+.It ControlMaster
+.It ControlPath
+.It GlobalKnownHostsFile
+.It GSSAPIAuthentication
+.It GSSAPIDelegateCredentials
+.It HashKnownHosts
+.It Host
+.It HostbasedAuthentication
+.It HostKeyAlgorithms
+.It HostKeyAlias
+.It HostName
+.It IdentityFile
+.It IdentitiesOnly
+.It IPQoS
+.It KbdInteractiveDevices
+.It KexAlgorithms
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It PKCS11Provider
+.It Port
+.It PreferredAuthentications
+.It Protocol
+.It ProxyCommand
+.It PubkeyAuthentication
+.It RekeyLimit
+.It RhostsRSAAuthentication
+.It RSAAuthentication
+.It SendEnv
+.It ServerAliveInterval
+.It ServerAliveCountMax
+.It StrictHostKeyChecking
+.It TCPKeepAlive
+.It UsePrivilegedPort
+.It User
+.It UserKnownHostsFile
+.It VerifyHostKeyDNS
+.El
+.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 p
+Preserves modification times, access times, and modes from the
+original file.
+.It Fl q
+Quiet mode: disables the progress meter as well as warning and diagnostic
+messages from
+.Xr ssh 1 .
+.It Fl r
+Recursively copy entire directories.
+Note that
+.Nm
+follows symbolic links encountered in the tree traversal.
+.It Fl S Ar program
+Name of
+.Ar program
+to use for the encrypted connection.
+The program must understand
+.Xr ssh 1
+options.
+.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.
+.El
+.Sh EXIT STATUS
+.Ex -std scp
+.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 ssh_config 5 ,
+.Xr sshd 8
+.Sh HISTORY
+.Nm
+is based on the
+.Xr rcp 1
+program in BSD source code from the Regents of the University of
+California.
+.Sh AUTHORS
+.An Timo Rinne Aq tri@iki.fi
+.An Tatu Ylonen Aq ylo@cs.hut.fi
diff --git a/scp.c b/scp.c
new file mode 100644 (file)
index 0000000..18b2597
--- /dev/null
+++ b/scp.c
@@ -0,0 +1,1329 @@
+/* $OpenBSD: scp.c,v 1.170 2010/12/09 14:13:33 jmc Exp $ */
+/*
+ * 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. 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 <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+# endif
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <sys/wait.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+#include <vis.h>
+#endif
+
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+#include "misc.h"
+#include "progressmeter.h"
+
+extern char *__progname;
+
+#define COPY_BUFLEN    16384
+
+int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
+int do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout);
+
+/* Struct for addargs */
+arglist args;
+arglist remote_remote_args;
+
+/* Bandwidth limit */
+long long limit_kbps = 0;
+struct bwlimit bwlimit;
+
+/* 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 set to non-zero if remote-remote copy should be piped
+ * through this process.
+ */
+int throughlocal = 0;
+
+/* This is the program to execute for the secured connection. ("ssh" or -S) */
+char *ssh_program = _PATH_SSH_PROGRAM;
+
+/* This is used to store the pid of ssh_program */
+pid_t do_cmd_pid = -1;
+
+static void
+killchild(int signo)
+{
+       if (do_cmd_pid > 1) {
+               kill(do_cmd_pid, signo ? signo : SIGTERM);
+               waitpid(do_cmd_pid, NULL, 0);
+       }
+
+       if (signo)
+               _exit(1);
+       exit(1);
+}
+
+static void
+suspchild(int signo)
+{
+       int status;
+
+       if (do_cmd_pid > 1) {
+               kill(do_cmd_pid, signo);
+               while (waitpid(do_cmd_pid, &status, WUNTRACED) == -1 &&
+                   errno == EINTR)
+                       ;
+               kill(getpid(), SIGSTOP);
+       }
+}
+
+static int
+do_local_cmd(arglist *a)
+{
+       u_int i;
+       int status;
+       pid_t pid;
+
+       if (a->num == 0)
+               fatal("do_local_cmd: no arguments");
+
+       if (verbose_mode) {
+               fprintf(stderr, "Executing:");
+               for (i = 0; i < a->num; i++)
+                       fprintf(stderr, " %s", a->list[i]);
+               fprintf(stderr, "\n");
+       }
+       if ((pid = fork()) == -1)
+               fatal("do_local_cmd: fork: %s", strerror(errno));
+
+       if (pid == 0) {
+               execvp(a->list[0], a->list);
+               perror(a->list[0]);
+               exit(1);
+       }
+
+       do_cmd_pid = pid;
+       signal(SIGTERM, killchild);
+       signal(SIGINT, killchild);
+       signal(SIGHUP, killchild);
+
+       while (waitpid(pid, &status, 0) == -1)
+               if (errno != EINTR)
+                       fatal("do_local_cmd: waitpid: %s", strerror(errno));
+
+       do_cmd_pid = -1;
+
+       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * 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 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.
+        */
+       if (pipe(reserved) < 0)
+               fatal("pipe: %s", strerror(errno));
+
+       /* 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]);
+
+       signal(SIGTSTP, suspchild);
+       signal(SIGTTIN, suspchild);
+       signal(SIGTTOU, suspchild);
+
+       /* Fork a child to execute the command on the remote host using ssh. */
+       do_cmd_pid = fork();
+       if (do_cmd_pid == 0) {
+               /* Child. */
+               close(pin[1]);
+               close(pout[0]);
+               dup2(pin[0], 0);
+               dup2(pout[1], 1);
+               close(pin[0]);
+               close(pout[1]);
+
+               replacearg(&args, 0, "%s", ssh_program);
+               if (remuser != NULL) {
+                       addargs(&args, "-l");
+                       addargs(&args, "%s", remuser);
+               }
+               addargs(&args, "--");
+               addargs(&args, "%s", host);
+               addargs(&args, "%s", cmd);
+
+               execvp(ssh_program, args.list);
+               perror(ssh_program);
+               exit(1);
+       } else if (do_cmd_pid == -1) {
+               fatal("fork: %s", strerror(errno));
+       }
+       /* Parent.  Close the other side, and return the local side. */
+       close(pin[0]);
+       *fdout = pin[1];
+       close(pout[1]);
+       *fdin = pout[0];
+       signal(SIGTERM, killchild);
+       signal(SIGINT, killchild);
+       signal(SIGHUP, killchild);
+       return 0;
+}
+
+/*
+ * This functions executes a command simlar to do_cmd(), but expects the
+ * input and output descriptors to be setup by a previous call to do_cmd().
+ * This way the input and output of two commands can be connected.
+ */
+int
+do_cmd2(char *host, char *remuser, char *cmd, int fdin, int fdout)
+{
+       pid_t pid;
+       int status;
+
+       if (verbose_mode)
+               fprintf(stderr,
+                   "Executing: 2nd program %s host %s, user %s, command %s\n",
+                   ssh_program, host,
+                   remuser ? remuser : "(unspecified)", cmd);
+
+       /* Fork a child to execute the command on the remote host using ssh. */
+       pid = fork();
+       if (pid == 0) {
+               dup2(fdin, 0);
+               dup2(fdout, 1);
+
+               replacearg(&args, 0, "%s", ssh_program);
+               if (remuser != NULL) {
+                       addargs(&args, "-l");
+                       addargs(&args, "%s", remuser);
+               }
+               addargs(&args, "--");
+               addargs(&args, "%s", host);
+               addargs(&args, "%s", cmd);
+
+               execvp(ssh_program, args.list);
+               perror(ssh_program);
+               exit(1);
+       } else if (pid == -1) {
+               fatal("fork: %s", strerror(errno));
+       }
+       while (waitpid(pid, &status, 0) == -1)
+               if (errno != EINTR)
+                       fatal("do_cmd2: waitpid: %s", strerror(errno));
+       return 0;
+}
+
+typedef struct {
+       size_t cnt;
+       char *buf;
+} BUF;
+
+BUF *allocbuf(BUF *, int, int);
+void lostconn(int);
+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(int argc, char **argv)
+{
+       int ch, fflag, tflag, status, n;
+       char *targ, **newargv;
+       const char *errstr;
+       extern char *optarg;
+       extern int optind;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       /* Copy argv, because we modify it */
+       newargv = xcalloc(MAX(argc + 1, 1), sizeof(*newargv));
+       for (n = 0; n < argc; n++)
+               newargv[n] = xstrdup(argv[n]);
+       argv = newargv;
+
+       __progname = ssh_get_progname(argv[0]);
+
+       memset(&args, '\0', sizeof(args));
+       memset(&remote_remote_args, '\0', sizeof(remote_remote_args));
+       args.list = remote_remote_args.list = NULL;
+       addargs(&args, "%s", ssh_program);
+       addargs(&args, "-x");
+       addargs(&args, "-oForwardAgent=no");
+       addargs(&args, "-oPermitLocalCommand=no");
+       addargs(&args, "-oClearAllForwardings=yes");
+
+       fflag = tflag = 0;
+       while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
+               switch (ch) {
+               /* User-visible flags. */
+               case '1':
+               case '2':
+               case '4':
+               case '6':
+               case 'C':
+                       addargs(&args, "-%c", ch);
+                       addargs(&remote_remote_args, "-%c", ch);
+                       break;
+               case '3':
+                       throughlocal = 1;
+                       break;
+               case 'o':
+               case 'c':
+               case 'i':
+               case 'F':
+                       addargs(&remote_remote_args, "-%c", ch);
+                       addargs(&remote_remote_args, "%s", optarg);
+                       addargs(&args, "-%c", ch);
+                       addargs(&args, "%s", optarg);
+                       break;
+               case 'P':
+                       addargs(&remote_remote_args, "-p");
+                       addargs(&remote_remote_args, "%s", optarg);
+                       addargs(&args, "-p");
+                       addargs(&args, "%s", optarg);
+                       break;
+               case 'B':
+                       addargs(&remote_remote_args, "-oBatchmode=yes");
+                       addargs(&args, "-oBatchmode=yes");
+                       break;
+               case 'l':
+                       limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
+                           &errstr);
+                       if (errstr != NULL)
+                               usage();
+                       limit_kbps *= 1024; /* kbps */
+                       bandwidth_limit_init(&bwlimit, limit_kbps, COPY_BUFLEN);
+                       break;
+               case 'p':
+                       pflag = 1;
+                       break;
+               case 'r':
+                       iamrecursive = 1;
+                       break;
+               case 'S':
+                       ssh_program = xstrdup(optarg);
+                       break;
+               case 'v':
+                       addargs(&args, "-v");
+                       addargs(&remote_remote_args, "-v");
+                       verbose_mode = 1;
+                       break;
+               case 'q':
+                       addargs(&args, "-q");
+                       addargs(&remote_remote_args, "-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 %u", (u_int) userid);
+
+       if (!isatty(STDOUT_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;
+       do_cmd_pid = -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 {
+               if (targetshouldbedirectory)
+                       verifydir(argv[argc - 1]);
+               tolocal(argc, argv);    /* Dest is local host. */
+       }
+       /*
+        * Finally check the exit status of the ssh process, if one was forked
+        * and no error has occurred yet
+        */
+       if (do_cmd_pid != -1 && errs == 0) {
+               if (remin != -1)
+                   (void) close(remin);
+               if (remout != -1)
+                   (void) close(remout);
+               if (waitpid(do_cmd_pid, &status, 0) == -1)
+                       errs = 1;
+               else {
+                       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+                               errs = 1;
+               }
+       }
+       exit(errs != 0);
+}
+
+/* Callback from atomicio6 to update progress meter and limit bandwidth */
+static int
+scpio(void *_cnt, size_t s)
+{
+       off_t *cnt = (off_t *)_cnt;
+
+       *cnt += s;
+       if (limit_kbps > 0)
+               bandwidth_limit(&bwlimit, s);
+       return 0;
+}
+
+void
+toremote(char *targ, int argc, char **argv)
+{
+       char *bp, *host, *src, *suser, *thost, *tuser, *arg;
+       arglist alist;
+       int i;
+       u_int j;
+
+       memset(&alist, '\0', sizeof(alist));
+       alist.list = NULL;
+
+       *targ++ = 0;
+       if (*targ == 0)
+               targ = ".";
+
+       arg = xstrdup(argv[argc - 1]);
+       if ((thost = strrchr(arg, '@'))) {
+               /* user@host */
+               *thost++ = 0;
+               tuser = arg;
+               if (*tuser == '\0')
+                       tuser = NULL;
+       } else {
+               thost = arg;
+               tuser = NULL;
+       }
+
+       if (tuser != NULL && !okname(tuser)) {
+               xfree(arg);
+               return;
+       }
+
+       for (i = 0; i < argc - 1; i++) {
+               src = colon(argv[i]);
+               if (src && throughlocal) {      /* extended remote to remote */
+                       *src++ = 0;
+                       if (*src == 0)
+                               src = ".";
+                       host = strrchr(argv[i], '@');
+                       if (host) {
+                               *host++ = 0;
+                               host = cleanhostname(host);
+                               suser = argv[i];
+                               if (*suser == '\0')
+                                       suser = pwd->pw_name;
+                               else if (!okname(suser))
+                                       continue;
+                       } else {
+                               host = cleanhostname(argv[i]);
+                               suser = NULL;
+                       }
+                       xasprintf(&bp, "%s -f -- %s", cmd, src);
+                       if (do_cmd(host, suser, bp, &remin, &remout) < 0)
+                               exit(1);
+                       (void) xfree(bp);
+                       host = cleanhostname(thost);
+                       xasprintf(&bp, "%s -t -- %s", cmd, targ);
+                       if (do_cmd2(host, tuser, bp, remin, remout) < 0)
+                               exit(1);
+                       (void) xfree(bp);
+                       (void) close(remin);
+                       (void) close(remout);
+                       remin = remout = -1;
+               } else if (src) {       /* standard remote to remote */
+                       freeargs(&alist);
+                       addargs(&alist, "%s", ssh_program);
+                       addargs(&alist, "-x");
+                       addargs(&alist, "-oClearAllForwardings=yes");
+                       addargs(&alist, "-n");
+                       for (j = 0; j < remote_remote_args.num; j++) {
+                               addargs(&alist, "%s",
+                                   remote_remote_args.list[j]);
+                       }
+                       *src++ = 0;
+                       if (*src == 0)
+                               src = ".";
+                       host = strrchr(argv[i], '@');
+
+                       if (host) {
+                               *host++ = 0;
+                               host = cleanhostname(host);
+                               suser = argv[i];
+                               if (*suser == '\0')
+                                       suser = pwd->pw_name;
+                               else if (!okname(suser))
+                                       continue;
+                               addargs(&alist, "-l");
+                               addargs(&alist, "%s", suser);
+                       } else {
+                               host = cleanhostname(argv[i]);
+                       }
+                       addargs(&alist, "--");
+                       addargs(&alist, "%s", host);
+                       addargs(&alist, "%s", cmd);
+                       addargs(&alist, "%s", src);
+                       addargs(&alist, "%s%s%s:%s",
+                           tuser ? tuser : "", tuser ? "@" : "",
+                           thost, targ);
+                       if (do_local_cmd(&alist) != 0)
+                               errs = 1;
+               } else {        /* local to remote */
+                       if (remin == -1) {
+                               xasprintf(&bp, "%s -t -- %s", cmd, targ);
+                               host = cleanhostname(thost);
+                               if (do_cmd(host, tuser, bp, &remin,
+                                   &remout) < 0)
+                                       exit(1);
+                               if (response() < 0)
+                                       exit(1);
+                               (void) xfree(bp);
+                       }
+                       source(1, argv + i);
+               }
+       }
+       xfree(arg);
+}
+
+void
+tolocal(int argc, char **argv)
+{
+       char *bp, *host, *src, *suser;
+       arglist alist;
+       int i;
+
+       memset(&alist, '\0', sizeof(alist));
+       alist.list = NULL;
+
+       for (i = 0; i < argc - 1; i++) {
+               if (!(src = colon(argv[i]))) {  /* Local to local. */
+                       freeargs(&alist);
+                       addargs(&alist, "%s", _PATH_CP);
+                       if (iamrecursive)
+                               addargs(&alist, "-r");
+                       if (pflag)
+                               addargs(&alist, "-p");
+                       addargs(&alist, "--");
+                       addargs(&alist, "%s", argv[i]);
+                       addargs(&alist, "%s", argv[argc-1]);
+                       if (do_local_cmd(&alist))
+                               ++errs;
+                       continue;
+               }
+               *src++ = 0;
+               if (*src == 0)
+                       src = ".";
+               if ((host = strrchr(argv[i], '@')) == NULL) {
+                       host = argv[i];
+                       suser = NULL;
+               } else {
+                       *host++ = 0;
+                       suser = argv[i];
+                       if (*suser == '\0')
+                               suser = pwd->pw_name;
+               }
+               host = cleanhostname(host);
+               xasprintf(&bp, "%s -f -- %s", cmd, src);
+               if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
+                       (void) xfree(bp);
+                       ++errs;
+                       continue;
+               }
+               xfree(bp);
+               sink(1, argv + argc - 1);
+               (void) close(remin);
+               remin = remout = -1;
+       }
+}
+
+void
+source(int argc, char **argv)
+{
+       struct stat stb;
+       static BUF buffer;
+       BUF *bp;
+       off_t i, statbytes;
+       size_t amt;
+       int fd = -1, haderr, indx;
+       char *last, *name, buf[2048], encname[MAXPATHLEN];
+       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 ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) < 0)
+                       goto syserr;
+               if (strchr(name, '\n') != NULL) {
+                       strnvis(encname, name, sizeof(encname), VIS_NL);
+                       name = encname;
+               }
+               if (fstat(fd, &stb) < 0) {
+syserr:                        run_err("%s: %s", name, strerror(errno));
+                       goto next;
+               }
+               if (stb.st_size < 0) {
+                       run_err("%s: %s", name, "Negative file size");
+                       goto next;
+               }
+               unset_nonblock(fd);
+               switch (stb.st_mode & S_IFMT) {
+               case S_IFREG:
+                       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 < 0 ? 0 : stb.st_mtime),
+                           (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime));
+                       if (verbose_mode) {
+                               fprintf(stderr, "File mtime %ld atime %ld\n",
+                                   (long)stb.st_mtime, (long)stb.st_atime);
+                               fprintf(stderr, "Sending file timestamps: %s",
+                                   buf);
+                       }
+                       (void) atomicio(vwrite, remout, buf, strlen(buf));
+                       if (response() < 0)
+                               goto next;
+               }
+#define        FILEMODEMASK    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
+               snprintf(buf, sizeof buf, "C%04o %lld %s\n",
+                   (u_int) (stb.st_mode & FILEMODEMASK),
+                   (long long)stb.st_size, last);
+               if (verbose_mode) {
+                       fprintf(stderr, "Sending file modes: %s", buf);
+               }
+               (void) atomicio(vwrite, remout, buf, strlen(buf));
+               if (response() < 0)
+                       goto next;
+               if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
+next:                  if (fd != -1) {
+                               (void) close(fd);
+                               fd = -1;
+                       }
+                       continue;
+               }
+               if (showprogress)
+                       start_progress_meter(curfile, stb.st_size, &statbytes);
+               set_nonblock(remout);
+               for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
+                       amt = bp->cnt;
+                       if (i + (off_t)amt > stb.st_size)
+                               amt = stb.st_size - i;
+                       if (!haderr) {
+                               if (atomicio(read, fd, bp->buf, amt) != amt)
+                                       haderr = errno;
+                       }
+                       /* Keep writing after error to retain sync */
+                       if (haderr) {
+                               (void)atomicio(vwrite, remout, bp->buf, amt);
+                               continue;
+                       }
+                       if (atomicio6(vwrite, remout, bp->buf, amt, scpio,
+                           &statbytes) != amt)
+                               haderr = errno;
+               }
+               unset_nonblock(remout);
+               if (showprogress)
+                       stop_progress_meter();
+
+               if (fd != -1) {
+                       if (close(fd) < 0 && !haderr)
+                               haderr = errno;
+                       fd = -1;
+               }
+               if (!haderr)
+                       (void) atomicio(vwrite, remout, "", 1);
+               else
+                       run_err("%s: %s", name, strerror(haderr));
+               (void) response();
+       }
+}
+
+void
+rsource(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(vwrite, 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(vwrite, 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(vwrite, remout, "E\n", 2);
+       (void) response();
+}
+
+void
+sink(int argc, char **argv)
+{
+       static BUF buffer;
+       struct stat stb;
+       enum {
+               YES, NO, DISPLAYED
+       } wrerr;
+       BUF *bp;
+       off_t i;
+       size_t j, count;
+       int amt, exists, first, ofd;
+       mode_t mode, omode, mask;
+       off_t size, statbytes;
+       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)    { why = str; goto screwup; }
+
+       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(vwrite, 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) != 1)
+                       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 (verbose_mode)
+                       fprintf(stderr, "Sink: %s", buf);
+
+               if (buf[0] == '\01' || buf[0] == '\02') {
+                       if (iamremote == 0)
+                               (void) atomicio(vwrite, STDERR_FILENO,
+                                   buf + 1, strlen(buf + 1));
+                       if (buf[0] == '\02')
+                               exit(1);
+                       ++errs;
+                       continue;
+               }
+               if (buf[0] == 'E') {
+                       (void) atomicio(vwrite, 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(vwrite, 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 ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
+                       run_err("error: unexpected filename: %s", cp);
+                       exit(1);
+               }
+               if (targisdir) {
+                       static char *namebuf;
+                       static size_t 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,
+                           strcmp(targ, "/") ? "/" : "", cp);
+                       np = namebuf;
+               } else
+                       np = targ;
+               curfile = cp;
+               exists = stat(np, &stb) == 0;
+               if (buf[0] == 'D') {
+                       int mod_flag = pflag;
+                       if (!iamrecursive)
+                               SCREWUP("received directory without -r");
+                       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(vwrite, remout, "", 1);
+               if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
+                       (void) close(ofd);
+                       continue;
+               }
+               cp = bp->buf;
+               wrerr = NO;
+
+               statbytes = 0;
+               if (showprogress)
+                       start_progress_meter(curfile, size, &statbytes);
+               set_nonblock(remin);
+               for (count = i = 0; i < size; i += bp->cnt) {
+                       amt = bp->cnt;
+                       if (i + amt > size)
+                               amt = size - i;
+                       count += amt;
+                       do {
+                               j = atomicio6(read, remin, cp, amt,
+                                   scpio, &statbytes);
+                               if (j == 0) {
+                                       run_err("%s", j != EPIPE ?
+                                           strerror(errno) :
+                                           "dropped connection");
+                                       exit(1);
+                               }
+                               amt -= j;
+                               cp += j;
+                       } while (amt > 0);
+
+                       if (count == bp->cnt) {
+                               /* Keep reading so we stay sync'd up. */
+                               if (wrerr == NO) {
+                                       if (atomicio(vwrite, ofd, bp->buf,
+                                           count) != count) {
+                                               wrerr = YES;
+                                               wrerrno = errno;
+                                       }
+                               }
+                               count = 0;
+                               cp = bp->buf;
+                       }
+               }
+               unset_nonblock(remin);
+               if (showprogress)
+                       stop_progress_meter();
+               if (count != 0 && wrerr == NO &&
+                   atomicio(vwrite, ofd, bp->buf, count) != count) {
+                       wrerr = YES;
+                       wrerrno = errno;
+               }
+               if (wrerr == NO && (!exists || S_ISREG(stb.st_mode)) &&
+                   ftruncate(ofd, size) != 0) {
+                       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));
+                                       wrerr = DISPLAYED;
+                               }
+               } 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));
+                                       wrerr = DISPLAYED;
+                               }
+               }
+               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(vwrite, remout, "", 1);
+                       break;
+               case DISPLAYED:
+                       break;
+               }
+       }
+screwup:
+       run_err("protocol error: %s", why);
+       exit(1);
+}
+
+int
+response(void)
+{
+       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(vwrite, STDERR_FILENO, rbuf, cp - rbuf);
+               ++errs;
+               if (resp == 1)
+                       return (-1);
+               exit(1);
+       }
+       /* NOTREACHED */
+}
+
+void
+usage(void)
+{
+       (void) fprintf(stderr,
+           "usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
+           "           [-l limit] [-o ssh_option] [-P port] [-S program]\n"
+           "           [[user@]host1:]file1 ... [[user@]host2:]file2\n");
+       exit(1);
+}
+
+void
+run_err(const char *fmt,...)
+{
+       static FILE *fp;
+       va_list ap;
+
+       ++errs;
+       if (fp != NULL || (remout != -1 && (fp = fdopen(remout, "w")))) {
+               (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(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));
+       killchild(0);
+}
+
+int
+okname(char *cp0)
+{
+       int c;
+       char *cp;
+
+       cp = cp0;
+       do {
+               c = (int)*cp;
+               if (c & 0200)
+                       goto bad;
+               if (!isalpha(c) && !isdigit(c)) {
+                       switch (c) {
+                       case '\'':
+                       case '"':
+                       case '`':
+                       case ' ':
+                       case '#':
+                               goto bad;
+                       default:
+                               break;
+                       }
+               }
+       } while (*++cp);
+       return (1);
+
+bad:   fprintf(stderr, "%s: invalid user name\n", cp0);
+       return (0);
+}
+
+BUF *
+allocbuf(BUF *bp, int fd, int 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);
+       }
+       size = roundup(stb.st_blksize, blksize);
+       if (size == 0)
+               size = 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, 1, size);
+       memset(bp->buf, 0, size);
+       bp->cnt = size;
+       return (bp);
+}
+
+void
+lostconn(int signo)
+{
+       if (!iamremote)
+               write(STDERR_FILENO, "lost connection\n", 16);
+       if (signo)
+               _exit(1);
+       else
+               exit(1);
+}
diff --git a/servconf.c b/servconf.c
new file mode 100644 (file)
index 0000000..e2f20a3
--- /dev/null
@@ -0,0 +1,1781 @@
+/* $OpenBSD: servconf.c,v 1.213 2010/11/13 23:27:50 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "compat.h"
+#include "pathnames.h"
+#include "misc.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include "mac.h"
+#include "match.h"
+#include "channels.h"
+#include "groupaccess.h"
+
+static void add_listen_addr(ServerOptions *, char *, int);
+static void add_one_listen_addr(ServerOptions *, char *, int);
+
+/* Use of privilege separation or not */
+extern int use_privsep;
+extern Buffer cfg;
+
+/* Initializes the server options to their default values. */
+
+void
+initialize_server_options(ServerOptions *options)
+{
+       memset(options, 0, sizeof(*options));
+
+       /* Portable-specific options */
+       options->use_pam = -1;
+
+       /* Standard Options */
+       options->num_ports = 0;
+       options->ports_from_cmdline = 0;
+       options->listen_addrs = NULL;
+       options->address_family = -1;
+       options->num_host_key_files = 0;
+       options->num_host_cert_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->x11_use_localhost = -1;
+       options->xauth_location = NULL;
+       options->strict_modes = -1;
+       options->tcp_keep_alive = -1;
+       options->log_facility = SYSLOG_FACILITY_NOT_SET;
+       options->log_level = SYSLOG_LEVEL_NOT_SET;
+       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;
+       options->kerberos_authentication = -1;
+       options->kerberos_or_local_passwd = -1;
+       options->kerberos_ticket_cleanup = -1;
+       options->kerberos_get_afs_token = -1;
+       options->gss_authentication=-1;
+       options->gss_cleanup_creds = -1;
+       options->password_authentication = -1;
+       options->kbd_interactive_authentication = -1;
+       options->challenge_response_authentication = -1;
+       options->permit_empty_passwd = -1;
+       options->permit_user_env = -1;
+       options->use_login = -1;
+       options->compression = -1;
+       options->allow_tcp_forwarding = -1;
+       options->allow_agent_forwarding = -1;
+       options->num_allow_users = 0;
+       options->num_deny_users = 0;
+       options->num_allow_groups = 0;
+       options->num_deny_groups = 0;
+       options->ciphers = NULL;
+       options->macs = NULL;
+       options->kex_algorithms = 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->max_authtries = -1;
+       options->max_sessions = -1;
+       options->banner = NULL;
+       options->use_dns = -1;
+       options->client_alive_interval = -1;
+       options->client_alive_count_max = -1;
+       options->authorized_keys_file = NULL;
+       options->authorized_keys_file2 = NULL;
+       options->num_accept_env = 0;
+       options->permit_tun = -1;
+       options->num_permitted_opens = -1;
+       options->adm_forced_command = NULL;
+       options->chroot_directory = NULL;
+       options->zero_knowledge_password_authentication = -1;
+       options->revoked_keys_file = NULL;
+       options->trusted_user_ca_keys = NULL;
+       options->authorized_principals_file = NULL;
+       options->ip_qos_interactive = -1;
+       options->ip_qos_bulk = -1;
+}
+
+void
+fill_default_server_options(ServerOptions *options)
+{
+       /* Portable-specific options */
+       if (options->use_pam == -1)
+               options->use_pam = 0;
+
+       /* Standard Options */
+       if (options->protocol == SSH_PROTO_UNKNOWN)
+               options->protocol = 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_RSA_KEY_FILE;
+                       options->host_key_files[options->num_host_key_files++] =
+                           _PATH_HOST_DSA_KEY_FILE;
+#ifdef OPENSSL_HAS_ECC
+                       options->host_key_files[options->num_host_key_files++] =
+                           _PATH_HOST_ECDSA_KEY_FILE;
+#endif
+               }
+       }
+       /* No certificates by default */
+       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 = 1024;
+       if (options->login_grace_time == -1)
+               options->login_grace_time = 120;
+       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;
+       if (options->x11_use_localhost == -1)
+               options->x11_use_localhost = 1;
+       if (options->xauth_location == NULL)
+               options->xauth_location = _PATH_XAUTH;
+       if (options->strict_modes == -1)
+               options->strict_modes = 1;
+       if (options->tcp_keep_alive == -1)
+               options->tcp_keep_alive = 1;
+       if (options->log_facility == SYSLOG_FACILITY_NOT_SET)
+               options->log_facility = SYSLOG_FACILITY_AUTH;
+       if (options->log_level == SYSLOG_LEVEL_NOT_SET)
+               options->log_level = SYSLOG_LEVEL_INFO;
+       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 (options->kerberos_authentication == -1)
+               options->kerberos_authentication = 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;
+       if (options->kerberos_get_afs_token == -1)
+               options->kerberos_get_afs_token = 0;
+       if (options->gss_authentication == -1)
+               options->gss_authentication = 0;
+       if (options->gss_cleanup_creds == -1)
+               options->gss_cleanup_creds = 1;
+       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->permit_user_env == -1)
+               options->permit_user_env = 0;
+       if (options->use_login == -1)
+               options->use_login = 0;
+       if (options->compression == -1)
+               options->compression = COMP_DELAYED;
+       if (options->allow_tcp_forwarding == -1)
+               options->allow_tcp_forwarding = 1;
+       if (options->allow_agent_forwarding == -1)
+               options->allow_agent_forwarding = 1;
+       if (options->gateway_ports == -1)
+               options->gateway_ports = 0;
+       if (options->max_startups == -1)
+               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->max_authtries == -1)
+               options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
+       if (options->max_sessions == -1)
+               options->max_sessions = DEFAULT_SESSIONS_MAX;
+       if (options->use_dns == -1)
+               options->use_dns = 1;
+       if (options->client_alive_interval == -1)
+               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 = xstrdup(options->authorized_keys_file);
+               else
+                       options->authorized_keys_file2 = xstrdup(_PATH_SSH_USER_PERMITTED_KEYS2);
+       }
+       if (options->authorized_keys_file == NULL)
+               options->authorized_keys_file = xstrdup(_PATH_SSH_USER_PERMITTED_KEYS);
+       if (options->permit_tun == -1)
+               options->permit_tun = SSH_TUNMODE_NO;
+       if (options->zero_knowledge_password_authentication == -1)
+               options->zero_knowledge_password_authentication = 0;
+       if (options->ip_qos_interactive == -1)
+               options->ip_qos_interactive = IPTOS_LOWDELAY;
+       if (options->ip_qos_bulk == -1)
+               options->ip_qos_bulk = IPTOS_THROUGHPUT;
+
+       /* Turn privilege separation on by default */
+       if (use_privsep == -1)
+               use_privsep = 1;
+
+#ifndef HAVE_MMAP
+       if (use_privsep && options->compression == 1) {
+               error("This platform does not support both privilege "
+                   "separation and compression");
+               error("Compression disabled");
+               options->compression = 0;
+       }
+#endif
+
+}
+
+/* Keyword tokens. */
+typedef enum {
+       sBadOption,             /* == unknown option */
+       /* Portable-specific options */
+       sUsePAM,
+       /* Standard Options */
+       sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
+       sPermitRootLogin, sLogFacility, sLogLevel,
+       sRhostsRSAAuthentication, sRSAAuthentication,
+       sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
+       sKerberosGetAFSToken,
+       sKerberosTgtPassing, sChallengeResponseAuthentication,
+       sPasswordAuthentication, sKbdInteractiveAuthentication,
+       sListenAddress, sAddressFamily,
+       sPrintMotd, sPrintLastLog, sIgnoreRhosts,
+       sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
+       sStrictModes, sEmptyPasswd, sTCPKeepAlive,
+       sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
+       sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+       sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
+       sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
+       sMaxStartups, sMaxAuthTries, sMaxSessions,
+       sBanner, sUseDNS, sHostbasedAuthentication,
+       sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
+       sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+       sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
+       sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
+       sUsePrivilegeSeparation, sAllowAgentForwarding,
+       sZeroKnowledgePasswordAuthentication, sHostCertificate,
+       sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+       sKexAlgorithms, sIPQoS,
+       sDeprecated, sUnsupported
+} ServerOpCodes;
+
+#define SSHCFG_GLOBAL  0x01    /* allowed in main section of sshd_config */
+#define SSHCFG_MATCH   0x02    /* allowed inside a Match section */
+#define SSHCFG_ALL     (SSHCFG_GLOBAL|SSHCFG_MATCH)
+
+/* Textual representation of the tokens. */
+static struct {
+       const char *name;
+       ServerOpCodes opcode;
+       u_int flags;
+} keywords[] = {
+       /* Portable-specific options */
+#ifdef USE_PAM
+       { "usepam", sUsePAM, SSHCFG_GLOBAL },
+#else
+       { "usepam", sUnsupported, SSHCFG_GLOBAL },
+#endif
+       { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL },
+       /* Standard Options */
+       { "port", sPort, SSHCFG_GLOBAL },
+       { "hostkey", sHostKeyFile, SSHCFG_GLOBAL },
+       { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL },          /* alias */
+       { "pidfile", sPidFile, SSHCFG_GLOBAL },
+       { "serverkeybits", sServerKeyBits, SSHCFG_GLOBAL },
+       { "logingracetime", sLoginGraceTime, SSHCFG_GLOBAL },
+       { "keyregenerationinterval", sKeyRegenerationTime, SSHCFG_GLOBAL },
+       { "permitrootlogin", sPermitRootLogin, SSHCFG_ALL },
+       { "syslogfacility", sLogFacility, SSHCFG_GLOBAL },
+       { "loglevel", sLogLevel, SSHCFG_GLOBAL },
+       { "rhostsauthentication", sDeprecated, SSHCFG_GLOBAL },
+       { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL },
+       { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL },
+       { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL },
+       { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL },
+       { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL },
+       { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */
+#ifdef KRB5
+       { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL },
+       { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL },
+       { "kerberosticketcleanup", sKerberosTicketCleanup, SSHCFG_GLOBAL },
+#ifdef USE_AFS
+       { "kerberosgetafstoken", sKerberosGetAFSToken, SSHCFG_GLOBAL },
+#else
+       { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
+#endif
+#else
+       { "kerberosauthentication", sUnsupported, SSHCFG_ALL },
+       { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL },
+       { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL },
+       { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL },
+#endif
+       { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL },
+       { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL },
+#ifdef GSSAPI
+       { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL },
+       { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL },
+#else
+       { "gssapiauthentication", sUnsupported, SSHCFG_ALL },
+       { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL },
+#endif
+       { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL },
+       { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL },
+       { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL },
+       { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */
+#ifdef JPAKE
+       { "zeroknowledgepasswordauthentication", sZeroKnowledgePasswordAuthentication, SSHCFG_ALL },
+#else
+       { "zeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL },
+#endif
+       { "checkmail", sDeprecated, SSHCFG_GLOBAL },
+       { "listenaddress", sListenAddress, SSHCFG_GLOBAL },
+       { "addressfamily", sAddressFamily, SSHCFG_GLOBAL },
+       { "printmotd", sPrintMotd, SSHCFG_GLOBAL },
+       { "printlastlog", sPrintLastLog, SSHCFG_GLOBAL },
+       { "ignorerhosts", sIgnoreRhosts, SSHCFG_GLOBAL },
+       { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL },
+       { "x11forwarding", sX11Forwarding, SSHCFG_ALL },
+       { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL },
+       { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
+       { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
+       { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
+       { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
+       { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
+       { "uselogin", sUseLogin, SSHCFG_GLOBAL },
+       { "compression", sCompression, SSHCFG_GLOBAL },
+       { "tcpkeepalive", sTCPKeepAlive, SSHCFG_GLOBAL },
+       { "keepalive", sTCPKeepAlive, SSHCFG_GLOBAL },  /* obsolete alias */
+       { "allowtcpforwarding", sAllowTcpForwarding, SSHCFG_ALL },
+       { "allowagentforwarding", sAllowAgentForwarding, SSHCFG_ALL },
+       { "allowusers", sAllowUsers, SSHCFG_GLOBAL },
+       { "denyusers", sDenyUsers, SSHCFG_GLOBAL },
+       { "allowgroups", sAllowGroups, SSHCFG_GLOBAL },
+       { "denygroups", sDenyGroups, SSHCFG_GLOBAL },
+       { "ciphers", sCiphers, SSHCFG_GLOBAL },
+       { "macs", sMacs, SSHCFG_GLOBAL },
+       { "protocol", sProtocol, SSHCFG_GLOBAL },
+       { "gatewayports", sGatewayPorts, SSHCFG_ALL },
+       { "subsystem", sSubsystem, SSHCFG_GLOBAL },
+       { "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
+       { "maxauthtries", sMaxAuthTries, SSHCFG_ALL },
+       { "maxsessions", sMaxSessions, SSHCFG_ALL },
+       { "banner", sBanner, SSHCFG_ALL },
+       { "usedns", sUseDNS, SSHCFG_GLOBAL },
+       { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
+       { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL },
+       { "clientaliveinterval", sClientAliveInterval, SSHCFG_GLOBAL },
+       { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL },
+       { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL },
+       { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_ALL },
+       { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
+       { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
+       { "permittunnel", sPermitTunnel, SSHCFG_ALL },
+       { "match", sMatch, SSHCFG_ALL },
+       { "permitopen", sPermitOpen, SSHCFG_ALL },
+       { "forcecommand", sForceCommand, SSHCFG_ALL },
+       { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
+       { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
+       { "revokedkeys", sRevokedKeys, SSHCFG_ALL },
+       { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
+       { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
+       { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+       { "ipqos", sIPQoS, SSHCFG_ALL },
+       { NULL, sBadOption, 0 }
+};
+
+static struct {
+       int val;
+       char *text;
+} tunmode_desc[] = {
+       { SSH_TUNMODE_NO, "no" },
+       { SSH_TUNMODE_POINTOPOINT, "point-to-point" },
+       { SSH_TUNMODE_ETHERNET, "ethernet" },
+       { SSH_TUNMODE_YES, "yes" },
+       { -1, NULL }
+};
+
+/*
+ * Returns the number of the token pointed to by cp or sBadOption.
+ */
+
+static ServerOpCodes
+parse_token(const char *cp, const char *filename,
+           int linenum, u_int *flags)
+{
+       u_int i;
+
+       for (i = 0; keywords[i].name; i++)
+               if (strcasecmp(cp, keywords[i].name) == 0) {
+                       *flags = keywords[i].flags;
+                       return keywords[i].opcode;
+               }
+
+       error("%s: line %d: Bad configuration option: %s",
+           filename, linenum, cp);
+       return sBadOption;
+}
+
+char *
+derelativise_path(const char *path)
+{
+       char *expanded, *ret, cwd[MAXPATHLEN];
+
+       expanded = tilde_expand_filename(path, getuid());
+       if (*expanded == '/')
+               return expanded;
+       if (getcwd(cwd, sizeof(cwd)) == NULL)
+               fatal("%s: getcwd: %s", __func__, strerror(errno));
+       xasprintf(&ret, "%s/%s", cwd, expanded);
+       xfree(expanded);
+       return ret;
+}
+
+static void
+add_listen_addr(ServerOptions *options, char *addr, int port)
+{
+       u_int i;
+
+       if (options->num_ports == 0)
+               options->ports[options->num_ports++] = SSH_DEFAULT_PORT;
+       if (options->address_family == -1)
+               options->address_family = AF_UNSPEC;
+       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, int port)
+{
+       struct addrinfo hints, *ai, *aitop;
+       char strport[NI_MAXSERV];
+       int gaierr;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = options->address_family;
+       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>",
+                   ssh_gai_strerror(gaierr));
+       for (ai = aitop; ai->ai_next; ai = ai->ai_next)
+               ;
+       ai->ai_next = options->listen_addrs;
+       options->listen_addrs = aitop;
+}
+
+/*
+ * The strategy for the Match blocks is that the config file is parsed twice.
+ *
+ * The first time is at startup.  activep is initialized to 1 and the
+ * directives in the global context are processed and acted on.  Hitting a
+ * Match directive unsets activep and the directives inside the block are
+ * checked for syntax only.
+ *
+ * The second time is after a connection has been established but before
+ * authentication.  activep is initialized to 2 and global config directives
+ * are ignored since they have already been processed.  If the criteria in a
+ * Match block is met, activep is set and the subsequent directives
+ * processed and actioned until EOF or another Match block unsets it.  Any
+ * options set are copied into the main server config.
+ *
+ * Potential additions/improvements:
+ *  - Add Match support for pre-kex directives, eg Protocol, Ciphers.
+ *
+ *  - Add a Tag directive (idea from David Leonard) ala pf, eg:
+ *     Match Address 192.168.0.*
+ *             Tag trusted
+ *     Match Group wheel
+ *             Tag trusted
+ *     Match Tag trusted
+ *             AllowTcpForwarding yes
+ *             GatewayPorts clientspecified
+ *             [...]
+ *
+ *  - Add a PermittedChannelRequests directive
+ *     Match Group shell
+ *             PermittedChannelRequests session,forwarded-tcpip
+ */
+
+static int
+match_cfg_line_group(const char *grps, int line, const char *user)
+{
+       int result = 0;
+       struct passwd *pw;
+
+       if (user == NULL)
+               goto out;
+
+       if ((pw = getpwnam(user)) == NULL) {
+               debug("Can't match group at line %d because user %.100s does "
+                   "not exist", line, user);
+       } else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
+               debug("Can't Match group because user %.100s not in any group "
+                   "at line %d", user, line);
+       } else if (ga_match_pattern_list(grps) != 1) {
+               debug("user %.100s does not match group list %.100s at line %d",
+                   user, grps, line);
+       } else {
+               debug("user %.100s matched group list %.100s at line %d", user,
+                   grps, line);
+               result = 1;
+       }
+out:
+       ga_free();
+       return result;
+}
+
+static int
+match_cfg_line(char **condition, int line, const char *user, const char *host,
+    const char *address)
+{
+       int result = 1;
+       char *arg, *attrib, *cp = *condition;
+       size_t len;
+
+       if (user == NULL)
+               debug3("checking syntax for 'Match %s'", cp);
+       else
+               debug3("checking match for '%s' user %s host %s addr %s", cp,
+                   user ? user : "(null)", host ? host : "(null)",
+                   address ? address : "(null)");
+
+       while ((attrib = strdelim(&cp)) && *attrib != '\0') {
+               if ((arg = strdelim(&cp)) == NULL || *arg == '\0') {
+                       error("Missing Match criteria for %s", attrib);
+                       return -1;
+               }
+               len = strlen(arg);
+               if (strcasecmp(attrib, "user") == 0) {
+                       if (!user) {
+                               result = 0;
+                               continue;
+                       }
+                       if (match_pattern_list(user, arg, len, 0) != 1)
+                               result = 0;
+                       else
+                               debug("user %.100s matched 'User %.100s' at "
+                                   "line %d", user, arg, line);
+               } else if (strcasecmp(attrib, "group") == 0) {
+                       switch (match_cfg_line_group(arg, line, user)) {
+                       case -1:
+                               return -1;
+                       case 0:
+                               result = 0;
+                       }
+               } else if (strcasecmp(attrib, "host") == 0) {
+                       if (!host) {
+                               result = 0;
+                               continue;
+                       }
+                       if (match_hostname(host, arg, len) != 1)
+                               result = 0;
+                       else
+                               debug("connection from %.100s matched 'Host "
+                                   "%.100s' at line %d", host, arg, line);
+               } else if (strcasecmp(attrib, "address") == 0) {
+                       switch (addr_match_list(address, arg)) {
+                       case 1:
+                               debug("connection from %.100s matched 'Address "
+                                   "%.100s' at line %d", address, arg, line);
+                               break;
+                       case 0:
+                       case -1:
+                               result = 0;
+                               break;
+                       case -2:
+                               return -1;
+                       }
+               } else {
+                       error("Unsupported Match attribute %s", attrib);
+                       return -1;
+               }
+       }
+       if (user != NULL)
+               debug3("match %sfound", result ? "" : "not ");
+       *condition = cp;
+       return result;
+}
+
+#define WHITESPACE " \t\r\n"
+
+int
+process_server_config_line(ServerOptions *options, char *line,
+    const char *filename, int linenum, int *activep, const char *user,
+    const char *host, const char *address)
+{
+       char *cp, **charptr, *arg, *p;
+       int cmdline = 0, *intptr, value, value2, n;
+       SyslogFacility *log_facility_ptr;
+       LogLevel *log_level_ptr;
+       ServerOpCodes opcode;
+       int port;
+       u_int i, flags = 0;
+       size_t len;
+
+       cp = line;
+       if ((arg = strdelim(&cp)) == NULL)
+               return 0;
+       /* Ignore leading whitespace */
+       if (*arg == '\0')
+               arg = strdelim(&cp);
+       if (!arg || !*arg || *arg == '#')
+               return 0;
+       intptr = NULL;
+       charptr = NULL;
+       opcode = parse_token(arg, filename, linenum, &flags);
+
+       if (activep == NULL) { /* We are processing a command line directive */
+               cmdline = 1;
+               activep = &cmdline;
+       }
+       if (*activep && opcode != sMatch)
+               debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
+       if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
+               if (user == NULL) {
+                       fatal("%s line %d: Directive '%s' is not allowed "
+                           "within a Match block", filename, linenum, arg);
+               } else { /* this is a directive we have already processed */
+                       while (arg)
+                               arg = strdelim(&cp);
+                       return 0;
+               }
+       }
+
+       switch (opcode) {
+       /* Portable-specific options */
+       case sUsePAM:
+               intptr = &options->use_pam;
+               goto parse_flag;
+
+       /* Standard Options */
+       case sBadOption:
+               return -1;
+       case sPort:
+               /* ignore ports from configfile if cmdline specifies ports */
+               if (options->ports_from_cmdline)
+                       return 0;
+               if (options->listen_addrs != NULL)
+                       fatal("%s line %d: ports must be specified before "
+                           "ListenAddress.", 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 (*activep && *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 == NULL || *arg == '\0')
+                       fatal("%s line %d: missing address",
+                           filename, linenum);
+               /* check for bare IPv6 address: no "[]" and 2 or more ":" */
+               if (strchr(arg, '[') == NULL && (p = strchr(arg, ':')) != NULL
+                   && strchr(p+1, ':') != NULL) {
+                       add_listen_addr(options, arg, 0);
+                       break;
+               }
+               p = hpdelim(&arg);
+               if (p == NULL)
+                       fatal("%s line %d: bad address:port usage",
+                           filename, linenum);
+               p = cleanhostname(p);
+               if (arg == NULL)
+                       port = 0;
+               else if ((port = a2port(arg)) <= 0)
+                       fatal("%s line %d: bad port number", filename, linenum);
+
+               add_listen_addr(options, p, port);
+
+               break;
+
+       case sAddressFamily:
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing address family.",
+                           filename, linenum);
+               intptr = &options->address_family;
+               if (options->listen_addrs != NULL)
+                       fatal("%s line %d: address family must be specified before "
+                           "ListenAddress.", filename, linenum);
+               if (strcasecmp(arg, "inet") == 0)
+                       value = AF_INET;
+               else if (strcasecmp(arg, "inet6") == 0)
+                       value = AF_INET6;
+               else if (strcasecmp(arg, "any") == 0)
+                       value = AF_UNSPEC;
+               else
+                       fatal("%s line %d: unsupported address family \"%s\".",
+                           filename, linenum, arg);
+               if (*intptr == -1)
+                       *intptr = value;
+               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 (*activep && *charptr == NULL) {
+                       *charptr = derelativise_path(arg);
+                       /* increase optional counter */
+                       if (intptr != NULL)
+                               *intptr = *intptr + 1;
+               }
+               break;
+
+       case sHostCertificate:
+               intptr = &options->num_host_cert_files;
+               if (*intptr >= MAX_HOSTKEYS)
+                       fatal("%s line %d: too many host certificates "
+                           "specified (max %d).", filename, linenum,
+                           MAX_HOSTCERTS);
+               charptr = &options->host_cert_files[*intptr];
+               goto parse_filename;
+               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 (*activep && *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 (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case sIgnoreUserKnownHosts:
+               intptr = &options->ignore_user_known_hosts;
+               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;
+
+       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;
+
+       case sKerberosGetAFSToken:
+               intptr = &options->kerberos_get_afs_token;
+               goto parse_flag;
+
+       case sGssAuthentication:
+               intptr = &options->gss_authentication;
+               goto parse_flag;
+
+       case sGssCleanupCreds:
+               intptr = &options->gss_cleanup_creds;
+               goto parse_flag;
+
+       case sPasswordAuthentication:
+               intptr = &options->password_authentication;
+               goto parse_flag;
+
+       case sZeroKnowledgePasswordAuthentication:
+               intptr = &options->zero_knowledge_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 sX11UseLocalhost:
+               intptr = &options->x11_use_localhost;
+               goto parse_flag;
+
+       case sXAuthLocation:
+               charptr = &options->xauth_location;
+               goto parse_filename;
+
+       case sStrictModes:
+               intptr = &options->strict_modes;
+               goto parse_flag;
+
+       case sTCPKeepAlive:
+               intptr = &options->tcp_keep_alive;
+               goto parse_flag;
+
+       case sEmptyPasswd:
+               intptr = &options->permit_empty_passwd;
+               goto parse_flag;
+
+       case sPermitUserEnvironment:
+               intptr = &options->permit_user_env;
+               goto parse_flag;
+
+       case sUseLogin:
+               intptr = &options->use_login;
+               goto parse_flag;
+
+       case sCompression:
+               intptr = &options->compression;
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing yes/no/delayed "
+                           "argument.", filename, linenum);
+               value = 0;      /* silence compiler */
+               if (strcmp(arg, "delayed") == 0)
+                       value = COMP_DELAYED;
+               else if (strcmp(arg, "yes") == 0)
+                       value = COMP_ZLIB;
+               else if (strcmp(arg, "no") == 0)
+                       value = COMP_NONE;
+               else
+                       fatal("%s line %d: Bad yes/no/delayed "
+                           "argument: %s", filename, linenum, arg);
+               if (*intptr == -1)
+                       *intptr = value;
+               break;
+
+       case sGatewayPorts:
+               intptr = &options->gateway_ports;
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing yes/no/clientspecified "
+                           "argument.", filename, linenum);
+               value = 0;      /* silence compiler */
+               if (strcmp(arg, "clientspecified") == 0)
+                       value = 2;
+               else if (strcmp(arg, "yes") == 0)
+                       value = 1;
+               else if (strcmp(arg, "no") == 0)
+                       value = 0;
+               else
+                       fatal("%s line %d: Bad yes/no/clientspecified "
+                           "argument: %s", filename, linenum, arg);
+               if (*activep && *intptr == -1)
+                       *intptr = value;
+               break;
+
+       case sUseDNS:
+               intptr = &options->use_dns;
+               goto parse_flag;
+
+       case sLogFacility:
+               log_facility_ptr = &options->log_facility;
+               arg = strdelim(&cp);
+               value = log_facility_number(arg);
+               if (value == SYSLOG_FACILITY_NOT_SET)
+                       fatal("%.200s line %d: unsupported log facility '%s'",
+                           filename, linenum, arg ? arg : "<NONE>");
+               if (*log_facility_ptr == -1)
+                       *log_facility_ptr = (SyslogFacility) value;
+               break;
+
+       case sLogLevel:
+               log_level_ptr = &options->log_level;
+               arg = strdelim(&cp);
+               value = log_level_number(arg);
+               if (value == SYSLOG_LEVEL_NOT_SET)
+                       fatal("%.200s line %d: unsupported log level '%s'",
+                           filename, linenum, arg ? arg : "<NONE>");
+               if (*log_level_ptr == -1)
+                       *log_level_ptr = (LogLevel) value;
+               break;
+
+       case sAllowTcpForwarding:
+               intptr = &options->allow_tcp_forwarding;
+               goto parse_flag;
+
+       case sAllowAgentForwarding:
+               intptr = &options->allow_agent_forwarding;
+               goto parse_flag;
+
+       case sUsePrivilegeSeparation:
+               intptr = &use_privsep;
+               goto parse_flag;
+
+       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 sKexAlgorithms:
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: Missing argument.",
+                           filename, linenum);
+               if (!kex_names_valid(arg))
+                       fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.",
+                           filename, linenum, arg ? arg : "<NONE>");
+               if (options->kex_algorithms == NULL)
+                       options->kex_algorithms = 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);
+               if (!*activep) {
+                       arg = strdelim(&cp);
+                       break;
+               }
+               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);
+
+               /* Collect arguments (separate to executable) */
+               p = xstrdup(arg);
+               len = strlen(p) + 1;
+               while ((arg = strdelim(&cp)) != NULL && *arg != '\0') {
+                       len += 1 + strlen(arg);
+                       p = xrealloc(p, 1, len);
+                       strlcat(p, " ", len);
+                       strlcat(p, arg, len);
+               }
+               options->subsystem_args[options->num_subsystems] = p;
+               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 sMaxAuthTries:
+               intptr = &options->max_authtries;
+               goto parse_int;
+
+       case sMaxSessions:
+               intptr = &options->max_sessions;
+               goto parse_int;
+
+       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:
+               charptr = &options->authorized_keys_file;
+               goto parse_tilde_filename;
+       case sAuthorizedKeysFile2:
+               charptr = &options->authorized_keys_file2;
+               goto parse_tilde_filename;
+       case sAuthorizedPrincipalsFile:
+               charptr = &options->authorized_principals_file;
+ parse_tilde_filename:
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing file name.",
+                           filename, linenum);
+               if (*activep && *charptr == NULL) {
+                       *charptr = tilde_expand_filename(arg, getuid());
+                       /* increase optional counter */
+                       if (intptr != NULL)
+                               *intptr = *intptr + 1;
+               }
+               break;
+
+       case sClientAliveInterval:
+               intptr = &options->client_alive_interval;
+               goto parse_time;
+
+       case sClientAliveCountMax:
+               intptr = &options->client_alive_count_max;
+               goto parse_int;
+
+       case sAcceptEnv:
+               while ((arg = strdelim(&cp)) && *arg != '\0') {
+                       if (strchr(arg, '=') != NULL)
+                               fatal("%s line %d: Invalid environment name.",
+                                   filename, linenum);
+                       if (options->num_accept_env >= MAX_ACCEPT_ENV)
+                               fatal("%s line %d: too many allow env.",
+                                   filename, linenum);
+                       if (!*activep)
+                               break;
+                       options->accept_env[options->num_accept_env++] =
+                           xstrdup(arg);
+               }
+               break;
+
+       case sPermitTunnel:
+               intptr = &options->permit_tun;
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: Missing yes/point-to-point/"
+                           "ethernet/no argument.", filename, linenum);
+               value = -1;
+               for (i = 0; tunmode_desc[i].val != -1; i++)
+                       if (strcmp(tunmode_desc[i].text, arg) == 0) {
+                               value = tunmode_desc[i].val;
+                               break;
+                       }
+               if (value == -1)
+                       fatal("%s line %d: Bad yes/point-to-point/ethernet/"
+                           "no argument: %s", filename, linenum, arg);
+               if (*intptr == -1)
+                       *intptr = value;
+               break;
+
+       case sMatch:
+               if (cmdline)
+                       fatal("Match directive not supported as a command-line "
+                          "option");
+               value = match_cfg_line(&cp, linenum, user, host, address);
+               if (value < 0)
+                       fatal("%s line %d: Bad Match condition", filename,
+                           linenum);
+               *activep = value;
+               break;
+
+       case sPermitOpen:
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing PermitOpen specification",
+                           filename, linenum);
+               n = options->num_permitted_opens;       /* modified later */
+               if (strcmp(arg, "any") == 0) {
+                       if (*activep && n == -1) {
+                               channel_clear_adm_permitted_opens();
+                               options->num_permitted_opens = 0;
+                       }
+                       break;
+               }
+               if (*activep && n == -1)
+                       channel_clear_adm_permitted_opens();
+               for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
+                       p = hpdelim(&arg);
+                       if (p == NULL)
+                               fatal("%s line %d: missing host in PermitOpen",
+                                   filename, linenum);
+                       p = cleanhostname(p);
+                       if (arg == NULL || (port = a2port(arg)) <= 0)
+                               fatal("%s line %d: bad port number in "
+                                   "PermitOpen", filename, linenum);
+                       if (*activep && n == -1)
+                               options->num_permitted_opens =
+                                   channel_add_adm_permitted_opens(p, port);
+               }
+               break;
+
+       case sForceCommand:
+               if (cp == NULL)
+                       fatal("%.200s line %d: Missing argument.", filename,
+                           linenum);
+               len = strspn(cp, WHITESPACE);
+               if (*activep && options->adm_forced_command == NULL)
+                       options->adm_forced_command = xstrdup(cp + len);
+               return 0;
+
+       case sChrootDirectory:
+               charptr = &options->chroot_directory;
+
+               arg = strdelim(&cp);
+               if (!arg || *arg == '\0')
+                       fatal("%s line %d: missing file name.",
+                           filename, linenum);
+               if (*activep && *charptr == NULL)
+                       *charptr = xstrdup(arg);
+               break;
+
+       case sTrustedUserCAKeys:
+               charptr = &options->trusted_user_ca_keys;
+               goto parse_filename;
+
+       case sRevokedKeys:
+               charptr = &options->revoked_keys_file;
+               goto parse_filename;
+
+       case sIPQoS:
+               arg = strdelim(&cp);
+               if ((value = parse_ipqos(arg)) == -1)
+                       fatal("%s line %d: Bad IPQoS value: %s",
+                           filename, linenum, arg);
+               arg = strdelim(&cp);
+               if (arg == NULL)
+                       value2 = value;
+               else if ((value2 = parse_ipqos(arg)) == -1)
+                       fatal("%s line %d: Bad IPQoS value: %s",
+                           filename, linenum, arg);
+               if (*activep) {
+                       options->ip_qos_interactive = value;
+                       options->ip_qos_bulk = value2;
+               }
+               break;
+
+       case sDeprecated:
+               logit("%s line %d: Deprecated option %s",
+                   filename, linenum, arg);
+               while (arg)
+                   arg = strdelim(&cp);
+               break;
+
+       case sUnsupported:
+               logit("%s line %d: Unsupported 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);
+       return 0;
+}
+
+/* Reads the server configuration file. */
+
+void
+load_server_config(const char *filename, Buffer *conf)
+{
+       char line[1024], *cp;
+       FILE *f;
+
+       debug2("%s: filename %s", __func__, filename);
+       if ((f = fopen(filename, "r")) == NULL) {
+               perror(filename);
+               exit(1);
+       }
+       buffer_clear(conf);
+       while (fgets(line, sizeof(line), f)) {
+               /*
+                * Trim out comments and strip whitespace
+                * NB - preserve newlines, they are needed to reproduce
+                * line numbers later for error messages
+                */
+               if ((cp = strchr(line, '#')) != NULL)
+                       memcpy(cp, "\n", 2);
+               cp = line + strspn(line, " \t\r");
+
+               buffer_append(conf, cp, strlen(cp));
+       }
+       buffer_append(conf, "\0", 1);
+       fclose(f);
+       debug2("%s: done config len = %d", __func__, buffer_len(conf));
+}
+
+void
+parse_server_match_config(ServerOptions *options, const char *user,
+    const char *host, const char *address)
+{
+       ServerOptions mo;
+
+       initialize_server_options(&mo);
+       parse_server_config(&mo, "reprocess config", &cfg, user, host, address);
+       copy_set_server_options(options, &mo, 0);
+}
+
+/* Helper macros */
+#define M_CP_INTOPT(n) do {\
+       if (src->n != -1) \
+               dst->n = src->n; \
+} while (0)
+#define M_CP_STROPT(n) do {\
+       if (src->n != NULL) { \
+               if (dst->n != NULL) \
+                       xfree(dst->n); \
+               dst->n = src->n; \
+       } \
+} while(0)
+
+/*
+ * Copy any supported values that are set.
+ *
+ * If the preauth flag is set, we do not bother copying the string or
+ * array values that are not used pre-authentication, because any that we
+ * do use must be explictly sent in mm_getpwnamallow().
+ */
+void
+copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
+{
+       M_CP_INTOPT(password_authentication);
+       M_CP_INTOPT(gss_authentication);
+       M_CP_INTOPT(rsa_authentication);
+       M_CP_INTOPT(pubkey_authentication);
+       M_CP_INTOPT(kerberos_authentication);
+       M_CP_INTOPT(hostbased_authentication);
+       M_CP_INTOPT(hostbased_uses_name_from_packet_only);
+       M_CP_INTOPT(kbd_interactive_authentication);
+       M_CP_INTOPT(zero_knowledge_password_authentication);
+       M_CP_INTOPT(permit_root_login);
+       M_CP_INTOPT(permit_empty_passwd);
+
+       M_CP_INTOPT(allow_tcp_forwarding);
+       M_CP_INTOPT(allow_agent_forwarding);
+       M_CP_INTOPT(permit_tun);
+       M_CP_INTOPT(gateway_ports);
+       M_CP_INTOPT(x11_display_offset);
+       M_CP_INTOPT(x11_forwarding);
+       M_CP_INTOPT(x11_use_localhost);
+       M_CP_INTOPT(max_sessions);
+       M_CP_INTOPT(max_authtries);
+       M_CP_INTOPT(ip_qos_interactive);
+       M_CP_INTOPT(ip_qos_bulk);
+
+       M_CP_STROPT(banner);
+       if (preauth)
+               return;
+       M_CP_STROPT(adm_forced_command);
+       M_CP_STROPT(chroot_directory);
+       M_CP_STROPT(trusted_user_ca_keys);
+       M_CP_STROPT(revoked_keys_file);
+       M_CP_STROPT(authorized_keys_file);
+       M_CP_STROPT(authorized_keys_file2);
+       M_CP_STROPT(authorized_principals_file);
+}
+
+#undef M_CP_INTOPT
+#undef M_CP_STROPT
+
+void
+parse_server_config(ServerOptions *options, const char *filename, Buffer *conf,
+    const char *user, const char *host, const char *address)
+{
+       int active, linenum, bad_options = 0;
+       char *cp, *obuf, *cbuf;
+
+       debug2("%s: config %s len %d", __func__, filename, buffer_len(conf));
+
+       obuf = cbuf = xstrdup(buffer_ptr(conf));
+       active = user ? 0 : 1;
+       linenum = 1;
+       while ((cp = strsep(&cbuf, "\n")) != NULL) {
+               if (process_server_config_line(options, cp, filename,
+                   linenum++, &active, user, host, address) != 0)
+                       bad_options++;
+       }
+       xfree(obuf);
+       if (bad_options > 0)
+               fatal("%s: terminating, %d bad configuration options",
+                   filename, bad_options);
+}
+
+static const char *
+fmt_intarg(ServerOpCodes code, int val)
+{
+       if (code == sAddressFamily) {
+               switch (val) {
+               case AF_INET:
+                       return "inet";
+               case AF_INET6:
+                       return "inet6";
+               case AF_UNSPEC:
+                       return "any";
+               default:
+                       return "UNKNOWN";
+               }
+       }
+       if (code == sPermitRootLogin) {
+               switch (val) {
+               case PERMIT_NO_PASSWD:
+                       return "without-password";
+               case PERMIT_FORCED_ONLY:
+                       return "forced-commands-only";
+               case PERMIT_YES:
+                       return "yes";
+               }
+       }
+       if (code == sProtocol) {
+               switch (val) {
+               case SSH_PROTO_1:
+                       return "1";
+               case SSH_PROTO_2:
+                       return "2";
+               case (SSH_PROTO_1|SSH_PROTO_2):
+                       return "2,1";
+               default:
+                       return "UNKNOWN";
+               }
+       }
+       if (code == sGatewayPorts && val == 2)
+               return "clientspecified";
+       if (code == sCompression && val == COMP_DELAYED)
+               return "delayed";
+       switch (val) {
+       case -1:
+               return "unset";
+       case 0:
+               return "no";
+       case 1:
+               return "yes";
+       }
+       return "UNKNOWN";
+}
+
+static const char *
+lookup_opcode_name(ServerOpCodes code)
+{
+       u_int i;
+
+       for (i = 0; keywords[i].name != NULL; i++)
+               if (keywords[i].opcode == code)
+                       return(keywords[i].name);
+       return "UNKNOWN";
+}
+
+static void
+dump_cfg_int(ServerOpCodes code, int val)
+{
+       printf("%s %d\n", lookup_opcode_name(code), val);
+}
+
+static void
+dump_cfg_fmtint(ServerOpCodes code, int val)
+{
+       printf("%s %s\n", lookup_opcode_name(code), fmt_intarg(code, val));
+}
+
+static void
+dump_cfg_string(ServerOpCodes code, const char *val)
+{
+       if (val == NULL)
+               return;
+       printf("%s %s\n", lookup_opcode_name(code), val);
+}
+
+static void
+dump_cfg_strarray(ServerOpCodes code, u_int count, char **vals)
+{
+       u_int i;
+
+       for (i = 0; i < count; i++)
+               printf("%s %s\n", lookup_opcode_name(code),  vals[i]);
+}
+
+void
+dump_config(ServerOptions *o)
+{
+       u_int i;
+       int ret;
+       struct addrinfo *ai;
+       char addr[NI_MAXHOST], port[NI_MAXSERV], *s = NULL;
+
+       /* these are usually at the top of the config */
+       for (i = 0; i < o->num_ports; i++)
+               printf("port %d\n", o->ports[i]);
+       dump_cfg_fmtint(sProtocol, o->protocol);
+       dump_cfg_fmtint(sAddressFamily, o->address_family);
+
+       /* ListenAddress must be after Port */
+       for (ai = o->listen_addrs; ai; ai = ai->ai_next) {
+               if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, addr,
+                   sizeof(addr), port, sizeof(port),
+                   NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+                       error("getnameinfo failed: %.100s",
+                           (ret != EAI_SYSTEM) ? gai_strerror(ret) :
+                           strerror(errno));
+               } else {
+                       if (ai->ai_family == AF_INET6)
+                               printf("listenaddress [%s]:%s\n", addr, port);
+                       else
+                               printf("listenaddress %s:%s\n", addr, port);
+               }
+       }
+
+       /* integer arguments */
+#ifdef USE_PAM
+       dump_cfg_int(sUsePAM, o->use_pam);
+#endif
+       dump_cfg_int(sServerKeyBits, o->server_key_bits);
+       dump_cfg_int(sLoginGraceTime, o->login_grace_time);
+       dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
+       dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
+       dump_cfg_int(sMaxAuthTries, o->max_authtries);
+       dump_cfg_int(sMaxSessions, o->max_sessions);
+       dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
+       dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
+
+       /* formatted integer arguments */
+       dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
+       dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
+       dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
+       dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
+       dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
+       dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
+           o->hostbased_uses_name_from_packet_only);
+       dump_cfg_fmtint(sRSAAuthentication, o->rsa_authentication);
+       dump_cfg_fmtint(sPubkeyAuthentication, o->pubkey_authentication);
+#ifdef KRB5
+       dump_cfg_fmtint(sKerberosAuthentication, o->kerberos_authentication);
+       dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd);
+       dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup);
+# ifdef USE_AFS
+       dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token);
+# endif
+#endif
+#ifdef GSSAPI
+       dump_cfg_fmtint(sGssAuthentication, o->gss_authentication);
+       dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds);
+#endif
+#ifdef JPAKE
+       dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication,
+           o->zero_knowledge_password_authentication);
+#endif
+       dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication);
+       dump_cfg_fmtint(sKbdInteractiveAuthentication,
+           o->kbd_interactive_authentication);
+       dump_cfg_fmtint(sChallengeResponseAuthentication,
+           o->challenge_response_authentication);
+       dump_cfg_fmtint(sPrintMotd, o->print_motd);
+       dump_cfg_fmtint(sPrintLastLog, o->print_lastlog);
+       dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding);
+       dump_cfg_fmtint(sX11UseLocalhost, o->x11_use_localhost);
+       dump_cfg_fmtint(sStrictModes, o->strict_modes);
+       dump_cfg_fmtint(sTCPKeepAlive, o->tcp_keep_alive);
+       dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd);
+       dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env);
+       dump_cfg_fmtint(sUseLogin, o->use_login);
+       dump_cfg_fmtint(sCompression, o->compression);
+       dump_cfg_fmtint(sGatewayPorts, o->gateway_ports);
+       dump_cfg_fmtint(sUseDNS, o->use_dns);
+       dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
+       dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+
+       /* string arguments */
+       dump_cfg_string(sPidFile, o->pid_file);
+       dump_cfg_string(sXAuthLocation, o->xauth_location);
+       dump_cfg_string(sCiphers, o->ciphers);
+       dump_cfg_string(sMacs, o->macs);
+       dump_cfg_string(sBanner, o->banner);
+       dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file);
+       dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2);
+       dump_cfg_string(sForceCommand, o->adm_forced_command);
+       dump_cfg_string(sChrootDirectory, o->chroot_directory);
+       dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
+       dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+       dump_cfg_string(sAuthorizedPrincipalsFile,
+           o->authorized_principals_file);
+
+       /* string arguments requiring a lookup */
+       dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+       dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
+
+       /* string array arguments */
+       dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
+            o->host_key_files);
+       dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files,
+            o->host_cert_files);
+       dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
+       dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
+       dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
+       dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
+       dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
+
+       /* other arguments */
+       for (i = 0; i < o->num_subsystems; i++)
+               printf("subsystem %s %s\n", o->subsystem_name[i],
+                   o->subsystem_args[i]);
+
+       printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
+           o->max_startups_rate, o->max_startups);
+
+       for (i = 0; tunmode_desc[i].val != -1; i++)
+               if (tunmode_desc[i].val == o->permit_tun) {
+                       s = tunmode_desc[i].text;
+                       break;
+               }
+       dump_cfg_string(sPermitTunnel, s);
+
+       printf("ipqos 0x%02x 0x%02x\n", o->ip_qos_interactive, o->ip_qos_bulk);
+
+       channel_print_adm_permitted_opens();
+}
diff --git a/servconf.h b/servconf.h
new file mode 100644 (file)
index 0000000..5a058a4
--- /dev/null
@@ -0,0 +1,178 @@
+/* $OpenBSD: servconf.h,v 1.95 2010/11/13 23:27:50 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#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. */
+#define MAX_HOSTCERTS          256     /* Max # host certificates. */
+#define MAX_ACCEPT_ENV         256     /* Max # of env vars. */
+#define MAX_MATCH_GROUPS       256     /* Max # of groups for Match. */
+
+/* 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
+
+#define DEFAULT_AUTH_FAIL_MAX  6       /* Default for MaxAuthTries */
+#define DEFAULT_SESSIONS_MAX   10      /* Default for MaxSessions */
+
+/* Magic name for internal sftp-server */
+#define INTERNAL_SFTP_NAME     "internal-sftp"
+
+typedef struct {
+       u_int   num_ports;
+       u_int   ports_from_cmdline;
+       int     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. */
+       int     address_family;         /* Address family used by the server. */
+       char   *host_key_files[MAX_HOSTKEYS];   /* Files containing host keys. */
+       int     num_host_key_files;     /* Number of files for host keys. */
+       char   *host_cert_files[MAX_HOSTCERTS]; /* Files containing host certs. */
+       int     num_host_cert_files;     /* Number of files for host certs. */
+       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 */
+       int     x11_use_localhost;      /* If true, use localhost for fake X11 server. */
+       char   *xauth_location; /* Location of xauth program */
+       int     strict_modes;   /* If true, require string home dir modes. */
+       int     tcp_keep_alive; /* If true, set SO_KEEPALIVE. */
+       int     ip_qos_interactive;     /* IP ToS/DSCP/class for interactive */
+       int     ip_qos_bulk;            /* IP ToS/DSCP/class for bulk traffic */
+       char   *ciphers;        /* Supported SSH2 ciphers. */
+       char   *macs;           /* Supported SSH2 macs. */
+       char   *kex_algorithms; /* SSH2 kex methods in order of preference. */
+       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_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. */
+       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. */
+       int     kerberos_get_afs_token;         /* If true, try to get AFS token if
+                                                * authenticated with Kerberos. */
+       int     gss_authentication;     /* If true, permit GSSAPI authentication */
+       int     gss_cleanup_creds;      /* If true, destroy cred cache on logout */
+       int     password_authentication;        /* If true, permit password
+                                                * authentication. */
+       int     kbd_interactive_authentication; /* If true, permit */
+       int     challenge_response_authentication;
+       int     zero_knowledge_password_authentication;
+                                       /* If true, permit jpake auth */
+       int     permit_empty_passwd;    /* If false, do not permit empty
+                                        * passwords. */
+       int     permit_user_env;        /* If true, read ~/.ssh/environment */
+       int     use_login;      /* If true, login(1) is used */
+       int     compression;    /* If true, compression is allowed */
+       int     allow_tcp_forwarding;
+       int     allow_agent_forwarding;
+       u_int num_allow_users;
+       char   *allow_users[MAX_ALLOW_USERS];
+       u_int num_deny_users;
+       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];
+       char   *subsystem_args[MAX_SUBSYSTEMS];
+
+       u_int num_accept_env;
+       char   *accept_env[MAX_ACCEPT_ENV];
+
+       int     max_startups_begin;
+       int     max_startups_rate;
+       int     max_startups;
+       int     max_authtries;
+       int     max_sessions;
+       char   *banner;                 /* SSH-2 banner message */
+       int     use_dns;
+       int     client_alive_interval;  /*
+                                        * 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;
+
+       char   *adm_forced_command;
+
+       int     use_pam;                /* Enable auth via PAM */
+
+       int     permit_tun;
+
+       int     num_permitted_opens;
+
+       char   *chroot_directory;
+       char   *revoked_keys_file;
+       char   *trusted_user_ca_keys;
+       char   *authorized_principals_file;
+}       ServerOptions;
+
+void    initialize_server_options(ServerOptions *);
+void    fill_default_server_options(ServerOptions *);
+int     process_server_config_line(ServerOptions *, char *, const char *, int,
+            int *, const char *, const char *, const char *);
+void    load_server_config(const char *, Buffer *);
+void    parse_server_config(ServerOptions *, const char *, Buffer *,
+            const char *, const char *, const char *);
+void    parse_server_match_config(ServerOptions *, const char *, const char *,
+            const char *);
+void    copy_set_server_options(ServerOptions *, ServerOptions *, int);
+void    dump_config(ServerOptions *);
+char   *derelativise_path(const char *);
+
+#endif                         /* SERVCONF_H */
diff --git a/serverloop.c b/serverloop.c
new file mode 100644 (file)
index 0000000..8be01c5
--- /dev/null
@@ -0,0 +1,1254 @@
+/* $OpenBSD: serverloop.c,v 1.159 2009/05/28 16:50:16 andreas Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "packet.h"
+#include "buffer.h"
+#include "log.h"
+#include "servconf.h"
+#include "canohost.h"
+#include "sshpty.h"
+#include "channels.h"
+#include "compat.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "session.h"
+#include "dispatch.h"
+#include "auth-options.h"
+#include "serverloop.h"
+#include "misc.h"
+#include "roaming.h"
+
+extern ServerOptions options;
+
+/* XXX */
+extern Kex *xxx_kex;
+extern Authctxt *the_authctxt;
+extern int use_privsep;
+
+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 no_more_sessions = 0; /* Disallow further sessions. */
+
+/*
+ * 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 sig_atomic_t child_terminated = 0;     /* The child has terminated. */
+
+/* Cleanup on signals (!use_privsep case only) */
+static volatile sig_atomic_t received_sigterm = 0;
+
+/* prototypes */
+static void server_init_dispatch(void);
+
+/*
+ * we write to this pipe if a SIGCHLD is caught in order to avoid
+ * the race between select() and child_terminated
+ */
+static int notify_pipe[2];
+static void
+notify_setup(void)
+{
+       if (pipe(notify_pipe) < 0) {
+               error("pipe(notify_pipe) failed %s", strerror(errno));
+       } else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) ||
+           (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) {
+               error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno));
+               close(notify_pipe[0]);
+               close(notify_pipe[1]);
+       } else {
+               set_nonblock(notify_pipe[0]);
+               set_nonblock(notify_pipe[1]);
+               return;
+       }
+       notify_pipe[0] = -1;    /* read end */
+       notify_pipe[1] = -1;    /* write end */
+}
+static void
+notify_parent(void)
+{
+       if (notify_pipe[1] != -1)
+               write(notify_pipe[1], "", 1);
+}
+static void
+notify_prepare(fd_set *readset)
+{
+       if (notify_pipe[0] != -1)
+               FD_SET(notify_pipe[0], readset);
+}
+static void
+notify_done(fd_set *readset)
+{
+       char c;
+
+       if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset))
+               while (read(notify_pipe[0], &c, 1) != -1)
+                       debug2("notify_done: reading");
+}
+
+/*ARGSUSED*/
+static void
+sigchld_handler(int sig)
+{
+       int save_errno = errno;
+       child_terminated = 1;
+#ifndef _UNICOS
+       mysignal(SIGCHLD, sigchld_handler);
+#endif
+       notify_parent();
+       errno = save_errno;
+}
+
+/*ARGSUSED*/
+static void
+sigterm_handler(int sig)
+{
+       received_sigterm = sig;
+}
+
+/*
+ * Make packets from buffered stderr data, and buffer it for sending
+ * to the client.
+ */
+static void
+make_packets_from_stderr_data(void)
+{
+       u_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)
+{
+       u_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 channel_id;
+
+       /* timeout, check to see how many we have had */
+       if (packet_inc_alive_timeouts() > options.client_alive_count_max) {
+               logit("Timeout, client not responding.");
+               cleanup_exit(255);
+       }
+
+       /*
+        * send a bogus global/channel request with "wantreply",
+        * we should get back a failure
+        */
+       if ((channel_id = channel_find_open()) == -1) {
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("keepalive@openssh.com");
+               packet_put_char(1);     /* boolean: want reply */
+       } else {
+               channel_request_start(channel_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,
+    u_int *nallocp, u_int max_time_milliseconds)
+{
+       struct timeval tv, *tvp;
+       int ret;
+       int client_alive_scheduled = 0;
+       int program_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()) {
+                       program_alive_scheduled = child_terminated;
+                       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);
+       }
+       notify_prepare(*readsetp);
+
+       /*
+        * 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;
+       }
+
+       /* 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();
+               if (!compat20 && program_alive_scheduled && fdin_is_tty) {
+                       if (!fdout_eof)
+                               FD_SET(fdout, *readsetp);
+                       if (!fderr_eof)
+                               FD_SET(fderr, *readsetp);
+               }
+       }
+
+       notify_done(*readsetp);
+}
+
+/*
+ * 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)) {
+               int cont = 0;
+               len = roaming_read(connection_in, buf, sizeof(buf), &cont);
+               if (len == 0) {
+                       if (cont)
+                               return;
+                       verbose("Connection closed by %.100s",
+                           get_remote_ipaddr());
+                       connection_closed = 1;
+                       if (compat20)
+                               return;
+                       cleanup_exit(255);
+               } else if (len < 0) {
+                       if (errno != EINTR && errno != EAGAIN &&
+                           errno != EWOULDBLOCK) {
+                               verbose("Read error from remote host "
+                                   "%.100s: %.100s",
+                                   get_remote_ipaddr(), strerror(errno));
+                               cleanup_exit(255);
+                       }
+               } 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)) {
+               errno = 0;
+               len = read(fdout, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
+                       /* do nothing */
+#ifndef PTY_ZEROREAD
+               } else if (len <= 0) {
+#else
+               } else if ((!isatty(fdout) && len <= 0) ||
+                   (isatty(fdout) && (len < 0 || (len == 0 && errno != 0)))) {
+#endif
+                       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)) {
+               errno = 0;
+               len = read(fderr, buf, sizeof(buf));
+               if (len < 0 && (errno == EINTR || ((errno == EAGAIN ||
+                   errno == EWOULDBLOCK) && !child_terminated))) {
+                       /* do nothing */
+#ifndef PTY_ZEROREAD
+               } else if (len <= 0) {
+#else
+               } else if ((!isatty(fderr) && len <= 0) ||
+                   (isatty(fderr) && (len < 0 || (len == 0 && errno != 0)))) {
+#endif
+                       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 || errno == EWOULDBLOCK)) {
+                       /* do nothing */
+               } else if (len <= 0) {
+                       if (fdin != fdout)
+                               close(fdin);
+                       else
+                               shutdown(fdin, SHUT_WR); /* We will no longer send. */
+                       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;
+       u_int 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);
+
+       if (!use_privsep) {
+               signal(SIGTERM, sigterm_handler);
+               signal(SIGINT, sigterm_handler);
+               signal(SIGQUIT, sigterm_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();
+
+       notify_setup();
+
+       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) {
+                       if (fdin != fdout)
+                               close(fdin);
+                       else
+                               shutdown(fdin, SHUT_WR); /* We will no longer send. */
+                       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);
+               max_fd = MAX(max_fd, notify_pipe[0]);
+
+               /* Sleep in select() until we can do something. */
+               wait_until_can_do_something(&readset, &writeset, &max_fd,
+                   &nalloc, max_time_milliseconds);
+
+               if (received_sigterm) {
+                       logit("Exiting on signal %d", received_sigterm);
+                       /* Clean up sessions, utmp, etc. */
+                       cleanup_exit(255);
+               }
+
+               /* 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);
+
+       while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0)
+               if (errno != EINTR)
+                       packet_disconnect("wait: %.100s", strerror(errno));
+       if (wait_pid != pid)
+               error("Strange, wait returned pid %ld, expected %ld",
+                   (long)wait_pid, (long)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 {
+                       type = packet_read();
+               }
+               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) {
+               debug("Received SIGCHLD.");
+               while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
+                   (pid < 0 && errno == EINTR))
+                       if (pid > 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();
+
+       if (!use_privsep) {
+               signal(SIGTERM, sigterm_handler);
+               signal(SIGINT, sigterm_handler);
+               signal(SIGQUIT, sigterm_handler);
+       }
+
+       notify_setup();
+
+       max_fd = MAX(connection_in, connection_out);
+       max_fd = MAX(max_fd, notify_pipe[0]);
+
+       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);
+
+               if (received_sigterm) {
+                       logit("Exiting on signal %d", received_sigterm);
+                       /* Clean up sessions, utmp, etc. */
+                       cleanup_exit(255);
+               }
+
+               collect_children();
+               if (!rekeying) {
+                       channel_after_select(readset, writeset);
+                       if (packet_need_rekeying()) {
+                               debug("need rekeying");
+                               xxx_kex->done = 0;
+                               kex_send_kexinit(xxx_kex);
+                       }
+               }
+               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(NULL);
+}
+
+static void
+server_input_keep_alive(int type, u_int32_t seq, void *ctxt)
+{
+       debug("Got %d/%u for keepalive", type, seq);
+       /*
+        * 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.
+        */
+       packet_set_alive_timeouts(0);
+}
+
+static void
+server_input_stdin_data(int type, u_int32_t seq, 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_check_eom();
+       buffer_append(&stdin_buffer, data, data_len);
+       memset(data, 0, data_len);
+       xfree(data);
+}
+
+static void
+server_input_eof(int type, u_int32_t seq, 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_check_eom();
+       stdin_eof = 1;
+}
+
+static void
+server_input_window_size(int type, u_int32_t seq, void *ctxt)
+{
+       u_int row = packet_get_int();
+       u_int col = packet_get_int();
+       u_int xpixel = packet_get_int();
+       u_int ypixel = packet_get_int();
+
+       debug("Window change received.");
+       packet_check_eom();
+       if (fdin != -1)
+               pty_change_window_size(fdin, row, col, xpixel, ypixel);
+}
+
+static Channel *
+server_request_direct_tcpip(void)
+{
+       Channel *c;
+       char *target, *originator;
+       u_short 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_check_eom();
+
+       debug("server_request_direct_tcpip: originator %s port %d, target %s "
+           "port %d", originator, originator_port, target, target_port);
+
+       /* XXX check permission */
+       c = channel_connect_to(target, target_port,
+           "direct-tcpip", "direct-tcpip");
+
+       xfree(originator);
+       xfree(target);
+
+       return c;
+}
+
+static Channel *
+server_request_tun(void)
+{
+       Channel *c = NULL;
+       int mode, tun;
+       int sock;
+
+       mode = packet_get_int();
+       switch (mode) {
+       case SSH_TUNMODE_POINTOPOINT:
+       case SSH_TUNMODE_ETHERNET:
+               break;
+       default:
+               packet_send_debug("Unsupported tunnel device mode.");
+               return NULL;
+       }
+       if ((options.permit_tun & mode) == 0) {
+               packet_send_debug("Server has rejected tunnel device "
+                   "forwarding");
+               return NULL;
+       }
+
+       tun = packet_get_int();
+       if (forced_tun_device != -1) {
+               if (tun != SSH_TUNID_ANY && forced_tun_device != tun)
+                       goto done;
+               tun = forced_tun_device;
+       }
+       sock = tun_open(tun, mode);
+       if (sock < 0)
+               goto done;
+       c = channel_new("tun", SSH_CHANNEL_OPEN, sock, sock, -1,
+           CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1);
+       c->datagram = 1;
+#if defined(SSH_TUN_FILTER)
+       if (mode == SSH_TUNMODE_POINTOPOINT)
+               channel_register_filter(c->self, sys_tun_infilter,
+                   sys_tun_outfilter, NULL, NULL);
+#endif
+
+ done:
+       if (c == NULL)
+               packet_send_debug("Failed to open the tunnel device.");
+       return c;
+}
+
+static Channel *
+server_request_session(void)
+{
+       Channel *c;
+
+       debug("input_session_request");
+       packet_check_eom();
+
+       if (no_more_sessions) {
+               packet_disconnect("Possible attack: attempt to open a session "
+                   "after additional sessions disabled");
+       }
+
+       /*
+        * A server session has no fd to read or write until a
+        * CHANNEL_REQUEST for a shell is made, so we set the type to
+        * SSH_CHANNEL_LARVAL.  Additionally, a callback for handling all
+        * CHANNEL_REQUEST messages is registered.
+        */
+       c = channel_new("session", SSH_CHANNEL_LARVAL,
+           -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT,
+           0, "server-session", 1);
+       if (session_open(the_authctxt, c->self) != 1) {
+               debug("session open failed, free channel %d", c->self);
+               channel_free(c);
+               return NULL;
+       }
+       channel_register_cleanup(c->self, session_close_by_channel, 0);
+       return c;
+}
+
+static void
+server_input_channel_open(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c = NULL;
+       char *ctype;
+       int rchan;
+       u_int rmaxpack, rwindow, len;
+
+       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();
+       } else if (strcmp(ctype, "direct-tcpip") == 0) {
+               c = server_request_direct_tcpip();
+       } else if (strcmp(ctype, "tun@openssh.com") == 0) {
+               c = server_request_tun();
+       }
+       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, u_int32_t seq, void *ctxt)
+{
+       char *rtype;
+       int want_reply;
+       int success = 0, allocated_listen_port = 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 = the_authctxt->pw;
+               if (pw == NULL || !the_authctxt->valid)
+                       fatal("server_input_global_request: no/invalid user");
+               listen_address = packet_get_string(NULL);
+               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 ||
+                   (!want_reply && listen_port == 0)
+#ifndef NO_IPPORT_RESERVED_CONCEPT
+                   || (listen_port != 0 && listen_port < IPPORT_RESERVED &&
+                    pw->pw_uid != 0)
+#endif
+                   ) {
+                       success = 0;
+                       packet_send_debug("Server has disabled port forwarding.");
+               } else {
+                       /* Start listening on the port */
+                       success = channel_setup_remote_fwd_listener(
+                           listen_address, listen_port,
+                           &allocated_listen_port, options.gateway_ports);
+               }
+               xfree(listen_address);
+       } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) {
+               char *cancel_address;
+               u_short cancel_port;
+
+               cancel_address = packet_get_string(NULL);
+               cancel_port = (u_short)packet_get_int();
+               debug("%s: cancel-tcpip-forward addr %s port %d", __func__,
+                   cancel_address, cancel_port);
+
+               success = channel_cancel_rport_listener(cancel_address,
+                   cancel_port);
+               xfree(cancel_address);
+       } else if (strcmp(rtype, "no-more-sessions@openssh.com") == 0) {
+               no_more_sessions = 1;
+               success = 1;
+       }
+       if (want_reply) {
+               packet_start(success ?
+                   SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE);
+               if (success && allocated_listen_port > 0)
+                       packet_put_int(allocated_listen_port);
+               packet_send();
+               packet_write_wait();
+       }
+       xfree(rtype);
+}
+
+static void
+server_input_channel_req(int type, u_int32_t seq, void *ctxt)
+{
+       Channel *c;
+       int id, reply, success = 0;
+       char *rtype;
+
+       id = packet_get_int();
+       rtype = packet_get_string(NULL);
+       reply = packet_get_char();
+
+       debug("server_input_channel_req: channel %d request %s reply %d",
+           id, rtype, reply);
+
+       if ((c = channel_lookup(id)) == NULL)
+               packet_disconnect("server_input_channel_req: "
+                   "unknown channel %d", id);
+       if (!strcmp(rtype, "eow@openssh.com")) {
+               packet_check_eom();
+               chan_rcvd_eow(c);
+       } else if ((c->type == SSH_CHANNEL_LARVAL ||
+           c->type == SSH_CHANNEL_OPEN) && strcmp(c->ctype, "session") == 0)
+               success = session_input_channel_req(c, rtype);
+       if (reply) {
+               packet_start(success ?
+                   SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+               packet_put_int(c->remote_id);
+               packet_send();
+       }
+       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, &server_input_channel_req);
+       dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+       dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request);
+       /* client_alive */
+       dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &server_input_keep_alive);
+       dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive);
+       dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive);
+       dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive);
+       /* rekeying */
+       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/serverloop.h b/serverloop.h
new file mode 100644 (file)
index 0000000..7311558
--- /dev/null
@@ -0,0 +1,27 @@
+/* $OpenBSD: serverloop.h,v 1.6 2006/03/25 22:22:43 djm 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/session.c b/session.c
new file mode 100644 (file)
index 0000000..fff31b0
--- /dev/null
+++ b/session.c
@@ -0,0 +1,2727 @@
+/* $OpenBSD: session.c,v 1.258 2010/11/25 04:10:09 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "sshpty.h"
+#include "packet.h"
+#include "buffer.h"
+#include "match.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "channels.h"
+#include "key.h"
+#include "cipher.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "hostfile.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 "misc.h"
+#include "session.h"
+#include "kex.h"
+#include "monitor_wrap.h"
+#include "sftp.h"
+
+#if defined(KRB5) && defined(USE_AFS)
+#include <kafs.h>
+#endif
+
+#define IS_INTERNAL_SFTP(c) \
+       (!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
+        (c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
+         c[sizeof(INTERNAL_SFTP_NAME) - 1] == ' ' || \
+         c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\t'))
+
+/* func */
+
+Session *session_new(void);
+void   session_set_fds(Session *, int, int, int, int, int);
+void   session_pty_cleanup(Session *);
+void   session_proctitle(Session *);
+int    session_setup_x11fwd(Session *);
+int    do_exec_pty(Session *, const char *);
+int    do_exec_no_pty(Session *, const char *);
+int    do_exec(Session *, const char *);
+void   do_login(Session *, const char *);
+#ifdef LOGIN_NEEDS_UTMPX
+static void    do_pre_login(Session *s);
+#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 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);
+extern Buffer loginmsg;
+
+/* original command from peer. */
+const char *original_command = NULL;
+
+/* data */
+static int sessions_first_unused = -1;
+static int sessions_nalloc = 0;
+static Session *sessions = NULL;
+
+#define SUBSYSTEM_NONE                 0
+#define SUBSYSTEM_EXT                  1
+#define SUBSYSTEM_INT_SFTP             2
+#define SUBSYSTEM_INT_SFTP_ERROR       3
+
+#ifdef HAVE_LOGIN_CAP
+login_cap_t *lc;
+#endif
+
+static int is_child = 0;
+
+/* Name and directory of socket for authentication agent forwarding. */
+static char *auth_sock_name = NULL;
+static char *auth_sock_dir = NULL;
+
+/* removes the agent forwarding socket */
+
+static void
+auth_sock_cleanup_proc(struct passwd *pw)
+{
+       if (auth_sock_name != NULL) {
+               temporarily_use_uid(pw);
+               unlink(auth_sock_name);
+               rmdir(auth_sock_dir);
+               auth_sock_name = NULL;
+               restore_uid();
+       }
+}
+
+static int
+auth_input_request_forwarding(struct passwd * pw)
+{
+       Channel *nc;
+       int sock = -1;
+       struct sockaddr_un sunaddr;
+
+       if (auth_sock_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_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
+
+       /* Create private directory for socket */
+       if (mkdtemp(auth_sock_dir) == NULL) {
+               packet_send_debug("Agent forwarding disabled: "
+                   "mkdtemp() failed: %.100s", strerror(errno));
+               restore_uid();
+               xfree(auth_sock_dir);
+               auth_sock_dir = NULL;
+               goto authsock_err;
+       }
+
+       xasprintf(&auth_sock_name, "%s/agent.%ld",
+           auth_sock_dir, (long) getpid());
+
+       /* Create the socket. */
+       sock = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (sock < 0) {
+               error("socket: %.100s", strerror(errno));
+               restore_uid();
+               goto authsock_err;
+       }
+
+       /* Bind it to the name. */
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
+
+       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
+               error("bind: %.100s", strerror(errno));
+               restore_uid();
+               goto authsock_err;
+       }
+
+       /* Restore the privileged uid. */
+       restore_uid();
+
+       /* Start listening on the socket. */
+       if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
+               error("listen: %.100s", strerror(errno));
+               goto authsock_err;
+       }
+
+       /* 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, "auth socket", 1);
+       nc->path = xstrdup(auth_sock_name);
+       return 1;
+
+ authsock_err:
+       if (auth_sock_name != NULL)
+               xfree(auth_sock_name);
+       if (auth_sock_dir != NULL) {
+               rmdir(auth_sock_dir);
+               xfree(auth_sock_dir);
+       }
+       if (sock != -1)
+               close(sock);
+       auth_sock_name = NULL;
+       auth_sock_dir = NULL;
+       return 0;
+}
+
+static void
+display_loginmsg(void)
+{
+       if (buffer_len(&loginmsg) > 0) {
+               buffer_append(&loginmsg, "\0", 1);
+               printf("%s", (char *)buffer_ptr(&loginmsg));
+               buffer_clear(&loginmsg);
+       }
+}
+
+void
+do_authenticated(Authctxt *authctxt)
+{
+       setproctitle("%s", authctxt->pw->pw_name);
+
+       /* setup the channel layer */
+       if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+               channel_permit_all_opens();
+
+       auth_debug_send();
+
+       if (compat20)
+               do_authenticated2(authctxt);
+       else
+               do_authenticated1(authctxt);
+
+       do_cleanup(authctxt);
+}
+
+/*
+ * 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, screen_flag;
+       int enable_compression_after_reply = 0;
+       u_int proto_len, data_len, dlen, compression_level = 0;
+
+       s = session_new();
+       if (s == NULL) {
+               error("no more sessions");
+               return;
+       }
+       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();
+
+               /* Process the packet. */
+               switch (type) {
+               case SSH_CMSG_REQUEST_COMPRESSION:
+                       compression_level = packet_get_int();
+                       packet_check_eom();
+                       if (compression_level < 1 || compression_level > 9) {
+                               packet_send_debug("Received invalid compression level %d.",
+                                   compression_level);
+                               break;
+                       }
+                       if (options.compression == COMP_NONE) {
+                               debug2("compression disabled");
+                               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_check_eom();
+                       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 (!options.allow_agent_forwarding ||
+                           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.");
+                       if (channel_input_port_forward_request(s->pw->pw_uid == 0,
+                           options.gateway_ports) < 0) {
+                               debug("Port forwarding failed.");
+                               break;
+                       }
+                       success = 1;
+                       break;
+
+               case SSH_CMSG_MAX_PACKET_SIZE:
+                       if (packet_set_maxsize(packet_get_int()) > 0)
+                               success = 1;
+                       break;
+
+               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);
+                               if (do_exec(s, command) != 0)
+                                       packet_disconnect(
+                                           "command execution failed");
+                               xfree(command);
+                       } else {
+                               if (do_exec(s, NULL) != 0)
+                                       packet_disconnect(
+                                           "shell execution failed");
+                       }
+                       packet_check_eom();
+                       session_close(s);
+                       return;
+
+               default:
+                       /*
+                        * Any unknown messages in this phase are ignored,
+                        * and a failure message is returned.
+                        */
+                       logit("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);
+               }
+       }
+}
+
+#define USE_PIPES
+/*
+ * This is called to fork and execute a command when we have no tty.  This
+ * will call do_child from the child, and server_loop from the parent after
+ * setting up file descriptors and such.
+ */
+int
+do_exec_no_pty(Session *s, const char *command)
+{
+       pid_t pid;
+
+#ifdef USE_PIPES
+       int pin[2], pout[2], perr[2];
+
+       if (s == NULL)
+               fatal("do_exec_no_pty: no session");
+
+       /* Allocate pipes for communicating with the program. */
+       if (pipe(pin) < 0) {
+               error("%s: pipe in: %.100s", __func__, strerror(errno));
+               return -1;
+       }
+       if (pipe(pout) < 0) {
+               error("%s: pipe out: %.100s", __func__, strerror(errno));
+               close(pin[0]);
+               close(pin[1]);
+               return -1;
+       }
+       if (pipe(perr) < 0) {
+               error("%s: pipe err: %.100s", __func__,
+                   strerror(errno));
+               close(pin[0]);
+               close(pin[1]);
+               close(pout[0]);
+               close(pout[1]);
+               return -1;
+       }
+#else
+       int inout[2], err[2];
+
+       if (s == NULL)
+               fatal("do_exec_no_pty: no session");
+
+       /* Uses socket pairs to communicate with the program. */
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
+               error("%s: socketpair #1: %.100s", __func__, strerror(errno));
+               return -1;
+       }
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
+               error("%s: socketpair #2: %.100s", __func__,
+                   strerror(errno));
+               close(inout[0]);
+               close(inout[1]);
+               return -1;
+       }
+#endif
+
+       session_proctitle(s);
+
+       /* Fork the child. */
+       switch ((pid = fork())) {
+       case -1:
+               error("%s: fork: %.100s", __func__, strerror(errno));
+#ifdef USE_PIPES
+               close(pin[0]);
+               close(pin[1]);
+               close(pout[0]);
+               close(pout[1]);
+               close(perr[0]);
+               close(perr[1]);
+#else
+               close(inout[0]);
+               close(inout[1]);
+               close(err[0]);
+               close(err[1]);
+#endif
+               return -1;
+       case 0:
+               is_child = 1;
+
+               /* Child.  Reinitialize the log since the pid has changed. */
+               log_init(__progname, options.log_level,
+                   options.log_facility, log_stderr);
+
+               /*
+                * 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
+               /*
+                * 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 (same as stdin) */
+                       perror("dup2 stdout");
+               close(inout[0]);
+               if (dup2(err[0], 2) < 0)        /* stderr */
+                       perror("dup2 stderr");
+               close(err[0]);
+#endif
+
+
+#ifdef _UNICOS
+               cray_init_job(s->pw); /* set up cray jid and tmpdir */
+#endif
+
+               /* Do processing for the child (exec command etc). */
+               do_child(s, command);
+               /* NOTREACHED */
+       default:
+               break;
+       }
+
+#ifdef _UNICOS
+       signal(WJSIGNAL, cray_job_termination_handler);
+#endif /* _UNICOS */
+#ifdef HAVE_CYGWIN
+       cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
+
+       s->pid = pid;
+       /* Set interactive/non-interactive mode. */
+       packet_set_interactive(s->display != NULL,
+           options.ip_qos_interactive, options.ip_qos_bulk);
+
+       /*
+        * Clear loginmsg, since it's the child's responsibility to display
+        * it to the user, otherwise multiple sessions may accumulate
+        * multiple copies of the login messages.
+        */
+       buffer_clear(&loginmsg);
+
+#ifdef USE_PIPES
+       /* We are the parent.  Close the child sides of the pipes. */
+       close(pin[0]);
+       close(pout[1]);
+       close(perr[1]);
+
+       if (compat20) {
+               session_set_fds(s, pin[1], pout[0], perr[0],
+                   s->is_subsystem, 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
+       /* 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], err[1],
+                   s->is_subsystem, 0);
+       } else {
+               server_loop(pid, inout[1], inout[1], err[1]);
+               /* server_loop has closed inout[1] and err[1]. */
+       }
+#endif
+       return 0;
+}
+
+/*
+ * 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.
+ */
+int
+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;
+
+       /*
+        * Create another descriptor of the pty master side for use as the
+        * standard input.  We could use the original descriptor, but this
+        * simplifies code in server_loop.  The descriptor is bidirectional.
+        * Do this before forking (and cleanup in the child) so as to
+        * detect and gracefully fail out-of-fd conditions.
+        */
+       if ((fdout = dup(ptyfd)) < 0) {
+               error("%s: dup #1: %s", __func__, strerror(errno));
+               close(ttyfd);
+               close(ptyfd);
+               return -1;
+       }
+       /* we keep a reference to the pty master */
+       if ((ptymaster = dup(ptyfd)) < 0) {
+               error("%s: dup #2: %s", __func__, strerror(errno));
+               close(ttyfd);
+               close(ptyfd);
+               close(fdout);
+               return -1;
+       }
+
+       /* Fork the child. */
+       switch ((pid = fork())) {
+       case -1:
+               error("%s: fork: %.100s", __func__, strerror(errno));
+               close(fdout);
+               close(ptymaster);
+               close(ttyfd);
+               close(ptyfd);
+               return -1;
+       case 0:
+               is_child = 1;
+
+               close(fdout);
+               close(ptymaster);
+
+               /* Child.  Reinitialize the log because the pid has changed. */
+               log_init(__progname, options.log_level,
+                   options.log_facility, log_stderr);
+               /* 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)) {
+#ifdef _UNICOS
+                       cray_init_job(s->pw); /* set up cray jid and tmpdir */
+#endif /* _UNICOS */
+                       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 */
+       default:
+               break;
+       }
+
+#ifdef _UNICOS
+       signal(WJSIGNAL, cray_job_termination_handler);
+#endif /* _UNICOS */
+#ifdef HAVE_CYGWIN
+       cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
+#endif
+
+       s->pid = pid;
+
+       /* Parent.  Close the slave side of the pseudo tty. */
+       close(ttyfd);
+
+       /* Enter interactive session. */
+       s->ptymaster = ptymaster;
+       packet_set_interactive(1, 
+           options.ip_qos_interactive, options.ip_qos_bulk);
+       if (compat20) {
+               session_set_fds(s, ptyfd, fdout, -1, 1, 1);
+       } else {
+               server_loop(pid, ptyfd, fdout, -1);
+               /* server_loop _has_ closed ptyfd and fdout. */
+       }
+       return 0;
+}
+
+#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));
+       fromlen = sizeof(from);
+       if (packet_connection_is_on_socket()) {
+               if (getpeername(packet_get_connection_in(),
+                   (struct sockaddr *)&from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       cleanup_exit(255);
+               }
+       }
+
+       record_utmp_only(pid, s->tty, s->pw->pw_name,
+           get_remote_name_or_ip(utmp_len, options.use_dns),
+           (struct sockaddr *)&from, fromlen);
+}
+#endif
+
+/*
+ * This is called to fork and execute a command.  If another command is
+ * to be forced, execute that instead.
+ */
+int
+do_exec(Session *s, const char *command)
+{
+       int ret;
+
+       if (options.adm_forced_command) {
+               original_command = command;
+               command = options.adm_forced_command;
+               if (IS_INTERNAL_SFTP(command)) {
+                       s->is_subsystem = s->is_subsystem ?
+                           SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+               } else if (s->is_subsystem)
+                       s->is_subsystem = SUBSYSTEM_EXT;
+               debug("Forced command (config) '%.900s'", command);
+       } else if (forced_command) {
+               original_command = command;
+               command = forced_command;
+               if (IS_INTERNAL_SFTP(command)) {
+                       s->is_subsystem = s->is_subsystem ?
+                           SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
+               } else if (s->is_subsystem)
+                       s->is_subsystem = SUBSYSTEM_EXT;
+               debug("Forced command (key option) '%.900s'", command);
+       }
+
+#ifdef SSH_AUDIT_EVENTS
+       if (command != NULL)
+               PRIVSEP(audit_run_command(command));
+       else if (s->ttyfd == -1) {
+               char *shell = s->pw->pw_shell;
+
+               if (shell[0] == '\0')   /* empty shell means /bin/sh */
+                       shell =_PATH_BSHELL;
+               PRIVSEP(audit_run_command(shell));
+       }
+#endif
+       if (s->ttyfd != -1)
+               ret = do_exec_pty(s, command);
+       else
+               ret = do_exec_no_pty(s, command);
+
+       original_command = NULL;
+
+       /*
+        * Clear loginmsg: it's the child's responsibility to display
+        * it to the user, otherwise multiple sessions may accumulate
+        * multiple copies of the login messages.
+        */
+       buffer_clear(&loginmsg);
+
+       return ret;
+}
+
+/* administrative, login(1)-like work */
+void
+do_login(Session *s, const char *command)
+{
+       socklen_t fromlen;
+       struct sockaddr_storage from;
+       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));
+       fromlen = sizeof(from);
+       if (packet_connection_is_on_socket()) {
+               if (getpeername(packet_get_connection_in(),
+                   (struct sockaddr *)&from, &fromlen) < 0) {
+                       debug("getpeername: %.100s", strerror(errno));
+                       cleanup_exit(255);
+               }
+       }
+
+       /* Record that there was a login on that tty from the remote host. */
+       if (!use_privsep)
+               record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
+                   get_remote_name_or_ip(utmp_len,
+                   options.use_dns),
+                   (struct sockaddr *)&from, fromlen);
+
+#ifdef USE_PAM
+       /*
+        * If password change is needed, do it now.
+        * This needs to occur before the ~/.hushlogin check.
+        */
+       if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) {
+               display_loginmsg();
+               do_pam_chauthtok();
+               s->authctxt->force_pwchange = 0;
+               /* XXX - signal [net] parent to enable forwardings */
+       }
+#endif
+
+       if (check_quietlogin(s, command))
+               return;
+
+       display_loginmsg();
+
+       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 overridden.
+ */
+void
+child_set_env(char ***envp, u_int *envsizep, const char *name,
+       const char *value)
+{
+       char **env;
+       u_int envsize;
+       u_int i, namelen;
+
+       /*
+        * If we're passed an uninitialized list, allocate a single null
+        * entry before continuing.
+        */
+       if (*envp == NULL && *envsizep == 0) {
+               *envp = xmalloc(sizeof(char *));
+               *envp[0] = NULL;
+               *envsizep = 1;
+       }
+
+       /*
+        * 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. */
+               envsize = *envsizep;
+               if (i >= envsize - 1) {
+                       if (envsize >= 1000)
+                               fatal("child_set_env: too many env vars");
+                       envsize += 50;
+                       env = (*envp) = xrealloc(env, envsize, sizeof(char *));
+                       *envsizep = envsize;
+               }
+               /* 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;
+       u_int lineno = 0;
+
+       f = fopen(filename, "r");
+       if (!f)
+               return;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               if (++lineno > 1000)
+                       fatal("Too many lines in environment file %s", filename);
+               for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '#' || *cp == '\n')
+                       continue;
+
+               cp[strcspn(cp, "\n")] = '\0';
+
+               value = strchr(cp, '=');
+               if (value == NULL) {
+                       fprintf(stderr, "Bad line %u in %.100s\n", lineno,
+                           filename);
+                       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 HAVE_ETC_DEFAULT_LOGIN
+/*
+ * Return named variable from specified environment, or NULL if not present.
+ */
+static char *
+child_get_env(char **env, const char *name)
+{
+       int i;
+       size_t len;
+
+       len = strlen(name);
+       for (i=0; env[i] != NULL; i++)
+               if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
+                       return(env[i] + len + 1);
+       return NULL;
+}
+
+/*
+ * Read /etc/default/login.
+ * We pick up the PATH (or SUPATH for root) and UMASK.
+ */
+static void
+read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
+{
+       char **tmpenv = NULL, *var;
+       u_int i, tmpenvsize = 0;
+       u_long mask;
+
+       /*
+        * We don't want to copy the whole file to the child's environment,
+        * so we use a temporary environment and copy the variables we're
+        * interested in.
+        */
+       read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
+
+       if (tmpenv == NULL)
+               return;
+
+       if (uid == 0)
+               var = child_get_env(tmpenv, "SUPATH");
+       else
+               var = child_get_env(tmpenv, "PATH");
+       if (var != NULL)
+               child_set_env(env, envsize, "PATH", var);
+
+       if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
+               if (sscanf(var, "%5lo", &mask) == 1)
+                       umask((mode_t)mask);
+
+       for (i = 0; tmpenv[i] != NULL; i++)
+               xfree(tmpenv[i]);
+       xfree(tmpenv);
+}
+#endif /* HAVE_ETC_DEFAULT_LOGIN */
+
+void
+copy_environment(char **source, char ***env, u_int *envsize)
+{
+       char *var_name, *var_val;
+       int i;
+
+       if (source == NULL)
+               return;
+
+       for(i = 0; source[i] != NULL; i++) {
+               var_name = xstrdup(source[i]);
+               if ((var_val = strstr(var_name, "=")) == NULL) {
+                       xfree(var_name);
+                       continue;
+               }
+               *var_val++ = '\0';
+
+               debug3("Copy environment: %s=%s", var_name, var_val);
+               child_set_env(env, envsize, var_name, var_val);
+
+               xfree(var_name);
+       }
+}
+
+static char **
+do_setup_env(Session *s, const char *shell)
+{
+       char buf[256];
+       u_int i, envsize;
+       char **env, *laddr;
+       struct passwd *pw = s->pw;
+#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
+       char *path = NULL;
+#endif
+
+       /* Initialize the environment. */
+       envsize = 100;
+       env = xcalloc(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.
+        */
+       {
+               char **p;
+
+               p = fetch_windows_environment();
+               copy_environment(p, &env, &envsize);
+               free_windows_environment(p);
+       }
+#endif
+
+#ifdef GSSAPI
+       /* Allow any GSSAPI methods that we've used to alter
+        * the childs environment as they see fit
+        */
+       ssh_gssapi_do_child(&env, &envsize);
+#endif
+
+       if (!options.use_login) {
+               /* Set basic environment. */
+               for (i = 0; i < s->num_env; i++)
+                       child_set_env(&env, &envsize, s->env[i].name,
+                           s->env[i].val);
+
+               child_set_env(&env, &envsize, "USER", pw->pw_name);
+               child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
+#ifdef _AIX
+               child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
+#endif
+               child_set_env(&env, &envsize, "HOME", pw->pw_dir);
+#ifdef HAVE_LOGIN_CAP
+               if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
+                       child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+               else
+                       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.
+                */
+#  ifdef HAVE_ETC_DEFAULT_LOGIN
+               read_etc_default_login(&env, &envsize, pw->pw_uid);
+               path = child_get_env(env, "PATH");
+#  endif /* HAVE_ETC_DEFAULT_LOGIN */
+               if (path == NULL || *path == '\0') {
+                       child_set_env(&env, &envsize, "PATH",
+                           s->pw->pw_uid == 0 ?
+                               SUPERUSER_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 *str = ce->s;
+
+                       for (i = 0; str[i] != '=' && str[i]; i++)
+                               ;
+                       if (str[i] == '=') {
+                               str[i] = 0;
+                               child_set_env(&env, &envsize, str, str + i + 1);
+                       }
+                       custom_environment = ce->next;
+                       xfree(ce->s);
+                       xfree(ce);
+               }
+       }
+
+       /* SSH_CLIENT deprecated */
+       snprintf(buf, sizeof buf, "%.50s %d %d",
+           get_remote_ipaddr(), get_remote_port(), get_local_port());
+       child_set_env(&env, &envsize, "SSH_CLIENT", buf);
+
+       laddr = get_local_ipaddr(packet_get_connection_in());
+       snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
+           get_remote_ipaddr(), get_remote_port(), laddr, get_local_port());
+       xfree(laddr);
+       child_set_env(&env, &envsize, "SSH_CONNECTION", 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 _UNICOS
+       if (cray_tmpdir[0] != '\0')
+               child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
+#endif /* _UNICOS */
+
+       /*
+        * Since we clear KRB5CCNAME at startup, if it's set now then it
+        * must have been set by a native authentication method (eg AIX or
+        * SIA), so copy it to the child.
+        */
+       {
+               char *cp;
+
+               if ((cp = getenv("KRB5CCNAME")) != NULL)
+                       child_set_env(&env, &envsize, "KRB5CCNAME", cp);
+       }
+
+#ifdef _AIX
+       {
+               char *cp;
+
+               if ((cp = getenv("AUTHSTATE")) != NULL)
+                       child_set_env(&env, &envsize, "AUTHSTATE", cp);
+               read_environment_file(&env, &envsize, "/etc/environment");
+       }
+#endif
+#ifdef KRB5
+       if (s->authctxt->krb5_ccname)
+               child_set_env(&env, &envsize, "KRB5CCNAME",
+                   s->authctxt->krb5_ccname);
+#endif
+#ifdef USE_PAM
+       /*
+        * Pull in any environment variables that may have
+        * been set by PAM.
+        */
+       if (options.use_pam) {
+               char **p;
+
+               p = fetch_pam_child_environment();
+               copy_environment(p, &env, &envsize);
+               free_pam_environment(p);
+
+               p = fetch_pam_environment();
+               copy_environment(p, &env, &envsize);
+               free_pam_environment(p);
+       }
+#endif /* USE_PAM */
+
+       if (auth_sock_name != NULL)
+               child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+                   auth_sock_name);
+
+       /* read $HOME/.ssh/environment. */
+       if (options.permit_user_env && !options.use_login) {
+               snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
+                   strcmp(pw->pw_dir, "/") ? 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]);
+       }
+       return env;
+}
+
+/*
+ * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found
+ * first in this order).
+ */
+static void
+do_rc_files(Session *s, const char *shell)
+{
+       FILE *f = NULL;
+       char cmd[1024];
+       int do_xauth;
+       struct stat st;
+
+       do_xauth =
+           s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
+
+       /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
+       if (!s->is_subsystem && options.adm_forced_command == NULL &&
+           !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) {
+               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. */
+               if (debug_flag) {
+                       fprintf(stderr,
+                           "Running %.500s remove %.100s\n",
+                           options.xauth_location, s->auth_display);
+                       fprintf(stderr,
+                           "%.500s add %.100s %.100s %.100s\n",
+                           options.xauth_location, s->auth_display,
+                           s->auth_proto, s->auth_data);
+               }
+               snprintf(cmd, sizeof cmd, "%s -q -",
+                   options.xauth_location);
+               f = popen(cmd, "w");
+               if (f) {
+                       fprintf(f, "remove %s\n",
+                           s->auth_display);
+                       fprintf(f, "add %s %s %s\n",
+                           s->auth_display, s->auth_proto,
+                           s->auth_data);
+                       pclose(f);
+               } else {
+                       fprintf(stderr, "Could not run %s\n",
+                           cmd);
+               }
+       }
+}
+
+static void
+do_nologin(struct passwd *pw)
+{
+       FILE *f = NULL;
+       char buf[1024], *nl, *def_nl = _PATH_NOLOGIN;
+       struct stat sb;
+
+#ifdef HAVE_LOGIN_CAP
+       if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+               return;
+       nl = login_getcapstr(lc, "nologin", def_nl, def_nl);
+#else
+       if (pw->pw_uid == 0)
+               return;
+       nl = def_nl;
+#endif
+       if (stat(nl, &sb) == -1) {
+               if (nl != def_nl)
+                       xfree(nl);
+               return;
+       }
+
+       /* /etc/nologin exists.  Print its contents if we can and exit. */
+       logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
+       if ((f = fopen(nl, "r")) != NULL) {
+               while (fgets(buf, sizeof(buf), f))
+                       fputs(buf, stderr);
+               fclose(f);
+       }
+       exit(254);
+}
+
+/*
+ * Chroot into a directory after checking it for safety: all path components
+ * must be root-owned directories with strict permissions.
+ */
+static void
+safely_chroot(const char *path, uid_t uid)
+{
+       const char *cp;
+       char component[MAXPATHLEN];
+       struct stat st;
+
+       if (*path != '/')
+               fatal("chroot path does not begin at root");
+       if (strlen(path) >= sizeof(component))
+               fatal("chroot path too long");
+
+       /*
+        * Descend the path, checking that each component is a
+        * root-owned directory with strict permissions.
+        */
+       for (cp = path; cp != NULL;) {
+               if ((cp = strchr(cp, '/')) == NULL)
+                       strlcpy(component, path, sizeof(component));
+               else {
+                       cp++;
+                       memcpy(component, path, cp - path);
+                       component[cp - path] = '\0';
+               }
+       
+               debug3("%s: checking '%s'", __func__, component);
+
+               if (stat(component, &st) != 0)
+                       fatal("%s: stat(\"%s\"): %s", __func__,
+                           component, strerror(errno));
+               if (st.st_uid != 0 || (st.st_mode & 022) != 0)
+                       fatal("bad ownership or modes for chroot "
+                           "directory %s\"%s\"", 
+                           cp == NULL ? "" : "component ", component);
+               if (!S_ISDIR(st.st_mode))
+                       fatal("chroot path %s\"%s\" is not a directory",
+                           cp == NULL ? "" : "component ", component);
+
+       }
+
+       if (chdir(path) == -1)
+               fatal("Unable to chdir to chroot path \"%s\": "
+                   "%s", path, strerror(errno));
+       if (chroot(path) == -1)
+               fatal("chroot(\"%s\"): %s", path, strerror(errno));
+       if (chdir("/") == -1)
+               fatal("%s: chdir(/) after chroot: %s",
+                   __func__, strerror(errno));
+       verbose("Changed root directory to \"%s\"", path);
+}
+
+/* Set login name, uid, gid, and groups. */
+void
+do_setusercontext(struct passwd *pw)
+{
+       char *chroot_path, *tmp;
+
+       platform_setusercontext(pw);
+
+       if (platform_privileged_uidswap()) {
+#ifdef HAVE_LOGIN_CAP
+               if (setusercontext(lc, pw, pw->pw_uid,
+                   (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
+                       perror("unable to set user context");
+                       exit(1);
+               }
+#else
+               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();
+#endif
+
+               platform_setusercontext_post_groups(pw);
+
+               if (options.chroot_directory != NULL &&
+                   strcasecmp(options.chroot_directory, "none") != 0) {
+                        tmp = tilde_expand_filename(options.chroot_directory,
+                           pw->pw_uid);
+                       chroot_path = percent_expand(tmp, "h", pw->pw_dir,
+                           "u", pw->pw_name, (char *)NULL);
+                       safely_chroot(chroot_path, pw->pw_uid);
+                       free(tmp);
+                       free(chroot_path);
+               }
+
+#ifdef HAVE_LOGIN_CAP
+               if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
+                       perror("unable to set user context (setuser)");
+                       exit(1);
+               }
+#else
+               /* Permanently switch to the desired uid. */
+               permanently_set_uid(pw);
+#endif
+       }
+
+       if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
+               fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+}
+
+static void
+do_pwchange(Session *s)
+{
+       fflush(NULL);
+       fprintf(stderr, "WARNING: Your password has expired.\n");
+       if (s->ttyfd != -1) {
+               fprintf(stderr,
+                   "You must change your password now and login again!\n");
+#ifdef PASSWD_NEEDS_USERNAME
+               execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name,
+                   (char *)NULL);
+#else
+               execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);
+#endif
+               perror("passwd");
+       } else {
+               fprintf(stderr,
+                   "Password change required but no TTY available.\n");
+       }
+       exit(1);
+}
+
+static void
+launch_login(struct passwd *pw, const char *hostname)
+{
+       /* Launch login(1). */
+
+       execl(LOGIN_PROGRAM, "login", "-h", hostname,
+#ifdef xxxLOGIN_NEEDS_TERM
+                   (s->term ? s->term : "unknown"),
+#endif /* LOGIN_NEEDS_TERM */
+#ifdef LOGIN_NO_ENDOPT
+           "-p", "-f", pw->pw_name, (char *)NULL);
+#else
+           "-p", "-f", "--", pw->pw_name, (char *)NULL);
+#endif
+
+       /* Login couldn't be executed, die. */
+
+       perror("login");
+       exit(1);
+}
+
+static void
+child_close_fds(void)
+{
+       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.
+        */
+       closefrom(STDERR_FILENO + 1);
+}
+
+/*
+ * 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.
+ */
+#define ARGV_MAX 10
+void
+do_child(Session *s, const char *command)
+{
+       extern char **environ;
+       char **env;
+       char *argv[ARGV_MAX];
+       const char *shell, *shell0, *hostname = NULL;
+       struct passwd *pw = s->pw;
+       int r = 0;
+
+       /* remove hostkey from the child's memory */
+       destroy_sensitive_data();
+
+       /* Force a password change */
+       if (s->authctxt->force_pwchange) {
+               do_setusercontext(pw);
+               child_close_fds();
+               do_pwchange(s);
+               exit(1);
+       }
+
+       /* login(1) is only called if we execute the login shell */
+       if (options.use_login && command != NULL)
+               options.use_login = 0;
+
+#ifdef _UNICOS
+       cray_setup(pw->pw_uid, pw->pw_name, command);
+#endif /* _UNICOS */
+
+       /*
+        * 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, s->ttyfd == -1 ? NULL : s->tty);
+               if (!check_quietlogin(s, command))
+                       do_motd();
+#else /* HAVE_OSF_SIA */
+               /* When PAM is enabled we rely on it to do the nologin check */
+               if (!options.use_pam)
+                       do_nologin(pw);
+               do_setusercontext(pw);
+               /*
+                * PAM session modules in do_setusercontext may have
+                * generated messages, so if this in an interactive
+                * login then display them too.
+                */
+               if (!check_quietlogin(s, command))
+                       display_loginmsg();
+#endif /* HAVE_OSF_SIA */
+       }
+
+#ifdef USE_PAM
+       if (options.use_pam && !options.use_login && !is_pam_session_open()) {
+               debug3("PAM session not opened, exiting");
+               display_loginmsg();
+               exit(254);
+       }
+#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;
+
+       /*
+        * Make sure $SHELL points to the shell from the password file,
+        * even if shell is overridden from login.conf
+        */
+       env = do_setup_env(s, shell);
+
+#ifdef HAVE_LOGIN_CAP
+       shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
+#endif
+
+       /* we have to stash the hostname before we close our socket. */
+       if (options.use_login)
+               hostname = get_remote_name_or_ip(utmp_len,
+                   options.use_dns);
+       /*
+        * 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.
+        */
+       child_close_fds();
+
+       /*
+        * Must take new environment into use so that .ssh/rc,
+        * /etc/ssh/sshrc and xauth are run in the proper environment.
+        */
+       environ = env;
+
+#if defined(KRB5) && defined(USE_AFS)
+       /*
+        * At this point, we check to see if AFS is active and if we have
+        * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
+        * if we can (and need to) extend the ticket into an AFS token. If
+        * we don't do this, we run into potential problems if the user's
+        * home directory is in AFS and it's not world-readable.
+        */
+
+       if (options.kerberos_get_afs_token && k_hasafs() &&
+           (s->authctxt->krb5_ctx != NULL)) {
+               char cell[64];
+
+               debug("Getting AFS token");
+
+               k_setpag();
+
+               if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+                       krb5_afslog(s->authctxt->krb5_ctx,
+                           s->authctxt->krb5_fwd_ccache, cell, NULL);
+
+               krb5_afslog_home(s->authctxt->krb5_ctx,
+                   s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
+       }
+#endif
+
+       /* Change current directory to the user's home directory. */
+       if (chdir(pw->pw_dir) < 0) {
+               /* Suppress missing homedir warning for chroot case */
+#ifdef HAVE_LOGIN_CAP
+               r = login_getcapbool(lc, "requirehome", 0);
+#endif
+               if (r || options.chroot_directory == NULL ||
+                   strcasecmp(options.chroot_directory, "none") == 0)
+                       fprintf(stderr, "Could not chdir to home "
+                           "directory %s: %s\n", pw->pw_dir,
+                           strerror(errno));
+               if (r)
+                       exit(1);
+       }
+
+       closefrom(STDERR_FILENO + 1);
+
+       if (!options.use_login)
+               do_rc_files(s, shell);
+
+       /* restore SIGPIPE for child */
+       signal(SIGPIPE, SIG_DFL);
+
+       if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
+               printf("This service allows sftp connections only.\n");
+               fflush(NULL);
+               exit(1);
+       } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
+               extern int optind, optreset;
+               int i;
+               char *p, *args;
+
+               setproctitle("%s@%s", s->pw->pw_name, INTERNAL_SFTP_NAME);
+               args = xstrdup(command ? command : "sftp-server");
+               for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
+                       if (i < ARGV_MAX - 1)
+                               argv[i++] = p;
+               argv[i] = NULL;
+               optind = optreset = 1;
+               __progname = argv[0];
+#ifdef WITH_SELINUX
+               ssh_selinux_change_context("sftpd_t");
+#endif
+               exit(sftp_server_main(i, argv, s->pw));
+       }
+
+       fflush(NULL);
+
+       if (options.use_login) {
+               launch_login(pw, hostname);
+               /* NEVERREACHED */
+       }
+
+       /* Get the last component of the shell name. */
+       if ((shell0 = strrchr(shell, '/')) != NULL)
+               shell0++;
+       else
+               shell0 = shell;
+
+       /*
+        * 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) {
+               char argv0[256];
+
+               /* Start the shell.  Set initial character to '-'. */
+               argv0[0] = '-';
+
+               if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
+                   >= sizeof(argv0) - 1) {
+                       errno = EINVAL;
+                       perror(shell);
+                       exit(1);
+               }
+
+               /* Execute the shell. */
+               argv[0] = argv0;
+               argv[1] = NULL;
+               execve(shell, argv, env);
+
+               /* Executing the shell failed. */
+               perror(shell);
+               exit(1);
+       }
+       /*
+        * Execute the command using the user's shell.  This uses the -c
+        * option to execute the command.
+        */
+       argv[0] = (char *) shell0;
+       argv[1] = "-c";
+       argv[2] = (char *) command;
+       argv[3] = NULL;
+       execve(shell, argv, env);
+       perror(shell);
+       exit(1);
+}
+
+void
+session_unused(int id)
+{
+       debug3("%s: session id %d unused", __func__, id);
+       if (id >= options.max_sessions ||
+           id >= sessions_nalloc) {
+               fatal("%s: insane session id %d (max %d nalloc %d)",
+                   __func__, id, options.max_sessions, sessions_nalloc);
+       }
+       bzero(&sessions[id], sizeof(*sessions));
+       sessions[id].self = id;
+       sessions[id].used = 0;
+       sessions[id].chanid = -1;
+       sessions[id].ptyfd = -1;
+       sessions[id].ttyfd = -1;
+       sessions[id].ptymaster = -1;
+       sessions[id].x11_chanids = NULL;
+       sessions[id].next_unused = sessions_first_unused;
+       sessions_first_unused = id;
+}
+
+Session *
+session_new(void)
+{
+       Session *s, *tmp;
+
+       if (sessions_first_unused == -1) {
+               if (sessions_nalloc >= options.max_sessions)
+                       return NULL;
+               debug2("%s: allocate (allocated %d max %d)",
+                   __func__, sessions_nalloc, options.max_sessions);
+               tmp = xrealloc(sessions, sessions_nalloc + 1,
+                   sizeof(*sessions));
+               if (tmp == NULL) {
+                       error("%s: cannot allocate %d sessions",
+                           __func__, sessions_nalloc + 1);
+                       return NULL;
+               }
+               sessions = tmp;
+               session_unused(sessions_nalloc++);
+       }
+
+       if (sessions_first_unused >= sessions_nalloc ||
+           sessions_first_unused < 0) {
+               fatal("%s: insane first_unused %d max %d nalloc %d",
+                   __func__, sessions_first_unused, options.max_sessions,
+                   sessions_nalloc);
+       }
+
+       s = &sessions[sessions_first_unused];
+       if (s->used) {
+               fatal("%s: session %d already used",
+                   __func__, sessions_first_unused);
+       }
+       sessions_first_unused = s->next_unused;
+       s->used = 1;
+       s->next_unused = -1;
+       debug("session_new: session %d", s->self);
+
+       return s;
+}
+
+static void
+session_dump(void)
+{
+       int i;
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+
+               debug("dump: used %d next_unused %d session %d %p "
+                   "channel %d pid %ld",
+                   s->used,
+                   s->next_unused,
+                   s->self,
+                   s,
+                   s->chanid,
+                   (long)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 || !authctxt->valid)
+               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;
+}
+
+Session *
+session_by_tty(char *tty)
+{
+       int i;
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
+                       debug("session_by_tty: session %d tty %s", i, tty);
+                       return s;
+               }
+       }
+       debug("session_by_tty: unknown tty %.100s", tty);
+       session_dump();
+       return NULL;
+}
+
+static Session *
+session_by_channel(int id)
+{
+       int i;
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->chanid == id) {
+                       debug("session_by_channel: session %d channel %d",
+                           i, id);
+                       return s;
+               }
+       }
+       debug("session_by_channel: unknown channel %d", id);
+       session_dump();
+       return NULL;
+}
+
+static Session *
+session_by_x11_channel(int id)
+{
+       int i, j;
+
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+
+               if (s->x11_chanids == NULL || !s->used)
+                       continue;
+               for (j = 0; s->x11_chanids[j] != -1; j++) {
+                       if (s->x11_chanids[j] == id) {
+                               debug("session_by_x11_channel: session %d "
+                                   "channel %d", s->self, id);
+                               return s;
+                       }
+               }
+       }
+       debug("session_by_x11_channel: unknown channel %d", id);
+       session_dump();
+       return NULL;
+}
+
+static Session *
+session_by_pid(pid_t pid)
+{
+       int i;
+       debug("session_by_pid: pid %ld", (long)pid);
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->pid == pid)
+                       return s;
+       }
+       error("session_by_pid: unknown pid %ld", (long)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_check_eom();
+       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 (!PRIVSEP(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);
+
+       if (!use_privsep)
+               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_check_eom();
+       session_proctitle(s);
+       return 1;
+}
+
+static int
+session_subsystem_req(Session *s)
+{
+       struct stat st;
+       u_int len;
+       int success = 0;
+       char *prog, *cmd, *subsys = packet_get_string(&len);
+       u_int i;
+
+       packet_check_eom();
+       logit("subsystem request for %.100s by user %s", subsys,
+           s->pw->pw_name);
+
+       for (i = 0; i < options.num_subsystems; i++) {
+               if (strcmp(subsys, options.subsystem_name[i]) == 0) {
+                       prog = options.subsystem_command[i];
+                       cmd = options.subsystem_args[i];
+                       if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) {
+                               s->is_subsystem = SUBSYSTEM_INT_SFTP;
+                               debug("subsystem: %s", prog);
+                       } else {
+                               if (stat(prog, &st) < 0)
+                                       debug("subsystem: cannot stat %s: %s",
+                                           prog, strerror(errno));
+                               s->is_subsystem = SUBSYSTEM_EXT;
+                               debug("subsystem: exec() %s", cmd);
+                       }
+                       success = do_exec(s, cmd) == 0;
+                       break;
+               }
+       }
+
+       if (!success)
+               logit("subsystem request for %.100s failed, subsystem not found",
+                   subsys);
+
+       xfree(subsys);
+       return success;
+}
+
+static int
+session_x11_req(Session *s)
+{
+       int success;
+
+       if (s->auth_proto != NULL || s->auth_data != NULL) {
+               error("session_x11_req: session %d: "
+                   "x11 forwarding already active", s->self);
+               return 0;
+       }
+       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_check_eom();
+
+       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_check_eom();
+       return do_exec(s, NULL) == 0;
+}
+
+static int
+session_exec_req(Session *s)
+{
+       u_int len, success;
+
+       char *command = packet_get_string(&len);
+       packet_check_eom();
+       success = do_exec(s, command) == 0;
+       xfree(command);
+       return success;
+}
+
+static int
+session_break_req(Session *s)
+{
+
+       packet_get_int();       /* ignored */
+       packet_check_eom();
+
+       if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
+               return 0;
+       return 1;
+}
+
+static int
+session_env_req(Session *s)
+{
+       char *name, *val;
+       u_int name_len, val_len, i;
+
+       name = packet_get_string(&name_len);
+       val = packet_get_string(&val_len);
+       packet_check_eom();
+
+       /* Don't set too many environment variables */
+       if (s->num_env > 128) {
+               debug2("Ignoring env request %s: too many env vars", name);
+               goto fail;
+       }
+
+       for (i = 0; i < options.num_accept_env; i++) {
+               if (match_pattern(name, options.accept_env[i])) {
+                       debug2("Setting env %d: %s=%s", s->num_env, name, val);
+                       s->env = xrealloc(s->env, s->num_env + 1,
+                           sizeof(*s->env));
+                       s->env[s->num_env].name = name;
+                       s->env[s->num_env].val = val;
+                       s->num_env++;
+                       return (1);
+               }
+       }
+       debug2("Ignoring env request %s: disallowed name", name);
+
+ fail:
+       xfree(name);
+       xfree(val);
+       return (0);
+}
+
+static int
+session_auth_agent_req(Session *s)
+{
+       static int called = 0;
+       packet_check_eom();
+       if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
+               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);
+       }
+}
+
+int
+session_input_channel_req(Channel *c, const char *rtype)
+{
+       int success = 0;
+       Session *s;
+
+       if ((s = session_by_channel(c->self)) == NULL) {
+               logit("session_input_channel_req: no session %d req %.100s",
+                   c->self, rtype);
+               return 0;
+       }
+       debug("session_input_channel_req: session %d req %s", s->self, rtype);
+
+       /*
+        * 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);
+               } else if (strcmp(rtype, "env") == 0) {
+                       success = session_env_req(s);
+               }
+       }
+       if (strcmp(rtype, "window-change") == 0) {
+               success = session_window_change_req(s);
+       } else if (strcmp(rtype, "break") == 0) {
+               success = session_break_req(s);
+       }
+
+       return success;
+}
+
+void
+session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
+    int is_tty)
+{
+       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,
+           ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
+           1, is_tty, CHAN_SES_WINDOW_DEFAULT);
+}
+
+/*
+ * Function to perform pty cleanup. Also called if we get aborted abnormally
+ * (e.g., due to a dropped connection).
+ */
+void
+session_pty_cleanup2(Session *s)
+{
+       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, s->pw->pw_name);
+
+       /* Release the pseudo-tty. */
+       if (getuid() == 0)
+               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 (s->ptymaster != -1 && close(s->ptymaster) < 0)
+               error("close(s->ptymaster/%d): %s",
+                   s->ptymaster, strerror(errno));
+
+       /* unlink pty from session */
+       s->ttyfd = -1;
+}
+
+void
+session_pty_cleanup(Session *s)
+{
+       PRIVSEP(session_pty_cleanup2(s));
+}
+
+static char *
+sig2name(int sig)
+{
+#define SSH_SIG(x) if (sig == SIG ## x) return #x
+       SSH_SIG(ABRT);
+       SSH_SIG(ALRM);
+       SSH_SIG(FPE);
+       SSH_SIG(HUP);
+       SSH_SIG(ILL);
+       SSH_SIG(INT);
+       SSH_SIG(KILL);
+       SSH_SIG(PIPE);
+       SSH_SIG(QUIT);
+       SSH_SIG(SEGV);
+       SSH_SIG(TERM);
+       SSH_SIG(USR1);
+       SSH_SIG(USR2);
+#undef SSH_SIG
+       return "SIG@openssh.com";
+}
+
+static void
+session_close_x11(int id)
+{
+       Channel *c;
+
+       if ((c = channel_by_id(id)) == NULL) {
+               debug("session_close_x11: x11 channel %d missing", id);
+       } else {
+               /* Detach X11 listener */
+               debug("session_close_x11: detach x11 channel %d", id);
+               channel_cancel_cleanup(id);
+               if (c->ostate != CHAN_OUTPUT_CLOSED)
+                       chan_mark_dead(c);
+       }
+}
+
+static void
+session_close_single_x11(int id, void *arg)
+{
+       Session *s;
+       u_int i;
+
+       debug3("session_close_single_x11: channel %d", id);
+       channel_cancel_cleanup(id);
+       if ((s = session_by_x11_channel(id)) == NULL)
+               fatal("session_close_single_x11: no x11 channel %d", id);
+       for (i = 0; s->x11_chanids[i] != -1; i++) {
+               debug("session_close_single_x11: session %d: "
+                   "closing channel %d", s->self, s->x11_chanids[i]);
+               /*
+                * The channel "id" is already closing, but make sure we
+                * close all of its siblings.
+                */
+               if (s->x11_chanids[i] != id)
+                       session_close_x11(s->x11_chanids[i]);
+       }
+       xfree(s->x11_chanids);
+       s->x11_chanids = NULL;
+       if (s->display) {
+               xfree(s->display);
+               s->display = NULL;
+       }
+       if (s->auth_proto) {
+               xfree(s->auth_proto);
+               s->auth_proto = NULL;
+       }
+       if (s->auth_data) {
+               xfree(s->auth_data);
+               s->auth_data = NULL;
+       }
+       if (s->auth_display) {
+               xfree(s->auth_display);
+               s->auth_display = NULL;
+       }
+}
+
+static void
+session_exit_message(Session *s, int status)
+{
+       Channel *c;
+
+       if ((c = channel_lookup(s->chanid)) == NULL)
+               fatal("session_exit_message: session %d: no channel %d",
+                   s->self, s->chanid);
+       debug("session_exit_message: session %d channel %d pid %ld",
+           s->self, s->chanid, (long)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_cstring(sig2name(WTERMSIG(status)));
+#ifdef WCOREDUMP
+               packet_put_char(WCOREDUMP(status)? 1 : 0);
+#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);
+
+       /*
+        * Adjust cleanup callback attachment to send close messages when
+        * the channel gets EOF. The session will be then be closed
+        * by session_close_by_channel when the childs close their fds.
+        */
+       channel_register_cleanup(c->self, session_close_by_channel, 1);
+
+       /*
+        * 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);
+}
+
+void
+session_close(Session *s)
+{
+       u_int i;
+
+       debug("session_close: session %d pid %ld", s->self, (long)s->pid);
+       if (s->ttyfd != -1)
+               session_pty_cleanup(s);
+       if (s->term)
+               xfree(s->term);
+       if (s->display)
+               xfree(s->display);
+       if (s->x11_chanids)
+               xfree(s->x11_chanids);
+       if (s->auth_display)
+               xfree(s->auth_display);
+       if (s->auth_data)
+               xfree(s->auth_data);
+       if (s->auth_proto)
+               xfree(s->auth_proto);
+       if (s->env != NULL) {
+               for (i = 0; i < s->num_env; i++) {
+                       xfree(s->env[i].name);
+                       xfree(s->env[i].val);
+               }
+               xfree(s->env);
+       }
+       session_proctitle(s);
+       session_unused(s->self);
+}
+
+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 %ld",
+                   (long)pid);
+               return;
+       }
+       if (s->chanid != -1)
+               session_exit_message(s, status);
+       if (s->ttyfd != -1)
+               session_pty_cleanup(s);
+       s->pid = 0;
+}
+
+/*
+ * 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);
+       u_int i;
+
+       if (s == NULL) {
+               debug("session_close_by_channel: no session for id %d", id);
+               return;
+       }
+       debug("session_close_by_channel: channel %d child %ld",
+           id, (long)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)
+                       session_pty_cleanup(s);
+               return;
+       }
+       /* detach by removing callback */
+       channel_cancel_cleanup(s->chanid);
+
+       /* Close any X11 listeners associated with this session */
+       if (s->x11_chanids != NULL) {
+               for (i = 0; s->x11_chanids[i] != -1; i++) {
+                       session_close_x11(s->x11_chanids[i]);
+                       s->x11_chanids[i] = -1;
+               }
+       }
+
+       s->chanid = -1;
+       session_close(s);
+}
+
+void
+session_destroy_all(void (*closefunc)(Session *))
+{
+       int i;
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+               if (s->used) {
+                       if (closefunc != NULL)
+                               closefunc(s);
+                       else
+                               session_close(s);
+               }
+       }
+}
+
+static char *
+session_tty_list(void)
+{
+       static char buf[1024];
+       int i;
+       char *cp;
+
+       buf[0] = '\0';
+       for (i = 0; i < sessions_nalloc; i++) {
+               Session *s = &sessions[i];
+               if (s->used && s->ttyfd != -1) {
+
+                       if (strncmp(s->tty, "/dev/", 5) != 0) {
+                               cp = strrchr(s->tty, '/');
+                               cp = (cp == NULL) ? s->tty : cp + 1;
+                       } else
+                               cp = s->tty + 5;
+
+                       if (buf[0] != '\0')
+                               strlcat(buf, ",", sizeof buf);
+                       strlcat(buf, cp, 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;
+       char display[512], auth_display[512];
+       char hostname[MAXHOSTNAMELEN];
+       u_int i;
+
+       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;
+       }
+       if (x11_create_display_inet(options.x11_display_offset,
+           options.x11_use_localhost, s->single_connection,
+           &s->display_number, &s->x11_chanids) == -1) {
+               debug("x11_create_display_inet failed.");
+               return 0;
+       }
+       for (i = 0; s->x11_chanids[i] != -1; i++) {
+               channel_register_cleanup(s->x11_chanids[i],
+                   session_close_single_x11, 0);
+       }
+
+       /* Set up a suitable value for the DISPLAY variable. */
+       if (gethostname(hostname, sizeof(hostname)) < 0)
+               fatal("gethostname: %.100s", strerror(errno));
+       /*
+        * auth_display must be used as the displayname when the
+        * authorization entry is added with xauth(1).  This will be
+        * different than the DISPLAY string for localhost displays.
+        */
+       if (options.x11_use_localhost) {
+               snprintf(display, sizeof display, "localhost:%u.%u",
+                   s->display_number, s->screen);
+               snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
+                   s->display_number, s->screen);
+               s->display = xstrdup(display);
+               s->auth_display = xstrdup(auth_display);
+       } else {
+#ifdef IPADDR_IN_DISPLAY
+               struct hostent *he;
+               struct in_addr my_addr;
+
+               he = gethostbyname(hostname);
+               if (he == NULL) {
+                       error("Can't get IP address for X11 DISPLAY.");
+                       packet_send_debug("Can't get IP address for X11 DISPLAY.");
+                       return 0;
+               }
+               memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
+               snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr),
+                   s->display_number, s->screen);
+#else
+               snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
+                   s->display_number, s->screen);
+#endif
+               s->display = xstrdup(display);
+               s->auth_display = xstrdup(display);
+       }
+
+       return 1;
+}
+
+static void
+do_authenticated2(Authctxt *authctxt)
+{
+       server_loop2(authctxt);
+}
+
+void
+do_cleanup(Authctxt *authctxt)
+{
+       static int called = 0;
+
+       debug("do_cleanup");
+
+       /* no cleanup if we're in the child for login shell */
+       if (is_child)
+               return;
+
+       /* avoid double cleanup */
+       if (called)
+               return;
+       called = 1;
+
+       if (authctxt == NULL)
+               return;
+
+#ifdef USE_PAM
+       if (options.use_pam) {
+               sshpam_cleanup();
+               sshpam_thread_cleanup();
+       }
+#endif
+
+       if (!authctxt->authenticated)
+               return;
+
+#ifdef KRB5
+       if (options.kerberos_ticket_cleanup &&
+           authctxt->krb5_ctx)
+               krb5_cleanup_proc(authctxt);
+#endif
+
+#ifdef GSSAPI
+       if (compat20 && options.gss_cleanup_creds)
+               ssh_gssapi_cleanup_creds();
+#endif
+
+       /* remove agent socket */
+       auth_sock_cleanup_proc(authctxt->pw);
+
+       /*
+        * Cleanup ptys/utmp only if privsep is disabled,
+        * or if running in monitor.
+        */
+       if (!use_privsep || mm_is_monitor())
+               session_destroy_all(session_pty_cleanup2);
+}
diff --git a/session.h b/session.h
new file mode 100644 (file)
index 0000000..cbb8e3a
--- /dev/null
+++ b/session.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: session.h,v 1.30 2008/05/08 12:21:16 djm 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
+
+#define TTYSZ 64
+typedef struct Session Session;
+struct Session {
+       int     used;
+       int     self;
+       int     next_unused;
+       struct passwd *pw;
+       Authctxt *authctxt;
+       pid_t   pid;
+
+       /* tty */
+       char    *term;
+       int     ptyfd, ttyfd, ptymaster;
+       u_int   row, col, xpixel, ypixel;
+       char    tty[TTYSZ];
+
+       /* X11 */
+       u_int   display_number;
+       char    *display;
+       u_int   screen;
+       char    *auth_display;
+       char    *auth_proto;
+       char    *auth_data;
+       int     single_connection;
+
+       /* proto 2 */
+       int     chanid;
+       int     *x11_chanids;
+       int     is_subsystem;
+       u_int   num_env;
+       struct {
+               char    *name;
+               char    *val;
+       } *env;
+};
+
+void    do_authenticated(Authctxt *);
+void    do_cleanup(Authctxt *);
+
+int     session_open(Authctxt *, int);
+void    session_unused(int);
+int     session_input_channel_req(Channel *, const char *);
+void    session_close_by_pid(pid_t, int);
+void    session_close_by_channel(int, void *);
+void    session_destroy_all(void (*)(Session *));
+void    session_pty_cleanup2(Session *);
+
+Session        *session_new(void);
+Session        *session_by_tty(char *);
+void    session_close(Session *);
+void    do_setusercontext(struct passwd *);
+void    child_set_env(char ***envp, u_int *envsizep, const char *name,
+                      const char *value);
+
+#endif
diff --git a/sftp-client.c b/sftp-client.c
new file mode 100644 (file)
index 0000000..caa384b
--- /dev/null
@@ -0,0 +1,1638 @@
+/* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 djm Exp $ */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* XXX: memleaks */
+/* XXX: signed vs unsigned */
+/* XXX: remove all logging, only return status codes */
+/* XXX: copy between two remote sites */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+#include "openbsd-compat/sys-queue.h"
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <sys/uio.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "atomicio.h"
+#include "progressmeter.h"
+#include "misc.h"
+
+#include "sftp.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+
+extern volatile sig_atomic_t interrupted;
+extern int showprogress;
+
+/* Minimum amount of data to read at a time */
+#define MIN_READ_SIZE  512
+
+/* Maximum depth to descend in directory trees */
+#define MAX_DIR_DEPTH 64
+
+struct sftp_conn {
+       int fd_in;
+       int fd_out;
+       u_int transfer_buflen;
+       u_int num_requests;
+       u_int version;
+       u_int msg_id;
+#define SFTP_EXT_POSIX_RENAME  0x00000001
+#define SFTP_EXT_STATVFS       0x00000002
+#define SFTP_EXT_FSTATVFS      0x00000004
+#define SFTP_EXT_HARDLINK      0x00000008
+       u_int exts;
+       u_int64_t limit_kbps;
+       struct bwlimit bwlimit_in, bwlimit_out;
+};
+
+static char *
+get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
+    const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
+
+/* ARGSUSED */
+static int
+sftpio(void *_bwlimit, size_t amount)
+{
+       struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
+
+       bandwidth_limit(bwlimit, amount);
+       return 0;
+}
+
+static void
+send_msg(struct sftp_conn *conn, Buffer *m)
+{
+       u_char mlen[4];
+       struct iovec iov[2];
+
+       if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
+               fatal("Outbound message too long %u", buffer_len(m));
+
+       /* Send length first */
+       put_u32(mlen, buffer_len(m));
+       iov[0].iov_base = mlen;
+       iov[0].iov_len = sizeof(mlen);
+       iov[1].iov_base = buffer_ptr(m);
+       iov[1].iov_len = buffer_len(m);
+
+       if (atomiciov6(writev, conn->fd_out, iov, 2,
+           conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 
+           buffer_len(m) + sizeof(mlen))
+               fatal("Couldn't send packet: %s", strerror(errno));
+
+       buffer_clear(m);
+}
+
+static void
+get_msg(struct sftp_conn *conn, Buffer *m)
+{
+       u_int msg_len;
+
+       buffer_append_space(m, 4);
+       if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4,
+           conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
+               if (errno == EPIPE)
+                       fatal("Connection closed");
+               else
+                       fatal("Couldn't read packet: %s", strerror(errno));
+       }
+
+       msg_len = buffer_get_int(m);
+       if (msg_len > SFTP_MAX_MSG_LENGTH)
+               fatal("Received message too long %u", msg_len);
+
+       buffer_append_space(m, msg_len);
+       if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len,
+           conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
+           != msg_len) {
+               if (errno == EPIPE)
+                       fatal("Connection closed");
+               else
+                       fatal("Read packet: %s", strerror(errno));
+       }
+}
+
+static void
+send_string_request(struct sftp_conn *conn, 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(conn, &msg);
+       debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
+       buffer_free(&msg);
+}
+
+static void
+send_string_attrs_request(struct sftp_conn *conn, 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(conn, &msg);
+       debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
+       buffer_free(&msg);
+}
+
+static u_int
+get_status(struct sftp_conn *conn, u_int expected_id)
+{
+       Buffer msg;
+       u_int type, id, status;
+
+       buffer_init(&msg);
+       get_msg(conn, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", id, expected_id);
+       if (type != SSH2_FXP_STATUS)
+               fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
+                   SSH2_FXP_STATUS, type);
+
+       status = buffer_get_int(&msg);
+       buffer_free(&msg);
+
+       debug3("SSH2_FXP_STATUS %u", status);
+
+       return status;
+}
+
+static char *
+get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
+    const char *errfmt, ...)
+{
+       Buffer msg;
+       u_int type, id;
+       char *handle, errmsg[256];
+       va_list args;
+       int status;
+
+       va_start(args, errfmt);
+       if (errfmt != NULL)
+               vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
+       va_end(args);
+
+       buffer_init(&msg);
+       get_msg(conn, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("%s: ID mismatch (%u != %u)",
+                   errfmt == NULL ? __func__ : errmsg, id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               status = buffer_get_int(&msg);
+               if (errfmt != NULL)
+                       error("%s: %s", errmsg, fx2txt(status));
+               buffer_free(&msg);
+               return(NULL);
+       } else if (type != SSH2_FXP_HANDLE)
+               fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
+                   errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
+
+       handle = buffer_get_string(&msg, len);
+       buffer_free(&msg);
+
+       return(handle);
+}
+
+static Attrib *
+get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
+{
+       Buffer msg;
+       u_int type, id;
+       Attrib *a;
+
+       buffer_init(&msg);
+       get_msg(conn, &msg);
+
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       debug3("Received stat reply T:%u I:%u", type, id);
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               int status = buffer_get_int(&msg);
+
+               if (quiet)
+                       debug("Couldn't stat remote file: %s", fx2txt(status));
+               else
+                       error("Couldn't stat remote file: %s", fx2txt(status));
+               buffer_free(&msg);
+               return(NULL);
+       } else if (type != SSH2_FXP_ATTRS) {
+               fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
+                   SSH2_FXP_ATTRS, type);
+       }
+       a = decode_attrib(&msg);
+       buffer_free(&msg);
+
+       return(a);
+}
+
+static int
+get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
+    u_int expected_id, int quiet)
+{
+       Buffer msg;
+       u_int type, id, flag;
+
+       buffer_init(&msg);
+       get_msg(conn, &msg);
+
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       debug3("Received statvfs reply T:%u I:%u", type, id);
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", id, expected_id);
+       if (type == SSH2_FXP_STATUS) {
+               int status = buffer_get_int(&msg);
+
+               if (quiet)
+                       debug("Couldn't statvfs: %s", fx2txt(status));
+               else
+                       error("Couldn't statvfs: %s", fx2txt(status));
+               buffer_free(&msg);
+               return -1;
+       } else if (type != SSH2_FXP_EXTENDED_REPLY) {
+               fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+                   SSH2_FXP_EXTENDED_REPLY, type);
+       }
+
+       bzero(st, sizeof(*st));
+       st->f_bsize = buffer_get_int64(&msg);
+       st->f_frsize = buffer_get_int64(&msg);
+       st->f_blocks = buffer_get_int64(&msg);
+       st->f_bfree = buffer_get_int64(&msg);
+       st->f_bavail = buffer_get_int64(&msg);
+       st->f_files = buffer_get_int64(&msg);
+       st->f_ffree = buffer_get_int64(&msg);
+       st->f_favail = buffer_get_int64(&msg);
+       st->f_fsid = buffer_get_int64(&msg);
+       flag = buffer_get_int64(&msg);
+       st->f_namemax = buffer_get_int64(&msg);
+
+       st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
+       st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
+
+       buffer_free(&msg);
+
+       return 0;
+}
+
+struct sftp_conn *
+do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
+    u_int64_t limit_kbps)
+{
+       u_int type;
+       Buffer msg;
+       struct sftp_conn *ret;
+
+       ret = xmalloc(sizeof(*ret));
+       ret->fd_in = fd_in;
+       ret->fd_out = fd_out;
+       ret->transfer_buflen = transfer_buflen;
+       ret->num_requests = num_requests;
+       ret->exts = 0;
+       ret->limit_kbps = 0;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_INIT);
+       buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
+       send_msg(ret, &msg);
+
+       buffer_clear(&msg);
+
+       get_msg(ret, &msg);
+
+       /* Expecting a VERSION reply */
+       if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
+               error("Invalid packet back from SSH2_FXP_INIT (type %u)",
+                   type);
+               buffer_free(&msg);
+               return(NULL);
+       }
+       ret->version = buffer_get_int(&msg);
+
+       debug2("Remote version: %u", ret->version);
+
+       /* Check for extensions */
+       while (buffer_len(&msg) > 0) {
+               char *name = buffer_get_string(&msg, NULL);
+               char *value = buffer_get_string(&msg, NULL);
+               int known = 0;
+
+               if (strcmp(name, "posix-rename@openssh.com") == 0 &&
+                   strcmp(value, "1") == 0) {
+                       ret->exts |= SFTP_EXT_POSIX_RENAME;
+                       known = 1;
+               } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
+                   strcmp(value, "2") == 0) {
+                       ret->exts |= SFTP_EXT_STATVFS;
+                       known = 1;
+               } else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
+                   strcmp(value, "2") == 0) {
+                       ret->exts |= SFTP_EXT_FSTATVFS;
+                       known = 1;
+               } else if (strcmp(name, "hardlink@openssh.com") == 0 &&
+                   strcmp(value, "1") == 0) {
+                       ret->exts |= SFTP_EXT_HARDLINK;
+                       known = 1;
+               }
+               if (known) {
+                       debug2("Server supports extension \"%s\" revision %s",
+                           name, value);
+               } else {
+                       debug2("Unrecognised server extension \"%s\"", name);
+               }
+               xfree(name);
+               xfree(value);
+       }
+
+       buffer_free(&msg);
+
+       /* Some filexfer v.0 servers don't support large packets */
+       if (ret->version == 0)
+               ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
+
+       ret->limit_kbps = limit_kbps;
+       if (ret->limit_kbps > 0) {
+               bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
+                   ret->transfer_buflen);
+               bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
+                   ret->transfer_buflen);
+       }
+
+       return ret;
+}
+
+u_int
+sftp_proto_version(struct sftp_conn *conn)
+{
+       return conn->version;
+}
+
+int
+do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
+{
+       u_int id, status;
+       Buffer msg;
+
+       buffer_init(&msg);
+
+       id = conn->msg_id++;
+       buffer_put_char(&msg, SSH2_FXP_CLOSE);
+       buffer_put_int(&msg, id);
+       buffer_put_string(&msg, handle, handle_len);
+       send_msg(conn, &msg);
+       debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't close file: %s", fx2txt(status));
+
+       buffer_free(&msg);
+
+       return status;
+}
+
+
+static int
+do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
+    SFTP_DIRENT ***dir)
+{
+       Buffer msg;
+       u_int count, type, id, handle_len, i, expected_id, ents = 0;
+       char *handle;
+
+       id = conn->msg_id++;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_OPENDIR);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, path);
+       send_msg(conn, &msg);
+
+       buffer_clear(&msg);
+
+       handle = get_handle(conn, id, &handle_len,
+           "remote readdir(\"%s\")", path);
+       if (handle == NULL)
+               return -1;
+
+       if (dir) {
+               ents = 0;
+               *dir = xmalloc(sizeof(**dir));
+               (*dir)[0] = NULL;
+       }
+
+       for (; !interrupted;) {
+               id = expected_id = conn->msg_id++;
+
+               debug3("Sending SSH2_FXP_READDIR I:%u", 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(conn, &msg);
+
+               buffer_clear(&msg);
+
+               get_msg(conn, &msg);
+
+               type = buffer_get_char(&msg);
+               id = buffer_get_int(&msg);
+
+               debug3("Received reply T:%u I:%u", type, id);
+
+               if (id != expected_id)
+                       fatal("ID mismatch (%u != %u)", id, expected_id);
+
+               if (type == SSH2_FXP_STATUS) {
+                       int status = buffer_get_int(&msg);
+
+                       debug3("Received SSH2_FXP_STATUS %d", status);
+
+                       if (status == SSH2_FX_EOF) {
+                               break;
+                       } else {
+                               error("Couldn't read directory: %s",
+                                   fx2txt(status));
+                               do_close(conn, handle, handle_len);
+                               xfree(handle);
+                               return(status);
+                       }
+               } else if (type != SSH2_FXP_NAME)
+                       fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
+                           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);
+
+                       /*
+                        * Directory entries should never contain '/'
+                        * These can be used to attack recursive ops
+                        * (e.g. send '../../../../etc/passwd')
+                        */
+                       if (strchr(filename, '/') != NULL) {
+                               error("Server sent suspect path \"%s\" "
+                                   "during readdir of \"%s\"", filename, path);
+                               goto next;
+                       }
+
+                       if (dir) {
+                               *dir = xrealloc(*dir, ents + 2, sizeof(**dir));
+                               (*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;
+                       }
+ next:
+                       xfree(filename);
+                       xfree(longname);
+               }
+       }
+
+       buffer_free(&msg);
+       do_close(conn, handle, handle_len);
+       xfree(handle);
+
+       /* Don't return partial matches on interrupt */
+       if (interrupted && dir != NULL && *dir != NULL) {
+               free_sftp_dirents(*dir);
+               *dir = xmalloc(sizeof(**dir));
+               **dir = NULL;
+       }
+
+       return 0;
+}
+
+int
+do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
+{
+       return(do_lsreaddir(conn, 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(struct sftp_conn *conn, char *path)
+{
+       u_int status, id;
+
+       debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
+
+       id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't delete file: %s", fx2txt(status));
+       return(status);
+}
+
+int
+do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
+{
+       u_int status, id;
+
+       id = conn->msg_id++;
+       send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
+           strlen(path), a);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK && printflag)
+               error("Couldn't create directory: %s", fx2txt(status));
+
+       return(status);
+}
+
+int
+do_rmdir(struct sftp_conn *conn, char *path)
+{
+       u_int status, id;
+
+       id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_RMDIR, path,
+           strlen(path));
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't remove directory: %s", fx2txt(status));
+
+       return(status);
+}
+
+Attrib *
+do_stat(struct sftp_conn *conn, char *path, int quiet)
+{
+       u_int id;
+
+       id = conn->msg_id++;
+
+       send_string_request(conn, id,
+           conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
+           path, strlen(path));
+
+       return(get_decode_stat(conn, id, quiet));
+}
+
+Attrib *
+do_lstat(struct sftp_conn *conn, char *path, int quiet)
+{
+       u_int id;
+
+       if (conn->version == 0) {
+               if (quiet)
+                       debug("Server version does not support lstat operation");
+               else
+                       logit("Server version does not support lstat operation");
+               return(do_stat(conn, path, quiet));
+       }
+
+       id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_LSTAT, path,
+           strlen(path));
+
+       return(get_decode_stat(conn, id, quiet));
+}
+
+#ifdef notyet
+Attrib *
+do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
+{
+       u_int id;
+
+       id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
+           handle_len);
+
+       return(get_decode_stat(conn, id, quiet));
+}
+#endif
+
+int
+do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
+{
+       u_int status, id;
+
+       id = conn->msg_id++;
+       send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
+           strlen(path), a);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't setstat on \"%s\": %s", path,
+                   fx2txt(status));
+
+       return(status);
+}
+
+int
+do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
+    Attrib *a)
+{
+       u_int status, id;
+
+       id = conn->msg_id++;
+       send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
+           handle_len, a);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't fsetstat: %s", fx2txt(status));
+
+       return(status);
+}
+
+char *
+do_realpath(struct sftp_conn *conn, char *path)
+{
+       Buffer msg;
+       u_int type, expected_id, count, id;
+       char *filename, *longname;
+       Attrib *a;
+
+       expected_id = id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_REALPATH, path,
+           strlen(path));
+
+       buffer_init(&msg);
+
+       get_msg(conn, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", id, expected_id);
+
+       if (type == SSH2_FXP_STATUS) {
+               u_int status = buffer_get_int(&msg);
+
+               error("Couldn't canonicalise: %s", fx2txt(status));
+               buffer_free(&msg);
+               return NULL;
+       } else if (type != SSH2_FXP_NAME)
+               fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
+                   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(struct sftp_conn *conn, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       buffer_init(&msg);
+
+       /* Send rename request */
+       id = conn->msg_id++;
+       if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
+               buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+               buffer_put_int(&msg, id);
+               buffer_put_cstring(&msg, "posix-rename@openssh.com");
+       } else {
+               buffer_put_char(&msg, SSH2_FXP_RENAME);
+               buffer_put_int(&msg, id);
+       }
+       buffer_put_cstring(&msg, oldpath);
+       buffer_put_cstring(&msg, newpath);
+       send_msg(conn, &msg);
+       debug3("Sent message %s \"%s\" -> \"%s\"",
+           (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
+           "SSH2_FXP_RENAME", oldpath, newpath);
+       buffer_free(&msg);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
+                   newpath, fx2txt(status));
+
+       return(status);
+}
+
+int
+do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       buffer_init(&msg);
+
+       /* Send link request */
+       id = conn->msg_id++;
+       if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
+               error("Server does not support hardlink@openssh.com extension");
+               return -1;
+       }
+
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, "hardlink@openssh.com");
+       buffer_put_cstring(&msg, oldpath);
+       buffer_put_cstring(&msg, newpath);
+       send_msg(conn, &msg);
+       debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
+              oldpath, newpath);
+       buffer_free(&msg);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
+                   newpath, fx2txt(status));
+
+       return(status);
+}
+
+int
+do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
+{
+       Buffer msg;
+       u_int status, id;
+
+       if (conn->version < 3) {
+               error("This server does not support the symlink operation");
+               return(SSH2_FX_OP_UNSUPPORTED);
+       }
+
+       buffer_init(&msg);
+
+       /* Send symlink request */
+       id = conn->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(conn, &msg);
+       debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
+           newpath);
+       buffer_free(&msg);
+
+       status = get_status(conn, id);
+       if (status != SSH2_FX_OK)
+               error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
+                   newpath, fx2txt(status));
+
+       return(status);
+}
+
+#ifdef notyet
+char *
+do_readlink(struct sftp_conn *conn, char *path)
+{
+       Buffer msg;
+       u_int type, expected_id, count, id;
+       char *filename, *longname;
+       Attrib *a;
+
+       expected_id = id = conn->msg_id++;
+       send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
+
+       buffer_init(&msg);
+
+       get_msg(conn, &msg);
+       type = buffer_get_char(&msg);
+       id = buffer_get_int(&msg);
+
+       if (id != expected_id)
+               fatal("ID mismatch (%u != %u)", 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(%u) packet, got %u",
+                   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);
+}
+#endif
+
+int
+do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
+    int quiet)
+{
+       Buffer msg;
+       u_int id;
+
+       if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
+               error("Server does not support statvfs@openssh.com extension");
+               return -1;
+       }
+
+       id = conn->msg_id++;
+
+       buffer_init(&msg);
+       buffer_clear(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, "statvfs@openssh.com");
+       buffer_put_cstring(&msg, path);
+       send_msg(conn, &msg);
+       buffer_free(&msg);
+
+       return get_decode_statvfs(conn, st, id, quiet);
+}
+
+#ifdef notyet
+int
+do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
+    struct sftp_statvfs *st, int quiet)
+{
+       Buffer msg;
+       u_int id;
+
+       if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
+               error("Server does not support fstatvfs@openssh.com extension");
+               return -1;
+       }
+
+       id = conn->msg_id++;
+
+       buffer_init(&msg);
+       buffer_clear(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+       buffer_put_int(&msg, id);
+       buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+       buffer_put_string(&msg, handle, handle_len);
+       send_msg(conn, &msg);
+       buffer_free(&msg);
+
+       return get_decode_statvfs(conn, st, id, quiet);
+}
+#endif
+
+static void
+send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
+    u_int len, char *handle, u_int handle_len)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       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, len);
+       send_msg(conn, &msg);
+       buffer_free(&msg);
+}
+
+int
+do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
+    Attrib *a, int pflag)
+{
+       Attrib junk;
+       Buffer msg;
+       char *handle;
+       int local_fd, status = 0, write_error;
+       int read_error, write_errno;
+       u_int64_t offset, size;
+       u_int handle_len, mode, type, id, buflen, num_req, max_req;
+       off_t progress_counter;
+       struct request {
+               u_int id;
+               u_int len;
+               u_int64_t offset;
+               TAILQ_ENTRY(request) tq;
+       };
+       TAILQ_HEAD(reqhead, request) requests;
+       struct request *req;
+
+       TAILQ_INIT(&requests);
+
+       if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
+               return -1;
+
+       /* Do not preserve set[ug]id here, as we do not preserve ownership */
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               mode = a->perm & 0777;
+       else
+               mode = 0666;
+
+       if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+           (!S_ISREG(a->perm))) {
+               error("Cannot download non-regular file: %s", remote_path);
+               return(-1);
+       }
+
+       if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
+               size = a->size;
+       else
+               size = 0;
+
+       buflen = conn->transfer_buflen;
+       buffer_init(&msg);
+
+       /* Send open request */
+       id = conn->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(conn, &msg);
+       debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
+
+       handle = get_handle(conn, id, &handle_len,
+           "remote open(\"%s\")", remote_path);
+       if (handle == NULL) {
+               buffer_free(&msg);
+               return(-1);
+       }
+
+       local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
+           mode | S_IWRITE);
+       if (local_fd == -1) {
+               error("Couldn't open local file \"%s\" for writing: %s",
+                   local_path, strerror(errno));
+               do_close(conn, handle, handle_len);
+               buffer_free(&msg);
+               xfree(handle);
+               return(-1);
+       }
+
+       /* Read from remote and write to local */
+       write_error = read_error = write_errno = num_req = offset = 0;
+       max_req = 1;
+       progress_counter = 0;
+
+       if (showprogress && size != 0)
+               start_progress_meter(remote_path, size, &progress_counter);
+
+       while (num_req > 0 || max_req > 0) {
+               char *data;
+               u_int len;
+
+               /*
+                * Simulate EOF on interrupt: stop sending new requests and
+                * allow outstanding requests to drain gracefully
+                */
+               if (interrupted) {
+                       if (num_req == 0) /* If we haven't started yet... */
+                               break;
+                       max_req = 0;
+               }
+
+               /* Send some more requests */
+               while (num_req < max_req) {
+                       debug3("Request range %llu -> %llu (%d/%d)",
+                           (unsigned long long)offset,
+                           (unsigned long long)offset + buflen - 1,
+                           num_req, max_req);
+                       req = xmalloc(sizeof(*req));
+                       req->id = conn->msg_id++;
+                       req->len = buflen;
+                       req->offset = offset;
+                       offset += buflen;
+                       num_req++;
+                       TAILQ_INSERT_TAIL(&requests, req, tq);
+                       send_read_request(conn, req->id, req->offset,
+                           req->len, handle, handle_len);
+               }
+
+               buffer_clear(&msg);
+               get_msg(conn, &msg);
+               type = buffer_get_char(&msg);
+               id = buffer_get_int(&msg);
+               debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
+
+               /* Find the request in our queue */
+               for (req = TAILQ_FIRST(&requests);
+                   req != NULL && req->id != id;
+                   req = TAILQ_NEXT(req, tq))
+                       ;
+               if (req == NULL)
+                       fatal("Unexpected reply %u", id);
+
+               switch (type) {
+               case SSH2_FXP_STATUS:
+                       status = buffer_get_int(&msg);
+                       if (status != SSH2_FX_EOF)
+                               read_error = 1;
+                       max_req = 0;
+                       TAILQ_REMOVE(&requests, req, tq);
+                       xfree(req);
+                       num_req--;
+                       break;
+               case SSH2_FXP_DATA:
+                       data = buffer_get_string(&msg, &len);
+                       debug3("Received data %llu -> %llu",
+                           (unsigned long long)req->offset,
+                           (unsigned long long)req->offset + len - 1);
+                       if (len > req->len)
+                               fatal("Received more data than asked for "
+                                   "%u > %u", len, req->len);
+                       if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
+                           atomicio(vwrite, local_fd, data, len) != len) &&
+                           !write_error) {
+                               write_errno = errno;
+                               write_error = 1;
+                               max_req = 0;
+                       }
+                       progress_counter += len;
+                       xfree(data);
+
+                       if (len == req->len) {
+                               TAILQ_REMOVE(&requests, req, tq);
+                               xfree(req);
+                               num_req--;
+                       } else {
+                               /* Resend the request for the missing data */
+                               debug3("Short data block, re-requesting "
+                                   "%llu -> %llu (%2d)",
+                                   (unsigned long long)req->offset + len,
+                                   (unsigned long long)req->offset +
+                                   req->len - 1, num_req);
+                               req->id = conn->msg_id++;
+                               req->len -= len;
+                               req->offset += len;
+                               send_read_request(conn, req->id,
+                                   req->offset, req->len, handle, handle_len);
+                               /* Reduce the request size */
+                               if (len < buflen)
+                                       buflen = MAX(MIN_READ_SIZE, len);
+                       }
+                       if (max_req > 0) { /* max_req = 0 iff EOF received */
+                               if (size > 0 && offset > size) {
+                                       /* Only one request at a time
+                                        * after the expected EOF */
+                                       debug3("Finish at %llu (%2d)",
+                                           (unsigned long long)offset,
+                                           num_req);
+                                       max_req = 1;
+                               } else if (max_req <= conn->num_requests) {
+                                       ++max_req;
+                               }
+                       }
+                       break;
+               default:
+                       fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
+                           SSH2_FXP_DATA, type);
+               }
+       }
+
+       if (showprogress && size)
+               stop_progress_meter();
+
+       /* Sanity check */
+       if (TAILQ_FIRST(&requests) != NULL)
+               fatal("Transfer complete, but requests still in queue");
+
+       if (read_error) {
+               error("Couldn't read from remote file \"%s\" : %s",
+                   remote_path, fx2txt(status));
+               do_close(conn, handle, handle_len);
+       } else if (write_error) {
+               error("Couldn't write to \"%s\": %s", local_path,
+                   strerror(write_errno));
+               status = -1;
+               do_close(conn, handle, handle_len);
+       } else {
+               status = do_close(conn, 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));
+               }
+       }
+       close(local_fd);
+       buffer_free(&msg);
+       xfree(handle);
+
+       return(status);
+}
+
+static int
+download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
+    Attrib *dirattrib, int pflag, int printflag, int depth)
+{
+       int i, ret = 0;
+       SFTP_DIRENT **dir_entries;
+       char *filename, *new_src, *new_dst;
+       mode_t mode = 0777;
+
+       if (depth >= MAX_DIR_DEPTH) {
+               error("Maximum directory depth exceeded: %d levels", depth);
+               return -1;
+       }
+
+       if (dirattrib == NULL &&
+           (dirattrib = do_stat(conn, src, 1)) == NULL) {
+               error("Unable to stat remote directory \"%s\"", src);
+               return -1;
+       }
+       if (!S_ISDIR(dirattrib->perm)) {
+               error("\"%s\" is not a directory", src);
+               return -1;
+       }
+       if (printflag)
+               printf("Retrieving %s\n", src);
+
+       if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
+               mode = dirattrib->perm & 01777;
+       else {
+               debug("Server did not send permissions for "
+                   "directory \"%s\"", dst);
+       }
+
+       if (mkdir(dst, mode) == -1 && errno != EEXIST) {
+               error("mkdir %s: %s", dst, strerror(errno));
+               return -1;
+       }
+
+       if (do_readdir(conn, src, &dir_entries) == -1) {
+               error("%s: Failed to get directory contents", src);
+               return -1;
+       }
+
+       for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
+               filename = dir_entries[i]->filename;
+
+               new_dst = path_append(dst, filename);
+               new_src = path_append(src, filename);
+
+               if (S_ISDIR(dir_entries[i]->a.perm)) {
+                       if (strcmp(filename, ".") == 0 ||
+                           strcmp(filename, "..") == 0)
+                               continue;
+                       if (download_dir_internal(conn, new_src, new_dst,
+                           &(dir_entries[i]->a), pflag, printflag,
+                           depth + 1) == -1)
+                               ret = -1;
+               } else if (S_ISREG(dir_entries[i]->a.perm) ) {
+                       if (do_download(conn, new_src, new_dst,
+                           &(dir_entries[i]->a), pflag) == -1) {
+                               error("Download of file %s to %s failed",
+                                   new_src, new_dst);
+                               ret = -1;
+                       }
+               } else
+                       logit("%s: not a regular file\n", new_src);
+
+               xfree(new_dst);
+               xfree(new_src);
+       }
+
+       if (pflag) {
+               if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+                       struct timeval tv[2];
+                       tv[0].tv_sec = dirattrib->atime;
+                       tv[1].tv_sec = dirattrib->mtime;
+                       tv[0].tv_usec = tv[1].tv_usec = 0;
+                       if (utimes(dst, tv) == -1)
+                               error("Can't set times on \"%s\": %s",
+                                   dst, strerror(errno));
+               } else
+                       debug("Server did not send times for directory "
+                           "\"%s\"", dst);
+       }
+
+       free_sftp_dirents(dir_entries);
+
+       return ret;
+}
+
+int
+download_dir(struct sftp_conn *conn, char *src, char *dst,
+    Attrib *dirattrib, int pflag, int printflag)
+{
+       char *src_canon;
+       int ret;
+
+       if ((src_canon = do_realpath(conn, src)) == NULL) {
+               error("Unable to canonicalise path \"%s\"", src);
+               return -1;
+       }
+
+       ret = download_dir_internal(conn, src_canon, dst,
+           dirattrib, pflag, printflag, 0);
+       xfree(src_canon);
+       return ret;
+}
+
+int
+do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
+    int pflag)
+{
+       int local_fd;
+       int status = SSH2_FX_OK;
+       u_int handle_len, id, type;
+       off_t offset;
+       char *handle, *data;
+       Buffer msg;
+       struct stat sb;
+       Attrib a;
+       u_int32_t startid;
+       u_int32_t ackid;
+       struct outstanding_ack {
+               u_int id;
+               u_int len;
+               off_t offset;
+               TAILQ_ENTRY(outstanding_ack) tq;
+       };
+       TAILQ_HEAD(ackhead, outstanding_ack) acks;
+       struct outstanding_ack *ack = NULL;
+
+       TAILQ_INIT(&acks);
+
+       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);
+       }
+       if (!S_ISREG(sb.st_mode)) {
+               error("%s is not a regular file", local_path);
+               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 = conn->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(conn, &msg);
+       debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
+
+       buffer_clear(&msg);
+
+       handle = get_handle(conn, id, &handle_len,
+           "remote open(\"%s\")", remote_path);
+       if (handle == NULL) {
+               close(local_fd);
+               buffer_free(&msg);
+               return -1;
+       }
+
+       startid = ackid = id + 1;
+       data = xmalloc(conn->transfer_buflen);
+
+       /* Read from local and write to remote */
+       offset = 0;
+       if (showprogress)
+               start_progress_meter(local_path, sb.st_size, &offset);
+
+       for (;;) {
+               int len;
+
+               /*
+                * Can't use atomicio here because it returns 0 on EOF,
+                * thus losing the last block of the file.
+                * Simulate an EOF on interrupt, allowing ACKs from the
+                * server to drain.
+                */
+               if (interrupted || status != SSH2_FX_OK)
+                       len = 0;
+               else do
+                       len = read(local_fd, data, conn->transfer_buflen);
+               while ((len == -1) &&
+                   (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
+
+               if (len == -1)
+                       fatal("Couldn't read from \"%s\": %s", local_path,
+                           strerror(errno));
+
+               if (len != 0) {
+                       ack = xmalloc(sizeof(*ack));
+                       ack->id = ++id;
+                       ack->offset = offset;
+                       ack->len = len;
+                       TAILQ_INSERT_TAIL(&acks, ack, tq);
+
+                       buffer_clear(&msg);
+                       buffer_put_char(&msg, SSH2_FXP_WRITE);
+                       buffer_put_int(&msg, ack->id);
+                       buffer_put_string(&msg, handle, handle_len);
+                       buffer_put_int64(&msg, offset);
+                       buffer_put_string(&msg, data, len);
+                       send_msg(conn, &msg);
+                       debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
+                           id, (unsigned long long)offset, len);
+               } else if (TAILQ_FIRST(&acks) == NULL)
+                       break;
+
+               if (ack == NULL)
+                       fatal("Unexpected ACK %u", id);
+
+               if (id == startid || len == 0 ||
+                   id - ackid >= conn->num_requests) {
+                       u_int r_id;
+
+                       buffer_clear(&msg);
+                       get_msg(conn, &msg);
+                       type = buffer_get_char(&msg);
+                       r_id = buffer_get_int(&msg);
+
+                       if (type != SSH2_FXP_STATUS)
+                               fatal("Expected SSH2_FXP_STATUS(%d) packet, "
+                                   "got %d", SSH2_FXP_STATUS, type);
+
+                       status = buffer_get_int(&msg);
+                       debug3("SSH2_FXP_STATUS %d", status);
+
+                       /* Find the request in our queue */
+                       for (ack = TAILQ_FIRST(&acks);
+                           ack != NULL && ack->id != r_id;
+                           ack = TAILQ_NEXT(ack, tq))
+                               ;
+                       if (ack == NULL)
+                               fatal("Can't find request for ID %u", r_id);
+                       TAILQ_REMOVE(&acks, ack, tq);
+                       debug3("In write loop, ack for %u %u bytes at %lld",
+                           ack->id, ack->len, (long long)ack->offset);
+                       ++ackid;
+                       xfree(ack);
+               }
+               offset += len;
+               if (offset < 0)
+                       fatal("%s: offset < 0", __func__);
+       }
+       buffer_free(&msg);
+
+       if (showprogress)
+               stop_progress_meter();
+       xfree(data);
+
+       if (status != SSH2_FX_OK) {
+               error("Couldn't write to remote file \"%s\": %s",
+                   remote_path, fx2txt(status));
+               status = -1;
+       }
+
+       if (close(local_fd) == -1) {
+               error("Couldn't close local file \"%s\": %s", local_path,
+                   strerror(errno));
+               status = -1;
+       }
+
+       /* Override umask and utimes if asked */
+       if (pflag)
+               do_fsetstat(conn, handle, handle_len, &a);
+
+       if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
+               status = -1;
+       xfree(handle);
+
+       return status;
+}
+
+static int
+upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
+    int pflag, int printflag, int depth)
+{
+       int ret = 0, status;
+       DIR *dirp;
+       struct dirent *dp;
+       char *filename, *new_src, *new_dst;
+       struct stat sb;
+       Attrib a;
+
+       if (depth >= MAX_DIR_DEPTH) {
+               error("Maximum directory depth exceeded: %d levels", depth);
+               return -1;
+       }
+
+       if (stat(src, &sb) == -1) {
+               error("Couldn't stat directory \"%s\": %s",
+                   src, strerror(errno));
+               return -1;
+       }
+       if (!S_ISDIR(sb.st_mode)) {
+               error("\"%s\" is not a directory", src);
+               return -1;
+       }
+       if (printflag)
+               printf("Entering %s\n", src);
+
+       attrib_clear(&a);
+       stat_to_attrib(&sb, &a);
+       a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
+       a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
+       a.perm &= 01777;
+       if (!pflag)
+               a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
+       
+       status = do_mkdir(conn, dst, &a, 0);
+       /*
+        * we lack a portable status for errno EEXIST,
+        * so if we get a SSH2_FX_FAILURE back we must check
+        * if it was created successfully.
+        */
+       if (status != SSH2_FX_OK) {
+               if (status != SSH2_FX_FAILURE)
+                       return -1;
+               if (do_stat(conn, dst, 0) == NULL) 
+                       return -1;
+       }
+
+       if ((dirp = opendir(src)) == NULL) {
+               error("Failed to open dir \"%s\": %s", src, strerror(errno));
+               return -1;
+       }
+       
+       while (((dp = readdir(dirp)) != NULL) && !interrupted) {
+               if (dp->d_ino == 0)
+                       continue;
+               filename = dp->d_name;
+               new_dst = path_append(dst, filename);
+               new_src = path_append(src, filename);
+
+               if (lstat(new_src, &sb) == -1) {
+                       logit("%s: lstat failed: %s", filename,
+                           strerror(errno));
+                       ret = -1;
+               } else if (S_ISDIR(sb.st_mode)) {
+                       if (strcmp(filename, ".") == 0 ||
+                           strcmp(filename, "..") == 0)
+                               continue;
+
+                       if (upload_dir_internal(conn, new_src, new_dst,
+                           pflag, printflag, depth + 1) == -1)
+                               ret = -1;
+               } else if (S_ISREG(sb.st_mode)) {
+                       if (do_upload(conn, new_src, new_dst, pflag) == -1) {
+                               error("Uploading of file %s to %s failed!",
+                                   new_src, new_dst);
+                               ret = -1;
+                       }
+               } else
+                       logit("%s: not a regular file\n", filename);
+               xfree(new_dst);
+               xfree(new_src);
+       }
+
+       do_setstat(conn, dst, &a);
+
+       (void) closedir(dirp);
+       return ret;
+}
+
+int
+upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
+    int pflag)
+{
+       char *dst_canon;
+       int ret;
+
+       if ((dst_canon = do_realpath(conn, dst)) == NULL) {
+               error("Unable to canonicalise path \"%s\"", dst);
+               return -1;
+       }
+
+       ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
+       xfree(dst_canon);
+       return ret;
+}
+
+char *
+path_append(char *p1, char *p2)
+{
+       char *ret;
+       size_t len = strlen(p1) + strlen(p2) + 2;
+
+       ret = xmalloc(len);
+       strlcpy(ret, p1, len);
+       if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
+               strlcat(ret, "/", len);
+       strlcat(ret, p2, len);
+
+       return(ret);
+}
+
diff --git a/sftp-client.h b/sftp-client.h
new file mode 100644 (file)
index 0000000..aef54ef
--- /dev/null
@@ -0,0 +1,132 @@
+/* $OpenBSD: sftp-client.h,v 1.20 2010/12/04 00:18:01 djm Exp $ */
+
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Client side of SSH2 filexfer protocol */
+
+#ifndef _SFTP_CLIENT_H
+#define _SFTP_CLIENT_H
+
+typedef struct SFTP_DIRENT SFTP_DIRENT;
+
+struct SFTP_DIRENT {
+       char *filename;
+       char *longname;
+       Attrib a;
+};
+
+/*
+ * Used for statvfs responses on the wire from the server, because the
+ * server's native format may be larger than the client's.
+ */
+struct sftp_statvfs {
+       u_int64_t f_bsize;
+       u_int64_t f_frsize;
+       u_int64_t f_blocks;
+       u_int64_t f_bfree;
+       u_int64_t f_bavail;
+       u_int64_t f_files;
+       u_int64_t f_ffree;
+       u_int64_t f_favail;
+       u_int64_t f_fsid;
+       u_int64_t f_flag;
+       u_int64_t f_namemax;
+};
+
+/*
+ * Initialise a SSH filexfer connection. Returns NULL on error or
+ * a pointer to a initialized sftp_conn struct on success.
+ */
+struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t);
+
+u_int sftp_proto_version(struct sftp_conn *);
+
+/* Close file referred to by 'handle' */
+int do_close(struct sftp_conn *, char *, u_int);
+
+/* Read contents of 'path' to NULL-terminated array 'dir' */
+int do_readdir(struct sftp_conn *, 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(struct sftp_conn *, char *);
+
+/* Create directory 'path' */
+int do_mkdir(struct sftp_conn *, char *, Attrib *, int);
+
+/* Remove directory 'path' */
+int do_rmdir(struct sftp_conn *, char *);
+
+/* Get file attributes of 'path' (follows symlinks) */
+Attrib *do_stat(struct sftp_conn *, char *, int);
+
+/* Get file attributes of 'path' (does not follow symlinks) */
+Attrib *do_lstat(struct sftp_conn *, char *, int);
+
+/* Set file attributes of 'path' */
+int do_setstat(struct sftp_conn *, char *, Attrib *);
+
+/* Set file attributes of open file 'handle' */
+int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
+
+/* Canonicalise 'path' - caller must free result */
+char *do_realpath(struct sftp_conn *, char *);
+
+/* Get statistics for filesystem hosting file at "path" */
+int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
+
+/* Rename 'oldpath' to 'newpath' */
+int do_rename(struct sftp_conn *, char *, char *);
+
+/* Link 'oldpath' to 'newpath' */
+int do_hardlink(struct sftp_conn *, char *, char *);
+
+/* Rename 'oldpath' to 'newpath' */
+int do_symlink(struct sftp_conn *, char *, 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(struct sftp_conn *, char *, char *, Attrib *, int);
+
+/*
+ * Recursively download 'remote_directory' to 'local_directory'. Preserve 
+ * times if 'pflag' is set
+ */
+int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int);
+
+/*
+ * Upload 'local_path' to 'remote_path'. Preserve permissions and times
+ * if 'pflag' is set
+ */
+int do_upload(struct sftp_conn *, char *, char *, int);
+
+/*
+ * Recursively upload 'local_directory' to 'remote_directory'. Preserve 
+ * times if 'pflag' is set
+ */
+int upload_dir(struct sftp_conn *, char *, char *, int, int);
+
+/* Concatenate paths, taking care of slashes. Caller must free result. */
+char *path_append(char *, char *);
+
+#endif
diff --git a/sftp-common.c b/sftp-common.c
new file mode 100644 (file)
index 0000000..a042875
--- /dev/null
@@ -0,0 +1,232 @@
+/* $OpenBSD: sftp-common.c,v 1.23 2010/01/15 09:24:23 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.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.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(const 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;
+}
+
+/* Convert from filexfer attribs to struct stat */
+void
+attrib_to_stat(const 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;
+       }
+}
+
+/* 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, const 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 */
+}
+
+/*
+ * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh
+ */
+char *
+ls_file(const char *name, const struct stat *st, int remote, int si_units)
+{
+       int ulen, glen, sz = 0;
+       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];
+       char sbuf[FMT_SCALED_STRSIZE];
+
+       strmode(st->st_mode, mode);
+       if (!remote) {
+               user = user_from_uid(st->st_uid, 0);
+       } else {
+               snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
+               user = ubuf;
+       }
+       if (!remote) {
+               group = group_from_gid(st->st_gid, 0);
+       } else {
+               snprintf(gbuf, sizeof gbuf, "%u", (u_int)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);
+       if (si_units) {
+               fmt_scaled((long long)st->st_size, sbuf);
+               snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8s %s %s", mode,
+                   (u_int)st->st_nlink, ulen, user, glen, group,
+                   sbuf, tbuf, name);
+       } else {
+               snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode,
+                   (u_int)st->st_nlink, ulen, user, glen, group,
+                   (unsigned long long)st->st_size, tbuf, name);
+       }
+       return xstrdup(buf);
+}
diff --git a/sftp-common.h b/sftp-common.h
new file mode 100644 (file)
index 0000000..9ed86c0
--- /dev/null
@@ -0,0 +1,51 @@
+/* $OpenBSD: sftp-common.h,v 1.11 2010/01/13 01:40:16 djm 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.
+ */
+
+/* Maximum packet that we are willing to send/accept */
+#define SFTP_MAX_MSG_LENGTH    (256 * 1024)
+
+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(const struct stat *, Attrib *);
+void    attrib_to_stat(const Attrib *, struct stat *);
+Attrib *decode_attrib(Buffer *);
+void    encode_attrib(Buffer *, const Attrib *);
+char   *ls_file(const char *, const struct stat *, int, int);
+
+const char *fx2txt(int);
diff --git a/sftp-glob.c b/sftp-glob.c
new file mode 100644 (file)
index 0000000..cdc2708
--- /dev/null
@@ -0,0 +1,149 @@
+/* $OpenBSD: sftp-glob.c,v 1.22 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#include <dirent.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "sftp.h"
+#include "buffer.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+
+int remote_glob(struct sftp_conn *, const char *, int,
+    int (*)(const char *, int), glob_t *);
+
+struct SFTP_OPENDIR {
+       SFTP_DIRENT **dir;
+       int offset;
+};
+
+static struct {
+       struct sftp_conn *conn;
+} cur;
+
+static void *
+fudge_opendir(const char *path)
+{
+       struct SFTP_OPENDIR *r;
+
+       r = xmalloc(sizeof(*r));
+
+       if (do_readdir(cur.conn, (char *)path, &r->dir)) {
+               xfree(r);
+               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 int
+fudge_lstat(const char *path, struct stat *st)
+{
+       Attrib *a;
+
+       if (!(a = do_lstat(cur.conn, (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.conn, (char *)path, 0)))
+               return(-1);
+
+       attrib_to_stat(a, st);
+
+       return(0);
+}
+
+int
+remote_glob(struct sftp_conn *conn, 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.conn = conn;
+
+       return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob));
+}
diff --git a/sftp-server-main.c b/sftp-server-main.c
new file mode 100644 (file)
index 0000000..7e644ab
--- /dev/null
@@ -0,0 +1,51 @@
+/* $OpenBSD: sftp-server-main.c,v 1.4 2009/02/21 19:32:04 tobias Exp $ */
+/*
+ * Copyright (c) 2008 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "sftp.h"
+#include "misc.h"
+
+void
+cleanup_exit(int i)
+{
+       sftp_server_cleanup_exit(i);
+}
+
+int
+main(int argc, char **argv)
+{
+       struct passwd *user_pw;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       if ((user_pw = getpwuid(getuid())) == NULL) {
+               fprintf(stderr, "No user found for uid %lu\n",
+                   (u_long)getuid());
+               return 1;
+       }
+
+       return (sftp_server_main(argc, argv, user_pw));
+}
diff --git a/sftp-server.0 b/sftp-server.0
new file mode 100644 (file)
index 0000000..b7d30ec
--- /dev/null
@@ -0,0 +1,64 @@
+SFTP-SERVER(8)          OpenBSD System Manager's Manual         SFTP-SERVER(8)
+
+NAME
+     sftp-server - SFTP server subsystem
+
+SYNOPSIS
+     sftp-server [-ehR] [-f log_facility] [-l log_level] [-u umask]
+
+DESCRIPTION
+     sftp-server is a program that speaks the server side of SFTP protocol to
+     stdout and expects client requests from stdin.  sftp-server is not
+     intended to be called directly, but from sshd(8) using the Subsystem
+     option.
+
+     Command-line flags to sftp-server should be specified in the Subsystem
+     declaration.  See sshd_config(5) for more information.
+
+     Valid options are:
+
+     -e      Causes sftp-server to print logging information to stderr instead
+             of syslog for debugging.
+
+     -f log_facility
+             Specifies the facility code that is used when logging messages
+             from sftp-server.  The possible values are: DAEMON, USER, AUTH,
+             LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+             The default is AUTH.
+
+     -h      Displays sftp-server usage information.
+
+     -l log_level
+             Specifies which messages will be logged by sftp-server.  The
+             possible values are: QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG,
+             DEBUG1, DEBUG2, and DEBUG3.  INFO and VERBOSE log transactions
+             that sftp-server performs on behalf of the client.  DEBUG and
+             DEBUG1 are equivalent.  DEBUG2 and DEBUG3 each specify higher
+             levels of debugging output.  The default is ERROR.
+
+     -R      Places this instance of sftp-server into a read-only mode.
+             Attempts to open files for writing, as well as other operations
+             that change the state of the filesystem, will be denied.
+
+     -u umask
+             Sets an explicit umask(2) to be applied to newly-created files
+             and directories, instead of the user's default mask.
+
+     For logging to work, sftp-server must be able to access /dev/log.  Use of
+     sftp-server in a chroot configuration therefore requires that syslogd(8)
+     establish a logging socket inside the chroot directory.
+
+SEE ALSO
+     sftp(1), ssh(1), sshd_config(5), sshd(8)
+
+     T. Ylonen and S. Lehtinen, SSH File Transfer Protocol,
+     draft-ietf-secsh-filexfer-00.txt, January 2001, work in progress
+     material.
+
+HISTORY
+     sftp-server first appeared in OpenBSD 2.8.
+
+AUTHORS
+     Markus Friedl <markus@openbsd.org>
+
+OpenBSD 4.9                     January 9, 2010                    OpenBSD 4.9
diff --git a/sftp-server.8 b/sftp-server.8
new file mode 100644 (file)
index 0000000..bb19c15
--- /dev/null
@@ -0,0 +1,124 @@
+.\" $OpenBSD: sftp-server.8,v 1.19 2010/01/09 03:36:00 jmc 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 $Mdocdate: January 9 2010 $
+.Dt SFTP-SERVER 8
+.Os
+.Sh NAME
+.Nm sftp-server
+.Nd SFTP server subsystem
+.Sh SYNOPSIS
+.Nm sftp-server
+.Op Fl ehR
+.Op Fl f Ar log_facility
+.Op Fl l Ar log_level
+.Op Fl u Ar umask
+.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.
+.Pp
+Command-line flags to
+.Nm
+should be specified in the
+.Cm Subsystem
+declaration.
+See
+.Xr sshd_config 5
+for more information.
+.Pp
+Valid options are:
+.Bl -tag -width Ds
+.It Fl e
+Causes
+.Nm
+to print logging information to stderr instead of syslog for debugging.
+.It Fl f Ar log_facility
+Specifies the facility code that is used when logging messages from
+.Nm .
+The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
+LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+The default is AUTH.
+.It Fl h
+Displays
+.Nm
+usage information.
+.It Fl l Ar log_level
+Specifies which messages will be logged by
+.Nm .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
+INFO and VERBOSE log transactions that
+.Nm
+performs on behalf of the client.
+DEBUG and DEBUG1 are equivalent.
+DEBUG2 and DEBUG3 each specify higher levels of debugging output.
+The default is ERROR.
+.It Fl R
+Places this instance of
+.Nm
+into a read-only mode.
+Attempts to open files for writing, as well as other operations that change
+the state of the filesystem, will be denied.
+.It Fl u Ar umask
+Sets an explicit
+.Xr umask 2
+to be applied to newly-created files and directories, instead of the
+user's default mask.
+.El
+.Pp
+For logging to work,
+.Nm
+must be able to access
+.Pa /dev/log .
+Use of
+.Nm
+in a chroot configuration therefore requires that
+.Xr syslogd 8
+establish a logging socket inside the chroot directory.
+.Sh SEE ALSO
+.Xr sftp 1 ,
+.Xr ssh 1 ,
+.Xr sshd_config 5 ,
+.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 HISTORY
+.Nm
+first appeared in
+.Ox 2.8 .
+.Sh AUTHORS
+.An Markus Friedl Aq markus@openbsd.org
diff --git a/sftp-server.c b/sftp-server.c
new file mode 100644 (file)
index 0000000..b268d08
--- /dev/null
@@ -0,0 +1,1548 @@
+/* $OpenBSD: sftp-server.c,v 1.93 2010/12/04 00:18:01 djm Exp $ */
+/*
+ * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pwd.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+#include "uidswap.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);
+
+/* Our verbosity */
+LogLevel log_level = SYSLOG_LEVEL_ERROR;
+
+/* Our client */
+struct passwd *pw = NULL;
+char *client_addr = NULL;
+
+/* input and output queue */
+Buffer iqueue;
+Buffer oqueue;
+
+/* Version of client */
+int version;
+
+/* Disable writes */
+int readonly;
+
+/* portable attributes, 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;
+       case ENOSYS:
+               ret = SSH2_FX_OP_UNSUPPORTED;
+               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 const char *
+string_from_portable(int pflags)
+{
+       static char ret[128];
+
+       *ret = '\0';
+
+#define PAPPEND(str)   {                               \
+               if (*ret != '\0')                       \
+                       strlcat(ret, ",", sizeof(ret)); \
+               strlcat(ret, str, sizeof(ret));         \
+       }
+
+       if (pflags & SSH2_FXF_READ)
+               PAPPEND("READ")
+       if (pflags & SSH2_FXF_WRITE)
+               PAPPEND("WRITE")
+       if (pflags & SSH2_FXF_CREAT)
+               PAPPEND("CREATE")
+       if (pflags & SSH2_FXF_TRUNC)
+               PAPPEND("TRUNCATE")
+       if (pflags & SSH2_FXF_EXCL)
+               PAPPEND("EXCL")
+
+       return ret;
+}
+
+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;
+       u_int64_t bytes_read, bytes_write;
+       int next_unused;
+};
+
+enum {
+       HANDLE_UNUSED,
+       HANDLE_DIR,
+       HANDLE_FILE
+};
+
+Handle *handles = NULL;
+u_int num_handles = 0;
+int first_unused_handle = -1;
+
+static void handle_unused(int i)
+{
+       handles[i].use = HANDLE_UNUSED;
+       handles[i].next_unused = first_unused_handle;
+       first_unused_handle = i;
+}
+
+static int
+handle_new(int use, const char *name, int fd, DIR *dirp)
+{
+       int i;
+
+       if (first_unused_handle == -1) {
+               if (num_handles + 1 <= num_handles)
+                       return -1;
+               num_handles++;
+               handles = xrealloc(handles, num_handles, sizeof(Handle));
+               handle_unused(num_handles - 1);
+       }
+
+       i = first_unused_handle;
+       first_unused_handle = handles[i].next_unused;
+
+       handles[i].use = use;
+       handles[i].dirp = dirp;
+       handles[i].fd = fd;
+       handles[i].name = xstrdup(name);
+       handles[i].bytes_read = handles[i].bytes_write = 0;
+
+       return i;
+}
+
+static int
+handle_is_ok(int i, int type)
+{
+       return i >= 0 && (u_int)i < num_handles && 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_u32(*stringp, handle);
+       *hlenp = sizeof(int32_t);
+       return 0;
+}
+
+static int
+handle_from_string(const char *handle, u_int hlen)
+{
+       int val;
+
+       if (hlen != sizeof(int32_t))
+               return -1;
+       val = get_u32(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 void
+handle_update_read(int handle, ssize_t bytes)
+{
+       if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
+               handles[handle].bytes_read += bytes;
+}
+
+static void
+handle_update_write(int handle, ssize_t bytes)
+{
+       if (handle_is_ok(handle, HANDLE_FILE) && bytes > 0)
+               handles[handle].bytes_write += bytes;
+}
+
+static u_int64_t
+handle_bytes_read(int handle)
+{
+       if (handle_is_ok(handle, HANDLE_FILE))
+               return (handles[handle].bytes_read);
+       return 0;
+}
+
+static u_int64_t
+handle_bytes_write(int handle)
+{
+       if (handle_is_ok(handle, HANDLE_FILE))
+               return (handles[handle].bytes_write);
+       return 0;
+}
+
+static int
+handle_close(int handle)
+{
+       int ret = -1;
+
+       if (handle_is_ok(handle, HANDLE_FILE)) {
+               ret = close(handles[handle].fd);
+               xfree(handles[handle].name);
+               handle_unused(handle);
+       } else if (handle_is_ok(handle, HANDLE_DIR)) {
+               ret = closedir(handles[handle].dirp);
+               xfree(handles[handle].name);
+               handle_unused(handle);
+       } else {
+               errno = ENOENT;
+       }
+       return ret;
+}
+
+static void
+handle_log_close(int handle, char *emsg)
+{
+       if (handle_is_ok(handle, HANDLE_FILE)) {
+               logit("%s%sclose \"%s\" bytes read %llu written %llu",
+                   emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
+                   handle_to_name(handle),
+                   (unsigned long long)handle_bytes_read(handle),
+                   (unsigned long long)handle_bytes_write(handle));
+       } else {
+               logit("%s%sclosedir \"%s\"",
+                   emsg == NULL ? "" : emsg, emsg == NULL ? "" : " ",
+                   handle_to_name(handle));
+       }
+}
+
+static void
+handle_log_exit(void)
+{
+       u_int i;
+
+       for (i = 0; i < num_handles; i++)
+               if (handles[i].use != HANDLE_UNUSED)
+                       handle_log_close(i, "forced");
+}
+
+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 const char *
+status_to_message(u_int32_t status)
+{
+       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 */
+       };
+       return (status_messages[MIN(status,SSH2_FX_MAX)]);
+}
+
+static void
+send_status(u_int32_t id, u_int32_t status)
+{
+       Buffer msg;
+
+       debug3("request %u: sent status %u", id, status);
+       if (log_level > SYSLOG_LEVEL_VERBOSE ||
+           (status != SSH2_FX_OK && status != SSH2_FX_EOF))
+               logit("sent status %s", status_to_message(status));
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_STATUS);
+       buffer_put_int(&msg, id);
+       buffer_put_int(&msg, status);
+       if (version >= 3) {
+               buffer_put_cstring(&msg, status_to_message(status));
+               buffer_put_cstring(&msg, "");
+       }
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+static void
+send_data_or_handle(char type, u_int32_t id, const 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, const char *data, int dlen)
+{
+       debug("request %u: sent data 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);
+       debug("request %u: sent handle 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, const 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);
+       debug("request %u: sent names 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, const Attrib *a)
+{
+       Buffer msg;
+
+       debug("request %u: sent attrib 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);
+}
+
+static void
+send_statvfs(u_int32_t id, struct statvfs *st)
+{
+       Buffer msg;
+       u_int64_t flag;
+
+       flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
+       flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
+       buffer_put_int(&msg, id);
+       buffer_put_int64(&msg, st->f_bsize);
+       buffer_put_int64(&msg, st->f_frsize);
+       buffer_put_int64(&msg, st->f_blocks);
+       buffer_put_int64(&msg, st->f_bfree);
+       buffer_put_int64(&msg, st->f_bavail);
+       buffer_put_int64(&msg, st->f_files);
+       buffer_put_int64(&msg, st->f_ffree);
+       buffer_put_int64(&msg, st->f_favail);
+       buffer_put_int64(&msg, FSID_TO_ULONG(st->f_fsid));
+       buffer_put_int64(&msg, flag);
+       buffer_put_int64(&msg, st->f_namemax);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+/* parse incoming */
+
+static void
+process_init(void)
+{
+       Buffer msg;
+
+       version = get_int();
+       verbose("received client version %d", version);
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_FXP_VERSION);
+       buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
+       /* POSIX rename extension */
+       buffer_put_cstring(&msg, "posix-rename@openssh.com");
+       buffer_put_cstring(&msg, "1"); /* version */
+       /* statvfs extension */
+       buffer_put_cstring(&msg, "statvfs@openssh.com");
+       buffer_put_cstring(&msg, "2"); /* version */
+       /* fstatvfs extension */
+       buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+       buffer_put_cstring(&msg, "2"); /* version */
+       /* hardlink extension */
+       buffer_put_cstring(&msg, "hardlink@openssh.com");
+       buffer_put_cstring(&msg, "1"); /* 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 */
+       debug3("request %u: open flags %d", id, pflags);
+       a = get_attrib();
+       flags = flags_from_portable(pflags);
+       mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666;
+       logit("open \"%s\" flags %s mode 0%o",
+           name, string_from_portable(pflags), mode);
+       if (readonly &&
+           ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR))
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               fd = open(name, flags, mode);
+               if (fd < 0) {
+                       status = errno_to_portable(errno);
+               } else {
+                       handle = handle_new(HANDLE_FILE, 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();
+       debug3("request %u: close handle %u", id, handle);
+       handle_log_close(handle, NULL);
+       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();
+
+       debug("request %u: read \"%s\" (handle %d) off %llu len %d",
+           id, handle_to_name(handle), handle, (unsigned long long)off, len);
+       if (len > sizeof buf) {
+               len = sizeof buf;
+               debug2("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;
+                               handle_update_read(handle, ret);
+                       }
+               }
+       }
+       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;
+       char *data;
+
+       id = get_int();
+       handle = get_handle();
+       off = get_int64();
+       data = get_string(&len);
+
+       debug("request %u: write \"%s\" (handle %d) off %llu len %d",
+           id, handle_to_name(handle), handle, (unsigned long long)off, len);
+       fd = handle_to_fd(handle);
+       
+       if (fd < 0)
+               status = SSH2_FX_FAILURE;
+       else if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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 < 0) {
+                               error("process_write: write failed");
+                               status = errno_to_portable(errno);
+                       } else if ((size_t)ret == len) {
+                               status = SSH2_FX_OK;
+                               handle_update_write(handle, ret);
+                       } else {
+                               debug2("nothing at all written");
+                               status = SSH2_FX_FAILURE;
+                       }
+               }
+       }
+       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);
+       debug3("request %u: %sstat", id, do_lstat ? "l" : "");
+       verbose("%sstat name \"%s\"", do_lstat ? "l" : "", 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();
+       debug("request %u: fstat \"%s\" (handle %u)",
+           id, handle_to_name(handle), 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(const 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 status = SSH2_FX_OK, ret;
+
+       id = get_int();
+       name = get_string(NULL);
+       a = get_attrib();
+       debug("request %u: setstat name \"%s\"", id, name);
+       if (readonly) {
+               status = SSH2_FX_PERMISSION_DENIED;
+               a->flags = 0;
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
+               logit("set \"%s\" size %llu",
+                   name, (unsigned long long)a->size);
+               ret = truncate(name, a->size);
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+               logit("set \"%s\" mode %04o", name, a->perm);
+               ret = chmod(name, a->perm & 07777);
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+               char buf[64];
+               time_t t = a->mtime;
+
+               strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+                   localtime(&t));
+               logit("set \"%s\" modtime %s", name, buf);
+               ret = utimes(name, attrib_to_tv(a));
+               if (ret == -1)
+                       status = errno_to_portable(errno);
+       }
+       if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
+               logit("set \"%s\" owner %lu group %lu", name,
+                   (u_long)a->uid, (u_long)a->gid);
+               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;
+
+       id = get_int();
+       handle = get_handle();
+       a = get_attrib();
+       debug("request %u: fsetstat handle %d", id, handle);
+       fd = handle_to_fd(handle);
+       if (fd < 0)
+               status = SSH2_FX_FAILURE;
+       else if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               char *name = handle_to_name(handle);
+
+               if (a->flags & SSH2_FILEXFER_ATTR_SIZE) {
+                       logit("set \"%s\" size %llu",
+                           name, (unsigned long long)a->size);
+                       ret = ftruncate(fd, a->size);
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+               if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
+                       logit("set \"%s\" mode %04o", name, a->perm);
+#ifdef HAVE_FCHMOD
+                       ret = fchmod(fd, a->perm & 07777);
+#else
+                       ret = chmod(name, a->perm & 07777);
+#endif
+                       if (ret == -1)
+                               status = errno_to_portable(errno);
+               }
+               if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
+                       char buf[64];
+                       time_t t = a->mtime;
+
+                       strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
+                           localtime(&t));
+                       logit("set \"%s\" modtime %s", name, buf);
+#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) {
+                       logit("set \"%s\" owner %lu group %lu", name,
+                           (u_long)a->uid, (u_long)a->gid);
+#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);
+       debug3("request %u: opendir", id);
+       logit("opendir \"%s\"", path);
+       dirp = opendir(path);
+       if (dirp == NULL) {
+               status = errno_to_portable(errno);
+       } else {
+               handle = handle_new(HANDLE_DIR, 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);
+}
+
+static void
+process_readdir(void)
+{
+       DIR *dirp;
+       struct dirent *dp;
+       char *path;
+       int handle;
+       u_int32_t id;
+
+       id = get_int();
+       handle = get_handle();
+       debug("request %u: readdir \"%s\" (handle %d)", id,
+           handle_to_name(handle), 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[MAXPATHLEN];
+               Stat *stats;
+               int nstats = 10, count = 0, i;
+
+               stats = xcalloc(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, 0, 0);
+                       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);
+       debug3("request %u: remove", id);
+       logit("remove name \"%s\"", name);
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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 & 07777 : 0777;
+       debug3("request %u: mkdir", id);
+       logit("mkdir name \"%s\" mode 0%o", name, mode);
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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);
+       debug3("request %u: rmdir", id);
+       logit("rmdir name \"%s\"", name);
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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(".");
+       }
+       debug3("request %u: realpath", id);
+       verbose("realpath \"%s\"", 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;
+       char *oldpath, *newpath;
+       int status;
+       struct stat sb;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       debug3("request %u: rename", id);
+       logit("rename old \"%s\" new \"%s\"", oldpath, newpath);
+       status = SSH2_FX_FAILURE;
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else if (lstat(oldpath, &sb) == -1)
+               status = errno_to_portable(errno);
+       else if (S_ISREG(sb.st_mode)) {
+               /* Race-free rename of regular files */
+               if (link(oldpath, newpath) == -1) {
+                       if (errno == EOPNOTSUPP || errno == ENOSYS
+#ifdef EXDEV
+                           || errno == EXDEV
+#endif
+#ifdef LINK_OPNOTSUPP_ERRNO
+                           || errno == LINK_OPNOTSUPP_ERRNO
+#endif
+                           ) {
+                               struct stat st;
+
+                               /*
+                                * fs doesn't support links, so fall back to
+                                * stat+rename.  This is racy.
+                                */
+                               if (stat(newpath, &st) == -1) {
+                                       if (rename(oldpath, newpath) == -1)
+                                               status =
+                                                   errno_to_portable(errno);
+                                       else
+                                               status = SSH2_FX_OK;
+                               }
+                       } else {
+                               status = errno_to_portable(errno);
+                       }
+               } else if (unlink(oldpath) == -1) {
+                       status = errno_to_portable(errno);
+                       /* clean spare link */
+                       unlink(newpath);
+               } else
+                       status = SSH2_FX_OK;
+       } else if (stat(newpath, &sb) == -1) {
+               if (rename(oldpath, newpath) == -1)
+                       status = errno_to_portable(errno);
+               else
+                       status = SSH2_FX_OK;
+       }
+       send_status(id, status);
+       xfree(oldpath);
+       xfree(newpath);
+}
+
+static void
+process_readlink(void)
+{
+       u_int32_t id;
+       int len;
+       char buf[MAXPATHLEN];
+       char *path;
+
+       id = get_int();
+       path = get_string(NULL);
+       debug3("request %u: readlink", id);
+       verbose("readlink \"%s\"", path);
+       if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1)
+               send_status(id, errno_to_portable(errno));
+       else {
+               Stat s;
+
+               buf[len] = '\0';
+               attrib_clear(&s.attrib);
+               s.name = s.long_name = buf;
+               send_names(id, 1, &s);
+       }
+       xfree(path);
+}
+
+static void
+process_symlink(void)
+{
+       u_int32_t id;
+       char *oldpath, *newpath;
+       int ret, status;
+
+       id = get_int();
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       debug3("request %u: symlink", id);
+       logit("symlink old \"%s\" new \"%s\"", oldpath, newpath);
+       /* this will fail if 'newpath' exists */
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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_posix_rename(u_int32_t id)
+{
+       char *oldpath, *newpath;
+       int ret, status;
+
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       debug3("request %u: posix-rename", id);
+       logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               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_extended_statvfs(u_int32_t id)
+{
+       char *path;
+       struct statvfs st;
+
+       path = get_string(NULL);
+       debug3("request %u: statfs", id);
+       logit("statfs \"%s\"", path);
+
+       if (statvfs(path, &st) != 0)
+               send_status(id, errno_to_portable(errno));
+       else
+               send_statvfs(id, &st);
+        xfree(path);
+}
+
+static void
+process_extended_fstatvfs(u_int32_t id)
+{
+       int handle, fd;
+       struct statvfs st;
+
+       handle = get_handle();
+       debug("request %u: fstatvfs \"%s\" (handle %u)",
+           id, handle_to_name(handle), handle);
+       if ((fd = handle_to_fd(handle)) < 0) {
+               send_status(id, SSH2_FX_FAILURE);
+               return;
+       }
+       if (fstatvfs(fd, &st) != 0)
+               send_status(id, errno_to_portable(errno));
+       else
+               send_statvfs(id, &st);
+}
+
+static void
+process_extended_hardlink(u_int32_t id)
+{
+       char *oldpath, *newpath;
+       int ret, status;
+
+       oldpath = get_string(NULL);
+       newpath = get_string(NULL);
+       debug3("request %u: hardlink", id);
+       logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
+       if (readonly)
+               status = SSH2_FX_PERMISSION_DENIED;
+       else {
+               ret = link(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);
+       if (strcmp(request, "posix-rename@openssh.com") == 0)
+               process_extended_posix_rename(id);
+       else if (strcmp(request, "statvfs@openssh.com") == 0)
+               process_extended_statvfs(id);
+       else if (strcmp(request, "fstatvfs@openssh.com") == 0)
+               process_extended_fstatvfs(id);
+       else if (strcmp(request, "hardlink@openssh.com") == 0)
+               process_extended_hardlink(id);
+       else
+               send_status(id, SSH2_FX_OP_UNSUPPORTED);        /* MUST */
+       xfree(request);
+}
+
+/* stolen from ssh-agent */
+
+static void
+process(void)
+{
+       u_int msg_len;
+       u_int buf_len;
+       u_int consumed;
+       u_int type;
+       u_char *cp;
+
+       buf_len = buffer_len(&iqueue);
+       if (buf_len < 5)
+               return;         /* Incomplete message. */
+       cp = buffer_ptr(&iqueue);
+       msg_len = get_u32(cp);
+       if (msg_len > SFTP_MAX_MSG_LENGTH) {
+               error("bad message from %s local user %s",
+                   client_addr, pw->pw_name);
+               sftp_server_cleanup_exit(11);
+       }
+       if (buf_len < msg_len + 4)
+               return;
+       buffer_consume(&iqueue, 4);
+       buf_len -= 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;
+       }
+       /* discard the remaining bytes from the current packet */
+       if (buf_len < buffer_len(&iqueue)) {
+               error("iqueue grew unexpectedly");
+               sftp_server_cleanup_exit(255);
+       }
+       consumed = buf_len - buffer_len(&iqueue);
+       if (msg_len < consumed) {
+               error("msg_len %d < consumed %d", msg_len, consumed);
+               sftp_server_cleanup_exit(255);
+       }
+       if (msg_len > consumed)
+               buffer_consume(&iqueue, msg_len - consumed);
+}
+
+/* Cleanup handler that logs active handles upon normal exit */
+void
+sftp_server_cleanup_exit(int i)
+{
+       if (pw != NULL && client_addr != NULL) {
+               handle_log_exit();
+               logit("session closed for local user %s from [%s]",
+                   pw->pw_name, client_addr);
+       }
+       _exit(i);
+}
+
+static void
+sftp_server_usage(void)
+{
+       extern char *__progname;
+
+       fprintf(stderr,
+           "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n",
+           __progname);
+       exit(1);
+}
+
+int
+sftp_server_main(int argc, char **argv, struct passwd *user_pw)
+{
+       fd_set *rset, *wset;
+       int in, out, max, ch, skipargs = 0, log_stderr = 0;
+       ssize_t len, olen, set_size;
+       SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
+       char *cp, buf[4*4096];
+       long mask;
+
+       extern char *optarg;
+       extern char *__progname;
+
+       __progname = ssh_get_progname(argv[0]);
+       log_init(__progname, log_level, log_facility, log_stderr);
+
+       while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) {
+               switch (ch) {
+               case 'R':
+                       readonly = 1;
+                       break;
+               case 'c':
+                       /*
+                        * Ignore all arguments if we are invoked as a
+                        * shell using "sftp-server -c command"
+                        */
+                       skipargs = 1;
+                       break;
+               case 'e':
+                       log_stderr = 1;
+                       break;
+               case 'l':
+                       log_level = log_level_number(optarg);
+                       if (log_level == SYSLOG_LEVEL_NOT_SET)
+                               error("Invalid log level \"%s\"", optarg);
+                       break;
+               case 'f':
+                       log_facility = log_facility_number(optarg);
+                       if (log_facility == SYSLOG_FACILITY_NOT_SET)
+                               error("Invalid log facility \"%s\"", optarg);
+                       break;
+               case 'u':
+                       errno = 0;
+                       mask = strtol(optarg, &cp, 8);
+                       if (mask < 0 || mask > 0777 || *cp != '\0' ||
+                           cp == optarg || (mask == 0 && errno != 0))
+                               fatal("Invalid umask \"%s\"", optarg);
+                       (void)umask((mode_t)mask);
+                       break;
+               case 'h':
+               default:
+                       sftp_server_usage();
+               }
+       }
+
+       log_init(__progname, log_level, log_facility, log_stderr);
+
+       if ((cp = getenv("SSH_CONNECTION")) != NULL) {
+               client_addr = xstrdup(cp);
+               if ((cp = strchr(client_addr, ' ')) == NULL) {
+                       error("Malformed SSH_CONNECTION variable: \"%s\"",
+                           getenv("SSH_CONNECTION"));
+                       sftp_server_cleanup_exit(255);
+               }
+               *cp = '\0';
+       } else
+               client_addr = xstrdup("UNKNOWN");
+
+       pw = pwcopy(user_pw);
+
+       logit("session opened for local user %s from [%s]",
+           pw->pw_name, client_addr);
+
+       in = STDIN_FILENO;
+       out = 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);
+
+               /*
+                * Ensure that we can read a full buffer and handle
+                * the worst-case length packet it can generate,
+                * otherwise apply backpressure by stopping reads.
+                */
+               if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
+                   buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
+                       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;
+                       error("select: %s", strerror(errno));
+                       sftp_server_cleanup_exit(2);
+               }
+
+               /* copy stdin to iqueue */
+               if (FD_ISSET(in, rset)) {
+                       len = read(in, buf, sizeof buf);
+                       if (len == 0) {
+                               debug("read eof");
+                               sftp_server_cleanup_exit(0);
+                       } else if (len < 0) {
+                               error("read: %s", strerror(errno));
+                               sftp_server_cleanup_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: %s", strerror(errno));
+                               sftp_server_cleanup_exit(1);
+                       } else {
+                               buffer_consume(&oqueue, len);
+                       }
+               }
+
+               /*
+                * Process requests from client if we can fit the results
+                * into the output buffer, otherwise stop processing input
+                * and let the output queue drain.
+                */
+               if (buffer_check_alloc(&oqueue, SFTP_MAX_MSG_LENGTH))
+                       process();
+       }
+}
diff --git a/sftp.0 b/sftp.0
new file mode 100644 (file)
index 0000000..960ffb9
--- /dev/null
+++ b/sftp.0
@@ -0,0 +1,331 @@
+SFTP(1)                    OpenBSD Reference Manual                    SFTP(1)
+
+NAME
+     sftp - secure file transfer program
+
+SYNOPSIS
+     sftp [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]
+          [-D sftp_server_path] [-F ssh_config] [-i identity_file] [-l limit]
+          [-o ssh_option] [-P port] [-R num_requests] [-S program]
+          [-s subsystem | sftp_server] host
+     sftp [user@]host[:file ...]
+     sftp [user@]host[:dir[/]]
+     sftp -b batchfile [user@]host
+
+DESCRIPTION
+     sftp is an interactive file transfer program, similar to ftp(1), which
+     performs all operations over an encrypted ssh(1) transport.  It may also
+     use many features of ssh, such as public key authentication and
+     compression.  sftp connects and logs into the specified host, then enters
+     an interactive command mode.
+
+     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.
+
+     The third usage format allows sftp to start in a remote directory.
+
+     The final usage format allows for automated sessions using the -b option.
+     In such cases, it is necessary to configure non-interactive
+     authentication to obviate the need to enter a password at connection time
+     (see sshd(8) and ssh-keygen(1) for details).  The options are as follows:
+
+     -1      Specify the use of protocol version 1.
+
+     -2      Specify the use of protocol version 2.
+
+     -4      Forces sftp to use IPv4 addresses only.
+
+     -6      Forces sftp to use IPv6 addresses only.
+
+     -B buffer_size
+             Specify the size of the buffer that sftp uses when transferring
+             files.  Larger buffers require fewer round trips at the cost of
+             higher memory consumption.  The default is 32768 bytes.
+
+     -b batchfile
+             Batch mode reads a series of commands from an input batchfile
+             instead of stdin.  Since it lacks user interaction it should be
+             used in conjunction with non-interactive authentication.  A
+             batchfile of `-' may be used to indicate standard input.  sftp
+             will abort if any of the following commands fail: get, put,
+             rename, ln, rm, mkdir, chdir, ls, lchdir, chmod, chown, chgrp,
+             lpwd, df, symlink, and lmkdir.  Termination on error can be
+             suppressed on a command by command basis by prefixing the command
+             with a `-' character (for example, -rm /tmp/blah*).
+
+     -C      Enables compression (via ssh's -C flag).
+
+     -c cipher
+             Selects the cipher to use for encrypting the data transfers.
+             This option is directly passed to ssh(1).
+
+     -D sftp_server_path
+             Connect directly to a local sftp server (rather than via ssh(1)).
+             This option may be useful in debugging the client and server.
+
+     -F ssh_config
+             Specifies an alternative per-user configuration file for ssh(1).
+             This option is directly passed to ssh(1).
+
+     -i identity_file
+             Selects the file from which the identity (private key) for public
+             key authentication is read.  This option is directly passed to
+             ssh(1).
+
+     -l limit
+             Limits the used bandwidth, specified in Kbit/s.
+
+     -o ssh_option
+             Can be used to pass options to ssh in the format used in
+             ssh_config(5).  This is useful for specifying options for which
+             there is no separate sftp command-line flag.  For example, to
+             specify an alternate port use: sftp -oPort=24.  For full details
+             of the options listed below, and their possible values, see
+             ssh_config(5).
+
+                   AddressFamily
+                   BatchMode
+                   BindAddress
+                   ChallengeResponseAuthentication
+                   CheckHostIP
+                   Cipher
+                   Ciphers
+                   Compression
+                   CompressionLevel
+                   ConnectionAttempts
+                   ConnectTimeout
+                   ControlMaster
+                   ControlPath
+                   GlobalKnownHostsFile
+                   GSSAPIAuthentication
+                   GSSAPIDelegateCredentials
+                   HashKnownHosts
+                   Host
+                   HostbasedAuthentication
+                   HostKeyAlgorithms
+                   HostKeyAlias
+                   HostName
+                   IdentityFile
+                   IdentitiesOnly
+                   IPQoS
+                   KbdInteractiveDevices
+                   KexAlgorithms
+                   LogLevel
+                   MACs
+                   NoHostAuthenticationForLocalhost
+                   NumberOfPasswordPrompts
+                   PasswordAuthentication
+                   PKCS11Provider
+                   Port
+                   PreferredAuthentications
+                   Protocol
+                   ProxyCommand
+                   PubkeyAuthentication
+                   RekeyLimit
+                   RhostsRSAAuthentication
+                   RSAAuthentication
+                   SendEnv
+                   ServerAliveInterval
+                   ServerAliveCountMax
+                   StrictHostKeyChecking
+                   TCPKeepAlive
+                   UsePrivilegedPort
+                   User
+                   UserKnownHostsFile
+                   VerifyHostKeyDNS
+
+     -P port
+             Specifies the port to connect to on the remote host.
+
+     -p      Preserves modification times, access times, and modes from the
+             original files transferred.
+
+     -q      Quiet mode: disables the progress meter as well as warning and
+             diagnostic messages from ssh(1).
+
+     -R num_requests
+             Specify how many requests may be outstanding at any one time.
+             Increasing this may slightly improve file transfer speed but will
+             increase memory usage.  The default is 64 outstanding requests.
+
+     -r      Recursively copy entire directories when uploading and
+             downloading.  Note that sftp does not follow symbolic links
+             encountered in the tree traversal.
+
+     -S program
+             Name of the program to use for the encrypted connection.  The
+             program must understand ssh(1) options.
+
+     -s 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 sshd(8) does not have an sftp
+             subsystem configured.
+
+     -v      Raise logging level.  This option is also passed to ssh.
+
+INTERACTIVE COMMANDS
+     Once in interactive mode, sftp understands a set of commands similar to
+     those of ftp(1).  Commands are case insensitive.  Pathnames that contain
+     spaces must be enclosed in quotes.  Any special characters contained
+     within pathnames that are recognized by glob(3) must be escaped with
+     backslashes (`\').
+
+     bye     Quit sftp.
+
+     cd path
+             Change remote directory to path.
+
+     chgrp grp path
+             Change group of file path to grp.  path may contain glob(3)
+             characters and may match multiple files.  grp must be a numeric
+             GID.
+
+     chmod mode path
+             Change permissions of file path to mode.  path may contain
+             glob(3) characters and may match multiple files.
+
+     chown own path
+             Change owner of file path to own.  path may contain glob(3)
+             characters and may match multiple files.  own must be a numeric
+             UID.
+
+     df [-hi] [path]
+             Display usage information for the filesystem holding the current
+             directory (or path if specified).  If the -h flag is specified,
+             the capacity information will be displayed using "human-readable"
+             suffixes.  The -i flag requests display of inode information in
+             addition to capacity information.  This command is only supported
+             on servers that implement the ``statvfs@openssh.com'' extension.
+
+     exit    Quit sftp.
+
+     get [-Ppr] remote-path [local-path]
+             Retrieve the 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.  remote-path may contain glob(3)
+             characters and may match multiple files.  If it does and
+             local-path is specified, then local-path must specify a
+             directory.
+
+             If either the -P or -p flag is specified, then full file
+             permissions and access times are copied too.
+
+             If the -r flag is specified then directories will be copied
+             recursively.  Note that sftp does not follow symbolic links when
+             performing recursive transfers.
+
+     help    Display help text.
+
+     lcd path
+             Change local directory to path.
+
+     lls [ls-options [path]]
+             Display local directory listing of either path or current
+             directory if path is not specified.  ls-options may contain any
+             flags supported by the local system's ls(1) command.  path may
+             contain glob(3) characters and may match multiple files.
+
+     lmkdir path
+             Create local directory specified by path.
+
+     ln [-s] oldpath newpath
+             Create a link from oldpath to newpath.  If the -s flag is
+             specified the created link is a symbolic link, otherwise it is a
+             hard link.
+
+     lpwd    Print local working directory.
+
+     ls [-1afhlnrSt] [path]
+             Display a remote directory listing of either path or the current
+             directory if path is not specified.  path may contain glob(3)
+             characters and may match multiple files.
+
+             The following flags are recognized and alter the behaviour of ls
+             accordingly:
+
+             -1      Produce single columnar output.
+
+             -a      List files beginning with a dot (`.').
+
+             -f      Do not sort the listing.  The default sort order is
+                     lexicographical.
+
+             -h      When used with a long format option, use unit suffixes:
+                     Byte, Kilobyte, Megabyte, Gigabyte, Terabyte, Petabyte,
+                     and Exabyte in order to reduce the number of digits to
+                     four or fewer using powers of 2 for sizes (K=1024,
+                     M=1048576, etc.).
+
+             -l      Display additional details including permissions and
+                     ownership information.
+
+             -n      Produce a long listing with user and group information
+                     presented numerically.
+
+             -r      Reverse the sort order of the listing.
+
+             -S      Sort the listing by file size.
+
+             -t      Sort the listing by last modification time.
+
+     lumask umask
+             Set local umask to umask.
+
+     mkdir path
+             Create remote directory specified by path.
+
+     progress
+             Toggle display of progress meter.
+
+     put [-Ppr] local-path [remote-path]
+             Upload 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.  local-path may contain glob(3)
+             characters and may match multiple files.  If it does and
+             remote-path is specified, then remote-path must specify a
+             directory.
+
+             If ether the -P or -p flag is specified, then full file
+             permissions and access times are copied too.
+
+             If the -r flag is specified then directories will be copied
+             recursively.  Note that sftp does not follow symbolic links when
+             performing recursive transfers.
+
+     pwd     Display remote working directory.
+
+     quit    Quit sftp.
+
+     rename oldpath newpath
+             Rename remote file from oldpath to newpath.
+
+     rm path
+             Delete remote file specified by path.
+
+     rmdir path
+             Remove remote directory specified by path.
+
+     symlink oldpath newpath
+             Create a symbolic link from oldpath to newpath.
+
+     version
+             Display the sftp protocol version.
+
+     !command
+             Execute command in local shell.
+
+     !       Escape to local shell.
+
+     ?       Synonym for help.
+
+SEE ALSO
+     ftp(1), ls(1), scp(1), ssh(1), ssh-add(1), ssh-keygen(1), glob(3),
+     ssh_config(5), sftp-server(8), sshd(8)
+
+     T. Ylonen and S. Lehtinen, SSH File Transfer Protocol,
+     draft-ietf-secsh-filexfer-00.txt, January 2001, work in progress
+     material.
+
+OpenBSD 4.9                    December 4, 2010                    OpenBSD 4.9
diff --git a/sftp.1 b/sftp.1
new file mode 100644 (file)
index 0000000..89b5d35
--- /dev/null
+++ b/sftp.1
@@ -0,0 +1,547 @@
+.\" $OpenBSD: sftp.1,v 1.88 2010/12/04 00:18:01 djm 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 $Mdocdate: December 4 2010 $
+.Dt SFTP 1
+.Os
+.Sh NAME
+.Nm sftp
+.Nd secure file transfer program
+.Sh SYNOPSIS
+.Nm sftp
+.Bk -words
+.Op Fl 1246Cpqrv
+.Op Fl B Ar buffer_size
+.Op Fl b Ar batchfile
+.Op Fl c Ar cipher
+.Op Fl D Ar sftp_server_path
+.Op Fl F Ar ssh_config
+.Op Fl i Ar identity_file
+.Op Fl l Ar limit
+.Op Fl o Ar ssh_option
+.Op Fl P Ar port
+.Op Fl R Ar num_requests
+.Op Fl S Ar program
+.Op Fl s Ar subsystem | sftp_server
+.Ar host
+.Ek
+.Nm sftp
+.Oo Ar user Ns @ Oc Ns
+.Ar host Ns Op : Ns Ar
+.Nm sftp
+.Oo
+.Ar user Ns @ Oc Ns
+.Ar host Ns Oo : Ns Ar dir Ns
+.Op Ar /
+.Oc
+.Nm sftp
+.Fl b Ar batchfile
+.Oo Ar user Ns @ Oc Ns Ar host
+.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 third usage format allows
+.Nm
+to start in a remote directory.
+.Pp
+The final usage format allows for automated sessions using the
+.Fl b
+option.
+In such cases, it is necessary to configure non-interactive authentication
+to obviate the need to enter a password at connection time (see
+.Xr sshd 8
+and
+.Xr ssh-keygen 1
+for details).
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 1
+Specify the use of protocol version 1.
+.It Fl 2
+Specify the use of protocol version 2.
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl B Ar buffer_size
+Specify the size of the buffer that
+.Nm
+uses when transferring files.
+Larger buffers require fewer round trips at the cost of higher
+memory consumption.
+The default is 32768 bytes.
+.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.
+A
+.Ar batchfile
+of
+.Sq \-
+may be used to indicate standard input.
+.Nm
+will abort if any of the following
+commands fail:
+.Ic get , put , rename , ln ,
+.Ic rm , mkdir , chdir , ls ,
+.Ic lchdir , chmod , chown ,
+.Ic chgrp , lpwd , df , symlink ,
+and
+.Ic lmkdir .
+Termination on error can be suppressed on a command by command basis by
+prefixing the command with a
+.Sq \-
+character (for example,
+.Ic -rm /tmp/blah* ) .
+.It Fl C
+Enables compression (via ssh's
+.Fl C
+flag).
+.It Fl c Ar cipher
+Selects the cipher to use for encrypting the data transfers.
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl D Ar sftp_server_path
+Connect directly to a local sftp server
+(rather than via
+.Xr ssh 1 ) .
+This option may be useful in debugging the client and server.
+.It Fl F Ar ssh_config
+Specifies an alternative
+per-user configuration file for
+.Xr ssh 1 .
+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 public key
+authentication is read.
+This option is directly passed to
+.Xr ssh 1 .
+.It Fl l Ar limit
+Limits the used bandwidth, specified in Kbit/s.
+.It Fl o Ar ssh_option
+Can be used to pass options to
+.Nm ssh
+in the format used in
+.Xr ssh_config 5 .
+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 .
+For full details of the options listed below, and their possible values, see
+.Xr ssh_config 5 .
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It AddressFamily
+.It BatchMode
+.It BindAddress
+.It ChallengeResponseAuthentication
+.It CheckHostIP
+.It Cipher
+.It Ciphers
+.It Compression
+.It CompressionLevel
+.It ConnectionAttempts
+.It ConnectTimeout
+.It ControlMaster
+.It ControlPath
+.It GlobalKnownHostsFile
+.It GSSAPIAuthentication
+.It GSSAPIDelegateCredentials
+.It HashKnownHosts
+.It Host
+.It HostbasedAuthentication
+.It HostKeyAlgorithms
+.It HostKeyAlias
+.It HostName
+.It IdentityFile
+.It IdentitiesOnly
+.It IPQoS
+.It KbdInteractiveDevices
+.It KexAlgorithms
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It PKCS11Provider
+.It Port
+.It PreferredAuthentications
+.It Protocol
+.It ProxyCommand
+.It PubkeyAuthentication
+.It RekeyLimit
+.It RhostsRSAAuthentication
+.It RSAAuthentication
+.It SendEnv
+.It ServerAliveInterval
+.It ServerAliveCountMax
+.It StrictHostKeyChecking
+.It TCPKeepAlive
+.It UsePrivilegedPort
+.It User
+.It UserKnownHostsFile
+.It VerifyHostKeyDNS
+.El
+.It Fl P Ar port
+Specifies the port to connect to on the remote host.
+.It Fl p
+Preserves modification times, access times, and modes from the
+original files transferred.
+.It Fl q
+Quiet mode: disables the progress meter as well as warning and
+diagnostic messages from
+.Xr ssh 1 .
+.It Fl R Ar num_requests
+Specify how many requests may be outstanding at any one time.
+Increasing this may slightly improve file transfer speed
+but will increase memory usage.
+The default is 64 outstanding requests.
+.It Fl r
+Recursively copy entire directories when uploading and downloading.
+Note that
+.Nm
+does not follow symbolic links encountered in the tree traversal.
+.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 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
+.Nm
+over protocol version 1, or when the remote
+.Xr sshd 8
+does not have an sftp subsystem configured.
+.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.
+Pathnames that contain spaces must be enclosed in quotes.
+Any special characters contained within pathnames that are recognized by
+.Xr glob 3
+must be escaped with backslashes
+.Pq Sq \e .
+.Bl -tag -width Ds
+.It Ic bye
+Quit
+.Nm sftp .
+.It Ic cd Ar path
+Change remote directory to
+.Ar path .
+.It Ic chgrp Ar grp Ar path
+Change group of file
+.Ar path
+to
+.Ar grp .
+.Ar path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+.Ar grp
+must be a numeric GID.
+.It Ic chmod Ar mode Ar path
+Change permissions of file
+.Ar path
+to
+.Ar mode .
+.Ar path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+.It Ic chown Ar own Ar path
+Change owner of file
+.Ar path
+to
+.Ar own .
+.Ar path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+.Ar own
+must be a numeric UID.
+.It Xo Ic df
+.Op Fl hi
+.Op Ar path
+.Xc
+Display usage information for the filesystem holding the current directory
+(or
+.Ar path
+if specified).
+If the
+.Fl h
+flag is specified, the capacity information will be displayed using
+"human-readable" suffixes.
+The
+.Fl i
+flag requests display of inode information in addition to capacity information.
+This command is only supported on servers that implement the
+.Dq statvfs@openssh.com
+extension.
+.It Ic exit
+Quit
+.Nm sftp .
+.It Xo Ic get
+.Op Fl Ppr
+.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.
+.Ar remote-path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+If it does and
+.Ar local-path
+is specified, then
+.Ar local-path
+must specify a directory.
+.Pp
+If either the
+.Fl P
+or
+.Fl p
+flag is specified, then full file permissions and access times are
+copied too.
+.Pp
+If the
+.Fl r
+flag is specified then directories will be copied recursively.
+Note that
+.Nm
+does not follow symbolic links when performing recursive transfers.
+.It Ic help
+Display help text.
+.It Ic lcd Ar path
+Change local directory to
+.Ar path .
+.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.
+.Ar ls-options
+may contain any flags supported by the local system's
+.Xr ls 1
+command.
+.Ar path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+.It Ic lmkdir Ar path
+Create local directory specified by
+.Ar path .
+.It Xo Ic ln
+.Op Fl s
+.Ar oldpath
+.Ar newpath
+.Xc
+Create a link from
+.Ar oldpath
+to
+.Ar newpath .
+If the
+.Fl s
+flag is specified the created link is a symbolic link, otherwise it is
+a hard link.
+.It Ic lpwd
+Print local working directory.
+.It Xo Ic ls
+.Op Fl 1afhlnrSt
+.Op Ar path
+.Xc
+Display a remote directory listing of either
+.Ar path
+or the current directory if
+.Ar path
+is not specified.
+.Ar path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+.Pp
+The following flags are recognized and alter the behaviour of
+.Ic ls
+accordingly:
+.Bl -tag -width Ds
+.It Fl 1
+Produce single columnar output.
+.It Fl a
+List files beginning with a dot
+.Pq Sq \&. .
+.It Fl f
+Do not sort the listing.
+The default sort order is lexicographical.
+.It Fl h
+When used with a long format option, use unit suffixes: Byte, Kilobyte,
+Megabyte, Gigabyte, Terabyte, Petabyte, and Exabyte in order to reduce
+the number of digits to four or fewer using powers of 2 for sizes (K=1024,
+M=1048576, etc.).
+.It Fl l
+Display additional details including permissions
+and ownership information.
+.It Fl n
+Produce a long listing with user and group information presented
+numerically.
+.It Fl r
+Reverse the sort order of the listing.
+.It Fl S
+Sort the listing by file size.
+.It Fl t
+Sort the listing by last modification time.
+.El
+.It Ic lumask Ar umask
+Set local umask to
+.Ar umask .
+.It Ic mkdir Ar path
+Create remote directory specified by
+.Ar path .
+.It Ic progress
+Toggle display of progress meter.
+.It Xo Ic put
+.Op Fl Ppr
+.Ar local-path
+.Op Ar remote-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.
+.Ar local-path
+may contain
+.Xr glob 3
+characters and may match multiple files.
+If it does and
+.Ar remote-path
+is specified, then
+.Ar remote-path
+must specify a directory.
+.Pp
+If ether the
+.Fl P
+or
+.Fl p
+flag is specified, then full file permissions and access times are
+copied too.
+.Pp
+If the
+.Fl r
+flag is specified then directories will be copied recursively.
+Note that
+.Nm
+does not follow symbolic links when performing recursive transfers.
+.It Ic pwd
+Display remote working directory.
+.It Ic quit
+Quit
+.Nm sftp .
+.It Ic rename Ar oldpath Ar newpath
+Rename remote file from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic rm Ar path
+Delete remote file specified by
+.Ar path .
+.It Ic rmdir Ar path
+Remove remote directory specified by
+.Ar path .
+.It Ic symlink Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic version
+Display the
+.Nm
+protocol version.
+.It Ic \&! Ns Ar command
+Execute
+.Ar command
+in local shell.
+.It Ic \&!
+Escape to local shell.
+.It Ic \&?
+Synonym for help.
+.El
+.Sh SEE ALSO
+.Xr ftp 1 ,
+.Xr ls 1 ,
+.Xr scp 1 ,
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr glob 3 ,
+.Xr ssh_config 5 ,
+.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/sftp.c b/sftp.c
new file mode 100644 (file)
index 0000000..ab667f5
--- /dev/null
+++ b/sftp.c
@@ -0,0 +1,2290 @@
+/* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#endif
+#ifdef USE_LIBEDIT
+#include <histedit.h>
+#else
+typedef void EditLine;
+#endif
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
+#include "xmalloc.h"
+#include "log.h"
+#include "pathnames.h"
+#include "misc.h"
+
+#include "sftp.h"
+#include "buffer.h"
+#include "sftp-common.h"
+#include "sftp-client.h"
+
+#define DEFAULT_COPY_BUFLEN    32768   /* Size of buffer for up/download */
+#define DEFAULT_NUM_REQUESTS   64      /* # concurrent outstanding requests */
+
+/* File to read commands from */
+FILE* infile;
+
+/* Are we in batchfile mode? */
+int batchmode = 0;
+
+/* PID of ssh transport process */
+static pid_t sshpid = -1;
+
+/* This is set to 0 if the progressmeter is not desired. */
+int showprogress = 1;
+
+/* When this option is set, we always recursively download/upload directories */
+int global_rflag = 0;
+
+/* When this option is set, the file transfers will always preserve times */
+int global_pflag = 0;
+
+/* SIGINT received during command processing */
+volatile sig_atomic_t interrupted = 0;
+
+/* I wish qsort() took a separate ctx for the comparison function...*/
+int sort_flag;
+
+/* Context used for commandline completion */
+struct complete_ctx {
+       struct sftp_conn *conn;
+       char **remote_pathp;
+};
+
+int remote_glob(struct sftp_conn *, const char *, int,
+    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
+
+extern char *__progname;
+
+/* Separators for interactive commands */
+#define WHITESPACE " \t\r\n"
+
+/* ls flags */
+#define LS_LONG_VIEW   0x0001  /* Full view ala ls -l */
+#define LS_SHORT_VIEW  0x0002  /* Single row view ala ls -1 */
+#define LS_NUMERIC_VIEW        0x0004  /* Long view with numeric uid/gid */
+#define LS_NAME_SORT   0x0008  /* Sort by name (default) */
+#define LS_TIME_SORT   0x0010  /* Sort by mtime */
+#define LS_SIZE_SORT   0x0020  /* Sort by file size */
+#define LS_REVERSE_SORT        0x0040  /* Reverse sort order */
+#define LS_SHOW_ALL    0x0080  /* Don't skip filenames starting with '.' */
+#define LS_SI_UNITS    0x0100  /* Display sizes as K, M, G, etc. */
+
+#define VIEW_FLAGS     (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
+#define SORT_FLAGS     (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
+
+/* Commands for interactive mode */
+#define I_CHDIR                1
+#define I_CHGRP                2
+#define I_CHMOD                3
+#define I_CHOWN                4
+#define I_DF           24
+#define I_GET          5
+#define I_HELP         6
+#define I_LCHDIR       7
+#define I_LINK         25
+#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
+#define I_PROGRESS     23
+
+struct CMD {
+       const char *c;
+       const int n;
+       const int t;
+};
+
+/* Type of completion */
+#define NOARGS 0
+#define REMOTE 1
+#define LOCAL  2
+
+static const struct CMD cmds[] = {
+       { "bye",        I_QUIT,         NOARGS  },
+       { "cd",         I_CHDIR,        REMOTE  },
+       { "chdir",      I_CHDIR,        REMOTE  },
+       { "chgrp",      I_CHGRP,        REMOTE  },
+       { "chmod",      I_CHMOD,        REMOTE  },
+       { "chown",      I_CHOWN,        REMOTE  },
+       { "df",         I_DF,           REMOTE  },
+       { "dir",        I_LS,           REMOTE  },
+       { "exit",       I_QUIT,         NOARGS  },
+       { "get",        I_GET,          REMOTE  },
+       { "help",       I_HELP,         NOARGS  },
+       { "lcd",        I_LCHDIR,       LOCAL   },
+       { "lchdir",     I_LCHDIR,       LOCAL   },
+       { "lls",        I_LLS,          LOCAL   },
+       { "lmkdir",     I_LMKDIR,       LOCAL   },
+       { "ln",         I_LINK,         REMOTE  },
+       { "lpwd",       I_LPWD,         LOCAL   },
+       { "ls",         I_LS,           REMOTE  },
+       { "lumask",     I_LUMASK,       NOARGS  },
+       { "mkdir",      I_MKDIR,        REMOTE  },
+       { "mget",       I_GET,          REMOTE  },
+       { "mput",       I_PUT,          LOCAL   },
+       { "progress",   I_PROGRESS,     NOARGS  },
+       { "put",        I_PUT,          LOCAL   },
+       { "pwd",        I_PWD,          REMOTE  },
+       { "quit",       I_QUIT,         NOARGS  },
+       { "rename",     I_RENAME,       REMOTE  },
+       { "rm",         I_RM,           REMOTE  },
+       { "rmdir",      I_RMDIR,        REMOTE  },
+       { "symlink",    I_SYMLINK,      REMOTE  },
+       { "version",    I_VERSION,      NOARGS  },
+       { "!",          I_SHELL,        NOARGS  },
+       { "?",          I_HELP,         NOARGS  },
+       { NULL,         -1,             -1      }
+};
+
+int interactive_loop(struct sftp_conn *, char *file1, char *file2);
+
+/* ARGSUSED */
+static void
+killchild(int signo)
+{
+       if (sshpid > 1) {
+               kill(sshpid, SIGTERM);
+               waitpid(sshpid, NULL, 0);
+       }
+
+       _exit(1);
+}
+
+/* ARGSUSED */
+static void
+cmd_interrupt(int signo)
+{
+       const char msg[] = "\rInterrupt  \n";
+       int olderrno = errno;
+
+       write(STDERR_FILENO, msg, sizeof(msg) - 1);
+       interrupted = 1;
+       errno = olderrno;
+}
+
+static void
+help(void)
+{
+       printf("Available commands:\n"
+           "bye                                Quit sftp\n"
+           "cd path                            Change remote directory to 'path'\n"
+           "chgrp grp path                     Change group of file 'path' to 'grp'\n"
+           "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
+           "chown own path                     Change owner of file 'path' to 'own'\n"
+           "df [-hi] [path]                    Display statistics for current directory or\n"
+           "                                   filesystem containing 'path'\n"
+           "exit                               Quit sftp\n"
+           "get [-Ppr] remote [local]          Download file\n"
+           "help                               Display this help text\n"
+           "lcd path                           Change local directory to 'path'\n"
+           "lls [ls-options [path]]            Display local directory listing\n"
+           "lmkdir path                        Create local directory\n"
+           "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
+           "lpwd                               Print local working directory\n"
+           "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
+           "lumask umask                       Set local umask to 'umask'\n"
+           "mkdir path                         Create remote directory\n"
+           "progress                           Toggle display of progress meter\n"
+           "put [-Ppr] local [remote]          Upload file\n"
+           "pwd                                Display remote working directory\n"
+           "quit                               Quit sftp\n"
+           "rename oldpath newpath             Rename remote file\n"
+           "rm path                            Delete remote file\n"
+           "rmdir path                         Remove remote directory\n"
+           "symlink oldpath newpath            Symlink remote file\n"
+           "version                            Show SFTP version\n"
+           "!command                           Execute 'command' in local shell\n"
+           "!                                  Escape to local shell\n"
+           "?                                  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 == '\0')
+               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);
+       }
+       while (waitpid(pid, &status, 0) == -1)
+               if (errno != EINTR)
+                       fatal("Couldn't wait for child: %s", strerror(errno));
+       if (!WIFEXITED(status))
+               error("Shell exited abnormally");
+       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);
+       }
+}
+
+/* Strip one path (usually the pwd) from the start of another */
+static char *
+path_strip(char *path, char *strip)
+{
+       size_t len;
+
+       if (strip == NULL)
+               return (xstrdup(path));
+
+       len = strlen(strip);
+       if (strncmp(path, strip, len) == 0) {
+               if (strip[len - 1] != '/' && path[len] == '/')
+                       len++;
+               return (xstrdup(path + len));
+       }
+
+       return (xstrdup(path));
+}
+
+static char *
+make_absolute(char *p, char *pwd)
+{
+       char *abs_str;
+
+       /* Derelativise */
+       if (p && p[0] != '/') {
+               abs_str = path_append(pwd, p);
+               xfree(p);
+               return(abs_str);
+       } else
+               return(p);
+}
+
+static int
+parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
+    int *rflag)
+{
+       extern int opterr, optind, optopt, optreset;
+       int ch;
+
+       optind = optreset = 1;
+       opterr = 0;
+
+       *rflag = *pflag = 0;
+       while ((ch = getopt(argc, argv, "PpRr")) != -1) {
+               switch (ch) {
+               case 'p':
+               case 'P':
+                       *pflag = 1;
+                       break;
+               case 'r':
+               case 'R':
+                       *rflag = 1;
+                       break;
+               default:
+                       error("%s: Invalid flag -%c", cmd, optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
+}
+
+static int
+parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
+{
+       extern int opterr, optind, optopt, optreset;
+       int ch;
+
+       optind = optreset = 1;
+       opterr = 0;
+
+       *sflag = 0;
+       while ((ch = getopt(argc, argv, "s")) != -1) {
+               switch (ch) {
+               case 's':
+                       *sflag = 1;
+                       break;
+               default:
+                       error("%s: Invalid flag -%c", cmd, optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
+}
+
+static int
+parse_ls_flags(char **argv, int argc, int *lflag)
+{
+       extern int opterr, optind, optopt, optreset;
+       int ch;
+
+       optind = optreset = 1;
+       opterr = 0;
+
+       *lflag = LS_NAME_SORT;
+       while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
+               switch (ch) {
+               case '1':
+                       *lflag &= ~VIEW_FLAGS;
+                       *lflag |= LS_SHORT_VIEW;
+                       break;
+               case 'S':
+                       *lflag &= ~SORT_FLAGS;
+                       *lflag |= LS_SIZE_SORT;
+                       break;
+               case 'a':
+                       *lflag |= LS_SHOW_ALL;
+                       break;
+               case 'f':
+                       *lflag &= ~SORT_FLAGS;
+                       break;
+               case 'h':
+                       *lflag |= LS_SI_UNITS;
+                       break;
+               case 'l':
+                       *lflag &= ~LS_SHORT_VIEW;
+                       *lflag |= LS_LONG_VIEW;
+                       break;
+               case 'n':
+                       *lflag &= ~LS_SHORT_VIEW;
+                       *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
+                       break;
+               case 'r':
+                       *lflag |= LS_REVERSE_SORT;
+                       break;
+               case 't':
+                       *lflag &= ~SORT_FLAGS;
+                       *lflag |= LS_TIME_SORT;
+                       break;
+               default:
+                       error("ls: Invalid flag -%c", optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
+}
+
+static int
+parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
+{
+       extern int opterr, optind, optopt, optreset;
+       int ch;
+
+       optind = optreset = 1;
+       opterr = 0;
+
+       *hflag = *iflag = 0;
+       while ((ch = getopt(argc, argv, "hi")) != -1) {
+               switch (ch) {
+               case 'h':
+                       *hflag = 1;
+                       break;
+               case 'i':
+                       *iflag = 1;
+                       break;
+               default:
+                       error("%s: Invalid flag -%c", cmd, optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
+}
+
+static int
+is_dir(char *path)
+{
+       struct stat sb;
+
+       /* XXX: report errors? */
+       if (stat(path, &sb) == -1)
+               return(0);
+
+       return(S_ISDIR(sb.st_mode));
+}
+
+static int
+remote_is_dir(struct sftp_conn *conn, char *path)
+{
+       Attrib *a;
+
+       /* XXX: report errors? */
+       if ((a = do_stat(conn, path, 1)) == NULL)
+               return(0);
+       if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
+               return(0);
+       return(S_ISDIR(a->perm));
+}
+
+/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
+static int
+pathname_is_dir(char *pathname)
+{
+       size_t l = strlen(pathname);
+
+       return l > 0 && pathname[l - 1] == '/';
+}
+
+static int
+process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
+    int pflag, int rflag)
+{
+       char *abs_src = NULL;
+       char *abs_dst = NULL;
+       glob_t g;
+       char *filename, *tmp=NULL;
+       int i, err = 0;
+
+       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(conn, abs_src, GLOB_MARK, NULL, &g)) {
+               error("File \"%s\" not found.", abs_src);
+               err = -1;
+               goto out;
+       }
+
+       /*
+        * If multiple matches then dst must be a directory or
+        * unspecified.
+        */
+       if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
+               error("Multiple source paths, but destination "
+                   "\"%s\" is not a directory", dst);
+               err = -1;
+               goto out;
+       }
+
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+               tmp = xstrdup(g.gl_pathv[i]);
+               if ((filename = basename(tmp)) == NULL) {
+                       error("basename %s: %s", tmp, strerror(errno));
+                       xfree(tmp);
+                       err = -1;
+                       goto out;
+               }
+
+               if (g.gl_matchc == 1 && dst) {
+                       if (is_dir(dst)) {
+                               abs_dst = path_append(dst, filename);
+                       } else {
+                               abs_dst = xstrdup(dst);
+                       }
+               } else if (dst) {
+                       abs_dst = path_append(dst, filename);
+               } else {
+                       abs_dst = xstrdup(filename);
+               }
+               xfree(tmp);
+
+               printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
+               if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
+                       if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 
+                           pflag || global_pflag, 1) == -1)
+                               err = -1;
+               } else {
+                       if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
+                           pflag || global_pflag) == -1)
+                               err = -1;
+               }
+               xfree(abs_dst);
+               abs_dst = NULL;
+       }
+
+out:
+       xfree(abs_src);
+       globfree(&g);
+       return(err);
+}
+
+static int
+process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
+    int pflag, int rflag)
+{
+       char *tmp_dst = NULL;
+       char *abs_dst = NULL;
+       char *tmp = NULL, *filename = NULL;
+       glob_t g;
+       int err = 0;
+       int i, dst_is_dir = 1;
+       struct stat sb;
+
+       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, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
+               error("File \"%s\" not found.", src);
+               err = -1;
+               goto out;
+       }
+
+       /* If we aren't fetching to pwd then stash this status for later */
+       if (tmp_dst != NULL)
+               dst_is_dir = remote_is_dir(conn, tmp_dst);
+
+       /* If multiple matches, dst may be directory or unspecified */
+       if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
+               error("Multiple paths match, but destination "
+                   "\"%s\" is not a directory", tmp_dst);
+               err = -1;
+               goto out;
+       }
+
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+               if (stat(g.gl_pathv[i], &sb) == -1) {
+                       err = -1;
+                       error("stat %s: %s", g.gl_pathv[i], strerror(errno));
+                       continue;
+               }
+               
+               tmp = xstrdup(g.gl_pathv[i]);
+               if ((filename = basename(tmp)) == NULL) {
+                       error("basename %s: %s", tmp, strerror(errno));
+                       xfree(tmp);
+                       err = -1;
+                       goto out;
+               }
+
+               if (g.gl_matchc == 1 && tmp_dst) {
+                       /* If directory specified, append filename */
+                       if (dst_is_dir)
+                               abs_dst = path_append(tmp_dst, filename);
+                       else
+                               abs_dst = xstrdup(tmp_dst);
+               } else if (tmp_dst) {
+                       abs_dst = path_append(tmp_dst, filename);
+               } else {
+                       abs_dst = make_absolute(xstrdup(filename), pwd);
+               }
+               xfree(tmp);
+
+               printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
+               if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
+                       if (upload_dir(conn, g.gl_pathv[i], abs_dst,
+                           pflag || global_pflag, 1) == -1)
+                               err = -1;
+               } else {
+                       if (do_upload(conn, g.gl_pathv[i], abs_dst,
+                           pflag || global_pflag) == -1)
+                               err = -1;
+               }
+       }
+
+out:
+       if (abs_dst)
+               xfree(abs_dst);
+       if (tmp_dst)
+               xfree(tmp_dst);
+       globfree(&g);
+       return(err);
+}
+
+static int
+sdirent_comp(const void *aa, const void *bb)
+{
+       SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
+       SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
+       int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
+
+#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
+       if (sort_flag & LS_NAME_SORT)
+               return (rmul * strcmp(a->filename, b->filename));
+       else if (sort_flag & LS_TIME_SORT)
+               return (rmul * NCMP(a->a.mtime, b->a.mtime));
+       else if (sort_flag & LS_SIZE_SORT)
+               return (rmul * NCMP(a->a.size, b->a.size));
+
+       fatal("Unknown ls sort type");
+}
+
+/* sftp ls.1 replacement for directories */
+static int
+do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
+{
+       int n;
+       u_int c = 1, colspace = 0, columns = 1;
+       SFTP_DIRENT **d;
+
+       if ((n = do_readdir(conn, path, &d)) != 0)
+               return (n);
+
+       if (!(lflag & LS_SHORT_VIEW)) {
+               u_int m = 0, width = 80;
+               struct winsize ws;
+               char *tmp;
+
+               /* Count entries for sort and find longest filename */
+               for (n = 0; d[n] != NULL; n++) {
+                       if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
+                               m = MAX(m, strlen(d[n]->filename));
+               }
+
+               /* Add any subpath that also needs to be counted */
+               tmp = path_strip(path, strip_path);
+               m += strlen(tmp);
+               xfree(tmp);
+
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+                       width = ws.ws_col;
+
+               columns = width / (m + 2);
+               columns = MAX(columns, 1);
+               colspace = width / columns;
+               colspace = MIN(colspace, width);
+       }
+
+       if (lflag & SORT_FLAGS) {
+               for (n = 0; d[n] != NULL; n++)
+                       ;       /* count entries */
+               sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
+               qsort(d, n, sizeof(*d), sdirent_comp);
+       }
+
+       for (n = 0; d[n] != NULL && !interrupted; n++) {
+               char *tmp, *fname;
+
+               if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
+                       continue;
+
+               tmp = path_append(path, d[n]->filename);
+               fname = path_strip(tmp, strip_path);
+               xfree(tmp);
+
+               if (lflag & LS_LONG_VIEW) {
+                       if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
+                               char *lname;
+                               struct stat sb;
+
+                               memset(&sb, 0, sizeof(sb));
+                               attrib_to_stat(&d[n]->a, &sb);
+                               lname = ls_file(fname, &sb, 1,
+                                   (lflag & LS_SI_UNITS));
+                               printf("%s\n", lname);
+                               xfree(lname);
+                       } else
+                               printf("%s\n", d[n]->longname);
+               } else {
+                       printf("%-*s", colspace, fname);
+                       if (c >= columns) {
+                               printf("\n");
+                               c = 1;
+                       } else
+                               c++;
+               }
+
+               xfree(fname);
+       }
+
+       if (!(lflag & LS_LONG_VIEW) && (c != 1))
+               printf("\n");
+
+       free_sftp_dirents(d);
+       return (0);
+}
+
+/* sftp ls.1 replacement which handles path globs */
+static int
+do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
+    int lflag)
+{
+       Attrib *a = NULL;
+       char *fname, *lname;
+       glob_t g;
+       int err;
+       struct winsize ws;
+       u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
+
+       memset(&g, 0, sizeof(g));
+
+       if (remote_glob(conn, path,
+           GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT, NULL, &g) ||
+           (g.gl_pathc && !g.gl_matchc)) {
+               if (g.gl_pathc)
+                       globfree(&g);
+               error("Can't ls: \"%s\" not found", path);
+               return -1;
+       }
+
+       if (interrupted)
+               goto out;
+
+       /*
+        * If the glob returns a single match and it is a directory,
+        * then just list its contents.
+        */
+       if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
+           S_ISDIR(g.gl_statv[0]->st_mode)) {
+               err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
+               globfree(&g);
+               return err;
+       }
+
+       if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+               width = ws.ws_col;
+
+       if (!(lflag & LS_SHORT_VIEW)) {
+               /* Count entries for sort and find longest filename */
+               for (i = 0; g.gl_pathv[i]; i++)
+                       m = MAX(m, strlen(g.gl_pathv[i]));
+
+               columns = width / (m + 2);
+               columns = MAX(columns, 1);
+               colspace = width / columns;
+       }
+
+       for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
+               fname = path_strip(g.gl_pathv[i], strip_path);
+               if (lflag & LS_LONG_VIEW) {
+                       if (g.gl_statv[i] == NULL) {
+                               error("no stat information for %s", fname);
+                               continue;
+                       }
+                       lname = ls_file(fname, g.gl_statv[i], 1,
+                           (lflag & LS_SI_UNITS));
+                       printf("%s\n", lname);
+                       xfree(lname);
+               } else {
+                       printf("%-*s", colspace, fname);
+                       if (c >= columns) {
+                               printf("\n");
+                               c = 1;
+                       } else
+                               c++;
+               }
+               xfree(fname);
+       }
+
+       if (!(lflag & LS_LONG_VIEW) && (c != 1))
+               printf("\n");
+
+ out:
+       if (g.gl_pathc)
+               globfree(&g);
+
+       return 0;
+}
+
+static int
+do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
+{
+       struct sftp_statvfs st;
+       char s_used[FMT_SCALED_STRSIZE];
+       char s_avail[FMT_SCALED_STRSIZE];
+       char s_root[FMT_SCALED_STRSIZE];
+       char s_total[FMT_SCALED_STRSIZE];
+       unsigned long long ffree;
+
+       if (do_statvfs(conn, path, &st, 1) == -1)
+               return -1;
+       if (iflag) {
+               ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0;
+               printf("     Inodes        Used       Avail      "
+                   "(root)    %%Capacity\n");
+               printf("%11llu %11llu %11llu %11llu         %3llu%%\n",
+                   (unsigned long long)st.f_files,
+                   (unsigned long long)(st.f_files - st.f_ffree),
+                   (unsigned long long)st.f_favail,
+                   (unsigned long long)st.f_ffree, ffree);
+       } else if (hflag) {
+               strlcpy(s_used, "error", sizeof(s_used));
+               strlcpy(s_avail, "error", sizeof(s_avail));
+               strlcpy(s_root, "error", sizeof(s_root));
+               strlcpy(s_total, "error", sizeof(s_total));
+               fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
+               fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
+               fmt_scaled(st.f_bfree * st.f_frsize, s_root);
+               fmt_scaled(st.f_blocks * st.f_frsize, s_total);
+               printf("    Size     Used    Avail   (root)    %%Capacity\n");
+               printf("%7sB %7sB %7sB %7sB         %3llu%%\n",
+                   s_total, s_used, s_avail, s_root,
+                   (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+                   st.f_blocks));
+       } else {
+               printf("        Size         Used        Avail       "
+                   "(root)    %%Capacity\n");
+               printf("%12llu %12llu %12llu %12llu         %3llu%%\n",
+                   (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
+                   (unsigned long long)(st.f_frsize *
+                   (st.f_blocks - st.f_bfree) / 1024),
+                   (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
+                   (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
+                   (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+                   st.f_blocks));
+       }
+       return 0;
+}
+
+/*
+ * Undo escaping of glob sequences in place. Used to undo extra escaping
+ * applied in makeargv() when the string is destined for a function that
+ * does not glob it.
+ */
+static void
+undo_glob_escape(char *s)
+{
+       size_t i, j;
+
+       for (i = j = 0;;) {
+               if (s[i] == '\0') {
+                       s[j] = '\0';
+                       return;
+               }
+               if (s[i] != '\\') {
+                       s[j++] = s[i++];
+                       continue;
+               }
+               /* s[i] == '\\' */
+               ++i;
+               switch (s[i]) {
+               case '?':
+               case '[':
+               case '*':
+               case '\\':
+                       s[j++] = s[i++];
+                       break;
+               case '\0':
+                       s[j++] = '\\';
+                       s[j] = '\0';
+                       return;
+               default:
+                       s[j++] = '\\';
+                       s[j++] = s[i++];
+                       break;
+               }
+       }
+}
+
+/*
+ * Split a string into an argument vector using sh(1)-style quoting,
+ * comment and escaping rules, but with some tweaks to handle glob(3)
+ * wildcards.
+ * The "sloppy" flag allows for recovery from missing terminating quote, for
+ * use in parsing incomplete commandlines during tab autocompletion.
+ *
+ * Returns NULL on error or a NULL-terminated array of arguments.
+ *
+ * If "lastquote" is not NULL, the quoting character used for the last
+ * argument is placed in *lastquote ("\0", "'" or "\"").
+ * 
+ * If "terminated" is not NULL, *terminated will be set to 1 when the
+ * last argument's quote has been properly terminated or 0 otherwise.
+ * This parameter is only of use if "sloppy" is set.
+ */
+#define MAXARGS        128
+#define MAXARGLEN      8192
+static char **
+makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
+    u_int *terminated)
+{
+       int argc, quot;
+       size_t i, j;
+       static char argvs[MAXARGLEN];
+       static char *argv[MAXARGS + 1];
+       enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
+
+       *argcp = argc = 0;
+       if (strlen(arg) > sizeof(argvs) - 1) {
+ args_too_longs:
+               error("string too long");
+               return NULL;
+       }
+       if (terminated != NULL)
+               *terminated = 1;
+       if (lastquote != NULL)
+               *lastquote = '\0';
+       state = MA_START;
+       i = j = 0;
+       for (;;) {
+               if (isspace(arg[i])) {
+                       if (state == MA_UNQUOTED) {
+                               /* Terminate current argument */
+                               argvs[j++] = '\0';
+                               argc++;
+                               state = MA_START;
+                       } else if (state != MA_START)
+                               argvs[j++] = arg[i];
+               } else if (arg[i] == '"' || arg[i] == '\'') {
+                       q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
+                       if (state == MA_START) {
+                               argv[argc] = argvs + j;
+                               state = q;
+                               if (lastquote != NULL)
+                                       *lastquote = arg[i];
+                       } else if (state == MA_UNQUOTED) 
+                               state = q;
+                       else if (state == q)
+                               state = MA_UNQUOTED;
+                       else
+                               argvs[j++] = arg[i];
+               } else if (arg[i] == '\\') {
+                       if (state == MA_SQUOTE || state == MA_DQUOTE) {
+                               quot = state == MA_SQUOTE ? '\'' : '"';
+                               /* Unescape quote we are in */
+                               /* XXX support \n and friends? */
+                               if (arg[i + 1] == quot) {
+                                       i++;
+                                       argvs[j++] = arg[i];
+                               } else if (arg[i + 1] == '?' ||
+                                   arg[i + 1] == '[' || arg[i + 1] == '*') {
+                                       /*
+                                        * Special case for sftp: append
+                                        * double-escaped glob sequence -
+                                        * glob will undo one level of
+                                        * escaping. NB. string can grow here.
+                                        */
+                                       if (j >= sizeof(argvs) - 5)
+                                               goto args_too_longs;
+                                       argvs[j++] = '\\';
+                                       argvs[j++] = arg[i++];
+                                       argvs[j++] = '\\';
+                                       argvs[j++] = arg[i];
+                               } else {
+                                       argvs[j++] = arg[i++];
+                                       argvs[j++] = arg[i];
+                               }
+                       } else {
+                               if (state == MA_START) {
+                                       argv[argc] = argvs + j;
+                                       state = MA_UNQUOTED;
+                                       if (lastquote != NULL)
+                                               *lastquote = '\0';
+                               }
+                               if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
+                                   arg[i + 1] == '*' || arg[i + 1] == '\\') {
+                                       /*
+                                        * Special case for sftp: append
+                                        * escaped glob sequence -
+                                        * glob will undo one level of
+                                        * escaping.
+                                        */
+                                       argvs[j++] = arg[i++];
+                                       argvs[j++] = arg[i];
+                               } else {
+                                       /* Unescape everything */
+                                       /* XXX support \n and friends? */
+                                       i++;
+                                       argvs[j++] = arg[i];
+                               }
+                       }
+               } else if (arg[i] == '#') {
+                       if (state == MA_SQUOTE || state == MA_DQUOTE)
+                               argvs[j++] = arg[i];
+                       else
+                               goto string_done;
+               } else if (arg[i] == '\0') {
+                       if (state == MA_SQUOTE || state == MA_DQUOTE) {
+                               if (sloppy) {
+                                       state = MA_UNQUOTED;
+                                       if (terminated != NULL)
+                                               *terminated = 0;
+                                       goto string_done;
+                               }
+                               error("Unterminated quoted argument");
+                               return NULL;
+                       }
+ string_done:
+                       if (state == MA_UNQUOTED) {
+                               argvs[j++] = '\0';
+                               argc++;
+                       }
+                       break;
+               } else {
+                       if (state == MA_START) {
+                               argv[argc] = argvs + j;
+                               state = MA_UNQUOTED;
+                               if (lastquote != NULL)
+                                       *lastquote = '\0';
+                       }
+                       if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
+                           (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
+                               /*
+                                * Special case for sftp: escape quoted
+                                * glob(3) wildcards. NB. string can grow
+                                * here.
+                                */
+                               if (j >= sizeof(argvs) - 3)
+                                       goto args_too_longs;
+                               argvs[j++] = '\\';
+                               argvs[j++] = arg[i];
+                       } else
+                               argvs[j++] = arg[i];
+               }
+               i++;
+       }
+       *argcp = argc;
+       return argv;
+}
+
+static int
+parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
+    int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
+{
+       const char *cmd, *cp = *cpp;
+       char *cp2, **argv;
+       int base = 0;
+       long l;
+       int i, cmdnum, optidx, argc;
+
+       /* Skip leading whitespace */
+       cp = cp + strspn(cp, WHITESPACE);
+
+       /* Check for leading '-' (disable error processing) */
+       *iflag = 0;
+       if (*cp == '-') {
+               *iflag = 1;
+               cp++;
+               cp = cp + strspn(cp, WHITESPACE);
+       }
+
+       /* Ignore blank lines and lines which begin with comment '#' char */
+       if (*cp == '\0' || *cp == '#')
+               return (0);
+
+       if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
+               return -1;
+
+       /* Figure out which command we have */
+       for (i = 0; cmds[i].c != NULL; i++) {
+               if (strcasecmp(cmds[i].c, argv[0]) == 0)
+                       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 */
+       *lflag = *pflag = *rflag = *hflag = *n_arg = 0;
+       *path1 = *path2 = NULL;
+       optidx = 1;
+       switch (cmdnum) {
+       case I_GET:
+       case I_PUT:
+               if ((optidx = parse_getput_flags(cmd, argv, argc,
+                   pflag, rflag)) == -1)
+                       return -1;
+               /* Get first pathname (mandatory) */
+               if (argc - optidx < 1) {
+                       error("You must specify at least one path after a "
+                           "%s command.", cmd);
+                       return -1;
+               }
+               *path1 = xstrdup(argv[optidx]);
+               /* Get second pathname (optional) */
+               if (argc - optidx > 1) {
+                       *path2 = xstrdup(argv[optidx + 1]);
+                       /* Destination is not globbed */
+                       undo_glob_escape(*path2);
+               }
+               break;
+       case I_LINK:
+               if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
+                       return -1;
+       case I_SYMLINK:
+       case I_RENAME:
+               if (argc - optidx < 2) {
+                       error("You must specify two paths after a %s "
+                           "command.", cmd);
+                       return -1;
+               }
+               *path1 = xstrdup(argv[optidx]);
+               *path2 = xstrdup(argv[optidx + 1]);
+               /* Paths are not globbed */
+               undo_glob_escape(*path1);
+               undo_glob_escape(*path2);
+               break;
+       case I_RM:
+       case I_MKDIR:
+       case I_RMDIR:
+       case I_CHDIR:
+       case I_LCHDIR:
+       case I_LMKDIR:
+               /* Get pathname (mandatory) */
+               if (argc - optidx < 1) {
+                       error("You must specify a path after a %s command.",
+                           cmd);
+                       return -1;
+               }
+               *path1 = xstrdup(argv[optidx]);
+               /* Only "rm" globs */
+               if (cmdnum != I_RM)
+                       undo_glob_escape(*path1);
+               break;
+       case I_DF:
+               if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
+                   iflag)) == -1)
+                       return -1;
+               /* Default to current directory if no path specified */
+               if (argc - optidx < 1)
+                       *path1 = NULL;
+               else {
+                       *path1 = xstrdup(argv[optidx]);
+                       undo_glob_escape(*path1);
+               }
+               break;
+       case I_LS:
+               if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
+                       return(-1);
+               /* Path is optional */
+               if (argc - optidx > 0)
+                       *path1 = xstrdup(argv[optidx]);
+               break;
+       case I_LLS:
+               /* Skip ls command and following whitespace */
+               cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
+       case I_SHELL:
+               /* Uses the rest of the line */
+               break;
+       case I_LUMASK:
+       case I_CHMOD:
+               base = 8;
+       case I_CHOWN:
+       case I_CHGRP:
+               /* Get numeric arg (mandatory) */
+               if (argc - optidx < 1)
+                       goto need_num_arg;
+               errno = 0;
+               l = strtol(argv[optidx], &cp2, base);
+               if (cp2 == argv[optidx] || *cp2 != '\0' ||
+                   ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
+                   l < 0) {
+ need_num_arg:
+                       error("You must supply a numeric argument "
+                           "to the %s command.", cmd);
+                       return -1;
+               }
+               *n_arg = l;
+               if (cmdnum == I_LUMASK)
+                       break;
+               /* Get pathname (mandatory) */
+               if (argc - optidx < 2) {
+                       error("You must specify a path after a %s command.",
+                           cmd);
+                       return -1;
+               }
+               *path1 = xstrdup(argv[optidx + 1]);
+               break;
+       case I_QUIT:
+       case I_PWD:
+       case I_LPWD:
+       case I_HELP:
+       case I_VERSION:
+       case I_PROGRESS:
+               break;
+       default:
+               fatal("Command not implemented");
+       }
+
+       *cpp = cp;
+       return(cmdnum);
+}
+
+static int
+parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
+    int err_abort)
+{
+       char *path1, *path2, *tmp;
+       int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
+       int cmdnum, i;
+       unsigned long n_arg = 0;
+       Attrib a, *aa;
+       char path_buf[MAXPATHLEN];
+       int err = 0;
+       glob_t g;
+
+       path1 = path2 = NULL;
+       cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
+           &sflag, &n_arg, &path1, &path2);
+
+       if (iflag != 0)
+               err_abort = 0;
+
+       memset(&g, 0, sizeof(g));
+
+       /* Perform command */
+       switch (cmdnum) {
+       case 0:
+               /* Blank line */
+               break;
+       case -1:
+               /* Unrecognized command */
+               err = -1;
+               break;
+       case I_GET:
+               err = process_get(conn, path1, path2, *pwd, pflag, rflag);
+               break;
+       case I_PUT:
+               err = process_put(conn, path1, path2, *pwd, pflag, rflag);
+               break;
+       case I_RENAME:
+               path1 = make_absolute(path1, *pwd);
+               path2 = make_absolute(path2, *pwd);
+               err = do_rename(conn, path1, path2);
+               break;
+       case I_SYMLINK:
+               sflag = 1;
+       case I_LINK:
+               path1 = make_absolute(path1, *pwd);
+               path2 = make_absolute(path2, *pwd);
+               err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
+               break;
+       case I_RM:
+               path1 = make_absolute(path1, *pwd);
+               remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+                       printf("Removing %s\n", g.gl_pathv[i]);
+                       err = do_rm(conn, g.gl_pathv[i]);
+                       if (err != 0 && err_abort)
+                               break;
+               }
+               break;
+       case I_MKDIR:
+               path1 = make_absolute(path1, *pwd);
+               attrib_clear(&a);
+               a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
+               a.perm = 0777;
+               err = do_mkdir(conn, path1, &a, 1);
+               break;
+       case I_RMDIR:
+               path1 = make_absolute(path1, *pwd);
+               err = do_rmdir(conn, path1);
+               break;
+       case I_CHDIR:
+               path1 = make_absolute(path1, *pwd);
+               if ((tmp = do_realpath(conn, path1)) == NULL) {
+                       err = 1;
+                       break;
+               }
+               if ((aa = do_stat(conn, 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_dir(conn, *pwd, *pwd, lflag);
+                       break;
+               }
+
+               /* Strip pwd off beginning of non-absolute paths */
+               tmp = NULL;
+               if (*path1 != '/')
+                       tmp = *pwd;
+
+               path1 = make_absolute(path1, *pwd);
+               err = do_globbed_ls(conn, path1, tmp, lflag);
+               break;
+       case I_DF:
+               /* Default to current directory if no path specified */
+               if (path1 == NULL)
+                       path1 = xstrdup(*pwd);
+               path1 = make_absolute(path1, *pwd);
+               err = do_df(conn, path1, hflag, iflag);
+               break;
+       case I_LCHDIR:
+               if (chdir(path1) == -1) {
+                       error("Couldn't change local directory to "
+                           "\"%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(conn, path1, GLOB_NOCHECK, NULL, &g);
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+                       printf("Changing mode on %s\n", g.gl_pathv[i]);
+                       err = do_setstat(conn, g.gl_pathv[i], &a);
+                       if (err != 0 && err_abort)
+                               break;
+               }
+               break;
+       case I_CHOWN:
+       case I_CHGRP:
+               path1 = make_absolute(path1, *pwd);
+               remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
+               for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+                       if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
+                               if (err_abort) {
+                                       err = -1;
+                                       break;
+                               } else
+                                       continue;
+                       }
+                       if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
+                               error("Can't get current ownership of "
+                                   "remote file \"%s\"", g.gl_pathv[i]);
+                               if (err_abort) {
+                                       err = -1;
+                                       break;
+                               } else
+                                       continue;
+                       }
+                       aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
+                       if (cmdnum == I_CHOWN) {
+                               printf("Changing owner on %s\n", g.gl_pathv[i]);
+                               aa->uid = n_arg;
+                       } else {
+                               printf("Changing group on %s\n", g.gl_pathv[i]);
+                               aa->gid = n_arg;
+                       }
+                       err = do_setstat(conn, g.gl_pathv[i], aa);
+                       if (err != 0 && err_abort)
+                               break;
+               }
+               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));
+                       err = -1;
+                       break;
+               }
+               printf("Local working directory: %s\n", path_buf);
+               break;
+       case I_QUIT:
+               /* Processed below */
+               break;
+       case I_HELP:
+               help();
+               break;
+       case I_VERSION:
+               printf("SFTP protocol version %u\n", sftp_proto_version(conn));
+               break;
+       case I_PROGRESS:
+               showprogress = !showprogress;
+               if (showprogress)
+                       printf("Progress meter enabled\n");
+               else
+                       printf("Progress meter disabled\n");
+               break;
+       default:
+               fatal("%d is not implemented", cmdnum);
+       }
+
+       if (g.gl_pathc)
+               globfree(&g);
+       if (path1)
+               xfree(path1);
+       if (path2)
+               xfree(path2);
+
+       /* If an unignored error occurs in batch mode we should abort. */
+       if (err_abort && err != 0)
+               return (-1);
+       else if (cmdnum == I_QUIT)
+               return (1);
+
+       return (0);
+}
+
+#ifdef USE_LIBEDIT
+static char *
+prompt(EditLine *el)
+{
+       return ("sftp> ");
+}
+
+/* Display entries in 'list' after skipping the first 'len' chars */
+static void
+complete_display(char **list, u_int len)
+{
+       u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
+       struct winsize ws;
+       char *tmp;
+
+       /* Count entries for sort and find longest */
+       for (y = 0; list[y]; y++) 
+               m = MAX(m, strlen(list[y]));
+
+       if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+               width = ws.ws_col;
+
+       m = m > len ? m - len : 0;
+       columns = width / (m + 2);
+       columns = MAX(columns, 1);
+       colspace = width / columns;
+       colspace = MIN(colspace, width);
+
+       printf("\n");
+       m = 1;
+       for (y = 0; list[y]; y++) {
+               llen = strlen(list[y]);
+               tmp = llen > len ? list[y] + len : "";
+               printf("%-*s", colspace, tmp);
+               if (m >= columns) {
+                       printf("\n");
+                       m = 1;
+               } else
+                       m++;
+       }
+       printf("\n");
+}
+
+/*
+ * Given a "list" of words that begin with a common prefix of "word",
+ * attempt to find an autocompletion to extends "word" by the next
+ * characters common to all entries in "list".
+ */
+static char *
+complete_ambiguous(const char *word, char **list, size_t count)
+{
+       if (word == NULL)
+               return NULL;
+
+       if (count > 0) {
+               u_int y, matchlen = strlen(list[0]);
+
+               /* Find length of common stem */
+               for (y = 1; list[y]; y++) {
+                       u_int x;
+
+                       for (x = 0; x < matchlen; x++) 
+                               if (list[0][x] != list[y][x]) 
+                                       break;
+
+                       matchlen = x;
+               }
+
+               if (matchlen > strlen(word)) {
+                       char *tmp = xstrdup(list[0]);
+
+                       tmp[matchlen] = '\0';
+                       return tmp;
+               }
+       } 
+
+       return xstrdup(word);
+}
+
+/* Autocomplete a sftp command */
+static int
+complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
+    int terminated)
+{
+       u_int y, count = 0, cmdlen, tmplen;
+       char *tmp, **list, argterm[3];
+       const LineInfo *lf;
+
+       list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
+
+       /* No command specified: display all available commands */
+       if (cmd == NULL) {
+               for (y = 0; cmds[y].c; y++)
+                       list[count++] = xstrdup(cmds[y].c);
+               
+               list[count] = NULL;
+               complete_display(list, 0);
+
+               for (y = 0; list[y] != NULL; y++)  
+                       xfree(list[y]); 
+               xfree(list);
+               return count;
+       }
+
+       /* Prepare subset of commands that start with "cmd" */
+       cmdlen = strlen(cmd);
+       for (y = 0; cmds[y].c; y++)  {
+               if (!strncasecmp(cmd, cmds[y].c, cmdlen)) 
+                       list[count++] = xstrdup(cmds[y].c);
+       }
+       list[count] = NULL;
+
+       if (count == 0)
+               return 0;
+
+       /* Complete ambigious command */
+       tmp = complete_ambiguous(cmd, list, count);
+       if (count > 1)
+               complete_display(list, 0);
+
+       for (y = 0; list[y]; y++)  
+               xfree(list[y]); 
+       xfree(list);
+
+       if (tmp != NULL) {
+               tmplen = strlen(tmp);
+               cmdlen = strlen(cmd);
+               /* If cmd may be extended then do so */
+               if (tmplen > cmdlen)
+                       if (el_insertstr(el, tmp + cmdlen) == -1)
+                               fatal("el_insertstr failed.");
+               lf = el_line(el);
+               /* Terminate argument cleanly */
+               if (count == 1) {
+                       y = 0;
+                       if (!terminated)
+                               argterm[y++] = quote;
+                       if (lastarg || *(lf->cursor) != ' ')
+                               argterm[y++] = ' ';
+                       argterm[y] = '\0';
+                       if (y > 0 && el_insertstr(el, argterm) == -1)
+                               fatal("el_insertstr failed.");
+               }
+               xfree(tmp);
+       }
+
+       return count;
+}
+
+/*
+ * Determine whether a particular sftp command's arguments (if any)
+ * represent local or remote files.
+ */
+static int
+complete_is_remote(char *cmd) {
+       int i;
+
+       if (cmd == NULL)
+               return -1;
+
+       for (i = 0; cmds[i].c; i++) {
+               if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) 
+                       return cmds[i].t;
+       }
+
+       return -1;
+}
+
+/* Autocomplete a filename "file" */
+static int
+complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
+    char *file, int remote, int lastarg, char quote, int terminated)
+{
+       glob_t g;
+       char *tmp, *tmp2, ins[3];
+       u_int i, hadglob, pwdlen, len, tmplen, filelen;
+       const LineInfo *lf;
+       
+       /* Glob from "file" location */
+       if (file == NULL)
+               tmp = xstrdup("*");
+       else
+               xasprintf(&tmp, "%s*", file);
+
+       memset(&g, 0, sizeof(g));
+       if (remote != LOCAL) {
+               tmp = make_absolute(tmp, remote_path);
+               remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
+       } else 
+               glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
+       
+       /* Determine length of pwd so we can trim completion display */
+       for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
+               /* Terminate counting on first unescaped glob metacharacter */
+               if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
+                       if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
+                               hadglob = 1;
+                       break;
+               }
+               if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
+                       tmplen++;
+               if (tmp[tmplen] == '/')
+                       pwdlen = tmplen + 1;    /* track last seen '/' */
+       }
+       xfree(tmp);
+
+       if (g.gl_matchc == 0) 
+               goto out;
+
+       if (g.gl_matchc > 1)
+               complete_display(g.gl_pathv, pwdlen);
+
+       tmp = NULL;
+       /* Don't try to extend globs */
+       if (file == NULL || hadglob)
+               goto out;
+
+       tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
+       tmp = path_strip(tmp2, remote_path);
+       xfree(tmp2);
+
+       if (tmp == NULL)
+               goto out;
+
+       tmplen = strlen(tmp);
+       filelen = strlen(file);
+
+       if (tmplen > filelen)  {
+               tmp2 = tmp + filelen;
+               len = strlen(tmp2); 
+               /* quote argument on way out */
+               for (i = 0; i < len; i++) {
+                       ins[0] = '\\';
+                       ins[1] = tmp2[i];
+                       ins[2] = '\0';
+                       switch (tmp2[i]) {
+                       case '\'':
+                       case '"':
+                       case '\\':
+                       case '\t':
+                       case '[':
+                       case ' ':
+                               if (quote == '\0' || tmp2[i] == quote) {
+                                       if (el_insertstr(el, ins) == -1)
+                                               fatal("el_insertstr "
+                                                   "failed.");
+                                       break;
+                               }
+                               /* FALLTHROUGH */
+                       default:
+                               if (el_insertstr(el, ins + 1) == -1)
+                                       fatal("el_insertstr failed.");
+                               break;
+                       }
+               }
+       }
+
+       lf = el_line(el);
+       if (g.gl_matchc == 1) {
+               i = 0;
+               if (!terminated)
+                       ins[i++] = quote;
+               if (*(lf->cursor - 1) != '/' &&
+                   (lastarg || *(lf->cursor) != ' '))
+                       ins[i++] = ' ';
+               ins[i] = '\0';
+               if (i > 0 && el_insertstr(el, ins) == -1)
+                       fatal("el_insertstr failed.");
+       }
+       xfree(tmp);
+
+ out:
+       globfree(&g);
+       return g.gl_matchc;
+}
+
+/* tab-completion hook function, called via libedit */
+static unsigned char
+complete(EditLine *el, int ch)
+{
+       char **argv, *line, quote; 
+       u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
+       const LineInfo *lf;
+       struct complete_ctx *complete_ctx;
+
+       lf = el_line(el);
+       if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
+               fatal("%s: el_get failed", __func__);
+
+       /* Figure out which argument the cursor points to */
+       cursor = lf->cursor - lf->buffer;
+       line = (char *)xmalloc(cursor + 1);
+       memcpy(line, lf->buffer, cursor);
+       line[cursor] = '\0';
+       argv = makeargv(line, &carg, 1, &quote, &terminated);
+       xfree(line);
+
+       /* Get all the arguments on the line */
+       len = lf->lastchar - lf->buffer;
+       line = (char *)xmalloc(len + 1);
+       memcpy(line, lf->buffer, len);
+       line[len] = '\0';
+       argv = makeargv(line, &argc, 1, NULL, NULL);
+
+       /* Ensure cursor is at EOL or a argument boundary */
+       if (line[cursor] != ' ' && line[cursor] != '\0' &&
+           line[cursor] != '\n') {
+               xfree(line);
+               return ret;
+       }
+
+       if (carg == 0) {
+               /* Show all available commands */
+               complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
+               ret = CC_REDISPLAY;
+       } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
+               /* Handle the command parsing */
+               if (complete_cmd_parse(el, argv[0], argc == carg,
+                   quote, terminated) != 0) 
+                       ret = CC_REDISPLAY;
+       } else if (carg >= 1) {
+               /* Handle file parsing */
+               int remote = complete_is_remote(argv[0]);
+               char *filematch = NULL;
+
+               if (carg > 1 && line[cursor-1] != ' ')
+                       filematch = argv[carg - 1];
+
+               if (remote != 0 &&
+                   complete_match(el, complete_ctx->conn,
+                   *complete_ctx->remote_pathp, filematch,
+                   remote, carg == argc, quote, terminated) != 0) 
+                       ret = CC_REDISPLAY;
+       }
+
+       xfree(line);    
+       return ret;
+}
+#endif /* USE_LIBEDIT */
+
+int
+interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
+{
+       char *remote_path;
+       char *dir = NULL;
+       char cmd[2048];
+       int err, interactive;
+       EditLine *el = NULL;
+#ifdef USE_LIBEDIT
+       History *hl = NULL;
+       HistEvent hev;
+       extern char *__progname;
+       struct complete_ctx complete_ctx;
+
+       if (!batchmode && isatty(STDIN_FILENO)) {
+               if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
+                       fatal("Couldn't initialise editline");
+               if ((hl = history_init()) == NULL)
+                       fatal("Couldn't initialise editline history");
+               history(hl, &hev, H_SETSIZE, 100);
+               el_set(el, EL_HIST, history, hl);
+
+               el_set(el, EL_PROMPT, prompt);
+               el_set(el, EL_EDITOR, "emacs");
+               el_set(el, EL_TERMINAL, NULL);
+               el_set(el, EL_SIGNAL, 1);
+               el_source(el, NULL);
+
+               /* Tab Completion */
+               el_set(el, EL_ADDFN, "ftp-complete", 
+                   "Context sensitive argument completion", complete);
+               complete_ctx.conn = conn;
+               complete_ctx.remote_pathp = &remote_path;
+               el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
+               el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
+       }
+#endif /* USE_LIBEDIT */
+
+       remote_path = do_realpath(conn, ".");
+       if (remote_path == NULL)
+               fatal("Need cwd");
+
+       if (file1 != NULL) {
+               dir = xstrdup(file1);
+               dir = make_absolute(dir, remote_path);
+
+               if (remote_is_dir(conn, dir) && file2 == NULL) {
+                       printf("Changing to: %s\n", dir);
+                       snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
+                       if (parse_dispatch_command(conn, cmd,
+                           &remote_path, 1) != 0) {
+                               xfree(dir);
+                               xfree(remote_path);
+                               xfree(conn);
+                               return (-1);
+                       }
+               } else {
+                       if (file2 == NULL)
+                               snprintf(cmd, sizeof cmd, "get %s", dir);
+                       else
+                               snprintf(cmd, sizeof cmd, "get %s %s", dir,
+                                   file2);
+
+                       err = parse_dispatch_command(conn, cmd,
+                           &remote_path, 1);
+                       xfree(dir);
+                       xfree(remote_path);
+                       xfree(conn);
+                       return (err);
+               }
+               xfree(dir);
+       }
+
+#if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF)
+       setvbuf(stdout, NULL, _IOLBF, 0);
+       setvbuf(infile, NULL, _IOLBF, 0);
+#else
+       setlinebuf(stdout);
+       setlinebuf(infile);
+#endif
+
+       interactive = !batchmode && isatty(STDIN_FILENO);
+       err = 0;
+       for (;;) {
+               char *cp;
+
+               signal(SIGINT, SIG_IGN);
+
+               if (el == NULL) {
+                       if (interactive)
+                               printf("sftp> ");
+                       if (fgets(cmd, sizeof(cmd), infile) == NULL) {
+                               if (interactive)
+                                       printf("\n");
+                               break;
+                       }
+                       if (!interactive) { /* Echo command */
+                               printf("sftp> %s", cmd);
+                               if (strlen(cmd) > 0 &&
+                                   cmd[strlen(cmd) - 1] != '\n')
+                                       printf("\n");
+                       }
+               } else {
+#ifdef USE_LIBEDIT
+                       const char *line;
+                       int count = 0;
+
+                       if ((line = el_gets(el, &count)) == NULL ||
+                           count <= 0) {
+                               printf("\n");
+                               break;
+                       }
+                       history(hl, &hev, H_ENTER, line);
+                       if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
+                               fprintf(stderr, "Error: input line too long\n");
+                               continue;
+                       }
+#endif /* USE_LIBEDIT */
+               }
+
+               cp = strrchr(cmd, '\n');
+               if (cp)
+                       *cp = '\0';
+
+               /* Handle user interrupts gracefully during commands */
+               interrupted = 0;
+               signal(SIGINT, cmd_interrupt);
+
+               err = parse_dispatch_command(conn, cmd, &remote_path,
+                   batchmode);
+               if (err != 0)
+                       break;
+       }
+       xfree(remote_path);
+       xfree(conn);
+
+#ifdef USE_LIBEDIT
+       if (el != NULL)
+               el_end(el);
+#endif /* USE_LIBEDIT */
+
+       /* err == 1 signifies normal "quit" exit */
+       return (err >= 0 ? 0 : -1);
+}
+
+static void
+connect_to_server(char *path, char **args, int *in, int *out)
+{
+       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);
+
+               /*
+                * The underlying ssh is in the same process group, so we must
+                * ignore SIGINT if we want to gracefully abort commands,
+                * otherwise the signal will make it to the ssh process and
+                * kill it too.  Contrawise, since sftp sends SIGTERMs to the
+                * underlying ssh, it must *not* ignore that signal.
+                */
+               signal(SIGINT, SIG_IGN);
+               signal(SIGTERM, SIG_DFL);
+               execvp(path, args);
+               fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
+               _exit(1);
+       }
+
+       signal(SIGTERM, killchild);
+       signal(SIGINT, killchild);
+       signal(SIGHUP, killchild);
+       close(c_in);
+       close(c_out);
+}
+
+static void
+usage(void)
+{
+       extern char *__progname;
+
+       fprintf(stderr,
+           "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
+           "          [-D sftp_server_path] [-F ssh_config] "
+           "[-i identity_file] [-l limit]\n"
+           "          [-o ssh_option] [-P port] [-R num_requests] "
+           "[-S program]\n"
+           "          [-s subsystem | sftp_server] host\n"
+           "       %s [user@]host[:file ...]\n"
+           "       %s [user@]host[:dir[/]]\n"
+           "       %s -b batchfile [user@]host\n",
+           __progname, __progname, __progname, __progname);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int in, out, ch, err;
+       char *host = NULL, *userhost, *cp, *file2 = NULL;
+       int debug_level = 0, sshver = 2;
+       char *file1 = NULL, *sftp_server = NULL;
+       char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
+       const char *errstr;
+       LogLevel ll = SYSLOG_LEVEL_INFO;
+       arglist args;
+       extern int optind;
+       extern char *optarg;
+       struct sftp_conn *conn;
+       size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
+       size_t num_requests = DEFAULT_NUM_REQUESTS;
+       long long limit_kbps = 0;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       __progname = ssh_get_progname(argv[0]);
+       memset(&args, '\0', sizeof(args));
+       args.list = NULL;
+       addargs(&args, "%s", ssh_program);
+       addargs(&args, "-oForwardX11 no");
+       addargs(&args, "-oForwardAgent no");
+       addargs(&args, "-oPermitLocalCommand no");
+       addargs(&args, "-oClearAllForwardings yes");
+
+       ll = SYSLOG_LEVEL_INFO;
+       infile = stdin;
+
+       while ((ch = getopt(argc, argv,
+           "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
+               switch (ch) {
+               /* Passed through to ssh(1) */
+               case '4':
+               case '6':
+               case 'C':
+                       addargs(&args, "-%c", ch);
+                       break;
+               /* Passed through to ssh(1) with argument */
+               case 'F':
+               case 'c':
+               case 'i':
+               case 'o':
+                       addargs(&args, "-%c", ch);
+                       addargs(&args, "%s", optarg);
+                       break;
+               case 'q':
+                       showprogress = 0;
+                       addargs(&args, "-%c", ch);
+                       break;
+               case 'P':
+                       addargs(&args, "-oPort %s", optarg);
+                       break;
+               case 'v':
+                       if (debug_level < 3) {
+                               addargs(&args, "-v");
+                               ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
+                       }
+                       debug_level++;
+                       break;
+               case '1':
+                       sshver = 1;
+                       if (sftp_server == NULL)
+                               sftp_server = _PATH_SFTP_SERVER;
+                       break;
+               case '2':
+                       sshver = 2;
+                       break;
+               case 'B':
+                       copy_buffer_len = strtol(optarg, &cp, 10);
+                       if (copy_buffer_len == 0 || *cp != '\0')
+                               fatal("Invalid buffer size \"%s\"", optarg);
+                       break;
+               case 'b':
+                       if (batchmode)
+                               fatal("Batch file already specified.");
+
+                       /* Allow "-" as stdin */
+                       if (strcmp(optarg, "-") != 0 &&
+                           (infile = fopen(optarg, "r")) == NULL)
+                               fatal("%s (%s).", strerror(errno), optarg);
+                       showprogress = 0;
+                       batchmode = 1;
+                       addargs(&args, "-obatchmode yes");
+                       break;
+               case 'p':
+                       global_pflag = 1;
+                       break;
+               case 'D':
+                       sftp_direct = optarg;
+                       break;
+               case 'l':
+                       limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
+                           &errstr);
+                       if (errstr != NULL)
+                               usage();
+                       limit_kbps *= 1024; /* kbps */
+                       break;
+               case 'r':
+                       global_rflag = 1;
+                       break;
+               case 'R':
+                       num_requests = strtol(optarg, &cp, 10);
+                       if (num_requests == 0 || *cp != '\0')
+                               fatal("Invalid number of requests \"%s\"",
+                                   optarg);
+                       break;
+               case 's':
+                       sftp_server = optarg;
+                       break;
+               case 'S':
+                       ssh_program = optarg;
+                       replacearg(&args, 0, "%s", ssh_program);
+                       break;
+               case 'h':
+               default:
+                       usage();
+               }
+       }
+
+       if (!isatty(STDERR_FILENO))
+               showprogress = 0;
+
+       log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
+
+       if (sftp_direct == NULL) {
+               if (optind == argc || argc > (optind + 2))
+                       usage();
+
+               userhost = xstrdup(argv[optind]);
+               file2 = argv[optind+1];
+
+               if ((host = strrchr(userhost, '@')) == NULL)
+                       host = userhost;
+               else {
+                       *host++ = '\0';
+                       if (!userhost[0]) {
+                               fprintf(stderr, "Missing username\n");
+                               usage();
+                       }
+                       addargs(&args, "-l");
+                       addargs(&args, "%s", userhost);
+               }
+
+               if ((cp = colon(host)) != NULL) {
+                       *cp++ = '\0';
+                       file1 = cp;
+               }
+
+               host = cleanhostname(host);
+               if (!*host) {
+                       fprintf(stderr, "Missing hostname\n");
+                       usage();
+               }
+
+               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, "--");
+               addargs(&args, "%s", host);
+               addargs(&args, "%s", (sftp_server != NULL ?
+                   sftp_server : "sftp"));
+
+               connect_to_server(ssh_program, args.list, &in, &out);
+       } else {
+               args.list = NULL;
+               addargs(&args, "sftp-server");
+
+               connect_to_server(sftp_direct, args.list, &in, &out);
+       }
+       freeargs(&args);
+
+       conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
+       if (conn == NULL)
+               fatal("Couldn't initialise connection to server");
+
+       if (!batchmode) {
+               if (sftp_direct == NULL)
+                       fprintf(stderr, "Connected to %s.\n", host);
+               else
+                       fprintf(stderr, "Attached to %s.\n", sftp_direct);
+       }
+
+       err = interactive_loop(conn, file1, file2);
+
+#if !defined(USE_PIPES)
+       shutdown(in, SHUT_RDWR);
+       shutdown(out, SHUT_RDWR);
+#endif
+
+       close(in);
+       close(out);
+       if (batchmode)
+               fclose(infile);
+
+       while (waitpid(sshpid, NULL, 0) == -1)
+               if (errno != EINTR)
+                       fatal("Couldn't wait for ssh process: %s",
+                           strerror(errno));
+
+       exit(err == 0 ? 0 : 1);
+}
diff --git a/sftp.h b/sftp.h
new file mode 100644 (file)
index 0000000..2bde8bb
--- /dev/null
+++ b/sftp.h
@@ -0,0 +1,101 @@
+/* $OpenBSD: sftp.h,v 1.9 2008/06/13 00:12:02 dtucker 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_STAT_VERSION_0                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
+
+/* statvfs@openssh.com f_flag flags */
+#define SSH2_FXE_STATVFS_ST_RDONLY     0x00000001
+#define SSH2_FXE_STATVFS_ST_NOSUID     0x00000002
+
+/* status messages */
+#define SSH2_FX_OK                     0
+#define SSH2_FX_EOF                    1
+#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
+
+struct passwd;
+
+int    sftp_server_main(int, char **, struct passwd *);
+void   sftp_server_cleanup_exit(int) __attribute__((noreturn));
diff --git a/ssh-add.0 b/ssh-add.0
new file mode 100644 (file)
index 0000000..d915128
--- /dev/null
+++ b/ssh-add.0
@@ -0,0 +1,115 @@
+SSH-ADD(1)                 OpenBSD Reference Manual                 SSH-ADD(1)
+
+NAME
+     ssh-add - adds private key identities to the authentication agent
+
+SYNOPSIS
+     ssh-add [-cDdLlXx] [-t life] [file ...]
+     ssh-add -s pkcs11
+     ssh-add -e pkcs11
+
+DESCRIPTION
+     ssh-add adds private key identities to the authentication agent,
+     ssh-agent(1).  When run without arguments, it adds the files
+     ~/.ssh/id_rsa, ~/.ssh/id_dsa, ~/.ssh/id_ecdsa and ~/.ssh/identity.  After
+     loading a private key, ssh-add will try to load corresponding certificate
+     information from the filename obtained by appending -cert.pub to the name
+     of the private key file.  Alternative file names can be given on the
+     command line.
+
+     If any file requires a passphrase, ssh-add asks for the passphrase from
+     the user.  The passphrase is read from the user's tty.  ssh-add retries
+     the last passphrase if multiple identity files are given.
+
+     The authentication agent must be running and the SSH_AUTH_SOCK
+     environment variable must contain the name of its socket for ssh-add to
+     work.
+
+     The options are as follows:
+
+     -c      Indicates that added identities should be subject to confirmation
+             before being used for authentication.  Confirmation is performed
+             by the SSH_ASKPASS program mentioned below.  Successful
+             confirmation is signaled by a zero exit status from the
+             SSH_ASKPASS program, rather than text entered into the requester.
+
+     -D      Deletes all identities from the agent.
+
+     -d      Instead of adding identities, removes identities from the agent.
+             If ssh-add has been run without arguments, the keys for the
+             default identities will be removed.  Otherwise, the argument list
+             will be interpreted as a list of paths to public key files and
+             matching keys will be removed from the agent.  If no public key
+             is found at a given path, ssh-add will append .pub and retry.
+
+     -e pkcs11
+             Remove keys provided by the PKCS#11 shared library pkcs11.
+
+     -L      Lists public key parameters of all identities currently
+             represented by the agent.
+
+     -l      Lists fingerprints of all identities currently represented by the
+             agent.
+
+     -s pkcs11
+             Add keys provided by the PKCS#11 shared library pkcs11.
+
+     -t life
+             Set a maximum lifetime when adding identities to an agent.  The
+             lifetime may be specified in seconds or in a time format
+             specified in sshd_config(5).
+
+     -X      Unlock the agent.
+
+     -x      Lock the agent with a password.
+
+ENVIRONMENT
+     DISPLAY and SSH_ASKPASS
+             If ssh-add needs a passphrase, it will read the passphrase from
+             the current terminal if it was run from a terminal.  If ssh-add
+             does not have a terminal associated with it but DISPLAY and
+             SSH_ASKPASS are set, it will execute the program specified by
+             SSH_ASKPASS and open an X11 window to read the passphrase.  This
+             is particularly useful when calling ssh-add from a .xsession or
+             related script.  (Note that on some machines it may be necessary
+             to redirect the input from /dev/null to make this work.)
+
+     SSH_AUTH_SOCK
+             Identifies the path of a UNIX-domain socket used to communicate
+             with the agent.
+
+FILES
+     ~/.ssh/identity
+             Contains the protocol version 1 RSA authentication identity of
+             the user.
+
+     ~/.ssh/id_dsa
+             Contains the protocol version 2 DSA authentication identity of
+             the user.
+
+     ~/.ssh/id_ecdsa
+             Contains the protocol version 2 ECDSA authentication identity of
+             the user.
+
+     ~/.ssh/id_rsa
+             Contains the protocol version 2 RSA authentication identity of
+             the user.
+
+     Identity files should not be readable by anyone but the user.  Note that
+     ssh-add ignores identity files if they are accessible by others.
+
+EXIT STATUS
+     Exit status is 0 on success, 1 if the specified command fails, and 2 if
+     ssh-add is unable to contact the authentication agent.
+
+SEE ALSO
+     ssh(1), ssh-agent(1), ssh-keygen(1), sshd(8)
+
+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.
+
+OpenBSD 4.9                    October 28, 2010                    OpenBSD 4.9
diff --git a/ssh-add.1 b/ssh-add.1
new file mode 100644 (file)
index 0000000..fd48ff9
--- /dev/null
+++ b/ssh-add.1
@@ -0,0 +1,195 @@
+.\"    $OpenBSD: ssh-add.1,v 1.55 2010/10/28 18:33:28 jmc 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 $Mdocdate: October 28 2010 $
+.Dt SSH-ADD 1
+.Os
+.Sh NAME
+.Nm ssh-add
+.Nd adds private key identities to the authentication agent
+.Sh SYNOPSIS
+.Nm ssh-add
+.Op Fl cDdLlXx
+.Op Fl t Ar life
+.Op Ar
+.Nm ssh-add
+.Fl s Ar pkcs11
+.Nm ssh-add
+.Fl e Ar pkcs11
+.Sh DESCRIPTION
+.Nm
+adds private key identities to the authentication agent,
+.Xr ssh-agent 1 .
+When run without arguments, it adds the files
+.Pa ~/.ssh/id_rsa ,
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/id_ecdsa
+and
+.Pa ~/.ssh/identity .
+After loading a private key,
+.Nm
+will try to load corresponding certificate information from the
+filename obtained by appending
+.Pa -cert.pub
+to the name of the private key file.
+Alternative file names can be given on the command line.
+.Pp
+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 the
+.Ev SSH_AUTH_SOCK
+environment variable must contain the name of its socket for
+.Nm
+to work.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c
+Indicates that added identities should be subject to confirmation before
+being used for authentication.
+Confirmation is performed by the
+.Ev SSH_ASKPASS
+program mentioned below.
+Successful confirmation is signaled by a zero exit status from the
+.Ev SSH_ASKPASS
+program, rather than text entered into the requester.
+.It Fl D
+Deletes all identities from the agent.
+.It Fl d
+Instead of adding identities, removes identities from the agent.
+If
+.Nm
+has been run without arguments, the keys for the default identities will
+be removed.
+Otherwise, the argument list will be interpreted as a list of paths to
+public key files and matching keys will be removed from the agent.
+If no public key is found at a given path,
+.Nm
+will append
+.Pa .pub
+and retry.
+.It Fl e Ar pkcs11
+Remove keys provided by the PKCS#11 shared library
+.Ar pkcs11 .
+.It Fl L
+Lists public key parameters of all identities currently represented
+by the agent.
+.It Fl l
+Lists fingerprints of all identities currently represented by the agent.
+.It Fl s Ar pkcs11
+Add keys provided by the PKCS#11 shared library
+.Ar pkcs11 .
+.It Fl t Ar life
+Set a maximum lifetime when adding identities to an agent.
+The lifetime may be specified in seconds or in a time format
+specified in
+.Xr sshd_config 5 .
+.It Fl X
+Unlock the agent.
+.It Fl x
+Lock the agent with a password.
+.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.)
+.It Ev SSH_AUTH_SOCK
+Identifies the path of a
+.Ux Ns -domain
+socket used to communicate with the agent.
+.El
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa ~/.ssh/identity
+Contains the protocol version 1 RSA authentication identity of the user.
+.It Pa ~/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+.It Pa ~/.ssh/id_ecdsa
+Contains the protocol version 2 ECDSA authentication identity of the user.
+.It Pa ~/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+.El
+.Pp
+Identity files should not be readable by anyone but the user.
+Note that
+.Nm
+ignores identity files if they are accessible by others.
+.Sh EXIT STATUS
+Exit status is 0 on success, 1 if the specified command fails,
+and 2 if
+.Nm
+is unable to contact the authentication agent.
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
+.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.
diff --git a/ssh-add.c b/ssh-add.c
new file mode 100644 (file)
index 0000000..125d664
--- /dev/null
+++ b/ssh-add.c
@@ -0,0 +1,472 @@
+/* $OpenBSD: ssh-add.c,v 1.100 2010/08/31 12:33:38 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <openssl/evp.h>
+#include "openbsd-compat/openssl-compat.h"
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "rsa.h"
+#include "log.h"
+#include "key.h"
+#include "buffer.h"
+#include "authfd.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "misc.h"
+
+/* argv0 */
+extern char *__progname;
+
+/* Default files to add */
+static char *default_files[] = {
+       _PATH_SSH_CLIENT_ID_RSA,
+       _PATH_SSH_CLIENT_ID_DSA,
+#ifdef OPENSSL_HAS_ECC
+       _PATH_SSH_CLIENT_ID_ECDSA,
+#endif
+       _PATH_SSH_CLIENT_IDENTITY,
+       NULL
+};
+
+/* Default lifetime (0 == forever) */
+static int lifetime = 0;
+
+/* User has to confirm key use */
+static int confirm = 0;
+
+/* 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)
+{
+       Key *private, *cert;
+       char *comment = NULL;
+       char msg[1024], *certpath;
+       int fd, perms_ok, ret = -1;
+
+       if ((fd = open(filename, O_RDONLY)) < 0) {
+               perror(filename);
+               return -1;
+       }
+
+       /*
+        * Since we'll try to load a keyfile multiple times, permission errors
+        * will occur multiple times, so check perms first and bail if wrong.
+        */
+       perms_ok = key_perm_ok(fd, filename);
+       close(fd);
+       if (!perms_ok)
+               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();
+                       snprintf(msg, sizeof msg,
+                           "Bad passphrase, try again for %.200s: ", comment);
+               }
+       }
+
+       if (ssh_add_identity_constrained(ac, private, comment, lifetime,
+           confirm)) {
+               fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
+               ret = 0;
+               if (lifetime != 0)
+                       fprintf(stderr,
+                           "Lifetime set to %d seconds\n", lifetime);
+               if (confirm != 0)
+                       fprintf(stderr,
+                           "The user must confirm each use of the key\n");
+       } else {
+               fprintf(stderr, "Could not add identity: %s\n", filename);
+       }
+
+
+       /* Now try to add the certificate flavour too */
+       xasprintf(&certpath, "%s-cert.pub", filename);
+       if ((cert = key_load_public(certpath, NULL)) == NULL)
+               goto out;
+
+       if (!key_equal_public(cert, private)) {
+               error("Certificate %s does not match private key %s",
+                   certpath, filename);
+               key_free(cert);
+               goto out;
+       } 
+
+       /* Graft with private bits */
+       if (key_to_certified(private, key_cert_is_legacy(cert)) != 0) {
+               error("%s: key_to_certified failed", __func__);
+               key_free(cert);
+               goto out;
+       }
+       key_cert_copy(cert, private);
+       key_free(cert);
+
+       if (!ssh_add_identity_constrained(ac, private, comment,
+           lifetime, confirm)) {
+               error("Certificate %s (%s) add failed", certpath,
+                   private->cert->key_id);
+       }
+       fprintf(stderr, "Certificate added: %s (%s)\n", certpath,
+           private->cert->key_id);
+       if (lifetime != 0)
+               fprintf(stderr, "Lifetime set to %d seconds\n", lifetime);
+       if (confirm != 0)
+               fprintf(stderr, "The user must confirm each use of the key\n");
+ out:
+       xfree(certpath);
+       xfree(comment);
+       key_free(private);
+
+       return ret;
+}
+
+static int
+update_card(AuthenticationConnection *ac, int add, const char *id)
+{
+       char *pin;
+       int ret = -1;
+
+       pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN);
+       if (pin == NULL)
+               return -1;
+
+       if (ssh_update_card(ac, add, id, pin, lifetime, confirm)) {
+               fprintf(stderr, "Card %s: %s\n",
+                   add ? "added" : "removed", id);
+               ret = 0;
+       } else {
+               fprintf(stderr, "Could not %s card: %s\n",
+                   add ? "add" : "remove", id);
+               ret = -1;
+       }
+       xfree(pin);
+       return ret;
+}
+
+static int
+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");
+               return -1;
+       }
+       return 0;
+}
+
+static int
+lock_agent(AuthenticationConnection *ac, int lock)
+{
+       char prompt[100], *p1, *p2;
+       int passok = 1, ret = -1;
+
+       strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
+       p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
+       if (lock) {
+               strlcpy(prompt, "Again: ", sizeof prompt);
+               p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
+               if (strcmp(p1, p2) != 0) {
+                       fprintf(stderr, "Passwords do not match.\n");
+                       passok = 0;
+               }
+               memset(p2, 0, strlen(p2));
+               xfree(p2);
+       }
+       if (passok && ssh_lock_agent(ac, lock, p1)) {
+               fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
+               ret = 0;
+       } else
+               fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un");
+       memset(p1, 0, strlen(p1));
+       xfree(p1);
+       return (ret);
+}
+
+static int
+do_file(AuthenticationConnection *ac, int deleting, char *file)
+{
+       if (deleting) {
+               if (delete_file(ac, file) == -1)
+                       return -1;
+       } else {
+               if (add_file(ac, file) == -1)
+                       return -1;
+       }
+       return 0;
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "usage: %s [options] [file ...]\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");
+       fprintf(stderr, "  -x          Lock agent.\n");
+       fprintf(stderr, "  -X          Unlock agent.\n");
+       fprintf(stderr, "  -t life     Set lifetime (in seconds) when adding identities.\n");
+       fprintf(stderr, "  -c          Require confirmation to sign using identities\n");
+       fprintf(stderr, "  -s pkcs11   Add keys from PKCS#11 provider.\n");
+       fprintf(stderr, "  -e pkcs11   Remove keys provided by PKCS#11 provider.\n");
+}
+
+int
+main(int argc, char **argv)
+{
+       extern char *optarg;
+       extern int optind;
+       AuthenticationConnection *ac = NULL;
+       char *pkcs11provider = NULL;
+       int i, ch, deleting = 0, ret = 0;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       __progname = ssh_get_progname(argv[0]);
+       init_rng();
+       seed_rng();
+
+       OpenSSL_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(2);
+       }
+       while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) {
+               switch (ch) {
+               case 'l':
+               case 'L':
+                       if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
+                               ret = 1;
+                       goto done;
+               case 'x':
+               case 'X':
+                       if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
+                               ret = 1;
+                       goto done;
+               case 'c':
+                       confirm = 1;
+                       break;
+               case 'd':
+                       deleting = 1;
+                       break;
+               case 'D':
+                       if (delete_all(ac) == -1)
+                               ret = 1;
+                       goto done;
+               case 's':
+                       pkcs11provider = optarg;
+                       break;
+               case 'e':
+                       deleting = 1;
+                       pkcs11provider = optarg;
+                       break;
+               case 't':
+                       if ((lifetime = convtime(optarg)) == -1) {
+                               fprintf(stderr, "Invalid lifetime\n");
+                               ret = 1;
+                               goto done;
+                       }
+                       break;
+               default:
+                       usage();
+                       ret = 1;
+                       goto done;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+       if (pkcs11provider != NULL) {
+               if (update_card(ac, !deleting, pkcs11provider) == -1)
+                       ret = 1;
+               goto done;
+       }
+       if (argc == 0) {
+               char buf[MAXPATHLEN];
+               struct passwd *pw;
+               struct stat st;
+               int count = 0;
+
+               if ((pw = getpwuid(getuid())) == NULL) {
+                       fprintf(stderr, "No user found with uid %u\n",
+                           (u_int)getuid());
+                       ret = 1;
+                       goto done;
+               }
+
+               for (i = 0; default_files[i]; i++) {
+                       snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
+                           default_files[i]);
+                       if (stat(buf, &st) < 0)
+                               continue;
+                       if (do_file(ac, deleting, buf) == -1)
+                               ret = 1;
+                       else
+                               count++;
+               }
+               if (count == 0)
+                       ret = 1;
+       } else {
+               for (i = 0; i < argc; i++) {
+                       if (do_file(ac, deleting, argv[i]) == -1)
+                               ret = 1;
+               }
+       }
+       clear_pass();
+
+done:
+       ssh_close_authentication_connection(ac);
+       return ret;
+}
diff --git a/ssh-agent.0 b/ssh-agent.0
new file mode 100644 (file)
index 0000000..c3de21b
--- /dev/null
@@ -0,0 +1,123 @@
+SSH-AGENT(1)               OpenBSD Reference Manual               SSH-AGENT(1)
+
+NAME
+     ssh-agent - authentication agent
+
+SYNOPSIS
+     ssh-agent [-c | -s] [-d] [-a bind_address] [-t life] [command [arg ...]]
+     ssh-agent [-c | -s] -k
+
+DESCRIPTION
+     ssh-agent is a program to hold private keys used for public key
+     authentication (RSA, DSA, ECDSA).  The idea is that ssh-agent 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 ssh(1).
+
+     The options are as follows:
+
+     -a bind_address
+             Bind the agent to the UNIX-domain socket bind_address.  The
+             default is $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>.
+
+     -c      Generate C-shell commands on stdout.  This is the default if
+             SHELL looks like it's a csh style of shell.
+
+     -d      Debug mode.  When this option is specified ssh-agent will not
+             fork.
+
+     -k      Kill the current agent (given by the SSH_AGENT_PID environment
+             variable).
+
+     -s      Generate Bourne shell commands on stdout.  This is the default if
+             SHELL does not look like it's a csh style of shell.
+
+     -t life
+             Set a default value for the maximum lifetime of identities added
+             to the agent.  The lifetime may be specified in seconds or in a
+             time format specified in sshd_config(5).  A lifetime specified
+             for an identity with ssh-add(1) overrides this value.  Without
+             this option the default maximum lifetime is forever.
+
+     If a commandline is given, this is executed as a subprocess of the agent.
+     When the command dies, so does the agent.
+
+     The agent initially does not have any private keys.  Keys are added using
+     ssh-add(1).  When executed without arguments, ssh-add(1) adds the files
+     ~/.ssh/id_rsa, ~/.ssh/id_dsa, ~/.ssh/id_ecdsa and ~/.ssh/identity.  If
+     the identity has a passphrase, ssh-add(1) asks for the passphrase on the
+     terminal if it has one or from a small X11 program if running under X11.
+     If neither of these is the case then the authentication will fail.  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.
+     ssh-add -l displays the identities currently held by the agent.
+
+     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.
+
+     There are two main ways to get an agent set up: The first is that the
+     agent starts a new subcommand into which some environment variables are
+     exported, eg ssh-agent xterm &.  The second is that the agent prints the
+     needed shell commands (either sh(1) or csh(1) syntax can be generated)
+     which can be evaluated in the calling shell, eg eval `ssh-agent -s` for
+     Bourne-type shells such as sh(1) or ksh(1) and eval `ssh-agent -c` for
+     csh(1) and derivatives.
+
+     Later ssh(1) looks at these variables and uses them to establish a
+     connection to the agent.
+
+     The agent will never send a private key over its request channel.
+     Instead, operations that require a private key will be performed by the
+     agent, and the result will be returned to the requester.  This way,
+     private keys are not exposed to clients using the agent.
+
+     A UNIX-domain socket is created and the name of this socket is stored in
+     the 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.
+
+     The SSH_AGENT_PID environment variable holds the agent's process ID.
+
+     The agent exits automatically when the command given on the command line
+     terminates.
+
+FILES
+     ~/.ssh/identity
+             Contains the protocol version 1 RSA authentication identity of
+             the user.
+
+     ~/.ssh/id_dsa
+             Contains the protocol version 2 DSA authentication identity of
+             the user.
+
+     ~/.ssh/id_ecdsa
+             Contains the protocol version 2 ECDSA authentication identity of
+             the user.
+
+     ~/.ssh/id_rsa
+             Contains the protocol version 2 RSA authentication identity of
+             the user.
+
+     $TMPDIR/ssh-XXXXXXXXXX/agent.<ppid>
+             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.
+
+SEE ALSO
+     ssh(1), ssh-add(1), ssh-keygen(1), sshd(8)
+
+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.
+
+OpenBSD 4.9                    November 21, 2010                   OpenBSD 4.9
diff --git a/ssh-agent.1 b/ssh-agent.1
new file mode 100644 (file)
index 0000000..bb801c9
--- /dev/null
@@ -0,0 +1,214 @@
+.\" $OpenBSD: ssh-agent.1,v 1.53 2010/11/21 01:01:13 djm 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 $Mdocdate: November 21 2010 $
+.Dt SSH-AGENT 1
+.Os
+.Sh NAME
+.Nm ssh-agent
+.Nd authentication agent
+.Sh SYNOPSIS
+.Nm ssh-agent
+.Op Fl c | s
+.Op Fl d
+.Op Fl a Ar bind_address
+.Op Fl t Ar life
+.Op Ar command Op Ar arg ...
+.Nm ssh-agent
+.Op Fl c | s
+.Fl k
+.Sh DESCRIPTION
+.Nm
+is a program to hold private keys used for public key authentication
+(RSA, DSA, ECDSA).
+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 a Ar bind_address
+Bind the agent to the
+.Ux Ns -domain
+socket
+.Ar bind_address .
+The default is
+.Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt .
+.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 d
+Debug mode.
+When this option is specified
+.Nm
+will not fork.
+.It Fl k
+Kill the current agent (given by the
+.Ev SSH_AGENT_PID
+environment variable).
+.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 t Ar life
+Set a default value for the maximum lifetime of identities added to the agent.
+The lifetime may be specified in seconds or in a time format specified in
+.Xr sshd_config 5 .
+A lifetime specified for an identity with
+.Xr ssh-add 1
+overrides this value.
+Without this option the default maximum lifetime is forever.
+.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 files
+.Pa ~/.ssh/id_rsa ,
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/id_ecdsa
+and
+.Pa ~/.ssh/identity .
+If the identity has a passphrase,
+.Xr ssh-add 1
+asks for the passphrase on the terminal if it has one or from a small X11
+program if running under X11.
+If neither of these is the case then the authentication will fail.
+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 set up:
+The first is that the agent starts a new subcommand into which some environment
+variables are exported, eg
+.Cm ssh-agent xterm & .
+The second is that the agent prints the needed shell commands (either
+.Xr sh 1
+or
+.Xr csh 1
+syntax can be generated) which can be evaluated in the calling shell, eg
+.Cm eval `ssh-agent -s`
+for Bourne-type shells such as
+.Xr sh 1
+or
+.Xr ksh 1
+and
+.Cm eval `ssh-agent -c`
+for
+.Xr csh 1
+and derivatives.
+.Pp
+Later
+.Xr ssh 1
+looks at these variables and uses them to establish a connection to the agent.
+.Pp
+The agent will never send a private key over its request channel.
+Instead, operations that require a private key will be performed
+by the agent, and the result will be returned to the requester.
+This way, private keys are not exposed to clients using the agent.
+.Pp
+A
+.Ux Ns -domain
+socket is created 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 process ID.
+.Pp
+The agent exits automatically when the command given on the command
+line terminates.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa ~/.ssh/identity
+Contains the protocol version 1 RSA authentication identity of the user.
+.It Pa ~/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+.It Pa ~/.ssh/id_ecdsa
+Contains the protocol version 2 ECDSA authentication identity of the user.
+.It Pa ~/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+.It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
+.Ux Ns -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 SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
+.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.
diff --git a/ssh-agent.c b/ssh-agent.c
new file mode 100644 (file)
index 0000000..afba413
--- /dev/null
@@ -0,0 +1,1370 @@
+/* $OpenBSD: ssh-agent.c,v 1.171 2010/11/21 01:01:13 djm 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"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+#include "openbsd-compat/sys-queue.h"
+
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+#include "openbsd-compat/openssl-compat.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "key.h"
+#include "authfd.h"
+#include "compat.h"
+#include "log.h"
+#include "misc.h"
+
+#ifdef ENABLE_PKCS11
+#include "ssh-pkcs11.h"
+#endif
+
+#if defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h> /* For prctl() and PR_SET_DUMPABLE */
+#endif
+
+typedef enum {
+       AUTH_UNUSED,
+       AUTH_SOCKET,
+       AUTH_CONNECTION
+} sock_type;
+
+typedef struct {
+       int fd;
+       sock_type type;
+       Buffer input;
+       Buffer output;
+       Buffer request;
+} SocketEntry;
+
+u_int sockets_alloc = 0;
+SocketEntry *sockets = NULL;
+
+typedef struct identity {
+       TAILQ_ENTRY(identity) next;
+       Key *key;
+       char *comment;
+       char *provider;
+       u_int death;
+       u_int confirm;
+} Identity;
+
+typedef struct {
+       int nentries;
+       TAILQ_HEAD(idqueue, identity) idlist;
+} 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;
+u_int parent_alive_interval = 0;
+
+/* pathname and directory for AUTH_SOCKET */
+char socket_name[MAXPATHLEN];
+char socket_dir[MAXPATHLEN];
+
+/* locking */
+int locked = 0;
+char *lock_passwd = NULL;
+
+extern char *__progname;
+
+/* Default lifetime (0 == forever) */
+static int lifetime = 0;
+
+static void
+close_socket(SocketEntry *e)
+{
+       close(e->fd);
+       e->fd = -1;
+       e->type = AUTH_UNUSED;
+       buffer_free(&e->input);
+       buffer_free(&e->output);
+       buffer_free(&e->request);
+}
+
+static void
+idtab_init(void)
+{
+       int i;
+
+       for (i = 0; i <=2; i++) {
+               TAILQ_INIT(&idtable[i].idlist);
+               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];
+}
+
+static void
+free_identity(Identity *id)
+{
+       key_free(id->key);
+       if (id->provider != NULL)
+               xfree(id->provider);
+       xfree(id->comment);
+       xfree(id);
+}
+
+/* return matching private key for given public key */
+static Identity *
+lookup_identity(Key *key, int version)
+{
+       Identity *id;
+
+       Idtab *tab = idtab_lookup(version);
+       TAILQ_FOREACH(id, &tab->idlist, next) {
+               if (key_equal(key, id->key))
+                       return (id);
+       }
+       return (NULL);
+}
+
+/* Check confirmation of keysign request */
+static int
+confirm_key(Identity *id)
+{
+       char *p;
+       int ret = -1;
+
+       p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+       if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
+           id->comment, p))
+               ret = 0;
+       xfree(p);
+
+       return (ret);
+}
+
+/* send list of supported public keys to 'client' */
+static void
+process_request_identities(SocketEntry *e, int version)
+{
+       Idtab *tab = idtab_lookup(version);
+       Identity *id;
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, (version == 1) ?
+           SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+       buffer_put_int(&msg, tab->nentries);
+       TAILQ_FOREACH(id, &tab->idlist, next) {
+               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)
+{
+       u_char buf[32], mdbuf[16], session_id[16];
+       u_int response_type;
+       BIGNUM *challenge;
+       Identity *id;
+       int i, len;
+       Buffer msg;
+       MD5_CTX md;
+       Key *key;
+
+       buffer_init(&msg);
+       key = key_new(KEY_RSA1);
+       if ((challenge = BN_new()) == NULL)
+               fatal("process_authentication_challenge1: BN_new failed");
+
+       (void) buffer_get_int(&e->request);                     /* ignored */
+       buffer_get_bignum(&e->request, key->rsa->e);
+       buffer_get_bignum(&e->request, key->rsa->n);
+       buffer_get_bignum(&e->request, challenge);
+
+       /* Only protocol 1.1 is supported */
+       if (buffer_len(&e->request) == 0)
+               goto failure;
+       buffer_get(&e->request, session_id, 16);
+       response_type = buffer_get_int(&e->request);
+       if (response_type != 1)
+               goto failure;
+
+       id = lookup_identity(key, 1);
+       if (id != NULL && (!id->confirm || confirm_key(id) == 0)) {
+               Key *private = id->key;
+               /* 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) {
+                       logit("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)
+{
+       u_char *blob, *data, *signature = NULL;
+       u_int blen, dlen, slen = 0;
+       extern int datafellows;
+       int odatafellows;
+       int ok = -1, flags;
+       Buffer msg;
+       Key *key;
+
+       datafellows = 0;
+
+       blob = buffer_get_string(&e->request, &blen);
+       data = buffer_get_string(&e->request, &dlen);
+
+       flags = buffer_get_int(&e->request);
+       odatafellows = datafellows;
+       if (flags & SSH_AGENT_OLD_SIGNATURE)
+               datafellows = SSH_BUG_SIGBLOB;
+
+       key = key_from_blob(blob, blen);
+       if (key != NULL) {
+               Identity *id = lookup_identity(key, 2);
+               if (id != NULL && (!id->confirm || confirm_key(id) == 0))
+                       ok = key_sign(id->key, &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);
+       datafellows = odatafellows;
+}
+
+/* shared */
+static void
+process_remove_identity(SocketEntry *e, int version)
+{
+       u_int blen, bits;
+       int success = 0;
+       Key *key = NULL;
+       u_char *blob;
+
+       switch (version) {
+       case 1:
+               key = key_new(KEY_RSA1);
+               bits = buffer_get_int(&e->request);
+               buffer_get_bignum(&e->request, key->rsa->e);
+               buffer_get_bignum(&e->request, key->rsa->n);
+
+               if (bits != key_size(key))
+                       logit("Warning: identity keysize mismatch: actual %u, announced %u",
+                           key_size(key), bits);
+               break;
+       case 2:
+               blob = buffer_get_string(&e->request, &blen);
+               key = key_from_blob(blob, blen);
+               xfree(blob);
+               break;
+       }
+       if (key != NULL) {
+               Identity *id = lookup_identity(key, version);
+               if (id != 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);
+                       if (tab->nentries < 1)
+                               fatal("process_remove_identity: "
+                                   "internal error: tab->nentries %d",
+                                   tab->nentries);
+                       TAILQ_REMOVE(&tab->idlist, id, next);
+                       free_identity(id);
+                       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)
+{
+       Idtab *tab = idtab_lookup(version);
+       Identity *id;
+
+       /* Loop over all identities and clear the keys. */
+       for (id = TAILQ_FIRST(&tab->idlist); id;
+           id = TAILQ_FIRST(&tab->idlist)) {
+               TAILQ_REMOVE(&tab->idlist, id, next);
+               free_identity(id);
+       }
+
+       /* 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);
+}
+
+/* removes expired keys and returns number of seconds until the next expiry */
+static u_int
+reaper(void)
+{
+       u_int deadline = 0, now = time(NULL);
+       Identity *id, *nxt;
+       int version;
+       Idtab *tab;
+
+       for (version = 1; version < 3; version++) {
+               tab = idtab_lookup(version);
+               for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
+                       nxt = TAILQ_NEXT(id, next);
+                       if (id->death == 0)
+                               continue;
+                       if (now >= id->death) {
+                               debug("expiring key '%s'", id->comment);
+                               TAILQ_REMOVE(&tab->idlist, id, next);
+                               free_identity(id);
+                               tab->nentries--;
+                       } else
+                               deadline = (deadline == 0) ? id->death :
+                                   MIN(deadline, id->death);
+               }
+       }
+       if (deadline == 0 || deadline <= now)
+               return 0;
+       else
+               return (deadline - now);
+}
+
+static void
+process_add_identity(SocketEntry *e, int version)
+{
+       Idtab *tab = idtab_lookup(version);
+       Identity *id;
+       int type, success = 0, death = 0, confirm = 0;
+       char *type_name, *comment;
+       Key *k = NULL;
+#ifdef OPENSSL_HAS_ECC
+       BIGNUM *exponent;
+       EC_POINT *q;
+       char *curve;
+#endif
+       u_char *cert;
+       u_int len;
+
+       switch (version) {
+       case 1:
+               k = key_new_private(KEY_RSA1);
+               (void) buffer_get_int(&e->request);             /* ignored */
+               buffer_get_bignum(&e->request, k->rsa->n);
+               buffer_get_bignum(&e->request, k->rsa->e);
+               buffer_get_bignum(&e->request, k->rsa->d);
+               buffer_get_bignum(&e->request, k->rsa->iqmp);
+
+               /* SSH and SSL have p and q swapped */
+               buffer_get_bignum(&e->request, k->rsa->q);      /* p */
+               buffer_get_bignum(&e->request, k->rsa->p);      /* q */
+
+               /* Generate additional parameters */
+               rsa_generate_additional_parameters(k->rsa);
+               break;
+       case 2:
+               type_name = buffer_get_string(&e->request, NULL);
+               type = key_type_from_name(type_name);
+               switch (type) {
+               case KEY_DSA:
+                       k = key_new_private(type);
+                       buffer_get_bignum2(&e->request, k->dsa->p);
+                       buffer_get_bignum2(&e->request, k->dsa->q);
+                       buffer_get_bignum2(&e->request, k->dsa->g);
+                       buffer_get_bignum2(&e->request, k->dsa->pub_key);
+                       buffer_get_bignum2(&e->request, k->dsa->priv_key);
+                       break;
+               case KEY_DSA_CERT_V00:
+               case KEY_DSA_CERT:
+                       cert = buffer_get_string(&e->request, &len);
+                       if ((k = key_from_blob(cert, len)) == NULL)
+                               fatal("Certificate parse failed");
+                       xfree(cert);
+                       key_add_private(k);
+                       buffer_get_bignum2(&e->request, k->dsa->priv_key);
+                       break;
+#ifdef OPENSSL_HAS_ECC
+               case KEY_ECDSA:
+                       k = key_new_private(type);
+                       k->ecdsa_nid = key_ecdsa_nid_from_name(type_name);
+                       curve = buffer_get_string(&e->request, NULL);
+                       if (k->ecdsa_nid != key_curve_name_to_nid(curve))
+                               fatal("%s: curve names mismatch", __func__);
+                       xfree(curve);
+                       k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
+                       if (k->ecdsa == NULL)
+                               fatal("%s: EC_KEY_new_by_curve_name failed",
+                                   __func__);
+                       q = EC_POINT_new(EC_KEY_get0_group(k->ecdsa));
+                       if (q == NULL)
+                               fatal("%s: BN_new failed", __func__);
+                       if ((exponent = BN_new()) == NULL)
+                               fatal("%s: BN_new failed", __func__);
+                       buffer_get_ecpoint(&e->request,
+                               EC_KEY_get0_group(k->ecdsa), q);
+                       buffer_get_bignum2(&e->request, exponent);
+                       if (EC_KEY_set_public_key(k->ecdsa, q) != 1)
+                               fatal("%s: EC_KEY_set_public_key failed",
+                                   __func__);
+                       if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
+                               fatal("%s: EC_KEY_set_private_key failed",
+                                   __func__);
+                       if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
+                           EC_KEY_get0_public_key(k->ecdsa)) != 0)
+                               fatal("%s: bad ECDSA public key", __func__);
+                       if (key_ec_validate_private(k->ecdsa) != 0)
+                               fatal("%s: bad ECDSA private key", __func__);
+                       BN_clear_free(exponent);
+                       EC_POINT_free(q);
+                       break;
+               case KEY_ECDSA_CERT:
+                       cert = buffer_get_string(&e->request, &len);
+                       if ((k = key_from_blob(cert, len)) == NULL)
+                               fatal("Certificate parse failed");
+                       xfree(cert);
+                       key_add_private(k);
+                       if ((exponent = BN_new()) == NULL)
+                               fatal("%s: BN_new failed", __func__);
+                       buffer_get_bignum2(&e->request, exponent);
+                       if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1)
+                               fatal("%s: EC_KEY_set_private_key failed",
+                                   __func__);
+                       if (key_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
+                           EC_KEY_get0_public_key(k->ecdsa)) != 0 ||
+                           key_ec_validate_private(k->ecdsa) != 0)
+                               fatal("%s: bad ECDSA key", __func__);
+                       BN_clear_free(exponent);
+                       break;
+#endif /* OPENSSL_HAS_ECC */
+               case KEY_RSA:
+                       k = key_new_private(type);
+                       buffer_get_bignum2(&e->request, k->rsa->n);
+                       buffer_get_bignum2(&e->request, k->rsa->e);
+                       buffer_get_bignum2(&e->request, k->rsa->d);
+                       buffer_get_bignum2(&e->request, k->rsa->iqmp);
+                       buffer_get_bignum2(&e->request, k->rsa->p);
+                       buffer_get_bignum2(&e->request, k->rsa->q);
+
+                       /* Generate additional parameters */
+                       rsa_generate_additional_parameters(k->rsa);
+                       break;
+               case KEY_RSA_CERT_V00:
+               case KEY_RSA_CERT:
+                       cert = buffer_get_string(&e->request, &len);
+                       if ((k = key_from_blob(cert, len)) == NULL)
+                               fatal("Certificate parse failed");
+                       xfree(cert);
+                       key_add_private(k);
+                       buffer_get_bignum2(&e->request, k->rsa->d);
+                       buffer_get_bignum2(&e->request, k->rsa->iqmp);
+                       buffer_get_bignum2(&e->request, k->rsa->p);
+                       buffer_get_bignum2(&e->request, k->rsa->q);
+                       break;
+               default:
+                       xfree(type_name);
+                       buffer_clear(&e->request);
+                       goto send;
+               }
+               xfree(type_name);
+               break;
+       }
+       /* enable blinding */
+       switch (k->type) {
+       case KEY_RSA:
+       case KEY_RSA_CERT_V00:
+       case KEY_RSA_CERT:
+       case KEY_RSA1:
+               if (RSA_blinding_on(k->rsa, NULL) != 1) {
+                       error("process_add_identity: RSA_blinding_on failed");
+                       key_free(k);
+                       goto send;
+               }
+               break;
+       }
+       comment = buffer_get_string(&e->request, NULL);
+       if (k == NULL) {
+               xfree(comment);
+               goto send;
+       }
+       while (buffer_len(&e->request)) {
+               switch ((type = buffer_get_char(&e->request))) {
+               case SSH_AGENT_CONSTRAIN_LIFETIME:
+                       death = time(NULL) + buffer_get_int(&e->request);
+                       break;
+               case SSH_AGENT_CONSTRAIN_CONFIRM:
+                       confirm = 1;
+                       break;
+               default:
+                       error("process_add_identity: "
+                           "Unknown constraint type %d", type);
+                       xfree(comment);
+                       key_free(k);
+                       goto send;
+               }
+       }
+       success = 1;
+       if (lifetime && !death)
+               death = time(NULL) + lifetime;
+       if ((id = lookup_identity(k, version)) == NULL) {
+               id = xcalloc(1, sizeof(Identity));
+               id->key = k;
+               TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+               /* Increment the number of identities. */
+               tab->nentries++;
+       } else {
+               key_free(k);
+               xfree(id->comment);
+       }
+       id->comment = comment;
+       id->death = death;
+       id->confirm = confirm;
+send:
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+/* XXX todo: encrypt sensitive data with passphrase */
+static void
+process_lock_agent(SocketEntry *e, int lock)
+{
+       int success = 0;
+       char *passwd;
+
+       passwd = buffer_get_string(&e->request, NULL);
+       if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
+               locked = 0;
+               memset(lock_passwd, 0, strlen(lock_passwd));
+               xfree(lock_passwd);
+               lock_passwd = NULL;
+               success = 1;
+       } else if (!locked && lock) {
+               locked = 1;
+               lock_passwd = xstrdup(passwd);
+               success = 1;
+       }
+       memset(passwd, 0, strlen(passwd));
+       xfree(passwd);
+
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+no_identities(SocketEntry *e, u_int type)
+{
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg,
+           (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
+           SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
+       buffer_put_int(&msg, 0);
+       buffer_put_int(&e->output, buffer_len(&msg));
+       buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
+       buffer_free(&msg);
+}
+
+#ifdef ENABLE_PKCS11
+static void
+process_add_smartcard_key(SocketEntry *e)
+{
+       char *provider = NULL, *pin;
+       int i, type, version, count = 0, success = 0, death = 0, confirm = 0;
+       Key **keys = NULL, *k;
+       Identity *id;
+       Idtab *tab;
+
+       provider = buffer_get_string(&e->request, NULL);
+       pin = buffer_get_string(&e->request, NULL);
+
+       while (buffer_len(&e->request)) {
+               switch ((type = buffer_get_char(&e->request))) {
+               case SSH_AGENT_CONSTRAIN_LIFETIME:
+                       death = time(NULL) + buffer_get_int(&e->request);
+                       break;
+               case SSH_AGENT_CONSTRAIN_CONFIRM:
+                       confirm = 1;
+                       break;
+               default:
+                       error("process_add_smartcard_key: "
+                           "Unknown constraint type %d", type);
+                       goto send;
+               }
+       }
+       if (lifetime && !death)
+               death = time(NULL) + lifetime;
+
+       count = pkcs11_add_provider(provider, pin, &keys);
+       for (i = 0; i < count; i++) {
+               k = keys[i];
+               version = k->type == KEY_RSA1 ? 1 : 2;
+               tab = idtab_lookup(version);
+               if (lookup_identity(k, version) == NULL) {
+                       id = xcalloc(1, sizeof(Identity));
+                       id->key = k;
+                       id->provider = xstrdup(provider);
+                       id->comment = xstrdup(provider); /* XXX */
+                       id->death = death;
+                       id->confirm = confirm;
+                       TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+                       tab->nentries++;
+                       success = 1;
+               } else {
+                       key_free(k);
+               }
+               keys[i] = NULL;
+       }
+send:
+       if (pin)
+               xfree(pin);
+       if (provider)
+               xfree(provider);
+       if (keys)
+               xfree(keys);
+       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)
+{
+       char *provider = NULL, *pin = NULL;
+       int version, success = 0;
+       Identity *id, *nxt;
+       Idtab *tab;
+
+       provider = buffer_get_string(&e->request, NULL);
+       pin = buffer_get_string(&e->request, NULL);
+       xfree(pin);
+
+       for (version = 1; version < 3; version++) {
+               tab = idtab_lookup(version);
+               for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
+                       nxt = TAILQ_NEXT(id, next);
+                       if (!strcmp(provider, id->provider)) {
+                               TAILQ_REMOVE(&tab->idlist, id, next);
+                               free_identity(id);
+                               tab->nentries--;
+                       }
+               }
+       }
+       if (pkcs11_del_provider(provider) == 0)
+               success = 1;
+       else
+               error("process_remove_smartcard_key:"
+                   " pkcs11_del_provider failed");
+       xfree(provider);
+       buffer_put_int(&e->output, 1);
+       buffer_put_char(&e->output,
+           success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* ENABLE_PKCS11 */
+
+/* dispatch incoming messages */
+
+static void
+process_message(SocketEntry *e)
+{
+       u_int msg_len, type;
+       u_char *cp;
+
+       if (buffer_len(&e->input) < 5)
+               return;         /* Incomplete message. */
+       cp = buffer_ptr(&e->input);
+       msg_len = get_u32(cp);
+       if (msg_len > 256 * 1024) {
+               close_socket(e);
+               return;
+       }
+       if (buffer_len(&e->input) < msg_len + 4)
+               return;
+
+       /* move the current input to e->request */
+       buffer_consume(&e->input, 4);
+       buffer_clear(&e->request);
+       buffer_append(&e->request, buffer_ptr(&e->input), msg_len);
+       buffer_consume(&e->input, msg_len);
+       type = buffer_get_char(&e->request);
+
+       /* check wheter agent is locked */
+       if (locked && type != SSH_AGENTC_UNLOCK) {
+               buffer_clear(&e->request);
+               switch (type) {
+               case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
+               case SSH2_AGENTC_REQUEST_IDENTITIES:
+                       /* send empty lists */
+                       no_identities(e, type);
+                       break;
+               default:
+                       /* send a fail message for all other request types */
+                       buffer_put_int(&e->output, 1);
+                       buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+               }
+               return;
+       }
+
+       debug("type %d", type);
+       switch (type) {
+       case SSH_AGENTC_LOCK:
+       case SSH_AGENTC_UNLOCK:
+               process_lock_agent(e, type == SSH_AGENTC_LOCK);
+               break;
+       /* 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:
+       case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
+               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:
+       case SSH2_AGENTC_ADD_ID_CONSTRAINED:
+               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 ENABLE_PKCS11
+       case SSH_AGENTC_ADD_SMARTCARD_KEY:
+       case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED:
+               process_add_smartcard_key(e);
+               break;
+       case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
+               process_remove_smartcard_key(e);
+               break;
+#endif /* ENABLE_PKCS11 */
+       default:
+               /* Unknown message.  Respond with failure. */
+               error("Unknown message %d", type);
+               buffer_clear(&e->request);
+               buffer_put_int(&e->output, 1);
+               buffer_put_char(&e->output, SSH_AGENT_FAILURE);
+               break;
+       }
+}
+
+static void
+new_socket(sock_type type, int fd)
+{
+       u_int i, old_alloc, new_alloc;
+
+       set_nonblock(fd);
+
+       if (fd > max_fd)
+               max_fd = fd;
+
+       for (i = 0; i < sockets_alloc; i++)
+               if (sockets[i].type == AUTH_UNUSED) {
+                       sockets[i].fd = fd;
+                       buffer_init(&sockets[i].input);
+                       buffer_init(&sockets[i].output);
+                       buffer_init(&sockets[i].request);
+                       sockets[i].type = type;
+                       return;
+               }
+       old_alloc = sockets_alloc;
+       new_alloc = sockets_alloc + 10;
+       sockets = xrealloc(sockets, new_alloc, sizeof(sockets[0]));
+       for (i = old_alloc; i < new_alloc; i++)
+               sockets[i].type = AUTH_UNUSED;
+       sockets_alloc = new_alloc;
+       sockets[old_alloc].fd = fd;
+       buffer_init(&sockets[old_alloc].input);
+       buffer_init(&sockets[old_alloc].output);
+       buffer_init(&sockets[old_alloc].request);
+       sockets[old_alloc].type = type;
+}
+
+static int
+prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp,
+    struct timeval **tvpp)
+{
+       u_int i, sz, deadline;
+       int n = 0;
+       static struct timeval tv;
+
+       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;
+               }
+       }
+       deadline = reaper();
+       if (parent_alive_interval != 0)
+               deadline = (deadline == 0) ? parent_alive_interval :
+                   MIN(deadline, parent_alive_interval);
+       if (deadline == 0) {
+               *tvpp = NULL;
+       } else {
+               tv.tv_sec = deadline;
+               tv.tv_usec = 0;
+               *tvpp = &tv;
+       }
+       return (1);
+}
+
+static void
+after_select(fd_set *readset, fd_set *writeset)
+{
+       struct sockaddr_un sunaddr;
+       socklen_t slen;
+       char buf[1024];
+       int len, sock;
+       u_int i, orig_alloc;
+       uid_t euid;
+       gid_t egid;
+
+       for (i = 0, orig_alloc = sockets_alloc; i < orig_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) {
+                                       error("accept from AUTH_SOCKET: %s",
+                                           strerror(errno));
+                                       break;
+                               }
+                               if (getpeereid(sock, &euid, &egid) < 0) {
+                                       error("getpeereid %d failed: %s",
+                                           sock, strerror(errno));
+                                       close(sock);
+                                       break;
+                               }
+                               if ((euid != 0) && (getuid() != euid)) {
+                                       error("uid mismatch: "
+                                           "peer euid %u != uid %u",
+                                           (u_int) euid, (u_int) getuid());
+                                       close(sock);
+                                       break;
+                               }
+                               new_socket(AUTH_CONNECTION, sock);
+                       }
+                       break;
+               case AUTH_CONNECTION:
+                       if (buffer_len(&sockets[i].output) > 0 &&
+                           FD_ISSET(sockets[i].fd, writeset)) {
+                               len = write(sockets[i].fd,
+                                   buffer_ptr(&sockets[i].output),
+                                   buffer_len(&sockets[i].output));
+                               if (len == -1 && (errno == EAGAIN ||
+                                   errno == EWOULDBLOCK ||
+                                   errno == EINTR))
+                                       continue;
+                               if (len <= 0) {
+                                       close_socket(&sockets[i]);
+                                       break;
+                               }
+                               buffer_consume(&sockets[i].output, len);
+                       }
+                       if (FD_ISSET(sockets[i].fd, readset)) {
+                               len = read(sockets[i].fd, buf, sizeof(buf));
+                               if (len == -1 && (errno == EAGAIN ||
+                                   errno == EWOULDBLOCK ||
+                                   errno == EINTR))
+                                       continue;
+                               if (len <= 0) {
+                                       close_socket(&sockets[i]);
+                                       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);
+}
+
+void
+cleanup_exit(int i)
+{
+       cleanup_socket();
+       _exit(i);
+}
+
+/*ARGSUSED*/
+static void
+cleanup_handler(int sig)
+{
+       cleanup_socket();
+#ifdef ENABLE_PKCS11
+       pkcs11_terminate();
+#endif
+       _exit(2);
+}
+
+static void
+check_parent_exists(void)
+{
+       if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
+               /* printf("Parent has died - Authentication agent exiting.\n"); */
+               cleanup_socket();
+               _exit(2);
+       }
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "usage: %s [options] [command [arg ...]]\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");
+       fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
+       fprintf(stderr, "  -t life     Default identity lifetime (seconds).\n");
+       exit(1);
+}
+
+int
+main(int ac, char **av)
+{
+       int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0;
+       int sock, fd, ch, result, saved_errno;
+       u_int nalloc;
+       char *shell, *format, *pidstr, *agentsocket = NULL;
+       fd_set *readsetp = NULL, *writesetp = NULL;
+       struct sockaddr_un sunaddr;
+#ifdef HAVE_SETRLIMIT
+       struct rlimit rlim;
+#endif
+       int prev_mask;
+       extern int optind;
+       extern char *optarg;
+       pid_t pid;
+       char pidstrbuf[1 + 3 * sizeof pid];
+       struct timeval *tvp = NULL;
+       size_t len;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       /* drop */
+       setegid(getgid());
+       setgid(getgid());
+
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+       /* Disable ptrace on Linux without sgid bit */
+       prctl(PR_SET_DUMPABLE, 0);
+#endif
+
+       OpenSSL_add_all_algorithms();
+
+       __progname = ssh_get_progname(av[0]);
+       init_rng();
+       seed_rng();
+
+       while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+               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;
+               case 'a':
+                       agentsocket = optarg;
+                       break;
+               case 't':
+                       if ((lifetime = convtime(optarg)) == -1) {
+                               fprintf(stderr, "Invalid lifetime\n");
+                               usage();
+                       }
+                       break;
+               default:
+                       usage();
+               }
+       }
+       ac -= optind;
+       av += optind;
+
+       if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
+               usage();
+
+       if (ac == 0 && !c_flag && !s_flag) {
+               shell = getenv("SHELL");
+               if (shell != NULL && (len = strlen(shell)) > 2 &&
+                   strncmp(shell + len - 3, "csh", 3) == 0)
+                       c_flag = 1;
+       }
+       if (k_flag) {
+               const char *errstr = NULL;
+
+               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 = (int)strtonum(pidstr, 2, INT_MAX, &errstr);
+               if (errstr) {
+                       fprintf(stderr,
+                           "%s=\"%s\", which is not a good PID: %s\n",
+                           SSH_AGENTPID_ENV_NAME, pidstr, errstr);
+                       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 %ld killed;\n", (long)pid);
+               exit(0);
+       }
+       parent_pid = getpid();
+
+       if (agentsocket == NULL) {
+               /* Create private directory for agent socket */
+               mktemp_proto(socket_dir, sizeof(socket_dir));
+               if (mkdtemp(socket_dir) == NULL) {
+                       perror("mkdtemp: private socket dir");
+                       exit(1);
+               }
+               snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
+                   (long)parent_pid);
+       } else {
+               /* Try to use specified agent socket */
+               socket_dir[0] = '\0';
+               strlcpy(socket_name, agentsocket, sizeof socket_name);
+       }
+
+       /*
+        * 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");
+               *socket_name = '\0'; /* Don't unlink any existing file */
+               cleanup_exit(1);
+       }
+       memset(&sunaddr, 0, sizeof(sunaddr));
+       sunaddr.sun_family = AF_UNIX;
+       strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
+       prev_mask = umask(0177);
+       if (bind(sock, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) {
+               perror("bind");
+               *socket_name = '\0'; /* Don't unlink any existing file */
+               umask(prev_mask);
+               cleanup_exit(1);
+       }
+       umask(prev_mask);
+       if (listen(sock, SSH_LISTEN_BACKLOG) < 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 %ld;\n", (long)parent_pid);
+               goto skip;
+       }
+       pid = fork();
+       if (pid == -1) {
+               perror("fork");
+               cleanup_exit(1);
+       }
+       if (pid != 0) {         /* Parent - execute the given command. */
+               close(sock);
+               snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)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 %ld;\n", (long)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);
+       }
+       /* child */
+       log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
+
+       if (setsid() == -1) {
+               error("setsid: %s", strerror(errno));
+               cleanup_exit(1);
+       }
+
+       (void)chdir("/");
+       if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+               /* XXX might close listen socket */
+               (void)dup2(fd, STDIN_FILENO);
+               (void)dup2(fd, STDOUT_FILENO);
+               (void)dup2(fd, STDERR_FILENO);
+               if (fd > 2)
+                       close(fd);
+       }
+
+#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) {
+               error("setrlimit RLIMIT_CORE: %s", strerror(errno));
+               cleanup_exit(1);
+       }
+#endif
+
+skip:
+
+#ifdef ENABLE_PKCS11
+       pkcs11_init(0);
+#endif
+       new_socket(AUTH_SOCKET, sock);
+       if (ac > 0)
+               parent_alive_interval = 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, &tvp);
+               result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
+               saved_errno = errno;
+               if (parent_alive_interval != 0)
+                       check_parent_exists();
+               (void) reaper();        /* remove expired keys */
+               if (result < 0) {
+                       if (saved_errno == EINTR)
+                               continue;
+                       fatal("select: %s", strerror(saved_errno));
+               } else if (result > 0)
+                       after_select(readsetp, writesetp);
+       }
+       /* NOTREACHED */
+}
diff --git a/ssh-dss.c b/ssh-dss.c
new file mode 100644 (file)
index 0000000..ede5e21
--- /dev/null
+++ b/ssh-dss.c
@@ -0,0 +1,187 @@
+/* $OpenBSD: ssh-dss.c,v 1.27 2010/08/31 09:58:37 djm 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 <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "compat.h"
+#include "log.h"
+#include "key.h"
+
+#define INTBLOB_LEN    20
+#define SIGBLOB_LEN    (2*INTBLOB_LEN)
+
+int
+ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp,
+    const u_char *data, u_int datalen)
+{
+       DSA_SIG *sig;
+       const EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN];
+       u_int rlen, slen, len, dlen;
+       Buffer b;
+
+       if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA &&
+           key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) {
+               error("ssh_dss_sign: no DSA key");
+               return -1;
+       }
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       sig = DSA_do_sign(digest, dlen, key->dsa);
+       memset(digest, 'd', sizeof(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 %u %u", 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) {
+               if (lenp != NULL)
+                       *lenp = SIGBLOB_LEN;
+               if (sigp != NULL) {
+                       *sigp = xmalloc(SIGBLOB_LEN);
+                       memcpy(*sigp, sigblob, SIGBLOB_LEN);
+               }
+       } else {
+               /* ietf-drafts */
+               buffer_init(&b);
+               buffer_put_cstring(&b, "ssh-dss");
+               buffer_put_string(&b, sigblob, SIGBLOB_LEN);
+               len = buffer_len(&b);
+               if (lenp != NULL)
+                       *lenp = len;
+               if (sigp != NULL) {
+                       *sigp = xmalloc(len);
+                       memcpy(*sigp, buffer_ptr(&b), len);
+               }
+               buffer_free(&b);
+       }
+       return 0;
+}
+int
+ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen,
+    const u_char *data, u_int datalen)
+{
+       DSA_SIG *sig;
+       const EVP_MD *evp_md = EVP_sha1();
+       EVP_MD_CTX md;
+       u_char digest[EVP_MAX_MD_SIZE], *sigblob;
+       u_int len, dlen;
+       int rlen, ret;
+       Buffer b;
+
+       if (key == NULL || key->dsa == NULL || (key->type != KEY_DSA &&
+           key->type != KEY_DSA_CERT && key->type != KEY_DSA_CERT_V00)) {
+               error("ssh_dss_verify: no DSA key");
+               return -1;
+       }
+
+       /* fetch signature */
+       if (datafellows & SSH_BUG_SIGBLOB) {
+               sigblob = xmalloc(signaturelen);
+               memcpy(sigblob, signature, signaturelen);
+               len = signaturelen;
+       } else {
+               /* ietf-drafts */
+               char *ktype;
+               buffer_init(&b);
+               buffer_append(&b, signature, signaturelen);
+               ktype = buffer_get_cstring(&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 %u != SIGBLOB_LEN", len);
+       }
+
+       /* parse signature */
+       if ((sig = DSA_SIG_new()) == NULL)
+               fatal("ssh_dss_verify: DSA_SIG_new failed");
+       if ((sig->r = BN_new()) == NULL)
+               fatal("ssh_dss_verify: BN_new failed");
+       if ((sig->s = BN_new()) == NULL)
+               fatal("ssh_dss_verify: BN_new failed");
+       if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
+           (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL))
+               fatal("ssh_dss_verify: BN_bin2bn failed");
+
+       /* clean up */
+       memset(sigblob, 0, len);
+       xfree(sigblob);
+
+       /* sha1 the data */
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       ret = DSA_do_verify(digest, dlen, sig, key->dsa);
+       memset(digest, 'd', sizeof(digest));
+
+       DSA_SIG_free(sig);
+
+       debug("ssh_dss_verify: signature %s",
+           ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
+       return ret;
+}
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
new file mode 100644 (file)
index 0000000..c8276b4
--- /dev/null
@@ -0,0 +1,168 @@
+/* $OpenBSD: ssh-ecdsa.c,v 1.4 2010/09/10 01:04:10 djm Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2010 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 OPENSSL_HAS_ECC
+
+#include <sys/types.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/ecdsa.h>
+#include <openssl/evp.h>
+
+#include <string.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "compat.h"
+#include "log.h"
+#include "key.h"
+
+int
+ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp,
+    const u_char *data, u_int datalen)
+{
+       ECDSA_SIG *sig;
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       u_char digest[EVP_MAX_MD_SIZE];
+       u_int len, dlen;
+       Buffer b, bb;
+
+       if (key == NULL || key->ecdsa == NULL ||
+           (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
+               error("%s: no ECDSA key", __func__);
+               return -1;
+       }
+       evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid);
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       sig = ECDSA_do_sign(digest, dlen, key->ecdsa);
+       memset(digest, 'd', sizeof(digest));
+
+       if (sig == NULL) {
+               error("%s: sign failed", __func__);
+               return -1;
+       }
+
+       buffer_init(&bb);
+       buffer_put_bignum2(&bb, sig->r);
+       buffer_put_bignum2(&bb, sig->s);
+       ECDSA_SIG_free(sig);
+
+       buffer_init(&b);
+       buffer_put_cstring(&b, key_ssh_name_plain(key));
+       buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
+       buffer_free(&bb);
+       len = buffer_len(&b);
+       if (lenp != NULL)
+               *lenp = len;
+       if (sigp != NULL) {
+               *sigp = xmalloc(len);
+               memcpy(*sigp, buffer_ptr(&b), len);
+       }
+       buffer_free(&b);
+
+       return 0;
+}
+int
+ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
+    const u_char *data, u_int datalen)
+{
+       ECDSA_SIG *sig;
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       u_char digest[EVP_MAX_MD_SIZE], *sigblob;
+       u_int len, dlen;
+       int rlen, ret;
+       Buffer b, bb;
+       char *ktype;
+
+       if (key == NULL || key->ecdsa == NULL ||
+           (key->type != KEY_ECDSA && key->type != KEY_ECDSA_CERT)) {
+               error("%s: no ECDSA key", __func__);
+               return -1;
+       }
+       evp_md = key_ec_nid_to_evpmd(key->ecdsa_nid);
+
+       /* fetch signature */
+       buffer_init(&b);
+       buffer_append(&b, signature, signaturelen);
+       ktype = buffer_get_string(&b, NULL);
+       if (strcmp(key_ssh_name_plain(key), ktype) != 0) {
+               error("%s: cannot handle type %s", __func__, 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("%s: remaining bytes in signature %d", __func__, rlen);
+               xfree(sigblob);
+               return -1;
+       }
+
+       /* parse signature */
+       if ((sig = ECDSA_SIG_new()) == NULL)
+               fatal("%s: ECDSA_SIG_new failed", __func__);
+       if ((sig->r = BN_new()) == NULL ||
+           (sig->s = BN_new()) == NULL)
+               fatal("%s: BN_new failed", __func__);
+
+       buffer_init(&bb);
+       buffer_append(&bb, sigblob, len);
+       buffer_get_bignum2(&bb, sig->r);
+       buffer_get_bignum2(&bb, sig->s);
+       if (buffer_len(&bb) != 0)
+               fatal("%s: remaining bytes in inner sigblob", __func__);
+
+       /* clean up */
+       memset(sigblob, 0, len);
+       xfree(sigblob);
+
+       /* hash the data */
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa);
+       memset(digest, 'd', sizeof(digest));
+
+       ECDSA_SIG_free(sig);
+
+       debug("%s: signature %s", __func__,
+           ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error");
+       return ret;
+}
+
+#endif /* OPENSSL_HAS_ECC */
diff --git a/ssh-gss.h b/ssh-gss.h
new file mode 100644 (file)
index 0000000..c29a1b7
--- /dev/null
+++ b/ssh-gss.h
@@ -0,0 +1,131 @@
+/* $OpenBSD: ssh-gss.h,v 1.10 2007/06/12 08:20:00 djm Exp $ */
+/*
+ * Copyright (c) 2001-2003 Simon Wilkinson. 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_GSS_H
+#define _SSH_GSS_H
+
+#ifdef GSSAPI
+
+#ifdef HAVE_GSSAPI_H
+#include <gssapi.h>
+#elif defined(HAVE_GSSAPI_GSSAPI_H)
+#include <gssapi/gssapi.h>
+#endif
+
+#ifdef KRB5
+# ifndef HEIMDAL
+#  ifdef HAVE_GSSAPI_GENERIC_H
+#   include <gssapi_generic.h>
+#  elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+#   include <gssapi/gssapi_generic.h>
+#  endif
+
+/* MIT Kerberos doesn't seem to define GSS_NT_HOSTBASED_SERVICE */
+
+#ifndef GSS_C_NT_HOSTBASED_SERVICE
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif /* GSS_C_NT_... */
+#endif /* !HEIMDAL */
+#endif /* KRB5 */
+
+/* draft-ietf-secsh-gsskeyex-06 */
+#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE              60
+#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN                 61
+#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE     63
+#define SSH2_MSG_USERAUTH_GSSAPI_ERROR                 64
+#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK                        65
+#define SSH2_MSG_USERAUTH_GSSAPI_MIC                   66
+
+#define SSH_GSS_OIDTYPE 0x06
+
+typedef struct {
+       char *filename;
+       char *envvar;
+       char *envval;
+       void *data;
+} ssh_gssapi_ccache;
+
+typedef struct {
+       gss_buffer_desc displayname;
+       gss_buffer_desc exportedname;
+       gss_cred_id_t creds;
+       struct ssh_gssapi_mech_struct *mech;
+       ssh_gssapi_ccache store;
+} ssh_gssapi_client;
+
+typedef struct ssh_gssapi_mech_struct {
+       char *enc_name;
+       char *name;
+       gss_OID_desc oid;
+       int (*dochild) (ssh_gssapi_client *);
+       int (*userok) (ssh_gssapi_client *, char *);
+       int (*localname) (ssh_gssapi_client *, char **);
+       void (*storecreds) (ssh_gssapi_client *);
+} ssh_gssapi_mech;
+
+typedef struct {
+       OM_uint32       major; /* both */
+       OM_uint32       minor; /* both */
+       gss_ctx_id_t    context; /* both */
+       gss_name_t      name; /* both */
+       gss_OID         oid; /* client */
+       gss_cred_id_t   creds; /* server */
+       gss_name_t      client; /* server */
+       gss_cred_id_t   client_creds; /* server */
+} Gssctxt;
+
+extern ssh_gssapi_mech *supported_mechs[];
+
+int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
+void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
+void ssh_gssapi_set_oid(Gssctxt *, gss_OID);
+void ssh_gssapi_supported_oids(gss_OID_set *);
+ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *);
+
+OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *);
+OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int,
+    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *,
+    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
+OM_uint32 ssh_gssapi_getclient(Gssctxt *, ssh_gssapi_client *);
+void ssh_gssapi_error(Gssctxt *);
+char *ssh_gssapi_last_error(Gssctxt *, OM_uint32 *, OM_uint32 *);
+void ssh_gssapi_build_ctx(Gssctxt **);
+void ssh_gssapi_delete_ctx(Gssctxt **);
+OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
+void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *);
+
+/* In the server */
+OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
+int ssh_gssapi_userok(char *name);
+OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+void ssh_gssapi_do_child(char ***, u_int *);
+void ssh_gssapi_cleanup_creds(void);
+void ssh_gssapi_storecreds(void);
+
+#endif /* GSSAPI */
+
+#endif /* _SSH_GSS_H */
diff --git a/ssh-keygen.0 b/ssh-keygen.0
new file mode 100644 (file)
index 0000000..a01b30d
--- /dev/null
@@ -0,0 +1,443 @@
+SSH-KEYGEN(1)              OpenBSD Reference Manual              SSH-KEYGEN(1)
+
+NAME
+     ssh-keygen - authentication key generation, management and conversion
+
+SYNOPSIS
+     ssh-keygen [-q] [-b bits] -t type [-N new_passphrase] [-C comment]
+                [-f output_keyfile]
+     ssh-keygen -p [-P old_passphrase] [-N new_passphrase] [-f keyfile]
+     ssh-keygen -i [-m key_format] [-f input_keyfile]
+     ssh-keygen -e [-m key_format] [-f input_keyfile]
+     ssh-keygen -y [-f input_keyfile]
+     ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]
+     ssh-keygen -l [-f input_keyfile]
+     ssh-keygen -B [-f input_keyfile]
+     ssh-keygen -D pkcs11
+     ssh-keygen -F hostname [-f known_hosts_file] [-l]
+     ssh-keygen -H [-f known_hosts_file]
+     ssh-keygen -R hostname [-f known_hosts_file]
+     ssh-keygen -r hostname [-f input_keyfile] [-g]
+     ssh-keygen -G output_file [-v] [-b bits] [-M memory] [-S start_point]
+     ssh-keygen -T output_file -f input_file [-v] [-a num_trials]
+                [-W generator]
+     ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]
+                [-O option] [-V validity_interval] [-z serial_number] file ...
+     ssh-keygen -L [-f input_keyfile]
+
+DESCRIPTION
+     ssh-keygen generates, manages and converts authentication keys for
+     ssh(1).  ssh-keygen can create RSA keys for use by SSH protocol version 1
+     and DSA, ECDSA or RSA keys for use by SSH protocol version 2.  The type
+     of key to be generated is specified with the -t option.  If invoked
+     without any arguments, ssh-keygen will generate an RSA key for use in SSH
+     protocol 2 connections.
+
+     ssh-keygen is also used to generate groups for use in Diffie-Hellman
+     group exchange (DH-GEX).  See the MODULI GENERATION section for details.
+
+     Normally each user wishing to use SSH with public key authentication runs
+     this once to create the authentication key in ~/.ssh/identity,
+     ~/.ssh/id_ecdsa, ~/.ssh/id_dsa or ~/.ssh/id_rsa.  Additionally, the
+     system administrator may use this to generate host keys, as seen in
+     /etc/rc.
+
+     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 ``.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.  A
+     passphrase is similar to a password, except it can be a phrase with a
+     series of words, punctuation, numbers, whitespace, or any string of
+     characters you want.  Good passphrases are 10-30 characters long, are not
+     simple sentences or otherwise easily guessable (English prose has only 1-
+     2 bits of entropy per character, and provides very bad passphrases), and
+     contain a mix of upper and lowercase letters, numbers, and non-
+     alphanumeric characters.  The passphrase can be changed later by using
+     the -p option.
+
+     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.
+
+     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 ``user@host'' when the key is created, but can be changed
+     using the -c option.
+
+     After a key is generated, instructions below detail where the keys should
+     be placed to be activated.
+
+     The options are as follows:
+
+     -a trials
+             Specifies the number of primality tests to perform when screening
+             DH-GEX candidates using the -T command.
+
+     -B      Show the bubblebabble digest of specified private or public key
+             file.
+
+     -b bits
+             Specifies the number of bits in the key to create.  For RSA keys,
+             the minimum size is 768 bits and the default is 2048 bits.
+             Generally, 2048 bits is considered sufficient.  DSA keys must be
+             exactly 1024 bits as specified by FIPS 186-2.
+
+     -C comment
+             Provides a new comment.
+
+     -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.
+
+     -D pkcs11
+             Download the RSA public keys provided by the PKCS#11 shared
+             library pkcs11.  When used in combination with -s, this option
+             indicates that a CA key resides in a PKCS#11 token (see the
+             CERTIFICATES section for details).
+
+     -e      This option will read a private or public OpenSSH key file and
+             print to stdout the key in one of the formats specified by the -m
+             option.  The default export format is ``RFC4716''.  This option
+             allows exporting OpenSSH keys for use by other programs,
+             including several commercial SSH implementations.
+
+     -F hostname
+             Search for the specified hostname in a known_hosts file, listing
+             any occurrences found.  This option is useful to find hashed host
+             names or addresses and may also be used in conjunction with the
+             -H option to print found keys in a hashed format.
+
+     -f filename
+             Specifies the filename of the key file.
+
+     -G output_file
+             Generate candidate primes for DH-GEX.  These primes must be
+             screened for safety (using the -T option) before use.
+
+     -g      Use generic DNS format when printing fingerprint resource records
+             using the -r command.
+
+     -H      Hash a known_hosts file.  This replaces all hostnames and
+             addresses with hashed representations within the specified file;
+             the original content is moved to a file with a .old suffix.
+             These hashes may be used normally by ssh and sshd, but they do
+             not reveal identifying information should the file's contents be
+             disclosed.  This option will not modify existing hashed hostnames
+             and is therefore safe to use on files that mix hashed and non-
+             hashed names.
+
+     -h      When signing a key, create a host certificate instead of a user
+             certificate.  Please see the CERTIFICATES section for details.
+
+     -I certificate_identity
+             Specify the key identity when signing a public key.  Please see
+             the CERTIFICATES section for details.
+
+     -i      This option will read an unencrypted private (or public) key file
+             in the format specified by the -m option and print an OpenSSH
+             compatible private (or public) key to stdout.  This option allows
+             importing keys from other software, including several commercial
+             SSH implementations.  The default import format is ``RFC4716''.
+
+     -L      Prints the contents of a certificate.
+
+     -l      Show fingerprint of specified public key file.  Private RSA1 keys
+             are also supported.  For RSA and DSA keys ssh-keygen tries to
+             find the matching public key file and prints its fingerprint.  If
+             combined with -v, an ASCII art representation of the key is
+             supplied with the fingerprint.
+
+     -M memory
+             Specify the amount of memory to use (in megabytes) when
+             generating candidate moduli for DH-GEX.
+
+     -m key_format
+             Specify a key format for the -i (import) or -e (export)
+             conversion options.  The supported key formats are: ``RFC4716''
+             (RFC 4716/SSH2 public or private key), ``PKCS8'' (PEM PKCS8
+             public key) or ``PEM'' (PEM public key).  The default conversion
+             format is ``RFC4716''.
+
+     -N new_passphrase
+             Provides the new passphrase.
+
+     -n principals
+             Specify one or more principals (user or host names) to be
+             included in a certificate when signing a key.  Multiple
+             principals may be specified, separated by commas.  Please see the
+             CERTIFICATES section for details.
+
+     -O option
+             Specify a certificate option when signing a key.  This option may
+             be specified multiple times.  Please see the CERTIFICATES section
+             for details.  The options that are valid for user certificates
+             are:
+
+             clear   Clear all enabled permissions.  This is useful for
+                     clearing the default set of permissions so permissions
+                     may be added individually.
+
+             force-command=command
+                     Forces the execution of command instead of any shell or
+                     command specified by the user when the certificate is
+                     used for authentication.
+
+             no-agent-forwarding
+                     Disable ssh-agent(1) forwarding (permitted by default).
+
+             no-port-forwarding
+                     Disable port forwarding (permitted by default).
+
+             no-pty  Disable PTY allocation (permitted by default).
+
+             no-user-rc
+                     Disable execution of ~/.ssh/rc by sshd(8) (permitted by
+                     default).
+
+             no-x11-forwarding
+                     Disable X11 forwarding (permitted by default).
+
+             permit-agent-forwarding
+                     Allows ssh-agent(1) forwarding.
+
+             permit-port-forwarding
+                     Allows port forwarding.
+
+             permit-pty
+                     Allows PTY allocation.
+
+             permit-user-rc
+                     Allows execution of ~/.ssh/rc by sshd(8).
+
+             permit-x11-forwarding
+                     Allows X11 forwarding.
+
+             source-address=address_list
+                     Restrict the source addresses from which the certificate
+                     is considered valid.  The address_list is a comma-
+                     separated list of one or more address/netmask pairs in
+                     CIDR format.
+
+             At present, no options are valid for host keys.
+
+     -P passphrase
+             Provides the (old) passphrase.
+
+     -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.
+
+     -q      Silence ssh-keygen.  Used by /etc/rc when creating a new key.
+
+     -R hostname
+             Removes all keys belonging to hostname from a known_hosts file.
+             This option is useful to delete hashed hosts (see the -H option
+             above).
+
+     -r hostname
+             Print the SSHFP fingerprint resource record named hostname for
+             the specified public key file.
+
+     -S start
+             Specify start point (in hex) when generating candidate moduli for
+             DH-GEX.
+
+     -s ca_key
+             Certify (sign) a public key using the specified CA key.  Please
+             see the CERTIFICATES section for details.
+
+     -T output_file
+             Test DH group exchange candidate primes (generated using the -G
+             option) for safety.
+
+     -t type
+             Specifies the type of key to create.  The possible values are
+             ``rsa1'' for protocol version 1 and ``dsa'', ``ecdsa'' or ``rsa''
+             for protocol version 2.
+
+     -V validity_interval
+             Specify a validity interval when signing a certificate.  A
+             validity interval may consist of a single time, indicating that
+             the certificate is valid beginning now and expiring at that time,
+             or may consist of two times separated by a colon to indicate an
+             explicit time interval.  The start time may be specified as a
+             date in YYYYMMDD format, a time in YYYYMMDDHHMMSS format or a
+             relative time (to the current time) consisting of a minus sign
+             followed by a relative time in the format described in the TIME
+             FORMATS section of sshd_config(5).  The end time may be specified
+             as a YYYYMMDD date, a YYYYMMDDHHMMSS time or a relative time
+             starting with a plus character.
+
+             For example: ``+52w1d'' (valid from now to 52 weeks and one day
+             from now), ``-4w:+4w'' (valid from four weeks ago to four weeks
+             from now), ``20100101123000:20110101123000'' (valid from 12:30
+             PM, January 1st, 2010 to 12:30 PM, January 1st, 2011),
+             ``-1d:20110101'' (valid from yesterday to midnight, January 1st,
+             2011).
+
+     -v      Verbose mode.  Causes ssh-keygen to print debugging messages
+             about its progress.  This is helpful for debugging moduli
+             generation.  Multiple -v options increase the verbosity.  The
+             maximum is 3.
+
+     -W generator
+             Specify desired generator when testing candidate moduli for DH-
+             GEX.
+
+     -y      This option will read a private OpenSSH format file and print an
+             OpenSSH public key to stdout.
+
+     -z serial_number
+             Specifies a serial number to be embedded in the certificate to
+             distinguish this certificate from others from the same CA.  The
+             default serial number is zero.
+
+MODULI GENERATION
+     ssh-keygen may be used to generate groups for the Diffie-Hellman Group
+     Exchange (DH-GEX) protocol.  Generating these groups is a two-step
+     process: first, candidate primes are generated using a fast, but memory
+     intensive process.  These candidate primes are then tested for
+     suitability (a CPU-intensive process).
+
+     Generation of primes is performed using the -G option.  The desired
+     length of the primes may be specified by the -b option.  For example:
+
+           # ssh-keygen -G moduli-2048.candidates -b 2048
+
+     By default, the search for primes begins at a random point in the desired
+     length range.  This may be overridden using the -S option, which
+     specifies a different start point (in hex).
+
+     Once a set of candidates have been generated, they must be tested for
+     suitability.  This may be performed using the -T option.  In this mode
+     ssh-keygen will read candidates from standard input (or a file specified
+     using the -f option).  For example:
+
+           # ssh-keygen -T moduli-2048 -f moduli-2048.candidates
+
+     By default, each candidate will be subjected to 100 primality tests.
+     This may be overridden using the -a option.  The DH generator value will
+     be chosen automatically for the prime under consideration.  If a specific
+     generator is desired, it may be requested using the -W option.  Valid
+     generator values are 2, 3, and 5.
+
+     Screened DH groups may be installed in /etc/moduli.  It is important that
+     this file contains moduli of a range of bit lengths and that both ends of
+     a connection share common moduli.
+
+CERTIFICATES
+     ssh-keygen supports signing of keys to produce certificates that may be
+     used for user or host authentication.  Certificates consist of a public
+     key, some identity information, zero or more principal (user or host)
+     names and a set of options that are signed by a Certification Authority
+     (CA) key.  Clients or servers may then trust only the CA key and verify
+     its signature on a certificate rather than trusting many user/host keys.
+     Note that OpenSSH certificates are a different, and much simpler, format
+     to the X.509 certificates used in ssl(8).
+
+     ssh-keygen supports two types of certificates: user and host.  User
+     certificates authenticate users to servers, whereas host certificates
+     authenticate server hosts to users.  To generate a user certificate:
+
+           $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
+
+     The resultant certificate will be placed in /path/to/user_key-cert.pub.
+     A host certificate requires the -h option:
+
+           $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
+
+     The host certificate will be output to /path/to/host_key-cert.pub.
+
+     It is possible to sign using a CA key stored in a PKCS#11 token by
+     providing the token library using -D and identifying the CA key by
+     providing its public half as an argument to -s:
+
+           $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id host_key.pub
+
+     In all cases, key_id is a "key identifier" that is logged by the server
+     when the certificate is used for authentication.
+
+     Certificates may be limited to be valid for a set of principal
+     (user/host) names.  By default, generated certificates are valid for all
+     users or hosts.  To generate a certificate for a specified set of
+     principals:
+
+           $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
+           $ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub
+
+     Additional limitations on the validity and use of user certificates may
+     be specified through certificate options.  A certificate option may
+     disable features of the SSH session, may be valid only when presented
+     from particular source addresses or may force the use of a specific
+     command.  For a list of valid certificate options, see the documentation
+     for the -O option above.
+
+     Finally, certificates may be defined with a validity lifetime.  The -V
+     option allows specification of certificate start and end times.  A
+     certificate that is presented at a time outside this range will not be
+     considered valid.  By default, certificates have a maximum validity
+     interval.
+
+     For certificates to be used for user or host authentication, the CA
+     public key must be trusted by sshd(8) or ssh(1).  Please refer to those
+     manual pages for details.
+
+FILES
+     ~/.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
+             ssh-keygen but it is offered as the default file for the private
+             key.  ssh(1) will read this file when a login attempt is made.
+
+     ~/.ssh/identity.pub
+             Contains the protocol version 1 RSA public key for
+             authentication.  The contents of this file should be added to
+             ~/.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.
+
+     ~/.ssh/id_dsa
+     ~/.ssh/id_ecdsa
+     ~/.ssh/id_rsa
+             Contains the protocol version 2 DSA, ECDSA or 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 128-bit AES.  This file is not
+             automatically accessed by ssh-keygen but it is offered as the
+             default file for the private key.  ssh(1) will read this file
+             when a login attempt is made.
+
+     ~/.ssh/id_dsa.pub
+     ~/.ssh/id_ecdsa.pub
+     ~/.ssh/id_rsa.pub
+             Contains the protocol version 2 DSA, ECDSA or RSA public key for
+             authentication.  The contents of this file should be added to
+             ~/.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.
+
+     /etc/moduli
+             Contains Diffie-Hellman groups used for DH-GEX.  The file format
+             is described in moduli(5).
+
+SEE ALSO
+     ssh(1), ssh-add(1), ssh-agent(1), moduli(5), sshd(8)
+
+     The Secure Shell (SSH) Public Key File Format, RFC 4716, 2006.
+
+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.
+
+OpenBSD 4.9                    October 28, 2010                    OpenBSD 4.9
diff --git a/ssh-keygen.1 b/ssh-keygen.1
new file mode 100644 (file)
index 0000000..205f741
--- /dev/null
@@ -0,0 +1,677 @@
+.\"    $OpenBSD: ssh-keygen.1,v 1.101 2010/10/28 18:33:28 jmc 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 $Mdocdate: October 28 2010 $
+.Dt SSH-KEYGEN 1
+.Os
+.Sh NAME
+.Nm ssh-keygen
+.Nd authentication key generation, management and conversion
+.Sh SYNOPSIS
+.Bk -words
+.Nm ssh-keygen
+.Op Fl q
+.Op Fl b Ar bits
+.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 m Ar key_format
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl e
+.Op Fl m Ar key_format
+.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 pkcs11
+.Nm ssh-keygen
+.Fl F Ar hostname
+.Op Fl f Ar known_hosts_file
+.Op Fl l
+.Nm ssh-keygen
+.Fl H
+.Op Fl f Ar known_hosts_file
+.Nm ssh-keygen
+.Fl R Ar hostname
+.Op Fl f Ar known_hosts_file
+.Nm ssh-keygen
+.Fl r Ar hostname
+.Op Fl f Ar input_keyfile
+.Op Fl g
+.Nm ssh-keygen
+.Fl G Ar output_file
+.Op Fl v
+.Op Fl b Ar bits
+.Op Fl M Ar memory
+.Op Fl S Ar start_point
+.Nm ssh-keygen
+.Fl T Ar output_file
+.Fl f Ar input_file
+.Op Fl v
+.Op Fl a Ar num_trials
+.Op Fl W Ar generator
+.Nm ssh-keygen
+.Fl s Ar ca_key
+.Fl I Ar certificate_identity
+.Op Fl h
+.Op Fl n Ar principals
+.Op Fl O Ar option
+.Op Fl V Ar validity_interval
+.Op Fl z Ar serial_number
+.Ar
+.Nm ssh-keygen
+.Fl L
+.Op Fl f Ar input_keyfile
+.Ek
+.Sh DESCRIPTION
+.Nm
+generates, manages and converts authentication keys for
+.Xr ssh 1 .
+.Nm
+can create RSA keys for use by SSH protocol version 1 and DSA, ECDSA or RSA
+keys for use by SSH protocol version 2.
+The type of key to be generated is specified with the
+.Fl t
+option.
+If invoked without any arguments,
+.Nm
+will generate an RSA key for use in SSH protocol 2 connections.
+.Pp
+.Nm
+is also used to generate groups for use in Diffie-Hellman group
+exchange (DH-GEX).
+See the
+.Sx MODULI GENERATION
+section for details.
+.Pp
+Normally each user wishing to use SSH
+with public key authentication runs this once to create the authentication
+key in
+.Pa ~/.ssh/identity ,
+.Pa ~/.ssh/id_ecdsa ,
+.Pa ~/.ssh/id_dsa
+or
+.Pa ~/.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.
+A passphrase is similar to a password, except it can be a phrase with a
+series of words, punctuation, numbers, whitespace, or any string of
+characters you want.
+Good passphrases are 10-30 characters long, are
+not simple sentences or otherwise easily guessable (English
+prose has only 1-2 bits of entropy per character, and provides very bad
+passphrases), and contain a mix of upper and lowercase letters,
+numbers, and non-alphanumeric characters.
+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 a Ar trials
+Specifies the number of primality tests to perform when screening DH-GEX
+candidates using the
+.Fl T
+command.
+.It Fl B
+Show the bubblebabble digest of specified private or public key file.
+.It Fl b Ar bits
+Specifies the number of bits in the key to create.
+For RSA keys, the minimum size is 768 bits and the default is 2048 bits.
+Generally, 2048 bits is considered sufficient.
+DSA keys must be exactly 1024 bits as specified by FIPS 186-2.
+.It Fl C Ar comment
+Provides a new comment.
+.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 D Ar pkcs11
+Download the RSA public keys provided by the PKCS#11 shared library
+.Ar pkcs11 .
+When used in combination with
+.Fl s ,
+this option indicates that a CA key resides in a PKCS#11 token (see the
+.Sx CERTIFICATES
+section for details).
+.It Fl e
+This option will read a private or public OpenSSH key file and
+print to stdout the key in one of the formats specified by the
+.Fl m
+option.
+The default export format is
+.Dq RFC4716 .
+This option allows exporting OpenSSH keys for use by other programs, including
+several commercial SSH implementations.
+.It Fl F Ar hostname
+Search for the specified
+.Ar hostname
+in a
+.Pa known_hosts
+file, listing any occurrences found.
+This option is useful to find hashed host names or addresses and may also be
+used in conjunction with the
+.Fl H
+option to print found keys in a hashed format.
+.It Fl f Ar filename
+Specifies the filename of the key file.
+.It Fl G Ar output_file
+Generate candidate primes for DH-GEX.
+These primes must be screened for
+safety (using the
+.Fl T
+option) before use.
+.It Fl g
+Use generic DNS format when printing fingerprint resource records using the
+.Fl r
+command.
+.It Fl H
+Hash a
+.Pa known_hosts
+file.
+This replaces all hostnames and addresses with hashed representations
+within the specified file; the original content is moved to a file with
+a .old suffix.
+These hashes may be used normally by
+.Nm ssh
+and
+.Nm sshd ,
+but they do not reveal identifying information should the file's contents
+be disclosed.
+This option will not modify existing hashed hostnames and is therefore safe
+to use on files that mix hashed and non-hashed names.
+.It Fl h
+When signing a key, create a host certificate instead of a user
+certificate.
+Please see the
+.Sx CERTIFICATES
+section for details.
+.It Fl I Ar certificate_identity
+Specify the key identity when signing a public key.
+Please see the
+.Sx CERTIFICATES
+section for details.
+.It Fl i
+This option will read an unencrypted private (or public) key file
+in the format specified by the
+.Fl m
+option and print an OpenSSH compatible private
+(or public) key to stdout.
+This option allows importing keys from other software, including several
+commercial SSH implementations.
+The default import format is
+.Dq RFC4716 .
+.It Fl L
+Prints the contents of a certificate.
+.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.
+If combined with
+.Fl v ,
+an ASCII art representation of the key is supplied with the fingerprint.
+.It Fl M Ar memory
+Specify the amount of memory to use (in megabytes) when generating
+candidate moduli for DH-GEX.
+.It Fl m Ar key_format
+Specify a key format for the
+.Fl i
+(import) or
+.Fl e
+(export) conversion options.
+The supported key formats are:
+.Dq RFC4716
+(RFC 4716/SSH2 public or private key),
+.Dq PKCS8
+(PEM PKCS8 public key)
+or
+.Dq PEM
+(PEM public key).
+The default conversion format is
+.Dq RFC4716 .
+.It Fl N Ar new_passphrase
+Provides the new passphrase.
+.It Fl n Ar principals
+Specify one or more principals (user or host names) to be included in
+a certificate when signing a key.
+Multiple principals may be specified, separated by commas.
+Please see the
+.Sx CERTIFICATES
+section for details.
+.It Fl O Ar option
+Specify a certificate option when signing a key.
+This option may be specified multiple times.
+Please see the
+.Sx CERTIFICATES
+section for details.
+The options that are valid for user certificates are:
+.Bl -tag -width Ds
+.It Ic clear
+Clear all enabled permissions.
+This is useful for clearing the default set of permissions so permissions may
+be added individually.
+.It Ic force-command Ns = Ns Ar command
+Forces the execution of
+.Ar command
+instead of any shell or command specified by the user when
+the certificate is used for authentication.
+.It Ic no-agent-forwarding
+Disable
+.Xr ssh-agent 1
+forwarding (permitted by default).
+.It Ic no-port-forwarding
+Disable port forwarding (permitted by default).
+.It Ic no-pty
+Disable PTY allocation (permitted by default).
+.It Ic no-user-rc
+Disable execution of
+.Pa ~/.ssh/rc
+by
+.Xr sshd 8
+(permitted by default).
+.It Ic no-x11-forwarding
+Disable X11 forwarding (permitted by default).
+.It Ic permit-agent-forwarding
+Allows
+.Xr ssh-agent 1
+forwarding.
+.It Ic permit-port-forwarding
+Allows port forwarding.
+.It Ic permit-pty
+Allows PTY allocation.
+.It Ic permit-user-rc
+Allows execution of
+.Pa ~/.ssh/rc
+by
+.Xr sshd 8 .
+.It Ic permit-x11-forwarding
+Allows X11 forwarding.
+.It Ic source-address Ns = Ns Ar address_list
+Restrict the source addresses from which the certificate is considered valid.
+The
+.Ar address_list
+is a comma-separated list of one or more address/netmask pairs in CIDR
+format.
+.El
+.Pp
+At present, no options are valid for host keys.
+.It Fl P Ar passphrase
+Provides the (old) passphrase.
+.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 R Ar hostname
+Removes all keys belonging to
+.Ar hostname
+from a
+.Pa known_hosts
+file.
+This option is useful to delete hashed hosts (see the
+.Fl H
+option above).
+.It Fl r Ar hostname
+Print the SSHFP fingerprint resource record named
+.Ar hostname
+for the specified public key file.
+.It Fl S Ar start
+Specify start point (in hex) when generating candidate moduli for DH-GEX.
+.It Fl s Ar ca_key
+Certify (sign) a public key using the specified CA key.
+Please see the
+.Sx CERTIFICATES
+section for details.
+.It Fl T Ar output_file
+Test DH group exchange candidate primes (generated using the
+.Fl G
+option) for safety.
+.It Fl t Ar type
+Specifies the type of key to create.
+The possible values are
+.Dq rsa1
+for protocol version 1 and
+.Dq dsa ,
+.Dq ecdsa
+or
+.Dq rsa
+for protocol version 2.
+.It Fl V Ar validity_interval
+Specify a validity interval when signing a certificate.
+A validity interval may consist of a single time, indicating that the
+certificate is valid beginning now and expiring at that time, or may consist
+of two times separated by a colon to indicate an explicit time interval.
+The start time may be specified as a date in YYYYMMDD format, a time
+in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting
+of a minus sign followed by a relative time in the format described in the
+.Sx TIME FORMATS
+section of
+.Xr sshd_config 5 .
+The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or
+a relative time starting with a plus character.
+.Pp
+For example:
+.Dq +52w1d
+(valid from now to 52 weeks and one day from now),
+.Dq -4w:+4w
+(valid from four weeks ago to four weeks from now),
+.Dq 20100101123000:20110101123000
+(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011),
+.Dq -1d:20110101
+(valid from yesterday to midnight, January 1st, 2011).
+.It Fl v
+Verbose mode.
+Causes
+.Nm
+to print debugging messages about its progress.
+This is helpful for debugging moduli generation.
+Multiple
+.Fl v
+options increase the verbosity.
+The maximum is 3.
+.It Fl W Ar generator
+Specify desired generator when testing candidate moduli for DH-GEX.
+.It Fl y
+This option will read a private
+OpenSSH format file and print an OpenSSH public key to stdout.
+.It Fl z Ar serial_number
+Specifies a serial number to be embedded in the certificate to distinguish
+this certificate from others from the same CA.
+The default serial number is zero.
+.El
+.Sh MODULI GENERATION
+.Nm
+may be used to generate groups for the Diffie-Hellman Group Exchange
+(DH-GEX) protocol.
+Generating these groups is a two-step process: first, candidate
+primes are generated using a fast, but memory intensive process.
+These candidate primes are then tested for suitability (a CPU-intensive
+process).
+.Pp
+Generation of primes is performed using the
+.Fl G
+option.
+The desired length of the primes may be specified by the
+.Fl b
+option.
+For example:
+.Pp
+.Dl # ssh-keygen -G moduli-2048.candidates -b 2048
+.Pp
+By default, the search for primes begins at a random point in the
+desired length range.
+This may be overridden using the
+.Fl S
+option, which specifies a different start point (in hex).
+.Pp
+Once a set of candidates have been generated, they must be tested for
+suitability.
+This may be performed using the
+.Fl T
+option.
+In this mode
+.Nm
+will read candidates from standard input (or a file specified using the
+.Fl f
+option).
+For example:
+.Pp
+.Dl # ssh-keygen -T moduli-2048 -f moduli-2048.candidates
+.Pp
+By default, each candidate will be subjected to 100 primality tests.
+This may be overridden using the
+.Fl a
+option.
+The DH generator value will be chosen automatically for the
+prime under consideration.
+If a specific generator is desired, it may be requested using the
+.Fl W
+option.
+Valid generator values are 2, 3, and 5.
+.Pp
+Screened DH groups may be installed in
+.Pa /etc/moduli .
+It is important that this file contains moduli of a range of bit lengths and
+that both ends of a connection share common moduli.
+.Sh CERTIFICATES
+.Nm
+supports signing of keys to produce certificates that may be used for
+user or host authentication.
+Certificates consist of a public key, some identity information, zero or
+more principal (user or host) names and a set of options that
+are signed by a Certification Authority (CA) key.
+Clients or servers may then trust only the CA key and verify its signature
+on a certificate rather than trusting many user/host keys.
+Note that OpenSSH certificates are a different, and much simpler, format to
+the X.509 certificates used in
+.Xr ssl 8 .
+.Pp
+.Nm
+supports two types of certificates: user and host.
+User certificates authenticate users to servers, whereas host certificates
+authenticate server hosts to users.
+To generate a user certificate:
+.Pp
+.Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
+.Pp
+The resultant certificate will be placed in
+.Pa /path/to/user_key-cert.pub .
+A host certificate requires the
+.Fl h
+option:
+.Pp
+.Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
+.Pp
+The host certificate will be output to
+.Pa /path/to/host_key-cert.pub .
+.Pp
+It is possible to sign using a CA key stored in a PKCS#11 token by
+providing the token library using
+.Fl D
+and identifying the CA key by providing its public half as an argument
+to
+.Fl s :
+.Pp
+.Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id host_key.pub
+.Pp
+In all cases,
+.Ar key_id
+is a "key identifier" that is logged by the server when the certificate
+is used for authentication.
+.Pp
+Certificates may be limited to be valid for a set of principal (user/host)
+names.
+By default, generated certificates are valid for all users or hosts.
+To generate a certificate for a specified set of principals:
+.Pp
+.Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
+.Dl "$ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub"
+.Pp
+Additional limitations on the validity and use of user certificates may
+be specified through certificate options.
+A certificate option may disable features of the SSH session, may be
+valid only when presented from particular source addresses or may
+force the use of a specific command.
+For a list of valid certificate options, see the documentation for the
+.Fl O
+option above.
+.Pp
+Finally, certificates may be defined with a validity lifetime.
+The
+.Fl V
+option allows specification of certificate start and end times.
+A certificate that is presented at a time outside this range will not be
+considered valid.
+By default, certificates have a maximum validity interval.
+.Pp
+For certificates to be used for user or host authentication, the CA
+public key must be trusted by
+.Xr sshd 8
+or
+.Xr ssh 1 .
+Please refer to those manual pages for details.
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It Pa ~/.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.
+.Pp
+.It Pa ~/.ssh/identity.pub
+Contains the protocol version 1 RSA public key for authentication.
+The contents of this file should be added to
+.Pa ~/.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.
+.Pp
+.It Pa ~/.ssh/id_dsa
+.It Pa ~/.ssh/id_ecdsa
+.It Pa ~/.ssh/id_rsa
+Contains the protocol version 2 DSA, ECDSA or 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 128-bit AES.
+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.
+.Pp
+.It Pa ~/.ssh/id_dsa.pub
+.It Pa ~/.ssh/id_ecdsa.pub
+.It Pa ~/.ssh/id_rsa.pub
+Contains the protocol version 2 DSA, ECDSA or RSA public key for authentication.
+The contents of this file should be added to
+.Pa ~/.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.
+.Pp
+.It Pa /etc/moduli
+Contains Diffie-Hellman groups used for DH-GEX.
+The file format is described in
+.Xr moduli 5 .
+.El
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr moduli 5 ,
+.Xr sshd 8
+.Rs
+.%R RFC 4716
+.%T "The Secure Shell (SSH) Public Key File Format"
+.%D 2006
+.Re
+.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.
diff --git a/ssh-keygen.c b/ssh-keygen.c
new file mode 100644 (file)
index 0000000..c95e4ab
--- /dev/null
@@ -0,0 +1,2267 @@
+/* $OpenBSD: ssh-keygen.c,v 1.205 2011/01/11 06:13:10 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include "openbsd-compat/openssl-compat.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "rsa.h"
+#include "authfile.h"
+#include "uuencode.h"
+#include "buffer.h"
+#include "pathnames.h"
+#include "log.h"
+#include "misc.h"
+#include "match.h"
+#include "hostfile.h"
+#include "dns.h"
+#include "ssh2.h"
+
+#ifdef ENABLE_PKCS11
+#include "ssh-pkcs11.h"
+#endif
+
+/* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
+#define DEFAULT_BITS           2048
+#define DEFAULT_BITS_DSA       1024
+#define DEFAULT_BITS_ECDSA     256
+u_int32_t bits = 0;
+
+/*
+ * 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;
+
+int log_level = SYSLOG_LEVEL_INFO;
+
+/* Flag indicating that we want to hash a known_hosts file */
+int hash_hosts = 0;
+/* Flag indicating that we want lookup a host in known_hosts file */
+int find_host = 0;
+/* Flag indicating that we want to delete a host from a known_hosts file */
+int delete_host = 0;
+
+/* Flag indicating that we want to show the contents of a certificate */
+int show_cert = 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;
+
+/* Path to CA key when certifying keys. */
+char *ca_key_path = NULL;
+
+/* Certificate serial number */
+long long cert_serial = 0;
+
+/* Key type when certifying */
+u_int cert_key_type = SSH2_CERT_TYPE_USER;
+
+/* "key ID" of signed key */
+char *cert_key_id = NULL;
+
+/* Comma-separated list of principal names for certifying keys */
+char *cert_principals = NULL;
+
+/* Validity period for certificates */
+u_int64_t cert_valid_from = 0;
+u_int64_t cert_valid_to = ~0ULL;
+
+/* Certificate options */
+#define CERTOPT_X_FWD  (1)
+#define CERTOPT_AGENT_FWD      (1<<1)
+#define CERTOPT_PORT_FWD       (1<<2)
+#define CERTOPT_PTY            (1<<3)
+#define CERTOPT_USER_RC        (1<<4)
+#define CERTOPT_DEFAULT        (CERTOPT_X_FWD|CERTOPT_AGENT_FWD| \
+                        CERTOPT_PORT_FWD|CERTOPT_PTY|CERTOPT_USER_RC)
+u_int32_t certflags_flags = CERTOPT_DEFAULT;
+char *certflags_command = NULL;
+char *certflags_src_addr = NULL;
+
+/* Conversion to/from various formats */
+int convert_to = 0;
+int convert_from = 0;
+enum {
+       FMT_RFC4716,
+       FMT_PKCS8,
+       FMT_PEM
+} convert_format = FMT_RFC4716;
+int print_public = 0;
+int print_generic = 0;
+
+char *key_type_name = NULL;
+
+/* Load key from this PKCS#11 provider */
+char *pkcs11provider = NULL;
+
+/* argv0 */
+extern char *__progname;
+
+char hostname[MAXHOSTNAMELEN];
+
+/* moduli.c */
+int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
+int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
+
+static void
+ask_filename(struct passwd *pw, const char *prompt)
+{
+       char buf[1024];
+       char *name = NULL;
+
+       if (key_type_name == NULL)
+               name = _PATH_SSH_CLIENT_ID_RSA;
+       else {
+               switch (key_type_from_name(key_type_name)) {
+               case KEY_RSA1:
+                       name = _PATH_SSH_CLIENT_IDENTITY;
+                       break;
+               case KEY_DSA_CERT:
+               case KEY_DSA_CERT_V00:
+               case KEY_DSA:
+                       name = _PATH_SSH_CLIENT_ID_DSA;
+                       break;
+#ifdef OPENSSL_HAS_ECC
+               case KEY_ECDSA_CERT:
+               case KEY_ECDSA:
+                       name = _PATH_SSH_CLIENT_ID_ECDSA;
+                       break;
+#endif
+               case KEY_RSA_CERT:
+               case KEY_RSA_CERT_V00:
+               case KEY_RSA:
+                       name = _PATH_SSH_CLIENT_ID_RSA;
+                       break;
+               default:
+                       fprintf(stderr, "bad key type\n");
+                       exit(1);
+                       break;
+               }
+       }
+       snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
+       fprintf(stderr, "%s (%s): ", prompt, identity_file);
+       if (fgets(buf, sizeof(buf), stdin) == NULL)
+               exit(1);
+       buf[strcspn(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)
+{
+       u_int len;
+       u_char *blob;
+       char comment[61];
+
+       if (key_to_blob(k, &blob, &len) <= 0) {
+               fprintf(stderr, "key_to_blob failed\n");
+               exit(1);
+       }
+       /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */
+       snprintf(comment, sizeof(comment),
+           "%u-bit %s, converted by %s@%s from OpenSSH",
+           key_size(k), key_type(k),
+           pw->pw_name, hostname);
+
+       fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
+       fprintf(stdout, "Comment: \"%s\"\n", comment);
+       dump_base64(stdout, blob, len);
+       fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
+       key_free(k);
+       xfree(blob);
+       exit(0);
+}
+
+static void
+do_convert_to_pkcs8(Key *k)
+{
+       switch (key_type_plain(k->type)) {
+       case KEY_RSA:
+               if (!PEM_write_RSA_PUBKEY(stdout, k->rsa))
+                       fatal("PEM_write_RSA_PUBKEY failed");
+               break;
+       case KEY_DSA:
+               if (!PEM_write_DSA_PUBKEY(stdout, k->dsa))
+                       fatal("PEM_write_DSA_PUBKEY failed");
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case KEY_ECDSA:
+               if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
+                       fatal("PEM_write_EC_PUBKEY failed");
+               break;
+#endif
+       default:
+               fatal("%s: unsupported key type %s", __func__, key_type(k));
+       }
+       exit(0);
+}
+
+static void
+do_convert_to_pem(Key *k)
+{
+       switch (key_type_plain(k->type)) {
+       case KEY_RSA:
+               if (!PEM_write_RSAPublicKey(stdout, k->rsa))
+                       fatal("PEM_write_RSAPublicKey failed");
+               break;
+#if notyet /* OpenSSH 0.9.8 lacks this function */
+       case KEY_DSA:
+               if (!PEM_write_DSAPublicKey(stdout, k->dsa))
+                       fatal("PEM_write_DSAPublicKey failed");
+               break;
+#endif
+       /* XXX ECDSA? */
+       default:
+               fatal("%s: unsupported key type %s", __func__, key_type(k));
+       }
+       exit(0);
+}
+
+static void
+do_convert_to(struct passwd *pw)
+{
+       Key *k;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+       if ((k = key_load_public(identity_file, NULL)) == NULL) {
+               if ((k = load_identity(identity_file)) == NULL) {
+                       fprintf(stderr, "load failed\n");
+                       exit(1);
+               }
+       }
+       if (k->type == KEY_RSA1) {
+               fprintf(stderr, "version 1 keys are not supported\n");
+               exit(1);
+       }
+
+       switch (convert_format) {
+       case FMT_RFC4716:
+               do_convert_to_ssh2(pw, k);
+               break;
+       case FMT_PKCS8:
+               do_convert_to_pkcs8(k);
+               break;
+       case FMT_PEM:
+               do_convert_to_pem(k);
+               break;
+       default:
+               fatal("%s: unknown key format %d", __func__, convert_format);
+       }
+       exit(0);
+}
+
+static void
+buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
+{
+       u_int bignum_bits = buffer_get_int(b);
+       u_int bytes = (bignum_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));
+       if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
+               fatal("buffer_get_bignum_bits: BN_bin2bn failed");
+       buffer_consume(b, bytes);
+}
+
+static Key *
+do_convert_private_ssh2_from_blob(u_char *blob, u_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 {
+               buffer_free(&b);
+               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 int
+get_line(FILE *fp, char *line, size_t len)
+{
+       int c;
+       size_t pos = 0;
+
+       line[0] = '\0';
+       while ((c = fgetc(fp)) != EOF) {
+               if (pos >= len - 1) {
+                       fprintf(stderr, "input line too long.\n");
+                       exit(1);
+               }
+               switch (c) {
+               case '\r':
+                       c = fgetc(fp);
+                       if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
+                               fprintf(stderr, "unget: %s\n", strerror(errno));
+                               exit(1);
+                       }
+                       return pos;
+               case '\n':
+                       return pos;
+               }
+               line[pos++] = c;
+               line[pos] = '\0';
+       }
+       /* We reached EOF */
+       return -1;
+}
+
+static void
+do_convert_from_ssh2(struct passwd *pw, Key **k, int *private)
+{
+       int blen;
+       u_int len;
+       char line[1024];
+       u_char blob[8096];
+       char encoded[8096];
+       int escaped = 0;
+       FILE *fp;
+
+       if ((fp = fopen(identity_file, "r")) == NULL)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+       encoded[0] = '\0';
+       while ((blen = get_line(fp, line, sizeof(line))) != -1) {
+               if (line[blen - 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;
+               }
+               strlcat(encoded, line, sizeof(encoded));
+       }
+       len = strlen(encoded);
+       if (((len % 4) == 3) &&
+           (encoded[len-1] == '=') &&
+           (encoded[len-2] == '=') &&
+           (encoded[len-3] == '='))
+               encoded[len-3] = '\0';
+       blen = uudecode(encoded, 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);
+       }
+       fclose(fp);
+}
+
+static void
+do_convert_from_pkcs8(Key **k, int *private)
+{
+       EVP_PKEY *pubkey;
+       FILE *fp;
+
+       if ((fp = fopen(identity_file, "r")) == NULL)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+       if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
+               fatal("%s: %s is not a recognised public key format", __func__,
+                   identity_file);
+       }
+       fclose(fp);
+       switch (EVP_PKEY_type(pubkey->type)) {
+       case EVP_PKEY_RSA:
+               *k = key_new(KEY_UNSPEC);
+               (*k)->type = KEY_RSA;
+               (*k)->rsa = EVP_PKEY_get1_RSA(pubkey);
+               break;
+       case EVP_PKEY_DSA:
+               *k = key_new(KEY_UNSPEC);
+               (*k)->type = KEY_DSA;
+               (*k)->dsa = EVP_PKEY_get1_DSA(pubkey);
+               break;
+#ifdef OPENSSL_HAS_ECC
+       case EVP_PKEY_EC:
+               *k = key_new(KEY_UNSPEC);
+               (*k)->type = KEY_ECDSA;
+               (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey);
+               (*k)->ecdsa_nid = key_ecdsa_key_to_nid((*k)->ecdsa);
+               break;
+#endif
+       default:
+               fatal("%s: unsupported pubkey type %d", __func__,
+                   EVP_PKEY_type(pubkey->type));
+       }
+       EVP_PKEY_free(pubkey);
+       return;
+}
+
+static void
+do_convert_from_pem(Key **k, int *private)
+{
+       FILE *fp;
+       RSA *rsa;
+#ifdef notyet
+       DSA *dsa;
+#endif
+
+       if ((fp = fopen(identity_file, "r")) == NULL)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+       if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) {
+               *k = key_new(KEY_UNSPEC);
+               (*k)->type = KEY_RSA;
+               (*k)->rsa = rsa;
+               fclose(fp);
+               return;
+       }
+#if notyet /* OpenSSH 0.9.8 lacks this function */
+       rewind(fp);
+       if ((dsa = PEM_read_DSAPublicKey(fp, NULL, NULL, NULL)) != NULL) {
+               *k = key_new(KEY_UNSPEC);
+               (*k)->type = KEY_DSA;
+               (*k)->dsa = dsa;
+               fclose(fp);
+               return;
+       }
+       /* XXX ECDSA */
+#endif
+       fatal("%s: unrecognised raw private key format", __func__);
+}
+
+static void
+do_convert_from(struct passwd *pw)
+{
+       Key *k = NULL;
+       int private = 0, ok = 0;
+       struct stat st;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+
+       switch (convert_format) {
+       case FMT_RFC4716:
+               do_convert_from_ssh2(pw, &k, &private);
+               break;
+       case FMT_PKCS8:
+               do_convert_from_pkcs8(&k, &private);
+               break;
+       case FMT_PEM:
+               do_convert_from_pem(&k, &private);
+               break;
+       default:
+               fatal("%s: unknown key format %d", __func__, convert_format);
+       }
+
+       if (!private)
+               ok = key_write(k, stdout);
+               if (ok)
+                       fprintf(stdout, "\n");
+       else {
+               switch (k->type) {
+               case KEY_DSA:
+                       ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL,
+                           NULL, 0, NULL, NULL);
+                       break;
+#ifdef OPENSSL_HAS_ECC
+               case KEY_ECDSA:
+                       ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL,
+                           NULL, 0, NULL, NULL);
+                       break;
+#endif
+               case KEY_RSA:
+                       ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL,
+                           NULL, 0, NULL, NULL);
+                       break;
+               default:
+                       fatal("%s: unsupported key type %s", __func__,
+                           key_type(k));
+               }
+       }
+
+       if (!ok) {
+               fprintf(stderr, "key write failed\n");
+               exit(1);
+       }
+       key_free(k);
+       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);
+}
+
+static void
+do_download(struct passwd *pw)
+{
+#ifdef ENABLE_PKCS11
+       Key **keys = NULL;
+       int i, nkeys;
+
+       pkcs11_init(0);
+       nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
+       if (nkeys <= 0)
+               fatal("cannot read public key from pkcs11");
+       for (i = 0; i < nkeys; i++) {
+               key_write(keys[i], stdout);
+               key_free(keys[i]);
+               fprintf(stdout, "\n");
+       }
+       xfree(keys);
+       pkcs11_terminate();
+       exit(0);
+#else
+       fatal("no pkcs11 support");
+#endif /* ENABLE_PKCS11 */
+}
+
+static void
+do_fingerprint(struct passwd *pw)
+{
+       FILE *f;
+       Key *public;
+       char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
+       int i, skip = 0, num = 0, invalid = 1;
+       enum fp_rep rep;
+       enum fp_type fptype;
+       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);
+               ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+               printf("%u %s %s (%s)\n", key_size(public), fp, comment,
+                   key_type(public));
+               if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                       printf("%s\n", ra);
+               key_free(public);
+               xfree(comment);
+               xfree(ra);
+               xfree(fp);
+               exit(0);
+       }
+       if (comment) {
+               xfree(comment);
+               comment = NULL;
+       }
+
+       if ((f = fopen(identity_file, "r")) == NULL)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+
+       while (fgets(line, sizeof(line), f)) {
+               if ((cp = strchr(line, '\n')) == NULL) {
+                       error("line %d too long: %.40s...",
+                           num + 1, line);
+                       skip = 1;
+                       continue;
+               }
+               num++;
+               if (skip) {
+                       skip = 0;
+                       continue;
+               }
+               *cp = '\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);
+               ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+               printf("%u %s %s (%s)\n", key_size(public), fp,
+                   comment ? comment : "no comment", key_type(public));
+               if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                       printf("%s\n", ra);
+               xfree(ra);
+               xfree(fp);
+               key_free(public);
+               invalid = 0;
+       }
+       fclose(f);
+
+       if (invalid) {
+               printf("%s is not a public key file.\n", identity_file);
+               exit(1);
+       }
+       exit(0);
+}
+
+static void
+printhost(FILE *f, const char *name, Key *public, int ca, int hash)
+{
+       if (print_fingerprint) {
+               enum fp_rep rep;
+               enum fp_type fptype;
+               char *fp, *ra;
+
+               fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
+               rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+               fp = key_fingerprint(public, fptype, rep);
+               ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+               printf("%u %s %s (%s)\n", key_size(public), fp, name,
+                   key_type(public));
+               if (log_level >= SYSLOG_LEVEL_VERBOSE)
+                       printf("%s\n", ra);
+               xfree(ra);
+               xfree(fp);
+       } else {
+               if (hash && (name = host_hash(name, NULL, 0)) == NULL)
+                       fatal("hash_host failed");
+               fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name);
+               if (!key_write(public, f))
+                       fatal("key_write failed");
+               fprintf(f, "\n");
+       }
+}
+
+static void
+do_known_hosts(struct passwd *pw, const char *name)
+{
+       FILE *in, *out = stdout;
+       Key *pub;
+       char *cp, *cp2, *kp, *kp2;
+       char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
+       int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
+       int ca;
+
+       if (!have_identity) {
+               cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
+               if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
+                   sizeof(identity_file))
+                       fatal("Specified known hosts path too long");
+               xfree(cp);
+               have_identity = 1;
+       }
+       if ((in = fopen(identity_file, "r")) == NULL)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+
+       /*
+        * Find hosts goes to stdout, hash and deletions happen in-place
+        * A corner case is ssh-keygen -HF foo, which should go to stdout
+        */
+       if (!find_host && (hash_hosts || delete_host)) {
+               if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
+                   strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
+                   strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
+                   strlcat(old, ".old", sizeof(old)) >= sizeof(old))
+                       fatal("known_hosts path too long");
+               umask(077);
+               if ((c = mkstemp(tmp)) == -1)
+                       fatal("mkstemp: %s", strerror(errno));
+               if ((out = fdopen(c, "w")) == NULL) {
+                       c = errno;
+                       unlink(tmp);
+                       fatal("fdopen: %s", strerror(c));
+               }
+               inplace = 1;
+       }
+
+       while (fgets(line, sizeof(line), in)) {
+               if ((cp = strchr(line, '\n')) == NULL) {
+                       error("line %d too long: %.40s...", num + 1, line);
+                       skip = 1;
+                       invalid = 1;
+                       continue;
+               }
+               num++;
+               if (skip) {
+                       skip = 0;
+                       continue;
+               }
+               *cp = '\0';
+
+               /* Skip leading whitespace, empty and comment lines. */
+               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+                       ;
+               if (!*cp || *cp == '\n' || *cp == '#') {
+                       if (inplace)
+                               fprintf(out, "%s\n", cp);
+                       continue;
+               }
+               /* Check whether this is a CA key */
+               if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 &&
+                   (cp[sizeof(CA_MARKER) - 1] == ' ' ||
+                   cp[sizeof(CA_MARKER) - 1] == '\t')) {
+                       ca = 1;
+                       cp += sizeof(CA_MARKER);
+               } else
+                       ca = 0;
+
+               /* Find the end of the host name portion. */
+               for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
+                       ;
+
+               if (*kp == '\0' || *(kp + 1) == '\0') {
+                       error("line %d missing key: %.40s...",
+                           num, line);
+                       invalid = 1;
+                       continue;
+               }
+               *kp++ = '\0';
+               kp2 = kp;
+
+               pub = key_new(KEY_RSA1);
+               if (key_read(pub, &kp) != 1) {
+                       kp = kp2;
+                       key_free(pub);
+                       pub = key_new(KEY_UNSPEC);
+                       if (key_read(pub, &kp) != 1) {
+                               error("line %d invalid key: %.40s...",
+                                   num, line);
+                               key_free(pub);
+                               invalid = 1;
+                               continue;
+                       }
+               }
+
+               if (*cp == HASH_DELIM) {
+                       if (find_host || delete_host) {
+                               cp2 = host_hash(name, cp, strlen(cp));
+                               if (cp2 == NULL) {
+                                       error("line %d: invalid hashed "
+                                           "name: %.64s...", num, line);
+                                       invalid = 1;
+                                       continue;
+                               }
+                               c = (strcmp(cp2, cp) == 0);
+                               if (find_host && c) {
+                                       printf("# Host %s found: "
+                                           "line %d type %s%s\n", name,
+                                           num, key_type(pub),
+                                           ca ? " (CA key)" : "");
+                                       printhost(out, cp, pub, ca, 0);
+                               }
+                               if (delete_host && !c && !ca)
+                                       printhost(out, cp, pub, ca, 0);
+                       } else if (hash_hosts)
+                               printhost(out, cp, pub, ca, 0);
+               } else {
+                       if (find_host || delete_host) {
+                               c = (match_hostname(name, cp,
+                                   strlen(cp)) == 1);
+                               if (find_host && c) {
+                                       printf("# Host %s found: "
+                                           "line %d type %s%s\n", name,
+                                           num, key_type(pub),
+                                           ca ? " (CA key)" : "");
+                                       printhost(out, name, pub,
+                                           ca, hash_hosts && !ca);
+                               }
+                               if (delete_host && !c && !ca)
+                                       printhost(out, cp, pub, ca, 0);
+                       } else if (hash_hosts) {
+                               for (cp2 = strsep(&cp, ",");
+                                   cp2 != NULL && *cp2 != '\0';
+                                   cp2 = strsep(&cp, ",")) {
+                                       if (ca) {
+                                               fprintf(stderr, "Warning: "
+                                                   "ignoring CA key for host: "
+                                                   "%.64s\n", cp2);
+                                               printhost(out, cp2, pub, ca, 0);
+                                       } else if (strcspn(cp2, "*?!") !=
+                                           strlen(cp2)) {
+                                               fprintf(stderr, "Warning: "
+                                                   "ignoring host name with "
+                                                   "metacharacters: %.64s\n",
+                                                   cp2);
+                                               printhost(out, cp2, pub, ca, 0);
+                                       } else
+                                               printhost(out, cp2, pub, ca, 1);
+                               }
+                               has_unhashed = 1;
+                       }
+               }
+               key_free(pub);
+       }
+       fclose(in);
+
+       if (invalid) {
+               fprintf(stderr, "%s is not a valid known_hosts file.\n",
+                   identity_file);
+               if (inplace) {
+                       fprintf(stderr, "Not replacing existing known_hosts "
+                           "file because of errors\n");
+                       fclose(out);
+                       unlink(tmp);
+               }
+               exit(1);
+       }
+
+       if (inplace) {
+               fclose(out);
+
+               /* Backup existing file */
+               if (unlink(old) == -1 && errno != ENOENT)
+                       fatal("unlink %.100s: %s", old, strerror(errno));
+               if (link(identity_file, old) == -1)
+                       fatal("link %.100s to %.100s: %s", identity_file, old,
+                           strerror(errno));
+               /* Move new one into place */
+               if (rename(tmp, identity_file) == -1) {
+                       error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
+                           strerror(errno));
+                       unlink(tmp);
+                       unlink(old);
+                       exit(1);
+               }
+
+               fprintf(stderr, "%s updated.\n", identity_file);
+               fprintf(stderr, "Original contents retained as %s\n", old);
+               if (has_unhashed) {
+                       fprintf(stderr, "WARNING: %s contains unhashed "
+                           "entries\n", old);
+                       fprintf(stderr, "Delete this file to ensure privacy "
+                           "of hostnames\n");
+               }
+       }
+
+       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);
+}
+
+/*
+ * Print the SSHFP RR.
+ */
+static int
+do_print_resource_record(struct passwd *pw, char *fname, char *hname)
+{
+       Key *public;
+       char *comment = NULL;
+       struct stat st;
+
+       if (fname == NULL)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(fname, &st) < 0) {
+               if (errno == ENOENT)
+                       return 0;
+               perror(fname);
+               exit(1);
+       }
+       public = key_load_public(fname, &comment);
+       if (public != NULL) {
+               export_dns_rr(hname, public, stdout, print_generic);
+               key_free(public);
+               xfree(comment);
+               return 1;
+       }
+       if (comment)
+               xfree(comment);
+
+       printf("failed to read v2 public key from %s.\n", fname);
+       exit(1);
+}
+
+/*
+ * 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);
+               }
+               new_comment[strcspn(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\n", identity_file);
+               exit(1);
+       }
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed\n");
+       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 const char *
+fmt_validity(u_int64_t valid_from, u_int64_t valid_to)
+{
+       char from[32], to[32];
+       static char ret[64];
+       time_t tt;
+       struct tm *tm;
+
+       *from = *to = '\0';
+       if (valid_from == 0 && valid_to == 0xffffffffffffffffULL)
+               return "forever";
+
+       if (valid_from != 0) {
+               /* XXX revisit INT_MAX in 2038 :) */
+               tt = valid_from > INT_MAX ? INT_MAX : valid_from;
+               tm = localtime(&tt);
+               strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
+       }
+       if (valid_to != 0xffffffffffffffffULL) {
+               /* XXX revisit INT_MAX in 2038 :) */
+               tt = valid_to > INT_MAX ? INT_MAX : valid_to;
+               tm = localtime(&tt);
+               strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
+       }
+
+       if (valid_from == 0) {
+               snprintf(ret, sizeof(ret), "before %s", to);
+               return ret;
+       }
+       if (valid_to == 0xffffffffffffffffULL) {
+               snprintf(ret, sizeof(ret), "after %s", from);
+               return ret;
+       }
+
+       snprintf(ret, sizeof(ret), "from %s to %s", from, to);
+       return ret;
+}
+
+static void
+add_flag_option(Buffer *c, const char *name)
+{
+       debug3("%s: %s", __func__, name);
+       buffer_put_cstring(c, name);
+       buffer_put_string(c, NULL, 0);
+}
+
+static void
+add_string_option(Buffer *c, const char *name, const char *value)
+{
+       Buffer b;
+
+       debug3("%s: %s=%s", __func__, name, value);
+       buffer_init(&b);
+       buffer_put_cstring(&b, value);
+
+       buffer_put_cstring(c, name);
+       buffer_put_string(c, buffer_ptr(&b), buffer_len(&b));
+
+       buffer_free(&b);
+}
+
+#define OPTIONS_CRITICAL       1
+#define OPTIONS_EXTENSIONS     2
+static void
+prepare_options_buf(Buffer *c, int which)
+{
+       buffer_clear(c);
+       if ((which & OPTIONS_CRITICAL) != 0 &&
+           certflags_command != NULL)
+               add_string_option(c, "force-command", certflags_command);
+       if ((which & OPTIONS_EXTENSIONS) != 0 &&
+           (certflags_flags & CERTOPT_AGENT_FWD) != 0)
+               add_flag_option(c, "permit-agent-forwarding");
+       if ((which & OPTIONS_EXTENSIONS) != 0 &&
+           (certflags_flags & CERTOPT_PORT_FWD) != 0)
+               add_flag_option(c, "permit-port-forwarding");
+       if ((which & OPTIONS_EXTENSIONS) != 0 &&
+           (certflags_flags & CERTOPT_PTY) != 0)
+               add_flag_option(c, "permit-pty");
+       if ((which & OPTIONS_EXTENSIONS) != 0 &&
+           (certflags_flags & CERTOPT_USER_RC) != 0)
+               add_flag_option(c, "permit-user-rc");
+       if ((which & OPTIONS_EXTENSIONS) != 0 &&
+           (certflags_flags & CERTOPT_X_FWD) != 0)
+               add_flag_option(c, "permit-X11-forwarding");
+       if ((which & OPTIONS_CRITICAL) != 0 &&
+           certflags_src_addr != NULL)
+               add_string_option(c, "source-address", certflags_src_addr);
+}
+
+static Key *
+load_pkcs11_key(char *path)
+{
+#ifdef ENABLE_PKCS11
+       Key **keys = NULL, *public, *private = NULL;
+       int i, nkeys;
+
+       if ((public = key_load_public(path, NULL)) == NULL)
+               fatal("Couldn't load CA public key \"%s\"", path);
+
+       nkeys = pkcs11_add_provider(pkcs11provider, identity_passphrase, &keys);
+       debug3("%s: %d keys", __func__, nkeys);
+       if (nkeys <= 0)
+               fatal("cannot read public key from pkcs11");
+       for (i = 0; i < nkeys; i++) {
+               if (key_equal_public(public, keys[i])) {
+                       private = keys[i];
+                       continue;
+               }
+               key_free(keys[i]);
+       }
+       xfree(keys);
+       key_free(public);
+       return private;
+#else
+       fatal("no pkcs11 support");
+#endif /* ENABLE_PKCS11 */
+}
+
+static void
+do_ca_sign(struct passwd *pw, int argc, char **argv)
+{
+       int i, fd;
+       u_int n;
+       Key *ca, *public;
+       char *otmp, *tmp, *cp, *out, *comment, **plist = NULL;
+       FILE *f;
+       int v00 = 0; /* legacy keys */
+
+       if (key_type_name != NULL) {
+               switch (key_type_from_name(key_type_name)) {
+               case KEY_RSA_CERT_V00:
+               case KEY_DSA_CERT_V00:
+                       v00 = 1;
+                       break;
+               case KEY_UNSPEC:
+                       if (strcasecmp(key_type_name, "v00") == 0) {
+                               v00 = 1;
+                               break;
+                       } else if (strcasecmp(key_type_name, "v01") == 0)
+                               break;
+                       /* FALLTHROUGH */
+               default:
+                       fprintf(stderr, "unknown key type %s\n", key_type_name);
+                       exit(1);
+               }
+       }
+
+       pkcs11_init(1);
+       tmp = tilde_expand_filename(ca_key_path, pw->pw_uid);
+       if (pkcs11provider != NULL) {
+               if ((ca = load_pkcs11_key(tmp)) == NULL)
+                       fatal("No PKCS#11 key matching %s found", ca_key_path);
+       } else if ((ca = load_identity(tmp)) == NULL)
+               fatal("Couldn't load CA key \"%s\"", tmp);
+       xfree(tmp);
+
+       for (i = 0; i < argc; i++) {
+               /* Split list of principals */
+               n = 0;
+               if (cert_principals != NULL) {
+                       otmp = tmp = xstrdup(cert_principals);
+                       plist = NULL;
+                       for (; (cp = strsep(&tmp, ",")) != NULL; n++) {
+                               plist = xrealloc(plist, n + 1, sizeof(*plist));
+                               if (*(plist[n] = xstrdup(cp)) == '\0')
+                                       fatal("Empty principal name");
+                       }
+                       xfree(otmp);
+               }
+       
+               tmp = tilde_expand_filename(argv[i], pw->pw_uid);
+               if ((public = key_load_public(tmp, &comment)) == NULL)
+                       fatal("%s: unable to open \"%s\"", __func__, tmp);
+               if (public->type != KEY_RSA && public->type != KEY_DSA &&
+                   public->type != KEY_ECDSA)
+                       fatal("%s: key \"%s\" type %s cannot be certified",
+                           __func__, tmp, key_type(public));
+
+               /* Prepare certificate to sign */
+               if (key_to_certified(public, v00) != 0)
+                       fatal("Could not upgrade key %s to certificate", tmp);
+               public->cert->type = cert_key_type;
+               public->cert->serial = (u_int64_t)cert_serial;
+               public->cert->key_id = xstrdup(cert_key_id);
+               public->cert->nprincipals = n;
+               public->cert->principals = plist;
+               public->cert->valid_after = cert_valid_from;
+               public->cert->valid_before = cert_valid_to;
+               if (v00) {
+                       prepare_options_buf(&public->cert->critical,
+                           OPTIONS_CRITICAL|OPTIONS_EXTENSIONS);
+               } else {
+                       prepare_options_buf(&public->cert->critical,
+                           OPTIONS_CRITICAL);
+                       prepare_options_buf(&public->cert->extensions,
+                           OPTIONS_EXTENSIONS);
+               }
+               public->cert->signature_key = key_from_private(ca);
+
+               if (key_certify(public, ca) != 0)
+                       fatal("Couldn't not certify key %s", tmp);
+
+               if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0)
+                       *cp = '\0';
+               xasprintf(&out, "%s-cert.pub", tmp);
+               xfree(tmp);
+
+               if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
+                       fatal("Could not open \"%s\" for writing: %s", out,
+                           strerror(errno));
+               if ((f = fdopen(fd, "w")) == NULL)
+                       fatal("%s: fdopen: %s", __func__, strerror(errno));
+               if (!key_write(public, f))
+                       fatal("Could not write certified key to %s", out);
+               fprintf(f, " %s\n", comment);
+               fclose(f);
+
+               if (!quiet) {
+                       logit("Signed %s key %s: id \"%s\" serial %llu%s%s "
+                           "valid %s", key_cert_type(public), 
+                           out, public->cert->key_id,
+                           (unsigned long long)public->cert->serial,
+                           cert_principals != NULL ? " for " : "",
+                           cert_principals != NULL ? cert_principals : "",
+                           fmt_validity(cert_valid_from, cert_valid_to));
+               }
+
+               key_free(public);
+               xfree(out);
+       }
+       pkcs11_terminate();
+       exit(0);
+}
+
+static u_int64_t
+parse_relative_time(const char *s, time_t now)
+{
+       int64_t mul, secs;
+
+       mul = *s == '-' ? -1 : 1;
+
+       if ((secs = convtime(s + 1)) == -1)
+               fatal("Invalid relative certificate time %s", s);
+       if (mul == -1 && secs > now)
+               fatal("Certificate time %s cannot be represented", s);
+       return now + (u_int64_t)(secs * mul);
+}
+
+static u_int64_t
+parse_absolute_time(const char *s)
+{
+       struct tm tm;
+       time_t tt;
+       char buf[32], *fmt;
+
+       /*
+        * POSIX strptime says "The application shall ensure that there 
+        * is white-space or other non-alphanumeric characters between
+        * any two conversion specifications" so arrange things this way.
+        */
+       switch (strlen(s)) {
+       case 8:
+               fmt = "%Y-%m-%d";
+               snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6);
+               break;
+       case 14:
+               fmt = "%Y-%m-%dT%H:%M:%S";
+               snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s",
+                   s, s + 4, s + 6, s + 8, s + 10, s + 12);
+               break;
+       default:
+               fatal("Invalid certificate time format %s", s);
+       }
+
+       bzero(&tm, sizeof(tm));
+       if (strptime(buf, fmt, &tm) == NULL)
+               fatal("Invalid certificate time %s", s);
+       if ((tt = mktime(&tm)) < 0)
+               fatal("Certificate time %s cannot be represented", s);
+       return (u_int64_t)tt;
+}
+
+static void
+parse_cert_times(char *timespec)
+{
+       char *from, *to;
+       time_t now = time(NULL);
+       int64_t secs;
+
+       /* +timespec relative to now */
+       if (*timespec == '+' && strchr(timespec, ':') == NULL) {
+               if ((secs = convtime(timespec + 1)) == -1)
+                       fatal("Invalid relative certificate life %s", timespec);
+               cert_valid_to = now + secs;
+               /*
+                * Backdate certificate one minute to avoid problems on hosts
+                * with poorly-synchronised clocks.
+                */
+               cert_valid_from = ((now - 59)/ 60) * 60;
+               return;
+       }
+
+       /*
+        * from:to, where
+        * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
+        *   to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS
+        */
+       from = xstrdup(timespec);
+       to = strchr(from, ':');
+       if (to == NULL || from == to || *(to + 1) == '\0')
+               fatal("Invalid certificate life specification %s", timespec);
+       *to++ = '\0';
+
+       if (*from == '-' || *from == '+')
+               cert_valid_from = parse_relative_time(from, now);
+       else
+               cert_valid_from = parse_absolute_time(from);
+
+       if (*to == '-' || *to == '+')
+               cert_valid_to = parse_relative_time(to, cert_valid_from);
+       else
+               cert_valid_to = parse_absolute_time(to);
+
+       if (cert_valid_to <= cert_valid_from)
+               fatal("Empty certificate validity interval");
+       xfree(from);
+}
+
+static void
+add_cert_option(char *opt)
+{
+       char *val;
+
+       if (strcmp(opt, "clear") == 0)
+               certflags_flags = 0;
+       else if (strcasecmp(opt, "no-x11-forwarding") == 0)
+               certflags_flags &= ~CERTOPT_X_FWD;
+       else if (strcasecmp(opt, "permit-x11-forwarding") == 0)
+               certflags_flags |= CERTOPT_X_FWD;
+       else if (strcasecmp(opt, "no-agent-forwarding") == 0)
+               certflags_flags &= ~CERTOPT_AGENT_FWD;
+       else if (strcasecmp(opt, "permit-agent-forwarding") == 0)
+               certflags_flags |= CERTOPT_AGENT_FWD;
+       else if (strcasecmp(opt, "no-port-forwarding") == 0)
+               certflags_flags &= ~CERTOPT_PORT_FWD;
+       else if (strcasecmp(opt, "permit-port-forwarding") == 0)
+               certflags_flags |= CERTOPT_PORT_FWD;
+       else if (strcasecmp(opt, "no-pty") == 0)
+               certflags_flags &= ~CERTOPT_PTY;
+       else if (strcasecmp(opt, "permit-pty") == 0)
+               certflags_flags |= CERTOPT_PTY;
+       else if (strcasecmp(opt, "no-user-rc") == 0)
+               certflags_flags &= ~CERTOPT_USER_RC;
+       else if (strcasecmp(opt, "permit-user-rc") == 0)
+               certflags_flags |= CERTOPT_USER_RC;
+       else if (strncasecmp(opt, "force-command=", 14) == 0) {
+               val = opt + 14;
+               if (*val == '\0')
+                       fatal("Empty force-command option");
+               if (certflags_command != NULL)
+                       fatal("force-command already specified");
+               certflags_command = xstrdup(val);
+       } else if (strncasecmp(opt, "source-address=", 15) == 0) {
+               val = opt + 15;
+               if (*val == '\0')
+                       fatal("Empty source-address option");
+               if (certflags_src_addr != NULL)
+                       fatal("source-address already specified");
+               if (addr_match_cidr_list(NULL, val) != 0)
+                       fatal("Invalid source-address list");
+               certflags_src_addr = xstrdup(val);
+       } else
+               fatal("Unsupported certificate option \"%s\"", opt);
+}
+
+static void
+show_options(const Buffer *optbuf, int v00, int in_critical)
+{
+       u_char *name, *data;
+       u_int dlen;
+       Buffer options, option;
+
+       buffer_init(&options);
+       buffer_append(&options, buffer_ptr(optbuf), buffer_len(optbuf));
+
+       buffer_init(&option);
+       while (buffer_len(&options) != 0) {
+               name = buffer_get_string(&options, NULL);
+               data = buffer_get_string_ptr(&options, &dlen);
+               buffer_append(&option, data, dlen);
+               printf("                %s", name);
+               if ((v00 || !in_critical) && 
+                   (strcmp(name, "permit-X11-forwarding") == 0 ||
+                   strcmp(name, "permit-agent-forwarding") == 0 ||
+                   strcmp(name, "permit-port-forwarding") == 0 ||
+                   strcmp(name, "permit-pty") == 0 ||
+                   strcmp(name, "permit-user-rc") == 0))
+                       printf("\n");
+               else if ((v00 || in_critical) &&
+                   (strcmp(name, "force-command") == 0 ||
+                   strcmp(name, "source-address") == 0)) {
+                       data = buffer_get_string(&option, NULL);
+                       printf(" %s\n", data);
+                       xfree(data);
+               } else {
+                       printf(" UNKNOWN OPTION (len %u)\n",
+                           buffer_len(&option));
+                       buffer_clear(&option);
+               }
+               xfree(name);
+               if (buffer_len(&option) != 0)
+                       fatal("Option corrupt: extra data at end");
+       }
+       buffer_free(&option);
+       buffer_free(&options);
+}
+
+static void
+do_show_cert(struct passwd *pw)
+{
+       Key *key;
+       struct stat st;
+       char *key_fp, *ca_fp;
+       u_int i, v00;
+
+       if (!have_identity)
+               ask_filename(pw, "Enter file in which the key is");
+       if (stat(identity_file, &st) < 0)
+               fatal("%s: %s: %s", __progname, identity_file, strerror(errno));
+       if ((key = key_load_public(identity_file, NULL)) == NULL)
+               fatal("%s is not a public key", identity_file);
+       if (!key_is_cert(key))
+               fatal("%s is not a certificate", identity_file);
+       v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
+
+       key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+       ca_fp = key_fingerprint(key->cert->signature_key,
+           SSH_FP_MD5, SSH_FP_HEX);
+
+       printf("%s:\n", identity_file);
+       printf("        Type: %s %s certificate\n", key_ssh_name(key),
+           key_cert_type(key));
+       printf("        Public key: %s %s\n", key_type(key), key_fp);
+       printf("        Signing CA: %s %s\n",
+           key_type(key->cert->signature_key), ca_fp);
+       printf("        Key ID: \"%s\"\n", key->cert->key_id);
+       if (!v00) {
+               printf("        Serial: %llu\n",
+                   (unsigned long long)key->cert->serial);
+       }
+       printf("        Valid: %s\n",
+           fmt_validity(key->cert->valid_after, key->cert->valid_before));
+       printf("        Principals: ");
+       if (key->cert->nprincipals == 0)
+               printf("(none)\n");
+       else {
+               for (i = 0; i < key->cert->nprincipals; i++)
+                       printf("\n                %s",
+                           key->cert->principals[i]);
+               printf("\n");
+       }
+       printf("        Critical Options: ");
+       if (buffer_len(&key->cert->critical) == 0)
+               printf("(none)\n");
+       else {
+               printf("\n");
+               show_options(&key->cert->critical, v00, 1);
+       }
+       if (!v00) {
+               printf("        Extensions: ");
+               if (buffer_len(&key->cert->extensions) == 0)
+                       printf("(none)\n");
+               else {
+                       printf("\n");
+                       show_options(&key->cert->extensions, v00, 0);
+               }
+       }
+       exit(0);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "usage: %s [options]\n", __progname);
+       fprintf(stderr, "Options:\n");
+       fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
+       fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
+       fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
+       fprintf(stderr, "  -C comment  Provide new comment.\n");
+       fprintf(stderr, "  -c          Change comment in private and public key files.\n");
+#ifdef ENABLE_PKCS11
+       fprintf(stderr, "  -D pkcs11   Download public key from pkcs11 token.\n");
+#endif
+       fprintf(stderr, "  -e          Export OpenSSH to foreign format key file.\n");
+       fprintf(stderr, "  -F hostname Find hostname in known hosts file.\n");
+       fprintf(stderr, "  -f filename Filename of the key file.\n");
+       fprintf(stderr, "  -G file     Generate candidates for DH-GEX moduli.\n");
+       fprintf(stderr, "  -g          Use generic DNS resource record format.\n");
+       fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
+       fprintf(stderr, "  -h          Generate host certificate instead of a user certificate.\n");
+       fprintf(stderr, "  -I key_id   Key identifier to include in certificate.\n");
+       fprintf(stderr, "  -i          Import foreign format to OpenSSH key file.\n");
+       fprintf(stderr, "  -L          Print the contents of a certificate.\n");
+       fprintf(stderr, "  -l          Show fingerprint of key file.\n");
+       fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
+       fprintf(stderr, "  -m key_fmt  Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n");
+       fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
+       fprintf(stderr, "  -n name,... User/host principal names to include in certificate\n");
+       fprintf(stderr, "  -O option   Specify a certificate option.\n");
+       fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
+       fprintf(stderr, "  -p          Change passphrase of private key file.\n");
+       fprintf(stderr, "  -q          Quiet.\n");
+       fprintf(stderr, "  -R hostname Remove host from known_hosts file.\n");
+       fprintf(stderr, "  -r hostname Print DNS resource record.\n");
+       fprintf(stderr, "  -S start    Start point (hex) for generating DH-GEX moduli.\n");
+       fprintf(stderr, "  -s ca_key   Certify keys with CA key.\n");
+       fprintf(stderr, "  -T file     Screen candidates for DH-GEX moduli.\n");
+       fprintf(stderr, "  -t type     Specify type of key to create.\n");
+       fprintf(stderr, "  -V from:to  Specify certificate validity interval.\n");
+       fprintf(stderr, "  -v          Verbose.\n");
+       fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
+       fprintf(stderr, "  -y          Read private key file and print public key.\n");
+       fprintf(stderr, "  -z serial   Specify a serial number.\n");
+
+       exit(1);
+}
+
+/*
+ * Main program for key management.
+ */
+int
+main(int argc, char **argv)
+{
+       char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
+       char out_file[MAXPATHLEN], *rr_hostname = NULL;
+       Key *private, *public;
+       struct passwd *pw;
+       struct stat st;
+       int opt, type, fd;
+       u_int maxbits;
+       u_int32_t memory = 0, generator_wanted = 0, trials = 100;
+       int do_gen_candidates = 0, do_screen_candidates = 0;
+       BIGNUM *start = NULL;
+       FILE *f;
+       const char *errstr;
+
+       extern int optind;
+       extern char *optarg;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       __progname = ssh_get_progname(argv[0]);
+
+       OpenSSL_add_all_algorithms();
+       log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+
+       init_rng();
+       seed_rng();
+
+       /* 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(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:m:N:n:"
+           "O:C:r:g:R:T:G:M:S:s:a:V:W:z:")) != -1) {
+               switch (opt) {
+               case 'b':
+                       bits = (u_int32_t)strtonum(optarg, 256, 32768, &errstr);
+                       if (errstr)
+                               fatal("Bits has bad value %s (%s)",
+                                       optarg, errstr);
+                       break;
+               case 'F':
+                       find_host = 1;
+                       rr_hostname = optarg;
+                       break;
+               case 'H':
+                       hash_hosts = 1;
+                       break;
+               case 'I':
+                       cert_key_id = optarg;
+                       break;
+               case 'R':
+                       delete_host = 1;
+                       rr_hostname = optarg;
+                       break;
+               case 'L':
+                       show_cert = 1;
+                       break;
+               case 'l':
+                       print_fingerprint = 1;
+                       break;
+               case 'B':
+                       print_bubblebabble = 1;
+                       break;
+               case 'm':
+                       if (strcasecmp(optarg, "RFC4716") == 0 ||
+                           strcasecmp(optarg, "ssh2") == 0) {
+                               convert_format = FMT_RFC4716;
+                               break;
+                       }
+                       if (strcasecmp(optarg, "PKCS8") == 0) {
+                               convert_format = FMT_PKCS8;
+                               break;
+                       }
+                       if (strcasecmp(optarg, "PEM") == 0) {
+                               convert_format = FMT_PEM;
+                               break;
+                       }
+                       fatal("Unsupported conversion format \"%s\"", optarg);
+               case 'n':
+                       cert_principals = optarg;
+                       break;
+               case 'p':
+                       change_passphrase = 1;
+                       break;
+               case 'c':
+                       change_comment = 1;
+                       break;
+               case 'f':
+                       if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
+                           sizeof(identity_file))
+                               fatal("Identity filename too long");
+                       have_identity = 1;
+                       break;
+               case 'g':
+                       print_generic = 1;
+                       break;
+               case 'P':
+                       identity_passphrase = optarg;
+                       break;
+               case 'N':
+                       identity_new_passphrase = optarg;
+                       break;
+               case 'O':
+                       add_cert_option(optarg);
+                       break;
+               case 'C':
+                       identity_comment = optarg;
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'e':
+               case 'x':
+                       /* export key */
+                       convert_to = 1;
+                       break;
+               case 'h':
+                       cert_key_type = SSH2_CERT_TYPE_HOST;
+                       certflags_flags = 0;
+                       break;
+               case 'i':
+               case 'X':
+                       /* import key */
+                       convert_from = 1;
+                       break;
+               case 'y':
+                       print_public = 1;
+                       break;
+               case 'd':
+                       key_type_name = "dsa";
+                       break;
+               case 's':
+                       ca_key_path = optarg;
+                       break;
+               case 't':
+                       key_type_name = optarg;
+                       break;
+               case 'D':
+                       pkcs11provider = optarg;
+                       break;
+               case 'v':
+                       if (log_level == SYSLOG_LEVEL_INFO)
+                               log_level = SYSLOG_LEVEL_DEBUG1;
+                       else {
+                               if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
+                                   log_level < SYSLOG_LEVEL_DEBUG3)
+                                       log_level++;
+                       }
+                       break;
+               case 'r':
+                       rr_hostname = optarg;
+                       break;
+               case 'W':
+                       generator_wanted = (u_int32_t)strtonum(optarg, 1,
+                           UINT_MAX, &errstr);
+                       if (errstr)
+                               fatal("Desired generator has bad value: %s (%s)",
+                                       optarg, errstr);
+                       break;
+               case 'a':
+                       trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
+                       if (errstr)
+                               fatal("Invalid number of trials: %s (%s)",
+                                       optarg, errstr);
+                       break;
+               case 'M':
+                       memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
+                       if (errstr)
+                               fatal("Memory limit is %s: %s", errstr, optarg);
+                       break;
+               case 'G':
+                       do_gen_candidates = 1;
+                       if (strlcpy(out_file, optarg, sizeof(out_file)) >=
+                           sizeof(out_file))
+                               fatal("Output filename too long");
+                       break;
+               case 'T':
+                       do_screen_candidates = 1;
+                       if (strlcpy(out_file, optarg, sizeof(out_file)) >=
+                           sizeof(out_file))
+                               fatal("Output filename too long");
+                       break;
+               case 'S':
+                       /* XXX - also compare length against bits */
+                       if (BN_hex2bn(&start, optarg) == 0)
+                               fatal("Invalid start point.");
+                       break;
+               case 'V':
+                       parse_cert_times(optarg);
+                       break;
+               case 'z':
+                       cert_serial = strtonum(optarg, 0, LLONG_MAX, &errstr);
+                       if (errstr)
+                               fatal("Invalid serial number: %s", errstr);
+                       break;
+               case '?':
+               default:
+                       usage();
+               }
+       }
+
+       /* reinit */
+       log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
+
+       argv += optind;
+       argc -= optind;
+
+       if (ca_key_path != NULL) {
+               if (argc < 1) {
+                       printf("Too few arguments.\n");
+                       usage();
+               }
+       } else if (argc > 0) {
+               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 && (delete_host || hash_hosts)) {
+               printf("Cannot use -l with -D or -R.\n");
+               usage();
+       }
+       if (ca_key_path != NULL) {
+               if (cert_key_id == NULL)
+                       fatal("Must specify key id (-I) when certifying");
+               do_ca_sign(pw, argc, argv);
+       }
+       if (show_cert)
+               do_show_cert(pw);
+       if (delete_host || hash_hosts || find_host)
+               do_known_hosts(pw, rr_hostname);
+       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)
+               do_convert_to(pw);
+       if (convert_from)
+               do_convert_from(pw);
+       if (print_public)
+               do_print_public(pw);
+       if (rr_hostname != NULL) {
+               unsigned int n = 0;
+
+               if (have_identity) {
+                       n = do_print_resource_record(pw,
+                           identity_file, rr_hostname);
+                       if (n == 0) {
+                               perror(identity_file);
+                               exit(1);
+                       }
+                       exit(0);
+               } else {
+
+                       n += do_print_resource_record(pw,
+                           _PATH_HOST_RSA_KEY_FILE, rr_hostname);
+                       n += do_print_resource_record(pw,
+                           _PATH_HOST_DSA_KEY_FILE, rr_hostname);
+
+                       if (n == 0)
+                               fatal("no keys found.");
+                       exit(0);
+               }
+       }
+       if (pkcs11provider != NULL)
+               do_download(pw);
+
+       if (do_gen_candidates) {
+               FILE *out = fopen(out_file, "w");
+
+               if (out == NULL) {
+                       error("Couldn't open modulus candidate file \"%s\": %s",
+                           out_file, strerror(errno));
+                       return (1);
+               }
+               if (bits == 0)
+                       bits = DEFAULT_BITS;
+               if (gen_candidates(out, memory, bits, start) != 0)
+                       fatal("modulus candidate generation failed");
+
+               return (0);
+       }
+
+       if (do_screen_candidates) {
+               FILE *in;
+               FILE *out = fopen(out_file, "w");
+
+               if (have_identity && strcmp(identity_file, "-") != 0) {
+                       if ((in = fopen(identity_file, "r")) == NULL) {
+                               fatal("Couldn't open modulus candidate "
+                                   "file \"%s\": %s", identity_file,
+                                   strerror(errno));
+                       }
+               } else
+                       in = stdin;
+
+               if (out == NULL) {
+                       fatal("Couldn't open moduli file \"%s\": %s",
+                           out_file, strerror(errno));
+               }
+               if (prime_test(in, out, trials, generator_wanted) != 0)
+                       fatal("modulus screening failed");
+               return (0);
+       }
+
+       arc4random_stir();
+
+       if (key_type_name == NULL)
+               key_type_name = "rsa";
+
+       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 (bits == 0) {
+               if (type == KEY_DSA)
+                       bits = DEFAULT_BITS_DSA;
+               else if (type == KEY_ECDSA)
+                       bits = DEFAULT_BITS_ECDSA;
+               else
+                       bits = DEFAULT_BITS;
+       }
+       maxbits = (type == KEY_DSA) ?
+           OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS;
+       if (bits > maxbits) {
+               fprintf(stderr, "key bits exceeds maximum %d\n", maxbits);
+               exit(1);
+       }
+       if (type == KEY_DSA && bits != 1024)
+               fatal("DSA keys must be 1024 bits");
+       else if (type != KEY_ECDSA && bits < 768)
+               fatal("Key must at least be 768 bits");
+       else if (type == KEY_ECDSA && key_ecdsa_bits_to_nid(bits) == -1)
+               fatal("Invalid ECDSA key length - valid lengths are "
+                   "256, 384 or 521 bits");
+       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\n");
+               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) {
+               if (stat(dotsshdir, &st) < 0) {
+                       if (errno != ENOENT) {
+                               error("Could not stat %s: %s", dotsshdir,
+                                   strerror(errno));
+                       } else if (mkdir(dotsshdir, 0700) < 0) {
+                               error("Could not create directory '%s': %s",
+                                   dotsshdir, strerror(errno));
+                       } 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 comment 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\n", identity_file);
+               exit(1);
+       }
+       if (!key_write(public, f))
+               fprintf(stderr, "write key failed\n");
+       fprintf(f, " %s\n", comment);
+       fclose(f);
+
+       if (!quiet) {
+               char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+               char *ra = key_fingerprint(public, SSH_FP_MD5,
+                   SSH_FP_RANDOMART);
+               printf("Your public key has been saved in %s.\n",
+                   identity_file);
+               printf("The key fingerprint is:\n");
+               printf("%s %s\n", fp, comment);
+               printf("The key's randomart image is:\n");
+               printf("%s\n", ra);
+               xfree(ra);
+               xfree(fp);
+       }
+
+       key_free(public);
+       exit(0);
+}
diff --git a/ssh-keyscan.0 b/ssh-keyscan.0
new file mode 100644 (file)
index 0000000..4c3d2db
--- /dev/null
@@ -0,0 +1,109 @@
+SSH-KEYSCAN(1)             OpenBSD Reference Manual             SSH-KEYSCAN(1)
+
+NAME
+     ssh-keyscan - gather ssh public keys
+
+SYNOPSIS
+     ssh-keyscan [-46Hv] [-f file] [-p port] [-T timeout] [-t type]
+                 [host | addrlist namelist] ...
+
+DESCRIPTION
+     ssh-keyscan is a utility for gathering the public ssh host keys of a
+     number of hosts.  It was designed to aid in building and verifying
+     ssh_known_hosts files.  ssh-keyscan provides a minimal interface suitable
+     for use by shell and perl scripts.
+
+     ssh-keyscan 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.
+
+     The options are as follows:
+
+     -4      Forces ssh-keyscan to use IPv4 addresses only.
+
+     -6      Forces ssh-keyscan to use IPv6 addresses only.
+
+     -f file
+             Read hosts or addrlist namelist pairs from this file, one per
+             line.  If - is supplied instead of a filename, ssh-keyscan will
+             read hosts or addrlist namelist pairs from the standard input.
+
+     -H      Hash all hostnames and addresses in the output.  Hashed names may
+             be used normally by ssh and sshd, but they do not reveal
+             identifying information should the file's contents be disclosed.
+
+     -p port
+             Port to connect to on the remote host.
+
+     -T timeout
+             Set the timeout for connection attempts.  If 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.
+
+     -t type
+             Specifies the type of the key to fetch from the scanned hosts.
+             The possible values are ``rsa1'' for protocol version 1 and
+             ``dsa'', ``ecdsa'' or ``rsa'' for protocol version 2.  Multiple
+             values may be specified by separating them with commas.  The
+             default is ``rsa''.
+
+     -v      Verbose mode.  Causes ssh-keyscan to print debugging messages
+             about its progress.
+
+SECURITY
+     If an ssh_known_hosts file is constructed using ssh-keyscan without
+     verifying the keys, users will be vulnerable to man in the middle
+     attacks.  On the other hand, if the security model allows such a risk,
+     ssh-keyscan 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.
+
+FILES
+     Input format:
+
+     1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4
+
+     Output format for rsa1 keys:
+
+     host-or-namelist bits exponent modulus
+
+     Output format for rsa, dsa and ecdsa keys:
+
+     host-or-namelist keytype base64-encoded-key
+
+     Where keytype is either ``ecdsa-sha2-nistp256'', ``ecdsa-sha2-nistp384'',
+     ``ecdsa-sha2-nistp521'', ``ssh-dss'' or ``ssh-rsa''.
+
+     /etc/ssh/ssh_known_hosts
+
+EXAMPLES
+     Print the rsa host key for machine hostname:
+
+     $ ssh-keyscan hostname
+
+     Find all hosts from the file ssh_hosts which have new or different keys
+     from those in the sorted file ssh_known_hosts:
+
+     $ ssh-keyscan -t rsa,dsa,ecdsa -f ssh_hosts | \
+             sort -u - ssh_known_hosts | diff ssh_known_hosts -
+
+SEE ALSO
+     ssh(1), sshd(8)
+
+AUTHORS
+     David Mazieres <dm@lcs.mit.edu> wrote the initial version, and Wayne
+     Davison <wayned@users.sourceforge.net> added support for protocol version
+     2.
+
+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.
+
+OpenBSD 4.9                     August 31, 2010                    OpenBSD 4.9
diff --git a/ssh-keyscan.1 b/ssh-keyscan.1
new file mode 100644 (file)
index 0000000..fe9bb6e
--- /dev/null
@@ -0,0 +1,172 @@
+.\"    $OpenBSD: ssh-keyscan.1,v 1.29 2010/08/31 11:54:45 djm 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 $Mdocdate: August 31 2010 $
+.Dt SSH-KEYSCAN 1
+.Os
+.Sh NAME
+.Nm ssh-keyscan
+.Nd gather ssh public keys
+.Sh SYNOPSIS
+.Nm ssh-keyscan
+.Bk -words
+.Op Fl 46Hv
+.Op Fl f Ar file
+.Op Fl p Ar port
+.Op Fl T Ar timeout
+.Op Fl t Ar type
+.Op Ar host | addrlist namelist
+.Ar ...
+.Ek
+.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 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl f Ar file
+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 H
+Hash all hostnames and addresses in the output.
+Hashed names may be used normally by
+.Nm ssh
+and
+.Nm sshd ,
+but they do not reveal identifying information should the file's contents
+be disclosed.
+.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 dsa ,
+.Dq ecdsa
+or
+.Dq rsa
+for protocol version 2.
+Multiple values may be specified by separating them with commas.
+The default is
+.Dq rsa .
+.It Fl v
+Verbose mode.
+Causes
+.Nm
+to print debugging messages about its progress.
+.El
+.Sh SECURITY
+If an ssh_known_hosts file is constructed using
+.Nm
+without verifying the keys, users will be vulnerable to
+.Em 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 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, dsa and ecdsa keys:
+.Bd -literal
+host-or-namelist keytype base64-encoded-key
+.Ed
+.Pp
+Where
+.Pa keytype
+is either
+.Dq ecdsa-sha2-nistp256 ,
+.Dq ecdsa-sha2-nistp384 ,
+.Dq ecdsa-sha2-nistp521 ,
+.Dq ssh-dss
+or
+.Dq ssh-rsa .
+.Pp
+.Pa /etc/ssh/ssh_known_hosts
+.Sh EXAMPLES
+Print the
+.Pa rsa
+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,ecdsa -f ssh_hosts | \e
+       sort -u - ssh_known_hosts | diff ssh_known_hosts -
+.Ed
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr sshd 8
+.Sh AUTHORS
+.An -nosplit
+.An David Mazieres Aq dm@lcs.mit.edu
+wrote the initial version, and
+.An Wayne Davison Aq wayned@users.sourceforge.net
+added support for protocol version 2.
+.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.
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
new file mode 100644 (file)
index 0000000..25d7ac6
--- /dev/null
@@ -0,0 +1,764 @@
+/* $OpenBSD: ssh-keyscan.c,v 1.84 2011/01/04 20:44:13 otto 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.
+ */
+
+#include "includes.h"
+#include "openbsd-compat/sys-queue.h"
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/bn.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "buffer.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "compat.h"
+#include "myproposal.h"
+#include "packet.h"
+#include "dispatch.h"
+#include "log.h"
+#include "atomicio.h"
+#include "misc.h"
+#include "hostfile.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. */
+int IPv4or6 = AF_UNSPEC;
+
+int ssh_port = SSH_DEFAULT_PORT;
+
+#define KT_RSA1                1
+#define KT_DSA         2
+#define KT_RSA         4
+#define KT_ECDSA       8
+
+int get_keytypes = KT_RSA;     /* Get only RSA keys by default */
+
+int hash_hosts = 0;            /* Hash hostname on output */
+
+#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)
+
+extern char *__progname;
+fd_set *read_wait;
+size_t read_wait_nfdset;
+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;
+
+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 SSH_SYSFDMAX;
+       else
+               return hard ? rlfd.rlim_max : rlfd.rlim_cur;
+#else
+       return SSH_SYSFDMAX;
+#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" : (c->c_keytype == KT_RSA ? "ssh-rsa" :
+           "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521");
+       c->c_kex = kex_setup(myproposal);
+       c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
+       c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
+       c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
+       c->c_kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
+       c->c_kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
+       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)
+{
+       char *host = c->c_output_name ? c->c_output_name : c->c_name;
+
+       if (!key)
+               return;
+       if (hash_hosts && (host = host_hash(host, NULL, 0)) == NULL)
+               fatal("host_hash failed");
+
+       fprintf(stdout, "%s ", host);
+       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, ssh_gai_strerror(gaierr));
+       for (ai = aitop; ai; ai = ai->ai_next) {
+               s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (s < 0) {
+                       error("socket: %s", strerror(errno));
+                       continue;
+               }
+               if (set_nonblock(s) == -1)
+                       fatal("%s: set_nonblock(%d)", __func__, s);
+               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)
+{
+       char *namebase, *name, *namelist;
+       int s;
+
+       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)
+{
+       con *c = &fdcon[s];
+       int ret;
+
+       ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype);
+       confree(s);
+       return (ret);
+}
+
+static void
+congreet(int s)
+{
+       int n = 0, remote_major = 0, remote_minor = 0;
+       char buf[256], *cp;
+       char remote_version[sizeof buf];
+       size_t bufsiz;
+       con *c = &fdcon[s];
+
+       for (;;) {
+               memset(buf, '\0', sizeof(buf));
+               bufsiz = sizeof(buf);
+               cp = buf;
+               while (bufsiz-- &&
+                   (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') {
+                       if (*cp == '\r')
+                               *cp = '\n';
+                       cp++;
+               }
+               if (n != 1 || strncmp(buf, "SSH-", 4) == 0)
+                       break;
+       }
+       if (n == 0) {
+               switch (errno) {
+               case EPIPE:
+                       error("%s: Connection closed by remote host", c->c_name);
+                       break;
+               case ECONNREFUSED:
+                       break;
+               default:
+                       error("read (%s): %s", c->c_name, strerror(errno));
+                       break;
+               }
+               conrecycle(s);
+               return;
+       }
+       if (*cp != '\n' && *cp != '\r') {
+               error("%s: bad greeting", c->c_name);
+               confree(s);
+               return;
+       }
+       *cp = '\0';
+       if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
+           &remote_major, &remote_minor, remote_version) == 3)
+               compat_datafellows(remote_version);
+       else
+               datafellows = 0;
+       if (c->c_keytype != KT_RSA1) {
+               if (!ssh2_capable(remote_major, remote_minor)) {
+                       debug("%s doesn't support ssh2", c->c_name);
+                       confree(s);
+                       return;
+               }
+       } else if (remote_major != 1) {
+               debug("%s doesn't support ssh1", 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 (n < 0 || (size_t)n >= sizeof(buf)) {
+               error("snprintf: buffer too small");
+               confree(s);
+               return;
+       }
+       if (atomicio(vwrite, s, buf, n) != (size_t)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)
+{
+       con *c = &fdcon[s];
+       size_t n;
+
+       if (c->c_status == CS_CON) {
+               congreet(s);
+               return;
+       }
+       n = atomicio(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;
+               default:
+                       fatal("conread: invalid status %d", c->c_status);
+                       break;
+               }
+
+       contouch(s);
+}
+
+static void
+conloop(void)
+{
+       struct timeval seltime, now;
+       fd_set *r, *e;
+       con *c;
+       int i;
+
+       gettimeofday(&now, NULL);
+       c = TAILQ_FIRST(&tq);
+
+       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 = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+       e = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+       memcpy(r, read_wait, read_wait_nfdset * sizeof(fd_mask));
+       memcpy(e, read_wait, read_wait_nfdset * sizeof(fd_mask));
+
+       while (select(maxfd, r, NULL, e, &seltime) == -1 &&
+           (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
+               ;
+
+       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 = TAILQ_FIRST(&tq);
+       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 = TAILQ_NEXT(c, c_link);
+               conrecycle(s);
+       }
+}
+
+static void
+do_host(char *host)
+{
+       char *name = strnnsep(&host, " \t\n");
+       int j;
+
+       if (name == NULL)
+               return;
+       for (j = KT_RSA1; j <= KT_ECDSA; j *= 2) {
+               if (get_keytypes & j) {
+                       while (ncon >= MAXCON)
+                               conloop();
+                       conalloc(name, *host ? host : name, j);
+               }
+       }
+}
+
+void
+fatal(const char *fmt,...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       do_log(SYSLOG_LEVEL_FATAL, fmt, args);
+       va_end(args);
+       if (nonfatal_fatal)
+               longjmp(kexjmp, -1);
+       else
+               exit(255);
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+           "usage: %s [-46Hv] [-f file] [-p port] [-T timeout] [-t type]\n"
+           "\t\t   [host | addrlist namelist] ...\n",
+           __progname);
+       exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO;
+       int opt, fopt_count = 0, j;
+       char *tname, *cp, line[NI_MAXHOST];
+       FILE *fp;
+       u_long linenum;
+
+       extern int optind;
+       extern char *optarg;
+
+       __progname = ssh_get_progname(argv[0]);
+       init_rng();
+       seed_rng();
+       TAILQ_INIT(&tq);
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       if (argc <= 1)
+               usage();
+
+       while ((opt = getopt(argc, argv, "Hv46p:T:t:f:")) != -1) {
+               switch (opt) {
+               case 'H':
+                       hash_hosts = 1;
+                       break;
+               case 'p':
+                       ssh_port = a2port(optarg);
+                       if (ssh_port <= 0) {
+                               fprintf(stderr, "Bad port '%s'\n", optarg);
+                               exit(1);
+                       }
+                       break;
+               case 'T':
+                       timeout = convtime(optarg);
+                       if (timeout == -1 || timeout == 0) {
+                               fprintf(stderr, "Bad timeout '%s'\n", optarg);
+                               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_ECDSA:
+                                       get_keytypes |= KT_ECDSA;
+                                       break;
+                               case KEY_RSA:
+                                       get_keytypes |= KT_RSA;
+                                       break;
+                               case KEY_UNSPEC:
+                                       fatal("unknown key type %s", 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);
+
+       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 = xcalloc(maxfd, sizeof(con));
+
+       read_wait_nfdset = howmany(maxfd, NFDBITS);
+       read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask));
+
+       for (j = 0; j < fopt_count; j++) {
+               if (argv[j] == NULL)
+                       fp = stdin;
+               else if ((fp = fopen(argv[j], "r")) == NULL)
+                       fatal("%s: %s: %s", __progname, argv[j],
+                           strerror(errno));
+               linenum = 0;
+
+               while (read_keyfile_line(fp,
+                   argv[j] == NULL ? "(stdin)" : argv[j], line, sizeof(line),
+                   &linenum) != -1) {
+                       /* Chomp off trailing whitespace and comments */
+                       if ((cp = strchr(line, '#')) == NULL)
+                               cp = line + strlen(line) - 1;
+                       while (cp >= line) {
+                               if (*cp == ' ' || *cp == '\t' ||
+                                   *cp == '\n' || *cp == '#')
+                                       *cp-- = '\0';
+                               else
+                                       break;
+                       }
+
+                       /* Skip empty lines */
+                       if (*line == '\0')
+                               continue;
+
+                       do_host(line);
+               }
+
+               if (ferror(fp))
+                       fatal("%s: %s: %s", __progname, argv[j],
+                           strerror(errno));
+
+               fclose(fp);
+       }
+
+       while (optind < argc)
+               do_host(argv[optind++]);
+
+       while (ncon > 0)
+               conloop();
+
+       return (0);
+}
diff --git a/ssh-keysign.0 b/ssh-keysign.0
new file mode 100644 (file)
index 0000000..bff850f
--- /dev/null
@@ -0,0 +1,51 @@
+SSH-KEYSIGN(8)          OpenBSD System Manager's Manual         SSH-KEYSIGN(8)
+
+NAME
+     ssh-keysign - ssh helper program for host-based authentication
+
+SYNOPSIS
+     ssh-keysign
+
+DESCRIPTION
+     ssh-keysign is used by ssh(1) to access the local host keys and generate
+     the digital signature required during host-based authentication with SSH
+     protocol version 2.
+
+     ssh-keysign is disabled by default and can only be enabled in the global
+     client configuration file /etc/ssh/ssh_config by setting EnableSSHKeysign
+     to ``yes''.
+
+     ssh-keysign is not intended to be invoked by the user, but from ssh(1).
+     See ssh(1) and sshd(8) for more information about host-based
+     authentication.
+
+FILES
+     /etc/ssh/ssh_config
+             Controls whether ssh-keysign is enabled.
+
+     /etc/ssh/ssh_host_dsa_key
+     /etc/ssh/ssh_host_ecdsa_key
+     /etc/ssh/ssh_host_rsa_key
+             These files contain the private parts of the host keys used to
+             generate the digital signature.  They should be owned by root,
+             readable only by root, and not accessible to others.  Since they
+             are readable only by root, ssh-keysign must be set-uid root if
+             host-based authentication is used.
+
+     /etc/ssh/ssh_host_dsa_key-cert.pub
+     /etc/ssh/ssh_host_ecdsa_key-cert.pub
+     /etc/ssh/ssh_host_rsa_key-cert.pub
+             If these files exist they are assumed to contain public
+             certificate information corresponding with the private keys
+             above.
+
+SEE ALSO
+     ssh(1), ssh-keygen(1), ssh_config(5), sshd(8)
+
+HISTORY
+     ssh-keysign first appeared in OpenBSD 3.2.
+
+AUTHORS
+     Markus Friedl <markus@openbsd.org>
+
+OpenBSD 4.9                     August 31, 2010                    OpenBSD 4.9
diff --git a/ssh-keysign.8 b/ssh-keysign.8
new file mode 100644 (file)
index 0000000..5e09e02
--- /dev/null
@@ -0,0 +1,91 @@
+.\" $OpenBSD: ssh-keysign.8,v 1.12 2010/08/31 11:54:45 djm Exp $
+.\"
+.\" Copyright (c) 2002 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 $Mdocdate: August 31 2010 $
+.Dt SSH-KEYSIGN 8
+.Os
+.Sh NAME
+.Nm ssh-keysign
+.Nd ssh helper program for host-based authentication
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+is used by
+.Xr ssh 1
+to access the local host keys and generate the digital signature
+required during host-based authentication with SSH protocol version 2.
+.Pp
+.Nm
+is disabled by default and can only be enabled in the
+global client configuration file
+.Pa /etc/ssh/ssh_config
+by setting
+.Cm EnableSSHKeysign
+to
+.Dq yes .
+.Pp
+.Nm
+is not intended to be invoked by the user, but from
+.Xr ssh 1 .
+See
+.Xr ssh 1
+and
+.Xr sshd 8
+for more information about host-based authentication.
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It Pa /etc/ssh/ssh_config
+Controls whether
+.Nm
+is enabled.
+.Pp
+.It Pa /etc/ssh/ssh_host_dsa_key
+.It Pa /etc/ssh/ssh_host_ecdsa_key
+.It Pa /etc/ssh/ssh_host_rsa_key
+These files contain the private parts of the host keys used to
+generate the digital signature.
+They should be owned by root, readable only by root, and not
+accessible to others.
+Since they are readable only by root,
+.Nm
+must be set-uid root if host-based authentication is used.
+.Pp
+.It Pa /etc/ssh/ssh_host_dsa_key-cert.pub
+.It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub
+.It Pa /etc/ssh/ssh_host_rsa_key-cert.pub
+If these files exist they are assumed to contain public certificate
+information corresponding with the private keys above.
+.El
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-keygen 1 ,
+.Xr ssh_config 5 ,
+.Xr sshd 8
+.Sh HISTORY
+.Nm
+first appeared in
+.Ox 3.2 .
+.Sh AUTHORS
+.An Markus Friedl Aq markus@openbsd.org
diff --git a/ssh-keysign.c b/ssh-keysign.c
new file mode 100644 (file)
index 0000000..d051560
--- /dev/null
@@ -0,0 +1,254 @@
+/* $OpenBSD: ssh-keysign.c,v 1.35 2010/08/31 12:33:38 djm Exp $ */
+/*
+ * Copyright (c) 2002 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 <fcntl.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "key.h"
+#include "ssh.h"
+#include "ssh2.h"
+#include "misc.h"
+#include "buffer.h"
+#include "authfile.h"
+#include "msg.h"
+#include "canohost.h"
+#include "pathnames.h"
+#include "readconf.h"
+#include "uidswap.h"
+
+/* XXX readconf.c needs these */
+uid_t original_real_uid;
+
+extern char *__progname;
+
+static int
+valid_request(struct passwd *pw, char *host, Key **ret, u_char *data,
+    u_int datalen)
+{
+       Buffer b;
+       Key *key = NULL;
+       u_char *pkblob;
+       u_int blen, len;
+       char *pkalg, *p;
+       int pktype, fail;
+
+       fail = 0;
+
+       buffer_init(&b);
+       buffer_append(&b, data, datalen);
+
+       /* session id, currently limited to SHA1 (20 bytes) or SHA256 (32) */
+       p = buffer_get_string(&b, &len);
+       if (len != 20 && len != 32)
+               fail++;
+       xfree(p);
+
+       if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST)
+               fail++;
+
+       /* server user */
+       buffer_skip_string(&b);
+
+       /* service */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp("ssh-connection", p) != 0)
+               fail++;
+       xfree(p);
+
+       /* method */
+       p = buffer_get_string(&b, NULL);
+       if (strcmp("hostbased", p) != 0)
+               fail++;
+       xfree(p);
+
+       /* pubkey */
+       pkalg = buffer_get_string(&b, NULL);
+       pkblob = buffer_get_string(&b, &blen);
+
+       pktype = key_type_from_name(pkalg);
+       if (pktype == KEY_UNSPEC)
+               fail++;
+       else if ((key = key_from_blob(pkblob, blen)) == NULL)
+               fail++;
+       else if (key->type != pktype)
+               fail++;
+       xfree(pkalg);
+       xfree(pkblob);
+
+       /* client host name, handle trailing dot */
+       p = buffer_get_string(&b, &len);
+       debug2("valid_request: check expect chost %s got %s", host, p);
+       if (strlen(host) != len - 1)
+               fail++;
+       else if (p[len - 1] != '.')
+               fail++;
+       else if (strncasecmp(host, p, len - 1) != 0)
+               fail++;
+       xfree(p);
+
+       /* local user */
+       p = buffer_get_string(&b, NULL);
+
+       if (strcmp(pw->pw_name, p) != 0)
+               fail++;
+       xfree(p);
+
+       /* end of message */
+       if (buffer_len(&b) != 0)
+               fail++;
+       buffer_free(&b);
+
+       debug3("valid_request: fail %d", fail);
+
+       if (fail && key != NULL)
+               key_free(key);
+       else
+               *ret = key;
+
+       return (fail ? -1 : 0);
+}
+
+int
+main(int argc, char **argv)
+{
+       Buffer b;
+       Options options;
+       Key *keys[2], *key = NULL;
+       struct passwd *pw;
+       int key_fd[2], i, found, version = 2, fd;
+       u_char *signature, *data;
+       char *host;
+       u_int slen, dlen;
+       u_int32_t rnd[256];
+
+       /* Ensure that stdin and stdout are connected */
+       if ((fd = open(_PATH_DEVNULL, O_RDWR)) < 2)
+               exit(1);
+       /* Leave /dev/null fd iff it is attached to stderr */
+       if (fd > 2)
+               close(fd);
+
+       key_fd[0] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
+       key_fd[1] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
+
+       original_real_uid = getuid();   /* XXX readconf.c needs this */
+       if ((pw = getpwuid(original_real_uid)) == NULL)
+               fatal("getpwuid failed");
+       pw = pwcopy(pw);
+
+       permanently_set_uid(pw);
+
+       init_rng();
+       seed_rng();
+       arc4random_stir();
+
+#ifdef DEBUG_SSH_KEYSIGN
+       log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0);
+#endif
+
+       /* verify that ssh-keysign is enabled by the admin */
+       initialize_options(&options);
+       (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0);
+       fill_default_options(&options);
+       if (options.enable_ssh_keysign != 1)
+               fatal("ssh-keysign not enabled in %s",
+                   _PATH_HOST_CONFIG_FILE);
+
+       if (key_fd[0] == -1 && key_fd[1] == -1)
+               fatal("could not open any host key");
+
+       OpenSSL_add_all_algorithms();
+       for (i = 0; i < 256; i++)
+               rnd[i] = arc4random();
+       RAND_seed(rnd, sizeof(rnd));
+
+       found = 0;
+       for (i = 0; i < 2; i++) {
+               keys[i] = NULL;
+               if (key_fd[i] == -1)
+                       continue;
+               keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC,
+                   NULL, NULL);
+               close(key_fd[i]);
+               if (keys[i] != NULL)
+                       found = 1;
+       }
+       if (!found)
+               fatal("no hostkey found");
+
+       buffer_init(&b);
+       if (ssh_msg_recv(STDIN_FILENO, &b) < 0)
+               fatal("ssh_msg_recv failed");
+       if (buffer_get_char(&b) != version)
+               fatal("bad version");
+       fd = buffer_get_int(&b);
+       if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO))
+               fatal("bad fd");
+       if ((host = get_local_name(fd)) == NULL)
+               fatal("cannot get local name for fd");
+
+       data = buffer_get_string(&b, &dlen);
+       if (valid_request(pw, host, &key, data, dlen) < 0)
+               fatal("not a valid request");
+       xfree(host);
+
+       found = 0;
+       for (i = 0; i < 2; i++) {
+               if (keys[i] != NULL &&
+                   key_equal_public(key, keys[i])) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found)
+               fatal("no matching hostkey found");
+
+       if (key_sign(keys[i], &signature, &slen, data, dlen) != 0)
+               fatal("key_sign failed");
+       xfree(data);
+
+       /* send reply */
+       buffer_clear(&b);
+       buffer_put_string(&b, signature, slen);
+       if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1)
+               fatal("ssh_msg_send failed");
+
+       return (0);
+}
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
new file mode 100644 (file)
index 0000000..650c373
--- /dev/null
@@ -0,0 +1,238 @@
+/* $OpenBSD: ssh-pkcs11-client.c,v 1.2 2010/02/24 06:12:53 djm Exp $ */
+/*
+ * Copyright (c) 2010 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifdef ENABLE_PKCS11
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <sys/socket.h>
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "pathnames.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+#include "key.h"
+#include "authfd.h"
+#include "atomicio.h"
+#include "ssh-pkcs11.h"
+
+/* borrows code from sftp-server and ssh-agent */
+
+int fd = -1;
+pid_t pid = -1;
+
+static void
+send_msg(Buffer *m)
+{
+       u_char buf[4];
+       int mlen = buffer_len(m);
+
+       put_u32(buf, mlen);
+       if (atomicio(vwrite, fd, buf, 4) != 4 ||
+           atomicio(vwrite, fd, buffer_ptr(m),
+           buffer_len(m)) != buffer_len(m))
+               error("write to helper failed");
+       buffer_consume(m, mlen);
+}
+
+static int
+recv_msg(Buffer *m)
+{
+       u_int l, len;
+       u_char buf[1024];
+
+       if ((len = atomicio(read, fd, buf, 4)) != 4) {
+               error("read from helper failed: %u", len);
+               return (0); /* XXX */
+       }
+       len = get_u32(buf);
+       if (len > 256 * 1024)
+               fatal("response too long: %u", len);
+       /* read len bytes into m */
+       buffer_clear(m);
+       while (len > 0) {
+               l = len;
+               if (l > sizeof(buf))
+                       l = sizeof(buf);
+               if (atomicio(read, fd, buf, l) != l) {
+                       error("response from helper failed.");
+                       return (0); /* XXX */
+               }
+               buffer_append(m, buf, l);
+               len -= l;
+       }
+       return (buffer_get_char(m));
+}
+
+int
+pkcs11_init(int interactive)
+{
+       return (0);
+}
+
+void
+pkcs11_terminate(void)
+{
+       close(fd);
+}
+
+static int
+pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
+    int padding)
+{
+       Key key;
+       u_char *blob, *signature = NULL;
+       u_int blen, slen = 0;
+       int ret = -1;
+       Buffer msg;
+
+       if (padding != RSA_PKCS1_PADDING)
+               return (-1);
+       key.type = KEY_RSA;
+       key.rsa = rsa;
+       if (key_to_blob(&key, &blob, &blen) == 0)
+               return -1;
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST);
+       buffer_put_string(&msg, blob, blen);
+       buffer_put_string(&msg, from, flen);
+       buffer_put_int(&msg, 0);
+       xfree(blob);
+       send_msg(&msg);
+
+       if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) {
+               signature = buffer_get_string(&msg, &slen);
+               if (slen <= (u_int)RSA_size(rsa)) {
+                       memcpy(to, signature, slen);
+                       ret = slen;
+               }
+               xfree(signature);
+       }
+       return (ret);
+}
+
+/* redirect the private key encrypt operation to the ssh-pkcs11-helper */
+static int
+wrap_key(RSA *rsa)
+{
+       static RSA_METHOD helper_rsa;
+
+       memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
+       helper_rsa.name = "ssh-pkcs11-helper";
+       helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
+       RSA_set_method(rsa, &helper_rsa);
+       return (0);
+}
+
+static int
+pkcs11_start_helper(void)
+{
+       int pair[2];
+
+       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
+               error("socketpair: %s", strerror(errno));
+               return (-1);
+       }
+       if ((pid = fork()) == -1) {
+               error("fork: %s", strerror(errno));
+               return (-1);
+       } else if (pid == 0) {
+               if ((dup2(pair[1], STDIN_FILENO) == -1) ||
+                   (dup2(pair[1], STDOUT_FILENO) == -1)) {
+                       fprintf(stderr, "dup2: %s\n", strerror(errno));
+                       _exit(1);
+               }
+               close(pair[0]);
+               close(pair[1]);
+               execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER,
+                   (char *) 0);
+               fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER,
+                   strerror(errno));
+               _exit(1);
+       }
+       close(pair[1]);
+       fd = pair[0];
+       return (0);
+}
+
+int
+pkcs11_add_provider(char *name, char *pin, Key ***keysp)
+{
+       Key *k;
+       int i, nkeys;
+       u_char *blob;
+       u_int blen;
+       Buffer msg;
+
+       if (fd < 0 && pkcs11_start_helper() < 0)
+               return (-1);
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY);
+       buffer_put_cstring(&msg, name);
+       buffer_put_cstring(&msg, pin);
+       send_msg(&msg);
+       buffer_clear(&msg);
+
+       if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) {
+               nkeys = buffer_get_int(&msg);
+               *keysp = xcalloc(nkeys, sizeof(Key *));
+               for (i = 0; i < nkeys; i++) {
+                       blob = buffer_get_string(&msg, &blen);
+                       xfree(buffer_get_string(&msg, NULL));
+                       k = key_from_blob(blob, blen);
+                       wrap_key(k->rsa);
+                       (*keysp)[i] = k;
+                       xfree(blob);
+               }
+       } else {
+               nkeys = -1;
+       }
+       buffer_free(&msg);
+       return (nkeys);
+}
+
+int
+pkcs11_del_provider(char *name)
+{
+       int ret = -1;
+       Buffer msg;
+
+       buffer_init(&msg);
+       buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY);
+       buffer_put_cstring(&msg, name);
+       buffer_put_cstring(&msg, "");
+       send_msg(&msg);
+       buffer_clear(&msg);
+
+       if (recv_msg(&msg) == SSH_AGENT_SUCCESS)
+               ret = 0;
+       buffer_free(&msg);
+       return (ret);
+}
+
+#endif /* ENABLE_PKCS11 */
diff --git a/ssh-pkcs11-helper.0 b/ssh-pkcs11-helper.0
new file mode 100644 (file)
index 0000000..2252678
--- /dev/null
@@ -0,0 +1,25 @@
+SSH-PKCS11-HELPER(8)    OpenBSD System Manager's Manual   SSH-PKCS11-HELPER(8)
+
+NAME
+     ssh-pkcs11-helper - ssh-agent helper program for PKCS#11 support
+
+SYNOPSIS
+     ssh-pkcs11-helper
+
+DESCRIPTION
+     ssh-pkcs11-helper is used by ssh-agent(1) to access keys provided by a
+     PKCS#11 token.
+
+     ssh-pkcs11-helper is not intended to be invoked by the user, but from
+     ssh-agent(1).
+
+SEE ALSO
+     ssh(1), ssh-add(1), ssh-agent(1)
+
+HISTORY
+     ssh-pkcs11-helper first appeared in OpenBSD 4.7.
+
+AUTHORS
+     Markus Friedl <markus@openbsd.org>
+
+OpenBSD 4.9                    February 10, 2010                   OpenBSD 4.9
diff --git a/ssh-pkcs11-helper.8 b/ssh-pkcs11-helper.8
new file mode 100644 (file)
index 0000000..9bdaadc
--- /dev/null
@@ -0,0 +1,43 @@
+.\" $OpenBSD: ssh-pkcs11-helper.8,v 1.3 2010/02/10 23:20:38 markus Exp $
+.\"
+.\" Copyright (c) 2010 Markus Friedl.  All rights reserved.
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: February 10 2010 $
+.Dt SSH-PKCS11-HELPER 8
+.Os
+.Sh NAME
+.Nm ssh-pkcs11-helper
+.Nd ssh-agent helper program for PKCS#11 support
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+is used by
+.Xr ssh-agent 1
+to access keys provided by a PKCS#11 token.
+.Pp
+.Nm
+is not intended to be invoked by the user, but from
+.Xr ssh-agent 1 .
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1
+.Sh HISTORY
+.Nm
+first appeared in
+.Ox 4.7 .
+.Sh AUTHORS
+.An Markus Friedl Aq markus@openbsd.org
diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c
new file mode 100644 (file)
index 0000000..8e3f57a
--- /dev/null
@@ -0,0 +1,372 @@
+/* $OpenBSD: ssh-pkcs11-helper.c,v 1.3 2010/02/24 06:12:53 djm Exp $ */
+/*
+ * Copyright (c) 2010 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "log.h"
+#include "misc.h"
+#include "key.h"
+#include "authfd.h"
+#include "ssh-pkcs11.h"
+
+#ifdef ENABLE_PKCS11
+
+/* borrows code from sftp-server and ssh-agent */
+
+struct pkcs11_keyinfo {
+       Key             *key;
+       char            *providername;
+       TAILQ_ENTRY(pkcs11_keyinfo) next;
+};
+
+TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist;
+
+#define MAX_MSG_LENGTH         10240 /*XXX*/
+
+/* helper */
+#define get_int()                      buffer_get_int(&iqueue);
+#define get_string(lenp)               buffer_get_string(&iqueue, lenp);
+
+/* input and output queue */
+Buffer iqueue;
+Buffer oqueue;
+
+static void
+add_key(Key *k, char *name)
+{
+       struct pkcs11_keyinfo *ki;
+
+       ki = xcalloc(1, sizeof(*ki));
+       ki->providername = xstrdup(name);
+       ki->key = k;
+       TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next);
+}
+
+static void
+del_keys_by_name(char *name)
+{
+       struct pkcs11_keyinfo *ki, *nxt;
+
+       for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) {
+               nxt = TAILQ_NEXT(ki, next);
+               if (!strcmp(ki->providername, name)) {
+                       TAILQ_REMOVE(&pkcs11_keylist, ki, next);
+                       xfree(ki->providername);
+                       key_free(ki->key);
+                       free(ki);
+               }
+       }
+}
+
+/* lookup matching 'private' key */
+static Key *
+lookup_key(Key *k)
+{
+       struct pkcs11_keyinfo *ki;
+
+       TAILQ_FOREACH(ki, &pkcs11_keylist, next) {
+               debug("check %p %s", ki, ki->providername);
+               if (key_equal(k, ki->key))
+                       return (ki->key);
+       }
+       return (NULL);
+}
+
+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
+process_add(void)
+{
+       char *name, *pin;
+       Key **keys;
+       int i, nkeys;
+       u_char *blob;
+       u_int blen;
+       Buffer msg;
+
+       buffer_init(&msg);
+       name = get_string(NULL);
+       pin = get_string(NULL);
+       if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) {
+               buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER);
+               buffer_put_int(&msg, nkeys);
+               for (i = 0; i < nkeys; i++) {
+                       key_to_blob(keys[i], &blob, &blen);
+                       buffer_put_string(&msg, blob, blen);
+                       buffer_put_cstring(&msg, name);
+                       xfree(blob);
+                       add_key(keys[i], name);
+               }
+               xfree(keys);
+       } else {
+               buffer_put_char(&msg, SSH_AGENT_FAILURE);
+       }
+       xfree(pin);
+       xfree(name);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+process_del(void)
+{
+       char *name, *pin;
+       Buffer msg;
+
+       buffer_init(&msg);
+       name = get_string(NULL);
+       pin = get_string(NULL);
+       del_keys_by_name(name);
+       if (pkcs11_del_provider(name) == 0)
+                buffer_put_char(&msg, SSH_AGENT_SUCCESS);
+       else
+                buffer_put_char(&msg, SSH_AGENT_FAILURE);
+       xfree(pin);
+       xfree(name);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+process_sign(void)
+{
+       u_char *blob, *data, *signature = NULL;
+       u_int blen, dlen, slen = 0;
+       int ok = -1, flags, ret;
+       Key *key, *found;
+       Buffer msg;
+
+       blob = get_string(&blen);
+       data = get_string(&dlen);
+       flags = get_int(); /* XXX ignore */
+
+       if ((key = key_from_blob(blob, blen)) != NULL) {
+               if ((found = lookup_key(key)) != NULL) {
+                       slen = RSA_size(key->rsa);
+                       signature = xmalloc(slen);
+                       if ((ret = RSA_private_encrypt(dlen, data, signature,
+                           found->rsa, RSA_PKCS1_PADDING)) != -1) {
+                               slen = ret;
+                               ok = 0;
+                       }
+               }
+               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);
+       }
+       xfree(data);
+       xfree(blob);
+       if (signature != NULL)
+               xfree(signature);
+       send_msg(&msg);
+       buffer_free(&msg);
+}
+
+static void
+process(void)
+{
+       u_int msg_len;
+       u_int buf_len;
+       u_int consumed;
+       u_int type;
+       u_char *cp;
+
+       buf_len = buffer_len(&iqueue);
+       if (buf_len < 5)
+               return;         /* Incomplete message. */
+       cp = buffer_ptr(&iqueue);
+       msg_len = get_u32(cp);
+       if (msg_len > MAX_MSG_LENGTH) {
+               error("bad message len %d", msg_len);
+               cleanup_exit(11);
+       }
+       if (buf_len < msg_len + 4)
+               return;
+       buffer_consume(&iqueue, 4);
+       buf_len -= 4;
+       type = buffer_get_char(&iqueue);
+       switch (type) {
+       case SSH_AGENTC_ADD_SMARTCARD_KEY:
+               debug("process_add");
+               process_add();
+               break;
+       case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
+               debug("process_del");
+               process_del();
+               break;
+       case SSH2_AGENTC_SIGN_REQUEST:
+               debug("process_sign");
+               process_sign();
+               break;
+       default:
+               error("Unknown message %d", type);
+               break;
+       }
+       /* discard the remaining bytes from the current packet */
+       if (buf_len < buffer_len(&iqueue)) {
+               error("iqueue grew unexpectedly");
+               cleanup_exit(255);
+       }
+       consumed = buf_len - buffer_len(&iqueue);
+       if (msg_len < consumed) {
+               error("msg_len %d < consumed %d", msg_len, consumed);
+               cleanup_exit(255);
+       }
+       if (msg_len > consumed)
+               buffer_consume(&iqueue, msg_len - consumed);
+}
+
+void
+cleanup_exit(int i)
+{
+       /* XXX */
+       _exit(i);
+}
+
+int
+main(int argc, char **argv)
+{
+       fd_set *rset, *wset;
+       int in, out, max, log_stderr = 0;
+       ssize_t len, olen, set_size;
+       SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
+       LogLevel log_level = SYSLOG_LEVEL_ERROR;
+       char buf[4*4096];
+
+       extern char *optarg;
+       extern char *__progname;
+
+       TAILQ_INIT(&pkcs11_keylist);
+       pkcs11_init(0);
+
+       init_rng();
+       seed_rng();
+       __progname = ssh_get_progname(argv[0]);
+
+       log_init(__progname, log_level, log_facility, log_stderr);
+
+       in = STDIN_FILENO;
+       out = STDOUT_FILENO;
+
+       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);
+
+               /*
+                * Ensure that we can read a full buffer and handle
+                * the worst-case length packet it can generate,
+                * otherwise apply backpressure by stopping reads.
+                */
+               if (buffer_check_alloc(&iqueue, sizeof(buf)) &&
+                   buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
+                       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;
+                       error("select: %s", strerror(errno));
+                       cleanup_exit(2);
+               }
+
+               /* copy stdin to iqueue */
+               if (FD_ISSET(in, rset)) {
+                       len = read(in, buf, sizeof buf);
+                       if (len == 0) {
+                               debug("read eof");
+                               cleanup_exit(0);
+                       } else if (len < 0) {
+                               error("read: %s", strerror(errno));
+                               cleanup_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: %s", strerror(errno));
+                               cleanup_exit(1);
+                       } else {
+                               buffer_consume(&oqueue, len);
+                       }
+               }
+
+               /*
+                * Process requests from client if we can fit the results
+                * into the output buffer, otherwise stop processing input
+                * and let the output queue drain.
+                */
+               if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH))
+                       process();
+       }
+}
+#else /* ENABLE_PKCS11 */
+int
+main(int argc, char **argv)
+{
+       extern char *__progname;
+
+       __progname = ssh_get_progname(argv[0]);
+       log_init(__progname, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTH, 0);
+       fatal("PKCS#11 support disabled at compile time");
+}
+#endif /* ENABLE_PKCS11 */
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
new file mode 100644 (file)
index 0000000..286c232
--- /dev/null
@@ -0,0 +1,593 @@
+/* $OpenBSD: ssh-pkcs11.c,v 1.6 2010/06/08 21:32:19 markus Exp $ */
+/*
+ * Copyright (c) 2010 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifdef ENABLE_PKCS11
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <string.h>
+#include <dlfcn.h>
+
+#include "openbsd-compat/sys-queue.h"
+
+#define CRYPTOKI_COMPAT
+#include "pkcs11.h"
+
+#include "log.h"
+#include "misc.h"
+#include "key.h"
+#include "ssh-pkcs11.h"
+#include "xmalloc.h"
+
+struct pkcs11_slotinfo {
+       CK_TOKEN_INFO           token;
+       CK_SESSION_HANDLE       session;
+       int                     logged_in;
+};
+
+struct pkcs11_provider {
+       char                    *name;
+       void                    *handle;
+       CK_FUNCTION_LIST        *function_list;
+       CK_INFO                 info;
+       CK_ULONG                nslots;
+       CK_SLOT_ID              *slotlist;
+       struct pkcs11_slotinfo  *slotinfo;
+       int                     valid;
+       int                     refcount;
+       TAILQ_ENTRY(pkcs11_provider) next;
+};
+
+TAILQ_HEAD(, pkcs11_provider) pkcs11_providers;
+
+struct pkcs11_key {
+       struct pkcs11_provider  *provider;
+       CK_ULONG                slotidx;
+       int                     (*orig_finish)(RSA *rsa);
+       RSA_METHOD              rsa_method;
+       char                    *keyid;
+       int                     keyid_len;
+};
+
+int pkcs11_interactive = 0;
+
+int
+pkcs11_init(int interactive)
+{
+       pkcs11_interactive = interactive;
+       TAILQ_INIT(&pkcs11_providers);
+       return (0);
+}
+
+/*
+ * finalize a provider shared libarary, it's no longer usable.
+ * however, there might still be keys referencing this provider,
+ * so the actuall freeing of memory is handled by pkcs11_provider_unref().
+ * this is called when a provider gets unregistered.
+ */
+static void
+pkcs11_provider_finalize(struct pkcs11_provider *p)
+{
+       CK_RV rv;
+       CK_ULONG i;
+
+       debug("pkcs11_provider_finalize: %p refcount %d valid %d",
+           p, p->refcount, p->valid);
+       if (!p->valid)
+               return;
+       for (i = 0; i < p->nslots; i++) {
+               if (p->slotinfo[i].session &&
+                   (rv = p->function_list->C_CloseSession(
+                   p->slotinfo[i].session)) != CKR_OK)
+                       error("C_CloseSession failed: %lu", rv);
+       }
+       if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
+               error("C_Finalize failed: %lu", rv);
+       p->valid = 0;
+       p->function_list = NULL;
+       dlclose(p->handle);
+}
+
+/*
+ * remove a reference to the provider.
+ * called when a key gets destroyed or when the provider is unregistered.
+ */
+static void
+pkcs11_provider_unref(struct pkcs11_provider *p)
+{
+       debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
+       if (--p->refcount <= 0) {
+               if (p->valid)
+                       error("pkcs11_provider_unref: %p still valid", p);
+               xfree(p->slotlist);
+               xfree(p->slotinfo);
+               xfree(p);
+       }
+}
+
+/* unregister all providers, keys might still point to the providers */
+void
+pkcs11_terminate(void)
+{
+       struct pkcs11_provider *p;
+
+       while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) {
+               TAILQ_REMOVE(&pkcs11_providers, p, next);
+               pkcs11_provider_finalize(p);
+               pkcs11_provider_unref(p);
+       }
+}
+
+/* lookup provider by name */
+static struct pkcs11_provider *
+pkcs11_provider_lookup(char *provider_id)
+{
+       struct pkcs11_provider *p;
+
+       TAILQ_FOREACH(p, &pkcs11_providers, next) {
+               debug("check %p %s", p, p->name);
+               if (!strcmp(provider_id, p->name))
+                       return (p);
+       }
+       return (NULL);
+}
+
+/* unregister provider by name */
+int
+pkcs11_del_provider(char *provider_id)
+{
+       struct pkcs11_provider *p;
+
+       if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
+               TAILQ_REMOVE(&pkcs11_providers, p, next);
+               pkcs11_provider_finalize(p);
+               pkcs11_provider_unref(p);
+               return (0);
+       }
+       return (-1);
+}
+
+/* openssl callback for freeing an RSA key */
+static int
+pkcs11_rsa_finish(RSA *rsa)
+{
+       struct pkcs11_key       *k11;
+       int rv = -1;
+
+       if ((k11 = RSA_get_app_data(rsa)) != NULL) {
+               if (k11->orig_finish)
+                       rv = k11->orig_finish(rsa);
+               if (k11->provider)
+                       pkcs11_provider_unref(k11->provider);
+               if (k11->keyid)
+                       xfree(k11->keyid);
+               xfree(k11);
+       }
+       return (rv);
+}
+
+/* find a single 'obj' for given attributes */
+static int
+pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
+    CK_ULONG nattr, CK_OBJECT_HANDLE *obj)
+{
+       CK_FUNCTION_LIST        *f;
+       CK_SESSION_HANDLE       session;
+       CK_ULONG                nfound = 0;
+       CK_RV                   rv;
+       int                     ret = -1;
+
+       f = p->function_list;
+       session = p->slotinfo[slotidx].session;
+       if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
+               error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
+               return (-1);
+       }
+       if ((rv = f->C_FindObjects(session, obj, 1, &nfound)) != CKR_OK ||
+           nfound != 1) {
+               debug("C_FindObjects failed (nfound %lu nattr %lu): %lu",
+                   nfound, nattr, rv);
+       } else
+               ret = 0;
+       if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
+               error("C_FindObjectsFinal failed: %lu", rv);
+       return (ret);
+}
+
+/* openssl callback doing the actual signing operation */
+static int
+pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
+    int padding)
+{
+       struct pkcs11_key       *k11;
+       struct pkcs11_slotinfo  *si;
+       CK_FUNCTION_LIST        *f;
+       CK_OBJECT_HANDLE        obj;
+       CK_ULONG                tlen = 0;
+       CK_RV                   rv;
+       CK_OBJECT_CLASS         private_key_class = CKO_PRIVATE_KEY;
+       CK_BBOOL                true_val = CK_TRUE;
+       CK_MECHANISM            mech = {
+               CKM_RSA_PKCS, NULL_PTR, 0
+       };
+       CK_ATTRIBUTE            key_filter[] = {
+               {CKA_CLASS, NULL, sizeof(private_key_class) },
+               {CKA_ID, NULL, 0},
+               {CKA_SIGN, NULL, sizeof(true_val) }
+       };
+       char                    *pin, prompt[1024];
+       int                     rval = -1;
+
+       /* some compilers complain about non-constant initializer so we
+          use NULL in CK_ATTRIBUTE above and set the values here */
+       key_filter[0].pValue = &private_key_class;
+       key_filter[2].pValue = &true_val;
+
+       if ((k11 = RSA_get_app_data(rsa)) == NULL) {
+               error("RSA_get_app_data failed for rsa %p", rsa);
+               return (-1);
+       }
+       if (!k11->provider || !k11->provider->valid) {
+               error("no pkcs11 (valid) provider for rsa %p", rsa);
+               return (-1);
+       }
+       f = k11->provider->function_list;
+       si = &k11->provider->slotinfo[k11->slotidx];
+       if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
+               if (!pkcs11_interactive) {
+                       error("need pin");
+                       return (-1);
+               }
+               snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
+                   si->token.label);
+               pin = read_passphrase(prompt, RP_ALLOW_EOF);
+               if (pin == NULL)
+                       return (-1);    /* bail out */
+               if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin)))
+                   != CKR_OK) {
+                       xfree(pin);
+                       error("C_Login failed: %lu", rv);
+                       return (-1);
+               }
+               xfree(pin);
+               si->logged_in = 1;
+       }
+       key_filter[1].pValue = k11->keyid;
+       key_filter[1].ulValueLen = k11->keyid_len;
+       /* try to find object w/CKA_SIGN first, retry w/o */
+       if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
+           pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
+               error("cannot find private key");
+       } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
+               error("C_SignInit failed: %lu", rv);
+       } else {
+               /* XXX handle CKR_BUFFER_TOO_SMALL */
+               tlen = RSA_size(rsa);
+               rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
+               if (rv == CKR_OK) 
+                       rval = tlen;
+               else 
+                       error("C_Sign failed: %lu", rv);
+       }
+       return (rval);
+}
+
+static int
+pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
+    int padding)
+{
+       return (-1);
+}
+
+/* redirect private key operations for rsa key to pkcs11 token */
+static int
+pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
+    CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
+{
+       struct pkcs11_key       *k11;
+       const RSA_METHOD        *def = RSA_get_default_method();
+
+       k11 = xcalloc(1, sizeof(*k11));
+       k11->provider = provider;
+       provider->refcount++;   /* provider referenced by RSA key */
+       k11->slotidx = slotidx;
+       /* identify key object on smartcard */
+       k11->keyid_len = keyid_attrib->ulValueLen;
+       k11->keyid = xmalloc(k11->keyid_len);
+       memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
+       k11->orig_finish = def->finish;
+       memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method));
+       k11->rsa_method.name = "pkcs11";
+       k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt;
+       k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt;
+       k11->rsa_method.finish = pkcs11_rsa_finish;
+       RSA_set_method(rsa, &k11->rsa_method);
+       RSA_set_app_data(rsa, k11);
+       return (0);
+}
+
+/* remove trailing spaces */
+static void
+rmspace(char *buf, size_t len)
+{
+       size_t i;
+
+       if (!len)
+               return;
+       for (i = len - 1;  i > 0; i--)
+               if (i == len - 1 || buf[i] == ' ')
+                       buf[i] = '\0';
+               else
+                       break;
+}
+
+/*
+ * open a pkcs11 session and login if required.
+ * if pin == NULL we delay login until key use
+ */
+static int
+pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin)
+{
+       CK_RV                   rv;
+       CK_FUNCTION_LIST        *f;
+       CK_SESSION_HANDLE       session;
+       int                     login_required;
+
+       f = p->function_list;
+       login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
+       if (pin && login_required && !strlen(pin)) {
+               error("pin required");
+               return (-1);
+       }
+       if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
+           CKF_SERIAL_SESSION, NULL, NULL, &session))
+           != CKR_OK) {
+               error("C_OpenSession failed: %lu", rv);
+               return (-1);
+       }
+       if (login_required && pin) {
+               if ((rv = f->C_Login(session, CKU_USER, pin, strlen(pin)))
+                   != CKR_OK) {
+                       error("C_Login failed: %lu", rv);
+                       if ((rv = f->C_CloseSession(session)) != CKR_OK)
+                               error("C_CloseSession failed: %lu", rv);
+                       return (-1);
+               }
+               p->slotinfo[slotidx].logged_in = 1;
+       }
+       p->slotinfo[slotidx].session = session;
+       return (0);
+}
+
+/*
+ * lookup public keys for token in slot identified by slotidx,
+ * add 'wrapped' public keys to the 'keysp' array and increment nkeys.
+ * keysp points to an (possibly empty) array with *nkeys keys.
+ */
+static int
+pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp,
+    int *nkeys)
+{
+       Key                     *key;
+       RSA                     *rsa;
+       int                     i;
+       CK_RV                   rv;
+       CK_OBJECT_HANDLE        obj;
+       CK_ULONG                nfound;
+       CK_SESSION_HANDLE       session;
+       CK_FUNCTION_LIST        *f;
+       CK_OBJECT_CLASS         pubkey_class = CKO_PUBLIC_KEY;
+       CK_ATTRIBUTE            pubkey_filter[] = {
+               { CKA_CLASS, NULL, sizeof(pubkey_class) }
+       };
+       CK_ATTRIBUTE            attribs[] = {
+               { CKA_ID, NULL, 0 },
+               { CKA_MODULUS, NULL, 0 },
+               { CKA_PUBLIC_EXPONENT, NULL, 0 }
+       };
+
+       /* some compilers complain about non-constant initializer so we
+          use NULL in CK_ATTRIBUTE above and set the value here */
+       pubkey_filter[0].pValue = &pubkey_class;
+
+       f = p->function_list;
+       session = p->slotinfo[slotidx].session;
+       /* setup a filter the looks for public keys */
+       if ((rv = f->C_FindObjectsInit(session, pubkey_filter, 1)) != CKR_OK) {
+               error("C_FindObjectsInit failed: %lu", rv);
+               return (-1);
+       }
+       while (1) {
+               /* XXX 3 attributes in attribs[] */
+               for (i = 0; i < 3; i++) {
+                       attribs[i].pValue = NULL;
+                       attribs[i].ulValueLen = 0;
+               }
+               if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK
+                   || nfound == 0)
+                       break;
+               /* found a key, so figure out size of the attributes */
+               if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
+                   != CKR_OK) {
+                       error("C_GetAttributeValue failed: %lu", rv);
+                       continue;
+               }
+               /* check that none of the attributes are zero length */
+               if (attribs[0].ulValueLen == 0 ||
+                   attribs[1].ulValueLen == 0 ||
+                   attribs[2].ulValueLen == 0) {
+                       continue;
+               }
+               /* allocate buffers for attributes */
+               for (i = 0; i < 3; i++)
+                       attribs[i].pValue = xmalloc(attribs[i].ulValueLen);
+               /* retrieve ID, modulus and public exponent of RSA key */
+               if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
+                   != CKR_OK) {
+                       error("C_GetAttributeValue failed: %lu", rv);
+               } else if ((rsa = RSA_new()) == NULL) {
+                       error("RSA_new failed");
+               } else {
+                       rsa->n = BN_bin2bn(attribs[1].pValue,
+                           attribs[1].ulValueLen, NULL);
+                       rsa->e = BN_bin2bn(attribs[2].pValue,
+                           attribs[2].ulValueLen, NULL);
+                       if (rsa->n && rsa->e &&
+                           pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
+                               key = key_new(KEY_UNSPEC);
+                               key->rsa = rsa;
+                               key->type = KEY_RSA;
+                               key->flags |= KEY_FLAG_EXT;
+                               /* expand key array and add key */
+                               *keysp = xrealloc(*keysp, *nkeys + 1,
+                                   sizeof(Key *));
+                               (*keysp)[*nkeys] = key;
+                               *nkeys = *nkeys + 1;
+                               debug("have %d keys", *nkeys);
+                       } else {
+                               RSA_free(rsa);
+                       }
+               }
+               for (i = 0; i < 3; i++)
+                       xfree(attribs[i].pValue);
+       }
+       if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
+               error("C_FindObjectsFinal failed: %lu", rv);
+       return (0);
+}
+
+/* register a new provider, fails if provider already exists */
+int
+pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp)
+{
+       int nkeys, need_finalize = 0;
+       struct pkcs11_provider *p = NULL;
+       void *handle = NULL;
+       CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
+       CK_RV rv;
+       CK_FUNCTION_LIST *f = NULL;
+       CK_TOKEN_INFO *token;
+       CK_ULONG i;
+
+       *keyp = NULL;
+       if (pkcs11_provider_lookup(provider_id) != NULL) {
+               error("provider already registered: %s", provider_id);
+               goto fail;
+       }
+       /* open shared pkcs11-libarary */
+       if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
+               error("dlopen %s failed: %s", provider_id, dlerror());
+               goto fail;
+       }
+       if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
+               error("dlsym(C_GetFunctionList) failed: %s", dlerror());
+               goto fail;
+       }
+       p = xcalloc(1, sizeof(*p));
+       p->name = xstrdup(provider_id);
+       p->handle = handle;
+       /* setup the pkcs11 callbacks */
+       if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
+               error("C_GetFunctionList failed: %lu", rv);
+               goto fail;
+       }
+       p->function_list = f;
+       if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
+               error("C_Initialize failed: %lu", rv);
+               goto fail;
+       }
+       need_finalize = 1;
+       if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
+               error("C_GetInfo failed: %lu", rv);
+               goto fail;
+       }
+       rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
+       rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
+       debug("manufacturerID <%s> cryptokiVersion %d.%d"
+           " libraryDescription <%s> libraryVersion %d.%d",
+           p->info.manufacturerID,
+           p->info.cryptokiVersion.major,
+           p->info.cryptokiVersion.minor,
+           p->info.libraryDescription,
+           p->info.libraryVersion.major,
+           p->info.libraryVersion.minor);
+       if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
+               error("C_GetSlotList failed: %lu", rv);
+               goto fail;
+       }
+       if (p->nslots == 0) {
+               error("no slots");
+               goto fail;
+       }
+       p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
+       if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
+           != CKR_OK) {
+               error("C_GetSlotList failed: %lu", rv);
+               goto fail;
+       }
+       p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
+       p->valid = 1;
+       nkeys = 0;
+       for (i = 0; i < p->nslots; i++) {
+               token = &p->slotinfo[i].token;
+               if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
+                   != CKR_OK) {
+                       error("C_GetTokenInfo failed: %lu", rv);
+                       continue;
+               }
+               rmspace(token->label, sizeof(token->label));
+               rmspace(token->manufacturerID, sizeof(token->manufacturerID));
+               rmspace(token->model, sizeof(token->model));
+               rmspace(token->serialNumber, sizeof(token->serialNumber));
+               debug("label <%s> manufacturerID <%s> model <%s> serial <%s>"
+                   " flags 0x%lx",
+                   token->label, token->manufacturerID, token->model,
+                   token->serialNumber, token->flags);
+               /* open session, login with pin and retrieve public keys */
+               if (pkcs11_open_session(p, i, pin) == 0)
+                       pkcs11_fetch_keys(p, i, keyp, &nkeys);
+       }
+       if (nkeys > 0) {
+               TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
+               p->refcount++;  /* add to provider list */
+               return (nkeys);
+       }
+       error("no keys");
+       /* don't add the provider, since it does not have any keys */
+fail:
+       if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
+               error("C_Finalize failed: %lu", rv);
+       if (p) {
+               if (p->slotlist)
+                       xfree(p->slotlist);
+               if (p->slotinfo)
+                       xfree(p->slotinfo);
+               xfree(p);
+       }
+       if (handle)
+               dlclose(handle);
+       return (-1);
+}
+
+#endif /* ENABLE_PKCS11 */
diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h
new file mode 100644 (file)
index 0000000..59f456a
--- /dev/null
@@ -0,0 +1,20 @@
+/* $OpenBSD: ssh-pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */
+/*
+ * Copyright (c) 2010 Markus Friedl.  All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+int    pkcs11_init(int);
+void   pkcs11_terminate(void);
+int    pkcs11_add_provider(char *, char *, Key ***);
+int    pkcs11_del_provider(char *);
diff --git a/ssh-rand-helper.0 b/ssh-rand-helper.0
new file mode 100644 (file)
index 0000000..93d3554
--- /dev/null
@@ -0,0 +1,51 @@
+SSH-RAND-HELPER(8)      OpenBSD System Manager's Manual     SSH-RAND-HELPER(8)
+
+NAME
+     ssh-rand-helper - random number gatherer for OpenSSH
+
+SYNOPSIS
+     ssh-rand-hlper [-vxXh] [-b bytes]
+
+DESCRIPTION
+     ssh-rand-helper is a small helper program used by ssh(1), ssh-add(1),
+     ssh-agent(1), ssh-keygen(1), ssh-keyscan(1) and sshd(8) to gather random
+     numbers of cryptographic quality if the openssl(4) library has not been
+     configured to provide them itself.
+
+     Normally ssh-rand-helper will generate a strong random seed and provide
+     it to the calling program via standard output. If standard output is a
+     tty, ssh-rand-helper will instead print the seed in hexidecimal format
+     unless told otherwise.
+
+     ssh-rand-helper will by default gather random numbers from the system
+     commands listed in /etc/ssh/ssh_prng_cmds.  The output of each of the
+     commands listed will be hashed and used to generate a random seed for the
+     calling program.  ssh-rand-helper will also store seed files in
+     ~/.ssh/prng_seed between executions.
+
+     Alternately, ssh-rand-helper may be configured at build time to collect
+     random numbers from a EGD/PRNGd server via a unix domain or localhost tcp
+     socket.
+
+     This program is not intended to be run by the end-user, so the few
+     commandline options are for debugging purposes only.
+
+     -b bytes
+             Specify the number of random bytes to include in the output.
+
+     -x      Output a hexidecimal instead of a binary seed.
+
+     -X      Force output of a binary seed, even if standard output is a tty
+
+     -v      Turn on debugging message. Multiple -v options will increase the
+             debugging level.
+
+     -h      Display a summary of options.
+
+AUTHORS
+     Damien Miller <djm@mindrot.org>
+
+SEE ALSO
+     ssh(1), ssh-add(1), ssh-keygen(1), sshd(8)
+
+OpenBSD 4.9                     April 14, 2002                     OpenBSD 4.9
diff --git a/ssh-rand-helper.8 b/ssh-rand-helper.8
new file mode 100644 (file)
index 0000000..af5a72f
--- /dev/null
@@ -0,0 +1,94 @@
+.\" $Id: ssh-rand-helper.8,v 1.3 2007/01/22 01:44:53 djm Exp $
+.\"
+.\" Copyright (c) 2002 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 April 14, 2002
+.Dt SSH-RAND-HELPER 8
+.Os
+.Sh NAME
+.Nm ssh-rand-helper
+.Nd random number gatherer for OpenSSH
+.Sh SYNOPSIS
+.Nm ssh-rand-hlper
+.Op Fl vxXh
+.Op Fl b Ar bytes
+.Sh DESCRIPTION
+.Nm
+is a small helper program used by
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr ssh-keyscan 1
+and
+.Xr sshd 8
+to gather random numbers of cryptographic quality if the
+.Xr openssl 4
+library has not been configured to provide them itself.
+.Pp
+Normally
+.Nm
+will generate a strong random seed and provide it to the calling
+program via standard output. If standard output is a tty,
+.Nm
+will instead print the seed in hexidecimal format unless told otherwise.
+.Pp
+.Nm
+will by default gather random numbers from the system commands listed
+in
+.Pa /etc/ssh/ssh_prng_cmds .
+The output of each of the commands listed will be hashed and used to
+generate a random seed for the calling program.
+.Nm
+will also store seed files in
+.Pa ~/.ssh/prng_seed
+between executions.
+.Pp
+Alternately,
+.Nm
+may be configured at build time to collect random numbers from a
+EGD/PRNGd server via a unix domain or localhost tcp socket.
+.Pp
+This program is not intended to be run by the end-user, so the few
+commandline options are for debugging purposes only.
+.Bl -tag -width Ds
+.It Fl b Ar bytes
+Specify the number of random bytes to include in the output.
+.It Fl x
+Output a hexidecimal instead of a binary seed.
+.It Fl X
+Force output of a binary seed, even if standard output is a tty
+.It Fl v
+Turn on debugging message. Multiple
+.Fl v
+options will increase the debugging level.
+.It Fl h
+Display a summary of options.
+.El
+.Sh AUTHORS
+Damien Miller <djm@mindrot.org>
+.Sh SEE ALSO
+.Xr ssh 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-keygen 1 ,
+.Xr sshd 8
diff --git a/ssh-rand-helper.c b/ssh-rand-helper.c
new file mode 100644 (file)
index 0000000..fa50704
--- /dev/null
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 2001-2002 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 <sys/types.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.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 "misc.h"
+#include "xmalloc.h"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+
+/* Number of bytes we write out */
+#define OUTPUT_SEED_SIZE       48
+
+/* Length of on-disk seedfiles */
+#define SEED_FILE_SIZE         1024
+
+/* Maximum number of command-line arguments to read from file */
+#define NUM_ARGS               10
+
+/* Minimum number of usable commands to be considered sufficient */
+#define MIN_ENTROPY_SOURCES    16
+
+/* Path to on-disk seed file (relative to user's home directory */
+#ifndef SSH_PRNG_SEED_FILE
+# define SSH_PRNG_SEED_FILE      _PATH_SSH_USER_DIR"/prng_seed"
+#endif
+
+/* Path to PRNG commands list */
+#ifndef SSH_PRNG_COMMAND_FILE
+# define SSH_PRNG_COMMAND_FILE   SSHDIR "/ssh_prng_cmds"
+#endif
+
+extern char *__progname;
+
+#define WHITESPACE " \t\n"
+
+#ifndef RUSAGE_SELF
+# define RUSAGE_SELF 0
+#endif
+#ifndef RUSAGE_CHILDREN
+# define RUSAGE_CHILDREN 0
+#endif
+
+#if !defined(PRNGD_SOCKET) && !defined(PRNGD_PORT)
+# define USE_SEED_FILES
+#endif
+
+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[NUM_ARGS]; /* XXX: arbitrary limit */
+       /* full command string (debug) */
+       char *cmdstring;
+} entropy_cmd_t;
+
+/* slow command timeouts (all in milliseconds) */
+/* static int entropy_timeout_default = ENTROPY_TIMEOUT_MSEC; */
+static int entropy_timeout_current = ENTROPY_TIMEOUT_MSEC;
+
+/* this is initialised from a file, by prng_read_commands() */
+static entropy_cmd_t *entropy_cmds = NULL;
+
+/* Prototypes */
+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_command_output(entropy_cmd_t *src, unsigned char *hash);
+int get_random_bytes_prngd(unsigned char *buf, int len,
+    unsigned short tcp_port, char *socket_path);
+
+/*
+ * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon
+ * listening either on 'tcp_port', or via Unix domain socket at *
+ * 'socket_path'.
+ * Either a non-zero tcp_port or a non-null socket_path must be
+ * supplied.
+ * Returns 0 on success, -1 on error
+ */
+int
+get_random_bytes_prngd(unsigned char *buf, int len,
+    unsigned short tcp_port, char *socket_path)
+{
+       int fd, addr_len, rval, errors;
+       u_char msg[2];
+       struct sockaddr_storage addr;
+       struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
+       struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr;
+       mysig_t old_sigpipe;
+
+       /* Sanity checks */
+       if (socket_path == NULL && tcp_port == 0)
+               fatal("You must specify a port or a socket");
+       if (socket_path != NULL &&
+           strlen(socket_path) >= sizeof(addr_un->sun_path))
+               fatal("Random pool path is too long");
+       if (len <= 0 || len > 255)
+               fatal("Too many bytes (%d) to read from PRNGD", len);
+
+       memset(&addr, '\0', sizeof(addr));
+
+       if (tcp_port != 0) {
+               addr_in->sin_family = AF_INET;
+               addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+               addr_in->sin_port = htons(tcp_port);
+               addr_len = sizeof(*addr_in);
+       } else {
+               addr_un->sun_family = AF_UNIX;
+               strlcpy(addr_un->sun_path, socket_path,
+                   sizeof(addr_un->sun_path));
+               addr_len = offsetof(struct sockaddr_un, sun_path) +
+                   strlen(socket_path) + 1;
+       }
+
+       old_sigpipe = mysignal(SIGPIPE, SIG_IGN);
+
+       errors = 0;
+       rval = -1;
+reopen:
+       fd = socket(addr.ss_family, SOCK_STREAM, 0);
+       if (fd == -1) {
+               error("Couldn't create socket: %s", strerror(errno));
+               goto done;
+       }
+
+       if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {
+               if (tcp_port != 0) {
+                       error("Couldn't connect to PRNGD port %d: %s",
+                           tcp_port, strerror(errno));
+               } else {
+                       error("Couldn't connect to PRNGD socket \"%s\": %s",
+                           addr_un->sun_path, strerror(errno));
+               }
+               goto done;
+       }
+
+       /* Send blocking read request to PRNGD */
+       msg[0] = 0x02;
+       msg[1] = len;
+
+       if (atomicio(vwrite, 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) != (size_t)len) {
+               if (errno == EPIPE && errors < 10) {
+                       close(fd);
+                       errors++;
+                       goto reopen;
+               }
+               error("Couldn't read from PRNGD socket: %s",
+                   strerror(errno));
+               goto done;
+       }
+
+       rval = 0;
+done:
+       mysignal(SIGPIPE, old_sigpipe);
+       if (fd != -1)
+               close(fd);
+       return rval;
+}
+
+static int
+seed_from_prngd(unsigned char *buf, size_t bytes)
+{
+#ifdef PRNGD_PORT
+       debug("trying egd/prngd port %d", PRNGD_PORT);
+       if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0)
+               return 0;
+#endif
+#ifdef PRNGD_SOCKET
+       debug("trying egd/prngd socket %s", PRNGD_SOCKET);
+       if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0)
+               return 0;
+#endif
+       return -1;
+}
+
+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
+timeval_diff(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_command_output(entropy_cmd_t *src, unsigned char *hash)
+{
+       char buf[8192];
+       fd_set rdset;
+       int bytes_read, cmd_eof, error_abort, msec_elapsed, p[2];
+       int status, total_bytes_read;
+       static int devnull = -1;
+       pid_t pid;
+       SHA_CTX sha;
+       struct timeval tv_start, tv_current;
+
+       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);
+
+                       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);
+
+       cmd_eof = error_abort = msec_elapsed = total_bytes_read = 0;
+       while (!error_abort && !cmd_eof) {
+               int ret;
+               struct timeval tv;
+               int msec_remaining;
+
+               (void) gettimeofday(&tv_current, 0);
+               msec_elapsed = timeval_diff(&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;
+                       kill(pid, SIGINT);
+                       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;
+}
+
+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 c;
+       double entropy, total_entropy;
+       unsigned char hash[SHA_DIGEST_LENGTH];
+
+       total_entropy = 0;
+       for(c = 0; entropy_cmds[c].path != NULL; c++) {
+               if (!entropy_cmds[c].badness) {
+                       /* Hash output from command */
+                       entropy = hash_command_output(&entropy_cmds[c],
+                           hash);
+
+                       /* Scale back estimate by command's rate */
+                       entropy *= entropy_cmds[c].rate;
+
+                       /* Upper bound of entropy is SHA_DIGEST_LENGTH */
+                       if (entropy > SHA_DIGEST_LENGTH)
+                               entropy = SHA_DIGEST_LENGTH;
+
+                       /* Stir it in */
+                       RAND_add(hash, sizeof(hash), entropy);
+
+                       debug3("Got %0.2f bytes of entropy from '%s'",
+                           entropy, entropy_cmds[c].cmdstring);
+
+                       total_entropy += entropy;
+
+                       /* Execution time should be a bit unpredictable */
+                       total_entropy += stir_gettimeofday(0.05);
+                       total_entropy += stir_clock(0.05);
+                       total_entropy += stir_rusage(RUSAGE_SELF, 0.1);
+                       total_entropy += stir_rusage(RUSAGE_CHILDREN, 0.1);
+               } else {
+                       debug2("Command '%s' disabled (badness %d)",
+                           entropy_cmds[c].cmdstring,
+                           entropy_cmds[c].badness);
+
+                       if (entropy_cmds[c].badness > 0)
+                               entropy_cmds[c].badness--;
+               }
+       }
+
+       return total_entropy;
+}
+
+/*
+ * prng seedfile functions
+ */
+int
+prng_check_seedfile(char *filename)
+{
+       struct stat st;
+
+       /*
+        * XXX raceable: eg replace seed between this stat and subsequent
+        * open. Not such a problem because we don't really trust the
+        * seed file anyway.
+        * XXX: use secure path checking as elsewhere in OpenSSH
+        */
+       if (lstat(filename, &st) == -1) {
+               /* Give up on hard errors */
+               if (errno != ENOENT)
+                       debug("WARNING: Couldn't stat random seed file "
+                           "\"%.100s\": %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 == getuid())) {
+               debug("WARNING: PRNG seedfile %.100s must be mode 0600, "
+                   "owned by uid %li", filename, (long int)getuid());
+               return 0;
+       }
+
+       return 1;
+}
+
+void
+prng_write_seedfile(void)
+{
+       int fd, save_errno;
+       unsigned char seed[SEED_FILE_SIZE];
+       char filename[MAXPATHLEN], tmpseed[MAXPATHLEN];
+       struct passwd *pw;
+       mode_t old_umask;
+
+       pw = getpwuid(getuid());
+       if (pw == NULL)
+               fatal("Couldn't get password entry for current user "
+                   "(%li): %s", (long int)getuid(), strerror(errno));
+
+       /* Try to ensure that the parent directory is there */
+       snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+           _PATH_SSH_USER_DIR);
+       if (mkdir(filename, 0700) < 0 && errno != EEXIST)
+               fatal("mkdir %.200s: %s", filename, strerror(errno));
+
+       snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir,
+           SSH_PRNG_SEED_FILE);
+
+       strlcpy(tmpseed, filename, sizeof(tmpseed));
+       if (strlcat(tmpseed, ".XXXXXXXXXX", sizeof(tmpseed)) >=
+           sizeof(tmpseed))
+               fatal("PRNG seed filename too long");
+
+       if (RAND_bytes(seed, sizeof(seed)) <= 0)
+               fatal("PRNG seed extraction failed");
+
+       /* Don't care if the seed doesn't exist */
+       prng_check_seedfile(filename);
+
+       old_umask = umask(0177);
+
+       if ((fd = mkstemp(tmpseed)) == -1) {
+               debug("WARNING: couldn't make temporary PRNG seedfile %.100s "
+                   "(%.100s)", tmpseed, strerror(errno));
+       } else {
+               debug("writing PRNG seed to file %.100s", tmpseed);
+               if (atomicio(vwrite, fd, &seed, sizeof(seed)) < sizeof(seed)) {
+                       save_errno = errno;
+                       close(fd);
+                       unlink(tmpseed);
+                       fatal("problem writing PRNG seedfile %.100s "
+                           "(%.100s)", filename, strerror(save_errno));
+               }
+               close(fd);
+               debug("moving temporary PRNG seed to file %.100s", filename);
+               if (rename(tmpseed, filename) == -1) {
+                       save_errno = errno;
+                       unlink(tmpseed);
+                       fatal("problem renaming PRNG seedfile from %.100s "
+                           "to %.100s (%.100s)", tmpseed, filename,
+                           strerror(save_errno));
+               }
+       }
+       umask(old_umask);
+}
+
+void
+prng_read_seedfile(void)
+{
+       int fd;
+       char seed[SEED_FILE_SIZE], filename[MAXPATHLEN];
+       struct passwd *pw;
+
+       pw = getpwuid(getuid());
+       if (pw == NULL)
+               fatal("Couldn't get password entry for current user "
+                   "(%li): %s", (long int)getuid(), 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 invalid, 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)
+{
+       char cmd[SEED_FILE_SIZE], *cp, line[1024], path[SEED_FILE_SIZE];
+       double est;
+       entropy_cmd_t *entcmd;
+       FILE *f;
+       int cur_cmd, linenum, num_cmds, arg;
+
+       if ((f = fopen(cmdfilename, "r")) == NULL) {
+               fatal("couldn't read entropy commands file %.100s: %.100s",
+                   cmdfilename, strerror(errno));
+       }
+
+       num_cmds = 64;
+       entcmd = xcalloc(num_cmds, sizeof(entropy_cmd_t));
+
+       /* Read in file */
+       cur_cmd = linenum = 0;
+       while (fgets(line, sizeof(line), f)) {
+               linenum++;
+
+               /* Skip leading whitespace, blank lines and comments */
+               cp = line + strspn(line, WHITESPACE);
+               if ((*cp == 0) || (*cp == '#'))
+                       continue; /* done with this line */
+
+               /*
+                * The first non-whitespace char should be a double quote
+                * delimiting the 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, NULL);
+
+               /* 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;
+               do {
+                       entcmd[cur_cmd].args[arg] = xstrdup(cp);
+                       arg++;
+               } while(arg < NUM_ARGS && (cp = strtok(NULL, WHITESPACE)));
+
+               if (strtok(NULL, WHITESPACE))
+                       error("ignored extra commands (max %d), %.100s "
+                           "line %d", NUM_ARGS, 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_cmd_t));
+               }
+       }
+
+       /* zero the last entry */
+       memset(&entcmd[cur_cmd], '\0', sizeof(entropy_cmd_t));
+
+       /* trim to size */
+       entropy_cmds = xrealloc(entcmd, (cur_cmd + 1),
+           sizeof(entropy_cmd_t));
+
+       debug("Loaded %d entropy commands from %.100s", cur_cmd,
+           cmdfilename);
+
+       fclose(f);
+       return cur_cmd < MIN_ENTROPY_SOURCES ? -1 : 0;
+}
+
+void
+usage(void)
+{
+       fprintf(stderr, "Usage: %s [options]\n", __progname);
+       fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
+       fprintf(stderr, "              Multiple -v increases verbosity.\n");
+       fprintf(stderr, "  -x          Force output in hexadecimal (for debugging)\n");
+       fprintf(stderr, "  -X          Force output in binary\n");
+       fprintf(stderr, "  -b bytes    Number of bytes to output (default %d)\n",
+           OUTPUT_SEED_SIZE);
+}
+
+int
+main(int argc, char **argv)
+{
+       unsigned char *buf;
+       int ret, ch, debug_level, output_hex, bytes;
+       extern char *optarg;
+       extern int optind;
+       LogLevel ll;
+
+       __progname = ssh_get_progname(argv[0]);
+       log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+
+       ll = SYSLOG_LEVEL_INFO;
+       debug_level = output_hex = 0;
+       bytes = OUTPUT_SEED_SIZE;
+
+       /* Don't write binary data to a tty, unless we are forced to */
+       if (isatty(STDOUT_FILENO))
+               output_hex = 1;
+
+       while ((ch = getopt(argc, argv, "vxXhb:")) != -1) {
+               switch (ch) {
+               case 'v':
+                       if (debug_level < 3)
+                               ll = SYSLOG_LEVEL_DEBUG1 + debug_level++;
+                       break;
+               case 'x':
+                       output_hex = 1;
+                       break;
+               case 'X':
+                       output_hex = 0;
+                       break;
+               case 'b':
+                       if ((bytes = atoi(optarg)) <= 0)
+                               fatal("Invalid number of output bytes");
+                       break;
+               case 'h':
+                       usage();
+                       exit(0);
+               default:
+                       error("Invalid commandline option");
+                       usage();
+                       exit(1);
+               }
+       }
+       log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
+
+       if (argc != optind) {
+               error("Unexpected commandline arguments.");
+               usage();
+               exit(1);
+       }
+
+#ifdef USE_SEED_FILES
+       prng_read_seedfile();
+#endif
+
+       buf = xmalloc(bytes);
+
+       /*
+        * Seed the RNG from wherever we can
+        */
+
+       /* Take whatever is on the stack, but don't credit it */
+       RAND_add(buf, bytes, 0);
+
+       debug("Seeded RNG with %i bytes from system calls",
+           (int)stir_from_system());
+
+       /* try prngd, fall back to commands if prngd fails or not configured */
+       if (seed_from_prngd(buf, bytes) == 0) {
+               RAND_add(buf, bytes, bytes);
+       } else {
+               /* Read in collection commands */
+               if (prng_read_commands(SSH_PRNG_COMMAND_FILE) == -1)
+                       fatal("PRNG initialisation failed -- exiting.");
+               debug("Seeded RNG with %i bytes from programs",
+                   (int)stir_from_programs());
+       }
+
+#ifdef USE_SEED_FILES
+       prng_write_seedfile();
+#endif
+
+       /*
+        * Write the seed to stdout
+        */
+
+       if (!RAND_status())
+               fatal("Not enough entropy in RNG");
+
+       if (RAND_bytes(buf, bytes) <= 0)
+               fatal("Couldn't extract entropy from PRNG");
+
+       if (output_hex) {
+               for(ret = 0; ret < bytes; ret++)
+                       printf("%02x", (unsigned char)(buf[ret]));
+               printf("\n");
+       } else
+               ret = atomicio(vwrite, STDOUT_FILENO, buf, bytes);
+
+       memset(buf, '\0', bytes);
+       xfree(buf);
+
+       return ret == bytes ? 0 : 1;
+}
+
+/*
+ * We may attempt to re-seed during mkstemp if we are using the one in the
+ * compat library (via mkstemp -> _gettemp -> arc4random -> seed_rng) so we
+ * need our own seed_rng().  We must also check that we have enough entropy.
+ */
+void
+seed_rng(void)
+{
+       if (!RAND_status())
+               fatal("Not enough entropy in RNG");
+}
diff --git a/ssh-rsa.c b/ssh-rsa.c
new file mode 100644 (file)
index 0000000..c6355fa
--- /dev/null
+++ b/ssh-rsa.c
@@ -0,0 +1,268 @@
+/* $OpenBSD: ssh-rsa.c,v 1.45 2010/08/31 09:58:37 djm Exp $ */
+/*
+ * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include "xmalloc.h"
+#include "log.h"
+#include "buffer.h"
+#include "key.h"
+#include "compat.h"
+#include "misc.h"
+#include "ssh.h"
+
+static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
+
+/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
+int
+ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
+    const u_char *data, u_int datalen)
+{
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       u_char digest[EVP_MAX_MD_SIZE], *sig;
+       u_int slen, dlen, len;
+       int ok, nid;
+       Buffer b;
+
+       if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
+           key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
+               error("ssh_rsa_sign: no RSA key");
+               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;
+       }
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       slen = RSA_size(key->rsa);
+       sig = xmalloc(slen);
+
+       ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa);
+       memset(digest, 'd', sizeof(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) {
+               u_int diff = slen - len;
+               debug("slen %u > len %u", slen, len);
+               memmove(sig + diff, sig, len);
+               memset(sig, 0, diff);
+       } else if (len > slen) {
+               error("ssh_rsa_sign: slen %u slen2 %u", 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);
+       if (lenp != NULL)
+               *lenp = len;
+       if (sigp != NULL) {
+               *sigp = xmalloc(len);
+               memcpy(*sigp, buffer_ptr(&b), len);
+       }
+       buffer_free(&b);
+       memset(sig, 's', slen);
+       xfree(sig);
+
+       return 0;
+}
+
+int
+ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen,
+    const u_char *data, u_int datalen)
+{
+       Buffer b;
+       const EVP_MD *evp_md;
+       EVP_MD_CTX md;
+       char *ktype;
+       u_char digest[EVP_MAX_MD_SIZE], *sigblob;
+       u_int len, dlen, modlen;
+       int rlen, ret, nid;
+
+       if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
+           key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
+               error("ssh_rsa_verify: no RSA key");
+               return -1;
+       }
+       if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+               error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
+                   BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
+               return -1;
+       }
+       buffer_init(&b);
+       buffer_append(&b, signature, signaturelen);
+       ktype = buffer_get_cstring(&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;
+       }
+       /* RSA_verify expects a signature of RSA_size */
+       modlen = RSA_size(key->rsa);
+       if (len > modlen) {
+               error("ssh_rsa_verify: len %u > modlen %u", len, modlen);
+               xfree(sigblob);
+               return -1;
+       } else if (len < modlen) {
+               u_int diff = modlen - len;
+               debug("ssh_rsa_verify: add padding: modlen %u > len %u",
+                   modlen, len);
+               sigblob = xrealloc(sigblob, 1, modlen);
+               memmove(sigblob + diff, sigblob, len);
+               memset(sigblob, 0, diff);
+               len = modlen;
+       }
+       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;
+       }
+       EVP_DigestInit(&md, evp_md);
+       EVP_DigestUpdate(&md, data, datalen);
+       EVP_DigestFinal(&md, digest, &dlen);
+
+       ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa);
+       memset(digest, 'd', sizeof(digest));
+       memset(sigblob, 's', len);
+       xfree(sigblob);
+       debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
+       return ret;
+}
+
+/*
+ * See:
+ * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
+ * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
+ */
+/*
+ * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ *     oiw(14) secsig(3) algorithms(2) 26 }
+ */
+static const u_char id_sha1[] = {
+       0x30, 0x21, /* type Sequence, length 0x21 (33) */
+       0x30, 0x09, /* type Sequence, length 0x09 */
+       0x06, 0x05, /* type OID, length 0x05 */
+       0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
+       0x05, 0x00, /* NULL */
+       0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
+};
+/*
+ * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
+ *     rsadsi(113549) digestAlgorithm(2) 5 }
+ */
+static const u_char id_md5[] = {
+       0x30, 0x20, /* type Sequence, length 0x20 (32) */
+       0x30, 0x0c, /* type Sequence, length 0x09 */
+       0x06, 0x08, /* type OID, length 0x05 */
+       0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */
+       0x05, 0x00, /* NULL */
+       0x04, 0x10  /* Octet string, length 0x10 (16), followed by md5 hash */
+};
+
+static int
+openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
+    u_char *sigbuf, u_int siglen, RSA *rsa)
+{
+       u_int ret, rsasize, oidlen = 0, hlen = 0;
+       int len, oidmatch, hashmatch;
+       const u_char *oid = NULL;
+       u_char *decrypted = NULL;
+
+       ret = 0;
+       switch (type) {
+       case NID_sha1:
+               oid = id_sha1;
+               oidlen = sizeof(id_sha1);
+               hlen = 20;
+               break;
+       case NID_md5:
+               oid = id_md5;
+               oidlen = sizeof(id_md5);
+               hlen = 16;
+               break;
+       default:
+               goto done;
+       }
+       if (hashlen != hlen) {
+               error("bad hashlen");
+               goto done;
+       }
+       rsasize = RSA_size(rsa);
+       if (siglen == 0 || siglen > rsasize) {
+               error("bad siglen");
+               goto done;
+       }
+       decrypted = xmalloc(rsasize);
+       if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
+           RSA_PKCS1_PADDING)) < 0) {
+               error("RSA_public_decrypt failed: %s",
+                   ERR_error_string(ERR_get_error(), NULL));
+               goto done;
+       }
+       if (len < 0 || (u_int)len != hlen + oidlen) {
+               error("bad decrypted len: %d != %d + %d", len, hlen, oidlen);
+               goto done;
+       }
+       oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
+       hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
+       if (!oidmatch) {
+               error("oid mismatch");
+               goto done;
+       }
+       if (!hashmatch) {
+               error("hash mismatch");
+               goto done;
+       }
+       ret = 1;
+done:
+       if (decrypted)
+               xfree(decrypted);
+       return ret;
+}
diff --git a/ssh.0 b/ssh.0
new file mode 100644 (file)
index 0000000..c1d3135
--- /dev/null
+++ b/ssh.0
@@ -0,0 +1,898 @@
+SSH(1)                     OpenBSD Reference Manual                     SSH(1)
+
+NAME
+     ssh - OpenSSH SSH client (remote login program)
+
+SYNOPSIS
+     ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
+         [-D [bind_address:]port] [-e escape_char] [-F configfile] [-I pkcs11]
+         [-i identity_file] [-L [bind_address:]port:host:hostport]
+         [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
+         [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
+         [-w local_tun[:remote_tun]] [user@]hostname [command]
+
+DESCRIPTION
+     ssh (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 ports can also be forwarded over the secure channel.
+
+     ssh connects and logs into the specified hostname (with optional user
+     name).  The user must prove his/her identity to the remote machine using
+     one of several methods depending on the protocol version used (see
+     below).
+
+     If command is specified, it is executed on the remote host instead of a
+     login shell.
+
+     The options are as follows:
+
+     -1      Forces ssh to try protocol version 1 only.
+
+     -2      Forces ssh to try protocol version 2 only.
+
+     -4      Forces ssh to use IPv4 addresses only.
+
+     -6      Forces ssh to use IPv6 addresses only.
+
+     -A      Enables forwarding of the authentication agent connection.  This
+             can also be specified on a per-host basis in a configuration
+             file.
+
+             Agent forwarding should be enabled with caution.  Users with the
+             ability to bypass file permissions on the remote host (for the
+             agent's UNIX-domain socket) can access the local agent through
+             the forwarded connection.  An attacker cannot obtain key material
+             from the agent, however they can perform operations on the keys
+             that enable them to authenticate using the identities loaded into
+             the agent.
+
+     -a      Disables forwarding of the authentication agent connection.
+
+     -b bind_address
+             Use bind_address on the local machine as the source address of
+             the connection.  Only useful on systems with more than one
+             address.
+
+     -C      Requests compression of all data (including stdin, stdout,
+             stderr, and data for forwarded X11 and TCP connections).  The
+             compression algorithm is the same used by gzip(1), and the
+             ``level'' can be controlled by the CompressionLevel option for
+             protocol version 1.  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 Compression option.
+
+     -c cipher_spec
+             Selects the cipher specification for encrypting the session.
+
+             Protocol version 1 allows specification of a single cipher.  The
+             supported values are ``3des'', ``blowfish'', and ``des''.  3des
+             (triple-des) is an encrypt-decrypt-encrypt triple with three
+             different keys.  It is believed to be secure.  blowfish is a fast
+             block cipher; it appears very secure and is much faster than
+             3des.  des is only supported in the ssh client for
+             interoperability with legacy protocol 1 implementations that do
+             not support the 3des cipher.  Its use is strongly discouraged due
+             to cryptographic weaknesses.  The default is ``3des''.
+
+             For protocol version 2, cipher_spec is a comma-separated list of
+             ciphers listed in order of preference.  See the Ciphers keyword
+             in ssh_config(5) for more information.
+
+     -D [bind_address:]port
+             Specifies a local ``dynamic'' application-level port forwarding.
+             This works by allocating a socket to listen to port on the local
+             side, optionally bound to the specified bind_address.  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 and SOCKS5 protocols are supported, and ssh will act
+             as a SOCKS server.  Only root can forward privileged ports.
+             Dynamic port forwardings can also be specified in the
+             configuration file.
+
+             IPv6 addresses can be specified by enclosing the address in
+             square brackets.  Only the superuser can forward privileged
+             ports.  By default, the local port is bound in accordance with
+             the GatewayPorts setting.  However, an explicit bind_address may
+             be used to bind the connection to a specific address.  The
+             bind_address of ``localhost'' indicates that the listening port
+             be bound for local use only, while an empty address or `*'
+             indicates that the port should be available from all interfaces.
+
+     -e escape_char
+             Sets the escape character for sessions with a pty (default: `~').
+             The escape character is only recognized at the beginning of a
+             line.  The escape character followed by a dot (`.') closes the
+             connection; followed by control-Z suspends the connection; and
+             followed by itself sends the escape character once.  Setting the
+             character to ``none'' disables any escapes and makes the session
+             fully transparent.
+
+     -F configfile
+             Specifies an alternative per-user configuration file.  If a
+             configuration file is given on the command line, the system-wide
+             configuration file (/etc/ssh/ssh_config) will be ignored.  The
+             default for the per-user configuration file is ~/.ssh/config.
+
+     -f      Requests ssh to go to background just before command execution.
+             This is useful if ssh is going to ask for passwords or
+             passphrases, but the user wants it in the background.  This
+             implies -n.  The recommended way to start X11 programs at a
+             remote site is with something like ssh -f host xterm.
+
+             If the ExitOnForwardFailure configuration option is set to
+             ``yes'', then a client started with -f will wait for all remote
+             port forwards to be successfully established before placing
+             itself in the background.
+
+     -g      Allows remote hosts to connect to local forwarded ports.
+
+     -I pkcs11
+             Specify the PKCS#11 shared library ssh should use to communicate
+             with a PKCS#11 token providing the user's private RSA key.
+
+     -i identity_file
+             Selects a file from which the identity (private key) for public
+             key authentication is read.  The default is ~/.ssh/identity for
+             protocol version 1, and ~/.ssh/id_dsa, ~/.ssh/id_ecdsa and
+             ~/.ssh/id_rsa for protocol version 2.  Identity files may also be
+             specified on a per-host basis in the configuration file.  It is
+             possible to have multiple -i options (and multiple identities
+             specified in configuration files).  ssh will also try to load
+             certificate information from the filename obtained by appending
+             -cert.pub to identity filenames.
+
+     -K      Enables GSSAPI-based authentication and forwarding (delegation)
+             of GSSAPI credentials to the server.
+
+     -k      Disables forwarding (delegation) of GSSAPI credentials to the
+             server.
+
+     -L [bind_address:]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 port on the local side,
+             optionally bound to the specified bind_address.  Whenever a
+             connection is made to this port, the connection is forwarded over
+             the secure channel, and a connection is made to host port
+             hostport from the remote machine.  Port forwardings can also be
+             specified in the configuration file.  IPv6 addresses can be
+             specified by enclosing the address in square brackets.  Only the
+             superuser can forward privileged ports.  By default, the local
+             port is bound in accordance with the GatewayPorts setting.
+             However, an explicit bind_address may be used to bind the
+             connection to a specific address.  The bind_address of
+             ``localhost'' indicates that the listening port be bound for
+             local use only, while an empty address or `*' indicates that the
+             port should be available from all interfaces.
+
+     -l 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.
+
+     -M      Places the ssh client into ``master'' mode for connection
+             sharing.  Multiple -M options places ssh into ``master'' mode
+             with confirmation required before slave connections are accepted.
+             Refer to the description of ControlMaster in ssh_config(5) for
+             details.
+
+     -m 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 MACs keyword for more information.
+
+     -N      Do not execute a remote command.  This is useful for just
+             forwarding ports (protocol version 2 only).
+
+     -n      Redirects stdin from /dev/null (actually, prevents reading from
+             stdin).  This must be used when ssh is run in the background.  A
+             common trick is to use this to run X11 programs on a remote
+             machine.  For example, 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 ssh
+             program will be put in the background.  (This does not work if
+             ssh needs to ask for a password or passphrase; see also the -f
+             option.)
+
+     -O ctl_cmd
+             Control an active connection multiplexing master process.  When
+             the -O option is specified, the ctl_cmd argument is interpreted
+             and passed to the master process.  Valid commands are: ``check''
+             (check that the master process is running), ``forward'' (request
+             forwardings without command execution) and ``exit'' (request the
+             master to exit).
+
+     -o 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.  For full details
+             of the options listed below, and their possible values, see
+             ssh_config(5).
+
+                   AddressFamily
+                   BatchMode
+                   BindAddress
+                   ChallengeResponseAuthentication
+                   CheckHostIP
+                   Cipher
+                   Ciphers
+                   ClearAllForwardings
+                   Compression
+                   CompressionLevel
+                   ConnectionAttempts
+                   ConnectTimeout
+                   ControlMaster
+                   ControlPath
+                   DynamicForward
+                   EscapeChar
+                   ExitOnForwardFailure
+                   ForwardAgent
+                   ForwardX11
+                   ForwardX11Trusted
+                   GatewayPorts
+                   GlobalKnownHostsFile
+                   GSSAPIAuthentication
+                   GSSAPIDelegateCredentials
+                   HashKnownHosts
+                   Host
+                   HostbasedAuthentication
+                   HostKeyAlgorithms
+                   HostKeyAlias
+                   HostName
+                   IdentityFile
+                   IdentitiesOnly
+                   IPQoS
+                   KbdInteractiveDevices
+                   KexAlgorithms
+                   LocalCommand
+                   LocalForward
+                   LogLevel
+                   MACs
+                   NoHostAuthenticationForLocalhost
+                   NumberOfPasswordPrompts
+                   PasswordAuthentication
+                   PermitLocalCommand
+                   PKCS11Provider
+                   Port
+                   PreferredAuthentications
+                   Protocol
+                   ProxyCommand
+                   PubkeyAuthentication
+                   RekeyLimit
+                   RemoteForward
+                   RhostsRSAAuthentication
+                   RSAAuthentication
+                   SendEnv
+                   ServerAliveInterval
+                   ServerAliveCountMax
+                   StrictHostKeyChecking
+                   TCPKeepAlive
+                   Tunnel
+                   TunnelDevice
+                   UsePrivilegedPort
+                   User
+                   UserKnownHostsFile
+                   VerifyHostKeyDNS
+                   VisualHostKey
+                   XAuthLocation
+
+     -p port
+             Port to connect to on the remote host.  This can be specified on
+             a per-host basis in the configuration file.
+
+     -q      Quiet mode.  Causes most warning and diagnostic messages to be
+             suppressed.
+
+     -R [bind_address:]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 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 host port 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 by enclosing
+             the address in square braces.
+
+             By default, the listening socket on the server will be bound to
+             the loopback interface only.  This may be overridden by
+             specifying a bind_address.  An empty bind_address, or the address
+             `*', indicates that the remote socket should listen on all
+             interfaces.  Specifying a remote bind_address will only succeed
+             if the server's GatewayPorts option is enabled (see
+             sshd_config(5)).
+
+             If the port argument is `0', the listen port will be dynamically
+             allocated on the server and reported to the client at run time.
+             When used together with -O forward the allocated port will be
+             printed to the standard output.
+
+     -S ctl_path
+             Specifies the location of a control socket for connection
+             sharing, or the string ``none'' to disable connection sharing.
+             Refer to the description of ControlPath and ControlMaster in
+             ssh_config(5) for details.
+
+     -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(1)).  The subsystem is specified as the
+             remote command.
+
+     -T      Disable pseudo-tty allocation.
+
+     -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 -t
+             options force tty allocation, even if ssh has no local tty.
+
+     -V      Display the version number and exit.
+
+     -v      Verbose mode.  Causes ssh to print debugging messages about its
+             progress.  This is helpful in debugging connection,
+             authentication, and configuration problems.  Multiple -v options
+             increase the verbosity.  The maximum is 3.
+
+     -W host:port
+             Requests that standard input and output on the client be
+             forwarded to host on port over the secure channel.  Implies -N,
+             -T, ExitOnForwardFailure and ClearAllForwardings and works with
+             Protocol version 2 only.
+
+     -w local_tun[:remote_tun]
+             Requests tunnel device forwarding with the specified tun(4)
+             devices between the client (local_tun) and the server
+             (remote_tun).
+
+             The devices may be specified by numerical ID or the keyword
+             ``any'', which uses the next available tunnel device.  If
+             remote_tun is not specified, it defaults to ``any''.  See also
+             the Tunnel and TunnelDevice directives in ssh_config(5).  If the
+             Tunnel directive is unset, it is set to the default tunnel mode,
+             which is ``point-to-point''.
+
+     -X      Enables X11 forwarding.  This can also be specified on a per-host
+             basis in a configuration file.
+
+             X11 forwarding should be enabled with caution.  Users with the
+             ability to bypass file permissions on the remote host (for the
+             user's X authorization database) can access the local X11 display
+             through the forwarded connection.  An attacker may then be able
+             to perform activities such as keystroke monitoring.
+
+             For this reason, X11 forwarding is subjected to X11 SECURITY
+             extension restrictions by default.  Please refer to the ssh -Y
+             option and the ForwardX11Trusted directive in ssh_config(5) for
+             more information.
+
+     -x      Disables X11 forwarding.
+
+     -Y      Enables trusted X11 forwarding.  Trusted X11 forwardings are not
+             subjected to the X11 SECURITY extension controls.
+
+     -y      Send log information using the syslog(3) system module.  By
+             default this information is sent to stderr.
+
+     ssh may additionally obtain configuration data from a per-user
+     configuration file and a system-wide configuration file.  The file format
+     and configuration options are described in ssh_config(5).
+
+AUTHENTICATION
+     The OpenSSH SSH client supports SSH protocols 1 and 2.  The default is to
+     use protocol 2 only, though this can be changed via the Protocol option
+     in ssh_config(5) or the -1 and -2 options (see above).  Both protocols
+     support similar authentication methods, but protocol 2 is the default
+     since it provides additional mechanisms for confidentiality (the traffic
+     is encrypted using AES, 3DES, Blowfish, CAST128, or Arcfour) and
+     integrity (hmac-md5, hmac-sha1, umac-64, hmac-ripemd160).  Protocol 1
+     lacks a strong mechanism for ensuring the integrity of the connection.
+
+     The methods available for authentication are: GSSAPI-based
+     authentication, host-based authentication, public key authentication,
+     challenge-response authentication, and password authentication.
+     Authentication methods are tried in the order specified above, though
+     protocol 2 has a configuration option to change the default order:
+     PreferredAuthentications.
+
+     Host-based authentication works as follows: If the machine the user logs
+     in from is listed in /etc/hosts.equiv or /etc/shosts.equiv on the remote
+     machine, and the user names are the same on both sides, or if the files
+     ~/.rhosts or ~/.shosts exist in the user's home directory on the remote
+     machine and contain a line containing the name of the client machine and
+     the name of the user on that machine, the user is considered for login.
+     Additionally, the server must be able to verify the client's host key
+     (see the description of /etc/ssh/ssh_known_hosts and ~/.ssh/known_hosts,
+     below) for login to be permitted.  This authentication method closes
+     security holes due to IP spoofing, DNS spoofing, and routing spoofing.
+     [Note to the administrator: /etc/hosts.equiv, ~/.rhosts, and the
+     rlogin/rsh protocol in general, are inherently insecure and should be
+     disabled if security is desired.]
+
+     Public key authentication works as follows: The scheme is based on
+     public-key cryptography, using cryptosystems where encryption and
+     decryption are done using separate keys, and it is unfeasible to derive
+     the decryption key from the encryption key.  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.
+     ssh implements public key authentication protocol automatically, using
+     one of the DSA, ECDSA or RSA algorithms.  Protocol 1 is restricted to
+     using only RSA keys, but protocol 2 may use any.  The HISTORY section of
+     ssl(8) contains a brief discussion of the DSA and RSA algorithms.
+
+     The file ~/.ssh/authorized_keys lists the public keys that are permitted
+     for logging in.  When the user logs in, the ssh program tells the server
+     which key pair it would like to use for authentication.  The client
+     proves that it has access to the private key and the server checks that
+     the corresponding public key is authorized to accept the account.
+
+     The user creates his/her key pair by running ssh-keygen(1).  This stores
+     the private key in ~/.ssh/identity (protocol 1), ~/.ssh/id_dsa (protocol
+     2 DSA), ~/.ssh/id_ecdsa (protocol 2 ECDSA), or ~/.ssh/id_rsa (protocol 2
+     RSA) and stores the public key in ~/.ssh/identity.pub (protocol 1),
+     ~/.ssh/id_dsa.pub (protocol 2 DSA), ~/.ssh/id_ecdsa.pub (protocol 2
+     ECDSA), or ~/.ssh/id_rsa.pub (protocol 2 RSA) in the user's home
+     directory.  The user should then copy the public key to
+     ~/.ssh/authorized_keys in his/her home directory on the remote machine.
+     The authorized_keys file corresponds to the conventional ~/.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.
+
+     A variation on public key authentication is available in the form of
+     certificate authentication: instead of a set of public/private keys,
+     signed certificates are used.  This has the advantage that a single
+     trusted certification authority can be used in place of many
+     public/private keys.  See the CERTIFICATES section of ssh-keygen(1) for
+     more information.
+
+     The most convenient way to use public key or certificate authentication
+     may be with an authentication agent.  See ssh-agent(1) for more
+     information.
+
+     Challenge-response authentication works as follows: The server sends an
+     arbitrary "challenge" text, and prompts for a response.  Protocol 2
+     allows multiple challenges and responses; protocol 1 is restricted to
+     just one challenge/response.  Examples of challenge-response
+     authentication include BSD Authentication (see login.conf(5)) and PAM
+     (some non-OpenBSD systems).
+
+     Finally, if other authentication methods fail, ssh 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.
+
+     ssh automatically maintains and checks a database containing
+     identification for all hosts it has ever been used with.  Host keys are
+     stored in ~/.ssh/known_hosts in the user's home directory.  Additionally,
+     the file /etc/ssh/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, ssh warns about this and disables
+     password authentication to prevent server spoofing or man-in-the-middle
+     attacks, which could otherwise be used to circumvent the encryption.  The
+     StrictHostKeyChecking option can be used to control logins to machines
+     whose host key is not known or has changed.
+
+     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.
+
+     If a pseudo-terminal has been allocated (normal login session), the user
+     may use the escape characters noted below.
+
+     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 ``none'' will also make the session transparent even
+     if a tty is used.
+
+     The session terminates when the command or shell on the remote machine
+     exits and all X11 and TCP connections have been closed.
+
+ESCAPE CHARACTERS
+     When a pseudo-terminal has been requested, ssh supports a number of
+     functions through the use of an escape character.
+
+     A single tilde character can be sent as ~~ 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 EscapeChar
+     configuration directive or on the command line by the -e option.
+
+     The supported escapes (assuming the default `~') are:
+
+     ~.      Disconnect.
+
+     ~^Z     Background ssh.
+
+     ~#      List forwarded connections.
+
+     ~&      Background ssh at logout when waiting for forwarded connection /
+             X11 sessions to terminate.
+
+     ~?      Display a list of escape characters.
+
+     ~B      Send a BREAK to the remote system (only useful for SSH protocol
+             version 2 and if the peer supports it).
+
+     ~C      Open command line.  Currently this allows the addition of port
+             forwardings using the -L, -R and -D options (see above).  It also
+             allows the cancellation of existing remote port-forwardings using
+             -KR[bind_address:]port.  !command allows the user to execute a
+             local command if the PermitLocalCommand option is enabled in
+             ssh_config(5).  Basic help is available, using the -h option.
+
+     ~R      Request rekeying of the connection (only useful for SSH protocol
+             version 2 and if the peer supports it).
+
+TCP FORWARDING
+     Forwarding of arbitrary TCP connections over the secure channel can be
+     specified either on the command line or in a configuration file.  One
+     possible application of TCP forwarding is a secure connection to a mail
+     server; another is going through firewalls.
+
+     In the example below, we look at encrypting communication between an IRC
+     client and server, even though the IRC server does not directly support
+     encrypted communications.  This works as follows: the user connects to
+     the remote host using ssh, specifying a port to be used to forward
+     connections to the remote server.  After that it is possible to start the
+     service which is to be encrypted on the client machine, connecting to the
+     same local port, and ssh will encrypt and forward the connection.
+
+     The following example tunnels an IRC session from client machine
+     ``127.0.0.1'' (localhost) to remote server ``server.example.com'':
+
+         $ ssh -f -L 1234:localhost:6667 server.example.com sleep 10
+         $ irc -c '#users' -p 1234 pinky 127.0.0.1
+
+     This tunnels a connection to IRC server ``server.example.com'', joining
+     channel ``#users'', nickname ``pinky'', using port 1234.  It doesn't
+     matter which port is used, as long as it's greater than 1023 (remember,
+     only root can open sockets on privileged ports) and doesn't conflict with
+     any ports already in use.  The connection is forwarded to port 6667 on
+     the remote server, since that's the standard port for IRC services.
+
+     The -f option backgrounds ssh and the remote command ``sleep 10'' is
+     specified to allow an amount of time (10 seconds, in the example) to
+     start the service which is to be tunnelled.  If no connections are made
+     within the time specified, ssh will exit.
+
+X11 FORWARDING
+     If the ForwardX11 variable is set to ``yes'' (or see the description of
+     the -X, -x, and -Y options above) and the user is using X11 (the 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 DISPLAY.
+     Forwarding of X11 connections can be configured on the command line or in
+     configuration files.
+
+     The DISPLAY value set by ssh will point to the server machine, but with a
+     display number greater than zero.  This is normal, and happens because
+     ssh creates a ``proxy'' X server on the server machine for forwarding the
+     connections over the encrypted channel.
+
+     ssh 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).
+
+     If the ForwardAgent variable is set to ``yes'' (or see the description of
+     the -A and -a options above) and the user is using an authentication
+     agent, the connection to the agent is automatically forwarded to the
+     remote side.
+
+VERIFYING HOST KEYS
+     When connecting to a server for the first time, a fingerprint of the
+     server's public key is presented to the user (unless the option
+     StrictHostKeyChecking has been disabled).  Fingerprints can be determined
+     using ssh-keygen(1):
+
+           $ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
+
+     If the fingerprint is already known, it can be matched and the key can be
+     accepted or rejected.  Because of the difficulty of comparing host keys
+     just by looking at hex strings, there is also support to compare host
+     keys visually, using random art.  By setting the VisualHostKey option to
+     ``yes'', a small ASCII graphic gets displayed on every login to a server,
+     no matter if the session itself is interactive or not.  By learning the
+     pattern a known server produces, a user can easily find out that the host
+     key has changed when a completely different pattern is displayed.
+     Because these patterns are not unambiguous however, a pattern that looks
+     similar to the pattern remembered only gives a good probability that the
+     host key is the same, not guaranteed proof.
+
+     To get a listing of the fingerprints along with their random art for all
+     known hosts, the following command line can be used:
+
+           $ ssh-keygen -lv -f ~/.ssh/known_hosts
+
+     If the fingerprint is unknown, an alternative method of verification is
+     available: SSH fingerprints verified by DNS.  An additional resource
+     record (RR), SSHFP, is added to a zonefile and the connecting client is
+     able to match the fingerprint with that of the key presented.
+
+     In this example, we are connecting a client to a server,
+     ``host.example.com''.  The SSHFP resource records should first be added
+     to the zonefile for host.example.com:
+
+           $ ssh-keygen -r host.example.com.
+
+     The output lines will have to be added to the zonefile.  To check that
+     the zone is answering fingerprint queries:
+
+           $ dig -t SSHFP host.example.com
+
+     Finally the client connects:
+
+           $ ssh -o "VerifyHostKeyDNS ask" host.example.com
+           [...]
+           Matching host key fingerprint found in DNS.
+           Are you sure you want to continue connecting (yes/no)?
+
+     See the VerifyHostKeyDNS option in ssh_config(5) for more information.
+
+SSH-BASED VIRTUAL PRIVATE NETWORKS
+     ssh contains support for Virtual Private Network (VPN) tunnelling using
+     the tun(4) network pseudo-device, allowing two networks to be joined
+     securely.  The sshd_config(5) configuration option PermitTunnel controls
+     whether the server supports this, and at what level (layer 2 or 3
+     traffic).
+
+     The following example would connect client network 10.0.50.0/24 with
+     remote network 10.0.99.0/24 using a point-to-point connection from
+     10.1.1.1 to 10.1.1.2, provided that the SSH server running on the gateway
+     to the remote network, at 192.168.1.15, allows it.
+
+     On the client:
+
+           # ssh -f -w 0:1 192.168.1.15 true
+           # ifconfig tun0 10.1.1.1 10.1.1.2 netmask 255.255.255.252
+           # route add 10.0.99.0/24 10.1.1.2
+
+     On the server:
+
+           # ifconfig tun1 10.1.1.2 10.1.1.1 netmask 255.255.255.252
+           # route add 10.0.50.0/24 10.1.1.1
+
+     Client access may be more finely tuned via the /root/.ssh/authorized_keys
+     file (see below) and the PermitRootLogin server option.  The following
+     entry would permit connections on tun(4) device 1 from user ``jane'' and
+     on tun device 2 from user ``john'', if PermitRootLogin is set to
+     ``forced-commands-only'':
+
+       tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... jane
+       tunnel="2",command="sh /etc/netstart tun2" ssh-rsa ... john
+
+     Since an SSH-based setup entails a fair amount of overhead, it may be
+     more suited to temporary setups, such as for wireless VPNs.  More
+     permanent VPNs are better provided by tools such as ipsecctl(8) and
+     isakmpd(8).
+
+ENVIRONMENT
+     ssh will normally set the following environment variables:
+
+     DISPLAY               The DISPLAY variable indicates the location of the
+                           X11 server.  It is automatically set by ssh to
+                           point to a value of the form ``hostname:n'', where
+                           ``hostname'' indicates the host where the shell
+                           runs, and `n' is an integer >= 1.  ssh uses this
+                           special value to forward X11 connections over the
+                           secure channel.  The user should normally not set
+                           DISPLAY explicitly, as that will render the X11
+                           connection insecure (and will require the user to
+                           manually copy any required authorization cookies).
+
+     HOME                  Set to the path of the user's home directory.
+
+     LOGNAME               Synonym for USER; set for compatibility with
+                           systems that use this variable.
+
+     MAIL                  Set to the path of the user's mailbox.
+
+     PATH                  Set to the default PATH, as specified when
+                           compiling ssh.
+
+     SSH_ASKPASS           If ssh needs a passphrase, it will read the
+                           passphrase from the current terminal if it was run
+                           from a terminal.  If ssh does not have a terminal
+                           associated with it but DISPLAY and SSH_ASKPASS are
+                           set, it will execute the program specified by
+                           SSH_ASKPASS and open an X11 window to read the
+                           passphrase.  This is particularly useful when
+                           calling ssh from a .xsession or related script.
+                           (Note that on some machines it may be necessary to
+                           redirect the input from /dev/null to make this
+                           work.)
+
+     SSH_AUTH_SOCK         Identifies the path of a UNIX-domain socket used to
+                           communicate with the agent.
+
+     SSH_CONNECTION        Identifies the client and server ends of the
+                           connection.  The variable contains four space-
+                           separated values: client IP address, client port
+                           number, server IP address, and server port number.
+
+     SSH_ORIGINAL_COMMAND  This variable contains the original command line if
+                           a forced command is executed.  It can be used to
+                           extract the original arguments.
+
+     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.
+
+     TZ                    This variable is set to indicate the present time
+                           zone if it was set when the daemon was started
+                           (i.e. the daemon passes the value on to new
+                           connections).
+
+     USER                  Set to the name of the user logging in.
+
+     Additionally, ssh reads ~/.ssh/environment, and adds lines of the format
+     ``VARNAME=value'' to the environment if the file exists and users are
+     allowed to change their environment.  For more information, see the
+     PermitUserEnvironment option in sshd_config(5).
+
+FILES
+     ~/.rhosts
+             This file is used for host-based authentication (see above).  On
+             some machines this file may need to be world-readable if the
+             user's home directory is on an NFS partition, because 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.
+
+     ~/.shosts
+             This file is used in exactly the same way as .rhosts, but allows
+             host-based authentication without permitting login with
+             rlogin/rsh.
+
+     ~/.ssh/
+             This directory is the default location for all user-specific
+             configuration and authentication information.  There is no
+             general requirement to keep the entire contents of this directory
+             secret, but the recommended permissions are read/write/execute
+             for the user, and not accessible by others.
+
+     ~/.ssh/authorized_keys
+             Lists the public keys (DSA/ECDSA/RSA) that can be used for
+             logging in as this user.  The format of this file is described in
+             the sshd(8) manual page.  This file is not highly sensitive, but
+             the recommended permissions are read/write for the user, and not
+             accessible by others.
+
+     ~/.ssh/config
+             This is the per-user configuration file.  The file format and
+             configuration options are described in ssh_config(5).  Because of
+             the potential for abuse, this file must have strict permissions:
+             read/write for the user, and not accessible by others.
+
+     ~/.ssh/environment
+             Contains additional definitions for environment variables; see
+             ENVIRONMENT, above.
+
+     ~/.ssh/identity
+     ~/.ssh/id_dsa
+     ~/.ssh/id_ecdsa
+     ~/.ssh/id_rsa
+             Contains the private key for authentication.  These files contain
+             sensitive data and should be readable by the user but not
+             accessible by others (read/write/execute).  ssh will simply
+             ignore a private key file if it is accessible by others.  It is
+             possible to specify a passphrase when generating the key which
+             will be used to encrypt the sensitive part of this file using
+             3DES.
+
+     ~/.ssh/identity.pub
+     ~/.ssh/id_dsa.pub
+     ~/.ssh/id_ecdsa.pub
+     ~/.ssh/id_rsa.pub
+             Contains the public key for authentication.  These files are not
+             sensitive and can (but need not) be readable by anyone.
+
+     ~/.ssh/known_hosts
+             Contains a list of host keys for all hosts the user has logged
+             into that are not already in the systemwide list of known host
+             keys.  See sshd(8) for further details of the format of this
+             file.
+
+     ~/.ssh/rc
+             Commands in this file are executed by ssh when the user logs in,
+             just before the user's shell (or command) is started.  See the
+             sshd(8) manual page for more information.
+
+     /etc/hosts.equiv
+             This file is for host-based authentication (see above).  It
+             should only be writable by root.
+
+     /etc/shosts.equiv
+             This file is used in exactly the same way as hosts.equiv, but
+             allows host-based authentication without permitting login with
+             rlogin/rsh.
+
+     /etc/ssh/ssh_config
+             Systemwide configuration file.  The file format and configuration
+             options are described in ssh_config(5).
+
+     /etc/ssh/ssh_host_key
+     /etc/ssh/ssh_host_dsa_key
+     /etc/ssh/ssh_host_ecdsa_key
+     /etc/ssh/ssh_host_rsa_key
+             These three files contain the private parts of the host keys and
+             are used for host-based authentication.  If protocol version 1 is
+             used, ssh must be setuid root, since the host key is readable
+             only by root.  For protocol version 2, ssh uses ssh-keysign(8) to
+             access the host keys, eliminating the requirement that ssh be
+             setuid root when host-based authentication is used.  By default
+             ssh is not setuid root.
+
+     /etc/ssh/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.  It should be world-readable.
+             See sshd(8) for further details of the format of this file.
+
+     /etc/ssh/sshrc
+             Commands in this file are executed by ssh when the user logs in,
+             just before the user's shell (or command) is started.  See the
+             sshd(8) manual page for more information.
+
+EXIT STATUS
+     ssh exits with the exit status of the remote command or with 255 if an
+     error occurred.
+
+SEE ALSO
+     scp(1), sftp(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1),
+     tun(4), hosts.equiv(5), ssh_config(5), ssh-keysign(8), sshd(8)
+
+     The Secure Shell (SSH) Protocol Assigned Numbers, RFC 4250, 2006.
+
+     The Secure Shell (SSH) Protocol Architecture, RFC 4251, 2006.
+
+     The Secure Shell (SSH) Authentication Protocol, RFC 4252, 2006.
+
+     The Secure Shell (SSH) Transport Layer Protocol, RFC 4253, 2006.
+
+     The Secure Shell (SSH) Connection Protocol, RFC 4254, 2006.
+
+     Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints, RFC
+     4255, 2006.
+
+     Generic Message Exchange Authentication for the Secure Shell Protocol
+     (SSH), RFC 4256, 2006.
+
+     The Secure Shell (SSH) Session Channel Break Extension, RFC 4335, 2006.
+
+     The Secure Shell (SSH) Transport Layer Encryption Modes, RFC 4344, 2006.
+
+     Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer
+     Protocol, RFC 4345, 2006.
+
+     Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer
+     Protocol, RFC 4419, 2006.
+
+     The Secure Shell (SSH) Public Key File Format, RFC 4716, 2006.
+
+     Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer,
+     RFC 5656, 2009.
+
+     A. Perrig and D. Song, Hash Visualization: a New Technique to improve
+     Real-World Security, 1999, International Workshop on Cryptographic
+     Techniques and E-Commerce (CrypTEC '99).
+
+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.
+
+OpenBSD 4.9                    November 18, 2010                   OpenBSD 4.9
diff --git a/ssh.1 b/ssh.1
new file mode 100644 (file)
index 0000000..e3a42b5
--- /dev/null
+++ b/ssh.1
@@ -0,0 +1,1490 @@
+.\"
+.\" 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.316 2010/11/18 15:01:00 jmc Exp $
+.Dd $Mdocdate: November 18 2010 $
+.Dt SSH 1
+.Os
+.Sh NAME
+.Nm ssh
+.Nd OpenSSH SSH client (remote login program)
+.Sh SYNOPSIS
+.Nm ssh
+.Bk -words
+.Op Fl 1246AaCfgKkMNnqsTtVvXxYy
+.Op Fl b Ar bind_address
+.Op Fl c Ar cipher_spec
+.Op Fl D Oo Ar bind_address : Oc Ns Ar port
+.Op Fl e Ar escape_char
+.Op Fl F Ar configfile
+.Op Fl I Ar pkcs11
+.Op Fl i Ar identity_file
+.Op Fl L Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport
+.Op Fl l Ar login_name
+.Op Fl m Ar mac_spec
+.Op Fl O Ar ctl_cmd
+.Op Fl o Ar option
+.Op Fl p Ar port
+.Op Fl R Oo Ar bind_address : Oc Ns Ar port : Ns Ar host : Ns Ar hostport
+.Op Fl S Ar ctl_path
+.Op Fl W Ar host : Ns Ar port
+.Op Fl w Ar local_tun Ns Op : Ns Ar remote_tun
+.Oo Ar user Ns @ Oc Ns Ar hostname
+.Op Ar command
+.Ek
+.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 ports
+can also be forwarded over the secure channel.
+.Pp
+.Nm
+connects and logs into the specified
+.Ar hostname
+(with optional
+.Ar user
+name).
+The user must prove
+his/her identity to the remote machine using one of several methods
+depending on the protocol version used (see below).
+.Pp
+If
+.Ar command
+is specified,
+it is executed on the remote host instead of a login shell.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.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.
+.It Fl A
+Enables forwarding of the authentication agent connection.
+This can also be specified on a per-host basis in a configuration file.
+.Pp
+Agent forwarding should be enabled with caution.
+Users with the ability to bypass file permissions on the remote host
+(for the agent's
+.Ux Ns -domain
+socket) can access the local agent through the forwarded connection.
+An attacker cannot obtain key material from the agent,
+however they can perform operations on the keys that enable them to
+authenticate using the identities loaded into the agent.
+.It Fl a
+Disables forwarding of the authentication agent connection.
+.It Fl b Ar bind_address
+Use
+.Ar bind_address
+on the local machine as the source address
+of the connection.
+Only useful on systems with more than one address.
+.It Fl C
+Requests compression of all data (including stdin, stdout, stderr, and
+data for forwarded X11 and TCP connections).
+The compression algorithm is the same used by
+.Xr gzip 1 ,
+and the
+.Dq level
+can be controlled by the
+.Cm CompressionLevel
+option for protocol version 1.
+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.
+.It Fl c Ar cipher_spec
+Selects the cipher specification for encrypting the session.
+.Pp
+Protocol version 1 allows specification of a single cipher.
+The supported values are
+.Dq 3des ,
+.Dq blowfish ,
+and
+.Dq des .
+.Ar 3des
+(triple-des) is an encrypt-decrypt-encrypt triple with three different keys.
+It is believed to be secure.
+.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.
+The default is
+.Dq 3des .
+.Pp
+For protocol version 2,
+.Ar cipher_spec
+is a comma-separated list of ciphers
+listed in order of preference.
+See the
+.Cm Ciphers
+keyword in
+.Xr ssh_config 5
+for more information.
+.It Fl D Xo
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port
+.Sm on
+.Xc
+Specifies a local
+.Dq dynamic
+application-level port forwarding.
+This works by allocating a socket to listen to
+.Ar port
+on the local side, optionally bound to the specified
+.Ar bind_address .
+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 and SOCKS5 protocols are supported, and
+.Nm
+will act as a SOCKS server.
+Only root can forward privileged ports.
+Dynamic port forwardings can also be specified in the configuration file.
+.Pp
+IPv6 addresses can be specified by enclosing the address in square brackets.
+Only the superuser can forward privileged ports.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Sq *
+indicates that the port should be available from all interfaces.
+.It Fl e Ar escape_char
+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 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/ssh_config
+will be ignored.
+The default for the per-user configuration file is
+.Pa ~/.ssh/config .
+.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 .
+.Pp
+If the
+.Cm ExitOnForwardFailure
+configuration option is set to
+.Dq yes ,
+then a client started with
+.Fl f
+will wait for all remote port forwards to be successfully established
+before placing itself in the background.
+.It Fl g
+Allows remote hosts to connect to local forwarded ports.
+.It Fl I Ar pkcs11
+Specify the PKCS#11 shared library
+.Nm
+should use to communicate with a PKCS#11 token providing the user's
+private RSA key.
+.It Fl i Ar identity_file
+Selects a file from which the identity (private key) for
+public key authentication is read.
+The default is
+.Pa ~/.ssh/identity
+for protocol version 1, and
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/id_ecdsa
+and
+.Pa ~/.ssh/id_rsa
+for protocol version 2.
+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).
+.Nm
+will also try to load certificate information from the filename obtained
+by appending
+.Pa -cert.pub
+to identity filenames.
+.It Fl K
+Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI
+credentials to the server.
+.It Fl k
+Disables forwarding (delegation) of GSSAPI credentials to the server.
+.It Fl L Xo
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port : host : hostport
+.Sm on
+.Xc
+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, optionally bound to the specified
+.Ar bind_address .
+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.
+IPv6 addresses can be specified by enclosing the address in square brackets.
+Only the superuser can forward privileged ports.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Sq *
+indicates that the port should be available from all interfaces.
+.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
+Places the
+.Nm
+client into
+.Dq master
+mode for connection sharing.
+Multiple
+.Fl M
+options places
+.Nm
+into
+.Dq master
+mode with confirmation required before slave connections are accepted.
+Refer to the description of
+.Cm ControlMaster
+in
+.Xr ssh_config 5
+for details.
+.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
+Do not execute a remote command.
+This is useful for just forwarding ports
+(protocol version 2 only).
+.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 O Ar ctl_cmd
+Control an active connection multiplexing master process.
+When the
+.Fl O
+option is specified, the
+.Ar ctl_cmd
+argument is interpreted and passed to the master process.
+Valid commands are:
+.Dq check
+(check that the master process is running),
+.Dq forward
+(request forwardings without command execution) and
+.Dq exit
+(request the master to exit).
+.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.
+For full details of the options listed below, and their possible values, see
+.Xr ssh_config 5 .
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It AddressFamily
+.It BatchMode
+.It BindAddress
+.It ChallengeResponseAuthentication
+.It CheckHostIP
+.It Cipher
+.It Ciphers
+.It ClearAllForwardings
+.It Compression
+.It CompressionLevel
+.It ConnectionAttempts
+.It ConnectTimeout
+.It ControlMaster
+.It ControlPath
+.It DynamicForward
+.It EscapeChar
+.It ExitOnForwardFailure
+.It ForwardAgent
+.It ForwardX11
+.It ForwardX11Trusted
+.It GatewayPorts
+.It GlobalKnownHostsFile
+.It GSSAPIAuthentication
+.It GSSAPIDelegateCredentials
+.It HashKnownHosts
+.It Host
+.It HostbasedAuthentication
+.It HostKeyAlgorithms
+.It HostKeyAlias
+.It HostName
+.It IdentityFile
+.It IdentitiesOnly
+.It IPQoS
+.It KbdInteractiveDevices
+.It KexAlgorithms
+.It LocalCommand
+.It LocalForward
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It PermitLocalCommand
+.It PKCS11Provider
+.It Port
+.It PreferredAuthentications
+.It Protocol
+.It ProxyCommand
+.It PubkeyAuthentication
+.It RekeyLimit
+.It RemoteForward
+.It RhostsRSAAuthentication
+.It RSAAuthentication
+.It SendEnv
+.It ServerAliveInterval
+.It ServerAliveCountMax
+.It StrictHostKeyChecking
+.It TCPKeepAlive
+.It Tunnel
+.It TunnelDevice
+.It UsePrivilegedPort
+.It User
+.It UserKnownHostsFile
+.It VerifyHostKeyDNS
+.It VisualHostKey
+.It XAuthLocation
+.El
+.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 q
+Quiet mode.
+Causes most warning and diagnostic messages to be suppressed.
+.It Fl R Xo
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port : host : hostport
+.Sm on
+.Xc
+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.
+.Pp
+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 by enclosing the address in square braces.
+.Pp
+By default, the listening socket on the server will be bound to the loopback
+interface only.
+This may be overridden by specifying a
+.Ar bind_address .
+An empty
+.Ar bind_address ,
+or the address
+.Ql * ,
+indicates that the remote socket should listen on all interfaces.
+Specifying a remote
+.Ar bind_address
+will only succeed if the server's
+.Cm GatewayPorts
+option is enabled (see
+.Xr sshd_config 5 ) .
+.Pp
+If the
+.Ar port
+argument is
+.Ql 0 ,
+the listen port will be dynamically allocated on the server and reported
+to the client at run time.
+When used together with
+.Ic -O forward
+the allocated port will be printed to the standard output.
+.It Fl S Ar ctl_path
+Specifies the location of a control socket for connection sharing,
+or the string
+.Dq none
+to disable connection sharing.
+Refer to the description of
+.Cm ControlPath
+and
+.Cm ControlMaster
+in
+.Xr ssh_config 5
+for details.
+.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.\&
+.Xr sftp 1 ) .
+The subsystem is specified as the remote command.
+.It Fl T
+Disable pseudo-tty allocation.
+.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 V
+Display the version number and exit.
+.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 increase the verbosity.
+The maximum is 3.
+.It Fl W Ar host : Ns Ar port
+Requests that standard input and output on the client be forwarded to
+.Ar host
+on
+.Ar port
+over the secure channel.
+Implies
+.Fl N ,
+.Fl T ,
+.Cm ExitOnForwardFailure
+and
+.Cm ClearAllForwardings
+and works with Protocol version 2 only.
+.It Fl w Xo
+.Ar local_tun Ns Op : Ns Ar remote_tun
+.Xc
+Requests
+tunnel
+device forwarding with the specified
+.Xr tun 4
+devices between the client
+.Pq Ar local_tun
+and the server
+.Pq Ar remote_tun .
+.Pp
+The devices may be specified by numerical ID or the keyword
+.Dq any ,
+which uses the next available tunnel device.
+If
+.Ar remote_tun
+is not specified, it defaults to
+.Dq any .
+See also the
+.Cm Tunnel
+and
+.Cm TunnelDevice
+directives in
+.Xr ssh_config 5 .
+If the
+.Cm Tunnel
+directive is unset, it is set to the default tunnel mode, which is
+.Dq point-to-point .
+.It Fl X
+Enables X11 forwarding.
+This can also be specified on a per-host basis in a configuration file.
+.Pp
+X11 forwarding should be enabled with caution.
+Users with the ability to bypass file permissions on the remote host
+(for the user's X authorization database)
+can access the local X11 display through the forwarded connection.
+An attacker may then be able to perform activities such as keystroke monitoring.
+.Pp
+For this reason, X11 forwarding is subjected to X11 SECURITY extension
+restrictions by default.
+Please refer to the
+.Nm
+.Fl Y
+option and the
+.Cm ForwardX11Trusted
+directive in
+.Xr ssh_config 5
+for more information.
+.It Fl x
+Disables X11 forwarding.
+.It Fl Y
+Enables trusted X11 forwarding.
+Trusted X11 forwardings are not subjected to the X11 SECURITY extension
+controls.
+.It Fl y
+Send log information using the
+.Xr syslog 3
+system module.
+By default this information is sent to stderr.
+.El
+.Pp
+.Nm
+may additionally obtain configuration data from
+a per-user configuration file and a system-wide configuration file.
+The file format and configuration options are described in
+.Xr ssh_config 5 .
+.Sh AUTHENTICATION
+The OpenSSH SSH client supports SSH protocols 1 and 2.
+The default is to use protocol 2 only,
+though this can be changed via the
+.Cm Protocol
+option in
+.Xr ssh_config 5
+or the
+.Fl 1
+and
+.Fl 2
+options (see above).
+Both protocols support similar authentication methods,
+but protocol 2 is the default since
+it provides additional mechanisms for confidentiality
+(the traffic is encrypted using AES, 3DES, Blowfish, CAST128, or Arcfour)
+and integrity (hmac-md5, hmac-sha1, umac-64, hmac-ripemd160).
+Protocol 1 lacks a strong mechanism for ensuring the
+integrity of the connection.
+.Pp
+The methods available for authentication are:
+GSSAPI-based authentication,
+host-based authentication,
+public key authentication,
+challenge-response authentication,
+and password authentication.
+Authentication methods are tried in the order specified above,
+though protocol 2 has a configuration option to change the default order:
+.Cm PreferredAuthentications .
+.Pp
+Host-based authentication works as follows:
+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, or if the files
+.Pa ~/.rhosts
+or
+.Pa ~/.shosts
+exist in the user's home directory on the
+remote machine and contain a line containing the name of the client
+machine and the name of the user on that machine, the user is
+considered for login.
+Additionally, the server
+.Em must
+be able to verify the client's
+host key (see the description of
+.Pa /etc/ssh/ssh_known_hosts
+and
+.Pa ~/.ssh/known_hosts ,
+below)
+for login to be 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 ~/.rhosts ,
+and the rlogin/rsh protocol in general, are inherently insecure and should be
+disabled if security is desired.]
+.Pp
+Public key authentication works as follows:
+The scheme is based on public-key cryptography,
+using cryptosystems
+where encryption and decryption are done using separate keys,
+and it is unfeasible to derive the decryption key from the encryption key.
+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.
+.Nm
+implements public key authentication protocol automatically,
+using one of the DSA, ECDSA or RSA algorithms.
+Protocol 1 is restricted to using only RSA keys,
+but protocol 2 may use any.
+The
+.Sx HISTORY
+section of
+.Xr ssl 8
+contains a brief discussion of the DSA and RSA algorithms.
+.Pp
+The file
+.Pa ~/.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 client proves that it has access to the private key
+and the server checks that the corresponding public key
+is authorized to accept the account.
+.Pp
+The user creates his/her key pair by running
+.Xr ssh-keygen 1 .
+This stores the private key in
+.Pa ~/.ssh/identity
+(protocol 1),
+.Pa ~/.ssh/id_dsa
+(protocol 2 DSA),
+.Pa ~/.ssh/id_ecdsa
+(protocol 2 ECDSA),
+or
+.Pa ~/.ssh/id_rsa
+(protocol 2 RSA)
+and stores the public key in
+.Pa ~/.ssh/identity.pub
+(protocol 1),
+.Pa ~/.ssh/id_dsa.pub
+(protocol 2 DSA),
+.Pa ~/.ssh/id_ecdsa.pub
+(protocol 2 ECDSA),
+or
+.Pa ~/.ssh/id_rsa.pub
+(protocol 2 RSA)
+in the user's home directory.
+The user should then copy the public key
+to
+.Pa ~/.ssh/authorized_keys
+in his/her home directory on the remote machine.
+The
+.Pa authorized_keys
+file corresponds to the conventional
+.Pa ~/.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.
+.Pp
+A variation on public key authentication
+is available in the form of certificate authentication:
+instead of a set of public/private keys,
+signed certificates are used.
+This has the advantage that a single trusted certification authority
+can be used in place of many public/private keys.
+See the
+.Sx CERTIFICATES
+section of
+.Xr ssh-keygen 1
+for more information.
+.Pp
+The most convenient way to use public key or certificate authentication
+may be with an authentication agent.
+See
+.Xr ssh-agent 1
+for more information.
+.Pp
+Challenge-response authentication works as follows:
+The server sends an arbitrary
+.Qq challenge
+text, and prompts for a response.
+Protocol 2 allows multiple challenges and responses;
+protocol 1 is restricted to just one challenge/response.
+Examples of challenge-response authentication include
+BSD Authentication (see
+.Xr login.conf 5 )
+and PAM (some non-OpenBSD systems).
+.Pp
+Finally, 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
+.Nm
+automatically maintains and checks a database containing
+identification for all hosts it has ever been used with.
+Host keys are stored in
+.Pa ~/.ssh/known_hosts
+in the user's home directory.
+Additionally, the file
+.Pa /etc/ssh/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
+server spoofing or man-in-the-middle attacks,
+which could otherwise be used to circumvent the encryption.
+The
+.Cm StrictHostKeyChecking
+option can be used to control logins to machines whose
+host key is not known or has changed.
+.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 connections have been closed.
+.Sh ESCAPE CHARACTERS
+When a pseudo-terminal has been requested,
+.Nm
+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
+.Nm .
+.It Cm ~#
+List forwarded connections.
+.It Cm ~&
+Background
+.Nm
+at logout when waiting for forwarded connection / X11 sessions to terminate.
+.It Cm ~?
+Display a list of escape characters.
+.It Cm ~B
+Send a BREAK to the remote system
+(only useful for SSH protocol version 2 and if the peer supports it).
+.It Cm ~C
+Open command line.
+Currently this allows the addition of port forwardings using the
+.Fl L ,
+.Fl R
+and
+.Fl D
+options (see above).
+It also allows the cancellation of existing remote port-forwardings
+using
+.Sm off
+.Fl KR Oo Ar bind_address : Oc Ar port .
+.Sm on
+.Ic !\& Ns Ar command
+allows the user to execute a local command if the
+.Ic PermitLocalCommand
+option is enabled in
+.Xr ssh_config 5 .
+Basic help is available, using the
+.Fl h
+option.
+.It Cm ~R
+Request rekeying of the connection
+(only useful for SSH protocol version 2 and if the peer supports it).
+.El
+.Sh TCP FORWARDING
+Forwarding of arbitrary TCP connections over the secure channel can
+be specified either on the command line or in a configuration file.
+One possible application of TCP forwarding is a secure connection to a
+mail server; another is going through firewalls.
+.Pp
+In the example below, we look at encrypting communication between
+an IRC client and server, even though the IRC server does not directly
+support encrypted communications.
+This works as follows:
+the user connects to the remote host using
+.Nm ,
+specifying a port to be used to forward connections
+to the remote server.
+After that it is possible to start the service which is to be encrypted
+on the client machine,
+connecting to the same local port,
+and
+.Nm
+will encrypt and forward the connection.
+.Pp
+The following example tunnels an IRC session from client machine
+.Dq 127.0.0.1
+(localhost)
+to remote server
+.Dq server.example.com :
+.Bd -literal -offset 4n
+$ ssh -f -L 1234:localhost:6667 server.example.com sleep 10
+$ irc -c '#users' -p 1234 pinky 127.0.0.1
+.Ed
+.Pp
+This tunnels a connection to IRC server
+.Dq server.example.com ,
+joining channel
+.Dq #users ,
+nickname
+.Dq pinky ,
+using port 1234.
+It doesn't matter which port is used,
+as long as it's greater than 1023
+(remember, only root can open sockets on privileged ports)
+and doesn't conflict with any ports already in use.
+The connection is forwarded to port 6667 on the remote server,
+since that's the standard port for IRC services.
+.Pp
+The
+.Fl f
+option backgrounds
+.Nm
+and the remote command
+.Dq sleep 10
+is specified to allow an amount of time
+(10 seconds, in the example)
+to start the service which is to be tunnelled.
+If no connections are made within the time specified,
+.Nm
+will exit.
+.Sh X11 FORWARDING
+If the
+.Cm ForwardX11
+variable is set to
+.Dq yes
+(or see the description of the
+.Fl X ,
+.Fl x ,
+and
+.Fl Y
+options above)
+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
+.Cm ForwardAgent
+variable is set to
+.Dq yes
+(or see the description of the
+.Fl A
+and
+.Fl a
+options above) and
+the user is using an authentication agent, the connection to the agent
+is automatically forwarded to the remote side.
+.Sh VERIFYING HOST KEYS
+When connecting to a server for the first time,
+a fingerprint of the server's public key is presented to the user
+(unless the option
+.Cm StrictHostKeyChecking
+has been disabled).
+Fingerprints can be determined using
+.Xr ssh-keygen 1 :
+.Pp
+.Dl $ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
+.Pp
+If the fingerprint is already known, it can be matched
+and the key can be accepted or rejected.
+Because of the difficulty of comparing host keys
+just by looking at hex strings,
+there is also support to compare host keys visually,
+using
+.Em random art .
+By setting the
+.Cm VisualHostKey
+option to
+.Dq yes ,
+a small ASCII graphic gets displayed on every login to a server, no matter
+if the session itself is interactive or not.
+By learning the pattern a known server produces, a user can easily
+find out that the host key has changed when a completely different pattern
+is displayed.
+Because these patterns are not unambiguous however, a pattern that looks
+similar to the pattern remembered only gives a good probability that the
+host key is the same, not guaranteed proof.
+.Pp
+To get a listing of the fingerprints along with their random art for
+all known hosts, the following command line can be used:
+.Pp
+.Dl $ ssh-keygen -lv -f ~/.ssh/known_hosts
+.Pp
+If the fingerprint is unknown,
+an alternative method of verification is available:
+SSH fingerprints verified by DNS.
+An additional resource record (RR),
+SSHFP,
+is added to a zonefile
+and the connecting client is able to match the fingerprint
+with that of the key presented.
+.Pp
+In this example, we are connecting a client to a server,
+.Dq host.example.com .
+The SSHFP resource records should first be added to the zonefile for
+host.example.com:
+.Bd -literal -offset indent
+$ ssh-keygen -r host.example.com.
+.Ed
+.Pp
+The output lines will have to be added to the zonefile.
+To check that the zone is answering fingerprint queries:
+.Pp
+.Dl $ dig -t SSHFP host.example.com
+.Pp
+Finally the client connects:
+.Bd -literal -offset indent
+$ ssh -o "VerifyHostKeyDNS ask" host.example.com
+[...]
+Matching host key fingerprint found in DNS.
+Are you sure you want to continue connecting (yes/no)?
+.Ed
+.Pp
+See the
+.Cm VerifyHostKeyDNS
+option in
+.Xr ssh_config 5
+for more information.
+.Sh SSH-BASED VIRTUAL PRIVATE NETWORKS
+.Nm
+contains support for Virtual Private Network (VPN) tunnelling
+using the
+.Xr tun 4
+network pseudo-device,
+allowing two networks to be joined securely.
+The
+.Xr sshd_config 5
+configuration option
+.Cm PermitTunnel
+controls whether the server supports this,
+and at what level (layer 2 or 3 traffic).
+.Pp
+The following example would connect client network 10.0.50.0/24
+with remote network 10.0.99.0/24 using a point-to-point connection
+from 10.1.1.1 to 10.1.1.2,
+provided that the SSH server running on the gateway to the remote network,
+at 192.168.1.15, allows it.
+.Pp
+On the client:
+.Bd -literal -offset indent
+# ssh -f -w 0:1 192.168.1.15 true
+# ifconfig tun0 10.1.1.1 10.1.1.2 netmask 255.255.255.252
+# route add 10.0.99.0/24 10.1.1.2
+.Ed
+.Pp
+On the server:
+.Bd -literal -offset indent
+# ifconfig tun1 10.1.1.2 10.1.1.1 netmask 255.255.255.252
+# route add 10.0.50.0/24 10.1.1.1
+.Ed
+.Pp
+Client access may be more finely tuned via the
+.Pa /root/.ssh/authorized_keys
+file (see below) and the
+.Cm PermitRootLogin
+server option.
+The following entry would permit connections on
+.Xr tun 4
+device 1 from user
+.Dq jane
+and on tun device 2 from user
+.Dq john ,
+if
+.Cm PermitRootLogin
+is set to
+.Dq forced-commands-only :
+.Bd -literal -offset 2n
+tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... jane
+tunnel="2",command="sh /etc/netstart tun2" ssh-rsa ... john
+.Ed
+.Pp
+Since an SSH-based setup entails a fair amount of overhead,
+it may be more suited to temporary setups,
+such as for wireless VPNs.
+More permanent VPNs are better provided by tools such as
+.Xr ipsecctl 8
+and
+.Xr isakmpd 8 .
+.Sh ENVIRONMENT
+.Nm
+will normally set the following environment variables:
+.Bl -tag -width "SSH_ORIGINAL_COMMAND"
+.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
+.Dq hostname
+indicates the host where the shell runs, and
+.Sq n
+is an integer \*(Ge 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 .
+.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
+.Ux Ns -domain
+socket used to communicate with the agent.
+.It Ev SSH_CONNECTION
+Identifies the client and server ends of the connection.
+The variable contains
+four space-separated values: client IP address, client port number,
+server IP address, and server port number.
+.It Ev SSH_ORIGINAL_COMMAND
+This 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
+This variable is set to indicate the present time zone 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 ~/.ssh/environment ,
+and adds lines of the format
+.Dq VARNAME=value
+to the environment if the file exists and users are allowed to
+change their environment.
+For more information, see the
+.Cm PermitUserEnvironment
+option in
+.Xr sshd_config 5 .
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It Pa ~/.rhosts
+This file is used for host-based authentication (see above).
+On some machines this file may need to be
+world-readable if the user's home directory is on an 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
+.It Pa ~/.shosts
+This file is used in exactly the same way as
+.Pa .rhosts ,
+but allows host-based authentication without permitting login with
+rlogin/rsh.
+.Pp
+.It Pa ~/.ssh/
+This directory is the default location for all user-specific configuration
+and authentication information.
+There is no general requirement to keep the entire contents of this directory
+secret, but the recommended permissions are read/write/execute for the user,
+and not accessible by others.
+.Pp
+.It Pa ~/.ssh/authorized_keys
+Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in as
+this user.
+The format of this file is described in the
+.Xr sshd 8
+manual page.
+This file is not highly sensitive, but the recommended
+permissions are read/write for the user, and not accessible by others.
+.Pp
+.It Pa ~/.ssh/config
+This is the per-user configuration file.
+The file format and configuration options are described in
+.Xr ssh_config 5 .
+Because of the potential for abuse, this file must have strict permissions:
+read/write for the user, and not accessible by others.
+.Pp
+.It Pa ~/.ssh/environment
+Contains additional definitions for environment variables; see
+.Sx ENVIRONMENT ,
+above.
+.Pp
+.It Pa ~/.ssh/identity
+.It Pa ~/.ssh/id_dsa
+.It Pa ~/.ssh/id_ecdsa
+.It Pa ~/.ssh/id_rsa
+Contains the private key for authentication.
+These files
+contain sensitive data and should be readable by the user but not
+accessible by others (read/write/execute).
+.Nm
+will simply ignore a private key file if it is accessible by others.
+It is possible to specify a passphrase when
+generating the key which will be used to encrypt the
+sensitive part of this file using 3DES.
+.Pp
+.It Pa ~/.ssh/identity.pub
+.It Pa ~/.ssh/id_dsa.pub
+.It Pa ~/.ssh/id_ecdsa.pub
+.It Pa ~/.ssh/id_rsa.pub
+Contains the public key for authentication.
+These files are not
+sensitive and can (but need not) be readable by anyone.
+.Pp
+.It Pa ~/.ssh/known_hosts
+Contains a list of host keys for all hosts the user has logged into
+that are not already in the systemwide list of known host keys.
+See
+.Xr sshd 8
+for further details of the format of this file.
+.Pp
+.It Pa ~/.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.
+.Pp
+.It Pa /etc/hosts.equiv
+This file is for host-based authentication (see above).
+It should only be writable by root.
+.Pp
+.It Pa /etc/shosts.equiv
+This file is used in exactly the same way as
+.Pa hosts.equiv ,
+but allows host-based authentication without permitting login with
+rlogin/rsh.
+.Pp
+.It Pa /etc/ssh/ssh_config
+Systemwide configuration file.
+The file format and configuration options are described in
+.Xr ssh_config 5 .
+.Pp
+.It Pa /etc/ssh/ssh_host_key
+.It Pa /etc/ssh/ssh_host_dsa_key
+.It Pa /etc/ssh/ssh_host_ecdsa_key
+.It Pa /etc/ssh/ssh_host_rsa_key
+These three files contain the private parts of the host keys
+and are used for host-based authentication.
+If protocol version 1 is used,
+.Nm
+must be setuid root, since the host key is readable only by root.
+For protocol version 2,
+.Nm
+uses
+.Xr ssh-keysign 8
+to access the host keys,
+eliminating the requirement that
+.Nm
+be setuid root when host-based authentication is used.
+By default
+.Nm
+is not setuid root.
+.Pp
+.It Pa /etc/ssh/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.
+It should be world-readable.
+See
+.Xr sshd 8
+for further details of the format of this file.
+.Pp
+.It Pa /etc/ssh/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.
+.El
+.Sh EXIT STATUS
+.Nm
+exits with the exit status of the remote command or with 255
+if an error occurred.
+.Sh SEE ALSO
+.Xr scp 1 ,
+.Xr sftp 1 ,
+.Xr ssh-add 1 ,
+.Xr ssh-agent 1 ,
+.Xr ssh-keygen 1 ,
+.Xr ssh-keyscan 1 ,
+.Xr tun 4 ,
+.Xr hosts.equiv 5 ,
+.Xr ssh_config 5 ,
+.Xr ssh-keysign 8 ,
+.Xr sshd 8
+.Rs
+.%R RFC 4250
+.%T "The Secure Shell (SSH) Protocol Assigned Numbers"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4251
+.%T "The Secure Shell (SSH) Protocol Architecture"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4252
+.%T "The Secure Shell (SSH) Authentication Protocol"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4253
+.%T "The Secure Shell (SSH) Transport Layer Protocol"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4254
+.%T "The Secure Shell (SSH) Connection Protocol"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4255
+.%T "Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4256
+.%T "Generic Message Exchange Authentication for the Secure Shell Protocol (SSH)"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4335
+.%T "The Secure Shell (SSH) Session Channel Break Extension"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4344
+.%T "The Secure Shell (SSH) Transport Layer Encryption Modes"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4345
+.%T "Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4419
+.%T "Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol"
+.%D 2006
+.Re
+.Rs
+.%R RFC 4716
+.%T "The Secure Shell (SSH) Public Key File Format"
+.%D 2006
+.Re
+.Rs
+.%R RFC 5656
+.%T "Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer"
+.%D 2009
+.Re
+.Rs
+.%T "Hash Visualization: a New Technique to improve Real-World Security"
+.%A A. Perrig
+.%A D. Song
+.%D 1999
+.%O "International Workshop on Cryptographic Techniques and E-Commerce (CrypTEC '99)"
+.Re
+.Sh AUTHORS
+OpenSSH is a derivative of the original and free
+ssh 1.2.12 release by Tatu Ylonen.
+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.
diff --git a/ssh.c b/ssh.c
new file mode 100644 (file)
index 0000000..d32ef78
--- /dev/null
+++ b/ssh.c
@@ -0,0 +1,1557 @@
+/* $OpenBSD: ssh.c,v 1.356 2011/01/06 22:23:53 djm Exp $ */
+/*
+ * 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.
+ * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl.  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"
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include "openbsd-compat/openssl-compat.h"
+#include "openbsd-compat/sys-queue.h"
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "canohost.h"
+#include "compat.h"
+#include "cipher.h"
+#include "packet.h"
+#include "buffer.h"
+#include "channels.h"
+#include "key.h"
+#include "authfd.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "dispatch.h"
+#include "clientloop.h"
+#include "log.h"
+#include "readconf.h"
+#include "sshconnect.h"
+#include "misc.h"
+#include "kex.h"
+#include "mac.h"
+#include "sshpty.h"
+#include "match.h"
+#include "msg.h"
+#include "uidswap.h"
+#include "roaming.h"
+#include "version.h"
+
+#ifdef ENABLE_PKCS11
+#include "ssh-pkcs11.h"
+#endif
+
+extern char *__progname;
+
+/* Flag indicating whether debug mode is on.  May be set on the command line. */
+int debug_flag = 0;
+
+/* Flag indicating whether a tty should be allocated */
+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 the current process should be backgrounded and
+ * a new slave launched in the foreground for ControlPersist.
+ */
+int need_controlpersist_detach = 0;
+
+/* Copies of flags for ControlPersist foreground slave */
+int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag;
+
+/*
+ * Flag indicating that ssh should fork after authentication.  This is useful
+ * so that the passphrase can be entered manually, and then ssh goes to the
+ * background.
+ */
+int fork_after_authentication_flag = 0;
+
+/* forward stdio to remote host and port */
+char *stdio_forward_host = NULL;
+int stdio_forward_port = 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. */
+Sensitive sensitive_data;
+
+/* Original real UID. */
+uid_t original_real_uid;
+uid_t original_effective_uid;
+
+/* command to be executed */
+Buffer command;
+
+/* Should we execute a command or invoke a subsystem? */
+int subsystem_flag = 0;
+
+/* # of replies received for global requests */
+static int remote_forward_confirms_received = 0;
+
+/* mux.c */
+extern int muxserver_sock;
+extern u_int muxclient_command;
+
+/* Prints a help message to the user.  This function never returns. */
+
+static void
+usage(void)
+{
+       fprintf(stderr,
+"usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n"
+"           [-D [bind_address:]port] [-e escape_char] [-F configfile]\n"
+"           [-I pkcs11] [-i identity_file]\n"
+"           [-L [bind_address:]port:host:hostport]\n"
+"           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n"
+"           [-R [bind_address:]port:host:hostport] [-S ctl_path]\n"
+"           [-W host:port] [-w local_tun[:remote_tun]]\n"
+"           [user@]hostname [command]\n"
+       );
+       exit(255);
+}
+
+static int ssh_session(void);
+static int ssh_session2(void);
+static void load_public_identity_files(void);
+static void main_sigchld_handler(int);
+
+/* from muxclient.c */
+void muxclient(const char *);
+void muxserver_listen(void);
+
+/*
+ * Main program for the ssh client.
+ */
+int
+main(int ac, char **av)
+{
+       int i, r, opt, exit_status, use_syslog;
+       char *p, *cp, *line, *argv0, buf[MAXPATHLEN], *host_arg;
+       struct stat st;
+       struct passwd *pw;
+       int dummy, timeout_ms;
+       extern int optind, optreset;
+       extern char *optarg;
+       struct servent *sp;
+       Forward fwd;
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       __progname = ssh_get_progname(av[0]);
+       init_rng();
+
+       /*
+        * Discard other fds that are hanging around. These can cause problem
+        * with backgrounded ssh processes started by ControlPersist.
+        */
+       closefrom(STDERR_FILENO + 1);
+
+       /*
+        * 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();
+
+       /*
+        * 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).
+        */
+       PRIV_END;
+
+#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) {
+               logit("You don't exist, go away!");
+               exit(255);
+       }
+       /* Take a copy of the returned structure. */
+       pw = pwcopy(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;
+       use_syslog = 0;
+       argv0 = av[0];
+
+ again:
+       while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
+           "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) {
+               switch (opt) {
+               case '1':
+                       options.protocol = SSH_PROTO_1;
+                       break;
+               case '2':
+                       options.protocol = SSH_PROTO_2;
+                       break;
+               case '4':
+                       options.address_family = AF_INET;
+                       break;
+               case '6':
+                       options.address_family = 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 'y':
+                       use_syslog = 1;
+                       break;
+               case 'Y':
+                       options.forward_x11 = 1;
+                       options.forward_x11_trusted = 1;
+                       break;
+               case 'g':
+                       options.gateway_ports = 1;
+                       break;
+               case 'O':
+                       if (stdio_forward_host != NULL)
+                               fatal("Cannot specify multiplexing "
+                                   "command with -W");
+                       else if (muxclient_command != 0)
+                               fatal("Multiplexing command already specified");
+                       if (strcmp(optarg, "check") == 0)
+                               muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
+                       else if (strcmp(optarg, "forward") == 0)
+                               muxclient_command = SSHMUX_COMMAND_FORWARD;
+                       else if (strcmp(optarg, "exit") == 0)
+                               muxclient_command = SSHMUX_COMMAND_TERMINATE;
+                       else
+                               fatal("Invalid multiplex command.");
+                       break;
+               case 'P':       /* deprecated */
+                       options.use_privileged_port = 0;
+                       break;
+               case 'a':
+                       options.forward_agent = 0;
+                       break;
+               case 'A':
+                       options.forward_agent = 1;
+                       break;
+               case 'k':
+                       options.gss_deleg_creds = 0;
+                       break;
+               case 'K':
+                       options.gss_authentication = 1;
+                       options.gss_deleg_creds = 1;
+                       break;
+               case 'i':
+                       if (stat(optarg, &st) < 0) {
+                               fprintf(stderr, "Warning: Identity file %s "
+                                   "not accessible: %s.\n", optarg,
+                                   strerror(errno));
+                               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 ENABLE_PKCS11
+                       options.pkcs11_provider = xstrdup(optarg);
+#else
+                       fprintf(stderr, "no support for PKCS#11.\n");
+#endif
+                       break;
+               case 't':
+                       if (tty_flag)
+                               force_tty_flag = 1;
+                       tty_flag = 1;
+                       break;
+               case 'v':
+                       if (debug_flag == 0) {
+                               debug_flag = 1;
+                               options.log_level = SYSLOG_LEVEL_DEBUG1;
+                       } else {
+                               if (options.log_level < SYSLOG_LEVEL_DEBUG3)
+                                       options.log_level++;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               case 'V':
+                       fprintf(stderr, "%s, %s\n",
+                           SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
+                       if (opt == 'V')
+                               exit(0);
+                       break;
+               case 'w':
+                       if (options.tun_open == -1)
+                               options.tun_open = SSH_TUNMODE_DEFAULT;
+                       options.tun_local = a2tun(optarg, &options.tun_remote);
+                       if (options.tun_local == SSH_TUNID_ERR) {
+                               fprintf(stderr,
+                                   "Bad tun device '%s'\n", optarg);
+                               exit(255);
+                       }
+                       break;
+               case 'W':
+                       if (stdio_forward_host != NULL)
+                               fatal("stdio forward already specified");
+                       if (muxclient_command != 0)
+                               fatal("Cannot specify stdio forward with -O");
+                       if (parse_forward(&fwd, optarg, 1, 0)) {
+                               stdio_forward_host = fwd.listen_host;
+                               stdio_forward_port = fwd.listen_port;
+                               xfree(fwd.connect_host);
+                       } else {
+                               fprintf(stderr,
+                                   "Bad stdio forwarding specification '%s'\n",
+                                   optarg);
+                               exit(255);
+                       }
+                       no_tty_flag = 1;
+                       no_shell_flag = 1;
+                       options.clear_forwardings = 1;
+                       options.exit_on_forward_failure = 1;
+                       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(255);
+                       }
+                       break;
+               case 'c':
+                       if (ciphers_valid(optarg)) {
+                               /* SSH2 only */
+                               options.ciphers = xstrdup(optarg);
+                               options.cipher = SSH_CIPHER_INVALID;
+                       } else {
+                               /* SSH1 only */
+                               options.cipher = cipher_number(optarg);
+                               if (options.cipher == -1) {
+                                       fprintf(stderr,
+                                           "Unknown cipher type '%s'\n",
+                                           optarg);
+                                       exit(255);
+                               }
+                               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(255);
+                       }
+                       break;
+               case 'M':
+                       if (options.control_master == SSHCTL_MASTER_YES)
+                               options.control_master = SSHCTL_MASTER_ASK;
+                       else
+                               options.control_master = SSHCTL_MASTER_YES;
+                       break;
+               case 'p':
+                       options.port = a2port(optarg);
+                       if (options.port <= 0) {
+                               fprintf(stderr, "Bad port '%s'\n", optarg);
+                               exit(255);
+                       }
+                       break;
+               case 'l':
+                       options.user = optarg;
+                       break;
+
+               case 'L':
+                       if (parse_forward(&fwd, optarg, 0, 0))
+                               add_local_forward(&options, &fwd);
+                       else {
+                               fprintf(stderr,
+                                   "Bad local forwarding specification '%s'\n",
+                                   optarg);
+                               exit(255);
+                       }
+                       break;
+
+               case 'R':
+                       if (parse_forward(&fwd, optarg, 0, 1)) {
+                               add_remote_forward(&options, &fwd);
+                       } else {
+                               fprintf(stderr,
+                                   "Bad remote forwarding specification "
+                                   "'%s'\n", optarg);
+                               exit(255);
+                       }
+                       break;
+
+               case 'D':
+                       if (parse_forward(&fwd, optarg, 1, 0)) {
+                               add_local_forward(&options, &fwd);
+                       } else {
+                               fprintf(stderr,
+                                   "Bad dynamic forwarding specification "
+                                   "'%s'\n", optarg);
+                               exit(255);
+                       }
+                       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;
+                       line = xstrdup(optarg);
+                       if (process_config_line(&options, host ? host : "",
+                           line, "command-line", 0, &dummy) != 0)
+                               exit(255);
+                       xfree(line);
+                       break;
+               case 's':
+                       subsystem_flag = 1;
+                       break;
+               case 'S':
+                       if (options.control_path != NULL)
+                               free(options.control_path);
+                       options.control_path = xstrdup(optarg);
+                       break;
+               case 'b':
+                       options.bind_address = optarg;
+                       break;
+               case 'F':
+                       config = optarg;
+                       break;
+               default:
+                       usage();
+               }
+       }
+
+       ac -= optind;
+       av += optind;
+
+       if (ac > 0 && !host) {
+               if (strrchr(*av, '@')) {
+                       p = xstrdup(*av);
+                       cp = strrchr(p, '@');
+                       if (cp == NULL || cp == p)
+                               usage();
+                       options.user = p;
+                       *cp = '\0';
+                       host = ++cp;
+               } else
+                       host = *av;
+               if (ac > 1) {
+                       optind = optreset = 1;
+                       goto again;
+               }
+               ac--, av++;
+       }
+
+       /* Check that we got a host name. */
+       if (!host)
+               usage();
+
+       OpenSSL_add_all_algorithms();
+       ERR_load_crypto_strings();
+
+       /* 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 || muxclient_command != 0)
+               tty_flag = 0;
+       /* Do not allocate a tty if stdin is not a tty. */
+       if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
+               if (tty_flag)
+                       logit("Pseudo-terminal will not be allocated because "
+                           "stdin is not a terminal.");
+               tty_flag = 0;
+       }
+
+       /*
+        * Initialize "log" output.  Since we are the client all output
+        * actually goes to stderr.
+        */
+       log_init(argv0,
+           options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
+           SYSLOG_FACILITY_USER, !use_syslog);
+
+       /*
+        * 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, 0))
+                       fatal("Can't open user config file %.100s: "
+                           "%.100s", config, strerror(errno));
+       } else {
+               r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir,
+                   _PATH_SSH_USER_CONFFILE);
+               if (r > 0 && (size_t)r < sizeof(buf))
+                       (void)read_config_file(buf, host, &options, 1);
+
+               /* Read systemwide configuration file after use config. */
+               (void)read_config_file(_PATH_HOST_CONFIG_FILE, host,
+                   &options, 0);
+       }
+
+       /* Fill configuration defaults. */
+       fill_default_options(&options);
+
+       channel_set_af(options.address_family);
+
+       /* reinit */
+       log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog);
+
+       seed_rng();
+
+       if (options.user == NULL)
+               options.user = xstrdup(pw->pw_name);
+
+       /* Get default port if port has not been set. */
+       if (options.port == 0) {
+               sp = getservbyname(SSH_SERVICE_NAME, "tcp");
+               options.port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
+       }
+
+       /* preserve host name given on command line for %n expansion */
+       host_arg = host;
+       if (options.hostname != NULL) {
+               host = percent_expand(options.hostname,
+                   "h", host, (char *)NULL);
+       }
+
+       if (options.local_command != NULL) {
+               char thishost[NI_MAXHOST];
+
+               if (gethostname(thishost, sizeof(thishost)) == -1)
+                       fatal("gethostname: %s", strerror(errno));
+               snprintf(buf, sizeof(buf), "%d", options.port);
+               debug3("expanding LocalCommand: %s", options.local_command);
+               cp = options.local_command;
+               options.local_command = percent_expand(cp, "d", pw->pw_dir,
+                   "h", host, "l", thishost, "n", host_arg, "r", options.user,
+                   "p", buf, "u", pw->pw_name, (char *)NULL);
+               debug3("expanded LocalCommand: %s", options.local_command);
+               xfree(cp);
+       }
+
+       /* force lowercase for hostkey matching */
+       if (options.host_key_alias != NULL) {
+               for (p = options.host_key_alias; *p; p++)
+                       if (isupper(*p))
+                               *p = (char)tolower(*p);
+       }
+
+       if (options.proxy_command != NULL &&
+           strcmp(options.proxy_command, "none") == 0) {
+               xfree(options.proxy_command);
+               options.proxy_command = NULL;
+       }
+       if (options.control_path != NULL &&
+           strcmp(options.control_path, "none") == 0) {
+               xfree(options.control_path);
+               options.control_path = NULL;
+       }
+
+       if (options.control_path != NULL) {
+               char thishost[NI_MAXHOST];
+
+               if (gethostname(thishost, sizeof(thishost)) == -1)
+                       fatal("gethostname: %s", strerror(errno));
+               snprintf(buf, sizeof(buf), "%d", options.port);
+               cp = tilde_expand_filename(options.control_path,
+                   original_real_uid);
+               xfree(options.control_path);
+               options.control_path = percent_expand(cp, "p", buf, "h", host,
+                   "r", options.user, "l", thishost, (char *)NULL);
+               xfree(cp);
+       }
+       if (muxclient_command != 0 && options.control_path == NULL)
+               fatal("No ControlPath specified for \"-O\" command");
+       if (options.control_path != NULL)
+               muxclient(options.control_path);
+
+       timeout_ms = options.connection_timeout * 1000;
+
+       /* Open a connection to the remote host. */
+       if (ssh_connect(host, &hostaddr, options.port,
+           options.address_family, options.connection_attempts, &timeout_ms,
+           options.tcp_keep_alive, 
+#ifdef HAVE_CYGWIN
+           options.use_privileged_port,
+#else
+           original_effective_uid == 0 && options.use_privileged_port,
+#endif
+           options.proxy_command) != 0)
+               exit(255);
+
+       if (timeout_ms > 0)
+               debug3("timeout: %d ms remain after connect", timeout_ms);
+
+       /*
+        * 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.
+        * If we cannot access the private keys, load the public keys
+        * instead and try to execute the ssh-keysign helper instead.
+        */
+       sensitive_data.nkeys = 0;
+       sensitive_data.keys = NULL;
+       sensitive_data.external_keysign = 0;
+       if (options.rhosts_rsa_authentication ||
+           options.hostbased_authentication) {
+               sensitive_data.nkeys = 7;
+               sensitive_data.keys = xcalloc(sensitive_data.nkeys,
+                   sizeof(Key));
+               for (i = 0; i < sensitive_data.nkeys; i++)
+                       sensitive_data.keys[i] = NULL;
+
+               PRIV_START;
+               sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
+                   _PATH_HOST_KEY_FILE, "", NULL, NULL);
+               sensitive_data.keys[1] = key_load_private_cert(KEY_DSA,
+                   _PATH_HOST_DSA_KEY_FILE, "", NULL);
+#ifdef OPENSSL_HAS_ECC
+               sensitive_data.keys[2] = key_load_private_cert(KEY_ECDSA,
+                   _PATH_HOST_ECDSA_KEY_FILE, "", NULL);
+#endif
+               sensitive_data.keys[3] = key_load_private_cert(KEY_RSA,
+                   _PATH_HOST_RSA_KEY_FILE, "", NULL);
+               sensitive_data.keys[4] = key_load_private_type(KEY_DSA,
+                   _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
+#ifdef OPENSSL_HAS_ECC
+               sensitive_data.keys[5] = key_load_private_type(KEY_ECDSA,
+                   _PATH_HOST_ECDSA_KEY_FILE, "", NULL, NULL);
+#endif
+               sensitive_data.keys[6] = key_load_private_type(KEY_RSA,
+                   _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);
+               PRIV_END;
+
+               if (options.hostbased_authentication == 1 &&
+                   sensitive_data.keys[0] == NULL &&
+                   sensitive_data.keys[4] == NULL &&
+                   sensitive_data.keys[5] == NULL &&
+                   sensitive_data.keys[6] == NULL) {
+                       sensitive_data.keys[1] = key_load_cert(
+                           _PATH_HOST_DSA_KEY_FILE);
+#ifdef OPENSSL_HAS_ECC
+                       sensitive_data.keys[2] = key_load_cert(
+                           _PATH_HOST_ECDSA_KEY_FILE);
+#endif
+                       sensitive_data.keys[3] = key_load_cert(
+                           _PATH_HOST_RSA_KEY_FILE);
+                       sensitive_data.keys[4] = key_load_public(
+                           _PATH_HOST_DSA_KEY_FILE, NULL);
+#ifdef OPENSSL_HAS_ECC
+                       sensitive_data.keys[5] = key_load_public(
+                           _PATH_HOST_ECDSA_KEY_FILE, NULL);
+#endif
+                       sensitive_data.keys[6] = key_load_public(
+                           _PATH_HOST_RSA_KEY_FILE, NULL);
+                       sensitive_data.external_keysign = 1;
+               }
+       }
+       /*
+        * 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.
+        */
+       if (original_effective_uid == 0) {
+               PRIV_START;
+               permanently_set_uid(pw);
+       }
+
+       /*
+        * Now that we are back to our own permissions, create ~/.ssh
+        * directory if it doesn't already exist.
+        */
+       r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir,
+           strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR);
+       if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) {
+#ifdef WITH_SELINUX
+               ssh_selinux_setfscreatecon(buf);
+#endif
+               if (mkdir(buf, 0700) < 0)
+                       error("Could not create directory '%.200s'.", buf);
+#ifdef WITH_SELINUX
+               ssh_selinux_setfscreatecon(NULL);
+#endif
+       }
+       /* 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 */
+       signal(SIGCHLD, main_sigchld_handler);
+
+       /* Log into the remote system.  Never returns if the login fails. */
+       ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
+           options.port, pw, timeout_ms);
+
+       if (packet_connection_is_on_socket()) {
+               verbose("Authenticated to %s ([%s]:%d).", host,
+                   get_remote_ipaddr(), get_remote_port());
+       } else {
+               verbose("Authenticated to %s (via proxy).", host);
+       }
+
+       /* 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();
+
+       if (options.control_path != NULL && muxserver_sock != -1)
+               unlink(options.control_path);
+
+       /* Kill ProxyCommand if it is running. */
+       ssh_kill_proxy_command();
+
+       return exit_status;
+}
+
+static void
+control_persist_detach(void)
+{
+       pid_t pid;
+       int devnull;
+
+       debug("%s: backgrounding master process", __func__);
+
+       /*
+        * master (current process) into the background, and make the
+        * foreground process a client of the backgrounded master.
+        */
+       switch ((pid = fork())) {
+       case -1:
+               fatal("%s: fork: %s", __func__, strerror(errno));
+       case 0:
+               /* Child: master process continues mainloop */
+               break;
+       default:
+               /* Parent: set up mux slave to connect to backgrounded master */
+               debug2("%s: background process is %ld", __func__, (long)pid);
+               stdin_null_flag = ostdin_null_flag;
+               no_shell_flag = ono_shell_flag;
+               no_tty_flag = ono_tty_flag;
+               tty_flag = otty_flag;
+               close(muxserver_sock);
+               muxserver_sock = -1;
+               options.control_master = SSHCTL_MASTER_NO;
+               muxclient(options.control_path);
+               /* muxclient() doesn't return on success. */
+               fatal("Failed to connect to new control master");
+       }
+       if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
+               error("%s: open(\"/dev/null\"): %s", __func__,
+                   strerror(errno));
+       } else {
+               if (dup2(devnull, STDIN_FILENO) == -1 ||
+                   dup2(devnull, STDOUT_FILENO) == -1)
+                       error("%s: dup2: %s", __func__, strerror(errno));
+               if (devnull > STDERR_FILENO)
+                       close(devnull);
+       }
+}
+
+/* Do fork() after authentication. Used by "ssh -f" */
+static void
+fork_postauth(void)
+{
+       if (need_controlpersist_detach)
+               control_persist_detach();
+       debug("forking to background");
+       fork_after_authentication_flag = 0;
+       if (daemon(1, 1) < 0)
+               fatal("daemon() failed: %.200s", strerror(errno));
+}
+
+/* Callback for remote forward global requests */
+static void
+ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+{
+       Forward *rfwd = (Forward *)ctxt;
+
+       /* XXX verbose() on failure? */
+       debug("remote forward %s for: listen %d, connect %s:%d",
+           type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",
+           rfwd->listen_port, rfwd->connect_host, rfwd->connect_port);
+       if (type == SSH2_MSG_REQUEST_SUCCESS && rfwd->listen_port == 0) {
+               rfwd->allocated_port = packet_get_int();
+               logit("Allocated port %u for remote forward to %s:%d",
+                   rfwd->allocated_port,
+                   rfwd->connect_host, rfwd->connect_port);
+       }
+       
+       if (type == SSH2_MSG_REQUEST_FAILURE) {
+               if (options.exit_on_forward_failure)
+                       fatal("Error: remote port forwarding failed for "
+                           "listen port %d", rfwd->listen_port);
+               else
+                       logit("Warning: remote port forwarding failed for "
+                           "listen port %d", rfwd->listen_port);
+       }
+       if (++remote_forward_confirms_received == options.num_remote_forwards) {
+               debug("All remote forwarding requests processed");
+               if (fork_after_authentication_flag)
+                       fork_postauth();
+       }
+}
+
+static void
+client_cleanup_stdio_fwd(int id, void *arg)
+{
+       debug("stdio forwarding: done");
+       cleanup_exit(0);
+}
+
+static int
+client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect)
+{
+       Channel *c;
+       int in, out;
+
+       debug3("client_setup_stdio_fwd %s:%d", host_to_connect,
+           port_to_connect);
+
+       in = dup(STDIN_FILENO);
+       out = dup(STDOUT_FILENO);
+       if (in < 0 || out < 0)
+               fatal("channel_connect_stdio_fwd: dup() in/out failed");
+
+       if ((c = channel_connect_stdio_fwd(host_to_connect, port_to_connect,
+           in, out)) == NULL)
+               return 0;
+       channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
+       return 1;
+}
+
+static void
+ssh_init_forwarding(void)
+{
+       int success = 0;
+       int i;
+
+       if (stdio_forward_host != NULL) {
+               if (!compat20) {
+                       fatal("stdio forwarding require Protocol 2");
+               }
+               if (!client_setup_stdio_fwd(stdio_forward_host,
+                   stdio_forward_port))
+                       fatal("Failed to connect in stdio forward mode.");
+       }
+
+       /* Initiate local TCP/IP port forwardings. */
+       for (i = 0; i < options.num_local_forwards; i++) {
+               debug("Local connections to %.200s:%d forwarded to remote "
+                   "address %.200s:%d",
+                   (options.local_forwards[i].listen_host == NULL) ?
+                   (options.gateway_ports ? "*" : "LOCALHOST") :
+                   options.local_forwards[i].listen_host,
+                   options.local_forwards[i].listen_port,
+                   options.local_forwards[i].connect_host,
+                   options.local_forwards[i].connect_port);
+               success += channel_setup_local_fwd_listener(
+                   options.local_forwards[i].listen_host,
+                   options.local_forwards[i].listen_port,
+                   options.local_forwards[i].connect_host,
+                   options.local_forwards[i].connect_port,
+                   options.gateway_ports);
+       }
+       if (i > 0 && success != i && options.exit_on_forward_failure)
+               fatal("Could not request local forwarding.");
+       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("Remote connections from %.200s:%d forwarded to "
+                   "local address %.200s:%d",
+                   (options.remote_forwards[i].listen_host == NULL) ?
+                   "LOCALHOST" : options.remote_forwards[i].listen_host,
+                   options.remote_forwards[i].listen_port,
+                   options.remote_forwards[i].connect_host,
+                   options.remote_forwards[i].connect_port);
+               if (channel_request_remote_forwarding(
+                   options.remote_forwards[i].listen_host,
+                   options.remote_forwards[i].listen_port,
+                   options.remote_forwards[i].connect_host,
+                   options.remote_forwards[i].connect_port) < 0) {
+                       if (options.exit_on_forward_failure)
+                               fatal("Could not request remote forwarding.");
+                       else
+                               logit("Warning: Could not request remote "
+                                   "forwarding.");
+               }
+               client_register_global_confirm(ssh_confirm_remote_forward,
+                   &options.remote_forwards[i]);
+       }
+
+       /* Initiate tunnel forwarding. */
+       if (options.tun_open != SSH_TUNMODE_NO) {
+               if (client_request_tun_fwd(options.tun_open,
+                   options.tun_local, options.tun_remote) == -1) {
+                       if (options.exit_on_forward_failure)
+                               fatal("Could not request tunnel forwarding.");
+                       else
+                               error("Could not request tunnel forwarding.");
+               }
+       }                       
+}
+
+static void
+check_agent_present(void)
+{
+       if (options.forward_agent) {
+               /* Clear agent forwarding if we don't have an agent. */
+               if (!ssh_agent_present())
+                       options.forward_agent = 0;
+       }
+}
+
+static int
+ssh_session(void)
+{
+       int type;
+       int interactive = 0;
+       int have_tty = 0;
+       struct winsize ws;
+       char *cp;
+       const char *display;
+
+       /* 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();
+               if (type == SSH_SMSG_SUCCESS)
+                       packet_start_compression(options.compression_level);
+               else if (type == SSH_SMSG_FAILURE)
+                       logit("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((u_int)ws.ws_row);
+               packet_put_int((u_int)ws.ws_col);
+               packet_put_int((u_int)ws.ws_xpixel);
+               packet_put_int((u_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();
+               if (type == SSH_SMSG_SUCCESS) {
+                       interactive = 1;
+                       have_tty = 1;
+               } else if (type == SSH_SMSG_FAILURE)
+                       logit("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. */
+       display = getenv("DISPLAY");
+       if (options.forward_x11 && display != NULL) {
+               char *proto, *data;
+               /* Get reasonable local authentication information. */
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted, 
+                   options.forward_x11_timeout,
+                   &proto, &data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
+               x11_request_forwarding_with_spoofing(0, display, proto, data);
+
+               /* Read response from the server. */
+               type = packet_read();
+               if (type == SSH_SMSG_SUCCESS) {
+                       interactive = 1;
+               } else if (type == SSH_SMSG_FAILURE) {
+                       logit("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,
+           options.ip_qos_interactive, options.ip_qos_bulk);
+
+       /* 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();
+               packet_check_eom();
+               if (type != SSH_SMSG_SUCCESS)
+                       logit("Warning: Remote host denied authentication agent forwarding.");
+       }
+
+       /* Initiate port forwardings. */
+       ssh_init_forwarding();
+
+       /* Execute a local command */
+       if (options.local_command != NULL &&
+           options.permit_local_command)
+               ssh_local_cmd(options.local_command);
+
+       /*
+        * If requested and we are not interested in replies to remote
+        * forwarding requests, then let ssh continue in the background.
+        */
+       if (fork_after_authentication_flag) {
+               if (options.exit_on_forward_failure &&
+                   options.num_remote_forwards > 0) {
+                       debug("deferring postauth fork until remote forward "
+                           "confirmation received");
+               } else
+                       fork_postauth();
+       }
+
+       /*
+        * 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,
+                   (u_char *)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);
+}
+
+/* request pty/x11/agent/tcpfwd/shell for channel */
+static void
+ssh_session2_setup(int id, int success, void *arg)
+{
+       extern char **environ;
+       const char *display;
+       int interactive = tty_flag;
+
+       if (!success)
+               return; /* No need for error message, channels code sens one */
+
+       display = getenv("DISPLAY");
+       if (options.forward_x11 && display != NULL) {
+               char *proto, *data;
+               /* Get reasonable local authentication information. */
+               client_x11_get_proto(display, options.xauth_location,
+                   options.forward_x11_trusted,
+                   options.forward_x11_timeout, &proto, &data);
+               /* Request forwarding with authentication spoofing. */
+               debug("Requesting X11 forwarding with authentication "
+                   "spoofing.");
+               x11_request_forwarding_with_spoofing(id, display, proto, data);
+               interactive = 1;
+               /* XXX wait for reply */
+       }
+
+       check_agent_present();
+       if (options.forward_agent) {
+               debug("Requesting authentication agent forwarding.");
+               channel_request_start(id, "auth-agent-req@openssh.com", 0);
+               packet_send();
+       }
+
+       client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),
+           NULL, fileno(stdin), &command, environ);
+}
+
+/* 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 >>= 1;
+               packetmax >>= 1;
+       }
+       c = channel_new(
+           "session", SSH_CHANNEL_OPENING, in, out, err,
+           window, packetmax, CHAN_EXTENDED_WRITE,
+           "client-session", /*nonblock*/0);
+
+       debug3("ssh_session2_open: channel_new: %d", c->self);
+
+       channel_send_open(c->self);
+       if (!no_shell_flag)
+               channel_register_open_confirm(c->self,
+                   ssh_session2_setup, NULL);
+
+       return c->self;
+}
+
+static int
+ssh_session2(void)
+{
+       int id = -1;
+
+       /* XXX should be pre-session */
+       ssh_init_forwarding();
+
+       /* Start listening for multiplex clients */
+       muxserver_listen();
+
+       /*
+        * If we are in control persist mode, then prepare to background
+        * ourselves and have a foreground client attach as a control
+        * slave. NB. we must save copies of the flags that we override for
+        * the backgrounding, since we defer attachment of the slave until
+        * after the connection is fully established (in particular,
+        * async rfwd replies have been received for ExitOnForwardFailure).
+        */
+       if (options.control_persist && muxserver_sock != -1) {
+               ostdin_null_flag = stdin_null_flag;
+               ono_shell_flag = no_shell_flag;
+               ono_tty_flag = no_tty_flag;
+               otty_flag = tty_flag;
+               stdin_null_flag = 1;
+               no_shell_flag = 1;
+               no_tty_flag = 1;
+               tty_flag = 0;
+               if (!fork_after_authentication_flag)
+                       need_controlpersist_detach = 1;
+               fork_after_authentication_flag = 1;
+       }
+
+       if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))
+               id = ssh_session2_open();
+
+       /* If we don't expect to open a new session, then disallow it */
+       if (options.control_master == SSHCTL_MASTER_NO &&
+           (datafellows & SSH_NEW_OPENSSH)) {
+               debug("Requesting no-more-sessions@openssh.com");
+               packet_start(SSH2_MSG_GLOBAL_REQUEST);
+               packet_put_cstring("no-more-sessions@openssh.com");
+               packet_put_char(0);
+               packet_send();
+       }
+
+       /* Execute a local command */
+       if (options.local_command != NULL &&
+           options.permit_local_command)
+               ssh_local_cmd(options.local_command);
+
+       /*
+        * If requested and we are not interested in replies to remote
+        * forwarding requests, then let ssh continue in the background.
+        */
+       if (fork_after_authentication_flag) {
+               if (options.exit_on_forward_failure &&
+                   options.num_remote_forwards > 0) {
+                       debug("deferring postauth fork until remote forward "
+                           "confirmation received");
+               } else
+                       fork_postauth();
+       }
+
+       if (options.use_roaming)
+               request_roaming();
+
+       return client_loop(tty_flag, tty_flag ?
+           options.escape_char : SSH_ESCAPECHAR_NONE, id);
+}
+
+static void
+load_public_identity_files(void)
+{
+       char *filename, *cp, thishost[NI_MAXHOST];
+       char *pwdir = NULL, *pwname = NULL;
+       int i = 0;
+       Key *public;
+       struct passwd *pw;
+       u_int n_ids;
+       char *identity_files[SSH_MAX_IDENTITY_FILES];
+       Key *identity_keys[SSH_MAX_IDENTITY_FILES];
+#ifdef ENABLE_PKCS11
+       Key **keys;
+       int nkeys;
+#endif /* PKCS11 */
+
+       n_ids = 0;
+       bzero(identity_files, sizeof(identity_files));
+       bzero(identity_keys, sizeof(identity_keys));
+
+#ifdef ENABLE_PKCS11
+       if (options.pkcs11_provider != NULL &&
+           options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
+           (pkcs11_init(!options.batch_mode) == 0) &&
+           (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
+           &keys)) > 0) {
+               for (i = 0; i < nkeys; i++) {
+                       if (n_ids >= SSH_MAX_IDENTITY_FILES) {
+                               key_free(keys[i]);
+                               continue;
+                       }
+                       identity_keys[n_ids] = keys[i];
+                       identity_files[n_ids] =
+                           xstrdup(options.pkcs11_provider); /* XXX */
+                       n_ids++;
+               }
+               xfree(keys);
+       }
+#endif /* ENABLE_PKCS11 */
+       if ((pw = getpwuid(original_real_uid)) == NULL)
+               fatal("load_public_identity_files: getpwuid failed");
+       pwname = xstrdup(pw->pw_name);
+       pwdir = xstrdup(pw->pw_dir);
+       if (gethostname(thishost, sizeof(thishost)) == -1)
+               fatal("load_public_identity_files: gethostname: %s",
+                   strerror(errno));
+       for (i = 0; i < options.num_identity_files; i++) {
+               if (n_ids >= SSH_MAX_IDENTITY_FILES) {
+                       xfree(options.identity_files[i]);
+                       continue;
+               }
+               cp = tilde_expand_filename(options.identity_files[i],
+                   original_real_uid);
+               filename = percent_expand(cp, "d", pwdir,
+                   "u", pwname, "l", thishost, "h", host,
+                   "r", options.user, (char *)NULL);
+               xfree(cp);
+               public = key_load_public(filename, NULL);
+               debug("identity file %s type %d", filename,
+                   public ? public->type : -1);
+               xfree(options.identity_files[i]);
+               identity_files[n_ids] = filename;
+               identity_keys[n_ids] = public;
+
+               if (++n_ids >= SSH_MAX_IDENTITY_FILES)
+                       continue;
+
+               /* Try to add the certificate variant too */
+               xasprintf(&cp, "%s-cert", filename);
+               public = key_load_public(cp, NULL);
+               debug("identity file %s type %d", cp,
+                   public ? public->type : -1);
+               if (public == NULL) {
+                       xfree(cp);
+                       continue;
+               }
+               if (!key_is_cert(public)) {
+                       debug("%s: key %s type %s is not a certificate",
+                           __func__, cp, key_type(public));
+                       key_free(public);
+                       xfree(cp);
+                       continue;
+               }
+               identity_keys[n_ids] = public;
+               /* point to the original path, most likely the private key */
+               identity_files[n_ids] = xstrdup(filename);
+               n_ids++;
+       }
+       options.num_identity_files = n_ids;
+       memcpy(options.identity_files, identity_files, sizeof(identity_files));
+       memcpy(options.identity_keys, identity_keys, sizeof(identity_keys));
+
+       bzero(pwname, strlen(pwname));
+       xfree(pwname);
+       bzero(pwdir, strlen(pwdir));
+       xfree(pwdir);
+}
+
+static void
+main_sigchld_handler(int sig)
+{
+       int save_errno = errno;
+       pid_t pid;
+       int status;
+
+       while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
+           (pid < 0 && errno == EINTR))
+               ;
+
+       signal(sig, main_sigchld_handler);
+       errno = save_errno;
+}
+
diff --git a/ssh.h b/ssh.h
new file mode 100644 (file)
index 0000000..c94633b
--- /dev/null
+++ b/ssh.h
@@ -0,0 +1,99 @@
+/* $OpenBSD: ssh.h,v 1.79 2010/06/25 07:14:46 djm 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".
+ */
+
+/* Cipher used for encrypting authentication files. */
+#define SSH_AUTHFILE_CIPHER    SSH_CIPHER_3DES
+
+/* Default port number. */
+#define SSH_DEFAULT_PORT       22
+
+/*
+ * 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
+
+/*
+ * Maximum length of lines in authorized_keys file.
+ * Current value permits 16kbit RSA and RSA1 keys and 8kbit DSA keys, with
+ * some room for options and comments.
+ */
+#define SSH_MAX_PUBKEY_BYTES           8192
+
+/*
+ * Major protocol version.  Different version indicates major incompatibility
+ * 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"
+
+/*
+ * Name of the environment variable containing the process ID of the
+ * authentication agent.
+ */
+#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
+
+/* Used to identify ``EscapeChar none'' */
+#define SSH_ESCAPECHAR_NONE            -2
+
+/*
+ * unprivileged user when UsePrivilegeSeparation=yes;
+ * sshd will change its privileges to this user and its
+ * primary group.
+ */
+#ifndef SSH_PRIVSEP_USER
+#define SSH_PRIVSEP_USER               "sshd"
+#endif
+
+/* Minimum modulus size (n) for RSA keys. */
+#define SSH_RSA_MINIMUM_MODULUS_SIZE   768
+
+/* Listen backlog for sshd, ssh-agent and forwarding sockets */
+#define SSH_LISTEN_BACKLOG             128
diff --git a/ssh1.h b/ssh1.h
new file mode 100644 (file)
index 0000000..353d930
--- /dev/null
+++ b/ssh1.h
@@ -0,0 +1,92 @@
+/* $OpenBSD: ssh1.h,v 1.6 2006/03/25 22:22:43 djm 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.
+ */
+/* Ranges */
+#define SSH_MSG_MIN                            1
+#define SSH_MSG_MAX                            254
+/* 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/ssh2.h b/ssh2.h
new file mode 100644 (file)
index 0000000..51a963c
--- /dev/null
+++ b/ssh2.h
@@ -0,0 +1,182 @@
+/* $OpenBSD: ssh2.h,v 1.14 2010/08/31 11:54:45 djm 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.
+ */
+
+/*
+ * 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
+ */
+
+/* ranges */
+
+#define SSH2_MSG_TRANSPORT_MIN                         1
+#define SSH2_MSG_TRANSPORT_MAX                         49
+#define SSH2_MSG_USERAUTH_MIN                          50
+#define SSH2_MSG_USERAUTH_MAX                          79
+#define SSH2_MSG_USERAUTH_PER_METHOD_MIN               60
+#define SSH2_MSG_USERAUTH_PER_METHOD_MAX               SSH2_MSG_USERAUTH_MAX
+#define SSH2_MSG_CONNECTION_MIN                                80
+#define SSH2_MSG_CONNECTION_MAX                                127
+#define SSH2_MSG_RESERVED_MIN                          128
+#define SSH2_MSG_RESERVED_MAX                          191
+#define SSH2_MSG_LOCAL_MIN                             192
+#define SSH2_MSG_LOCAL_MAX                             255
+#define SSH2_MSG_MIN                                   1
+#define SSH2_MSG_MAX                                   255
+
+/* 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
+
+/* ecdh */
+#define SSH2_MSG_KEX_ECDH_INIT                         30
+#define SSH2_MSG_KEX_ECDH_REPLY                                31
+
+/* 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
+#define SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1           60
+#define SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1           61
+#define SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2           62
+#define SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2           63
+#define SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM         64
+#define SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM         65
+
+/* 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
+
+/* kex messages for resume@appgate.com */
+#define SSH2_MSG_KEX_ROAMING_RESUME                    30
+#define SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED             31
+#define SSH2_MSG_KEX_ROAMING_AUTH                      32
+#define SSH2_MSG_KEX_ROAMING_AUTH_OK                   33
+#define SSH2_MSG_KEX_ROAMING_AUTH_FAIL                 34
+
+/* Certificate types for OpenSSH certificate keys extension */
+#define SSH2_CERT_TYPE_USER                            1
+#define SSH2_CERT_TYPE_HOST                            2
diff --git a/ssh_config b/ssh_config
new file mode 100644 (file)
index 0000000..1893674
--- /dev/null
@@ -0,0 +1,47 @@
+#      $OpenBSD: ssh_config,v 1.26 2010/01/11 01:39:46 dtucker Exp $
+
+# This is the ssh client system-wide configuration file.  See
+# ssh_config(5) 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 some commonly used options.  For a comprehensive
+# list of available options, their meanings and defaults, please see the
+# ssh_config(5) man page.
+
+# Host *
+#   ForwardAgent no
+#   ForwardX11 no
+#   RhostsRSAAuthentication no
+#   RSAAuthentication yes
+#   PasswordAuthentication yes
+#   HostbasedAuthentication no
+#   GSSAPIAuthentication no
+#   GSSAPIDelegateCredentials no
+#   BatchMode no
+#   CheckHostIP yes
+#   AddressFamily any
+#   ConnectTimeout 0
+#   StrictHostKeyChecking ask
+#   IdentityFile ~/.ssh/identity
+#   IdentityFile ~/.ssh/id_rsa
+#   IdentityFile ~/.ssh/id_dsa
+#   Port 22
+#   Protocol 2,1
+#   Cipher 3des
+#   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc
+#   MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
+#   EscapeChar ~
+#   Tunnel no
+#   TunnelDevice any:any
+#   PermitLocalCommand no
+#   VisualHostKey no
+#   ProxyCommand ssh -q -W %h:%p gateway.example.com
diff --git a/ssh_config.0 b/ssh_config.0
new file mode 100644 (file)
index 0000000..c4a12f7
--- /dev/null
@@ -0,0 +1,744 @@
+SSH_CONFIG(5)             OpenBSD Programmer's Manual            SSH_CONFIG(5)
+
+NAME
+     ssh_config - OpenSSH SSH client configuration files
+
+SYNOPSIS
+     ~/.ssh/config
+     /etc/ssh/ssh_config
+
+DESCRIPTION
+     ssh(1) obtains configuration data from the following sources in the
+     following order:
+
+           1.   command-line options
+           2.   user's configuration file (~/.ssh/config)
+           3.   system-wide configuration file (/etc/ssh/ssh_config)
+
+     For each parameter, the first obtained value will be used.  The
+     configuration files contain sections separated by ``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.
+
+     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.
+
+     The configuration file has the following format:
+
+     Empty lines and lines starting with `#' are comments.  Otherwise a line
+     is of the format ``keyword arguments''.  Configuration options may be
+     separated by whitespace or optional whitespace and exactly one `='; the
+     latter format is useful to avoid the need to quote whitespace when
+     specifying configuration options using the ssh, scp, and sftp -o option.
+     Arguments may optionally be enclosed in double quotes (") in order to
+     represent arguments containing spaces.
+
+     The possible keywords and their meanings are as follows (note that
+     keywords are case-insensitive and arguments are case-sensitive):
+
+     Host    Restricts the following declarations (up to the next Host
+             keyword) to be only for those hosts that match one of the
+             patterns given after the keyword.  If more than one pattern is
+             provided, they should be separated by whitespace.  A single `*'
+             as a pattern can be used to provide global defaults for all
+             hosts.  The host is the hostname argument given on the command
+             line (i.e. the name is not converted to a canonicalized host name
+             before matching).
+
+             See PATTERNS for more information on patterns.
+
+     AddressFamily
+             Specifies which address family to use when connecting.  Valid
+             arguments are ``any'', ``inet'' (use IPv4 only), or ``inet6''
+             (use IPv6 only).
+
+     BatchMode
+             If set to ``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
+             ``yes'' or ``no''.  The default is ``no''.
+
+     BindAddress
+             Use the specified address on the local machine as the source
+             address of the connection.  Only useful on systems with more than
+             one address.  Note that this option does not work if
+             UsePrivilegedPort is set to ``yes''.
+
+     ChallengeResponseAuthentication
+             Specifies whether to use challenge-response authentication.  The
+             argument to this keyword must be ``yes'' or ``no''.  The default
+             is ``yes''.
+
+     CheckHostIP
+             If this flag is set to ``yes'', ssh(1) will additionally check
+             the host IP address in the known_hosts file.  This allows ssh to
+             detect if a host key changed due to DNS spoofing.  If the option
+             is set to ``no'', the check will not be executed.  The default is
+             ``yes''.
+
+     Cipher  Specifies the cipher to use for encrypting the session in
+             protocol version 1.  Currently, ``blowfish'', ``3des'', and
+             ``des'' are supported.  des is only supported in the ssh(1)
+             client for interoperability with legacy protocol 1
+             implementations that do not support the 3des cipher.  Its use is
+             strongly discouraged due to cryptographic weaknesses.  The
+             default is ``3des''.
+
+     Ciphers
+             Specifies the ciphers allowed for protocol version 2 in order of
+             preference.  Multiple ciphers must be comma-separated.  The
+             supported ciphers are ``3des-cbc'', ``aes128-cbc'',
+             ``aes192-cbc'', ``aes256-cbc'', ``aes128-ctr'', ``aes192-ctr'',
+             ``aes256-ctr'', ``arcfour128'', ``arcfour256'', ``arcfour'',
+             ``blowfish-cbc'', and ``cast128-cbc''.  The default is:
+
+                aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
+                aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
+                aes256-cbc,arcfour
+
+     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
+             ssh(1) command line to clear port forwardings set in
+             configuration files, and is automatically set by scp(1) and
+             sftp(1).  The argument must be ``yes'' or ``no''.  The default is
+             ``no''.
+
+     Compression
+             Specifies whether to use compression.  The argument must be
+             ``yes'' or ``no''.  The default is ``no''.
+
+     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 gzip(1).  Note that this
+             option applies to protocol version 1 only.
+
+     ConnectionAttempts
+             Specifies the number of tries (one per second) to make before
+             exiting.  The argument must be an integer.  This may be useful in
+             scripts if the connection sometimes fails.  The default is 1.
+
+     ConnectTimeout
+             Specifies the timeout (in seconds) used when connecting to the
+             SSH server, instead of using the default system TCP timeout.
+             This value is used only when the target is down or really
+             unreachable, not when it refuses the connection.
+
+     ControlMaster
+             Enables the sharing of multiple sessions over a single network
+             connection.  When set to ``yes'', ssh(1) will listen for
+             connections on a control socket specified using the ControlPath
+             argument.  Additional sessions can connect to this socket using
+             the same ControlPath with ControlMaster set to ``no'' (the
+             default).  These sessions will try to reuse the master instance's
+             network connection rather than initiating new ones, but will fall
+             back to connecting normally if the control socket does not exist,
+             or is not listening.
+
+             Setting this to ``ask'' will cause ssh to listen for control
+             connections, but require confirmation using the SSH_ASKPASS
+             program before they are accepted (see ssh-add(1) for details).
+             If the ControlPath cannot be opened, ssh will continue without
+             connecting to a master instance.
+
+             X11 and ssh-agent(1) forwarding is supported over these
+             multiplexed connections, however the display and agent forwarded
+             will be the one belonging to the master connection i.e. it is not
+             possible to forward multiple displays or agents.
+
+             Two additional options allow for opportunistic multiplexing: try
+             to use a master connection but fall back to creating a new one if
+             one does not already exist.  These options are: ``auto'' and
+             ``autoask''.  The latter requires confirmation like the ``ask''
+             option.
+
+     ControlPath
+             Specify the path to the control socket used for connection
+             sharing as described in the ControlMaster section above or the
+             string ``none'' to disable connection sharing.  In the path, `%l'
+             will be substituted by the local host name, `%h' will be
+             substituted by the target host name, `%p' the port, and `%r' by
+             the remote login username.  It is recommended that any
+             ControlPath used for opportunistic connection sharing include at
+             least %h, %p, and %r.  This ensures that shared connections are
+             uniquely identified.
+
+     ControlPersist
+             When used in conjunction with ControlMaster, specifies that the
+             master connection should remain open in the background (waiting
+             for future client connections) after the initial client
+             connection has been closed.  If set to ``no'', then the master
+             connection will not be placed into the background, and will close
+             as soon as the initial client connection is closed.  If set to
+             ``yes'', then the master connection will remain in the background
+             indefinitely (until killed or closed via a mechanism such as the
+             ssh(1) ``-O exit'' option).  If set to a time in seconds, or a
+             time in any of the formats documented in sshd_config(5), then the
+             backgrounded master connection will automatically terminate after
+             it has remained idle (with no client connections) for the
+             specified time.
+
+     DynamicForward
+             Specifies that a TCP 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 [bind_address:]port.  IPv6 addresses can be
+             specified by enclosing addresses in square brackets.  By default,
+             the local port is bound in accordance with the GatewayPorts
+             setting.  However, an explicit bind_address may be used to bind
+             the connection to a specific address.  The bind_address of
+             ``localhost'' indicates that the listening port be bound for
+             local use only, while an empty address or `*' indicates that the
+             port should be available from all interfaces.
+
+             Currently the SOCKS4 and SOCKS5 protocols are supported, and
+             ssh(1) will act as a SOCKS server.  Multiple forwardings may be
+             specified, and additional forwardings can be given on the command
+             line.  Only the superuser can forward privileged ports.
+
+     EnableSSHKeysign
+             Setting this option to ``yes'' in the global client configuration
+             file /etc/ssh/ssh_config enables the use of the helper program
+             ssh-keysign(8) during HostbasedAuthentication.  The argument must
+             be ``yes'' or ``no''.  The default is ``no''.  This option should
+             be placed in the non-hostspecific section.  See ssh-keysign(8)
+             for more information.
+
+     EscapeChar
+             Sets the escape character (default: `~').  The escape character
+             can also be set on the command line.  The argument should be a
+             single character, `^' followed by a letter, or ``none'' to
+             disable the escape character entirely (making the connection
+             transparent for binary data).
+
+     ExitOnForwardFailure
+             Specifies whether ssh(1) should terminate the connection if it
+             cannot set up all requested dynamic, tunnel, local, and remote
+             port forwardings.  The argument must be ``yes'' or ``no''.  The
+             default is ``no''.
+
+     ForwardAgent
+             Specifies whether the connection to the authentication agent (if
+             any) will be forwarded to the remote machine.  The argument must
+             be ``yes'' or ``no''.  The default is ``no''.
+
+             Agent forwarding should be enabled with caution.  Users with the
+             ability to bypass file permissions on the remote host (for the
+             agent's Unix-domain socket) can access the local agent through
+             the forwarded connection.  An attacker cannot obtain key material
+             from the agent, however they can perform operations on the keys
+             that enable them to authenticate using the identities loaded into
+             the agent.
+
+     ForwardX11
+             Specifies whether X11 connections will be automatically
+             redirected over the secure channel and DISPLAY set.  The argument
+             must be ``yes'' or ``no''.  The default is ``no''.
+
+             X11 forwarding should be enabled with caution.  Users with the
+             ability to bypass file permissions on the remote host (for the
+             user's X11 authorization database) can access the local X11
+             display through the forwarded connection.  An attacker may then
+             be able to perform activities such as keystroke monitoring if the
+             ForwardX11Trusted option is also enabled.
+
+     ForwardX11Timeout
+             Specify a timeout for untrusted X11 forwarding using the format
+             described in the TIME FORMATS section of sshd_config(5).  X11
+             connections received by ssh(1) after this time will be refused.
+             The default is to disable untrusted X11 forwarding after twenty
+             minutes has elapsed.
+
+     ForwardX11Trusted
+             If this option is set to ``yes'', remote X11 clients will have
+             full access to the original X11 display.
+
+             If this option is set to ``no'', remote X11 clients will be
+             considered untrusted and prevented from stealing or tampering
+             with data belonging to trusted X11 clients.  Furthermore, the
+             xauth(1) token used for the session will be set to expire after
+             20 minutes.  Remote clients will be refused access after this
+             time.
+
+             The default is ``no''.
+
+             See the X11 SECURITY extension specification for full details on
+             the restrictions imposed on untrusted clients.
+
+     GatewayPorts
+             Specifies whether remote hosts are allowed to connect to local
+             forwarded ports.  By default, ssh(1) binds local port forwardings
+             to the loopback address.  This prevents other remote hosts from
+             connecting to forwarded ports.  GatewayPorts can be used to
+             specify that ssh should bind local port forwardings to the
+             wildcard address, thus allowing remote hosts to connect to
+             forwarded ports.  The argument must be ``yes'' or ``no''.  The
+             default is ``no''.
+
+     GlobalKnownHostsFile
+             Specifies a file to use for the global host key database instead
+             of /etc/ssh/ssh_known_hosts.
+
+     GSSAPIAuthentication
+             Specifies whether user authentication based on GSSAPI is allowed.
+             The default is ``no''.  Note that this option applies to protocol
+             version 2 only.
+
+     GSSAPIDelegateCredentials
+             Forward (delegate) credentials to the server.  The default is
+             ``no''.  Note that this option applies to protocol version 2
+             only.
+
+     HashKnownHosts
+             Indicates that ssh(1) should hash host names and addresses when
+             they are added to ~/.ssh/known_hosts.  These hashed names may be
+             used normally by ssh(1) and sshd(8), but they do not reveal
+             identifying information should the file's contents be disclosed.
+             The default is ``no''.  Note that existing names and addresses in
+             known hosts files will not be converted automatically, but may be
+             manually hashed using ssh-keygen(1).
+
+     HostbasedAuthentication
+             Specifies whether to try rhosts based authentication with public
+             key authentication.  The argument must be ``yes'' or ``no''.  The
+             default is ``no''.  This option applies to protocol version 2
+             only and is similar to RhostsRSAAuthentication.
+
+     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:
+
+                ecdsa-sha2-nistp256-cert-v01@openssh.com,
+                ecdsa-sha2-nistp384-cert-v01@openssh.com,
+                ecdsa-sha2-nistp521-cert-v01@openssh.com,
+                ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,
+                ssh-rsa-cert-v00@openssh.com,ssh-dss-cert-v00@openssh.com,
+                ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+                ssh-rsa,ssh-dss
+
+             If hostkeys are known for the destination host then this default
+             is modified to prefer their algorithms.
+
+     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.
+
+     HostName
+             Specifies the real host name to log into.  This can be used to
+             specify nicknames or abbreviations for hosts.  If the hostname
+             contains the character sequence `%h', then this will be replaced
+             with the host name specified on the commandline (this is useful
+             for manipulating unqualified names).  The default is the name
+             given on the command line.  Numeric IP addresses are also
+             permitted (both on the command line and in HostName
+             specifications).
+
+     IdentitiesOnly
+             Specifies that ssh(1) should only use the authentication identity
+             files configured in the ssh_config files, even if ssh-agent(1)
+             offers more identities.  The argument to this keyword must be
+             ``yes'' or ``no''.  This option is intended for situations where
+             ssh-agent offers many different identities.  The default is
+             ``no''.
+
+     IdentityFile
+             Specifies a file from which the user's DSA, ECDSA or DSA
+             authentication identity is read.  The default is ~/.ssh/identity
+             for protocol version 1, and ~/.ssh/id_dsa, ~/.ssh/id_ecdsa and
+             ~/.ssh/id_rsa for protocol version 2.  Additionally, any
+             identities represented by the authentication agent will be used
+             for authentication.  ssh(1) will try to load certificate
+             information from the filename obtained by appending -cert.pub to
+             the path of a specified IdentityFile.
+
+             The file name may use the tilde syntax to refer to a user's home
+             directory or one of the following escape characters: `%d' (local
+             user's home directory), `%u' (local user name), `%l' (local host
+             name), `%h' (remote host name) or `%r' (remote user name).
+
+             It is possible to have multiple identity files specified in
+             configuration files; all these identities will be tried in
+             sequence.
+
+     IPQoS   Specifies the IPv4 type-of-service or DSCP class for connections.
+             Accepted values are ``af11'', ``af12'', ``af13'', ``af14'',
+             ``af22'', ``af23'', ``af31'', ``af32'', ``af33'', ``af41'',
+             ``af42'', ``af43'', ``cs0'', ``cs1'', ``cs2'', ``cs3'', ``cs4'',
+             ``cs5'', ``cs6'', ``cs7'', ``ef'', ``lowdelay'', ``throughput'',
+             ``reliability'', or a numeric value.  This option may take one or
+             two arguments, separated by whitespace.  If one argument is
+             specified, it is used as the packet class unconditionally.  If
+             two values are specified, the first is automatically selected for
+             interactive sessions and the second for non-interactive sessions.
+             The default is ``lowdelay'' for interactive sessions and
+             ``throughput'' for non-interactive sessions.
+
+     KbdInteractiveAuthentication
+             Specifies whether to use keyboard-interactive authentication.
+             The argument to this keyword must be ``yes'' or ``no''.  The
+             default is ``yes''.
+
+     KbdInteractiveDevices
+             Specifies the list of methods to use in keyboard-interactive
+             authentication.  Multiple method names must be comma-separated.
+             The default is to use the server specified list.  The methods
+             available vary depending on what the server supports.  For an
+             OpenSSH server, it may be zero or more of: ``bsdauth'', ``pam'',
+             and ``skey''.
+
+     KexAlgorithms
+             Specifies the available KEX (Key Exchange) algorithms.  Multiple
+             algorithms must be comma-separated.  The default is:
+
+                   ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
+                   diffie-hellman-group-exchange-sha256,
+                   diffie-hellman-group-exchange-sha1,
+                   diffie-hellman-group14-sha1,
+                   diffie-hellman-group1-sha1
+
+     LocalCommand
+             Specifies a command to execute on the local machine after
+             successfully connecting to the server.  The command string
+             extends to the end of the line, and is executed with the user's
+             shell.  The following escape character substitutions will be
+             performed: `%d' (local user's home directory), `%h' (remote host
+             name), `%l' (local host name), `%n' (host name as provided on the
+             command line), `%p' (remote port), `%r' (remote user name) or
+             `%u' (local user name).
+
+             The command is run synchronously and does not have access to the
+             session of the ssh(1) that spawned it.  It should not be used for
+             interactive commands.
+
+             This directive is ignored unless PermitLocalCommand has been
+             enabled.
+
+     LocalForward
+             Specifies that a TCP 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 [bind_address:]port and the
+             second argument must be host:hostport.  IPv6 addresses can be
+             specified by enclosing addresses in square brackets.  Multiple
+             forwardings may be specified, and additional forwardings can be
+             given on the command line.  Only the superuser can forward
+             privileged ports.  By default, the local port is bound in
+             accordance with the GatewayPorts setting.  However, an explicit
+             bind_address may be used to bind the connection to a specific
+             address.  The bind_address of ``localhost'' indicates that the
+             listening port be bound for local use only, while an empty
+             address or `*' indicates that the port should be available from
+             all interfaces.
+
+     LogLevel
+             Gives the verbosity level that is used when logging messages from
+             ssh(1).  The possible values are: QUIET, FATAL, ERROR, INFO,
+             VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.  The default is INFO.
+             DEBUG and DEBUG1 are equivalent.  DEBUG2 and DEBUG3 each specify
+             higher levels of verbose output.
+
+     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:
+
+                   hmac-md5,hmac-sha1,umac-64@openssh.com,
+                   hmac-ripemd160,hmac-sha1-96,hmac-md5-96
+
+     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 ``yes'' or ``no''.  The default is to check the host key
+             for localhost.
+
+     NumberOfPasswordPrompts
+             Specifies the number of password prompts before giving up.  The
+             argument to this keyword must be an integer.  The default is 3.
+
+     PasswordAuthentication
+             Specifies whether to use password authentication.  The argument
+             to this keyword must be ``yes'' or ``no''.  The default is
+             ``yes''.
+
+     PermitLocalCommand
+             Allow local command execution via the LocalCommand option or
+             using the !command escape sequence in ssh(1).  The argument must
+             be ``yes'' or ``no''.  The default is ``no''.
+
+     PKCS11Provider
+             Specifies which PKCS#11 provider to use.  The argument to this
+             keyword is the PKCS#11 shared library ssh(1) should use to
+             communicate with a PKCS#11 token providing the user's private RSA
+             key.
+
+     Port    Specifies the port number to connect on the remote host.  The
+             default is 22.
+
+     PreferredAuthentications
+             Specifies the order in which the client should try protocol 2
+             authentication methods.  This allows a client to prefer one
+             method (e.g. keyboard-interactive) over another method (e.g.
+             password).  The default is:
+
+                   gssapi-with-mic,hostbased,publickey,
+                   keyboard-interactive,password
+
+     Protocol
+             Specifies the protocol versions ssh(1) should support in order of
+             preference.  The possible values are `1' and `2'.  Multiple
+             versions must be comma-separated.  When this option is set to
+             ``2,1'' ssh will try version 2 and fall back to version 1 if
+             version 2 is not available.  The default is `2'.
+
+     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 the user's shell.  In the command string, any occurrence of
+             `%h' will be substituted by the host name to connect, `%p' by the
+             port, and `%r' by the remote user name.  The command can be
+             basically anything, and should read from its standard input and
+             write to its standard output.  It should eventually connect an
+             sshd(8) server running on some machine, or execute 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).  Setting the command to ``none'' disables this option
+             entirely.  Note that CheckHostIP is not available for connects
+             with a proxy command.
+
+             This directive is useful in conjunction with nc(1) and its proxy
+             support.  For example, the following directive would connect via
+             an HTTP proxy at 192.0.2.0:
+
+                ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
+
+     PubkeyAuthentication
+             Specifies whether to try public key authentication.  The argument
+             to this keyword must be ``yes'' or ``no''.  The default is
+             ``yes''.  This option applies to protocol version 2 only.
+
+     RekeyLimit
+             Specifies the maximum amount of data that may be transmitted
+             before the session key is renegotiated.  The argument is the
+             number of bytes, with an optional suffix of `K', `M', or `G' to
+             indicate Kilobytes, Megabytes, or Gigabytes, respectively.  The
+             default is between `1G' and `4G', depending on the cipher.  This
+             option applies to protocol version 2 only.
+
+     RemoteForward
+             Specifies that a TCP 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 [bind_address:]port and the
+             second argument must be host:hostport.  IPv6 addresses can be
+             specified by enclosing addresses in square brackets.  Multiple
+             forwardings may be specified, and additional forwardings can be
+             given on the command line.  Privileged ports can be forwarded
+             only when logging in as root on the remote machine.
+
+             If the port argument is `0', the listen port will be dynamically
+             allocated on the server and reported to the client at run time.
+
+             If the bind_address is not specified, the default is to only bind
+             to loopback addresses.  If the bind_address is `*' or an empty
+             string, then the forwarding is requested to listen on all
+             interfaces.  Specifying a remote bind_address will only succeed
+             if the server's GatewayPorts option is enabled (see
+             sshd_config(5)).
+
+     RhostsRSAAuthentication
+             Specifies whether to try rhosts based authentication with RSA
+             host authentication.  The argument must be ``yes'' or ``no''.
+             The default is ``no''.  This option applies to protocol version 1
+             only and requires ssh(1) to be setuid root.
+
+     RSAAuthentication
+             Specifies whether to try RSA authentication.  The argument to
+             this keyword must be ``yes'' or ``no''.  RSA authentication will
+             only be attempted if the identity file exists, or an
+             authentication agent is running.  The default is ``yes''.  Note
+             that this option applies to protocol version 1 only.
+
+     SendEnv
+             Specifies what variables from the local environ(7) should be sent
+             to the server.  Note that environment passing is only supported
+             for protocol 2.  The server must also support it, and the server
+             must be configured to accept these environment variables.  Refer
+             to AcceptEnv in sshd_config(5) for how to configure the server.
+             Variables are specified by name, which may contain wildcard
+             characters.  Multiple environment variables may be separated by
+             whitespace or spread across multiple SendEnv directives.  The
+             default is not to send any environment variables.
+
+             See PATTERNS for more information on patterns.
+
+     ServerAliveCountMax
+             Sets the number of server alive messages (see below) which may be
+             sent without ssh(1) receiving any messages back from the server.
+             If this threshold is reached while server alive messages are
+             being sent, ssh will disconnect from the server, terminating the
+             session.  It is important to note that the use of server alive
+             messages is very different from TCPKeepAlive (below).  The server
+             alive messages are sent through the encrypted channel and
+             therefore will not be spoofable.  The TCP keepalive option
+             enabled by TCPKeepAlive is spoofable.  The server alive mechanism
+             is valuable when the client or server depend on knowing when a
+             connection has become inactive.
+
+             The default value is 3.  If, for example, ServerAliveInterval
+             (see below) is set to 15 and ServerAliveCountMax is left at the
+             default, if the server becomes unresponsive, ssh will disconnect
+             after approximately 45 seconds.  This option applies to protocol
+             version 2 only.
+
+     ServerAliveInterval
+             Sets a timeout interval in seconds after which if no data has
+             been received from the server, ssh(1) will send a message through
+             the encrypted channel to request a response from the server.  The
+             default is 0, indicating that these messages will not be sent to
+             the server.  This option applies to protocol version 2 only.
+
+     StrictHostKeyChecking
+             If this flag is set to ``yes'', ssh(1) will never automatically
+             add host keys to the ~/.ssh/known_hosts file, and refuses to
+             connect to hosts whose host key has changed.  This provides
+             maximum protection against trojan horse attacks, though it can be
+             annoying when the /etc/ssh/ssh_known_hosts file is poorly
+             maintained or when connections to new hosts are frequently made.
+             This option forces the user to manually add all new hosts.  If
+             this flag is set to ``no'', ssh will automatically add new host
+             keys to the user known hosts files.  If this flag is set to
+             ``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 ssh 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 ``yes'',
+             ``no'', or ``ask''.  The default is ``ask''.
+
+     TCPKeepAlive
+             Specifies whether the system should send TCP 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.
+
+             The default is ``yes'' (to send TCP keepalive messages), 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.
+
+             To disable TCP keepalive messages, the value should be set to
+             ``no''.
+
+     Tunnel  Request tun(4) device forwarding between the client and the
+             server.  The argument must be ``yes'', ``point-to-point'' (layer
+             3), ``ethernet'' (layer 2), or ``no''.  Specifying ``yes''
+             requests the default tunnel mode, which is ``point-to-point''.
+             The default is ``no''.
+
+     TunnelDevice
+             Specifies the tun(4) devices to open on the client (local_tun)
+             and the server (remote_tun).
+
+             The argument must be local_tun[:remote_tun].  The devices may be
+             specified by numerical ID or the keyword ``any'', which uses the
+             next available tunnel device.  If remote_tun is not specified, it
+             defaults to ``any''.  The default is ``any:any''.
+
+     UsePrivilegedPort
+             Specifies whether to use a privileged port for outgoing
+             connections.  The argument must be ``yes'' or ``no''.  The
+             default is ``no''.  If set to ``yes'', ssh(1) must be setuid
+             root.  Note that this option must be set to ``yes'' for
+             RhostsRSAAuthentication with older servers.
+
+     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.
+
+     UserKnownHostsFile
+             Specifies a file to use for the user host key database instead of
+             ~/.ssh/known_hosts.
+
+     VerifyHostKeyDNS
+             Specifies whether to verify the remote key using DNS and SSHFP
+             resource records.  If this option is set to ``yes'', the client
+             will implicitly trust keys that match a secure fingerprint from
+             DNS.  Insecure fingerprints will be handled as if this option was
+             set to ``ask''.  If this option is set to ``ask'', information on
+             fingerprint match will be displayed, but the user will still need
+             to confirm new host keys according to the StrictHostKeyChecking
+             option.  The argument must be ``yes'', ``no'', or ``ask''.  The
+             default is ``no''.  Note that this option applies to protocol
+             version 2 only.
+
+             See also VERIFYING HOST KEYS in ssh(1).
+
+     VisualHostKey
+             If this flag is set to ``yes'', an ASCII art representation of
+             the remote host key fingerprint is printed in addition to the hex
+             fingerprint string at login and for unknown host keys.  If this
+             flag is set to ``no'', no fingerprint strings are printed at
+             login and only the hex fingerprint string will be printed for
+             unknown host keys.  The default is ``no''.
+
+     XAuthLocation
+             Specifies the full pathname of the xauth(1) program.  The default
+             is /usr/X11R6/bin/xauth.
+
+PATTERNS
+     A pattern consists of zero or more non-whitespace characters, `*' (a
+     wildcard that matches zero or more characters), or `?' (a wildcard that
+     matches exactly one character).  For example, to specify a set of
+     declarations for any host in the ``.co.uk'' set of domains, the following
+     pattern could be used:
+
+           Host *.co.uk
+
+     The following pattern would match any host in the 192.168.0.[0-9] network
+     range:
+
+           Host 192.168.0.?
+
+     A pattern-list is a comma-separated list of patterns.  Patterns within
+     pattern-lists may be negated by preceding them with an exclamation mark
+     (`!').  For example, to allow a key to be used from anywhere within an
+     organisation except from the ``dialup'' pool, the following entry (in
+     authorized_keys) could be used:
+
+           from="!*.dialup.example.com,*.example.com"
+
+FILES
+     ~/.ssh/config
+             This is the per-user configuration file.  The format of this file
+             is described above.  This file is used by the SSH client.
+             Because of the potential for abuse, this file must have strict
+             permissions: read/write for the user, and not accessible by
+             others.
+
+     /etc/ssh/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.
+
+SEE ALSO
+     ssh(1)
+
+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.
+
+OpenBSD 4.9                    December 8, 2010                    OpenBSD 4.9
diff --git a/ssh_config.5 b/ssh_config.5
new file mode 100644 (file)
index 0000000..50bcae8
--- /dev/null
@@ -0,0 +1,1250 @@
+.\"
+.\" 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_config.5,v 1.146 2010/12/08 04:02:47 djm Exp $
+.Dd $Mdocdate: December 8 2010 $
+.Dt SSH_CONFIG 5
+.Os
+.Sh NAME
+.Nm ssh_config
+.Nd OpenSSH SSH client configuration files
+.Sh SYNOPSIS
+.Nm ~/.ssh/config
+.Nm /etc/ssh/ssh_config
+.Sh DESCRIPTION
+.Xr ssh 1
+obtains configuration data from the following sources in
+the following order:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+command-line options
+.It
+user's configuration file
+.Pq Pa ~/.ssh/config
+.It
+system-wide configuration file
+.Pq Pa /etc/ssh/ssh_config
+.El
+.Pp
+For each parameter, the first obtained value
+will be used.
+The configuration files contain sections separated 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.
+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.
+Arguments may optionally be enclosed in double quotes
+.Pq \&"
+in order to represent arguments containing spaces.
+.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.
+If more than one pattern is provided, they should be separated by whitespace.
+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).
+.Pp
+See
+.Sx PATTERNS
+for more information on patterns.
+.It Cm AddressFamily
+Specifies which address family to use when connecting.
+Valid arguments are
+.Dq any ,
+.Dq inet
+(use IPv4 only), or
+.Dq inet6
+(use IPv6 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
+Use the specified address on the local machine as the source address of
+the connection.
+Only useful on systems with more than one address.
+Note that this option does not work if
+.Cm UsePrivilegedPort
+is set to
+.Dq yes .
+.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 CheckHostIP
+If this flag is set to
+.Dq yes ,
+.Xr ssh 1
+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
+.Xr ssh 1
+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 supported ciphers are
+.Dq 3des-cbc ,
+.Dq aes128-cbc ,
+.Dq aes192-cbc ,
+.Dq aes256-cbc ,
+.Dq aes128-ctr ,
+.Dq aes192-ctr ,
+.Dq aes256-ctr ,
+.Dq arcfour128 ,
+.Dq arcfour256 ,
+.Dq arcfour ,
+.Dq blowfish-cbc ,
+and
+.Dq cast128-cbc .
+The default is:
+.Bd -literal -offset 3n
+aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
+aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
+aes256-cbc,arcfour
+.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
+.Xr ssh 1
+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 exiting.
+The argument must be an integer.
+This may be useful in scripts if the connection sometimes fails.
+The default is 1.
+.It Cm ConnectTimeout
+Specifies the timeout (in seconds) used when connecting to the
+SSH server, instead of using the default system TCP timeout.
+This value is used only when the target is down or really unreachable,
+not when it refuses the connection.
+.It Cm ControlMaster
+Enables the sharing of multiple sessions over a single network connection.
+When set to
+.Dq yes ,
+.Xr ssh 1
+will listen for connections on a control socket specified using the
+.Cm ControlPath
+argument.
+Additional sessions can connect to this socket using the same
+.Cm ControlPath
+with
+.Cm ControlMaster
+set to
+.Dq no
+(the default).
+These sessions will try to reuse the master instance's network connection
+rather than initiating new ones, but will fall back to connecting normally
+if the control socket does not exist, or is not listening.
+.Pp
+Setting this to
+.Dq ask
+will cause ssh
+to listen for control connections, but require confirmation using the
+.Ev SSH_ASKPASS
+program before they are accepted (see
+.Xr ssh-add 1
+for details).
+If the
+.Cm ControlPath
+cannot be opened,
+ssh will continue without connecting to a master instance.
+.Pp
+X11 and
+.Xr ssh-agent 1
+forwarding is supported over these multiplexed connections, however the
+display and agent forwarded will be the one belonging to the master
+connection i.e. it is not possible to forward multiple displays or agents.
+.Pp
+Two additional options allow for opportunistic multiplexing: try to use a
+master connection but fall back to creating a new one if one does not already
+exist.
+These options are:
+.Dq auto
+and
+.Dq autoask .
+The latter requires confirmation like the
+.Dq ask
+option.
+.It Cm ControlPath
+Specify the path to the control socket used for connection sharing as described
+in the
+.Cm ControlMaster
+section above or the string
+.Dq none
+to disable connection sharing.
+In the path,
+.Ql %l
+will be substituted by the local host name,
+.Ql %h
+will be substituted by the target host name,
+.Ql %p
+the port, and
+.Ql %r
+by the remote login username.
+It is recommended that any
+.Cm ControlPath
+used for opportunistic connection sharing include
+at least %h, %p, and %r.
+This ensures that shared connections are uniquely identified.
+.It Cm ControlPersist
+When used in conjunction with
+.Cm ControlMaster ,
+specifies that the master connection should remain open
+in the background (waiting for future client connections)
+after the initial client connection has been closed.
+If set to
+.Dq no ,
+then the master connection will not be placed into the background,
+and will close as soon as the initial client connection is closed.
+If set to
+.Dq yes ,
+then the master connection will remain in the background indefinitely
+(until killed or closed via a mechanism such as the
+.Xr ssh 1
+.Dq Fl O No exit
+option).
+If set to a time in seconds, or a time in any of the formats documented in
+.Xr sshd_config 5 ,
+then the backgrounded master connection will automatically terminate
+after it has remained idle (with no client connections) for the
+specified time.
+.It Cm DynamicForward
+Specifies that a TCP 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.
+.Pp
+The argument must be
+.Sm off
+.Oo Ar bind_address : Oc Ar port .
+.Sm on
+IPv6 addresses can be specified by enclosing addresses in square brackets.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Sq *
+indicates that the port should be available from all interfaces.
+.Pp
+Currently the SOCKS4 and SOCKS5 protocols are supported, and
+.Xr ssh 1
+will act as a SOCKS 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 EnableSSHKeysign
+Setting this option to
+.Dq yes
+in the global client configuration file
+.Pa /etc/ssh/ssh_config
+enables the use of the helper program
+.Xr ssh-keysign 8
+during
+.Cm HostbasedAuthentication .
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+This option should be placed in the non-hostspecific section.
+See
+.Xr ssh-keysign 8
+for more information.
+.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 ExitOnForwardFailure
+Specifies whether
+.Xr ssh 1
+should terminate the connection if it cannot set up all requested
+dynamic, tunnel, local, and remote port forwardings.
+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 .
+.Pp
+Agent forwarding should be enabled with caution.
+Users with the ability to bypass file permissions on the remote host
+(for the agent's Unix-domain socket)
+can access the local agent through the forwarded connection.
+An attacker cannot obtain key material from the agent,
+however they can perform operations on the keys that enable them to
+authenticate using the identities loaded into the agent.
+.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 .
+.Pp
+X11 forwarding should be enabled with caution.
+Users with the ability to bypass file permissions on the remote host
+(for the user's X11 authorization database)
+can access the local X11 display through the forwarded connection.
+An attacker may then be able to perform activities such as keystroke monitoring
+if the
+.Cm ForwardX11Trusted
+option is also enabled.
+.It Cm ForwardX11Timeout
+Specify a timeout for untrusted X11 forwarding
+using the format described in the
+.Sx TIME FORMATS
+section of
+.Xr sshd_config 5 .
+X11 connections received by
+.Xr ssh 1
+after this time will be refused.
+The default is to disable untrusted X11 forwarding after twenty minutes has
+elapsed.
+.It Cm ForwardX11Trusted
+If this option is set to
+.Dq yes ,
+remote X11 clients will have full access to the original X11 display.
+.Pp
+If this option is set to
+.Dq no ,
+remote X11 clients will be considered untrusted and prevented
+from stealing or tampering with data belonging to trusted X11
+clients.
+Furthermore, the
+.Xr xauth 1
+token used for the session will be set to expire after 20 minutes.
+Remote clients will be refused access after this time.
+.Pp
+The default is
+.Dq no .
+.Pp
+See the X11 SECURITY extension specification for full details on
+the restrictions imposed on untrusted clients.
+.It Cm GatewayPorts
+Specifies whether remote hosts are allowed to connect to local
+forwarded ports.
+By default,
+.Xr ssh 1
+binds local port forwardings to the loopback address.
+This prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that ssh
+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/ssh_known_hosts .
+.It Cm GSSAPIAuthentication
+Specifies whether user authentication based on GSSAPI is allowed.
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIDelegateCredentials
+Forward (delegate) credentials to the server.
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
+.It Cm HashKnownHosts
+Indicates that
+.Xr ssh 1
+should hash host names and addresses when they are added to
+.Pa ~/.ssh/known_hosts .
+These hashed names may be used normally by
+.Xr ssh 1
+and
+.Xr sshd 8 ,
+but they do not reveal identifying information should the file's contents
+be disclosed.
+The default is
+.Dq no .
+Note that existing names and addresses in known hosts files
+will not be converted automatically,
+but may be manually hashed using
+.Xr ssh-keygen 1 .
+.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:
+.Bd -literal -offset 3n
+ecdsa-sha2-nistp256-cert-v01@openssh.com,
+ecdsa-sha2-nistp384-cert-v01@openssh.com,
+ecdsa-sha2-nistp521-cert-v01@openssh.com,
+ssh-rsa-cert-v01@openssh.com,ssh-dss-cert-v01@openssh.com,
+ssh-rsa-cert-v00@openssh.com,ssh-dss-cert-v00@openssh.com,
+ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,
+ssh-rsa,ssh-dss
+.Ed
+.Pp
+If hostkeys are known for the destination host then this default is modified
+to prefer their algorithms.
+.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.
+If the hostname contains the character sequence
+.Ql %h ,
+then this will be replaced with the host name specified on the commandline
+(this is useful for manipulating unqualified names).
+The 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 IdentitiesOnly
+Specifies that
+.Xr ssh 1
+should only use the authentication identity files configured in the
+.Nm
+files,
+even if
+.Xr ssh-agent 1
+offers more identities.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+This option is intended for situations where ssh-agent
+offers many different identities.
+The default is
+.Dq no .
+.It Cm IdentityFile
+Specifies a file from which the user's DSA, ECDSA or DSA authentication
+identity is read.
+The default is
+.Pa ~/.ssh/identity
+for protocol version 1, and
+.Pa ~/.ssh/id_dsa ,
+.Pa ~/.ssh/id_ecdsa
+and
+.Pa ~/.ssh/id_rsa
+for protocol version 2.
+Additionally, any identities represented by the authentication agent
+will be used for authentication.
+.Xr ssh 1
+will try to load certificate information from the filename obtained by
+appending
+.Pa -cert.pub
+to the path of a specified
+.Cm IdentityFile .
+.Pp
+The file name may use the tilde
+syntax to refer to a user's home directory or one of the following
+escape characters:
+.Ql %d
+(local user's home directory),
+.Ql %u
+(local user name),
+.Ql %l
+(local host name),
+.Ql %h
+(remote host name) or
+.Ql %r
+(remote user name).
+.Pp
+It is possible to have
+multiple identity files specified in configuration files; all these
+identities will be tried in sequence.
+.It Cm IPQoS
+Specifies the IPv4 type-of-service or DSCP class for connections.
+Accepted values are
+.Dq af11 ,
+.Dq af12 ,
+.Dq af13 ,
+.Dq af14 ,
+.Dq af22 ,
+.Dq af23 ,
+.Dq af31 ,
+.Dq af32 ,
+.Dq af33 ,
+.Dq af41 ,
+.Dq af42 ,
+.Dq af43 ,
+.Dq cs0 ,
+.Dq cs1 ,
+.Dq cs2 ,
+.Dq cs3 ,
+.Dq cs4 ,
+.Dq cs5 ,
+.Dq cs6 ,
+.Dq cs7 ,
+.Dq ef ,
+.Dq lowdelay ,
+.Dq throughput ,
+.Dq reliability ,
+or a numeric value.
+This option may take one or two arguments, separated by whitespace.
+If one argument is specified, it is used as the packet class unconditionally.
+If two values are specified, the first is automatically selected for
+interactive sessions and the second for non-interactive sessions.
+The default is
+.Dq lowdelay
+for interactive sessions and
+.Dq throughput
+for non-interactive sessions.
+.It Cm KbdInteractiveAuthentication
+Specifies whether to use keyboard-interactive authentication.
+The argument to this keyword must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+.It Cm KbdInteractiveDevices
+Specifies the list of methods to use in keyboard-interactive authentication.
+Multiple method names must be comma-separated.
+The default is to use the server specified list.
+The methods available vary depending on what the server supports.
+For an OpenSSH server,
+it may be zero or more of:
+.Dq bsdauth ,
+.Dq pam ,
+and
+.Dq skey .
+.It Cm KexAlgorithms
+Specifies the available KEX (Key Exchange) algorithms.
+Multiple algorithms must be comma-separated.
+The default is:
+.Bd -literal -offset indent
+ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
+diffie-hellman-group-exchange-sha256,
+diffie-hellman-group-exchange-sha1,
+diffie-hellman-group14-sha1,
+diffie-hellman-group1-sha1
+.Ed
+.It Cm LocalCommand
+Specifies a command to execute on the local machine after successfully
+connecting to the server.
+The command string extends to the end of the line, and is executed with
+the user's shell.
+The following escape character substitutions will be performed:
+.Ql %d
+(local user's home directory),
+.Ql %h
+(remote host name),
+.Ql %l
+(local host name),
+.Ql %n
+(host name as provided on the command line),
+.Ql %p
+(remote port),
+.Ql %r
+(remote user name) or
+.Ql %u
+(local user name).
+.Pp
+The command is run synchronously and does not have access to the
+session of the
+.Xr ssh 1
+that spawned it.
+It should not be used for interactive commands.
+.Pp
+This directive is ignored unless
+.Cm PermitLocalCommand
+has been enabled.
+.It Cm LocalForward
+Specifies that a TCP 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
+.Sm off
+.Oo Ar bind_address : Oc Ar port
+.Sm on
+and the second argument must be
+.Ar host : Ns Ar hostport .
+IPv6 addresses can be specified by enclosing addresses in square brackets.
+Multiple forwardings may be specified, and additional forwardings can be
+given on the command line.
+Only the superuser can forward privileged ports.
+By default, the local port is bound in accordance with the
+.Cm GatewayPorts
+setting.
+However, an explicit
+.Ar bind_address
+may be used to bind the connection to a specific address.
+The
+.Ar bind_address
+of
+.Dq localhost
+indicates that the listening port be bound for local use only, while an
+empty address or
+.Sq *
+indicates that the port should be available from all interfaces.
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Xr ssh 1 .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
+The default is INFO.
+DEBUG and DEBUG1 are equivalent.
+DEBUG2 and DEBUG3 each specify higher levels of verbose output.
+.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:
+.Bd -literal -offset indent
+hmac-md5,hmac-sha1,umac-64@openssh.com,
+hmac-ripemd160,hmac-sha1-96,hmac-md5-96
+.Ed
+.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.
+The 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 PermitLocalCommand
+Allow local command execution via the
+.Ic LocalCommand
+option or using the
+.Ic !\& Ns Ar command
+escape sequence in
+.Xr ssh 1 .
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.It Cm PKCS11Provider
+Specifies which PKCS#11 provider to use.
+The argument to this keyword is the PKCS#11 shared library
+.Xr ssh 1
+should use to communicate with a PKCS#11 token providing the user's
+private RSA key.
+.It Cm Port
+Specifies the port number to connect on the remote host.
+The 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 is:
+.Bd -literal -offset indent
+gssapi-with-mic,hostbased,publickey,
+keyboard-interactive,password
+.Ed
+.It Cm Protocol
+Specifies the protocol versions
+.Xr ssh 1
+should support in order of preference.
+The possible values are
+.Sq 1
+and
+.Sq 2 .
+Multiple versions must be comma-separated.
+When this option is set to
+.Dq 2,1
+.Nm ssh
+will try version 2 and fall back to version 1
+if version 2 is not available.
+The default is
+.Sq 2 .
+.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
+the user's shell.
+In the command string, any occurrence of
+.Ql %h
+will be substituted by the host name to
+connect,
+.Ql %p
+by the port, and
+.Ql %r
+by the remote user name.
+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).
+Setting the command to
+.Dq none
+disables this option entirely.
+Note that
+.Cm CheckHostIP
+is not available for connects with a proxy command.
+.Pp
+This directive is useful in conjunction with
+.Xr nc 1
+and its proxy support.
+For example, the following directive would connect via an HTTP proxy at
+192.0.2.0:
+.Bd -literal -offset 3n
+ProxyCommand /usr/bin/nc -X connect -x 192.0.2.0:8080 %h %p
+.Ed
+.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 RekeyLimit
+Specifies the maximum amount of data that may be transmitted before the
+session key is renegotiated.
+The argument is the number of bytes, with an optional suffix of
+.Sq K ,
+.Sq M ,
+or
+.Sq G
+to indicate Kilobytes, Megabytes, or Gigabytes, respectively.
+The default is between
+.Sq 1G
+and
+.Sq 4G ,
+depending on the cipher.
+This option applies to protocol version 2 only.
+.It Cm RemoteForward
+Specifies that a TCP 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
+.Sm off
+.Oo Ar bind_address : Oc Ar port
+.Sm on
+and the second argument must be
+.Ar host : Ns Ar hostport .
+IPv6 addresses can be specified by enclosing addresses in square brackets.
+Multiple forwardings may be specified, and additional
+forwardings can be given on the command line.
+Privileged ports can be forwarded only when
+logging in as root on the remote machine.
+.Pp
+If the
+.Ar port
+argument is
+.Ql 0 ,
+the listen port will be dynamically allocated on the server and reported
+to the client at run time.
+.Pp
+If the
+.Ar bind_address
+is not specified, the default is to only bind to loopback addresses.
+If the
+.Ar bind_address
+is
+.Ql *
+or an empty string, then the forwarding is requested to listen on all
+interfaces.
+Specifying a remote
+.Ar bind_address
+will only succeed if the server's
+.Cm GatewayPorts
+option is enabled (see
+.Xr sshd_config 5 ) .
+.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 no .
+This option applies to protocol version 1 only and requires
+.Xr ssh 1
+to be setuid root.
+.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 SendEnv
+Specifies what variables from the local
+.Xr environ 7
+should be sent to the server.
+Note that environment passing is only supported for protocol 2.
+The server must also support it, and the server must be configured to
+accept these environment variables.
+Refer to
+.Cm AcceptEnv
+in
+.Xr sshd_config 5
+for how to configure the server.
+Variables are specified by name, which may contain wildcard characters.
+Multiple environment variables may be separated by whitespace or spread
+across multiple
+.Cm SendEnv
+directives.
+The default is not to send any environment variables.
+.Pp
+See
+.Sx PATTERNS
+for more information on patterns.
+.It Cm ServerAliveCountMax
+Sets the number of server alive messages (see below) which may be
+sent without
+.Xr ssh 1
+receiving any messages back from the server.
+If this threshold is reached while server alive messages are being sent,
+ssh will disconnect from the server, terminating the session.
+It is important to note that the use of server alive messages is very
+different from
+.Cm TCPKeepAlive
+(below).
+The server alive messages are sent through the encrypted channel
+and therefore will not be spoofable.
+The TCP keepalive option enabled by
+.Cm TCPKeepAlive
+is spoofable.
+The server 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, for example,
+.Cm ServerAliveInterval
+(see below) is set to 15 and
+.Cm ServerAliveCountMax
+is left at the default, if the server becomes unresponsive,
+ssh will disconnect after approximately 45 seconds.
+This option applies to protocol version 2 only.
+.It Cm ServerAliveInterval
+Sets a timeout interval in seconds after which if no data has been received
+from the server,
+.Xr ssh 1
+will send a message through the encrypted
+channel to request a response from the server.
+The default
+is 0, indicating that these messages will not be sent to the server.
+This option applies to protocol version 2 only.
+.It Cm StrictHostKeyChecking
+If this flag is set to
+.Dq yes ,
+.Xr ssh 1
+will never automatically add host keys to the
+.Pa ~/.ssh/known_hosts
+file, and refuses to connect to hosts whose host key has changed.
+This provides maximum protection against trojan horse attacks,
+though it can be annoying when the
+.Pa /etc/ssh/ssh_known_hosts
+file is poorly maintained or when 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 ,
+ssh 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
+ssh 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 TCPKeepAlive
+Specifies whether the system should send TCP 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 TCP keepalive messages), 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 TCP keepalive messages, the value should be set to
+.Dq no .
+.It Cm Tunnel
+Request
+.Xr tun 4
+device forwarding between the client and the server.
+The argument must be
+.Dq yes ,
+.Dq point-to-point
+(layer 3),
+.Dq ethernet
+(layer 2),
+or
+.Dq no .
+Specifying
+.Dq yes
+requests the default tunnel mode, which is
+.Dq point-to-point .
+The default is
+.Dq no .
+.It Cm TunnelDevice
+Specifies the
+.Xr tun 4
+devices to open on the client
+.Pq Ar local_tun
+and the server
+.Pq Ar remote_tun .
+.Pp
+The argument must be
+.Sm off
+.Ar local_tun Op : Ar remote_tun .
+.Sm on
+The devices may be specified by numerical ID or the keyword
+.Dq any ,
+which uses the next available tunnel device.
+If
+.Ar remote_tun
+is not specified, it defaults to
+.Dq any .
+The default is
+.Dq any:any .
+.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 .
+If set to
+.Dq yes ,
+.Xr ssh 1
+must be setuid root.
+Note that this option must be set to
+.Dq yes
+for
+.Cm RhostsRSAAuthentication
+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 ~/.ssh/known_hosts .
+.It Cm VerifyHostKeyDNS
+Specifies whether to verify the remote key using DNS and SSHFP resource
+records.
+If this option is set to
+.Dq yes ,
+the client will implicitly trust keys that match a secure fingerprint
+from DNS.
+Insecure fingerprints will be handled as if this option was set to
+.Dq ask .
+If this option is set to
+.Dq ask ,
+information on fingerprint match will be displayed, but the user will still
+need to confirm new host keys according to the
+.Cm StrictHostKeyChecking
+option.
+The argument must be
+.Dq yes ,
+.Dq no ,
+or
+.Dq ask .
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
+.Pp
+See also
+.Sx VERIFYING HOST KEYS
+in
+.Xr ssh 1 .
+.It Cm VisualHostKey
+If this flag is set to
+.Dq yes ,
+an ASCII art representation of the remote host key fingerprint is
+printed in addition to the hex fingerprint string at login and
+for unknown host keys.
+If this flag is set to
+.Dq no ,
+no fingerprint strings are printed at login and
+only the hex fingerprint string will be printed for unknown host keys.
+The default is
+.Dq no .
+.It Cm XAuthLocation
+Specifies the full pathname of the
+.Xr xauth 1
+program.
+The default is
+.Pa /usr/X11R6/bin/xauth .
+.El
+.Sh PATTERNS
+A
+.Em pattern
+consists of zero or more non-whitespace characters,
+.Sq *
+(a wildcard that matches zero or more characters),
+or
+.Sq ?\&
+(a wildcard that matches exactly one character).
+For example, to specify a set of declarations for any host in the
+.Dq .co.uk
+set of domains,
+the following pattern could be used:
+.Pp
+.Dl Host *.co.uk
+.Pp
+The following pattern
+would match any host in the 192.168.0.[0-9] network range:
+.Pp
+.Dl Host 192.168.0.?
+.Pp
+A
+.Em pattern-list
+is a comma-separated list of patterns.
+Patterns within pattern-lists may be negated
+by preceding them with an exclamation mark
+.Pq Sq !\& .
+For example,
+to allow a key to be used from anywhere within an organisation
+except from the
+.Dq dialup
+pool,
+the following entry (in authorized_keys) could be used:
+.Pp
+.Dl from=\&"!*.dialup.example.com,*.example.com\&"
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa ~/.ssh/config
+This is the per-user configuration file.
+The format of this file is described above.
+This file is used by the SSH client.
+Because of the potential for abuse, this file must have strict permissions:
+read/write for the user, and not accessible by others.
+.It Pa /etc/ssh/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.
+.El
+.Sh SEE ALSO
+.Xr ssh 1
+.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.
diff --git a/ssh_prng_cmds.in b/ssh_prng_cmds.in
new file mode 100644 (file)
index 0000000..0d29d49
--- /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: ssh_prng_cmds.in,v 1.9 2003/11/21 12:48:56 djm Exp $
+
+"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 -n -a"                            @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/sshconnect.c b/sshconnect.c
new file mode 100644 (file)
index 0000000..74643a8
--- /dev/null
@@ -0,0 +1,1292 @@
+/* $OpenBSD: sshconnect.c,v 1.232 2011/01/16 11:50:36 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "hostfile.h"
+#include "ssh.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"
+#include "dns.h"
+#include "roaming.h"
+#include "ssh2.h"
+#include "version.h"
+
+char *client_version_string = NULL;
+char *server_version_string = NULL;
+
+static int matching_host_key_dns = 0;
+
+static pid_t proxy_command_pid = 0;
+
+/* import */
+extern Options options;
+extern char *__progname;
+extern uid_t original_real_uid;
+extern uid_t original_effective_uid;
+
+static int show_other_keys(struct hostkeys *, Key *);
+static void warn_changed_key(Key *);
+
+/*
+ * Connect to the given ssh server using a proxy command.
+ */
+static int
+ssh_proxy_connect(const char *host, u_short port, const char *proxy_command)
+{
+       char *command_string, *tmp;
+       int pin[2], pout[2];
+       pid_t pid;
+       char *shell, strport[NI_MAXSERV];
+
+       if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
+               shell = _PATH_BSHELL;
+
+       /* 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.
+        *
+        * Use "exec" to avoid "sh -c" processes on some platforms
+        * (e.g. Solaris)
+        */
+       xasprintf(&tmp, "exec %s", proxy_command);
+       command_string = percent_expand(tmp, "h", host, "p", strport,
+           "r", options.user, (char *)NULL);
+       xfree(tmp);
+
+       /* 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_drop_suid(original_real_uid);
+
+               /* 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] = shell;
+               argv[1] = "-c";
+               argv[2] = command_string;
+               argv[3] = NULL;
+
+               /* Execute the proxy command.  Note that we gave up any
+                  extra privileges above. */
+               signal(SIGPIPE, SIG_DFL);
+               execv(argv[0], argv);
+               perror(argv[0]);
+               exit(1);
+       }
+       /* Parent. */
+       if (pid < 0)
+               fatal("fork failed: %.100s", strerror(errno));
+       else
+               proxy_command_pid = pid; /* save pid to clean up later */
+
+       /* Close child side of the descriptors. */
+       close(pin[0]);
+       close(pout[1]);
+
+       /* Free the command name. */
+       xfree(command_string);
+
+       /* Set the connection file descriptors. */
+       packet_set_connection(pout[0], pin[1]);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
+
+       /* Indicate OK return */
+       return 0;
+}
+
+void
+ssh_kill_proxy_command(void)
+{
+       /*
+        * Send SIGHUP to proxy command if used. We don't wait() in
+        * case it hangs and instead rely on init to reap the child
+        */
+       if (proxy_command_pid > 1)
+               kill(proxy_command_pid, SIGHUP);
+}
+
+/*
+ * Creates a (possibly privileged) socket for use as the ssh connection.
+ */
+static int
+ssh_create_socket(int privileged, struct addrinfo *ai)
+{
+       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;
+               PRIV_START;
+               sock = rresvport_af(&p, ai->ai_family);
+               PRIV_END;
+               if (sock < 0)
+                       error("rresvport: af=%d %.100s", ai->ai_family,
+                           strerror(errno));
+               else
+                       debug("Allocated local port %d.", p);
+               return sock;
+       }
+       sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+       if (sock < 0) {
+               error("socket: %.100s", strerror(errno));
+               return -1;
+       }
+       fcntl(sock, F_SETFD, FD_CLOEXEC);
+
+       /* Bind the socket to an alternative local IP address */
+       if (options.bind_address == NULL)
+               return sock;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = ai->ai_family;
+       hints.ai_socktype = ai->ai_socktype;
+       hints.ai_protocol = ai->ai_protocol;
+       hints.ai_flags = AI_PASSIVE;
+       gaierr = getaddrinfo(options.bind_address, NULL, &hints, &res);
+       if (gaierr) {
+               error("getaddrinfo: %s: %s", options.bind_address,
+                   ssh_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;
+}
+
+static int
+timeout_connect(int sockfd, const struct sockaddr *serv_addr,
+    socklen_t addrlen, int *timeoutp)
+{
+       fd_set *fdset;
+       struct timeval tv, t_start;
+       socklen_t optlen;
+       int optval, rc, result = -1;
+
+       gettimeofday(&t_start, NULL);
+
+       if (*timeoutp <= 0) {
+               result = connect(sockfd, serv_addr, addrlen);
+               goto done;
+       }
+
+       set_nonblock(sockfd);
+       rc = connect(sockfd, serv_addr, addrlen);
+       if (rc == 0) {
+               unset_nonblock(sockfd);
+               result = 0;
+               goto done;
+       }
+       if (errno != EINPROGRESS) {
+               result = -1;
+               goto done;
+       }
+
+       fdset = (fd_set *)xcalloc(howmany(sockfd + 1, NFDBITS),
+           sizeof(fd_mask));
+       FD_SET(sockfd, fdset);
+       ms_to_timeval(&tv, *timeoutp);
+
+       for (;;) {
+               rc = select(sockfd + 1, NULL, fdset, NULL, &tv);
+               if (rc != -1 || errno != EINTR)
+                       break;
+       }
+
+       switch (rc) {
+       case 0:
+               /* Timed out */
+               errno = ETIMEDOUT;
+               break;
+       case -1:
+               /* Select error */
+               debug("select: %s", strerror(errno));
+               break;
+       case 1:
+               /* Completed or failed */
+               optval = 0;
+               optlen = sizeof(optval);
+               if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval,
+                   &optlen) == -1) {
+                       debug("getsockopt: %s", strerror(errno));
+                       break;
+               }
+               if (optval != 0) {
+                       errno = optval;
+                       break;
+               }
+               result = 0;
+               unset_nonblock(sockfd);
+               break;
+       default:
+               /* Should not occur */
+               fatal("Bogus return (%d) from select()", rc);
+       }
+
+       xfree(fdset);
+
+ done:
+       if (result == 0 && *timeoutp > 0) {
+               ms_subtract_diff(&t_start, timeoutp);
+               if (*timeoutp <= 0) {
+                       errno = ETIMEDOUT;
+                       result = -1;
+               }
+       }
+
+       return (result);
+}
+
+/*
+ * 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 needpriv is true,
+ * a privileged port will be allocated to make the connection.
+ * This requires super-user privileges if needpriv is true.
+ * 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.
+ */
+int
+ssh_connect(const char *host, struct sockaddr_storage * hostaddr,
+    u_short port, int family, int connection_attempts, int *timeout_ms,
+    int want_keepalive, int needpriv, 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;
+
+       debug2("ssh_connect: needpriv %d", needpriv);
+
+       /* If a proxy command is given, connect using it. */
+       if (proxy_command != NULL)
+               return ssh_proxy_connect(host, port, proxy_command);
+
+       /* No proxy command. */
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = family;
+       hints.ai_socktype = SOCK_STREAM;
+       snprintf(strport, sizeof strport, "%u", port);
+       if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
+               fatal("%s: Could not resolve hostname %.100s: %s", __progname,
+                   host, ssh_gai_strerror(gaierr));
+
+       for (attempt = 0; attempt < connection_attempts; attempt++) {
+               if (attempt > 0) {
+                       /* Sleep a moment before retrying. */
+                       sleep(1);
+                       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(needpriv, ai);
+                       if (sock < 0)
+                               /* Any error is already output */
+                               continue;
+
+                       if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen,
+                           timeout_ms) >= 0) {
+                               /* Successful connection. */
+                               memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen);
+                               break;
+                       } else {
+                               debug("connect to address %s port %s: %s",
+                                   ntop, strport, strerror(errno));
+                               close(sock);
+                               sock = -1;
+                       }
+               }
+               if (sock != -1)
+                       break;  /* Successful connection. */
+       }
+
+       freeaddrinfo(aitop);
+
+       /* Return failure if we didn't get a successful connection. */
+       if (sock == -1) {
+               error("ssh: connect to host %s port %s: %s",
+                   host, strport, strerror(errno));
+               return (-1);
+       }
+
+       debug("Connection established.");
+
+       /* Set SO_KEEPALIVE if requested. */
+       if (want_keepalive &&
+           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);
+       packet_set_timeout(options.server_alive_interval,
+           options.server_alive_count_max);
+
+       return 0;
+}
+
+/*
+ * Waits for the server identification string, and sends our own
+ * identification string.
+ */
+void
+ssh_exchange_identification(int timeout_ms)
+{
+       char buf[256], remote_version[256];     /* must be same size! */
+       int remote_major, remote_minor, mismatch;
+       int connection_in = packet_get_connection_in();
+       int connection_out = packet_get_connection_out();
+       int minor1 = PROTOCOL_MINOR_1;
+       u_int i, n;
+       size_t len;
+       int fdsetsz, remaining, rc;
+       struct timeval t_start, t_remaining;
+       fd_set *fdset;
+
+       fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
+       fdset = xcalloc(1, fdsetsz);
+
+       /* Read other side's version identification. */
+       remaining = timeout_ms;
+       for (n = 0;;) {
+               for (i = 0; i < sizeof(buf) - 1; i++) {
+                       if (timeout_ms > 0) {
+                               gettimeofday(&t_start, NULL);
+                               ms_to_timeval(&t_remaining, remaining);
+                               FD_SET(connection_in, fdset);
+                               rc = select(connection_in + 1, fdset, NULL,
+                                   fdset, &t_remaining);
+                               ms_subtract_diff(&t_start, &remaining);
+                               if (rc == 0 || remaining <= 0)
+                                       fatal("Connection timed out during "
+                                           "banner exchange");
+                               if (rc == -1) {
+                                       if (errno == EINTR)
+                                               continue;
+                                       fatal("ssh_exchange_identification: "
+                                           "select: %s", strerror(errno));
+                               }
+                       }
+
+                       len = roaming_atomicio(read, connection_in, &buf[i], 1);
+
+                       if (len != 1 && errno == EPIPE)
+                               fatal("ssh_exchange_identification: "
+                                   "Connection closed by remote host");
+                       else if (len != 1)
+                               fatal("ssh_exchange_identification: "
+                                   "read: %.100s", strerror(errno));
+                       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;
+                       }
+                       if (++n > 65536)
+                               fatal("ssh_exchange_identification: "
+                                   "No banner received");
+               }
+               buf[sizeof(buf) - 1] = 0;
+               if (strncmp(buf, "SSH-", 4) == 0)
+                       break;
+               debug("ssh_exchange_identification: %s", buf);
+       }
+       server_version_string = xstrdup(buf);
+       xfree(fdset);
+
+       /*
+        * 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) {
+                               logit("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%s",
+           compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
+           compat20 ? PROTOCOL_MINOR_2 : minor1,
+           SSH_VERSION, compat20 ? "\r\n" : "\n");
+       if (roaming_atomicio(vwrite, 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)
+{
+       const char *msg, *again = "Please type 'yes' or 'no': ";
+       char *p;
+       int ret = -1;
+
+       if (options.batch_mode)
+               return 0;
+       for (msg = prompt;;msg = again) {
+               p = read_passphrase(msg, RP_ECHO);
+               if (p == NULL ||
+                   (p[0] == '\0') || (p[0] == '\n') ||
+                   strncasecmp(p, "no", 2) == 0)
+                       ret = 0;
+               if (p && strncasecmp(p, "yes", 3) == 0)
+                       ret = 1;
+               if (p)
+                       xfree(p);
+               if (ret != -1)
+                       return ret;
+       }
+}
+
+static int
+check_host_cert(const char *host, const Key *host_key)
+{
+       const char *reason;
+
+       if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) {
+               error("%s", reason);
+               return 0;
+       }
+       if (buffer_len(&host_key->cert->critical) != 0) {
+               error("Certificate for %s contains unsupported "
+                   "critical options(s)", host);
+               return 0;
+       }
+       return 1;
+}
+
+static int
+sockaddr_is_local(struct sockaddr *hostaddr)
+{
+       switch (hostaddr->sa_family) {
+       case AF_INET:
+               return (ntohl(((struct sockaddr_in *)hostaddr)->
+                   sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
+       case AF_INET6:
+               return IN6_IS_ADDR_LOOPBACK(
+                   &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
+       default:
+               return 0;
+       }
+}
+
+/*
+ * Prepare the hostname and ip address strings that are used to lookup
+ * host keys in known_hosts files. These may have a port number appended.
+ */
+void
+get_hostfile_hostname_ipaddr(char *hostname, struct sockaddr *hostaddr,
+    u_short port, char **hostfile_hostname, char **hostfile_ipaddr)
+{
+       char ntop[NI_MAXHOST];
+       socklen_t addrlen;
+
+       switch (hostaddr == NULL ? -1 : hostaddr->sa_family) {
+       case -1:
+               addrlen = 0;
+               break;
+       case AF_INET:
+               addrlen = sizeof(struct sockaddr_in);
+               break;
+       case AF_INET6:
+               addrlen = sizeof(struct sockaddr_in6);
+               break;
+       default:
+               addrlen = sizeof(struct sockaddr);
+               break;
+       }
+
+       /*
+        * We don't have the remote ip-address for connections
+        * using a proxy command
+        */
+       if (hostfile_ipaddr != NULL) {
+               if (options.proxy_command == NULL) {
+                       if (getnameinfo(hostaddr, addrlen,
+                           ntop, sizeof(ntop), NULL, 0, NI_NUMERICHOST) != 0)
+                       fatal("check_host_key: getnameinfo failed");
+                       *hostfile_ipaddr = put_host_port(ntop, port);
+               } else {
+                       *hostfile_ipaddr = xstrdup("<no hostip for proxy "
+                           "command>");
+               }
+       }
+
+       /*
+        * Allow the user to record the key under a different name or
+        * differentiate a non-standard port.  This is useful for ssh
+        * tunneling over forwarded connections or if you run multiple
+        * sshd's on different ports on the same machine.
+        */
+       if (hostfile_hostname != NULL) {
+               if (options.host_key_alias != NULL) {
+                       *hostfile_hostname = xstrdup(options.host_key_alias);
+                       debug("using hostkeyalias: %s", *hostfile_hostname);
+               } else {
+                       *hostfile_hostname = put_host_port(hostname, port);
+               }
+       }
+}
+
+/*
+ * 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.
+ */
+#define RDRW   0
+#define RDONLY 1
+#define ROQUIET        2
+static int
+check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
+    Key *host_key, int readonly, char *user_hostfile,
+    char *system_hostfile)
+{
+       Key *raw_key = NULL;
+       const char *type;
+       char *ip = NULL, *host = NULL;
+       char hostline[1000], *hostp, *fp, *ra;
+       HostStatus host_status;
+       HostStatus ip_status;
+       int r, want_cert = key_is_cert(host_key), host_ip_differ = 0;
+       int local = sockaddr_is_local(hostaddr);
+       char msg[1024];
+       int len, cancelled_forwarding = 0;
+       struct hostkeys *host_hostkeys, *ip_hostkeys;
+       const struct hostkey_entry *host_found, *ip_found;
+
+       /*
+        * 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.
+        */
+       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;
+       }
+
+       /*
+        * Prepare the hostname and address strings used for hostkey lookup.
+        * In some cases, these will have a port number appended.
+        */
+       get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip);
+
+       /*
+        * 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(hostname, ip) == 0 || options.proxy_command != NULL))
+               options.check_host_ip = 0;
+
+       host_hostkeys = init_hostkeys();
+       load_hostkeys(host_hostkeys, host, user_hostfile);
+       load_hostkeys(host_hostkeys, host, system_hostfile);
+
+       ip_hostkeys = NULL;
+       if (!want_cert && options.check_host_ip) {
+               ip_hostkeys = init_hostkeys();
+               load_hostkeys(ip_hostkeys, ip, user_hostfile);
+               load_hostkeys(ip_hostkeys, ip, system_hostfile);
+       }
+
+ retry:
+       /* Reload these as they may have changed on cert->key downgrade */
+       want_cert = key_is_cert(host_key);
+       type = key_type(host_key);
+
+       /*
+        * Check if the host key is present in the user's list of known
+        * hosts or in the systemwide list.
+        */
+       host_status = check_key_in_hostkeys(host_hostkeys, host_key,
+           &host_found);
+
+       /*
+        * Also perform check for the ip address, skip the check if we are
+        * localhost, looking for a certificate, or the hostname was an ip
+        * address to begin with.
+        */
+       if (!want_cert && ip_hostkeys != NULL) {
+               ip_status = check_key_in_hostkeys(ip_hostkeys, host_key,
+                   &ip_found);
+               if (host_status == HOST_CHANGED &&
+                   (ip_status != HOST_CHANGED || 
+                   (ip_found != NULL &&
+                   !key_equal(ip_found->key, host_found->key))))
+                       host_ip_differ = 1;
+       } else
+               ip_status = host_status;
+
+       switch (host_status) {
+       case HOST_OK:
+               /* The host is known and the key matches. */
+               debug("Host '%.200s' is known and matches the %s host %s.",
+                   host, type, want_cert ? "certificate" : "key");
+               debug("Found %s in %s:%lu", want_cert ? "CA key" : "key",
+                   host_found->file, host_found->line);
+               if (want_cert && !check_host_cert(hostname, host_key))
+                       goto fail;
+               if (options.check_host_ip && ip_status == HOST_NEW) {
+                       if (readonly || want_cert)
+                               logit("%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, options.hash_known_hosts))
+                               logit("Failed to add the %s host key for IP "
+                                   "address '%.128s' to the list of known "
+                                   "hosts (%.30s).", type, ip, user_hostfile);
+                       else
+                               logit("Warning: Permanently added the %s host "
+                                   "key for IP address '%.128s' to the list "
+                                   "of known hosts.", type, ip);
+               } else if (options.visual_host_key) {
+                       fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+                       ra = key_fingerprint(host_key, SSH_FP_MD5,
+                           SSH_FP_RANDOMART);
+                       logit("Host key fingerprint is %s\n%s\n", fp, ra);
+                       xfree(ra);
+                       xfree(fp);
+               }
+               break;
+       case HOST_NEW:
+               if (options.host_key_alias == NULL && port != 0 &&
+                   port != SSH_DEFAULT_PORT) {
+                       debug("checking without port identifier");
+                       if (check_host_key(hostname, hostaddr, 0, host_key,
+                           ROQUIET, user_hostfile, system_hostfile) == 0) {
+                               debug("found matching key w/out port");
+                               break;
+                       }
+               }
+               if (readonly || want_cert)
+                       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) {
+                       char msg1[1024], msg2[1024];
+
+                       if (show_other_keys(host_hostkeys, host_key))
+                               snprintf(msg1, sizeof(msg1),
+                                   "\nbut keys of different type are already"
+                                   " known for this host.");
+                       else
+                               snprintf(msg1, sizeof(msg1), ".");
+                       /* The default */
+                       fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+                       ra = key_fingerprint(host_key, SSH_FP_MD5,
+                           SSH_FP_RANDOMART);
+                       msg2[0] = '\0';
+                       if (options.verify_host_key_dns) {
+                               if (matching_host_key_dns)
+                                       snprintf(msg2, sizeof(msg2),
+                                           "Matching host key fingerprint"
+                                           " found in DNS.\n");
+                               else
+                                       snprintf(msg2, sizeof(msg2),
+                                           "No matching host key fingerprint"
+                                           " found in DNS.\n");
+                       }
+                       snprintf(msg, sizeof(msg),
+                           "The authenticity of host '%.200s (%s)' can't be "
+                           "established%s\n"
+                           "%s key fingerprint is %s.%s%s\n%s"
+                           "Are you sure you want to continue connecting "
+                           "(yes/no)? ",
+                           host, ip, msg1, type, fp,
+                           options.visual_host_key ? "\n" : "",
+                           options.visual_host_key ? ra : "",
+                           msg2);
+                       xfree(ra);
+                       xfree(fp);
+                       if (!confirm(msg))
+                               goto fail;
+               }
+               /*
+                * If not in strict mode, add the key automatically to the
+                * local known_hosts file.
+                */
+               if (options.check_host_ip && ip_status == HOST_NEW) {
+                       snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
+                       hostp = hostline;
+                       if (options.hash_known_hosts) {
+                               /* Add hash of host and IP separately */
+                               r = add_host_to_hostfile(user_hostfile, host,
+                                   host_key, options.hash_known_hosts) &&
+                                   add_host_to_hostfile(user_hostfile, ip,
+                                   host_key, options.hash_known_hosts);
+                       } else {
+                               /* Add unhashed "host,ip" */
+                               r = add_host_to_hostfile(user_hostfile,
+                                   hostline, host_key,
+                                   options.hash_known_hosts);
+                       }
+               } else {
+                       r = add_host_to_hostfile(user_hostfile, host, host_key,
+                           options.hash_known_hosts);
+                       hostp = host;
+               }
+
+               if (!r)
+                       logit("Failed to add the host to the list of known "
+                           "hosts (%.500s).", user_hostfile);
+               else
+                       logit("Warning: Permanently added '%.200s' (%s) to the "
+                           "list of known hosts.", hostp, type);
+               break;
+       case HOST_REVOKED:
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("@       WARNING: REVOKED HOST KEY DETECTED!               @");
+               error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+               error("The %s host key for %s is marked as revoked.", type, host);
+               error("This could mean that a stolen key is being used to");
+               error("impersonate this host.");
+
+               /*
+                * 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 was revoked and you have "
+                           "requested strict checking.", type, host);
+                       goto fail;
+               }
+               goto continue_unsafe;
+
+       case HOST_CHANGED:
+               if (want_cert) {
+                       /*
+                        * This is only a debug() since it is valid to have
+                        * CAs with wildcard DNS matches that don't match
+                        * all hosts that one might visit.
+                        */
+                       debug("Host certificate authority does not "
+                           "match %s in %s:%lu", CA_MARKER,
+                           host_found->file, host_found->line);
+                       goto fail;
+               }
+               if (readonly == ROQUIET)
+                       goto fail;
+               if (options.check_host_ip && host_ip_differ) {
+                       char *key_msg;
+                       if (ip_status == HOST_NEW)
+                               key_msg = "is unknown";
+                       else if (ip_status == HOST_OK)
+                               key_msg = "is unchanged";
+                       else
+                               key_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 corresponding IP address %s", ip);
+                       error("%s. This could either mean that", key_msg);
+                       error("DNS SPOOFING is happening or the IP address for the host");
+                       error("and its host key have changed at the same time.");
+                       if (ip_status != HOST_NEW)
+                               error("Offending key for IP in %s:%lu",
+                                   ip_found->file, ip_found->line);
+               }
+               /* The host key has changed. */
+               warn_changed_key(host_key);
+               error("Add correct host key in %.100s to get rid of this message.",
+                   user_hostfile);
+               error("Offending %s key in %s:%lu", key_type(host_found->key),
+                   host_found->file, host_found->line);
+
+               /*
+                * 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;
+               }
+
+ continue_unsafe:
+               /*
+                * If strict host key checking has not been requested, allow
+                * the connection but without MITM-able authentication or
+                * forwarding.
+                */
+               if (options.password_authentication) {
+                       error("Password authentication is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.password_authentication = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.kbd_interactive_authentication) {
+                       error("Keyboard-interactive authentication is disabled"
+                           " to avoid man-in-the-middle attacks.");
+                       options.kbd_interactive_authentication = 0;
+                       options.challenge_response_authentication = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.challenge_response_authentication) {
+                       error("Challenge/response authentication is disabled"
+                           " to avoid man-in-the-middle attacks.");
+                       options.challenge_response_authentication = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.forward_agent) {
+                       error("Agent forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.forward_agent = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.forward_x11) {
+                       error("X11 forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.forward_x11 = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.num_local_forwards > 0 ||
+                   options.num_remote_forwards > 0) {
+                       error("Port forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.num_local_forwards =
+                           options.num_remote_forwards = 0;
+                       cancelled_forwarding = 1;
+               }
+               if (options.tun_open != SSH_TUNMODE_NO) {
+                       error("Tunnel forwarding is disabled to avoid "
+                           "man-in-the-middle attacks.");
+                       options.tun_open = SSH_TUNMODE_NO;
+                       cancelled_forwarding = 1;
+               }
+               if (options.exit_on_forward_failure && cancelled_forwarding)
+                       fatal("Error: forwarding disabled due to host key "
+                           "check failure");
+               
+               /*
+                * XXX Should permit the user to change to use the new id.
+                * This could be done by converting the host key to an
+                * identifying sentence, tell that the host identifies itself
+                * by that sentence, and ask the user if he/she wishes to
+                * accept the authentication.
+                */
+               break;
+       case HOST_FOUND:
+               fatal("internal error");
+               break;
+       }
+
+       if (options.check_host_ip && host_status != HOST_CHANGED &&
+           ip_status == HOST_CHANGED) {
+               snprintf(msg, sizeof(msg),
+                   "Warning: the %s host key for '%.200s' "
+                   "differs from the key for the IP address '%.128s'"
+                   "\nOffending key for IP in %s:%lu",
+                   type, host, ip, ip_found->file, ip_found->line);
+               if (host_status == HOST_OK) {
+                       len = strlen(msg);
+                       snprintf(msg + len, sizeof(msg) - len,
+                           "\nMatching host key in %s:%lu",
+                           host_found->file, host_found->line);
+               }
+               if (options.strict_host_key_checking == 1) {
+                       logit("%s", msg);
+                       error("Exiting, you have requested strict checking.");
+                       goto fail;
+               } else if (options.strict_host_key_checking == 2) {
+                       strlcat(msg, "\nAre you sure you want "
+                           "to continue connecting (yes/no)? ", sizeof(msg));
+                       if (!confirm(msg))
+                               goto fail;
+               } else {
+                       logit("%s", msg);
+               }
+       }
+
+       xfree(ip);
+       xfree(host);
+       if (host_hostkeys != NULL)
+               free_hostkeys(host_hostkeys);
+       if (ip_hostkeys != NULL)
+               free_hostkeys(ip_hostkeys);
+       return 0;
+
+fail:
+       if (want_cert && host_status != HOST_REVOKED) {
+               /*
+                * No matching certificate. Downgrade cert to raw key and
+                * search normally.
+                */
+               debug("No matching CA found. Retry with plain key");
+               raw_key = key_from_private(host_key);
+               if (key_drop_cert(raw_key) != 0)
+                       fatal("Couldn't drop certificate");
+               host_key = raw_key;
+               goto retry;
+       }
+       if (raw_key != NULL)
+               key_free(raw_key);
+       xfree(ip);
+       xfree(host);
+       if (host_hostkeys != NULL)
+               free_hostkeys(host_hostkeys);
+       if (ip_hostkeys != NULL)
+               free_hostkeys(ip_hostkeys);
+       return -1;
+}
+
+/* returns 0 if key verifies or -1 if key does NOT verify */
+int
+verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
+{
+       struct stat st;
+       int flags = 0;
+       char *fp;
+
+       fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+       debug("Server host key: %s %s", key_type(host_key), fp);
+       xfree(fp);
+
+       /* XXX certs are not yet supported for DNS */
+       if (!key_is_cert(host_key) && options.verify_host_key_dns &&
+           verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
+
+               if (flags & DNS_VERIFY_FOUND) {
+
+                       if (options.verify_host_key_dns == 1 &&
+                           flags & DNS_VERIFY_MATCH &&
+                           flags & DNS_VERIFY_SECURE)
+                               return 0;
+
+                       if (flags & DNS_VERIFY_MATCH) {
+                               matching_host_key_dns = 1;
+                       } else {
+                               warn_changed_key(host_key);
+                               error("Update the SSHFP RR in DNS with the new "
+                                   "host key to get rid of this message.");
+                       }
+               }
+       }
+
+       /* 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, options.port, host_key,
+                   RDONLY, options.user_hostfile2,
+                   options.system_hostfile2) == 0)
+                       return 0;
+       }
+       return check_host_key(host, hostaddr, options.port, host_key,
+           RDRW, 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(Sensitive *sensitive, const char *orighost,
+    struct sockaddr *hostaddr, u_short port, struct passwd *pw, int timeout_ms)
+{
+       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 = (char)tolower(*cp);
+
+       /* Exchange protocol version identification strings with the server. */
+       ssh_exchange_identification(timeout_ms);
+
+       /* Put the connection into non-blocking mode. */
+       packet_set_nonblocking();
+
+       /* key exchange */
+       /* authenticate user */
+       if (compat20) {
+               ssh_kex2(host, hostaddr, port);
+               ssh_userauth2(local_user, server_user, host, sensitive);
+       } else {
+               ssh_kex(host, hostaddr);
+               ssh_userauth1(local_user, server_user, host, sensitive);
+       }
+       xfree(local_user);
+}
+
+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 = xcalloc(1, size);
+       strlcpy(padded, password, size);
+       packet_put_string(padded, size);
+       memset(padded, 0, size);
+       xfree(padded);
+}
+
+/* print all known host keys for a given host, but skip keys of given type */
+static int
+show_other_keys(struct hostkeys *hostkeys, Key *key)
+{
+       int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, -1};
+       int i, ret = 0;
+       char *fp, *ra;
+       const struct hostkey_entry *found;
+
+       for (i = 0; type[i] != -1; i++) {
+               if (type[i] == key->type)
+                       continue;
+               if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
+                       continue;
+               fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
+               ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
+               logit("WARNING: %s key found for host %s\n"
+                   "in %s:%lu\n"
+                   "%s key fingerprint %s.",
+                   key_type(found->key),
+                   found->host, found->file, found->line,
+                   key_type(found->key), fp);
+               if (options.visual_host_key)
+                       logit("%s", ra);
+               xfree(ra);
+               xfree(fp);
+               ret = 1;
+       }
+       return ret;
+}
+
+static void
+warn_changed_key(Key *host_key)
+{
+       char *fp;
+
+       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 a host key has just been changed.");
+       error("The fingerprint for the %s key sent by the remote host is\n%s.",
+           key_type(host_key), fp);
+       error("Please contact your system administrator.");
+
+       xfree(fp);
+}
+
+/*
+ * Execute a local command
+ */
+int
+ssh_local_cmd(const char *args)
+{
+       char *shell;
+       pid_t pid;
+       int status;
+       void (*osighand)(int);
+
+       if (!options.permit_local_command ||
+           args == NULL || !*args)
+               return (1);
+
+       if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
+               shell = _PATH_BSHELL;
+
+       osighand = signal(SIGCHLD, SIG_DFL);
+       pid = fork();
+       if (pid == 0) {
+               signal(SIGPIPE, SIG_DFL);
+               debug3("Executing %s -c \"%s\"", shell, args);
+               execl(shell, shell, "-c", args, (char *)NULL);
+               error("Couldn't execute %s -c \"%s\": %s",
+                   shell, args, strerror(errno));
+               _exit(1);
+       } else if (pid == -1)
+               fatal("fork failed: %.100s", strerror(errno));
+       while (waitpid(pid, &status, 0) == -1)
+               if (errno != EINTR)
+                       fatal("Couldn't wait for child: %s", strerror(errno));
+       signal(SIGCHLD, osighand);
+
+       if (!WIFEXITED(status))
+               return (1);
+
+       return (WEXITSTATUS(status));
+}
diff --git a/sshconnect.h b/sshconnect.h
new file mode 100644 (file)
index 0000000..fd7f7f7
--- /dev/null
@@ -0,0 +1,75 @@
+/* $OpenBSD: sshconnect.h,v 1.27 2010/11/29 23:45:51 djm 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.
+ */
+
+typedef struct Sensitive Sensitive;
+struct Sensitive {
+       Key     **keys;
+       int     nkeys;
+       int     external_keysign;
+};
+
+int
+ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int,
+    int *, int, int, const char *);
+void    ssh_kill_proxy_command(void);
+
+void    ssh_login(Sensitive *, const char *, struct sockaddr *, u_short,
+    struct passwd *, int);
+
+void    ssh_exchange_identification(int);
+
+int     verify_host_key(char *, struct sockaddr *, Key *);
+
+void    get_hostfile_hostname_ipaddr(char *, struct sockaddr *, u_short,
+    char **, char **);
+
+void    ssh_kex(char *, struct sockaddr *);
+void    ssh_kex2(char *, struct sockaddr *, u_short);
+
+void    ssh_userauth1(const char *, const char *, char *, Sensitive *);
+void    ssh_userauth2(const char *, const char *, char *, Sensitive *);
+
+void    ssh_put_password(char *);
+int     ssh_local_cmd(const char *);
+
+/*
+ * Macros to raise/lower permissions.
+ */
+#define PRIV_START do {                                        \
+       int save_errno = errno;                         \
+       if (seteuid(original_effective_uid) != 0)       \
+               fatal("PRIV_START: seteuid: %s",        \
+                   strerror(errno));                   \
+       errno = save_errno;                             \
+} while (0)
+
+#define PRIV_END do {                                  \
+       int save_errno = errno;                         \
+       if (seteuid(original_real_uid) != 0)            \
+               fatal("PRIV_END: seteuid: %s",          \
+                   strerror(errno));                   \
+       errno = save_errno;                             \
+} while (0)
diff --git a/sshconnect1.c b/sshconnect1.c
new file mode 100644 (file)
index 0000000..fd07bbf
--- /dev/null
@@ -0,0 +1,753 @@
+/* $OpenBSD: sshconnect1.c,v 1.70 2006/11/06 21:25:28 markus Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "rsa.h"
+#include "buffer.h"
+#include "packet.h"
+#include "key.h"
+#include "cipher.h"
+#include "kex.h"
+#include "uidswap.h"
+#include "log.h"
+#include "readconf.h"
+#include "authfd.h"
+#include "sshconnect.h"
+#include "authfile.h"
+#include "misc.h"
+#include "canohost.h"
+#include "hostfile.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;
+       Key *key;
+       BIGNUM *challenge;
+
+       /* Get connection to the agent. */
+       auth = ssh_get_authentication_connection();
+       if (!auth)
+               return 0;
+
+       if ((challenge = BN_new()) == NULL)
+               fatal("try_agent_authentication: BN_new failed");
+       /* 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();
+
+               /* 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);
+               packet_check_eom();
+
+               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.
+                        */
+                       logit("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();
+
+               /* 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 || (u_int)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, perm_ok = 1, type, quit;
+
+       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();
+
+       /*
+        * 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. */
+       if ((challenge = BN_new()) == NULL)
+               fatal("try_rsa_authentication: BN_new failed");
+       packet_get_bignum(challenge);
+       packet_check_eom();
+
+       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,
+                   &perm_ok);
+       if (private == NULL && !options.batch_mode && perm_ok) {
+               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, 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 && perm_ok)
+                       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(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();
+       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;
+
+       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();
+
+       /* 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. */
+       if ((challenge = BN_new()) == NULL)
+               fatal("try_rhosts_rsa_authentication: BN_new failed");
+       packet_get_bignum(challenge);
+       packet_check_eom();
+
+       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();
+       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;
+}
+
+/*
+ * 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;
+       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();
+               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_check_eom();
+               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)
+                       logit("WARNING: Encryption is disabled! "
+                           "Response 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();
+               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;
+       char *password;
+
+       debug("Doing password authentication.");
+       if (options.cipher == SSH_CIPHER_NONE)
+               logit("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();
+               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;
+       Key *host_key, *server_key;
+       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;
+       u_int32_t rnd = 0;
+
+       debug("Waiting for server public key.");
+
+       /* Wait for a public key packet from the server. */
+       packet_read_expect(SSH_SMSG_PUBLIC_KEY);
+
+       /* Get cookie from the packet. */
+       for (i = 0; i < 8; i++)
+               cookie[i] = packet_get_char();
+
+       /* Get the public key. */
+       server_key = key_new(KEY_RSA1);
+       bits = packet_get_int();
+       packet_get_bignum(server_key->rsa->e);
+       packet_get_bignum(server_key->rsa->n);
+
+       rbits = BN_num_bits(server_key->rsa->n);
+       if (bits != rbits) {
+               logit("Warning: Server lies about size of server public key: "
+                   "actual size is %d bits vs. announced %d.", rbits, bits);
+               logit("Warning: This may be due to an old implementation of ssh.");
+       }
+       /* Get the host key. */
+       host_key = key_new(KEY_RSA1);
+       bits = packet_get_int();
+       packet_get_bignum(host_key->rsa->e);
+       packet_get_bignum(host_key->rsa->n);
+
+       rbits = BN_num_bits(host_key->rsa->n);
+       if (bits != rbits) {
+               logit("Warning: Server lies about size of server host key: "
+                   "actual size is %d bits vs. announced %d.", rbits, bits);
+               logit("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();
+       packet_check_eom();
+
+       debug("Received server public key (%d bits) and host key (%d bits).",
+           BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n));
+
+       if (verify_host_key(host, hostaddr, host_key) == -1)
+               fatal("Host key verification failed.");
+
+       client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
+
+       derive_ssh1_session_id(host_key->rsa->n, server_key->rsa->n, cookie, session_id);
+
+       /* 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)
+                       rnd = arc4random();
+               session_key[i] = rnd & 0xff;
+               rnd >>= 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.
+        */
+       if ((key = BN_new()) == NULL)
+               fatal("ssh_kex: BN_new failed");
+       if (BN_set_word(key, 0) == 0)
+               fatal("ssh_kex: BN_set_word failed");
+       for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) {
+               if (BN_lshift(key, key, 8) == 0)
+                       fatal("ssh_kex: BN_lshift failed");
+               if (i < 16) {
+                       if (BN_add_word(key, session_key[i] ^ session_id[i])
+                           == 0)
+                               fatal("ssh_kex: BN_add_word failed");
+               } else {
+                       if (BN_add_word(key, session_key[i]) == 0)
+                               fatal("ssh_kex: BN_add_word failed");
+               }
+       }
+
+       /*
+        * Encrypt the integer using the public key and host key of the
+        * server (key with smaller modulus first).
+        */
+       if (BN_cmp(server_key->rsa->n, host_key->rsa->n) < 0) {
+               /* Public key has smaller modulus. */
+               if (BN_num_bits(host_key->rsa->n) <
+                   BN_num_bits(server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("respond_to_rsa_challenge: host_key %d < server_key %d + "
+                           "SSH_KEY_BITS_RESERVED %d",
+                           BN_num_bits(host_key->rsa->n),
+                           BN_num_bits(server_key->rsa->n),
+                           SSH_KEY_BITS_RESERVED);
+               }
+               rsa_public_encrypt(key, key, server_key->rsa);
+               rsa_public_encrypt(key, key, host_key->rsa);
+       } else {
+               /* Host key has smaller modulus (or they are equal). */
+               if (BN_num_bits(server_key->rsa->n) <
+                   BN_num_bits(host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+                       fatal("respond_to_rsa_challenge: server_key %d < host_key %d + "
+                           "SSH_KEY_BITS_RESERVED %d",
+                           BN_num_bits(server_key->rsa->n),
+                           BN_num_bits(host_key->rsa->n),
+                           SSH_KEY_BITS_RESERVED);
+               }
+               rsa_public_encrypt(key, key, host_key->rsa);
+               rsa_public_encrypt(key, key, server_key->rsa);
+       }
+
+       /* Destroy the public keys since we no longer need them. */
+       key_free(server_key);
+       key_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_INVALID ||
+           !(cipher_mask_ssh1(1) & (1 << options.cipher))) {
+               logit("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(SSH_SMSG_SUCCESS);
+
+       debug("Received encrypted confirmation.");
+}
+
+/*
+ * Authenticate user
+ */
+void
+ssh_userauth1(const char *local_user, const char *server_user, char *host,
+    Sensitive *sensitive)
+{
+       int i, type;
+
+       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();
+
+       /* 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);
+
+       /*
+        * 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 < sensitive->nkeys; i++) {
+                       if (sensitive->keys[i] != NULL &&
+                           sensitive->keys[i]->type == KEY_RSA1 &&
+                           try_rhosts_rsa_authentication(local_user,
+                           sensitive->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:
+       return; /* need statement after label */
+}
diff --git a/sshconnect2.c b/sshconnect2.c
new file mode 100644 (file)
index 0000000..3cb9b10
--- /dev/null
@@ -0,0 +1,1916 @@
+/* $OpenBSD: sshconnect2.c,v 1.186 2010/11/29 23:45:51 djm Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2008 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H)
+#include <vis.h>
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh2.h"
+#include "buffer.h"
+#include "packet.h"
+#include "compat.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include "myproposal.h"
+#include "sshconnect.h"
+#include "authfile.h"
+#include "dh.h"
+#include "authfd.h"
+#include "log.h"
+#include "readconf.h"
+#include "misc.h"
+#include "match.h"
+#include "dispatch.h"
+#include "canohost.h"
+#include "msg.h"
+#include "pathnames.h"
+#include "uidswap.h"
+#include "hostfile.h"
+#include "schnorr.h"
+#include "jpake.h"
+
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
+/* import */
+extern char *client_version_string;
+extern char *server_version_string;
+extern Options options;
+
+/*
+ * SSH2 key exchange
+ */
+
+u_char *session_id2 = NULL;
+u_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;
+}
+
+static char *
+order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
+{
+       char *oavail, *avail, *first, *last, *alg, *hostname, *ret;
+       size_t maxlen;
+       struct hostkeys *hostkeys;
+       int ktype;
+
+       /* Find all hostkeys for this hostname */
+       get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL);
+       hostkeys = init_hostkeys();
+       load_hostkeys(hostkeys, hostname, options.user_hostfile2);
+       load_hostkeys(hostkeys, hostname, options.system_hostfile2);
+       load_hostkeys(hostkeys, hostname, options.user_hostfile);
+       load_hostkeys(hostkeys, hostname, options.system_hostfile);
+
+       oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG);
+       maxlen = strlen(avail) + 1;
+       first = xmalloc(maxlen);
+       last = xmalloc(maxlen);
+       *first = *last = '\0';
+
+#define ALG_APPEND(to, from) \
+       do { \
+               if (*to != '\0') \
+                       strlcat(to, ",", maxlen); \
+               strlcat(to, from, maxlen); \
+       } while (0)
+
+       while ((alg = strsep(&avail, ",")) && *alg != '\0') {
+               if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC)
+                       fatal("%s: unknown alg %s", __func__, alg);
+               if (lookup_key_in_hostkeys_by_type(hostkeys,
+                   key_type_plain(ktype), NULL))
+                       ALG_APPEND(first, alg);
+               else
+                       ALG_APPEND(last, alg);
+       }
+#undef ALG_APPEND
+       xasprintf(&ret, "%s%s%s", first, *first == '\0' ? "" : ",", last);
+       if (*first != '\0')
+               debug3("%s: prefer hostkeyalgs: %s", __func__, first);
+
+       xfree(first);
+       xfree(last);
+       xfree(hostname);
+       xfree(oavail);
+       free_hostkeys(hostkeys);
+
+       return ret;
+}
+
+void
+ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
+{
+       Kex *kex;
+
+       xxx_host = host;
+       xxx_hostaddr = hostaddr;
+
+       if (options.ciphers == (char *)-1) {
+               logit("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@openssh.com,zlib,none";
+       } else {
+               myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+               myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib";
+       }
+       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;
+       else {
+               /* Prefer algorithms that we already have keys for */
+               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+                   order_hostkeyalgs(host, hostaddr, port);
+       }
+       if (options.kex_algorithms != NULL)
+               myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
+
+       if (options.rekey_limit)
+               packet_set_rekey_limit((u_int32_t)options.rekey_limit);
+
+       /* start key exchange */
+       kex = kex_setup(myproposal);
+       kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
+       kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
+       kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
+       kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
+       kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
+       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);
+
+       if (options.use_roaming && !kex->roaming) {
+               debug("Roaming not allowed by server");
+               options.use_roaming = 0;
+       }
+
+       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
+}
+
+/*
+ * Authenticate user
+ */
+
+typedef struct Authctxt Authctxt;
+typedef struct Authmethod Authmethod;
+typedef struct identity Identity;
+typedef struct idlist Idlist;
+
+struct identity {
+       TAILQ_ENTRY(identity) next;
+       AuthenticationConnection *ac;   /* set if agent supports key */
+       Key     *key;                   /* public/private key */
+       char    *filename;              /* comment for agent-only keys */
+       int     tried;
+       int     isprivate;              /* key points to the private key */
+};
+TAILQ_HEAD(idlist, identity);
+
+struct Authctxt {
+       const char *server_user;
+       const char *local_user;
+       const char *host;
+       const char *service;
+       Authmethod *method;
+       sig_atomic_t success;
+       char *authlist;
+       /* pubkey */
+       Idlist keys;
+       AuthenticationConnection *agent;
+       /* hostbased */
+       Sensitive *sensitive;
+       /* kbd-interactive */
+       int info_req_seen;
+       /* generic */
+       void *methoddata;
+};
+struct Authmethod {
+       char    *name;          /* string to compare against server's list */
+       int     (*userauth)(Authctxt *authctxt);
+       void    (*cleanup)(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, u_int32_t, void *);
+void   input_userauth_success_unexpected(int, u_int32_t, void *);
+void   input_userauth_failure(int, u_int32_t, void *);
+void   input_userauth_banner(int, u_int32_t, void *);
+void   input_userauth_error(int, u_int32_t, void *);
+void   input_userauth_info_req(int, u_int32_t, void *);
+void   input_userauth_pk_ok(int, u_int32_t, void *);
+void   input_userauth_passwd_changereq(int, u_int32_t, void *);
+void   input_userauth_jpake_server_step1(int, u_int32_t, void *);
+void   input_userauth_jpake_server_step2(int, u_int32_t, void *);
+void   input_userauth_jpake_server_confirm(int, u_int32_t, void *);
+
+int    userauth_none(Authctxt *);
+int    userauth_pubkey(Authctxt *);
+int    userauth_passwd(Authctxt *);
+int    userauth_kbdint(Authctxt *);
+int    userauth_hostbased(Authctxt *);
+int    userauth_jpake(Authctxt *);
+
+void   userauth_jpake_cleanup(Authctxt *);
+
+#ifdef GSSAPI
+int    userauth_gssapi(Authctxt *authctxt);
+void   input_gssapi_response(int type, u_int32_t, void *);
+void   input_gssapi_token(int type, u_int32_t, void *);
+void   input_gssapi_hash(int type, u_int32_t, void *);
+void   input_gssapi_error(int, u_int32_t, void *);
+void   input_gssapi_errtok(int, u_int32_t, void *);
+#endif
+
+void   userauth(Authctxt *, char *);
+
+static int sign_and_send_pubkey(Authctxt *, Identity *);
+static void pubkey_prepare(Authctxt *);
+static void pubkey_cleanup(Authctxt *);
+static Key *load_identity_file(char *);
+
+static Authmethod *authmethod_get(char *authlist);
+static Authmethod *authmethod_lookup(const char *name);
+static char *authmethods_get(void);
+
+Authmethod authmethods[] = {
+#ifdef GSSAPI
+       {"gssapi-with-mic",
+               userauth_gssapi,
+               NULL,
+               &options.gss_authentication,
+               NULL},
+#endif
+       {"hostbased",
+               userauth_hostbased,
+               NULL,
+               &options.hostbased_authentication,
+               NULL},
+       {"publickey",
+               userauth_pubkey,
+               NULL,
+               &options.pubkey_authentication,
+               NULL},
+#ifdef JPAKE
+       {"jpake-01@openssh.com",
+               userauth_jpake,
+               userauth_jpake_cleanup,
+               &options.zero_knowledge_password_authentication,
+               &options.batch_mode},
+#endif
+       {"keyboard-interactive",
+               userauth_kbdint,
+               NULL,
+               &options.kbd_interactive_authentication,
+               &options.batch_mode},
+       {"password",
+               userauth_passwd,
+               NULL,
+               &options.password_authentication,
+               &options.batch_mode},
+       {"none",
+               userauth_none,
+               NULL,
+               NULL,
+               NULL},
+       {NULL, NULL, NULL, NULL, NULL}
+};
+
+void
+ssh_userauth2(const char *local_user, const char *server_user, char *host,
+    Sensitive *sensitive)
+{
+       Authctxt authctxt;
+       int type;
+
+       if (options.challenge_response_authentication)
+               options.kbd_interactive_authentication = 1;
+
+       packet_start(SSH2_MSG_SERVICE_REQUEST);
+       packet_put_cstring("ssh-userauth");
+       packet_send();
+       debug("SSH2_MSG_SERVICE_REQUEST sent");
+       packet_write_wait();
+       type = packet_read();
+       if (type != SSH2_MSG_SERVICE_ACCEPT)
+               fatal("Server denied authentication request: %d", type);
+       if (packet_remaining() > 0) {
+               char *reply = packet_get_string(NULL);
+               debug2("service_accept: %s", reply);
+               xfree(reply);
+       } else {
+               debug2("buggy server: service_accept w/o service");
+       }
+       packet_check_eom();
+       debug("SSH2_MSG_SERVICE_ACCEPT received");
+
+       if (options.preferred_authentications == NULL)
+               options.preferred_authentications = authmethods_get();
+
+       /* setup authentication context */
+       memset(&authctxt, 0, sizeof(authctxt));
+       pubkey_prepare(&authctxt);
+       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.methoddata = NULL;
+       authctxt.sensitive = sensitive;
+       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 */
+
+       pubkey_cleanup(&authctxt);
+       dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
+
+       debug("Authentication succeeded (%s).", authctxt.method->name);
+}
+
+void
+userauth(Authctxt *authctxt, char *authlist)
+{
+       if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
+               authctxt->method->cleanup(authctxt);
+
+       if (authctxt->methoddata) {
+               xfree(authctxt->methoddata);
+               authctxt->methoddata = NULL;
+       }
+       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;
+
+               /* reset the per method handler */
+               dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
+                   SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
+
+               /* and try new 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;
+               }
+       }
+}
+
+/* ARGSUSED */
+void
+input_userauth_error(int type, u_int32_t seq, void *ctxt)
+{
+       fatal("input_userauth_error: bad message during authentication: "
+           "type %d", type);
+}
+
+/* ARGSUSED */
+void
+input_userauth_banner(int type, u_int32_t seq, void *ctxt)
+{
+       char *msg, *raw, *lang;
+       u_int len;
+
+       debug3("input_userauth_banner");
+       raw = packet_get_string(&len);
+       lang = packet_get_string(NULL);
+       if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) {
+               if (len > 65536)
+                       len = 65536;
+               msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */
+               strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH);
+               fprintf(stderr, "%s", msg);
+               xfree(msg);
+       }
+       xfree(raw);
+       xfree(lang);
+}
+
+/* ARGSUSED */
+void
+input_userauth_success(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+
+       if (authctxt == NULL)
+               fatal("input_userauth_success: no authentication context");
+       if (authctxt->authlist) {
+               xfree(authctxt->authlist);
+               authctxt->authlist = NULL;
+       }
+       if (authctxt->method != NULL && authctxt->method->cleanup != NULL)
+               authctxt->method->cleanup(authctxt);
+       if (authctxt->methoddata) {
+               xfree(authctxt->methoddata);
+               authctxt->methoddata = NULL;
+       }
+       authctxt->success = 1;                  /* break out */
+}
+
+void
+input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+
+       if (authctxt == NULL)
+               fatal("%s: no authentication context", __func__);
+
+       fatal("Unexpected authentication success during %s.",
+           authctxt->method->name);
+}
+
+/* ARGSUSED */
+void
+input_userauth_failure(int type, u_int32_t seq, 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_check_eom();
+
+       if (partial != 0)
+               logit("Authenticated with partial success.");
+       debug("Authentications that can continue: %s", authlist);
+
+       userauth(authctxt, authlist);
+}
+
+/* ARGSUSED */
+void
+input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Key *key = NULL;
+       Identity *id = NULL;
+       Buffer b;
+       int pktype, sent = 0;
+       u_int alen, blen;
+       char *pkalg, *fp;
+       u_char *pkblob;
+
+       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_check_eom();
+
+       debug("Server accepts key: pkalg %s blen %u", pkalg, blen);
+
+       if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) {
+               debug("unknown pkalg %s", pkalg);
+               goto done;
+       }
+       if ((key = key_from_blob(pkblob, blen)) == NULL) {
+               debug("no key from blob. pkalg %s", pkalg);
+               goto done;
+       }
+       if (key->type != pktype) {
+               error("input_userauth_pk_ok: type mismatch "
+                   "for decoded key (received %d, expected %d)",
+                   key->type, pktype);
+               goto done;
+       }
+       fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+       debug2("input_userauth_pk_ok: fp %s", fp);
+       xfree(fp);
+
+       /*
+        * search keys in the reverse order, because last candidate has been
+        * moved to the end of the queue.  this also avoids confusion by
+        * duplicate keys
+        */
+       TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) {
+               if (key_equal(key, id->key)) {
+                       sent = sign_and_send_pubkey(authctxt, id);
+                       break;
+               }
+       }
+done:
+       if (key != NULL)
+               key_free(key);
+       xfree(pkalg);
+       xfree(pkblob);
+
+       /* try another method if we did not send a packet */
+       if (sent == 0)
+               userauth(authctxt, NULL);
+}
+
+#ifdef GSSAPI
+int
+userauth_gssapi(Authctxt *authctxt)
+{
+       Gssctxt *gssctxt = NULL;
+       static gss_OID_set gss_supported = NULL;
+       static u_int mech = 0;
+       OM_uint32 min;
+       int ok = 0;
+
+       /* Try one GSSAPI method at a time, rather than sending them all at
+        * once. */
+
+       if (gss_supported == NULL)
+               gss_indicate_mechs(&min, &gss_supported);
+
+       /* Check to see if the mechanism is usable before we offer it */
+       while (mech < gss_supported->count && !ok) {
+               /* My DER encoding requires length<128 */
+               if (gss_supported->elements[mech].length < 128 &&
+                   ssh_gssapi_check_mechanism(&gssctxt, 
+                   &gss_supported->elements[mech], authctxt->host)) {
+                       ok = 1; /* Mechanism works */
+               } else {
+                       mech++;
+               }
+       }
+
+       if (!ok)
+               return 0;
+
+       authctxt->methoddata=(void *)gssctxt;
+
+       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_int(1);
+
+       packet_put_int((gss_supported->elements[mech].length) + 2);
+       packet_put_char(SSH_GSS_OIDTYPE);
+       packet_put_char(gss_supported->elements[mech].length);
+       packet_put_raw(gss_supported->elements[mech].elements,
+           gss_supported->elements[mech].length);
+
+       packet_send();
+
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+
+       mech++; /* Move along to next candidate */
+
+       return 1;
+}
+
+static OM_uint32
+process_gssapi_token(void *ctxt, gss_buffer_t recv_tok)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt = authctxt->methoddata;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc gssbuf;
+       OM_uint32 status, ms, flags;
+       Buffer b;
+
+       status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+           recv_tok, &send_tok, &flags);
+
+       if (send_tok.length > 0) {
+               if (GSS_ERROR(status))
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+               else
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+
+               packet_put_string(send_tok.value, send_tok.length);
+               packet_send();
+               gss_release_buffer(&ms, &send_tok);
+       }
+
+       if (status == GSS_S_COMPLETE) {
+               /* send either complete or MIC, depending on mechanism */
+               if (!(flags & GSS_C_INTEG_FLAG)) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+                       packet_send();
+               } else {
+                       ssh_gssapi_buildmic(&b, authctxt->server_user,
+                           authctxt->service, "gssapi-with-mic");
+
+                       gssbuf.value = buffer_ptr(&b);
+                       gssbuf.length = buffer_len(&b);
+
+                       status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic);
+
+                       if (!GSS_ERROR(status)) {
+                               packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC);
+                               packet_put_string(mic.value, mic.length);
+
+                               packet_send();
+                       }
+
+                       buffer_free(&b);
+                       gss_release_buffer(&ms, &mic);
+               }
+       }
+
+       return status;
+}
+
+/* ARGSUSED */
+void
+input_gssapi_response(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       int oidlen;
+       char *oidv;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+
+       /* Setup our OID */
+       oidv = packet_get_string(&oidlen);
+
+       if (oidlen <= 2 ||
+           oidv[0] != SSH_GSS_OIDTYPE ||
+           oidv[1] != oidlen - 2) {
+               xfree(oidv);
+               debug("Badly encoded mechanism OID received");
+               userauth(authctxt, NULL);
+               return;
+       }
+
+       if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2))
+               fatal("Server returned different OID than expected");
+
+       packet_check_eom();
+
+       xfree(oidv);
+
+       if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) {
+               /* Start again with next method on list */
+               debug("Trying to start again");
+               userauth(authctxt, NULL);
+               return;
+       }
+}
+
+/* ARGSUSED */
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       gss_buffer_desc recv_tok;
+       OM_uint32 status;
+       u_int slen;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+
+       recv_tok.value = packet_get_string(&slen);
+       recv_tok.length = slen; /* safe typecast */
+
+       packet_check_eom();
+
+       status = process_gssapi_token(ctxt, &recv_tok);
+
+       xfree(recv_tok.value);
+
+       if (GSS_ERROR(status)) {
+               /* Start again with the next method in the list */
+               userauth(authctxt, NULL);
+               return;
+       }
+}
+
+/* ARGSUSED */
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc recv_tok;
+       OM_uint32 status, ms;
+       u_int len;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+
+       recv_tok.value = packet_get_string(&len);
+       recv_tok.length = len;
+
+       packet_check_eom();
+
+       /* Stick it into GSSAPI and see what it says */
+       status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+           &recv_tok, &send_tok, NULL);
+
+       xfree(recv_tok.value);
+       gss_release_buffer(&ms, &send_tok);
+
+       /* Server will be returning a failed packet after this one */
+}
+
+/* ARGSUSED */
+void
+input_gssapi_error(int type, u_int32_t plen, void *ctxt)
+{
+       OM_uint32 maj, min;
+       char *msg;
+       char *lang;
+
+       maj=packet_get_int();
+       min=packet_get_int();
+       msg=packet_get_string(NULL);
+       lang=packet_get_string(NULL);
+
+       packet_check_eom();
+
+       debug("Server GSSAPI Error:\n%s", msg);
+       xfree(msg);
+       xfree(lang);
+}
+#endif /* GSSAPI */
+
+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[150];
+       char *password;
+       const char *host = options.host_key_alias ?  options.host_key_alias :
+           authctxt->host;
+
+       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, 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();
+
+       dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
+           &input_userauth_passwd_changereq);
+
+       return 1;
+}
+
+/*
+ * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST
+ */
+/* ARGSUSED */
+void
+input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       char *info, *lang, *password = NULL, *retype = NULL;
+       char prompt[150];
+       const char *host = options.host_key_alias ? options.host_key_alias :
+           authctxt->host;
+
+       debug2("input_userauth_passwd_changereq");
+
+       if (authctxt == NULL)
+               fatal("input_userauth_passwd_changereq: "
+                   "no authentication context");
+
+       info = packet_get_string(NULL);
+       lang = packet_get_string(NULL);
+       if (strlen(info) > 0)
+               logit("%s", info);
+       xfree(info);
+       xfree(lang);
+       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(1);                     /* additional info */
+       snprintf(prompt, sizeof(prompt),
+           "Enter %.30s@%.128s's old password: ",
+           authctxt->server_user, host);
+       password = read_passphrase(prompt, 0);
+       packet_put_cstring(password);
+       memset(password, 0, strlen(password));
+       xfree(password);
+       password = NULL;
+       while (password == NULL) {
+               snprintf(prompt, sizeof(prompt),
+                   "Enter %.30s@%.128s's new password: ",
+                   authctxt->server_user, host);
+               password = read_passphrase(prompt, RP_ALLOW_EOF);
+               if (password == NULL) {
+                       /* bail out */
+                       return;
+               }
+               snprintf(prompt, sizeof(prompt),
+                   "Retype %.30s@%.128s's new password: ",
+                   authctxt->server_user, host);
+               retype = read_passphrase(prompt, 0);
+               if (strcmp(password, retype) != 0) {
+                       memset(password, 0, strlen(password));
+                       xfree(password);
+                       logit("Mismatch; try again, EOF to quit.");
+                       password = NULL;
+               }
+               memset(retype, 0, strlen(retype));
+               xfree(retype);
+       }
+       packet_put_cstring(password);
+       memset(password, 0, strlen(password));
+       xfree(password);
+       packet_add_padding(64);
+       packet_send();
+
+       dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ,
+           &input_userauth_passwd_changereq);
+}
+
+#ifdef JPAKE
+static char *
+pw_encrypt(const char *password, const char *crypt_scheme, const char *salt)
+{
+       /* OpenBSD crypt(3) handles all of these */
+       if (strcmp(crypt_scheme, "crypt") == 0 ||
+           strcmp(crypt_scheme, "bcrypt") == 0 ||
+           strcmp(crypt_scheme, "md5crypt") == 0 ||
+           strcmp(crypt_scheme, "crypt-extended") == 0)
+               return xstrdup(crypt(password, salt));
+       error("%s: unsupported password encryption scheme \"%.100s\"",
+           __func__, crypt_scheme);
+       return NULL;
+}
+
+static BIGNUM *
+jpake_password_to_secret(Authctxt *authctxt, const char *crypt_scheme,
+    const char *salt)
+{
+       char prompt[256], *password, *crypted;
+       u_char *secret;
+       u_int secret_len;
+       BIGNUM *ret;
+
+       snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password (JPAKE): ",
+           authctxt->server_user, authctxt->host);
+       password = read_passphrase(prompt, 0);
+
+       if ((crypted = pw_encrypt(password, crypt_scheme, salt)) == NULL) {
+               logit("Disabling %s authentication", authctxt->method->name);
+               authctxt->method->enabled = NULL;
+               /* Continue with an empty password to fail gracefully */
+               crypted = xstrdup("");
+       }
+
+#ifdef JPAKE_DEBUG
+       debug3("%s: salt = %s", __func__, salt);
+       debug3("%s: scheme = %s", __func__, crypt_scheme);
+       debug3("%s: crypted = %s", __func__, crypted);
+#endif
+
+       if (hash_buffer(crypted, strlen(crypted), EVP_sha256(),
+           &secret, &secret_len) != 0)
+               fatal("%s: hash_buffer", __func__);
+
+       bzero(password, strlen(password));
+       bzero(crypted, strlen(crypted));
+       xfree(password);
+       xfree(crypted);
+
+       if ((ret = BN_bin2bn(secret, secret_len, NULL)) == NULL)
+               fatal("%s: BN_bin2bn (secret)", __func__);
+       bzero(secret, secret_len);
+       xfree(secret);
+
+       return ret;
+}
+
+/* ARGSUSED */
+void
+input_userauth_jpake_server_step1(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->methoddata;
+       u_char *x3_proof, *x4_proof, *x2_s_proof;
+       u_int x3_proof_len, x4_proof_len, x2_s_proof_len;
+       char *crypt_scheme, *salt;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, NULL);
+
+       if ((pctx->g_x3 = BN_new()) == NULL ||
+           (pctx->g_x4 = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       /* Fetch step 1 values */
+       crypt_scheme = packet_get_string(NULL);
+       salt = packet_get_string(NULL);
+       pctx->server_id = packet_get_string(&pctx->server_id_len);
+       packet_get_bignum2(pctx->g_x3);
+       packet_get_bignum2(pctx->g_x4);
+       x3_proof = packet_get_string(&x3_proof_len);
+       x4_proof = packet_get_string(&x4_proof_len);
+       packet_check_eom();
+
+       JPAKE_DEBUG_CTX((pctx, "step 1 received in %s", __func__));
+
+       /* Obtain password and derive secret */
+       pctx->s = jpake_password_to_secret(authctxt, crypt_scheme, salt);
+       bzero(crypt_scheme, strlen(crypt_scheme));
+       bzero(salt, strlen(salt));
+       xfree(crypt_scheme);
+       xfree(salt);
+       JPAKE_DEBUG_BN((pctx->s, "%s: s = ", __func__));
+
+       /* Calculate step 2 values */
+       jpake_step2(pctx->grp, pctx->s, pctx->g_x1,
+           pctx->g_x3, pctx->g_x4, pctx->x2,
+           pctx->server_id, pctx->server_id_len,
+           pctx->client_id, pctx->client_id_len,
+           x3_proof, x3_proof_len,
+           x4_proof, x4_proof_len,
+           &pctx->a,
+           &x2_s_proof, &x2_s_proof_len);
+
+       bzero(x3_proof, x3_proof_len);
+       bzero(x4_proof, x4_proof_len);
+       xfree(x3_proof);
+       xfree(x4_proof);
+
+       JPAKE_DEBUG_CTX((pctx, "step 2 sending in %s", __func__));
+
+       /* Send values for step 2 */
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP2);
+       packet_put_bignum2(pctx->a);
+       packet_put_string(x2_s_proof, x2_s_proof_len);
+       packet_send();
+
+       bzero(x2_s_proof, x2_s_proof_len);
+       xfree(x2_s_proof);
+
+       /* Expect step 2 packet from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2,
+           input_userauth_jpake_server_step2);
+}
+
+/* ARGSUSED */
+void
+input_userauth_jpake_server_step2(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->methoddata;
+       u_char *x4_s_proof;
+       u_int x4_s_proof_len;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP2, NULL);
+
+       if ((pctx->b = BN_new()) == NULL)
+               fatal("%s: BN_new", __func__);
+
+       /* Fetch step 2 values */
+       packet_get_bignum2(pctx->b);
+       x4_s_proof = packet_get_string(&x4_s_proof_len);
+       packet_check_eom();
+
+       JPAKE_DEBUG_CTX((pctx, "step 2 received in %s", __func__));
+
+       /* Derive shared key and calculate confirmation hash */
+       jpake_key_confirm(pctx->grp, pctx->s, pctx->b,
+           pctx->x2, pctx->g_x1, pctx->g_x2, pctx->g_x3, pctx->g_x4,
+           pctx->client_id, pctx->client_id_len,
+           pctx->server_id, pctx->server_id_len,
+           session_id2, session_id2_len,
+           x4_s_proof, x4_s_proof_len,
+           &pctx->k,
+           &pctx->h_k_cid_sessid, &pctx->h_k_cid_sessid_len);
+
+       bzero(x4_s_proof, x4_s_proof_len);
+       xfree(x4_s_proof);
+
+       JPAKE_DEBUG_CTX((pctx, "confirm sending in %s", __func__));
+
+       /* Send key confirmation proof */
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_CONFIRM);
+       packet_put_string(pctx->h_k_cid_sessid, pctx->h_k_cid_sessid_len);
+       packet_send();
+
+       /* Expect confirmation from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM,
+           input_userauth_jpake_server_confirm);
+}
+
+/* ARGSUSED */
+void
+input_userauth_jpake_server_confirm(int type, u_int32_t seq, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       struct jpake_ctx *pctx = authctxt->methoddata;
+
+       /* Disable this message */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_CONFIRM, NULL);
+
+       pctx->h_k_sid_sessid = packet_get_string(&pctx->h_k_sid_sessid_len);
+       packet_check_eom();
+
+       JPAKE_DEBUG_CTX((pctx, "confirm received in %s", __func__));
+
+       /* Verify expected confirmation hash */
+       if (jpake_check_confirm(pctx->k,
+           pctx->server_id, pctx->server_id_len,
+           session_id2, session_id2_len,
+           pctx->h_k_sid_sessid, pctx->h_k_sid_sessid_len) == 1)
+               debug("%s: %s success", __func__, authctxt->method->name);
+       else {
+               debug("%s: confirmation mismatch", __func__);
+               /* XXX stash this so if auth succeeds then we can warn/kill */
+       }
+
+       userauth_jpake_cleanup(authctxt);
+}
+#endif /* JPAKE */
+
+static int
+identity_sign(Identity *id, u_char **sigp, u_int *lenp,
+    u_char *data, u_int datalen)
+{
+       Key *prv;
+       int ret;
+
+       /* the agent supports this key */
+       if (id->ac)
+               return (ssh_agent_sign(id->ac, id->key, sigp, lenp,
+                   data, datalen));
+       /*
+        * we have already loaded the private key or
+        * the private key is stored in external hardware
+        */
+       if (id->isprivate || (id->key->flags & KEY_FLAG_EXT))
+               return (key_sign(id->key, sigp, lenp, data, datalen));
+       /* load the private key from the file */
+       if ((prv = load_identity_file(id->filename)) == NULL)
+               return (-1);
+       ret = key_sign(prv, sigp, lenp, data, datalen);
+       key_free(prv);
+       return (ret);
+}
+
+static int
+sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
+{
+       Buffer b;
+       u_char *blob, *signature;
+       u_int bloblen, slen;
+       u_int skip = 0;
+       int ret = -1;
+       int have_sig = 1;
+       char *fp;
+
+       fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+       debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
+       xfree(fp);
+
+       if (key_to_blob(id->key, &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(id->key));
+       }
+       buffer_put_string(&b, blob, bloblen);
+
+       /* generate signature */
+       ret = identity_sign(id, &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(id->key));
+               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, Identity *id)
+{
+       u_char *blob;
+       u_int bloblen, have_sig = 0;
+
+       debug3("send_pubkey_test");
+
+       if (key_to_blob(id->key, &blob, &bloblen) == 0) {
+               /* we cannot handle this key */
+               debug3("send_pubkey_test: cannot handle key");
+               return 0;
+       }
+       /* register callback for USERAUTH_PK_OK message */
+       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(id->key));
+       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 perm_ok = 0, 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, &perm_ok);
+       if (!perm_ok)
+               return 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, 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;
+}
+
+/*
+ * try keys in the following order:
+ *     1. agent keys that are found in the config file
+ *     2. other agent keys
+ *     3. keys that are only listed in the config file
+ */
+static void
+pubkey_prepare(Authctxt *authctxt)
+{
+       Identity *id;
+       Idlist agent, files, *preferred;
+       Key *key;
+       AuthenticationConnection *ac;
+       char *comment;
+       int i, found;
+
+       TAILQ_INIT(&agent);     /* keys from the agent */
+       TAILQ_INIT(&files);     /* keys from the config file */
+       preferred = &authctxt->keys;
+       TAILQ_INIT(preferred);  /* preferred order of keys */
+
+       /* list of keys stored in the filesystem */
+       for (i = 0; i < options.num_identity_files; i++) {
+               key = options.identity_keys[i];
+               if (key && key->type == KEY_RSA1)
+                       continue;
+               if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER)
+                       continue;
+               options.identity_keys[i] = NULL;
+               id = xcalloc(1, sizeof(*id));
+               id->key = key;
+               id->filename = xstrdup(options.identity_files[i]);
+               TAILQ_INSERT_TAIL(&files, id, next);
+       }
+       /* list of keys supported by the agent */
+       if ((ac = ssh_get_authentication_connection())) {
+               for (key = ssh_get_first_identity(ac, &comment, 2);
+                   key != NULL;
+                   key = ssh_get_next_identity(ac, &comment, 2)) {
+                       found = 0;
+                       TAILQ_FOREACH(id, &files, next) {
+                               /* agent keys from the config file are preferred */
+                               if (key_equal(key, id->key)) {
+                                       key_free(key);
+                                       xfree(comment);
+                                       TAILQ_REMOVE(&files, id, next);
+                                       TAILQ_INSERT_TAIL(preferred, id, next);
+                                       id->ac = ac;
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (!found && !options.identities_only) {
+                               id = xcalloc(1, sizeof(*id));
+                               id->key = key;
+                               id->filename = comment;
+                               id->ac = ac;
+                               TAILQ_INSERT_TAIL(&agent, id, next);
+                       }
+               }
+               /* append remaining agent keys */
+               for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) {
+                       TAILQ_REMOVE(&agent, id, next);
+                       TAILQ_INSERT_TAIL(preferred, id, next);
+               }
+               authctxt->agent = ac;
+       }
+       /* append remaining keys from the config file */
+       for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) {
+               TAILQ_REMOVE(&files, id, next);
+               TAILQ_INSERT_TAIL(preferred, id, next);
+       }
+       TAILQ_FOREACH(id, preferred, next) {
+               debug2("key: %s (%p)", id->filename, id->key);
+       }
+}
+
+static void
+pubkey_cleanup(Authctxt *authctxt)
+{
+       Identity *id;
+
+       if (authctxt->agent != NULL)
+               ssh_close_authentication_connection(authctxt->agent);
+       for (id = TAILQ_FIRST(&authctxt->keys); id;
+           id = TAILQ_FIRST(&authctxt->keys)) {
+               TAILQ_REMOVE(&authctxt->keys, id, next);
+               if (id->key)
+                       key_free(id->key);
+               if (id->filename)
+                       xfree(id->filename);
+               xfree(id);
+       }
+}
+
+int
+userauth_pubkey(Authctxt *authctxt)
+{
+       Identity *id;
+       int sent = 0;
+
+       while ((id = TAILQ_FIRST(&authctxt->keys))) {
+               if (id->tried++)
+                       return (0);
+               /* move key to the end of the queue */
+               TAILQ_REMOVE(&authctxt->keys, id, next);
+               TAILQ_INSERT_TAIL(&authctxt->keys, id, next);
+               /*
+                * send a test message if we have the public key. for
+                * encrypted keys we cannot do this and have to load the
+                * private key instead
+                */
+               if (id->key && id->key->type != KEY_RSA1) {
+                       debug("Offering %s public key: %s", key_type(id->key),
+                           id->filename);
+                       sent = send_pubkey_test(authctxt, id);
+               } else if (id->key == NULL) {
+                       debug("Trying private key: %s", id->filename);
+                       id->key = load_identity_file(id->filename);
+                       if (id->key != NULL) {
+                               id->isprivate = 1;
+                               sent = sign_and_send_pubkey(authctxt, id);
+                               key_free(id->key);
+                               id->key = NULL;
+                       }
+               }
+               if (sent)
+                       return (sent);
+       }
+       return (0);
+}
+
+/*
+ * 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, u_int32_t seq, 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)
+               logit("%s", name);
+       if (strlen(inst) > 0)
+               logit("%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_check_eom(); /* done with parsing incoming message. */
+
+       packet_add_padding(64);
+       packet_send();
+}
+
+static int
+ssh_keysign(Key *key, u_char **sigp, u_int *lenp,
+    u_char *data, u_int datalen)
+{
+       Buffer b;
+       struct stat st;
+       pid_t pid;
+       int to[2], from[2], status, version = 2;
+
+       debug2("ssh_keysign called");
+
+       if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) {
+               error("ssh_keysign: not installed: %s", strerror(errno));
+               return -1;
+       }
+       if (fflush(stdout) != 0)
+               error("ssh_keysign: fflush: %s", strerror(errno));
+       if (pipe(to) < 0) {
+               error("ssh_keysign: pipe: %s", strerror(errno));
+               return -1;
+       }
+       if (pipe(from) < 0) {
+               error("ssh_keysign: pipe: %s", strerror(errno));
+               return -1;
+       }
+       if ((pid = fork()) < 0) {
+               error("ssh_keysign: fork: %s", strerror(errno));
+               return -1;
+       }
+       if (pid == 0) {
+               /* keep the socket on exec */
+               fcntl(packet_get_connection_in(), F_SETFD, 0);
+               permanently_drop_suid(getuid());
+               close(from[0]);
+               if (dup2(from[1], STDOUT_FILENO) < 0)
+                       fatal("ssh_keysign: dup2: %s", strerror(errno));
+               close(to[1]);
+               if (dup2(to[0], STDIN_FILENO) < 0)
+                       fatal("ssh_keysign: dup2: %s", strerror(errno));
+               close(from[1]);
+               close(to[0]);
+               execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0);
+               fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN,
+                   strerror(errno));
+       }
+       close(from[1]);
+       close(to[0]);
+
+       buffer_init(&b);
+       buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */
+       buffer_put_string(&b, data, datalen);
+       if (ssh_msg_send(to[1], version, &b) == -1)
+               fatal("ssh_keysign: couldn't send request");
+
+       if (ssh_msg_recv(from[0], &b) < 0) {
+               error("ssh_keysign: no reply");
+               buffer_free(&b);
+               return -1;
+       }
+       close(from[0]);
+       close(to[1]);
+
+       while (waitpid(pid, &status, 0) < 0)
+               if (errno != EINTR)
+                       break;
+
+       if (buffer_get_char(&b) != version) {
+               error("ssh_keysign: bad version");
+               buffer_free(&b);
+               return -1;
+       }
+       *sigp = buffer_get_string(&b, lenp);
+       buffer_free(&b);
+
+       return 0;
+}
+
+int
+userauth_hostbased(Authctxt *authctxt)
+{
+       Key *private = NULL;
+       Sensitive *sensitive = authctxt->sensitive;
+       Buffer b;
+       u_char *signature, *blob;
+       char *chost, *pkalg, *p;
+       const char *service;
+       u_int blen, slen;
+       int ok, i, found = 0;
+
+       /* check for a useful key */
+       for (i = 0; i < sensitive->nkeys; i++) {
+               private = sensitive->keys[i];
+               if (private && private->type != KEY_RSA1) {
+                       found = 1;
+                       /* we take and free the key */
+                       sensitive->keys[i] = NULL;
+                       break;
+               }
+       }
+       if (!found) {
+               debug("No more client hostkeys for hostbased authentication.");
+               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);
+               xfree(blob);
+               return 0;
+       }
+       xasprintf(&chost, "%s.", p);
+       debug2("userauth_hostbased: chost %s", chost);
+       xfree(p);
+
+       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
+       if (sensitive->external_keysign)
+               ok = ssh_keysign(private, &signature, &slen,
+                   buffer_ptr(&b), buffer_len(&b));
+       else
+               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);
+               xfree(blob);
+               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);
+       xfree(blob);
+
+       packet_send();
+       return 1;
+}
+
+#ifdef JPAKE
+int
+userauth_jpake(Authctxt *authctxt)
+{
+       struct jpake_ctx *pctx;
+       u_char *x1_proof, *x2_proof;
+       u_int x1_proof_len, x2_proof_len;
+       static int attempt = 0; /* XXX share with userauth_password's? */
+
+       if (attempt++ >= options.number_of_password_prompts)
+               return 0;
+       if (attempt != 1)
+               error("Permission denied, please try again.");
+
+       if (authctxt->methoddata != NULL)
+               fatal("%s: authctxt->methoddata already set (%p)",
+                   __func__, authctxt->methoddata);
+
+       authctxt->methoddata = pctx = jpake_new();
+
+       /*
+        * Send request immediately, to get the protocol going while
+        * we do the initial computations.
+        */
+       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();
+       packet_write_wait();
+
+       jpake_step1(pctx->grp,
+           &pctx->client_id, &pctx->client_id_len,
+           &pctx->x1, &pctx->x2, &pctx->g_x1, &pctx->g_x2,
+           &x1_proof, &x1_proof_len,
+           &x2_proof, &x2_proof_len);
+
+       JPAKE_DEBUG_CTX((pctx, "step 1 sending in %s", __func__));
+
+       packet_start(SSH2_MSG_USERAUTH_JPAKE_CLIENT_STEP1);
+       packet_put_string(pctx->client_id, pctx->client_id_len);
+       packet_put_bignum2(pctx->g_x1);
+       packet_put_bignum2(pctx->g_x2);
+       packet_put_string(x1_proof, x1_proof_len);
+       packet_put_string(x2_proof, x2_proof_len);
+       packet_send();
+
+       bzero(x1_proof, x1_proof_len);
+       bzero(x2_proof, x2_proof_len);
+       xfree(x1_proof);
+       xfree(x2_proof);
+
+       /* Expect step 1 packet from peer */
+       dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1,
+           input_userauth_jpake_server_step1);
+       dispatch_set(SSH2_MSG_USERAUTH_SUCCESS,
+           &input_userauth_success_unexpected);
+
+       return 1;
+}
+
+void
+userauth_jpake_cleanup(Authctxt *authctxt)
+{
+       debug3("%s: clean up", __func__);
+       if (authctxt->methoddata != NULL) {
+               jpake_free(authctxt->methoddata);
+               authctxt->methoddata = NULL;
+       }
+       dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success);
+}
+#endif /* JPAKE */
+
+/* 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;
+       u_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 authentication 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 authentication method: %s", name);
+                       return current;
+               }
+       }
+}
+
+static char *
+authmethods_get(void)
+{
+       Authmethod *method = NULL;
+       Buffer b;
+       char *list;
+
+       buffer_init(&b);
+       for (method = authmethods; method->name != NULL; method++) {
+               if (authmethod_is_enabled(method)) {
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       buffer_append(&b, method->name, strlen(method->name));
+               }
+       }
+       buffer_append(&b, "\0", 1);
+       list = xstrdup(buffer_ptr(&b));
+       buffer_free(&b);
+       return list;
+}
+
diff --git a/sshd.0 b/sshd.0
new file mode 100644 (file)
index 0000000..873584d
--- /dev/null
+++ b/sshd.0
@@ -0,0 +1,634 @@
+SSHD(8)                 OpenBSD System Manager's Manual                SSHD(8)
+
+NAME
+     sshd - OpenSSH SSH daemon
+
+SYNOPSIS
+     sshd [-46DdeiqTt] [-b bits] [-C connection_spec]
+          [-c host_certificate_file] [-f config_file] [-g login_grace_time]
+          [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]
+
+DESCRIPTION
+     sshd (OpenSSH Daemon) is the daemon program for ssh(1).  Together these
+     programs replace rlogin(1) and rsh(1), and provide secure encrypted
+     communications between two untrusted hosts over an insecure network.
+
+     sshd listens for connections from clients.  It is normally started at
+     boot from /etc/rc.  It forks a new daemon for each incoming connection.
+     The forked daemons handle key exchange, encryption, authentication,
+     command execution, and data exchange.
+
+     sshd can be configured using command-line options or a configuration file
+     (by default sshd_config(5)); command-line options override values
+     specified in the configuration file.  sshd rereads its configuration file
+     when it receives a hangup signal, SIGHUP, by executing itself with the
+     name and options it was started with, e.g. /usr/sbin/sshd.
+
+     The options are as follows:
+
+     -4      Forces sshd to use IPv4 addresses only.
+
+     -6      Forces sshd to use IPv6 addresses only.
+
+     -b bits
+             Specifies the number of bits in the ephemeral protocol version 1
+             server key (default 1024).
+
+     -C connection_spec
+             Specify the connection parameters to use for the -T extended test
+             mode.  If provided, any Match directives in the configuration
+             file that would apply to the specified user, host, and address
+             will be set before the configuration is written to standard
+             output.  The connection parameters are supplied as keyword=value
+             pairs.  The keywords are ``user'', ``host'', and ``addr''.  All
+             are required and may be supplied in any order, either with
+             multiple -C options or as a comma-separated list.
+
+     -c host_certificate_file
+             Specifies a path to a certificate file to identify sshd during
+             key exchange.  The certificate file must match a host key file
+             specified using the -h option or the HostKey configuration
+             directive.
+
+     -D      When this option is specified, sshd will not detach and does not
+             become a daemon.  This allows easy monitoring of sshd.
+
+     -d      Debug mode.  The server sends verbose debug output to standard
+             error, 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.
+
+     -e      When this option is specified, sshd will send the output to the
+             standard error instead of the system log.
+
+     -f config_file
+             Specifies the name of the configuration file.  The default is
+             /etc/ssh/sshd_config.  sshd refuses to start if there is no
+             configuration file.
+
+     -g login_grace_time
+             Gives the grace time for clients to authenticate themselves
+             (default 120 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.
+
+     -h host_key_file
+             Specifies a file from which a host key is read.  This option must
+             be given if sshd is not run as root (as the normal host key files
+             are normally not readable by anyone but root).  The default is
+             /etc/ssh/ssh_host_key for protocol version 1, and
+             /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_ecdsa_key and
+             /etc/ssh/ssh_host_rsa_key for protocol version 2.  It is possible
+             to have multiple host key files for the different protocol
+             versions and host key algorithms.
+
+     -i      Specifies that sshd is being run from inetd(8).  sshd 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 sshd from inetd may be feasible.
+
+     -k 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.
+
+     -o 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.  For full details
+             of the options, and their values, see sshd_config(5).
+
+     -p port
+             Specifies the port on which the server listens for connections
+             (default 22).  Multiple port options are permitted.  Ports
+             specified in the configuration file with the Port option are
+             ignored when a command-line port is specified.  Ports specified
+             using the ListenAddress option override command-line ports.
+
+     -q      Quiet mode.  Nothing is sent to the system log.  Normally the
+             beginning, authentication, and termination of each connection is
+             logged.
+
+     -T      Extended test mode.  Check the validity of the configuration
+             file, output the effective configuration to stdout and then exit.
+             Optionally, Match rules may be applied by specifying the
+             connection parameters using one or more -C options.
+
+     -t      Test mode.  Only check the validity of the configuration file and
+             sanity of the keys.  This is useful for updating sshd reliably as
+             configuration options may change.
+
+     -u len  This option is used to specify the size of the field in the utmp
+             structure that holds the remote host name.  If the resolved host
+             name is longer than 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
+             -u0 indicates that only dotted decimal addresses should be put
+             into the utmp file.  -u0 may also be used to prevent sshd from
+             making DNS requests unless the authentication mechanism or
+             configuration requires it.  Authentication mechanisms that may
+             require DNS include RhostsRSAAuthentication,
+             HostbasedAuthentication, and using a from="pattern-list" option
+             in a key file.  Configuration options that require DNS include
+             using a USER@HOST pattern in AllowUsers or DenyUsers.
+
+AUTHENTICATION
+     The OpenSSH SSH daemon supports SSH protocols 1 and 2.  The default is to
+     use protocol 2 only, though this can be changed via the Protocol option
+     in sshd_config(5).  Protocol 2 supports DSA, ECDSA and RSA keys; protocol
+     1 only supports RSA keys.  For both protocols, each host has a host-
+     specific key, normally 2048 bits, used to identify the host.
+
+     Forward security for protocol 1 is provided through an additional server
+     key, normally 768 bits, generated when the server starts.  This key is
+     normally regenerated every hour if it has been used, and is never stored
+     on disk.  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.
+
+     For protocol 2, forward security is provided through a Diffie-Hellman key
+     agreement.  This key agreement results in a shared session key.  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-md5, hmac-sha1, umac-64
+     or hmac-ripemd160).
+
+     Finally, the server and the client enter an authentication dialog.  The
+     client tries to authenticate itself using host-based authentication,
+     public key authentication, challenge-response authentication, or password
+     authentication.
+
+     Regardless of the authentication type, the account is checked to ensure
+     that it is accessible.  An account is not accessible if it is locked,
+     listed in DenyUsers or its group is listed in DenyGroups .  The
+     definition of a locked account is system dependant. Some platforms have
+     their own account database (eg AIX) and some modify the passwd field (
+     `*LK*' on Solaris and UnixWare, `*' on HP-UX, containing `Nologin' on
+     Tru64, a leading `*LOCKED*' on FreeBSD and a leading `!' on most
+     Linuxes).  If there is a requirement to disable password authentication
+     for the account while allowing still public-key, then the passwd field
+     should be set to something other than these values (eg `NP' or `*NP*' ).
+
+     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
+     connections, or forwarding the authentication agent connection over the
+     secure channel.
+
+     After this, 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.
+
+     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.
+
+LOGIN PROCESS
+     When a user successfully logs in, sshd does the following:
+
+           1.   If the login is on a tty, and no command has been specified,
+                prints last login time and /etc/motd (unless prevented in the
+                configuration file or by ~/.hushlogin; see the FILES section).
+
+           2.   If the login is on a tty, records login time.
+
+           3.   Checks /etc/nologin; if it exists, prints contents and quits
+                (unless root).
+
+           4.   Changes to run with normal user privileges.
+
+           5.   Sets up basic environment.
+
+           6.   Reads the file ~/.ssh/environment, if it exists, and users are
+                allowed to change their environment.  See the
+                PermitUserEnvironment option in sshd_config(5).
+
+           7.   Changes to user's home directory.
+
+           8.   If ~/.ssh/rc exists, runs it; else if /etc/ssh/sshrc exists,
+                runs it; otherwise runs xauth.  The ``rc'' files are given the
+                X11 authentication protocol and cookie in standard input.  See
+                SSHRC, below.
+
+           9.   Runs user's shell or command.
+
+SSHRC
+     If the file ~/.ssh/rc exists, sh(1) runs it after reading the environment
+     files but before starting the user's shell or command.  It must not
+     produce any output on stdout; stderr must be used instead.  If X11
+     forwarding is in use, it will receive the "proto cookie" pair in its
+     standard input (and DISPLAY in its environment).  The script must call
+     xauth(1) because sshd will not run xauth automatically to add X11
+     cookies.
+
+     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.
+
+     This file will probably contain some initialization code followed by
+     something similar to:
+
+        if read proto cookie && [ -n "$DISPLAY" ]; then
+                if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
+                        # X11UseLocalhost=yes
+                        echo add unix:`echo $DISPLAY |
+                            cut -c11-` $proto $cookie
+                else
+                        # X11UseLocalhost=no
+                        echo add $DISPLAY $proto $cookie
+                fi | xauth -q -
+        fi
+
+     If this file does not exist, /etc/ssh/sshrc is run, and if that does not
+     exist either, xauth is used to add the cookie.
+
+AUTHORIZED_KEYS FILE FORMAT
+     AuthorizedKeysFile specifies the file containing public keys for public
+     key authentication; if none is specified, the default is
+     ~/.ssh/authorized_keys.  Each line of the file contains one key (empty
+     lines and lines starting with a `#' are ignored as comments).  Protocol 1
+     public keys consist of the following space-separated fields: options,
+     bits, exponent, modulus, comment.  Protocol 2 public key consist of:
+     options, keytype, base64-encoded key, comment.  The options field is
+     optional; its presence is determined by whether the line starts with a
+     number or not (the options 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 ``ecdsa-sha2-nistp256'', ``ecdsa-sha2-nistp384'',
+     ``ecdsa-sha2-nistp521'', ``ssh-dss'' or ``ssh-rsa''.
+
+     Note that lines in this file are usually several hundred bytes long
+     (because of the size of the public key encoding) up to a limit of 8
+     kilobytes, which permits DSA keys up to 8 kilobits and RSA keys up to 16
+     kilobits.  You don't want to type them in; instead, copy the
+     identity.pub, id_dsa.pub, id_ecdsa.pub, or the id_rsa.pub file and edit
+     it.
+
+     sshd enforces a minimum RSA key modulus size for protocol 1 and protocol
+     2 keys of 768 bits.
+
+     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):
+
+     cert-authority
+             Specifies that the listed key is a certification authority (CA)
+             that is trusted to validate signed certificates for user
+             authentication.
+
+             Certificates may encode access restrictions similar to these key
+             options.  If both certificate restrictions and key options are
+             present, the most restrictive union of the two is applied.
+
+     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 an 8-bit clean
+             channel is required, one must not request a pty or should specify
+             no-pty.  A quote may be included in the command by quoting it
+             with a backslash.  This option might be useful to restrict
+             certain public 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 and/or X11 forwarding
+             unless they are explicitly prohibited.  The command originally
+             supplied by the client is available in the SSH_ORIGINAL_COMMAND
+             environment variable.  Note that this option applies to shell,
+             command or subsystem execution.  Also note that this command may
+             be superseded by either a sshd_config(5) ForceCommand directive
+             or a command embedded in a certificate.
+
+     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.  Environment processing is disabled by
+             default and is controlled via the PermitUserEnvironment option.
+             This option is automatically disabled if UseLogin is enabled.
+
+     from="pattern-list"
+             Specifies that in addition to public key authentication, either
+             the canonical name of the remote host or its IP address must be
+             present in the comma-separated list of patterns.  See PATTERNS in
+             ssh_config(5) for more information on patterns.
+
+             In addition to the wildcard matching that may be applied to
+             hostnames or addresses, a from stanza may match IP addresses
+             using CIDR address/masklen notation.
+
+             The purpose of this option is to optionally increase security:
+             public key authentication by itself does not trust the network or
+             name servers or anything (but the key); however, if somebody
+             somehow steals the key, the key permits an intruder to log in
+             from anywhere in the world.  This additional option makes using a
+             stolen key more difficult (name servers and/or routers would have
+             to be compromised in addition to just the key).
+
+     no-agent-forwarding
+             Forbids authentication agent forwarding when this key is used for
+             authentication.
+
+     no-port-forwarding
+             Forbids TCP 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 command option.
+
+     no-pty  Prevents tty allocation (a request to allocate a pty will fail).
+
+     no-user-rc
+             Disables execution of ~/.ssh/rc.
+
+     no-X11-forwarding
+             Forbids X11 forwarding when this key is used for authentication.
+             Any X11 forward requests by the client will return an error.
+
+     permitopen="host:port"
+             Limit local ``ssh -L'' port forwarding such that it may only
+             connect to the specified host and port.  IPv6 addresses can be
+             specified by enclosing the address in square brackets.  Multiple
+             permitopen options may be applied separated by commas.  No
+             pattern matching is performed on the specified hostnames, they
+             must be literal domains or addresses.
+
+     principals="principals"
+             On a cert-authority line, specifies allowed principals for
+             certificate authentication as a comma-separated list.  At least
+             one name from the list must appear in the certificate's list of
+             principals for the certificate to be accepted.  This option is
+             ignored for keys that are not marked as trusted certificate
+             signers using the cert-authority option.
+
+     tunnel="n"
+             Force a tun(4) device on the server.  Without this option, the
+             next available device will be used if the client requests a
+             tunnel.
+
+     An example authorized_keys file:
+
+        # Comments allowed at start of line
+        ssh-rsa AAAAB3Nza...LiPk== user@example.net
+        from="*.sales.example.net,!pc.sales.example.net" ssh-rsa
+        AAAAB2...19Q== john@example.net
+        command="dump /home",no-pty,no-port-forwarding ssh-dss
+        AAAAC3...51R== example.net
+        permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss
+        AAAAB5...21S==
+        tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...==
+        jane@example.net
+
+SSH_KNOWN_HOSTS FILE FORMAT
+     The /etc/ssh/ssh_known_hosts and ~/.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.
+
+     Each line in these files contains the following fields: markers
+     (optional), hostnames, bits, exponent, modulus, comment.  The fields are
+     separated by spaces.
+
+     The marker is optional, but if it is present then it must be one of
+     ``@cert-authority'', to indicate that the line contains a certification
+     authority (CA) key, or ``@revoked'', to indicate that the key contained
+     on the line is revoked and must not ever be accepted.  Only one marker
+     should be used on a key line.
+
+     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 `!' 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.
+     A hostname or address may optionally be enclosed within `[' and `]'
+     brackets then followed by `:' and a non-standard port number.
+
+     Alternately, hostnames may be stored in a hashed form which hides host
+     names and addresses should the file's contents be disclosed.  Hashed
+     hostnames start with a `|' character.  Only one hashed hostname may
+     appear on a single line and none of the above negation or wildcard
+     operators may be applied.
+
+     Bits, exponent, and modulus are taken directly from the RSA host key;
+     they can be obtained, for example, from /etc/ssh/ssh_host_key.pub.  The
+     optional comment field continues to the end of the line, and is not used.
+
+     Lines starting with `#' and empty lines are ignored as comments.
+
+     When performing host authentication, authentication is accepted if any
+     matching line has the proper key; either one that matches exactly or, if
+     the server has presented a certificate for authentication, the key of the
+     certification authority that signed the certificate.  For a key to be
+     trusted as a certification authority, it must use the ``@cert-authority''
+     marker described above.
+
+     The known hosts file also provides a facility to mark keys as revoked,
+     for example when it is known that the associated private key has been
+     stolen.  Revoked keys are specified by including the ``@revoked'' marker
+     at the beginning of the key line, and are never accepted for
+     authentication or as certification authorities, but instead will produce
+     a warning from ssh(1) when they are encountered.
+
+     It is 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.
+
+     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, ssh-keyscan(1) or by taking
+     /etc/ssh/ssh_host_key.pub and adding the host names at the front.
+     ssh-keygen(1) also offers some basic automated editing for
+     ~/.ssh/known_hosts including removing hosts matching a host name and
+     converting all host names to their hashed representations.
+
+     An example ssh_known_hosts file:
+
+        # Comments allowed at start of line
+        closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net
+        cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
+        # A hashed hostname
+        |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
+        AAAA1234.....=
+        # A revoked key
+        @revoked * ssh-rsa AAAAB5W...
+        # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
+        @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
+
+FILES
+     ~/.hushlogin
+             This file is used to suppress printing the last login time and
+             /etc/motd, if PrintLastLog and PrintMotd, respectively, are
+             enabled.  It does not suppress printing of the banner specified
+             by Banner.
+
+     ~/.rhosts
+             This file is used for host-based authentication (see ssh(1) for
+             more information).  On some machines this file may need to be
+             world-readable if the user's home directory is on an NFS
+             partition, because sshd 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.
+
+     ~/.shosts
+             This file is used in exactly the same way as .rhosts, but allows
+             host-based authentication without permitting login with
+             rlogin/rsh.
+
+     ~/.ssh/
+             This directory is the default location for all user-specific
+             configuration and authentication information.  There is no
+             general requirement to keep the entire contents of this directory
+             secret, but the recommended permissions are read/write/execute
+             for the user, and not accessible by others.
+
+     ~/.ssh/authorized_keys
+             Lists the public keys (DSA/ECDSA/RSA) that can be used for
+             logging in as this user.  The format of this file is described
+             above.  The content of the file is not highly sensitive, but the
+             recommended permissions are read/write for the user, and not
+             accessible by others.
+
+             If this file, the ~/.ssh directory, or the user's home directory
+             are writable by other users, then the file could be modified or
+             replaced by unauthorized users.  In this case, sshd will not
+             allow it to be used unless the StrictModes option has been set to
+             ``no''.
+
+     ~/.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
+             `#'), 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.  Environment processing is disabled by default and
+             is controlled via the PermitUserEnvironment option.
+
+     ~/.ssh/known_hosts
+             Contains a list of host keys for all hosts the user has logged
+             into that are not already in the systemwide list of known host
+             keys.  The format of this file is described above.  This file
+             should be writable only by root/the owner and can, but need not
+             be, world-readable.
+
+     ~/.ssh/rc
+             Contains initialization routines to be run before the user's home
+             directory becomes accessible.  This file should be writable only
+             by the user, and need not be readable by anyone else.
+
+     /etc/hosts.allow
+     /etc/hosts.deny
+             Access controls that should be enforced by tcp-wrappers are
+             defined here.  Further details are described in hosts_access(5).
+
+     /etc/hosts.equiv
+             This file is for host-based authentication (see ssh(1)).  It
+             should only be writable by root.
+
+     /etc/moduli
+             Contains Diffie-Hellman groups used for the "Diffie-Hellman Group
+             Exchange".  The file format is described in moduli(5).
+
+     /etc/motd
+             See motd(5).
+
+     /etc/nologin
+             If this file exists, sshd 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.
+
+     /etc/shosts.equiv
+             This file is used in exactly the same way as hosts.equiv, but
+             allows host-based authentication without permitting login with
+             rlogin/rsh.
+
+     /etc/ssh/ssh_host_key
+     /etc/ssh/ssh_host_dsa_key
+     /etc/ssh/ssh_host_ecdsa_key
+     /etc/ssh/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 sshd does not start if
+             these files are group/world-accessible.
+
+     /etc/ssh/ssh_host_key.pub
+     /etc/ssh/ssh_host_dsa_key.pub
+     /etc/ssh/ssh_host_ecdsa_key.pub
+     /etc/ssh/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 ssh-keygen(1).
+
+     /etc/ssh/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.  The format of this file is
+             described above.  This file should be writable only by root/the
+             owner and should be world-readable.
+
+     /etc/ssh/sshd_config
+             Contains configuration data for sshd.  The file format and
+             configuration options are described in sshd_config(5).
+
+     /etc/ssh/sshrc
+             Similar to ~/.ssh/rc, it can be used to specify machine-specific
+             login-time initializations globally.  This file should be
+             writable only by root, and should be world-readable.
+
+     /var/empty
+             chroot(2) directory used by sshd during privilege separation in
+             the pre-authentication phase.  The directory should not contain
+             any files and must be owned by root and not group or world-
+             writable.
+
+     /var/run/sshd.pid
+             Contains the process ID of the sshd listening for connections (if
+             there are several daemons running concurrently for different
+             ports, this contains the process ID of the one started last).
+             The content of this file is not sensitive; it can be world-
+             readable.
+
+SEE ALSO
+     scp(1), sftp(1), ssh(1), ssh-add(1), ssh-agent(1), ssh-keygen(1),
+     ssh-keyscan(1), chroot(2), hosts_access(5), login.conf(5), moduli(5),
+     sshd_config(5), inetd(8), sftp-server(8)
+
+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.  Niels Provos and Markus Friedl contributed support
+     for privilege separation.
+
+CAVEATS
+     System security is not improved unless rshd, rlogind, and rexecd are
+     disabled (thus completely disabling rlogin and rsh into the machine).
+
+OpenBSD 4.9                    October 28, 2010                    OpenBSD 4.9
diff --git a/sshd.8 b/sshd.8
new file mode 100644 (file)
index 0000000..5503b13
--- /dev/null
+++ b/sshd.8
@@ -0,0 +1,976 @@
+.\"
+.\" 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.260 2010/10/28 18:33:28 jmc Exp $
+.Dd $Mdocdate: October 28 2010 $
+.Dt SSHD 8
+.Os
+.Sh NAME
+.Nm sshd
+.Nd OpenSSH SSH daemon
+.Sh SYNOPSIS
+.Nm sshd
+.Bk -words
+.Op Fl 46DdeiqTt
+.Op Fl b Ar bits
+.Op Fl C Ar connection_spec
+.Op Fl c Ar host_certificate_file
+.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 o Ar option
+.Op Fl p Ar port
+.Op Fl u Ar len
+.Ek
+.Sh DESCRIPTION
+.Nm
+(OpenSSH Daemon) is the daemon program for
+.Xr ssh 1 .
+Together these programs replace
+.Xr rlogin 1
+and
+.Xr rsh 1 ,
+and provide secure encrypted communications between two untrusted hosts
+over an insecure network.
+.Pp
+.Nm
+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.
+.Pp
+.Nm
+can be configured using command-line options or a configuration file
+(by default
+.Xr sshd_config 5 ) ;
+command-line options override values specified in the
+configuration file.
+.Nm
+rereads its configuration file when it receives a hangup signal,
+.Dv SIGHUP ,
+by executing itself with the name and options it was started with, e.g.\&
+.Pa /usr/sbin/sshd .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl b Ar bits
+Specifies the number of bits in the ephemeral protocol version 1
+server key (default 1024).
+.It Fl C Ar connection_spec
+Specify the connection parameters to use for the
+.Fl T
+extended test mode.
+If provided, any
+.Cm Match
+directives in the configuration file
+that would apply to the specified user, host, and address will be set before
+the configuration is written to standard output.
+The connection parameters are supplied as keyword=value pairs.
+The keywords are
+.Dq user ,
+.Dq host ,
+and
+.Dq addr .
+All are required and may be supplied in any order, either with multiple
+.Fl C
+options or as a comma-separated list.
+.It Fl c Ar host_certificate_file
+Specifies a path to a certificate file to identify
+.Nm
+during key exchange.
+The certificate file must match a host key file specified using the
+.Fl h
+option or the
+.Cm HostKey
+configuration directive.
+.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 d
+Debug mode.
+The server sends verbose debug output to standard error,
+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
+.Fl 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 config_file
+Specifies the name of the configuration file.
+The default is
+.Pa /etc/ssh/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
+120 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 a file from which a host key is read.
+This option must be given if
+.Nm
+is not run as root (as the normal
+host key files are normally not readable by anyone but root).
+The default is
+.Pa /etc/ssh/ssh_host_key
+for protocol version 1, and
+.Pa /etc/ssh/ssh_host_dsa_key ,
+.Pa /etc/ssh/ssh_host_ecdsa_key
+and
+.Pa /etc/ssh/ssh_host_rsa_key
+for protocol version 2.
+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
+.Xr inetd 8 .
+.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 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.
+For full details of the options, and their values, see
+.Xr sshd_config 5 .
+.It Fl p Ar port
+Specifies the port on which the server listens for connections
+(default 22).
+Multiple port options are permitted.
+Ports specified in the configuration file with the
+.Cm Port
+option are ignored when a command-line port is specified.
+Ports specified using the
+.Cm ListenAddress
+option override command-line ports.
+.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
+Extended test mode.
+Check the validity of the configuration file, output the effective configuration
+to stdout and then exit.
+Optionally,
+.Cm Match
+rules may be applied by specifying the connection parameters using one or more
+.Fl C
+options.
+.It Fl t
+Test mode.
+Only check the validity of the configuration file and sanity of the keys.
+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
+may 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 RhostsRSAAuthentication ,
+.Cm HostbasedAuthentication ,
+and using a
+.Cm from="pattern-list"
+option in a key file.
+Configuration options that require DNS include using a
+USER@HOST pattern in
+.Cm AllowUsers
+or
+.Cm DenyUsers .
+.El
+.Sh AUTHENTICATION
+The OpenSSH SSH daemon supports SSH protocols 1 and 2.
+The default is to use protocol 2 only,
+though this can be changed via the
+.Cm Protocol
+option in
+.Xr sshd_config 5 .
+Protocol 2 supports DSA, ECDSA and RSA keys;
+protocol 1 only supports RSA keys.
+For both protocols,
+each host has a host-specific key,
+normally 2048 bits,
+used to identify the host.
+.Pp
+Forward security for protocol 1 is provided through
+an additional server key,
+normally 768 bits,
+generated when the server starts.
+This key is normally regenerated every hour if it has been used, and
+is never stored on disk.
+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
+For protocol 2,
+forward security is provided through a Diffie-Hellman key agreement.
+This key agreement results in a shared session key.
+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-md5, hmac-sha1, umac-64 or hmac-ripemd160).
+.Pp
+Finally, the server and the client enter an authentication dialog.
+The client tries to authenticate itself using
+host-based authentication,
+public key authentication,
+challenge-response authentication,
+or password authentication.
+.Pp
+Regardless of the authentication type, the account is checked to
+ensure that it is accessible.  An account is not accessible if it is
+locked, listed in
+.Cm DenyUsers
+or its group is listed in
+.Cm DenyGroups
+\&.  The definition of a locked account is system dependant. Some platforms
+have their own account database (eg AIX) and some modify the passwd field (
+.Ql \&*LK\&*
+on Solaris and UnixWare,
+.Ql \&*
+on HP-UX, containing
+.Ql Nologin
+on Tru64,
+a leading
+.Ql \&*LOCKED\&*
+on FreeBSD and a leading
+.Ql \&!
+on most Linuxes).
+If there is a requirement to disable password authentication
+for the account while allowing still public-key, then the passwd field
+should be set to something other than these values (eg
+.Ql NP
+or
+.Ql \&*NP\&*
+).
+.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 connections, or forwarding the authentication agent
+connection over the secure channel.
+.Pp
+After this, 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.
+.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 ~/.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 the file
+.Pa ~/.ssh/environment ,
+if it exists, and users are allowed to change their environment.
+See the
+.Cm PermitUserEnvironment
+option in
+.Xr sshd_config 5 .
+.It
+Changes to user's home directory.
+.It
+If
+.Pa ~/.ssh/rc
+exists, runs it; else if
+.Pa /etc/ssh/sshrc
+exists, runs
+it; otherwise runs xauth.
+The
+.Dq rc
+files are given the X11
+authentication protocol and cookie in standard input.
+See
+.Sx SSHRC ,
+below.
+.It
+Runs user's shell or command.
+.El
+.Sh SSHRC
+If the file
+.Pa ~/.ssh/rc
+exists,
+.Xr sh 1
+runs it after reading the
+environment files but before starting the user's shell or command.
+It must not produce any output on stdout; stderr must be used
+instead.
+If X11 forwarding is in use, it will receive the "proto cookie" pair in
+its standard input (and
+.Ev DISPLAY
+in its environment).
+The script must call
+.Xr xauth 1
+because
+.Nm
+will not run xauth automatically to add X11 cookies.
+.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 -offset 3n
+if read proto cookie && [ -n "$DISPLAY" ]; then
+       if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then
+               # X11UseLocalhost=yes
+               echo add unix:`echo $DISPLAY |
+                   cut -c11-` $proto $cookie
+       else
+               # X11UseLocalhost=no
+               echo add $DISPLAY $proto $cookie
+       fi | xauth -q -
+fi
+.Ed
+.Pp
+If this file does not exist,
+.Pa /etc/ssh/sshrc
+is run, and if that
+does not exist either, xauth is used to add the cookie.
+.Sh AUTHORIZED_KEYS FILE FORMAT
+.Cm AuthorizedKeysFile
+specifies the file containing public keys for
+public key authentication;
+if none is specified, the default is
+.Pa ~/.ssh/authorized_keys .
+Each line of the file contains one
+key (empty lines and lines starting with a
+.Ql #
+are ignored as
+comments).
+Protocol 1 public keys consist of the following space-separated fields:
+options, bits, exponent, modulus, comment.
+Protocol 2 public key consist of:
+options, keytype, base64-encoded key, comment.
+The options field is optional;
+its presence is determined by whether the line starts
+with a number or not (the options 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 ecdsa-sha2-nistp256 ,
+.Dq ecdsa-sha2-nistp384 ,
+.Dq ecdsa-sha2-nistp521 ,
+.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 public key encoding) up to a limit of
+8 kilobytes, which permits DSA keys up to 8 kilobits and RSA
+keys up to 16 kilobits.
+You don't want to type them in; instead, copy the
+.Pa identity.pub ,
+.Pa id_dsa.pub ,
+.Pa id_ecdsa.pub ,
+or the
+.Pa id_rsa.pub
+file and edit it.
+.Pp
+.Nm
+enforces a minimum RSA key modulus size for protocol 1
+and protocol 2 keys of 768 bits.
+.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 cert-authority
+Specifies that the listed key is a certification authority (CA) that is
+trusted to validate signed certificates for user authentication.
+.Pp
+Certificates may encode access restrictions similar to these key options.
+If both certificate restrictions and key options are present, the most
+restrictive union of the two is applied.
+.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 an 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 public 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 and/or X11
+forwarding unless they are explicitly prohibited.
+The command originally supplied by the client is available in the
+.Ev SSH_ORIGINAL_COMMAND
+environment variable.
+Note that this option applies to shell, command or subsystem execution.
+Also note that this command may be superseded by either a
+.Xr sshd_config 5
+.Cm ForceCommand
+directive or a command embedded in a certificate.
+.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.
+Environment processing is disabled by default and is
+controlled via the
+.Cm PermitUserEnvironment
+option.
+This option is automatically disabled if
+.Cm UseLogin
+is enabled.
+.It Cm from="pattern-list"
+Specifies that in addition to public key authentication, either the canonical
+name of the remote host or its IP address must be present in the
+comma-separated list of patterns.
+See
+.Sx PATTERNS
+in
+.Xr ssh_config 5
+for more information on patterns.
+.Pp
+In addition to the wildcard matching that may be applied to hostnames or
+addresses, a
+.Cm from
+stanza may match IP addresses using CIDR address/masklen notation.
+.Pp
+The purpose of this option is to optionally increase security: public key
+authentication by itself does not trust the network or name servers or
+anything (but the key); however, if somebody somehow steals the key, the key
+permits an intruder to log in from anywhere in the world.
+This additional option makes using a stolen key more difficult (name
+servers and/or routers would have to be compromised in addition to
+just the key).
+.It Cm no-agent-forwarding
+Forbids authentication agent forwarding when this key is used for
+authentication.
+.It Cm no-port-forwarding
+Forbids TCP 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-pty
+Prevents tty allocation (a request to allocate a pty will fail).
+.It Cm no-user-rc
+Disables execution of
+.Pa ~/.ssh/rc .
+.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 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 by enclosing the address in square brackets.
+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.
+.It Cm principals="principals"
+On a
+.Cm cert-authority
+line, specifies allowed principals for certificate authentication as a
+comma-separated list.
+At least one name from the list must appear in the certificate's
+list of principals for the certificate to be accepted.
+This option is ignored for keys that are not marked as trusted certificate
+signers using the
+.Cm cert-authority
+option.
+.It Cm tunnel="n"
+Force a
+.Xr tun 4
+device on the server.
+Without this option, the next available device will be used if
+the client requests a tunnel.
+.El
+.Pp
+An example authorized_keys file:
+.Bd -literal -offset 3n
+# Comments allowed at start of line
+ssh-rsa AAAAB3Nza...LiPk== user@example.net
+from="*.sales.example.net,!pc.sales.example.net" ssh-rsa
+AAAAB2...19Q== john@example.net
+command="dump /home",no-pty,no-port-forwarding ssh-dss
+AAAAC3...51R== example.net
+permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss
+AAAAB5...21S==
+tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...==
+jane@example.net
+.Ed
+.Sh SSH_KNOWN_HOSTS FILE FORMAT
+The
+.Pa /etc/ssh/ssh_known_hosts
+and
+.Pa ~/.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: markers (optional),
+hostnames, bits, exponent, modulus, comment.
+The fields are separated by spaces.
+.Pp
+The marker is optional, but if it is present then it must be one of
+.Dq @cert-authority ,
+to indicate that the line contains a certification authority (CA) key,
+or
+.Dq @revoked ,
+to indicate that the key contained on the line is revoked and must not ever
+be accepted.
+Only one marker should be used on a key line.
+.Pp
+Hostnames is a comma-separated list of patterns
+.Pf ( Ql *
+and
+.Ql \&?
+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.
+A hostname or address may optionally be enclosed within
+.Ql \&[
+and
+.Ql \&]
+brackets then followed by
+.Ql \&:
+and a non-standard port number.
+.Pp
+Alternately, hostnames may be stored in a hashed form which hides host names
+and addresses should the file's contents be disclosed.
+Hashed hostnames start with a
+.Ql |
+character.
+Only one hashed hostname may appear on a single line and none of the above
+negation or wildcard operators may be applied.
+.Pp
+Bits, exponent, and modulus are taken directly from the RSA host key; they
+can be obtained, for example, from
+.Pa /etc/ssh/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; either one that matches exactly or,
+if the server has presented a certificate for authentication, the key
+of the certification authority that signed the certificate.
+For a key to be trusted as a certification authority, it must use the
+.Dq @cert-authority
+marker described above.
+.Pp
+The known hosts file also provides a facility to mark keys as revoked,
+for example when it is known that the associated private key has been
+stolen.
+Revoked keys are specified by including the
+.Dq @revoked
+marker at the beginning of the key line, and are never accepted for
+authentication or as certification authorities, but instead will
+produce a warning from
+.Xr ssh 1
+when they are encountered.
+.Pp
+It is 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,
+.Xr ssh-keyscan 1
+or by taking
+.Pa /etc/ssh/ssh_host_key.pub
+and adding the host names at the front.
+.Xr ssh-keygen 1
+also offers some basic automated editing for
+.Pa ~/.ssh/known_hosts
+including removing hosts matching a host name and converting all host
+names to their hashed representations.
+.Pp
+An example ssh_known_hosts file:
+.Bd -literal -offset 3n
+# Comments allowed at start of line
+closenet,...,192.0.2.53 1024 37 159...93 closenet.example.net
+cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....=
+# A hashed hostname
+|1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa
+AAAA1234.....=
+# A revoked key
+@revoked * ssh-rsa AAAAB5W...
+# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org
+@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W...
+.Ed
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It Pa ~/.hushlogin
+This file is used to suppress printing the last login time and
+.Pa /etc/motd ,
+if
+.Cm PrintLastLog
+and
+.Cm PrintMotd ,
+respectively,
+are enabled.
+It does not suppress printing of the banner specified by
+.Cm Banner .
+.Pp
+.It Pa ~/.rhosts
+This file is used for host-based authentication (see
+.Xr ssh 1
+for more information).
+On some machines this file may need to be
+world-readable if the user's home directory is on an NFS partition,
+because
+.Nm
+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
+.It Pa ~/.shosts
+This file is used in exactly the same way as
+.Pa .rhosts ,
+but allows host-based authentication without permitting login with
+rlogin/rsh.
+.Pp
+.It Pa ~/.ssh/
+This directory is the default location for all user-specific configuration
+and authentication information.
+There is no general requirement to keep the entire contents of this directory
+secret, but the recommended permissions are read/write/execute for the user,
+and not accessible by others.
+.Pp
+.It Pa ~/.ssh/authorized_keys
+Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in
+as this user.
+The format of this file is described above.
+The content of the file is not highly sensitive, but the recommended
+permissions are read/write for the user, and not accessible by others.
+.Pp
+If this file, the
+.Pa ~/.ssh
+directory, or the user's home directory are writable
+by other users, then the file could be modified or replaced by unauthorized
+users.
+In this case,
+.Nm
+will not allow it to be used unless the
+.Cm StrictModes
+option has been set to
+.Dq no .
+.Pp
+.It Pa ~/.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.
+Environment processing is disabled by default and is
+controlled via the
+.Cm PermitUserEnvironment
+option.
+.Pp
+.It Pa ~/.ssh/known_hosts
+Contains a list of host keys for all hosts the user has logged into
+that are not already in the systemwide list of known host keys.
+The format of this file is described above.
+This file should be writable only by root/the owner and
+can, but need not be, world-readable.
+.Pp
+.It Pa ~/.ssh/rc
+Contains initialization routines to be run before
+the user's home directory becomes accessible.
+This file should be writable only by the user, and need not be
+readable by anyone else.
+.Pp
+.It Pa /etc/hosts.allow
+.It Pa /etc/hosts.deny
+Access controls that should be enforced by tcp-wrappers are defined here.
+Further details are described in
+.Xr hosts_access 5 .
+.Pp
+.It Pa /etc/hosts.equiv
+This file is for host-based authentication (see
+.Xr ssh 1 ) .
+It should only be writable by root.
+.Pp
+.It Pa /etc/moduli
+Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
+The file format is described in
+.Xr moduli 5 .
+.Pp
+.It Pa /etc/motd
+See
+.Xr motd 5 .
+.Pp
+.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.
+.Pp
+.It Pa /etc/shosts.equiv
+This file is used in exactly the same way as
+.Pa hosts.equiv ,
+but allows host-based authentication without permitting login with
+rlogin/rsh.
+.Pp
+.It Pa /etc/ssh/ssh_host_key
+.It Pa /etc/ssh/ssh_host_dsa_key
+.It Pa /etc/ssh/ssh_host_ecdsa_key
+.It Pa /etc/ssh/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 these files are group/world-accessible.
+.Pp
+.It Pa /etc/ssh/ssh_host_key.pub
+.It Pa /etc/ssh/ssh_host_dsa_key.pub
+.It Pa /etc/ssh/ssh_host_ecdsa_key.pub
+.It Pa /etc/ssh/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 .
+.Pp
+.It Pa /etc/ssh/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.
+The format of this file is described above.
+This file should be writable only by root/the owner and
+should be world-readable.
+.Pp
+.It Pa /etc/ssh/sshd_config
+Contains configuration data for
+.Nm sshd .
+The file format and configuration options are described in
+.Xr sshd_config 5 .
+.Pp
+.It Pa /etc/ssh/sshrc
+Similar to
+.Pa ~/.ssh/rc ,
+it can be used to specify
+machine-specific login-time initializations globally.
+This file should be writable only by root, and should be world-readable.
+.Pp
+.It Pa /var/empty
+.Xr chroot 2
+directory used by
+.Nm
+during privilege separation in the pre-authentication phase.
+The directory should not contain any files and must be owned by root
+and not group or world-writable.
+.Pp
+.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 process ID of the one
+started last).
+The content of this file is not sensitive; it can be world-readable.
+.El
+.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 ssh-keyscan 1 ,
+.Xr chroot 2 ,
+.Xr hosts_access 5 ,
+.Xr login.conf 5 ,
+.Xr moduli 5 ,
+.Xr sshd_config 5 ,
+.Xr inetd 8 ,
+.Xr sftp-server 8
+.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.
+Niels Provos and Markus Friedl contributed support
+for privilege separation.
+.Sh CAVEATS
+System security is not improved unless
+.Nm rshd ,
+.Nm rlogind ,
+and
+.Nm rexecd
+are disabled (thus completely disabling
+.Xr rlogin
+and
+.Xr rsh
+into the machine).
diff --git a/sshd.c b/sshd.c
new file mode 100644 (file)
index 0000000..cb45cec
--- /dev/null
+++ b/sshd.c
@@ -0,0 +1,2349 @@
+/* $OpenBSD: sshd.c,v 1.381 2011/01/11 06:13:10 djm Exp $ */
+/*
+ * 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:
+ * Privilege Separation:
+ *
+ * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.
+ * Copyright (c) 2002 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"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+#include "openbsd-compat/sys-tree.h"
+#include "openbsd-compat/sys-queue.h"
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+#include "openbsd-compat/openssl-compat.h"
+
+#ifdef HAVE_SECUREWARE
+#include <sys/security.h>
+#include <prot.h>
+#endif
+
+#include "xmalloc.h"
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "rsa.h"
+#include "sshpty.h"
+#include "packet.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+#include "uidswap.h"
+#include "compat.h"
+#include "cipher.h"
+#include "key.h"
+#include "kex.h"
+#include "dh.h"
+#include "myproposal.h"
+#include "authfile.h"
+#include "pathnames.h"
+#include "atomicio.h"
+#include "canohost.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "misc.h"
+#include "msg.h"
+#include "dispatch.h"
+#include "channels.h"
+#include "session.h"
+#include "monitor_mm.h"
+#include "monitor.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "monitor_wrap.h"
+#include "roaming.h"
+#include "version.h"
+
+#ifdef LIBWRAP
+#include <tcpd.h>
+#include <syslog.h>
+int allow_severity;
+int deny_severity;
+#endif /* LIBWRAP */
+
+#ifndef O_NOCTTY
+#define O_NOCTTY       0
+#endif
+
+/* Re-exec fds */
+#define REEXEC_DEVCRYPTO_RESERVED_FD   (STDERR_FILENO + 1)
+#define REEXEC_STARTUP_PIPE_FD         (STDERR_FILENO + 2)
+#define REEXEC_CONFIG_PASS_FD          (STDERR_FILENO + 3)
+#define REEXEC_MIN_FREE_FD             (STDERR_FILENO + 4)
+
+extern char *__progname;
+
+/* Server configuration options. */
+ServerOptions options;
+
+/* Name of the server configuration file. */
+char *config_file_name = _PATH_SERVER_CONFIG_FILE;
+
+/*
+ * 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;
+
+/* re-exec */
+int rexeced_flag = 0;
+int rexec_flag = 1;
+int rexec_argc = 0;
+char **rexec_argv;
+
+/*
+ * 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 */
+       Key     **host_certificates;    /* all public host certificates */
+       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.
+ */
+static volatile sig_atomic_t key_do_regen = 0;
+
+/* This is set to true when a signal is received. */
+static volatile sig_atomic_t received_sighup = 0;
+static volatile sig_atomic_t received_sigterm = 0;
+
+/* session identifier, used by RSA-auth */
+u_char session_id[16];
+
+/* same for ssh2 */
+u_char *session_id2 = NULL;
+u_int session_id2_len = 0;
+
+/* record remote hostname or ip */
+u_int utmp_len = MAXHOSTNAMELEN;
+
+/* options.max_startup sized array of fd ints */
+int *startup_pipes = NULL;
+int startup_pipe;              /* in child */
+
+/* variables used for privilege separation */
+int use_privsep = -1;
+struct monitor *pmonitor = NULL;
+
+/* global authentication context */
+Authctxt *the_authctxt = NULL;
+
+/* sshd_config buffer */
+Buffer cfg;
+
+/* message to be displayed after login */
+Buffer loginmsg;
+
+/* Unprivileged user */
+struct passwd *privsep_pw = NULL;
+
+/* Prototypes for various functions defined later in this file. */
+void destroy_sensitive_data(void);
+void demote_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;
+}
+
+static void
+close_startup_pipes(void)
+{
+       int i;
+
+       if (startup_pipes)
+               for (i = 0; i < options.max_startups; i++)
+                       if (startup_pipes[i] != -1)
+                               close(startup_pipes[i]);
+}
+
+/*
+ * 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).
+ */
+
+/*ARGSUSED*/
+static void
+sighup_handler(int sig)
+{
+       int save_errno = errno;
+
+       received_sighup = 1;
+       signal(SIGHUP, sighup_handler);
+       errno = save_errno;
+}
+
+/*
+ * Called from the main program after receiving SIGHUP.
+ * Restarts the server.
+ */
+static void
+sighup_restart(void)
+{
+       logit("Received SIGHUP; restarting.");
+       close_listen_socks();
+       close_startup_pipes();
+       alarm(0);  /* alarm timer persists across exec */
+       signal(SIGHUP, SIG_IGN); /* will be restored after exec */
+       execv(saved_argv[0], saved_argv);
+       logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0],
+           strerror(errno));
+       exit(1);
+}
+
+/*
+ * Generic signal handler for terminating signals in the master daemon.
+ */
+/*ARGSUSED*/
+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.
+ */
+/*ARGSUSED*/
+static void
+main_sigchld_handler(int sig)
+{
+       int save_errno = errno;
+       pid_t pid;
+       int status;
+
+       while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||
+           (pid < 0 && errno == EINTR))
+               ;
+
+       signal(SIGCHLD, main_sigchld_handler);
+       errno = save_errno;
+}
+
+/*
+ * Signal handler for the alarm after the login grace period has expired.
+ */
+/*ARGSUSED*/
+static void
+grace_alarm_handler(int sig)
+{
+       if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
+               kill(pmonitor->m_pid, SIGALRM);
+
+       /* Log error and exit. */
+       sigdie("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)
+{
+       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.");
+
+       arc4random_buf(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH);
+       arc4random_stir();
+}
+
+/*ARGSUSED*/
+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)
+{
+       u_int i;
+       int mismatch;
+       int remote_major, remote_minor;
+       int major, minor;
+       char *s, *newline = "\n";
+       char buf[256];                  /* Must not be larger than remote_version. */
+       char remote_version[256];       /* Must be at least as big as buf. */
+
+       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;
+               newline = "\r\n";
+       } else {
+               major = PROTOCOL_MAJOR_1;
+               minor = PROTOCOL_MINOR_1;
+       }
+       snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s%s", major, minor,
+           SSH_VERSION, newline);
+       server_version_string = xstrdup(buf);
+
+       /* Send our protocol version identification. */
+       if (roaming_atomicio(vwrite, sock_out, server_version_string,
+           strlen(server_version_string))
+           != strlen(server_version_string)) {
+               logit("Could not write ident string to %s", get_remote_ipaddr());
+               cleanup_exit(255);
+       }
+
+       /* Read other sides version identification. */
+       memset(buf, 0, sizeof(buf));
+       for (i = 0; i < sizeof(buf) - 1; i++) {
+               if (roaming_atomicio(read, sock_in, &buf[i], 1) != 1) {
+                       logit("Did not receive identification string from %s",
+                           get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
+               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(vwrite, sock_out, s, strlen(s));
+               close(sock_in);
+               close(sock_out);
+               logit("Bad protocol version identification '%.100s' from %s",
+                   client_version_string, get_remote_ipaddr());
+               cleanup_exit(255);
+       }
+       debug("Client protocol version %d.%d; client software version %.100s",
+           remote_major, remote_minor, remote_version);
+
+       compat_datafellows(remote_version);
+
+       if (datafellows & SSH_BUG_PROBE) {
+               logit("probed from %s with %s.  Don't panic.",
+                   get_remote_ipaddr(), client_version_string);
+               cleanup_exit(255);
+       }
+
+       if (datafellows & SSH_BUG_SCANNER) {
+               logit("scanned from %s with %s.  Don't panic.",
+                   get_remote_ipaddr(), client_version_string);
+               cleanup_exit(255);
+       }
+
+       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(vwrite, sock_out, s, strlen(s));
+               close(sock_in);
+               close(sock_out);
+               logit("Protocol major versions differ for %s: %.200s vs. %.200s",
+                   get_remote_ipaddr(),
+                   server_version_string, client_version_string);
+               cleanup_exit(255);
+       }
+}
+
+/* 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;
+               }
+               if (sensitive_data.host_certificates[i]) {
+                       key_free(sensitive_data.host_certificates[i]);
+                       sensitive_data.host_certificates[i] = NULL;
+               }
+       }
+       sensitive_data.ssh1_host_key = NULL;
+       memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH);
+}
+
+/* Demote private to public keys for network child */
+void
+demote_sensitive_data(void)
+{
+       Key *tmp;
+       int i;
+
+       if (sensitive_data.server_key) {
+               tmp = key_demote(sensitive_data.server_key);
+               key_free(sensitive_data.server_key);
+               sensitive_data.server_key = tmp;
+       }
+
+       for (i = 0; i < options.num_host_key_files; i++) {
+               if (sensitive_data.host_keys[i]) {
+                       tmp = key_demote(sensitive_data.host_keys[i]);
+                       key_free(sensitive_data.host_keys[i]);
+                       sensitive_data.host_keys[i] = tmp;
+                       if (tmp->type == KEY_RSA1)
+                               sensitive_data.ssh1_host_key = tmp;
+               }
+               /* Certs do not need demotion */
+       }
+
+       /* We do not clear ssh1_host key and cookie.  XXX - Okay Niels? */
+}
+
+static void
+privsep_preauth_child(void)
+{
+       u_int32_t rnd[256];
+       gid_t gidset[1];
+
+       /* Enable challenge-response authentication for privilege separation */
+       privsep_challenge_enable();
+
+       arc4random_stir();
+       arc4random_buf(rnd, sizeof(rnd));
+       RAND_seed(rnd, sizeof(rnd));
+
+       /* Demote the private keys to public keys. */
+       demote_sensitive_data();
+
+       /* Change our root directory */
+       if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1)
+               fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR,
+                   strerror(errno));
+       if (chdir("/") == -1)
+               fatal("chdir(\"/\"): %s", strerror(errno));
+
+       /* Drop our privileges */
+       debug3("privsep user:group %u:%u", (u_int)privsep_pw->pw_uid,
+           (u_int)privsep_pw->pw_gid);
+#if 0
+       /* XXX not ready, too heavy after chroot */
+       do_setusercontext(privsep_pw);
+#else
+       gidset[0] = privsep_pw->pw_gid;
+       if (setgroups(1, gidset) < 0)
+               fatal("setgroups: %.100s", strerror(errno));
+       permanently_set_uid(privsep_pw);
+#endif
+}
+
+static int
+privsep_preauth(Authctxt *authctxt)
+{
+       int status;
+       pid_t pid;
+
+       /* Set up unprivileged child process to deal with network data */
+       pmonitor = monitor_init();
+       /* Store a pointer to the kex for later rekeying */
+       pmonitor->m_pkex = &xxx_kex;
+
+       pid = fork();
+       if (pid == -1) {
+               fatal("fork of unprivileged child failed");
+       } else if (pid != 0) {
+               debug2("Network child is on pid %ld", (long)pid);
+
+               close(pmonitor->m_recvfd);
+               pmonitor->m_pid = pid;
+               monitor_child_preauth(authctxt, pmonitor);
+               close(pmonitor->m_sendfd);
+
+               /* Sync memory */
+               monitor_sync(pmonitor);
+
+               /* Wait for the child's exit status */
+               while (waitpid(pid, &status, 0) < 0)
+                       if (errno != EINTR)
+                               break;
+               return (1);
+       } else {
+               /* child */
+
+               close(pmonitor->m_sendfd);
+
+               /* Demote the child */
+               if (getuid() == 0 || geteuid() == 0)
+                       privsep_preauth_child();
+               setproctitle("%s", "[net]");
+       }
+       return (0);
+}
+
+static void
+privsep_postauth(Authctxt *authctxt)
+{
+       u_int32_t rnd[256];
+
+#ifdef DISABLE_FD_PASSING
+       if (1) {
+#else
+       if (authctxt->pw->pw_uid == 0 || options.use_login) {
+#endif
+               /* File descriptor passing is broken or root login */
+               use_privsep = 0;
+               goto skip;
+       }
+
+       /* New socket pair */
+       monitor_reinit(pmonitor);
+
+       pmonitor->m_pid = fork();
+       if (pmonitor->m_pid == -1)
+               fatal("fork of unprivileged child failed");
+       else if (pmonitor->m_pid != 0) {
+               verbose("User child is on pid %ld", (long)pmonitor->m_pid);
+               close(pmonitor->m_recvfd);
+               buffer_clear(&loginmsg);
+               monitor_child_postauth(pmonitor);
+
+               /* NEVERREACHED */
+               exit(0);
+       }
+
+       close(pmonitor->m_sendfd);
+
+       /* Demote the private keys to public keys. */
+       demote_sensitive_data();
+
+       arc4random_stir();
+       arc4random_buf(rnd, sizeof(rnd));
+       RAND_seed(rnd, sizeof(rnd));
+
+       /* Drop privileges */
+       do_setusercontext(authctxt->pw);
+
+ skip:
+       /* It is safe now to apply the key state */
+       monitor_apply_keystate(pmonitor);
+
+       /*
+        * Tell the packet layer that authentication was successful, since
+        * this information is not part of the key state.
+        */
+       packet_set_authenticated();
+}
+
+static char *
+list_hostkey_types(void)
+{
+       Buffer b;
+       const char *p;
+       char *ret;
+       int i;
+       Key *key;
+
+       buffer_init(&b);
+       for (i = 0; i < options.num_host_key_files; i++) {
+               key = sensitive_data.host_keys[i];
+               if (key == NULL)
+                       continue;
+               switch (key->type) {
+               case KEY_RSA:
+               case KEY_DSA:
+               case KEY_ECDSA:
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       p = key_ssh_name(key);
+                       buffer_append(&b, p, strlen(p));
+                       break;
+               }
+               /* If the private key has a cert peer, then list that too */
+               key = sensitive_data.host_certificates[i];
+               if (key == NULL)
+                       continue;
+               switch (key->type) {
+               case KEY_RSA_CERT_V00:
+               case KEY_DSA_CERT_V00:
+               case KEY_RSA_CERT:
+               case KEY_DSA_CERT:
+               case KEY_ECDSA_CERT:
+                       if (buffer_len(&b) > 0)
+                               buffer_append(&b, ",", 1);
+                       p = key_ssh_name(key);
+                       buffer_append(&b, p, strlen(p));
+                       break;
+               }
+       }
+       buffer_append(&b, "\0", 1);
+       ret = xstrdup(buffer_ptr(&b));
+       buffer_free(&b);
+       debug("list_hostkey_types: %s", ret);
+       return ret;
+}
+
+static Key *
+get_hostkey_by_type(int type, int need_private)
+{
+       int i;
+       Key *key;
+
+       for (i = 0; i < options.num_host_key_files; i++) {
+               switch (type) {
+               case KEY_RSA_CERT_V00:
+               case KEY_DSA_CERT_V00:
+               case KEY_RSA_CERT:
+               case KEY_DSA_CERT:
+               case KEY_ECDSA_CERT:
+                       key = sensitive_data.host_certificates[i];
+                       break;
+               default:
+                       key = sensitive_data.host_keys[i];
+                       break;
+               }
+               if (key != NULL && key->type == type)
+                       return need_private ?
+                           sensitive_data.host_keys[i] : key;
+       }
+       return NULL;
+}
+
+Key *
+get_hostkey_public_by_type(int type)
+{
+       return get_hostkey_by_type(type, 0);
+}
+
+Key *
+get_hostkey_private_by_type(int type)
+{
+       return get_hostkey_by_type(type, 1);
+}
+
+Key *
+get_hostkey_by_index(int ind)
+{
+       if (ind < 0 || ind >= options.num_host_key_files)
+               return (NULL);
+       return (sensitive_data.host_keys[ind]);
+}
+
+int
+get_hostkey_index(Key *key)
+{
+       int i;
+
+       for (i = 0; i < options.num_host_key_files; i++) {
+               if (key_is_cert(key)) {
+                       if (key == sensitive_data.host_certificates[i])
+                               return (i);
+               } else {
+                       if (key == sensitive_data.host_keys[i])
+                               return (i);
+               }
+       }
+       return (-1);
+}
+
+/*
+ * 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)
+{
+       int 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 /= options.max_startups - options.max_startups_begin;
+       p += options.max_startups_rate;
+       r = arc4random_uniform(100);
+
+       debug("drop_connection: p %d, r %d", p, r);
+       return (r < p) ? 1 : 0;
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "%s, %s\n",
+           SSH_RELEASE, SSLeay_version(SSLEAY_VERSION));
+       fprintf(stderr,
+"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n"
+"            [-f config_file] [-g login_grace_time] [-h host_key_file]\n"
+"            [-k key_gen_time] [-o option] [-p port] [-u len]\n"
+       );
+       exit(1);
+}
+
+static void
+send_rexec_state(int fd, Buffer *conf)
+{
+       Buffer m;
+
+       debug3("%s: entering fd = %d config len %d", __func__, fd,
+           buffer_len(conf));
+
+       /*
+        * Protocol from reexec master to child:
+        *      string  configuration
+        *      u_int   ephemeral_key_follows
+        *      bignum  e               (only if ephemeral_key_follows == 1)
+        *      bignum  n                       "
+        *      bignum  d                       "
+        *      bignum  iqmp                    "
+        *      bignum  p                       "
+        *      bignum  q                       "
+        *      string rngseed          (only if OpenSSL is not self-seeded)
+        */
+       buffer_init(&m);
+       buffer_put_cstring(&m, buffer_ptr(conf));
+
+       if (sensitive_data.server_key != NULL &&
+           sensitive_data.server_key->type == KEY_RSA1) {
+               buffer_put_int(&m, 1);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->e);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->n);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->d);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->p);
+               buffer_put_bignum(&m, sensitive_data.server_key->rsa->q);
+       } else
+               buffer_put_int(&m, 0);
+
+#ifndef OPENSSL_PRNG_ONLY
+       rexec_send_rng_seed(&m);
+#endif
+
+       if (ssh_msg_send(fd, 0, &m) == -1)
+               fatal("%s: ssh_msg_send failed", __func__);
+
+       buffer_free(&m);
+
+       debug3("%s: done", __func__);
+}
+
+static void
+recv_rexec_state(int fd, Buffer *conf)
+{
+       Buffer m;
+       char *cp;
+       u_int len;
+
+       debug3("%s: entering fd = %d", __func__, fd);
+
+       buffer_init(&m);
+
+       if (ssh_msg_recv(fd, &m) == -1)
+               fatal("%s: ssh_msg_recv failed", __func__);
+       if (buffer_get_char(&m) != 0)
+               fatal("%s: rexec version mismatch", __func__);
+
+       cp = buffer_get_string(&m, &len);
+       if (conf != NULL)
+               buffer_append(conf, cp, len + 1);
+       xfree(cp);
+
+       if (buffer_get_int(&m)) {
+               if (sensitive_data.server_key != NULL)
+                       key_free(sensitive_data.server_key);
+               sensitive_data.server_key = key_new_private(KEY_RSA1);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->e);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->n);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->d);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->p);
+               buffer_get_bignum(&m, sensitive_data.server_key->rsa->q);
+               rsa_generate_additional_parameters(
+                   sensitive_data.server_key->rsa);
+       }
+
+#ifndef OPENSSL_PRNG_ONLY
+       rexec_recv_rng_seed(&m);
+#endif
+
+       buffer_free(&m);
+
+       debug3("%s: done", __func__);
+}
+
+/* Accept a connection from inetd */
+static void
+server_accept_inetd(int *sock_in, int *sock_out)
+{
+       int fd;
+
+       startup_pipe = -1;
+       if (rexeced_flag) {
+               close(REEXEC_CONFIG_PASS_FD);
+               *sock_in = *sock_out = dup(STDIN_FILENO);
+               if (!debug_flag) {
+                       startup_pipe = dup(REEXEC_STARTUP_PIPE_FD);
+                       close(REEXEC_STARTUP_PIPE_FD);
+               }
+       } else {
+               *sock_in = dup(STDIN_FILENO);
+               *sock_out = dup(STDOUT_FILENO);
+       }
+       /*
+        * 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.
+        */
+       if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+               dup2(fd, STDIN_FILENO);
+               dup2(fd, STDOUT_FILENO);
+               if (fd > STDOUT_FILENO)
+                       close(fd);
+       }
+       debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out);
+}
+
+/*
+ * Listen for TCP connections
+ */
+static void
+server_listen(void)
+{
+       int ret, listen_sock, on = 1;
+       struct addrinfo *ai;
+       char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+
+       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 ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen,
+                   ntop, sizeof(ntop), strport, sizeof(strport),
+                   NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+                       error("getnameinfo failed: %.100s",
+                           ssh_gai_strerror(ret));
+                       continue;
+               }
+               /* Create socket for listening. */
+               listen_sock = socket(ai->ai_family, ai->ai_socktype,
+                   ai->ai_protocol);
+               if (listen_sock < 0) {
+                       /* kernel may not support ipv6 */
+                       verbose("socket: %.100s", strerror(errno));
+                       continue;
+               }
+               if (set_nonblock(listen_sock) == -1) {
+                       close(listen_sock);
+                       continue;
+               }
+               /*
+                * Set socket options.
+                * Allow local port reuse in TIME_WAIT.
+                */
+               if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,
+                   &on, sizeof(on)) == -1)
+                       error("setsockopt SO_REUSEADDR: %s", strerror(errno));
+
+               /* Only communicate in IPv6 over AF_INET6 sockets. */
+               if (ai->ai_family == AF_INET6)
+                       sock_set_v6only(listen_sock);
+
+               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) {
+                       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. */
+               if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0)
+                       fatal("listen on [%s]:%s: %.100s",
+                           ntop, strport, strerror(errno));
+               logit("Server listening on %s port %s.", ntop, strport);
+       }
+       freeaddrinfo(options.listen_addrs);
+
+       if (!num_listen_socks)
+               fatal("Cannot bind any address.");
+}
+
+/*
+ * The main TCP accept loop. Note that, for the non-debug case, returns
+ * from this function are in a forked subprocess.
+ */
+static void
+server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
+{
+       fd_set *fdset;
+       int i, j, ret, maxfd;
+       int key_used = 0, startups = 0;
+       int startup_p[2] = { -1 , -1 };
+       struct sockaddr_storage from;
+       socklen_t fromlen;
+       pid_t pid;
+
+       /* setup fd set for accept */
+       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 = xcalloc(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);
+               fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS),
+                   sizeof(fd_mask));
+
+               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) {
+                       logit("Received signal %d; terminating.",
+                           (int) 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 != EAGAIN &&
+                                   errno != EWOULDBLOCK)
+                                       error("accept: %.100s", strerror(errno));
+                               continue;
+                       }
+                       if (unset_nonblock(*newsock) == -1) {
+                               close(*newsock);
+                               continue;
+                       }
+                       if (drop_connection(startups) == 1) {
+                               debug("drop connection #%d", startups);
+                               close(*newsock);
+                               continue;
+                       }
+                       if (pipe(startup_p) == -1) {
+                               close(*newsock);
+                               continue;
+                       }
+
+                       if (rexec_flag && socketpair(AF_UNIX,
+                           SOCK_STREAM, 0, config_s) == -1) {
+                               error("reexec socketpair: %s",
+                                   strerror(errno));
+                               close(*newsock);
+                               close(startup_p[0]);
+                               close(startup_p[1]);
+                               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;
+                               close(startup_p[0]);
+                               close(startup_p[1]);
+                               startup_pipe = -1;
+                               pid = getpid();
+                               if (rexec_flag) {
+                                       send_rexec_state(config_s[0],
+                                           &cfg);
+                                       close(config_s[0]);
+                               }
+                               break;
+                       }
+
+                       /*
+                        * Normal production daemon.  Fork, and have
+                        * the child process the connection. The
+                        * parent continues listening.
+                        */
+                       platform_pre_fork();
+                       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.
+                                */
+                               platform_post_fork_child();
+                               startup_pipe = startup_p[1];
+                               close_startup_pipes();
+                               close_listen_socks();
+                               *sock_in = *newsock;
+                               *sock_out = *newsock;
+                               log_init(__progname,
+                                   options.log_level,
+                                   options.log_facility,
+                                   log_stderr);
+                               if (rexec_flag)
+                                       close(config_s[0]);
+                               break;
+                       }
+
+                       /* Parent.  Stay in the loop. */
+                       platform_post_fork_parent(pid);
+                       if (pid < 0)
+                               error("fork: %.100s", strerror(errno));
+                       else
+                               debug("Forked child %ld.", (long)pid);
+
+                       close(startup_p[1]);
+
+                       if (rexec_flag) {
+                               send_rexec_state(config_s[0], &cfg);
+                               close(config_s[0]);
+                               close(config_s[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;
+                       }
+
+                       close(*newsock);
+
+                       /*
+                        * Ensure that our random state differs
+                        * from that of the child
+                        */
+                       arc4random_stir();
+               }
+
+               /* child process check (or debug mode) */
+               if (num_listen_socks < 0)
+                       break;
+       }
+}
+
+
+/*
+ * Main program for the daemon.
+ */
+int
+main(int ac, char **av)
+{
+       extern char *optarg;
+       extern int optind;
+       int opt, i, j, on = 1;
+       int sock_in = -1, sock_out = -1, newsock = -1;
+       const char *remote_ip;
+       char *test_user = NULL, *test_host = NULL, *test_addr = NULL;
+       int remote_port;
+       char *line, *p, *cp;
+       int config_s[2] = { -1 , -1 };
+       u_int64_t ibytes, obytes;
+       mode_t new_umask;
+       Key *key;
+       Authctxt *authctxt;
+
+#ifdef HAVE_SECUREWARE
+       (void)set_auth_parameters(ac, av);
+#endif
+       __progname = ssh_get_progname(av[0]);
+       init_rng();
+
+       /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
+       saved_argc = ac;
+       rexec_argc = ac;
+       saved_argv = xcalloc(ac + 1, sizeof(*saved_argv));
+       for (i = 0; i < ac; i++)
+               saved_argv[i] = xstrdup(av[i]);
+       saved_argv[i] = NULL;
+
+#ifndef HAVE_SETPROCTITLE
+       /* Prepare for later setproctitle emulation */
+       compat_init_setproctitle(ac, av);
+       av = saved_argv;
+#endif
+
+       if (geteuid() == 0 && setgroups(0, NULL) == -1)
+               debug("setgroups(): %.200s", strerror(errno));
+
+       /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+       sanitise_stdfd();
+
+       /* 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:u:o:C:dDeiqrtQRT46")) != -1) {
+               switch (opt) {
+               case '4':
+                       options.address_family = AF_INET;
+                       break;
+               case '6':
+                       options.address_family = AF_INET6;
+                       break;
+               case 'f':
+                       config_file_name = optarg;
+                       break;
+               case 'c':
+                       if (options.num_host_cert_files >= MAX_HOSTCERTS) {
+                               fprintf(stderr, "too many host certificates.\n");
+                               exit(1);
+                       }
+                       options.host_cert_files[options.num_host_cert_files++] =
+                          derelativise_path(optarg);
+                       break;
+               case 'd':
+                       if (debug_flag == 0) {
+                               debug_flag = 1;
+                               options.log_level = SYSLOG_LEVEL_DEBUG1;
+                       } else if (options.log_level < SYSLOG_LEVEL_DEBUG3)
+                               options.log_level++;
+                       break;
+               case 'D':
+                       no_daemon_flag = 1;
+                       break;
+               case 'e':
+                       log_stderr = 1;
+                       break;
+               case 'i':
+                       inetd_flag = 1;
+                       break;
+               case 'r':
+                       rexec_flag = 0;
+                       break;
+               case 'R':
+                       rexeced_flag = 1;
+                       inetd_flag = 1;
+                       break;
+               case 'Q':
+                       /* ignored */
+                       break;
+               case 'q':
+                       options.log_level = SYSLOG_LEVEL_QUIET;
+                       break;
+               case 'b':
+                       options.server_key_bits = (int)strtonum(optarg, 256,
+                           32768, NULL);
+                       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++] = 
+                          derelativise_path(optarg);
+                       break;
+               case 't':
+                       test_flag = 1;
+                       break;
+               case 'T':
+                       test_flag = 2;
+                       break;
+               case 'C':
+                       cp = optarg;
+                       while ((p = strsep(&cp, ",")) && *p != '\0') {
+                               if (strncmp(p, "addr=", 5) == 0)
+                                       test_addr = xstrdup(p + 5);
+                               else if (strncmp(p, "host=", 5) == 0)
+                                       test_host = xstrdup(p + 5);
+                               else if (strncmp(p, "user=", 5) == 0)
+                                       test_user = xstrdup(p + 5);
+                               else {
+                                       fprintf(stderr, "Invalid test "
+                                           "mode specification %s\n", p);
+                                       exit(1);
+                               }
+                       }
+                       break;
+               case 'u':
+                       utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL);
+                       if (utmp_len > MAXHOSTNAMELEN) {
+                               fprintf(stderr, "Invalid utmp length.\n");
+                               exit(1);
+                       }
+                       break;
+               case 'o':
+                       line = xstrdup(optarg);
+                       if (process_server_config_line(&options, line,
+                           "command-line", 0, NULL, NULL, NULL, NULL) != 0)
+                               exit(1);
+                       xfree(line);
+                       break;
+               case '?':
+               default:
+                       usage();
+                       break;
+               }
+       }
+       if (rexeced_flag || inetd_flag)
+               rexec_flag = 0;
+       if (!test_flag && (rexec_flag && (av[0] == NULL || *av[0] != '/')))
+               fatal("sshd re-exec requires execution with an absolute path");
+       if (rexeced_flag)
+               closefrom(REEXEC_MIN_FREE_FD);
+       else
+               closefrom(REEXEC_DEVCRYPTO_RESERVED_FD);
+
+       OpenSSL_add_all_algorithms();
+
+       /*
+        * Force logging to stderr until we have loaded the private host
+        * key (unless started from inetd)
+        */
+       log_init(__progname,
+           options.log_level == SYSLOG_LEVEL_NOT_SET ?
+           SYSLOG_LEVEL_INFO : options.log_level,
+           options.log_facility == SYSLOG_FACILITY_NOT_SET ?
+           SYSLOG_FACILITY_AUTH : options.log_facility,
+           log_stderr || !inetd_flag);
+
+       /*
+        * Unset KRB5CCNAME, otherwise the user's session may inherit it from
+        * root's environment
+        */
+       if (getenv("KRB5CCNAME") != NULL)
+               unsetenv("KRB5CCNAME");
+
+#ifdef _UNICOS
+       /* Cray can define user privs drop all privs now!
+        * Not needed on PRIV_SU systems!
+        */
+       drop_cray_privs();
+#endif
+
+       sensitive_data.server_key = NULL;
+       sensitive_data.ssh1_host_key = NULL;
+       sensitive_data.have_ssh1_key = 0;
+       sensitive_data.have_ssh2_key = 0;
+
+       /*
+        * If we're doing an extended config test, make sure we have all of
+        * the parameters we need.  If we're not doing an extended test,
+        * do not silently ignore connection test params.
+        */
+       if (test_flag >= 2 &&
+          (test_user != NULL || test_host != NULL || test_addr != NULL)
+           && (test_user == NULL || test_host == NULL || test_addr == NULL))
+               fatal("user, host and addr are all required when testing "
+                  "Match configs");
+       if (test_flag < 2 && (test_user != NULL || test_host != NULL ||
+           test_addr != NULL))
+               fatal("Config test connection parameter (-C) provided without "
+                  "test mode (-T)");
+
+       /* Fetch our configuration */
+       buffer_init(&cfg);
+       if (rexeced_flag)
+               recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg);
+       else
+               load_server_config(config_file_name, &cfg);
+
+       parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
+           &cfg, NULL, NULL, NULL);
+
+       seed_rng();
+
+       /* Fill in default values for those options not explicitly set. */
+       fill_default_server_options(&options);
+
+       /* challenge-response is implemented via keyboard interactive */
+       if (options.challenge_response_authentication)
+               options.kbd_interactive_authentication = 1;
+
+       /* set default channel AF */
+       channel_set_af(options.address_family);
+
+       /* 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_RELEASE);
+
+       /* Store privilege separation user for later use if required. */
+       if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) {
+               if (use_privsep || options.kerberos_authentication)
+                       fatal("Privilege separation user %s does not exist",
+                           SSH_PRIVSEP_USER);
+       } else {
+               memset(privsep_pw->pw_passwd, 0, strlen(privsep_pw->pw_passwd));
+               privsep_pw = pwcopy(privsep_pw);
+               xfree(privsep_pw->pw_passwd);
+               privsep_pw->pw_passwd = xstrdup("*");
+       }
+       endpwent();
+
+       /* load private host keys */
+       sensitive_data.host_keys = xcalloc(options.num_host_key_files,
+           sizeof(Key *));
+       for (i = 0; i < options.num_host_key_files; i++)
+               sensitive_data.host_keys[i] = NULL;
+
+       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:
+               case KEY_ECDSA:
+                       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) {
+               logit("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) {
+               logit("Disabling protocol version 2. Could not load host key");
+               options.protocol &= ~SSH_PROTO_2;
+       }
+       if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
+               logit("sshd: no hostkeys available -- exiting.");
+               exit(1);
+       }
+
+       /*
+        * Load certificates. They are stored in an array at identical
+        * indices to the public keys that they relate to.
+        */
+       sensitive_data.host_certificates = xcalloc(options.num_host_key_files,
+           sizeof(Key *));
+       for (i = 0; i < options.num_host_key_files; i++)
+               sensitive_data.host_certificates[i] = NULL;
+
+       for (i = 0; i < options.num_host_cert_files; i++) {
+               key = key_load_public(options.host_cert_files[i], NULL);
+               if (key == NULL) {
+                       error("Could not load host certificate: %s",
+                           options.host_cert_files[i]);
+                       continue;
+               }
+               if (!key_is_cert(key)) {
+                       error("Certificate file is not a certificate: %s",
+                           options.host_cert_files[i]);
+                       key_free(key);
+                       continue;
+               }
+               /* Find matching private key */
+               for (j = 0; j < options.num_host_key_files; j++) {
+                       if (key_equal_public(key,
+                           sensitive_data.host_keys[j])) {
+                               sensitive_data.host_certificates[j] = key;
+                               break;
+                       }
+               }
+               if (j >= options.num_host_key_files) {
+                       error("No matching private key for certificate: %s",
+                           options.host_cert_files[i]);
+                       key_free(key);
+                       continue;
+               }
+               sensitive_data.host_certificates[j] = key;
+               debug("host certificate: #%d type %d %s", j, key->type,
+                   key_type(key));
+       }
+       /* 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);
+               }
+       }
+
+       if (use_privsep) {
+               struct stat st;
+
+               if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) ||
+                   (S_ISDIR(st.st_mode) == 0))
+                       fatal("Missing privilege separation directory: %s",
+                           _PATH_PRIVSEP_CHROOT_DIR);
+
+#ifdef HAVE_CYGWIN
+               if (check_ntsec(_PATH_PRIVSEP_CHROOT_DIR) &&
+                   (st.st_uid != getuid () ||
+                   (st.st_mode & (S_IWGRP|S_IWOTH)) != 0))
+#else
+               if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0)
+#endif
+                       fatal("%s must be owned by root and not group or "
+                           "world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
+       }
+
+       if (test_flag > 1) {
+               if (test_user != NULL && test_addr != NULL && test_host != NULL)
+                       parse_server_match_config(&options, test_user,
+                           test_host, test_addr);
+               dump_config(&options);
+       }
+
+       /* Configuration looks good, so exit if in test mode. */
+       if (test_flag)
+               exit(0);
+
+       /*
+        * Clear out any supplemental groups we may have inherited.  This
+        * prevents inadvertent creation of files with bad modes (in the
+        * portable version at least, it's certainly possible for PAM
+        * to create a file, and we can't control the code in every
+        * module which might be used).
+        */
+       if (setgroups(0, NULL) < 0)
+               debug("setgroups() failed: %.200s", strerror(errno));
+
+       if (rexec_flag) {
+               rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *));
+               for (i = 0; i < rexec_argc; i++) {
+                       debug("rexec_argv[%d]='%s'", i, saved_argv[i]);
+                       rexec_argv[i] = saved_argv[i];
+               }
+               rexec_argv[rexec_argc] = "-R";
+               rexec_argv[rexec_argc + 1] = NULL;
+       }
+
+       /* Ensure that umask disallows at least group and world write */
+       new_umask = umask(0077) | 0022;
+       (void) umask(new_umask);
+
+       /* Initialize the log (it is reinitialized below in case we forked). */
+       if (debug_flag && (!inetd_flag || rexeced_flag))
+               log_stderr = 1;
+       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);
+
+       /* Get a connection, either from inetd or a listening TCP socket */
+       if (inetd_flag) {
+               server_accept_inetd(&sock_in, &sock_out);
+       } else {
+               platform_pre_listen();
+               server_listen();
+
+               if (options.protocol & SSH_PROTO_1)
+                       generate_ephemeral_server_key();
+
+               signal(SIGHUP, sighup_handler);
+               signal(SIGCHLD, main_sigchld_handler);
+               signal(SIGTERM, sigterm_handler);
+               signal(SIGQUIT, sigterm_handler);
+
+               /*
+                * Write out the pid file after the sigterm handler
+                * is setup and the listen sockets are bound
+                */
+               if (!debug_flag) {
+                       FILE *f = fopen(options.pid_file, "w");
+
+                       if (f == NULL) {
+                               error("Couldn't create pid file \"%s\": %s",
+                                   options.pid_file, strerror(errno));
+                       } else {
+                               fprintf(f, "%ld\n", (long) getpid());
+                               fclose(f);
+                       }
+               }
+
+               /* Accept a connection and return in a forked child */
+               server_accept_loop(&sock_in, &sock_out,
+                   &newsock, config_s);
+       }
+
+       /* This is the child processing a new connection. */
+       setproctitle("%s", "[accepted]");
+
+       /*
+        * Create a new session and process group since the 4.4BSD
+        * setlogin() affects the entire process group.  We don't
+        * want the child to be able to affect the parent.
+        */
+#if !defined(SSHD_ACQUIRES_CTTY)
+       /*
+        * If setsid is called, on some platforms sshd will later acquire a
+        * controlling terminal which will result in "could not set
+        * controlling tty" errors.
+        */
+       if (!debug_flag && !inetd_flag && setsid() < 0)
+               error("setsid: %.100s", strerror(errno));
+#endif
+
+       if (rexec_flag) {
+               int fd;
+
+               debug("rexec start in %d out %d newsock %d pipe %d sock %d",
+                   sock_in, sock_out, newsock, startup_pipe, config_s[0]);
+               dup2(newsock, STDIN_FILENO);
+               dup2(STDIN_FILENO, STDOUT_FILENO);
+               if (startup_pipe == -1)
+                       close(REEXEC_STARTUP_PIPE_FD);
+               else
+                       dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD);
+
+               dup2(config_s[1], REEXEC_CONFIG_PASS_FD);
+               close(config_s[1]);
+               if (startup_pipe != -1)
+                       close(startup_pipe);
+
+               execv(rexec_argv[0], rexec_argv);
+
+               /* Reexec has failed, fall back and continue */
+               error("rexec of %s failed: %s", rexec_argv[0], strerror(errno));
+               recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL);
+               log_init(__progname, options.log_level,
+                   options.log_facility, log_stderr);
+
+               /* Clean up fds */
+               startup_pipe = REEXEC_STARTUP_PIPE_FD;
+               close(config_s[1]);
+               close(REEXEC_CONFIG_PASS_FD);
+               newsock = sock_out = sock_in = dup(STDIN_FILENO);
+               if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+                       dup2(fd, STDIN_FILENO);
+                       dup2(fd, STDOUT_FILENO);
+                       if (fd > STDERR_FILENO)
+                               close(fd);
+               }
+               debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d",
+                   sock_in, sock_out, newsock, startup_pipe, config_s[0]);
+       }
+
+       /* Executed child processes don't need these. */
+       fcntl(sock_out, F_SETFD, FD_CLOEXEC);
+       fcntl(sock_in, F_SETFD, FD_CLOEXEC);
+
+       /*
+        * 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);
+
+       /*
+        * Register our connection.  This turns encryption off because we do
+        * not have a key.
+        */
+       packet_set_connection(sock_in, sock_out);
+       packet_set_server();
+
+       /* Set SO_KEEPALIVE if requested. */
+       if (options.tcp_keep_alive && packet_connection_is_on_socket() &&
+           setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
+               error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));
+
+       if ((remote_port = get_remote_port()) < 0) {
+               debug("get_remote_port failed");
+               cleanup_exit(255);
+       }
+
+       /*
+        * We use get_canonical_hostname with usedns = 0 instead of
+        * get_remote_ipaddr here so IP options will be checked.
+        */
+       (void) get_canonical_hostname(0);
+       /*
+        * The rest of the code depends on the fact that
+        * get_remote_ipaddr() caches the remote ip, even if
+        * the socket goes away.
+        */
+       remote_ip = get_remote_ipaddr();
+
+#ifdef SSH_AUDIT_EVENTS
+       audit_connection_from(remote_ip, remote_port);
+#endif
+#ifdef LIBWRAP
+       allow_severity = options.log_facility|LOG_INFO;
+       deny_severity = options.log_facility|LOG_WARNING;
+       /* Check whether logins are denied from this host. */
+       if (packet_connection_is_on_socket()) {
+               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);
+
+       /* In inetd mode, generate ephemeral key only for proto 1 connections */
+       if (!compat20 && inetd_flag && sensitive_data.server_key == NULL)
+               generate_ephemeral_server_key();
+
+       packet_set_nonblocking();
+
+       /* allocate authentication context */
+       authctxt = xcalloc(1, sizeof(*authctxt));
+
+       authctxt->loginmsg = &loginmsg;
+
+       /* XXX global for cleanup, access from other modules */
+       the_authctxt = authctxt;
+
+       /* prepare buffer to collect messages to display to user after login */
+       buffer_init(&loginmsg);
+       auth_debug_reset();
+
+       if (use_privsep)
+               if (privsep_preauth(authctxt) == 1)
+                       goto authenticated;
+
+       /* perform the key exchange */
+       /* authenticate user and start session */
+       if (compat20) {
+               do_ssh2_kex();
+               do_authentication2(authctxt);
+       } else {
+               do_ssh1_kex();
+               do_authentication(authctxt);
+       }
+       /*
+        * If we use privilege separation, the unprivileged child transfers
+        * the current keystate and exits
+        */
+       if (use_privsep) {
+               mm_send_keystate(pmonitor);
+               exit(0);
+       }
+
+ authenticated:
+       /*
+        * Cancel the alarm we set to limit the time taken for
+        * authentication.
+        */
+       alarm(0);
+       signal(SIGALRM, SIG_DFL);
+       authctxt->authenticated = 1;
+       if (startup_pipe != -1) {
+               close(startup_pipe);
+               startup_pipe = -1;
+       }
+
+#ifdef SSH_AUDIT_EVENTS
+       audit_event(SSH_AUTH_SUCCESS);
+#endif
+
+#ifdef GSSAPI
+       if (options.gss_authentication) {
+               temporarily_use_uid(authctxt->pw);
+               ssh_gssapi_storecreds();
+               restore_uid();
+       }
+#endif
+#ifdef USE_PAM
+       if (options.use_pam) {
+               do_pam_setcred(1);
+               do_pam_session();
+       }
+#endif
+
+       /*
+        * In privilege separation, we fork another child and prepare
+        * file descriptor passing.
+        */
+       if (use_privsep) {
+               privsep_postauth(authctxt);
+               /* the monitor process [priv] will not return */
+               if (!compat20)
+                       destroy_sensitive_data();
+       }
+
+       packet_set_timeout(options.client_alive_interval,
+           options.client_alive_count_max);
+
+       /* Start session. */
+       do_authenticated(authctxt);
+
+       /* The connection has been terminated. */
+       packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes);
+       packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes);
+       verbose("Transferred: sent %llu, received %llu bytes",
+           (unsigned long long)obytes, (unsigned long long)ibytes);
+
+       verbose("Closing connection to %.500s port %d", remote_ip, remote_port);
+
+#ifdef USE_PAM
+       if (options.use_pam)
+               finish_pam();
+#endif /* USE_PAM */
+
+#ifdef SSH_AUDIT_EVENTS
+       PRIVSEP(audit_event(SSH_CONNECTION_CLOSE));
+#endif
+
+       packet_close();
+
+       if (use_privsep)
+               mm_terminate();
+
+       exit(0);
+}
+
+/*
+ * Decrypt session_key_int using our private server key and private host key
+ * (key with larger modulus first).
+ */
+int
+ssh1_session_key(BIGNUM *session_key_int)
+{
+       int rsafail = 0;
+
+       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++;
+       }
+       return (rsafail);
+}
+/*
+ * SSH1 key exchange
+ */
+static void
+do_ssh1_kex(void)
+{
+       int i, len;
+       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;
+
+       /*
+        * 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.
+        */
+       arc4random_buf(cookie, sizeof(cookie));
+
+       /*
+        * 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_rsa_authentication)
+               auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA;
+       if (options.rsa_authentication)
+               auth_mask |= 1 << SSH_AUTH_RSA;
+       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(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. */
+       if ((session_key_int = BN_new()) == NULL)
+               fatal("do_ssh1_kex: BN_new failed");
+       packet_get_bignum(session_key_int);
+
+       protocol_flags = packet_get_int();
+       packet_set_protocol_flags(protocol_flags);
+       packet_check_eom();
+
+       /* Decrypt session_key_int using host/server keys */
+       rsafail = PRIVSEP(ssh1_session_key(session_key_int));
+
+       /*
+        * 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) {
+               (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8);
+               len = BN_num_bytes(session_key_int);
+               if (len < 0 || (u_int)len > sizeof(session_key)) {
+                       error("do_ssh1_kex: 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);
+
+                       derive_ssh1_session_id(
+                           sensitive_data.ssh1_host_key->rsa->n,
+                           sensitive_data.server_key->rsa->n,
+                           cookie, session_id);
+                       /*
+                        * 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);
+               u_char *buf = xmalloc(bytes);
+               MD5_CTX md;
+
+               logit("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. No longer. */
+       destroy_sensitive_data();
+
+       if (use_privsep)
+               mm_ssh1_session_id(session_id);
+
+       /* 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 acknowledgment 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;
+       }
+       if (options.compression == COMP_NONE) {
+               myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+               myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
+       } else if (options.compression == COMP_DELAYED) {
+               myproposal[PROPOSAL_COMP_ALGS_CTOS] =
+               myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com";
+       }
+       if (options.kex_algorithms != NULL)
+               myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;
+
+       myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
+
+       /* start key exchange */
+       kex = kex_setup(myproposal);
+       kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
+       kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
+       kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+       kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
+       kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
+       kex->server = 1;
+       kex->client_version_string=client_version_string;
+       kex->server_version_string=server_version_string;
+       kex->load_host_public_key=&get_hostkey_public_by_type;
+       kex->load_host_private_key=&get_hostkey_private_by_type;
+       kex->host_key_index=&get_hostkey_index;
+
+       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");
+}
+
+/* server specific fatal cleanup */
+void
+cleanup_exit(int i)
+{
+       if (the_authctxt)
+               do_cleanup(the_authctxt);
+#ifdef SSH_AUDIT_EVENTS
+       /* done after do_cleanup so it can cancel the PAM auth 'thread' */
+       if (!use_privsep || mm_is_monitor())
+               audit_event(SSH_CONNECTION_ABANDON);
+#endif
+       _exit(i);
+}
diff --git a/sshd_config b/sshd_config
new file mode 100644 (file)
index 0000000..4534841
--- /dev/null
@@ -0,0 +1,118 @@
+#      $OpenBSD: sshd_config,v 1.82 2010/09/06 17:10:19 naddy Exp $
+
+# This is the sshd server system-wide configuration file.  See
+# sshd_config(5) for more information.
+
+# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
+
+# The strategy used for options in the default sshd_config shipped with
+# OpenSSH is to specify options with their default value where
+# possible, but leave them commented.  Uncommented options change a
+# default value.
+
+#Port 22
+#AddressFamily any
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# The default requires explicit activation of protocol 1
+#Protocol 2
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_dsa_key
+#HostKey /etc/ssh/ssh_host_ecdsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 1h
+#ServerKeyBits 1024
+
+# Logging
+# obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+#LogLevel INFO
+
+# Authentication:
+
+#LoginGraceTime 2m
+#PermitRootLogin yes
+#StrictModes yes
+#MaxAuthTries 6
+#MaxSessions 10
+
+#RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile    .ssh/authorized_keys
+
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
+# similar for protocol version 2
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+
+# To disable tunneled clear text passwords, change to no here!
+#PasswordAuthentication yes
+#PermitEmptyPasswords no
+
+# Change to no to disable s/key passwords
+#ChallengeResponseAuthentication yes
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+#KerberosGetAFSToken no
+
+# GSSAPI options
+#GSSAPIAuthentication no
+#GSSAPICleanupCredentials yes
+
+# Set this to 'yes' to enable PAM authentication, account processing, 
+# and session processing. If this is enabled, PAM authentication will 
+# be allowed through the ChallengeResponseAuthentication and
+# PasswordAuthentication.  Depending on your PAM configuration,
+# PAM authentication via ChallengeResponseAuthentication may bypass
+# the setting of "PermitRootLogin without-password".
+# If you just want the PAM account and session checks to run without
+# PAM authentication, then enable this but set PasswordAuthentication
+# and ChallengeResponseAuthentication to 'no'.
+#UsePAM no
+
+#AllowAgentForwarding yes
+#AllowTcpForwarding yes
+#GatewayPorts no
+#X11Forwarding no
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#TCPKeepAlive yes
+#UseLogin no
+#UsePrivilegeSeparation yes
+#PermitUserEnvironment no
+#Compression delayed
+#ClientAliveInterval 0
+#ClientAliveCountMax 3
+#UseDNS yes
+#PidFile /var/run/sshd.pid
+#MaxStartups 10
+#PermitTunnel no
+#ChrootDirectory none
+
+# no default banner path
+#Banner none
+
+# override default of no subsystems
+Subsystem      sftp    /usr/libexec/sftp-server
+
+# Example of overriding settings on a per-user basis
+#Match User anoncvs
+#      X11Forwarding no
+#      AllowTcpForwarding no
+#      ForceCommand cvs server
diff --git a/sshd_config.0 b/sshd_config.0
new file mode 100644 (file)
index 0000000..ab0d79b
--- /dev/null
@@ -0,0 +1,713 @@
+SSHD_CONFIG(5)            OpenBSD Programmer's Manual           SSHD_CONFIG(5)
+
+NAME
+     sshd_config - OpenSSH SSH daemon configuration file
+
+SYNOPSIS
+     /etc/ssh/sshd_config
+
+DESCRIPTION
+     sshd(8) reads configuration data from /etc/ssh/sshd_config (or the file
+     specified with -f on the command line).  The file contains keyword-
+     argument pairs, one per line.  Lines starting with `#' and empty lines
+     are interpreted as comments.  Arguments may optionally be enclosed in
+     double quotes (") in order to represent arguments containing spaces.
+
+     The possible keywords and their meanings are as follows (note that
+     keywords are case-insensitive and arguments are case-sensitive):
+
+     AcceptEnv
+             Specifies what environment variables sent by the client will be
+             copied into the session's environ(7).  See SendEnv in
+             ssh_config(5) for how to configure the client.  Note that
+             environment passing is only supported for protocol 2.  Variables
+             are specified by name, which may contain the wildcard characters
+             `*' and `?'.  Multiple environment variables may be separated by
+             whitespace or spread across multiple AcceptEnv directives.  Be
+             warned that some environment variables could be used to bypass
+             restricted user environments.  For this reason, care should be
+             taken in the use of this directive.  The default is not to accept
+             any environment variables.
+
+     AddressFamily
+             Specifies which address family should be used by sshd(8).  Valid
+             arguments are ``any'', ``inet'' (use IPv4 only), or ``inet6''
+             (use IPv6 only).  The default is ``any''.
+
+     AllowAgentForwarding
+             Specifies whether ssh-agent(1) forwarding is permitted.  The
+             default is ``yes''.  Note that disabling agent forwarding does
+             not improve security unless users are also denied shell access,
+             as they can always install their own forwarders.
+
+     AllowGroups
+             This keyword can be followed by a list of group name patterns,
+             separated by spaces.  If specified, login is allowed only for
+             users whose primary group or supplementary group list matches one
+             of the patterns.  Only group names are valid; a numerical group
+             ID is not recognized.  By default, login is allowed for all
+             groups.  The allow/deny directives are processed in the following
+             order: DenyUsers, AllowUsers, DenyGroups, and finally
+             AllowGroups.
+
+             See PATTERNS in ssh_config(5) for more information on patterns.
+
+     AllowTcpForwarding
+             Specifies whether TCP forwarding is permitted.  The default is
+             ``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.
+
+     AllowUsers
+             This keyword can be followed by a list of user name patterns,
+             separated by spaces.  If specified, login is allowed only for
+             user names that match one of the patterns.  Only user names are
+             valid; a numerical user ID is not recognized.  By default, login
+             is allowed for all users.  If the pattern takes the form
+             USER@HOST then USER and HOST are separately checked, restricting
+             logins to particular users from particular hosts.  The allow/deny
+             directives are processed in the following order: DenyUsers,
+             AllowUsers, DenyGroups, and finally AllowGroups.
+
+             See PATTERNS in ssh_config(5) for more information on patterns.
+
+     AuthorizedKeysFile
+             Specifies the file that contains the public keys that can be used
+             for user authentication.  The format is described in the
+             AUTHORIZED_KEYS FILE FORMAT section of sshd(8).
+             AuthorizedKeysFile may contain tokens of the form %T which are
+             substituted during connection setup.  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,
+             AuthorizedKeysFile is taken to be an absolute path or one
+             relative to the user's home directory.  The default is
+             ``.ssh/authorized_keys''.
+
+     AuthorizedPrincipalsFile
+             Specifies a file that lists principal names that are accepted for
+             certificate authentication.  When using certificates signed by a
+             key listed in TrustedUserCAKeys, this file lists names, one of
+             which must appear in the certificate for it to be accepted for
+             authentication.  Names are listed one per line preceded by key
+             options (as described in AUTHORIZED_KEYS FILE FORMAT in sshd(8)).
+             Empty lines and comments starting with `#' are ignored.
+
+             AuthorizedPrincipalsFile may contain tokens of the form %T which
+             are substituted during connection setup.  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,
+             AuthorizedPrincipalsFile is taken to be an absolute path or one
+             relative to the user's home directory.
+
+             The default is not to use a principals file - in this case, the
+             username of the user must appear in a certificate's principals
+             list for it to be accepted.  Note that AuthorizedPrincipalsFile
+             is only used when authentication proceeds using a CA listed in
+             TrustedUserCAKeys and is not consulted for certification
+             authorities trusted via ~/.ssh/authorized_keys, though the
+             principals= key option offers a similar facility (see sshd(8) for
+             details).
+
+     Banner  The contents of the specified file are sent to the remote user
+             before authentication is allowed.  If the argument is ``none''
+             then no banner is displayed.  This option is only available for
+             protocol version 2.  By default, no banner is displayed.
+
+     ChallengeResponseAuthentication
+             Specifies whether challenge-response authentication is allowed
+             (e.g. via PAM or though authentication styles supported in
+             login.conf(5)) The default is ``yes''.
+
+     ChrootDirectory
+             Specifies the pathname of a directory to chroot(2) to after
+             authentication.  All components of the pathname must be root-
+             owned directories that are not writable by any other user or
+             group.  After the chroot, sshd(8) changes the working directory
+             to the user's home directory.
+
+             The pathname may contain the following tokens that are expanded
+             at runtime once the connecting user has been authenticated: %% 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.
+
+             The ChrootDirectory must contain the necessary files and
+             directories to support the user's session.  For an interactive
+             session this requires at least a shell, typically sh(1), and
+             basic /dev nodes such as null(4), zero(4), stdin(4), stdout(4),
+             stderr(4), arandom(4) and tty(4) devices.  For file transfer
+             sessions using ``sftp'', no additional configuration of the
+             environment is necessary if the in-process sftp server is used,
+             though sessions which use logging do require /dev/log inside the
+             chroot directory (see sftp-server(8) for details).
+
+             The default is not to chroot(2).
+
+     Ciphers
+             Specifies the ciphers allowed for protocol version 2.  Multiple
+             ciphers must be comma-separated.  The supported ciphers are
+             ``3des-cbc'', ``aes128-cbc'', ``aes192-cbc'', ``aes256-cbc'',
+             ``aes128-ctr'', ``aes192-ctr'', ``aes256-ctr'', ``arcfour128'',
+             ``arcfour256'', ``arcfour'', ``blowfish-cbc'', and
+             ``cast128-cbc''.  The default is:
+
+                aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
+                aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
+                aes256-cbc,arcfour
+
+     ClientAliveCountMax
+             Sets the number of client alive messages (see below) which may be
+             sent without sshd(8) receiving any messages back from the client.
+             If this threshold is reached while client alive messages are
+             being sent, sshd will disconnect the client, terminating the
+             session.  It is important to note that the use of client alive
+             messages is very different from TCPKeepAlive (below).  The client
+             alive messages are sent through the encrypted channel and
+             therefore will not be spoofable.  The TCP keepalive option
+             enabled by TCPKeepAlive is spoofable.  The client alive mechanism
+             is valuable when the client or server depend on knowing when a
+             connection has become inactive.
+
+             The default value is 3.  If ClientAliveInterval (see below) is
+             set to 15, and ClientAliveCountMax is left at the default,
+             unresponsive SSH clients will be disconnected after approximately
+             45 seconds.  This option applies to protocol version 2 only.
+
+     ClientAliveInterval
+             Sets a timeout interval in seconds after which if no data has
+             been received from the client, sshd(8) 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.
+
+     Compression
+             Specifies whether compression is allowed, or delayed until the
+             user has authenticated successfully.  The argument must be
+             ``yes'', ``delayed'', or ``no''.  The default is ``delayed''.
+
+     DenyGroups
+             This keyword can be followed by a list of group name patterns,
+             separated by spaces.  Login is disallowed for users whose primary
+             group or supplementary group list matches one of the patterns.
+             Only group names are valid; a numerical group ID is not
+             recognized.  By default, login is allowed for all groups.  The
+             allow/deny directives are processed in the following order:
+             DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups.
+
+             See PATTERNS in ssh_config(5) for more information on patterns.
+
+     DenyUsers
+             This keyword can be followed by a list of user name patterns,
+             separated by spaces.  Login is disallowed for user names that
+             match one of the patterns.  Only user names are valid; a
+             numerical user ID is not recognized.  By default, login is
+             allowed for all users.  If the pattern takes the form USER@HOST
+             then USER and HOST are separately checked, restricting logins to
+             particular users from particular hosts.  The allow/deny
+             directives are processed in the following order: DenyUsers,
+             AllowUsers, DenyGroups, and finally AllowGroups.
+
+             See PATTERNS in ssh_config(5) for more information on patterns.
+
+     ForceCommand
+             Forces the execution of the command specified by ForceCommand,
+             ignoring any command supplied by the client and ~/.ssh/rc if
+             present.  The command is invoked by using the user's login shell
+             with the -c option.  This applies to shell, command, or subsystem
+             execution.  It is most useful inside a Match block.  The command
+             originally supplied by the client is available in the
+             SSH_ORIGINAL_COMMAND environment variable.  Specifying a command
+             of ``internal-sftp'' will force the use of an in-process sftp
+             server that requires no support files when used with
+             ChrootDirectory.
+
+     GatewayPorts
+             Specifies whether remote hosts are allowed to connect to ports
+             forwarded for the client.  By default, sshd(8) binds remote port
+             forwardings to the loopback address.  This prevents other remote
+             hosts from connecting to forwarded ports.  GatewayPorts can be
+             used to specify that sshd should allow remote port forwardings to
+             bind to non-loopback addresses, thus allowing other hosts to
+             connect.  The argument may be ``no'' to force remote port
+             forwardings to be available to the local host only, ``yes'' to
+             force remote port forwardings to bind to the wildcard address, or
+             ``clientspecified'' to allow the client to select the address to
+             which the forwarding is bound.  The default is ``no''.
+
+     GSSAPIAuthentication
+             Specifies whether user authentication based on GSSAPI is allowed.
+             The default is ``no''.  Note that this option applies to protocol
+             version 2 only.
+
+     GSSAPICleanupCredentials
+             Specifies whether to automatically destroy the user's credentials
+             cache on logout.  The default is ``yes''.  Note that this option
+             applies to protocol version 2 only.
+
+     HostbasedAuthentication
+             Specifies whether rhosts or /etc/hosts.equiv authentication
+             together with successful public key client host authentication is
+             allowed (host-based authentication).  This option is similar to
+             RhostsRSAAuthentication and applies to protocol version 2 only.
+             The default is ``no''.
+
+     HostbasedUsesNameFromPacketOnly
+             Specifies whether or not the server will attempt to perform a
+             reverse name lookup when matching the name in the ~/.shosts,
+             ~/.rhosts, and /etc/hosts.equiv files during
+             HostbasedAuthentication.  A setting of ``yes'' means that sshd(8)
+             uses the name supplied by the client rather than attempting to
+             resolve the name from the TCP connection itself.  The default is
+             ``no''.
+
+     HostCertificate
+             Specifies a file containing a public host certificate.  The
+             certificate's public key must match a private host key already
+             specified by HostKey.  The default behaviour of sshd(8) is not to
+             load any certificates.
+
+     HostKey
+             Specifies a file containing a private host key used by SSH.  The
+             default is /etc/ssh/ssh_host_key for protocol version 1, and
+             /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_ecdsa_key and
+             /etc/ssh/ssh_host_rsa_key for protocol version 2.  Note that
+             sshd(8) will refuse to use a file if it is group/world-
+             accessible.  It is possible to have multiple host key files.
+             ``rsa1'' keys are used for version 1 and ``dsa'', ``ecdsa'' or
+             ``rsa'' are used for version 2 of the SSH protocol.
+
+     IgnoreRhosts
+             Specifies that .rhosts and .shosts files will not be used in
+             RhostsRSAAuthentication or HostbasedAuthentication.
+
+             /etc/hosts.equiv and /etc/shosts.equiv are still used.  The
+             default is ``yes''.
+
+     IgnoreUserKnownHosts
+             Specifies whether sshd(8) should ignore the user's
+             ~/.ssh/known_hosts during RhostsRSAAuthentication or
+             HostbasedAuthentication.  The default is ``no''.
+
+     IPQoS   Specifies the IPv4 type-of-service or DSCP class for the
+             connection.  Accepted values are ``af11'', ``af12'', ``af13'',
+             ``af14'', ``af22'', ``af23'', ``af31'', ``af32'', ``af33'',
+             ``af41'', ``af42'', ``af43'', ``cs0'', ``cs1'', ``cs2'', ``cs3'',
+             ``cs4'', ``cs5'', ``cs6'', ``cs7'', ``ef'', ``lowdelay'',
+             ``throughput'', ``reliability'', or a numeric value.  This option
+             may take one or two arguments, separated by whitespace.  If one
+             argument is specified, it is used as the packet class
+             unconditionally.  If two values are specified, the first is
+             automatically selected for interactive sessions and the second
+             for non-interactive sessions.  The default is ``lowdelay'' for
+             interactive sessions and ``throughput'' for non-interactive
+             sessions.
+
+     KerberosAuthentication
+             Specifies whether the password provided by the user for
+             PasswordAuthentication 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.  The default
+             is ``no''.
+
+     KerberosGetAFSToken
+             If AFS is active and the user has a Kerberos 5 TGT, attempt to
+             acquire an AFS token before accessing the user's home directory.
+             The default is ``no''.
+
+     KerberosOrLocalPasswd
+             If password authentication through Kerberos fails then the
+             password will be validated via any additional local mechanism
+             such as /etc/passwd.  The default is ``yes''.
+
+     KerberosTicketCleanup
+             Specifies whether to automatically destroy the user's ticket
+             cache file on logout.  The default is ``yes''.
+
+     KexAlgorithms
+             Specifies the available KEX (Key Exchange) algorithms.  Multiple
+             algorithms must be comma-separated.  The default is
+             ``ecdh-sha2-nistp256'', ``ecdh-sha2-nistp384'',
+             ``ecdh-sha2-nistp521'', ``diffie-hellman-group-exchange-sha256'',
+             ``diffie-hellman-group-exchange-sha1'',
+             ``diffie-hellman-group14-sha1'', ``diffie-hellman-group1-sha1''.
+
+     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).
+
+     ListenAddress
+             Specifies the local addresses sshd(8) should listen on.  The
+             following forms may be used:
+
+                   ListenAddress host|IPv4_addr|IPv6_addr
+                   ListenAddress host|IPv4_addr:port
+                   ListenAddress [host|IPv6_addr]:port
+
+             If port is not specified, sshd will listen on the address and all
+             prior Port options specified.  The default is to listen on all
+             local addresses.  Multiple ListenAddress options are permitted.
+             Additionally, any Port options must precede this option for non-
+             port qualified addresses.
+
+     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 120 seconds.
+
+     LogLevel
+             Gives the verbosity level that is used when logging messages from
+             sshd(8).  The possible values are: QUIET, FATAL, ERROR, INFO,
+             VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.  The default is INFO.
+             DEBUG and DEBUG1 are equivalent.  DEBUG2 and DEBUG3 each specify
+             higher levels of debugging output.  Logging with a DEBUG level
+             violates the privacy of users and is not recommended.
+
+     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:
+
+                   hmac-md5,hmac-sha1,umac-64@openssh.com,
+                   hmac-ripemd160,hmac-sha1-96,hmac-md5-96
+
+     Match   Introduces a conditional block.  If all of the criteria on the
+             Match line are satisfied, the keywords on the following lines
+             override those set in the global section of the config file,
+             until either another Match line or the end of the file.
+
+             The arguments to Match are one or more criteria-pattern pairs.
+             The available criteria are User, Group, Host, and Address.  The
+             match patterns may consist of single entries or comma-separated
+             lists and may use the wildcard and negation operators described
+             in the PATTERNS section of ssh_config(5).
+
+             The patterns in an Address criteria may additionally contain
+             addresses to match in CIDR address/masklen format, e.g.
+             ``192.0.2.0/24'' or ``3ffe:ffff::/32''.  Note that the mask
+             length provided must be consistent with the address - it is an
+             error to specify a mask length that is too long for the address
+             or one with bits set in this host portion of the address.  For
+             example, ``192.0.2.0/33'' and ``192.0.2.0/8'' respectively.
+
+             Only a subset of keywords may be used on the lines following a
+             Match keyword.  Available keywords are AllowAgentForwarding,
+             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
+             Banner, ChrootDirectory, ForceCommand, GatewayPorts,
+             GSSAPIAuthentication, HostbasedAuthentication,
+             HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
+             KerberosAuthentication, MaxAuthTries, MaxSessions,
+             PasswordAuthentication, PermitEmptyPasswords, PermitOpen,
+             PermitRootLogin, PermitTunnel, PubkeyAuthentication,
+             RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset,
+             X11Forwarding and X11UseLocalHost.
+
+     MaxAuthTries
+             Specifies the maximum number of authentication attempts permitted
+             per connection.  Once the number of failures reaches half this
+             value, additional failures are logged.  The default is 6.
+
+     MaxSessions
+             Specifies the maximum number of open sessions permitted per
+             network connection.  The default is 10.
+
+     MaxStartups
+             Specifies the maximum number of concurrent unauthenticated
+             connections to the SSH daemon.  Additional connections will be
+             dropped until authentication succeeds or the LoginGraceTime
+             expires for a connection.  The default is 10.
+
+             Alternatively, random early drop can be enabled by specifying the
+             three colon separated values ``start:rate:full'' (e.g.
+             "10:30:60").  sshd(8) will refuse connection attempts with a
+             probability of ``rate/100'' (30%) if there are currently
+             ``start'' (10) unauthenticated connections.  The probability
+             increases linearly and all connection attempts are refused if the
+             number of unauthenticated connections reaches ``full'' (60).
+
+     PasswordAuthentication
+             Specifies whether password authentication is allowed.  The
+             default is ``yes''.
+
+     PermitEmptyPasswords
+             When password authentication is allowed, it specifies whether the
+             server allows login to accounts with empty password strings.  The
+             default is ``no''.
+
+     PermitOpen
+             Specifies the destinations to which TCP port forwarding is
+             permitted.  The forwarding specification must be one of the
+             following forms:
+
+                   PermitOpen host:port
+                   PermitOpen IPv4_addr:port
+                   PermitOpen [IPv6_addr]:port
+
+             Multiple forwards may be specified by separating them with
+             whitespace.  An argument of ``any'' can be used to remove all
+             restrictions and permit any forwarding requests.  By default all
+             port forwarding requests are permitted.
+
+     PermitRootLogin
+             Specifies whether root can log in using ssh(1).  The argument
+             must be ``yes'', ``without-password'', ``forced-commands-only'',
+             or ``no''.  The default is ``yes''.
+
+             If this option is set to ``without-password'', password
+             authentication is disabled for root.
+
+             If this option is set to ``forced-commands-only'', root login
+             with public key authentication will be allowed, but only if the
+             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.
+
+             If this option is set to ``no'', root is not allowed to log in.
+
+     PermitTunnel
+             Specifies whether tun(4) device forwarding is allowed.  The
+             argument must be ``yes'', ``point-to-point'' (layer 3),
+             ``ethernet'' (layer 2), or ``no''.  Specifying ``yes'' permits
+             both ``point-to-point'' and ``ethernet''.  The default is ``no''.
+
+     PermitUserEnvironment
+             Specifies whether ~/.ssh/environment and environment= options in
+             ~/.ssh/authorized_keys are processed by sshd(8).  The default is
+             ``no''.  Enabling environment processing may enable users to
+             bypass access restrictions in some configurations using
+             mechanisms such as LD_PRELOAD.
+
+     PidFile
+             Specifies the file that contains the process ID of the SSH
+             daemon.  The default is /var/run/sshd.pid.
+
+     Port    Specifies the port number that sshd(8) listens on.  The default
+             is 22.  Multiple options of this type are permitted.  See also
+             ListenAddress.
+
+     PrintLastLog
+             Specifies whether sshd(8) should print the date and time of the
+             last user login when a user logs in interactively.  The default
+             is ``yes''.
+
+     PrintMotd
+             Specifies whether sshd(8) should print /etc/motd when a user logs
+             in interactively.  (On some systems it is also printed by the
+             shell, /etc/profile, or equivalent.)  The default is ``yes''.
+
+     Protocol
+             Specifies the protocol versions sshd(8) supports.  The possible
+             values are `1' and `2'.  Multiple versions must be comma-
+             separated.  The default is `2'.  Note that the order of the
+             protocol list does not indicate preference, because the client
+             selects among multiple protocol versions offered by the server.
+             Specifying ``2,1'' is identical to ``1,2''.
+
+     PubkeyAuthentication
+             Specifies whether public key authentication is allowed.  The
+             default is ``yes''.  Note that this option applies to protocol
+             version 2 only.
+
+     RevokedKeys
+             Specifies a list of revoked public keys.  Keys listed in this
+             file will be refused for public key authentication.  Note that if
+             this file is not readable, then public key authentication will be
+             refused for all users.
+
+     RhostsRSAAuthentication
+             Specifies whether rhosts or /etc/hosts.equiv authentication
+             together with successful RSA host authentication is allowed.  The
+             default is ``no''.  This option applies to protocol version 1
+             only.
+
+     RSAAuthentication
+             Specifies whether pure RSA authentication is allowed.  The
+             default is ``yes''.  This option applies to protocol version 1
+             only.
+
+     ServerKeyBits
+             Defines the number of bits in the ephemeral protocol version 1
+             server key.  The minimum value is 512, and the default is 1024.
+
+     StrictModes
+             Specifies whether sshd(8) 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
+             ``yes''.  Note that this does not apply to ChrootDirectory, whose
+             permissions and ownership are checked unconditionally.
+
+     Subsystem
+             Configures an external subsystem (e.g. file transfer daemon).
+             Arguments should be a subsystem name and a command (with optional
+             arguments) to execute upon subsystem request.
+
+             The command sftp-server(8) implements the ``sftp'' file transfer
+             subsystem.
+
+             Alternately the name ``internal-sftp'' implements an in-process
+             ``sftp'' server.  This may simplify configurations using
+             ChrootDirectory to force a different filesystem root on clients.
+
+             By default no subsystems are defined.  Note that this option
+             applies to protocol version 2 only.
+
+     SyslogFacility
+             Gives the facility code that is used when logging messages from
+             sshd(8).  The possible values are: DAEMON, USER, AUTH, LOCAL0,
+             LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.  The
+             default is AUTH.
+
+     TCPKeepAlive
+             Specifies whether the system should send TCP 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 TCP keepalives are not sent, sessions may hang
+             indefinitely on the server, leaving ``ghost'' users and consuming
+             server resources.
+
+             The default is ``yes'' (to send TCP keepalive messages), and the
+             server will notice if the network goes down or the client host
+             crashes.  This avoids infinitely hanging sessions.
+
+             To disable TCP keepalive messages, the value should be set to
+             ``no''.
+
+     TrustedUserCAKeys
+             Specifies a file containing public keys of certificate
+             authorities that are trusted to sign user certificates for
+             authentication.  Keys are listed one per line; empty lines and
+             comments starting with `#' are allowed.  If a certificate is
+             presented for authentication and has its signing CA key listed in
+             this file, then it may be used for authentication for any user
+             listed in the certificate's principals list.  Note that
+             certificates that lack a list of principals will not be permitted
+             for authentication using TrustedUserCAKeys.  For more details on
+             certificates, see the CERTIFICATES section in ssh-keygen(1).
+
+     UseDNS  Specifies whether sshd(8) should look up 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 ``yes''.
+
+     UseLogin
+             Specifies whether login(1) is used for interactive login
+             sessions.  The default is ``no''.  Note that login(1) is never
+             used for remote command execution.  Note also, that if this is
+             enabled, X11Forwarding will be disabled because login(1) does not
+             know how to handle xauth(1) cookies.  If UsePrivilegeSeparation
+             is specified, it will be disabled after authentication.
+
+     UsePAM  Enables the Pluggable Authentication Module interface.  If set to
+             ``yes'' this will enable PAM authentication using
+             ChallengeResponseAuthentication and PasswordAuthentication in
+             addition to PAM account and session module processing for all
+             authentication types.
+
+             Because PAM challenge-response authentication usually serves an
+             equivalent role to password authentication, you should disable
+             either PasswordAuthentication or ChallengeResponseAuthentication.
+
+             If UsePAM is enabled, you will not be able to run sshd(8) as a
+             non-root user.  The default is ``no''.
+
+     UsePrivilegeSeparation
+             Specifies whether sshd(8) separates privileges by creating an
+             unprivileged child process to deal with incoming network traffic.
+             After successful authentication, another process will be created
+             that has the privilege of the authenticated user.  The goal of
+             privilege separation is to prevent privilege escalation by
+             containing any corruption within the unprivileged processes.  The
+             default is ``yes''.
+
+     X11DisplayOffset
+             Specifies the first display number available for sshd(8)'s X11
+             forwarding.  This prevents sshd from interfering with real X11
+             servers.  The default is 10.
+
+     X11Forwarding
+             Specifies whether X11 forwarding is permitted.  The argument must
+             be ``yes'' or ``no''.  The default is ``no''.
+
+             When X11 forwarding is enabled, there may be additional exposure
+             to the server and to client displays if the sshd(8) proxy display
+             is configured to listen on the wildcard address (see
+             X11UseLocalhost below), though this is not the default.
+             Additionally, the authentication spoofing and authentication data
+             verification and substitution occur on the client side.  The
+             security risk of using X11 forwarding is that the client's X11
+             display server may be exposed to attack when the SSH client
+             requests forwarding (see the warnings for ForwardX11 in
+             ssh_config(5)).  A system administrator may have a stance in
+             which they want to protect clients that may expose themselves to
+             attack by unwittingly requesting X11 forwarding, which can
+             warrant a ``no'' setting.
+
+             Note that disabling X11 forwarding does not prevent users from
+             forwarding X11 traffic, as users can always install their own
+             forwarders.  X11 forwarding is automatically disabled if UseLogin
+             is enabled.
+
+     X11UseLocalhost
+             Specifies whether sshd(8) should bind the X11 forwarding server
+             to the loopback address or to the wildcard address.  By default,
+             sshd binds the forwarding server to the loopback address and sets
+             the hostname part of the DISPLAY environment variable to
+             ``localhost''.  This prevents remote hosts from connecting to the
+             proxy display.  However, some older X11 clients may not function
+             with this configuration.  X11UseLocalhost may be set to ``no'' to
+             specify that the forwarding server should be bound to the
+             wildcard address.  The argument must be ``yes'' or ``no''.  The
+             default is ``yes''.
+
+     XAuthLocation
+             Specifies the full pathname of the xauth(1) program.  The default
+             is /usr/X11R6/bin/xauth.
+
+TIME FORMATS
+     sshd(8) 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>  seconds
+           s | S   seconds
+           m | M   minutes
+           h | H   hours
+           d | D   days
+           w | W   weeks
+
+     Each member of the sequence is added together to calculate the total time
+     value.
+
+     Time format examples:
+
+           600     600 seconds (10 minutes)
+           10m     10 minutes
+           1h30m   1 hour 30 minutes (90 minutes)
+
+FILES
+     /etc/ssh/sshd_config
+             Contains configuration data for sshd(8).  This file should be
+             writable by root only, but it is recommended (though not
+             necessary) that it be world-readable.
+
+SEE ALSO
+     sshd(8)
+
+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.  Niels Provos and Markus Friedl contributed support
+     for privilege separation.
+
+OpenBSD 4.9                    December 8, 2010                    OpenBSD 4.9
diff --git a/sshd_config.5 b/sshd_config.5
new file mode 100644 (file)
index 0000000..c3d6df3
--- /dev/null
@@ -0,0 +1,1206 @@
+.\"
+.\" 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_config.5,v 1.131 2010/12/08 04:02:47 djm Exp $
+.Dd $Mdocdate: December 8 2010 $
+.Dt SSHD_CONFIG 5
+.Os
+.Sh NAME
+.Nm sshd_config
+.Nd OpenSSH SSH daemon configuration file
+.Sh SYNOPSIS
+.Nm /etc/ssh/sshd_config
+.Sh DESCRIPTION
+.Xr sshd 8
+reads configuration data from
+.Pa /etc/ssh/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.
+Arguments may optionally be enclosed in double quotes
+.Pq \&"
+in order to represent arguments containing spaces.
+.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 AcceptEnv
+Specifies what environment variables sent by the client will be copied into
+the session's
+.Xr environ 7 .
+See
+.Cm SendEnv
+in
+.Xr ssh_config 5
+for how to configure the client.
+Note that environment passing is only supported for protocol 2.
+Variables are specified by name, which may contain the wildcard characters
+.Ql *
+and
+.Ql \&? .
+Multiple environment variables may be separated by whitespace or spread
+across multiple
+.Cm AcceptEnv
+directives.
+Be warned that some environment variables could be used to bypass restricted
+user environments.
+For this reason, care should be taken in the use of this directive.
+The default is not to accept any environment variables.
+.It Cm AddressFamily
+Specifies which address family should be used by
+.Xr sshd 8 .
+Valid arguments are
+.Dq any ,
+.Dq inet
+(use IPv4 only), or
+.Dq inet6
+(use IPv6 only).
+The default is
+.Dq any .
+.It Cm AllowAgentForwarding
+Specifies whether
+.Xr ssh-agent 1
+forwarding is permitted.
+The default is
+.Dq yes .
+Note that disabling agent forwarding does not improve security
+unless users are also denied shell access, as they can always install
+their own forwarders.
+.It Cm AllowGroups
+This keyword can be followed by a list of group name patterns, separated
+by spaces.
+If specified, login is allowed only for users whose primary
+group or supplementary group list matches one of the patterns.
+Only group names are valid; a numerical group ID is not recognized.
+By default, login is allowed for all groups.
+The allow/deny directives are processed in the following order:
+.Cm DenyUsers ,
+.Cm AllowUsers ,
+.Cm DenyGroups ,
+and finally
+.Cm AllowGroups .
+.Pp
+See
+.Sx PATTERNS
+in
+.Xr ssh_config 5
+for more information on patterns.
+.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.
+.It Cm AllowUsers
+This keyword can be followed by a list of user name patterns, separated
+by spaces.
+If specified, login is allowed only for user names that
+match one of the patterns.
+Only user names are valid; a numerical user ID is not recognized.
+By default, login is allowed for all users.
+If the pattern takes the form USER@HOST then USER and HOST
+are separately checked, restricting logins to particular
+users from particular hosts.
+The allow/deny directives are processed in the following order:
+.Cm DenyUsers ,
+.Cm AllowUsers ,
+.Cm DenyGroups ,
+and finally
+.Cm AllowGroups .
+.Pp
+See
+.Sx PATTERNS
+in
+.Xr ssh_config 5
+for more information on patterns.
+.It Cm AuthorizedKeysFile
+Specifies the file that contains the public keys that can be used
+for user authentication.
+The format is described in the
+.Sx AUTHORIZED_KEYS FILE FORMAT
+section of
+.Xr sshd 8 .
+.Cm AuthorizedKeysFile
+may contain tokens of the form %T which are substituted during connection
+setup.
+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 AuthorizedPrincipalsFile
+Specifies a file that lists principal names that are accepted for
+certificate authentication.
+When using certificates signed by a key listed in
+.Cm TrustedUserCAKeys ,
+this file lists names, one of which must appear in the certificate for it
+to be accepted for authentication.
+Names are listed one per line preceded by key options (as described
+in
+.Sx AUTHORIZED_KEYS FILE FORMAT
+in
+.Xr sshd 8 ) .
+Empty lines and comments starting with
+.Ql #
+are ignored.
+.Pp
+.Cm AuthorizedPrincipalsFile
+may contain tokens of the form %T which are substituted during connection
+setup.
+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 AuthorizedPrincipalsFile
+is taken to be an absolute path or one relative to the user's home
+directory.
+.Pp
+The default is not to use a principals file \(en in this case, the username
+of the user must appear in a certificate's principals list for it to be
+accepted.
+Note that
+.Cm AuthorizedPrincipalsFile
+is only used when authentication proceeds using a CA listed in
+.Cm TrustedUserCAKeys
+and is not consulted for certification authorities trusted via
+.Pa ~/.ssh/authorized_keys ,
+though the
+.Cm principals=
+key option offers a similar facility (see
+.Xr sshd 8
+for details).
+.It Cm Banner
+The contents of the specified file are sent to the remote user before
+authentication is allowed.
+If the argument is
+.Dq none
+then no banner is displayed.
+This option is only available for protocol version 2.
+By default, no banner is displayed.
+.It Cm ChallengeResponseAuthentication
+Specifies whether challenge-response authentication is allowed (e.g. via
+PAM or though authentication styles supported in
+.Xr login.conf 5 )
+The default is
+.Dq yes .
+.It Cm ChrootDirectory
+Specifies the pathname of a directory to
+.Xr chroot 2
+to after authentication.
+All components of the pathname must be root-owned directories that are
+not writable by any other user or group.
+After the chroot,
+.Xr sshd 8
+changes the working directory to the user's home directory.
+.Pp
+The pathname may contain the following tokens that are expanded at runtime once
+the connecting user has been authenticated: %% 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.
+.Pp
+The
+.Cm ChrootDirectory
+must contain the necessary files and directories to support the
+user's session.
+For an interactive session this requires at least a shell, typically
+.Xr sh 1 ,
+and basic
+.Pa /dev
+nodes such as
+.Xr null 4 ,
+.Xr zero 4 ,
+.Xr stdin 4 ,
+.Xr stdout 4 ,
+.Xr stderr 4 ,
+.Xr arandom 4
+and
+.Xr tty 4
+devices.
+For file transfer sessions using
+.Dq sftp ,
+no additional configuration of the environment is necessary if the
+in-process sftp server is used,
+though sessions which use logging do require
+.Pa /dev/log
+inside the chroot directory (see
+.Xr sftp-server 8
+for details).
+.Pp
+The default is not to
+.Xr chroot 2 .
+.It Cm Ciphers
+Specifies the ciphers allowed for protocol version 2.
+Multiple ciphers must be comma-separated.
+The supported ciphers are
+.Dq 3des-cbc ,
+.Dq aes128-cbc ,
+.Dq aes192-cbc ,
+.Dq aes256-cbc ,
+.Dq aes128-ctr ,
+.Dq aes192-ctr ,
+.Dq aes256-ctr ,
+.Dq arcfour128 ,
+.Dq arcfour256 ,
+.Dq arcfour ,
+.Dq blowfish-cbc ,
+and
+.Dq cast128-cbc .
+The default is:
+.Bd -literal -offset 3n
+aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,
+aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc,
+aes256-cbc,arcfour
+.Ed
+.It Cm ClientAliveCountMax
+Sets the number of client alive messages (see below) which may be
+sent without
+.Xr sshd 8
+receiving any messages back from the client.
+If this threshold is reached while client alive messages are being sent,
+sshd will disconnect the client, terminating the session.
+It is important to note that the use of client alive messages is very
+different from
+.Cm TCPKeepAlive
+(below).
+The client alive messages are sent through the encrypted channel
+and therefore will not be spoofable.
+The TCP keepalive option enabled by
+.Cm TCPKeepAlive
+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
+(see below) is set to 15, and
+.Cm ClientAliveCountMax
+is left at the default, unresponsive SSH clients
+will be disconnected after approximately 45 seconds.
+This option applies to protocol version 2 only.
+.It Cm ClientAliveInterval
+Sets a timeout interval in seconds after which if no data has been received
+from the client,
+.Xr sshd 8
+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 Compression
+Specifies whether compression is allowed, or delayed until
+the user has authenticated successfully.
+The argument must be
+.Dq yes ,
+.Dq delayed ,
+or
+.Dq no .
+The default is
+.Dq delayed .
+.It Cm DenyGroups
+This keyword can be followed by a list of group name patterns, separated
+by spaces.
+Login is disallowed for users whose primary group or supplementary
+group list matches one of the patterns.
+Only group names are valid; a numerical group ID is not recognized.
+By default, login is allowed for all groups.
+The allow/deny directives are processed in the following order:
+.Cm DenyUsers ,
+.Cm AllowUsers ,
+.Cm DenyGroups ,
+and finally
+.Cm AllowGroups .
+.Pp
+See
+.Sx PATTERNS
+in
+.Xr ssh_config 5
+for more information on patterns.
+.It Cm DenyUsers
+This keyword can be followed by a list of user name patterns, separated
+by spaces.
+Login is disallowed for user names that match one of the patterns.
+Only user names are valid; a numerical user ID is not recognized.
+By default, login is allowed for all users.
+If the pattern takes the form USER@HOST then USER and HOST
+are separately checked, restricting logins to particular
+users from particular hosts.
+The allow/deny directives are processed in the following order:
+.Cm DenyUsers ,
+.Cm AllowUsers ,
+.Cm DenyGroups ,
+and finally
+.Cm AllowGroups .
+.Pp
+See
+.Sx PATTERNS
+in
+.Xr ssh_config 5
+for more information on patterns.
+.It Cm ForceCommand
+Forces the execution of the command specified by
+.Cm ForceCommand ,
+ignoring any command supplied by the client and
+.Pa ~/.ssh/rc
+if present.
+The command is invoked by using the user's login shell with the -c option.
+This applies to shell, command, or subsystem execution.
+It is most useful inside a
+.Cm Match
+block.
+The command originally supplied by the client is available in the
+.Ev SSH_ORIGINAL_COMMAND
+environment variable.
+Specifying a command of
+.Dq internal-sftp
+will force the use of an in-process sftp server that requires no support
+files when used with
+.Cm ChrootDirectory .
+.It Cm GatewayPorts
+Specifies whether remote hosts are allowed to connect to ports
+forwarded for the client.
+By default,
+.Xr sshd 8
+binds remote port forwardings to the loopback address.
+This prevents other remote hosts from connecting to forwarded ports.
+.Cm GatewayPorts
+can be used to specify that sshd
+should allow remote port forwardings to bind to non-loopback addresses, thus
+allowing other hosts to connect.
+The argument may be
+.Dq no
+to force remote port forwardings to be available to the local host only,
+.Dq yes
+to force remote port forwardings to bind to the wildcard address, or
+.Dq clientspecified
+to allow the client to select the address to which the forwarding is bound.
+The default is
+.Dq no .
+.It Cm GSSAPIAuthentication
+Specifies whether user authentication based on GSSAPI is allowed.
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
+.It Cm GSSAPICleanupCredentials
+Specifies whether to automatically destroy the user's credentials cache
+on logout.
+The default is
+.Dq yes .
+Note that this option applies to protocol version 2 only.
+.It Cm HostbasedAuthentication
+Specifies whether rhosts or /etc/hosts.equiv authentication together
+with successful public key client host authentication is allowed
+(host-based authentication).
+This option is similar to
+.Cm RhostsRSAAuthentication
+and applies to protocol version 2 only.
+The default is
+.Dq no .
+.It Cm HostbasedUsesNameFromPacketOnly
+Specifies whether or not the server will attempt to perform a reverse
+name lookup when matching the name in the
+.Pa ~/.shosts ,
+.Pa ~/.rhosts ,
+and
+.Pa /etc/hosts.equiv
+files during
+.Cm HostbasedAuthentication .
+A setting of
+.Dq yes
+means that
+.Xr sshd 8
+uses the name supplied by the client rather than
+attempting to resolve the name from the TCP connection itself.
+The default is
+.Dq no .
+.It Cm HostCertificate
+Specifies a file containing a public host certificate.
+The certificate's public key must match a private host key already specified
+by
+.Cm HostKey .
+The default behaviour of
+.Xr sshd 8
+is not to load any certificates.
+.It Cm HostKey
+Specifies a file containing a private host key
+used by SSH.
+The default is
+.Pa /etc/ssh/ssh_host_key
+for protocol version 1, and
+.Pa /etc/ssh/ssh_host_dsa_key ,
+.Pa /etc/ssh/ssh_host_ecdsa_key
+and
+.Pa /etc/ssh/ssh_host_rsa_key
+for protocol version 2.
+Note that
+.Xr sshd 8
+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 ,
+.Dq ecdsa
+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 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
+.Xr sshd 8
+should ignore the user's
+.Pa ~/.ssh/known_hosts
+during
+.Cm RhostsRSAAuthentication
+or
+.Cm HostbasedAuthentication .
+The default is
+.Dq no .
+.It Cm IPQoS
+Specifies the IPv4 type-of-service or DSCP class for the connection.
+Accepted values are
+.Dq af11 ,
+.Dq af12 ,
+.Dq af13 ,
+.Dq af14 ,
+.Dq af22 ,
+.Dq af23 ,
+.Dq af31 ,
+.Dq af32 ,
+.Dq af33 ,
+.Dq af41 ,
+.Dq af42 ,
+.Dq af43 ,
+.Dq cs0 ,
+.Dq cs1 ,
+.Dq cs2 ,
+.Dq cs3 ,
+.Dq cs4 ,
+.Dq cs5 ,
+.Dq cs6 ,
+.Dq cs7 ,
+.Dq ef ,
+.Dq lowdelay ,
+.Dq throughput ,
+.Dq reliability ,
+or a numeric value.
+This option may take one or two arguments, separated by whitespace.
+If one argument is specified, it is used as the packet class unconditionally.
+If two values are specified, the first is automatically selected for
+interactive sessions and the second for non-interactive sessions.
+The default is
+.Dq lowdelay
+for interactive sessions and
+.Dq throughput
+for non-interactive sessions.
+.It Cm KerberosAuthentication
+Specifies whether the password provided by the user for
+.Cm PasswordAuthentication
+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.
+The default is
+.Dq no .
+.It Cm KerberosGetAFSToken
+If AFS is active and the user has a Kerberos 5 TGT, attempt to acquire
+an AFS token before accessing the user's home directory.
+The default is
+.Dq no .
+.It Cm KerberosOrLocalPasswd
+If password authentication through Kerberos fails then
+the password will be validated via any additional local mechanism
+such as
+.Pa /etc/passwd .
+The default is
+.Dq yes .
+.It Cm KerberosTicketCleanup
+Specifies whether to automatically destroy the user's ticket cache
+file on logout.
+The default is
+.Dq yes .
+.It Cm KexAlgorithms
+Specifies the available KEX (Key Exchange) algorithms.
+Multiple algorithms must be comma-separated.
+The default is
+.Dq ecdh-sha2-nistp256 ,
+.Dq ecdh-sha2-nistp384 ,
+.Dq ecdh-sha2-nistp521 ,
+.Dq diffie-hellman-group-exchange-sha256 ,
+.Dq diffie-hellman-group-exchange-sha1 ,
+.Dq diffie-hellman-group14-sha1 ,
+.Dq diffie-hellman-group1-sha1 .
+.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
+.Xr sshd 8
+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,
+sshd 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 120 seconds.
+.It Cm LogLevel
+Gives the verbosity level that is used when logging messages from
+.Xr sshd 8 .
+The possible values are:
+QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3.
+The default is INFO.
+DEBUG and DEBUG1 are equivalent.
+DEBUG2 and DEBUG3 each specify higher levels of debugging output.
+Logging with a DEBUG level 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:
+.Bd -literal -offset indent
+hmac-md5,hmac-sha1,umac-64@openssh.com,
+hmac-ripemd160,hmac-sha1-96,hmac-md5-96
+.Ed
+.It Cm Match
+Introduces a conditional block.
+If all of the criteria on the
+.Cm Match
+line are satisfied, the keywords on the following lines override those
+set in the global section of the config file, until either another
+.Cm Match
+line or the end of the file.
+.Pp
+The arguments to
+.Cm Match
+are one or more criteria-pattern pairs.
+The available criteria are
+.Cm User ,
+.Cm Group ,
+.Cm Host ,
+and
+.Cm Address .
+The match patterns may consist of single entries or comma-separated
+lists and may use the wildcard and negation operators described in the
+.Sx PATTERNS
+section of
+.Xr ssh_config 5 .
+.Pp
+The patterns in an
+.Cm Address
+criteria may additionally contain addresses to match in CIDR
+address/masklen format, e.g.\&
+.Dq 192.0.2.0/24
+or
+.Dq 3ffe:ffff::/32 .
+Note that the mask length provided must be consistent with the address -
+it is an error to specify a mask length that is too long for the address
+or one with bits set in this host portion of the address.
+For example,
+.Dq 192.0.2.0/33
+and
+.Dq 192.0.2.0/8
+respectively.
+.Pp
+Only a subset of keywords may be used on the lines following a
+.Cm Match
+keyword.
+Available keywords are
+.Cm AllowAgentForwarding ,
+.Cm AllowTcpForwarding ,
+.Cm AuthorizedKeysFile ,
+.Cm AuthorizedPrincipalsFile ,
+.Cm Banner ,
+.Cm ChrootDirectory ,
+.Cm ForceCommand ,
+.Cm GatewayPorts ,
+.Cm GSSAPIAuthentication ,
+.Cm HostbasedAuthentication ,
+.Cm HostbasedUsesNameFromPacketOnly ,
+.Cm KbdInteractiveAuthentication ,
+.Cm KerberosAuthentication ,
+.Cm MaxAuthTries ,
+.Cm MaxSessions ,
+.Cm PasswordAuthentication ,
+.Cm PermitEmptyPasswords ,
+.Cm PermitOpen ,
+.Cm PermitRootLogin ,
+.Cm PermitTunnel ,
+.Cm PubkeyAuthentication ,
+.Cm RhostsRSAAuthentication ,
+.Cm RSAAuthentication ,
+.Cm X11DisplayOffset ,
+.Cm X11Forwarding
+and
+.Cm X11UseLocalHost .
+.It Cm MaxAuthTries
+Specifies the maximum number of authentication attempts permitted per
+connection.
+Once the number of failures reaches half this value,
+additional failures are logged.
+The default is 6.
+.It Cm MaxSessions
+Specifies the maximum number of open sessions permitted per network connection.
+The default is 10.
+.It Cm MaxStartups
+Specifies the maximum number of concurrent unauthenticated connections to the
+SSH daemon.
+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").
+.Xr sshd 8
+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 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 PermitOpen
+Specifies the destinations to which TCP port forwarding is permitted.
+The forwarding specification must be one of the following forms:
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Cm PermitOpen
+.Sm off
+.Ar host : port
+.Sm on
+.It
+.Cm PermitOpen
+.Sm off
+.Ar IPv4_addr : port
+.Sm on
+.It
+.Cm PermitOpen
+.Sm off
+.Ar \&[ IPv6_addr \&] : port
+.Sm on
+.El
+.Pp
+Multiple forwards may be specified by separating them with whitespace.
+An argument of
+.Dq any
+can be used to remove all restrictions and permit any forwarding requests.
+By default all port forwarding requests are permitted.
+.It Cm PermitRootLogin
+Specifies whether root can log in 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 log in.
+.It Cm PermitTunnel
+Specifies whether
+.Xr tun 4
+device forwarding is allowed.
+The argument must be
+.Dq yes ,
+.Dq point-to-point
+(layer 3),
+.Dq ethernet
+(layer 2), or
+.Dq no .
+Specifying
+.Dq yes
+permits both
+.Dq point-to-point
+and
+.Dq ethernet .
+The default is
+.Dq no .
+.It Cm PermitUserEnvironment
+Specifies whether
+.Pa ~/.ssh/environment
+and
+.Cm environment=
+options in
+.Pa ~/.ssh/authorized_keys
+are processed by
+.Xr sshd 8 .
+The default is
+.Dq no .
+Enabling environment processing may enable users to bypass access
+restrictions in some configurations using mechanisms such as
+.Ev LD_PRELOAD .
+.It Cm PidFile
+Specifies the file that contains the process ID of the
+SSH daemon.
+The default is
+.Pa /var/run/sshd.pid .
+.It Cm Port
+Specifies the port number that
+.Xr sshd 8
+listens on.
+The default is 22.
+Multiple options of this type are permitted.
+See also
+.Cm ListenAddress .
+.It Cm PrintLastLog
+Specifies whether
+.Xr sshd 8
+should print the date and time of the last user login when a user logs
+in interactively.
+The default is
+.Dq yes .
+.It Cm PrintMotd
+Specifies whether
+.Xr sshd 8
+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
+.Xr sshd 8
+supports.
+The possible values are
+.Sq 1
+and
+.Sq 2 .
+Multiple versions must be comma-separated.
+The default is
+.Sq 2 .
+Note that the order of the protocol list does not indicate preference,
+because the client selects among multiple protocol versions offered
+by the server.
+Specifying
+.Dq 2,1
+is identical to
+.Dq 1,2 .
+.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 RevokedKeys
+Specifies a list of revoked public keys.
+Keys listed in this file will be refused for public key authentication.
+Note that if this file is not readable, then public key authentication will
+be refused for all users.
+.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 1024.
+.It Cm StrictModes
+Specifies whether
+.Xr sshd 8
+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 .
+Note that this does not apply to
+.Cm ChrootDirectory ,
+whose permissions and ownership are checked unconditionally.
+.It Cm Subsystem
+Configures an external subsystem (e.g. file transfer daemon).
+Arguments should be a subsystem name and a command (with optional arguments)
+to execute upon subsystem request.
+.Pp
+The command
+.Xr sftp-server 8
+implements the
+.Dq sftp
+file transfer subsystem.
+.Pp
+Alternately the name
+.Dq internal-sftp
+implements an in-process
+.Dq sftp
+server.
+This may simplify configurations using
+.Cm ChrootDirectory
+to force a different filesystem root on clients.
+.Pp
+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
+.Xr sshd 8 .
+The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2,
+LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7.
+The default is AUTH.
+.It Cm TCPKeepAlive
+Specifies whether the system should send TCP 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 TCP 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 TCP keepalive messages), and the server will notice
+if the network goes down or the client host crashes.
+This avoids infinitely hanging sessions.
+.Pp
+To disable TCP keepalive messages, the value should be set to
+.Dq no .
+.It Cm TrustedUserCAKeys
+Specifies a file containing public keys of certificate authorities that are
+trusted to sign user certificates for authentication.
+Keys are listed one per line; empty lines and comments starting with
+.Ql #
+are allowed.
+If a certificate is presented for authentication and has its signing CA key
+listed in this file, then it may be used for authentication for any user
+listed in the certificate's principals list.
+Note that certificates that lack a list of principals will not be permitted
+for authentication using
+.Cm TrustedUserCAKeys .
+For more details on certificates, see the
+.Sx CERTIFICATES
+section in
+.Xr ssh-keygen 1 .
+.It Cm UseDNS
+Specifies whether
+.Xr sshd 8
+should look up 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 yes .
+.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.
+If
+.Cm UsePrivilegeSeparation
+is specified, it will be disabled after authentication.
+.It Cm UsePAM
+Enables the Pluggable Authentication Module interface.
+If set to
+.Dq yes
+this will enable PAM authentication using
+.Cm ChallengeResponseAuthentication
+and
+.Cm PasswordAuthentication
+in addition to PAM account and session module processing for all
+authentication types.
+.Pp
+Because PAM challenge-response authentication usually serves an equivalent
+role to password authentication, you should disable either
+.Cm PasswordAuthentication
+or
+.Cm ChallengeResponseAuthentication.
+.Pp
+If
+.Cm UsePAM
+is enabled, you will not be able to run
+.Xr sshd 8
+as a non-root user.
+The default is
+.Dq no .
+.It Cm UsePrivilegeSeparation
+Specifies whether
+.Xr sshd 8
+separates privileges by creating an unprivileged child process
+to deal with incoming network traffic.
+After successful authentication, another process will be created that has
+the privilege of the authenticated user.
+The goal of privilege separation is to prevent privilege
+escalation by containing any corruption within the unprivileged processes.
+The default is
+.Dq yes .
+.It Cm X11DisplayOffset
+Specifies the first display number available for
+.Xr sshd 8 Ns 's
+X11 forwarding.
+This prevents sshd from interfering with real X11 servers.
+The default is 10.
+.It Cm X11Forwarding
+Specifies whether X11 forwarding is permitted.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
+.Pp
+When X11 forwarding is enabled, there may be additional exposure to
+the server and to client displays if the
+.Xr sshd 8
+proxy display is configured to listen on the wildcard address (see
+.Cm X11UseLocalhost
+below), though this is not the default.
+Additionally, the authentication spoofing and authentication data
+verification and substitution occur on the client side.
+The security risk of using X11 forwarding is that the client's X11
+display server may be exposed to attack when the SSH client requests
+forwarding (see the warnings for
+.Cm ForwardX11
+in
+.Xr ssh_config 5 ) .
+A system administrator may have a stance in which they want to
+protect clients that may expose themselves to attack by unwittingly
+requesting X11 forwarding, which can warrant a
+.Dq no
+setting.
+.Pp
+Note that disabling X11 forwarding does not prevent users from
+forwarding X11 traffic, as users can always install their own forwarders.
+X11 forwarding is automatically disabled if
+.Cm UseLogin
+is enabled.
+.It Cm X11UseLocalhost
+Specifies whether
+.Xr sshd 8
+should bind the X11 forwarding server to the loopback address or to
+the wildcard address.
+By default,
+sshd binds the forwarding server to the loopback address and sets the
+hostname part of the
+.Ev DISPLAY
+environment variable to
+.Dq localhost .
+This prevents remote hosts from connecting to the proxy display.
+However, some older X11 clients may not function with this
+configuration.
+.Cm X11UseLocalhost
+may be set to
+.Dq no
+to specify that the forwarding server should be bound to the wildcard
+address.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq yes .
+.It Cm XAuthLocation
+Specifies the full pathname of the
+.Xr xauth 1
+program.
+The default is
+.Pa /usr/X11R6/bin/xauth .
+.El
+.Sh TIME FORMATS
+.Xr sshd 8
+command-line arguments and configuration file options that specify time
+may be expressed using a sequence of the form:
+.Sm off
+.Ar time Op Ar qualifier ,
+.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 Aq 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 FILES
+.Bl -tag -width Ds
+.It Pa /etc/ssh/sshd_config
+Contains configuration data for
+.Xr sshd 8 .
+This file should be writable by root only, but it is recommended
+(though not necessary) that it be world-readable.
+.El
+.Sh SEE ALSO
+.Xr sshd 8
+.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.
+Niels Provos and Markus Friedl contributed support
+for privilege separation.
diff --git a/sshlogin.c b/sshlogin.c
new file mode 100644 (file)
index 0000000..54629f7
--- /dev/null
@@ -0,0 +1,163 @@
+/* $OpenBSD: sshlogin.c,v 1.27 2011/01/11 06:06:09 djm Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "loginrec.h"
+#include "log.h"
+#include "buffer.h"
+#include "servconf.h"
+
+extern Buffer loginmsg;
+extern ServerOptions options;
+
+/*
+ * 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.
+ */
+time_t
+get_last_login_time(uid_t uid, const char *logname,
+    char *buf, size_t bufsize)
+{
+       struct logininfo li;
+
+       login_get_lastlog(&li, uid);
+       strlcpy(buf, li.hostname, bufsize);
+       return (time_t)li.tv_sec;
+}
+
+/*
+ * Generate and store last login message.  This must be done before
+ * login_login() is called and lastlog is updated.
+ */
+static void
+store_lastlog_message(const char *user, uid_t uid)
+{
+#ifndef NO_SSH_LASTLOG
+       char *time_string, hostname[MAXHOSTNAMELEN] = "", buf[512];
+       time_t last_login_time;
+
+       if (!options.print_lastlog)
+               return;
+
+# ifdef CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG
+       time_string = sys_auth_get_lastlogin_msg(user, uid);
+       if (time_string != NULL) {
+               buffer_append(&loginmsg, time_string, strlen(time_string));
+               xfree(time_string);
+       }
+# else
+       last_login_time = get_last_login_time(uid, user, hostname,
+           sizeof(hostname));
+
+       if (last_login_time != 0) {
+               time_string = ctime(&last_login_time);
+               time_string[strcspn(time_string, "\n")] = '\0';
+               if (strcmp(hostname, "") == 0)
+                       snprintf(buf, sizeof(buf), "Last login: %s\r\n",
+                           time_string);
+               else
+                       snprintf(buf, sizeof(buf), "Last login: %s from %s\r\n",
+                           time_string, hostname);
+               buffer_append(&loginmsg, buf, strlen(buf));
+       }
+# endif /* CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG */
+#endif /* NO_SSH_LASTLOG */
+}
+
+/*
+ * Records that the user has logged in.  I wish these parts of operating
+ * systems were more standardized.
+ */
+void
+record_login(pid_t pid, const char *tty, const char *user, uid_t uid,
+    const char *host, struct sockaddr *addr, socklen_t addrlen)
+{
+       struct logininfo *li;
+
+       /* save previous login details before writing new */
+       store_lastlog_message(user, uid);
+
+       li = login_alloc_entry(pid, user, host, tty);
+       login_set_addr(li, addr, addrlen);
+       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, socklen_t addrlen)
+{
+       struct logininfo *li;
+
+       li = login_alloc_entry(pid, user, host, ttyname);
+       login_set_addr(li, addr, addrlen);
+       login_utmp_only(li);
+       login_free_entry(li);
+}
+#endif
+
+/* Records that the user has logged out. */
+void
+record_logout(pid_t pid, const char *tty, const char *user)
+{
+       struct logininfo *li;
+
+       li = login_alloc_entry(pid, user, NULL, tty);
+       login_logout(li);
+       login_free_entry(li);
+}
diff --git a/sshlogin.h b/sshlogin.h
new file mode 100644 (file)
index 0000000..500d3fe
--- /dev/null
@@ -0,0 +1,23 @@
+/* $OpenBSD: sshlogin.h,v 1.8 2006/08/03 03:34:42 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".
+ */
+
+void   record_login(pid_t, const char *, const char *, uid_t,
+    const char *, struct sockaddr *, socklen_t);
+void   record_logout(pid_t, const char *, const char *);
+time_t get_last_login_time(uid_t, const char *, char *, u_int);
+
+#ifdef LOGIN_NEEDS_UTMPX
+void   record_utmp_only(pid_t, const char *, const char *, const char *,
+               struct sockaddr *, socklen_t);
+#endif
diff --git a/sshpty.c b/sshpty.c
new file mode 100644 (file)
index 0000000..bbbc0fe
--- /dev/null
+++ b/sshpty.c
@@ -0,0 +1,258 @@
+/* $OpenBSD: sshpty.c,v 1.28 2007/09/11 23:49:09 stevesk Exp $ */
+/*
+ * 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"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#include <pwd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <termios.h>
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+#include <unistd.h>
+
+#include "sshpty.h"
+#include "log.h"
+#include "misc.h"
+
+#ifdef HAVE_PTY_H
+# include <pty.h>
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifdef __APPLE__
+# include <AvailabilityMacros.h>
+# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+#  define __APPLE_PRIVPTY__
+# endif
+#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, size_t namebuflen)
+{
+       /* 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;
+}
+
+/* Releases the tty.  Its ownership is returned to root, and permissions to 0666. */
+
+void
+pty_release(const char *tty)
+{
+#ifndef __APPLE_PRIVPTY__
+       if (chown(tty, (uid_t) 0, (gid_t) 0) < 0)
+               error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno));
+       if (chmod(tty, (mode_t) 0666) < 0)
+               error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno));
+#endif /* __APPLE_PRIVPTY__ */
+}
+
+/* Makes the tty the process's controlling tty and sets it to sane modes. */
+
+void
+pty_make_controlling_tty(int *ttyfd, const char *tty)
+{
+       int fd;
+#ifdef USE_VHANGUP
+       void *old;
+#endif /* USE_VHANGUP */
+
+#ifdef _UNICOS
+       if (setsid() < 0)
+               error("setsid: %.100s", strerror(errno));
+
+       fd = open(tty, O_RDWR|O_NOCTTY);
+       if (fd != -1) {
+               signal(SIGHUP, SIG_IGN);
+               ioctl(fd, TCVHUP, (char *)NULL);
+               signal(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", tty, strerror(errno));
+       close(*ttyfd);
+       *ttyfd = fd;
+#else /* _UNICOS */
+
+       /* 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 NEED_SETPGRP
+       if (setpgrp(0,0) < 0)
+               error("SETPGRP %s",strerror(errno));
+#endif /* NEED_SETPGRP */
+#ifdef USE_VHANGUP
+       old = signal(SIGHUP, SIG_IGN);
+       vhangup();
+       signal(SIGHUP, old);
+#endif /* USE_VHANGUP */
+       fd = open(tty, O_RDWR);
+       if (fd < 0) {
+               error("%.100s: %.100s", tty, 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 /* _UNICOS */
+}
+
+/* Changes the window size associated with the pty. */
+
+void
+pty_change_window_size(int ptyfd, u_int row, u_int col,
+       u_int xpixel, u_int ypixel)
+{
+       struct winsize w;
+
+       /* may truncate u_int -> u_short */
+       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 *tty)
+{
+       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(tty, &st))
+               fatal("stat(%.100s) failed: %.100s", tty,
+                   strerror(errno));
+
+#ifdef WITH_SELINUX
+       ssh_selinux_setup_pty(pw->pw_name, tty);
+#endif
+
+       if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
+               if (chown(tty, pw->pw_uid, gid) < 0) {
+                       if (errno == EROFS &&
+                           (st.st_uid == pw->pw_uid || st.st_uid == 0))
+                               debug("chown(%.100s, %u, %u) failed: %.100s",
+                                   tty, (u_int)pw->pw_uid, (u_int)gid,
+                                   strerror(errno));
+                       else
+                               fatal("chown(%.100s, %u, %u) failed: %.100s",
+                                   tty, (u_int)pw->pw_uid, (u_int)gid,
+                                   strerror(errno));
+               }
+       }
+
+       if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
+               if (chmod(tty, mode) < 0) {
+                       if (errno == EROFS &&
+                           (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
+                               debug("chmod(%.100s, 0%o) failed: %.100s",
+                                   tty, (u_int)mode, strerror(errno));
+                       else
+                               fatal("chmod(%.100s, 0%o) failed: %.100s",
+                                   tty, (u_int)mode, strerror(errno));
+               }
+       }
+}
diff --git a/sshpty.h b/sshpty.h
new file mode 100644 (file)
index 0000000..cfa3224
--- /dev/null
+++ b/sshpty.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: sshpty.h,v 1.12 2010/01/09 05:04:24 djm Exp $ */
+
+/*
+ * 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".
+ */
+
+#include <termios.h>
+
+struct termios *get_saved_tio(void);
+void    leave_raw_mode(int);
+void    enter_raw_mode(int);
+
+int     pty_allocate(int *, int *, char *, size_t);
+void    pty_release(const char *);
+void    pty_make_controlling_tty(int *, const char *);
+void    pty_change_window_size(int, u_int, u_int, u_int, u_int);
+void    pty_setowner(struct passwd *, const char *);
diff --git a/sshtty.c b/sshtty.c
new file mode 100644 (file)
index 0000000..d214ce3
--- /dev/null
+++ b/sshtty.c
@@ -0,0 +1,96 @@
+/* $OpenBSD: sshtty.c,v 1.14 2010/01/09 05:04:24 djm 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 <sys/types.h>
+#include <stdio.h>
+#include <termios.h>
+#include <pwd.h>
+
+#include "sshpty.h"
+
+static struct termios _saved_tio;
+static int _in_raw_mode = 0;
+
+struct termios *
+get_saved_tio(void)
+{
+       return _in_raw_mode ? &_saved_tio : NULL;
+}
+
+void
+leave_raw_mode(int quiet)
+{
+       if (!_in_raw_mode)
+               return;
+       if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) {
+               if (!quiet)
+                       perror("tcsetattr");
+       } else
+               _in_raw_mode = 0;
+}
+
+void
+enter_raw_mode(int quiet)
+{
+       struct termios tio;
+
+       if (tcgetattr(fileno(stdin), &tio) == -1) {
+               if (!quiet)
+                       perror("tcgetattr");
+               return;
+       }
+       _saved_tio = tio;
+       tio.c_iflag |= IGNPAR;
+       tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+#ifdef IUCLC
+       tio.c_iflag &= ~IUCLC;
+#endif
+       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) {
+               if (!quiet)
+                       perror("tcsetattr");
+       } else
+               _in_raw_mode = 1;
+}
diff --git a/survey.sh.in b/survey.sh.in
new file mode 100644 (file)
index 0000000..d6075a6
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (c) 2004, 2005 Darren Tucker
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+host="@host@"
+AWK="@AWK@"
+CC="@CC@"
+CPP="@CPP@"
+CFLAGS="@CFLAGS@"
+CPPFLAGS="@CPPFLAGS@"
+LDFLAGS="@LDFLAGS@"
+LIBS="@LIBS@"
+
+# Note format:
+# identifier: [data] CRCR
+
+echo "openssh-survey-version: 1"
+echo
+echo "openssh-version: `./ssh -V 2>&1`"
+echo
+configinv=`$AWK '/^  \\\$.*configure/' config.log | sed 's/^  \\\$ //g'`
+echo "configure-invocation: $configinv"
+echo
+echo "host: $host"
+echo
+echo "uname: `uname`"
+echo
+echo "uname-r: `uname -r`"
+echo
+echo "uname-m: `uname -m`"
+echo
+echo "uname-p: `uname -p`"
+echo
+echo "oslevel: `oslevel 2>/dev/null`"
+echo
+echo "oslevel-r: `oslevel -r 2>/dev/null`"
+echo
+echo "cc: $CC"
+echo
+echo "cflags: $CFLAGS"
+echo
+echo "cppflags: $CPPFLAGS"
+echo
+echo "ldflags: $LDFLAGS"
+echo
+echo "libs: $LIBS"
+echo
+echo "ccver-v: `$CC -v 2>&1 | sed '/^[ \t]*$/d'`"
+echo
+echo "ccver-V: `$CC -V 2>&1 | sed '/^[ \t]*$/d'`"
+echo
+echo "cppdefines:"
+${CPP} -dM - </dev/null
+echo
+echo "config.h:"
+egrep '#define|#undef' config.h
+echo
diff --git a/ttymodes.c b/ttymodes.c
new file mode 100644 (file)
index 0000000..6f51b8a
--- /dev/null
@@ -0,0 +1,490 @@
+/* $OpenBSD: ttymodes.c,v 1.29 2008/11/02 00:16:16 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.
+ */
+
+/*
+ * 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"
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <string.h>
+#include <termios.h>
+#include <stdarg.h>
+
+#include "packet.h"
+#include "log.h"
+#include "ssh1.h"
+#include "compat.h"
+#include "buffer.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;
+       }
+}
+
+/*
+ * Encode a special character into SSH line format.
+ */
+static u_int
+special_char_encode(cc_t c)
+{
+#ifdef _POSIX_VDISABLE
+       if (c == _POSIX_VDISABLE)
+               return 255;
+#endif /* _POSIX_VDISABLE */
+       return c;
+}
+
+/*
+ * Decode a special character from SSH line format.
+ */
+static cc_t
+special_char_decode(u_int c)
+{
+#ifdef _POSIX_VDISABLE
+       if (c == 255)
+               return _POSIX_VDISABLE;
+#endif /* _POSIX_VDISABLE */
+       return c;
+}
+
+/*
+ * 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 (fd == -1) {
+                       debug("tty_make_modes: no fd or tio");
+                       goto end;
+               }
+               if (tcgetattr(fd, &tio) == -1) {
+                       logit("tcgetattr: %.100s", strerror(errno));
+                       goto end;
+               }
+       } else
+               tio = *tiop;
+
+       /* Store input and output baud rates. */
+       baud = speed_to_baud(cfgetospeed(&tio));
+       buffer_put_char(&buf, tty_op_ospeed);
+       buffer_put_int(&buf, baud);
+       baud = speed_to_baud(cfgetispeed(&tio));
+       buffer_put_char(&buf, tty_op_ispeed);
+       buffer_put_int(&buf, baud);
+
+       /* Store values of mode flags. */
+#define TTYCHAR(NAME, OP) \
+       buffer_put_char(&buf, OP); \
+       put_arg(&buf, special_char_encode(tio.c_cc[NAME]));
+
+#define TTYMODE(NAME, FIELD, OP) \
+       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);
+}
+
+/*
+ * 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_size;
+
+       if (compat20) {
+               *n_bytes_ptr = packet_get_int();
+               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) {
+               logit("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();
+                       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();
+                       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] = special_char_decode(get_arg()); \
+         break;
+#define TTYMODE(NAME, FIELD, OP) \
+       case OP: \
+         n_bytes += arg_size; \
+         if (get_arg()) \
+           tio.FIELD |= NAME; \
+         else \
+           tio.FIELD &= ~NAME; \
+         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.
+                                        */
+                                       logit("parse_tty_modes: unknown opcode %d",
+                                           opcode);
+                                       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 {
+                                       logit("parse_tty_modes: unknown opcode %d",
+                                           opcode);
+                                       goto set;
+                               }
+                       }
+               }
+       }
+
+set:
+       if (*n_bytes_ptr != n_bytes) {
+               *n_bytes_ptr = n_bytes;
+               logit("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)
+               logit("Setting tty modes failed: %.100s", strerror(errno));
+}
diff --git a/ttymodes.h b/ttymodes.h
new file mode 100644 (file)
index 0000000..4d848fe
--- /dev/null
@@ -0,0 +1,175 @@
+/* $OpenBSD: ttymodes.h,v 1.14 2006/03/25 22:22:43 djm 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
+#ifdef ONLCR
+TTYMODE(ONLCR, c_oflag, 72)
+#endif
+#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/uidswap.c b/uidswap.c
new file mode 100644 (file)
index 0000000..8376483
--- /dev/null
+++ b/uidswap.c
@@ -0,0 +1,288 @@
+/* $OpenBSD: uidswap.c,v 1.35 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * 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"
+
+#include <sys/param.h>
+#include <errno.h>
+#include <pwd.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <grp.h>
+
+#include "log.h"
+#include "uidswap.h"
+#include "xmalloc.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 = NULL, *user_groups = NULL;
+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: %u/%u (e=%u/%u)",
+           (u_int)pw->pw_uid, (u_int)pw->pw_gid,
+           (u_int)saved_euid, (u_int)saved_egid);
+#ifndef HAVE_CYGWIN
+       if (saved_euid != 0) {
+               privileged = 0;
+               return;
+       }
+#endif
+#else
+       if (geteuid() != 0) {
+               privileged = 0;
+               return;
+       }
+#endif /* SAVED_IDS_WORK_WITH_SETEUID */
+
+       privileged = 1;
+       temporarily_use_uid_effective = 1;
+
+       saved_egroupslen = getgroups(0, NULL);
+       if (saved_egroupslen < 0)
+               fatal("getgroups: %.100s", strerror(errno));
+       if (saved_egroupslen > 0) {
+               saved_egroups = xrealloc(saved_egroups,
+                   saved_egroupslen, sizeof(gid_t));
+               if (getgroups(saved_egroupslen, saved_egroups) < 0)
+                       fatal("getgroups: %.100s", strerror(errno));
+       } else { /* saved_egroupslen == 0 */
+               if (saved_egroups != NULL)
+                       xfree(saved_egroups);
+       }
+
+       /* 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(0, NULL);
+               if (user_groupslen < 0)
+                       fatal("getgroups: %.100s", strerror(errno));
+               if (user_groupslen > 0) {
+                       user_groups = xrealloc(user_groups,
+                           user_groupslen, sizeof(gid_t));
+                       if (getgroups(user_groupslen, user_groups) < 0)
+                               fatal("getgroups: %.100s", strerror(errno));
+               } else { /* user_groupslen == 0 */
+                       if (user_groups)
+                               xfree(user_groups);
+               }
+       }
+       /* Set the effective uid to the given (unprivileged) uid. */
+       if (setgroups(user_groupslen, user_groups) < 0)
+               fatal("setgroups: %.100s", strerror(errno));
+#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));
+}
+
+void
+permanently_drop_suid(uid_t uid)
+{
+       uid_t old_uid = getuid();
+
+       debug("permanently_drop_suid: %u", (u_int)uid);
+#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID)
+       if (setresuid(uid, uid, uid) < 0)
+               fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
+#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID)
+       if (setreuid(uid, uid) < 0)
+               fatal("setreuid %u: %.100s", (u_int)uid, strerror(errno));
+#else
+# ifndef SETEUID_BREAKS_SETUID
+       if (seteuid(uid) < 0)
+               fatal("seteuid %u: %.100s", (u_int)uid, strerror(errno));
+# endif
+       if (setuid(uid) < 0)
+               fatal("setuid %u: %.100s", (u_int)uid, strerror(errno));
+#endif
+
+#ifndef HAVE_CYGWIN
+       /* Try restoration of UID if changed (test clearing of saved uid) */
+       if (old_uid != uid &&
+           (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
+               fatal("%s: was able to restore old [e]uid", __func__);
+#endif
+
+       /* Verify UID drop was successful */
+       if (getuid() != uid || geteuid() != uid) {
+               fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
+                   __func__, (u_int)getuid(), (u_int)geteuid(), (u_int)uid);
+       }
+}
+
+/*
+ * Restores to the original (privileged) uid.
+ */
+void
+restore_uid(void)
+{
+       /* it's a no-op unless privileged */
+       if (!privileged) {
+               debug("restore_uid: (unprivileged)");
+               return;
+       }
+       if (!temporarily_use_uid_effective)
+               fatal("restore_uid: temporarily_use_uid not effective");
+
+#ifdef SAVED_IDS_WORK_WITH_SETEUID
+       debug("restore_uid: %u/%u", (u_int)saved_euid, (u_int)saved_egid);
+       /* 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 */
+
+       if (setgroups(saved_egroupslen, saved_egroups) < 0)
+               fatal("setgroups: %.100s", strerror(errno));
+       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)
+{
+       uid_t old_uid = getuid();
+       gid_t old_gid = getgid();
+
+       if (pw == NULL)
+               fatal("permanently_set_uid: no user given");
+       if (temporarily_use_uid_effective)
+               fatal("permanently_set_uid: temporarily_use_uid effective");
+       debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid,
+           (u_int)pw->pw_gid);
+
+#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID)
+       if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0)
+               fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
+#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID)
+       if (setregid(pw->pw_gid, pw->pw_gid) < 0)
+               fatal("setregid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
+#else
+       if (setegid(pw->pw_gid) < 0)
+               fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
+       if (setgid(pw->pw_gid) < 0)
+               fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno));
+#endif
+
+#ifdef __APPLE__
+       /*
+        * OS X requires initgroups after setgid to opt back into
+        * memberd support for >16 supplemental groups.
+        */
+       if (initgroups(pw->pw_name, pw->pw_gid) < 0)
+               fatal("initgroups %.100s %u: %.100s",
+                   pw->pw_name, (u_int)pw->pw_gid, strerror(errno));
+#endif
+
+#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID)
+       if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
+               fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
+#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID)
+       if (setreuid(pw->pw_uid, pw->pw_uid) < 0)
+               fatal("setreuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
+#else
+# ifndef SETEUID_BREAKS_SETUID
+       if (seteuid(pw->pw_uid) < 0)
+               fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
+# endif
+       if (setuid(pw->pw_uid) < 0)
+               fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
+#endif
+
+#ifndef HAVE_CYGWIN
+       /* Try restoration of GID if changed (test clearing of saved gid) */
+       if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
+           (setgid(old_gid) != -1 || setegid(old_gid) != -1))
+               fatal("%s: was able to restore old [e]gid", __func__);
+#endif
+
+       /* Verify GID drop was successful */
+       if (getgid() != pw->pw_gid || getegid() != pw->pw_gid) {
+               fatal("%s: egid incorrect gid:%u egid:%u (should be %u)",
+                   __func__, (u_int)getgid(), (u_int)getegid(),
+                   (u_int)pw->pw_gid);
+       }
+
+#ifndef HAVE_CYGWIN
+       /* Try restoration of UID if changed (test clearing of saved uid) */
+       if (old_uid != pw->pw_uid &&
+           (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
+               fatal("%s: was able to restore old [e]uid", __func__);
+#endif
+
+       /* Verify UID drop was successful */
+       if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) {
+               fatal("%s: euid incorrect uid:%u euid:%u (should be %u)",
+                   __func__, (u_int)getuid(), (u_int)geteuid(),
+                   (u_int)pw->pw_uid);
+       }
+}
diff --git a/uidswap.h b/uidswap.h
new file mode 100644 (file)
index 0000000..1c1163d
--- /dev/null
+++ b/uidswap.h
@@ -0,0 +1,18 @@
+/* $OpenBSD: uidswap.h,v 1.13 2006/08/03 03:34:42 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".
+ */
+
+void    temporarily_use_uid(struct passwd *);
+void    restore_uid(void);
+void    permanently_set_uid(struct passwd *);
+void    permanently_drop_suid(uid_t);
diff --git a/umac.c b/umac.c
new file mode 100644 (file)
index 0000000..92902bc
--- /dev/null
+++ b/umac.c
@@ -0,0 +1,1277 @@
+/* $OpenBSD: umac.c,v 1.3 2008/05/12 20:52:20 pvalchev Exp $ */
+/* -----------------------------------------------------------------------
+ * 
+ * umac.c -- C Implementation UMAC Message Authentication
+ *
+ * Version 0.93b of rfc4418.txt -- 2006 July 18
+ *
+ * For a full description of UMAC message authentication see the UMAC
+ * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac
+ * Please report bugs and suggestions to the UMAC webpage.
+ *
+ * Copyright (c) 1999-2006 Ted Krovetz
+ *                                                                 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and with or without fee, is hereby
+ * granted provided that the above copyright notice appears in all copies
+ * and in supporting documentation, and that the name of the copyright
+ * holder not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ * Comments should be directed to Ted Krovetz (tdk@acm.org)                                        
+ *                                                                   
+ * ---------------------------------------------------------------------- */
+ /* ////////////////////// IMPORTANT NOTES /////////////////////////////////
+  *
+  * 1) This version does not work properly on messages larger than 16MB
+  *
+  * 2) If you set the switch to use SSE2, then all data must be 16-byte
+  *    aligned
+  *
+  * 3) When calling the function umac(), it is assumed that msg is in
+  * a writable buffer of length divisible by 32 bytes. The message itself
+  * does not have to fill the entire buffer, but bytes beyond msg may be
+  * zeroed.
+  *
+  * 4) Three free AES implementations are supported by this implementation of
+  * UMAC. Paulo Barreto's version is in the public domain and can be found
+  * at http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ (search for
+  * "Barreto"). The only two files needed are rijndael-alg-fst.c and
+  * rijndael-alg-fst.h. Brian Gladman's version is distributed with the GNU
+  * Public lisence at http://fp.gladman.plus.com/AES/index.htm. It
+  * includes a fast IA-32 assembly version. The OpenSSL crypo library is
+  * the third.
+  *
+  * 5) With FORCE_C_ONLY flags set to 0, incorrect results are sometimes
+  * produced under gcc with optimizations set -O3 or higher. Dunno why.
+  *
+  /////////////////////////////////////////////////////////////////////// */
+/* ---------------------------------------------------------------------- */
+/* --- User Switches ---------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+#define UMAC_OUTPUT_LEN     8  /* Alowable: 4, 8, 12, 16                  */
+/* #define FORCE_C_ONLY        1  ANSI C and 64-bit integers req'd        */
+/* #define AES_IMPLEMENTAION   1  1 = OpenSSL, 2 = Barreto, 3 = Gladman   */
+/* #define SSE2                0  Is SSE2 is available?                   */
+/* #define RUN_TESTS           0  Run basic correctness/speed tests       */
+/* #define UMAC_AE_SUPPORT     0  Enable auhthenticated encrytion         */
+
+/* ---------------------------------------------------------------------- */
+/* -- Global Includes --------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+#include "includes.h"
+#include <sys/types.h>
+
+#include "xmalloc.h"
+#include "umac.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+/* ---------------------------------------------------------------------- */
+/* --- Primitive Data Types ---                                           */
+/* ---------------------------------------------------------------------- */
+
+/* The following assumptions may need change on your system */
+typedef u_int8_t       UINT8;  /* 1 byte   */
+typedef u_int16_t      UINT16; /* 2 byte   */
+typedef u_int32_t      UINT32; /* 4 byte   */
+typedef u_int64_t      UINT64; /* 8 bytes  */
+typedef unsigned int   UWORD;  /* Register */
+
+/* ---------------------------------------------------------------------- */
+/* --- Constants -------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+#define UMAC_KEY_LEN           16  /* UMAC takes 16 bytes of external key */
+
+/* Message "words" are read from memory in an endian-specific manner.     */
+/* For this implementation to behave correctly, __LITTLE_ENDIAN__ must    */
+/* be set true if the host computer is little-endian.                     */
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define __LITTLE_ENDIAN__ 1
+#else
+#define __LITTLE_ENDIAN__ 0
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Architecture Specific ------------------------------------------ */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Primitive Routines --------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------- */
+/* --- 32-bit by 32-bit to 64-bit Multiplication ------------------------ */
+/* ---------------------------------------------------------------------- */
+
+#define MUL64(a,b) ((UINT64)((UINT64)(UINT32)(a) * (UINT64)(UINT32)(b)))
+
+/* ---------------------------------------------------------------------- */
+/* --- Endian Conversion --- Forcing assembly on some platforms           */
+/* ---------------------------------------------------------------------- */
+
+#if HAVE_SWAP32
+#define LOAD_UINT32_REVERSED(p)                (swap32(*(UINT32 *)(p)))
+#define STORE_UINT32_REVERSED(p,v)     (*(UINT32 *)(p) = swap32(v))
+#else /* HAVE_SWAP32 */
+
+static UINT32 LOAD_UINT32_REVERSED(void *ptr)
+{
+    UINT32 temp = *(UINT32 *)ptr;
+    temp = (temp >> 24) | ((temp & 0x00FF0000) >> 8 )
+         | ((temp & 0x0000FF00) << 8 ) | (temp << 24);
+    return (UINT32)temp;
+}
+
+# if (__LITTLE_ENDIAN__)
+static void STORE_UINT32_REVERSED(void *ptr, UINT32 x)
+{
+    UINT32 i = (UINT32)x;
+    *(UINT32 *)ptr = (i >> 24) | ((i & 0x00FF0000) >> 8 )
+                   | ((i & 0x0000FF00) << 8 ) | (i << 24);
+}
+# endif /* __LITTLE_ENDIAN */
+#endif /* HAVE_SWAP32 */
+
+/* The following definitions use the above reversal-primitives to do the right
+ * thing on endian specific load and stores.
+ */
+
+#if (__LITTLE_ENDIAN__)
+#define LOAD_UINT32_LITTLE(ptr)     (*(UINT32 *)(ptr))
+#define STORE_UINT32_BIG(ptr,x)     STORE_UINT32_REVERSED(ptr,x)
+#else
+#define LOAD_UINT32_LITTLE(ptr)     LOAD_UINT32_REVERSED(ptr)
+#define STORE_UINT32_BIG(ptr,x)     (*(UINT32 *)(ptr) = (UINT32)(x))
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Begin KDF & PDF Section ---------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* UMAC uses AES with 16 byte block and key lengths */
+#define AES_BLOCK_LEN  16
+
+/* OpenSSL's AES */
+#include "openbsd-compat/openssl-compat.h"
+#ifndef USE_BUILTIN_RIJNDAEL
+# include <openssl/aes.h>
+#endif
+typedef AES_KEY aes_int_key[1];
+#define aes_encryption(in,out,int_key)                  \
+  AES_encrypt((u_char *)(in),(u_char *)(out),(AES_KEY *)int_key)
+#define aes_key_setup(key,int_key)                      \
+  AES_set_encrypt_key((u_char *)(key),UMAC_KEY_LEN*8,int_key)
+
+/* The user-supplied UMAC key is stretched using AES in a counter
+ * mode to supply all random bits needed by UMAC. The kdf function takes
+ * an AES internal key representation 'key' and writes a stream of
+ * 'nbytes' bytes to the memory pointed at by 'bufp'. Each distinct
+ * 'ndx' causes a distinct byte stream.
+ */
+static void kdf(void *bufp, aes_int_key key, UINT8 ndx, int nbytes)
+{
+    UINT8 in_buf[AES_BLOCK_LEN] = {0};
+    UINT8 out_buf[AES_BLOCK_LEN];
+    UINT8 *dst_buf = (UINT8 *)bufp;
+    int i;
+    
+    /* Setup the initial value */
+    in_buf[AES_BLOCK_LEN-9] = ndx;
+    in_buf[AES_BLOCK_LEN-1] = i = 1;
+        
+    while (nbytes >= AES_BLOCK_LEN) {
+        aes_encryption(in_buf, out_buf, key);
+        memcpy(dst_buf,out_buf,AES_BLOCK_LEN);
+        in_buf[AES_BLOCK_LEN-1] = ++i;
+        nbytes -= AES_BLOCK_LEN;
+        dst_buf += AES_BLOCK_LEN;
+    }
+    if (nbytes) {
+        aes_encryption(in_buf, out_buf, key);
+        memcpy(dst_buf,out_buf,nbytes);
+    }
+}
+
+/* The final UHASH result is XOR'd with the output of a pseudorandom
+ * function. Here, we use AES to generate random output and 
+ * xor the appropriate bytes depending on the last bits of nonce.
+ * This scheme is optimized for sequential, increasing big-endian nonces.
+ */
+
+typedef struct {
+    UINT8 cache[AES_BLOCK_LEN];  /* Previous AES output is saved      */
+    UINT8 nonce[AES_BLOCK_LEN];  /* The AES input making above cache  */
+    aes_int_key prf_key;         /* Expanded AES key for PDF          */
+} pdf_ctx;
+
+static void pdf_init(pdf_ctx *pc, aes_int_key prf_key)
+{
+    UINT8 buf[UMAC_KEY_LEN];
+    
+    kdf(buf, prf_key, 0, UMAC_KEY_LEN);
+    aes_key_setup(buf, pc->prf_key);
+    
+    /* Initialize pdf and cache */
+    memset(pc->nonce, 0, sizeof(pc->nonce));
+    aes_encryption(pc->nonce, pc->cache, pc->prf_key);
+}
+
+static void pdf_gen_xor(pdf_ctx *pc, UINT8 nonce[8], UINT8 buf[8])
+{
+    /* 'ndx' indicates that we'll be using the 0th or 1st eight bytes
+     * of the AES output. If last time around we returned the ndx-1st
+     * element, then we may have the result in the cache already.
+     */
+     
+#if (UMAC_OUTPUT_LEN == 4)
+#define LOW_BIT_MASK 3
+#elif (UMAC_OUTPUT_LEN == 8)
+#define LOW_BIT_MASK 1
+#elif (UMAC_OUTPUT_LEN > 8)
+#define LOW_BIT_MASK 0
+#endif
+
+    UINT8 tmp_nonce_lo[4];
+#if LOW_BIT_MASK != 0
+    int ndx = nonce[7] & LOW_BIT_MASK;
+#endif
+    *(UINT32 *)tmp_nonce_lo = ((UINT32 *)nonce)[1];
+    tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */
+    
+    if ( (((UINT32 *)tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) ||
+         (((UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) )
+    {
+        ((UINT32 *)pc->nonce)[0] = ((UINT32 *)nonce)[0];
+        ((UINT32 *)pc->nonce)[1] = ((UINT32 *)tmp_nonce_lo)[0];
+        aes_encryption(pc->nonce, pc->cache, pc->prf_key);
+    }
+    
+#if (UMAC_OUTPUT_LEN == 4)
+    *((UINT32 *)buf) ^= ((UINT32 *)pc->cache)[ndx];
+#elif (UMAC_OUTPUT_LEN == 8)
+    *((UINT64 *)buf) ^= ((UINT64 *)pc->cache)[ndx];
+#elif (UMAC_OUTPUT_LEN == 12)
+    ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0];
+    ((UINT32 *)buf)[2] ^= ((UINT32 *)pc->cache)[2];
+#elif (UMAC_OUTPUT_LEN == 16)
+    ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0];
+    ((UINT64 *)buf)[1] ^= ((UINT64 *)pc->cache)[1];
+#endif
+}
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Begin NH Hash Section ------------------------------------------ */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* The NH-based hash functions used in UMAC are described in the UMAC paper
+ * and specification, both of which can be found at the UMAC website.     
+ * The interface to this implementation has two         
+ * versions, one expects the entire message being hashed to be passed
+ * in a single buffer and returns the hash result immediately. The second
+ * allows the message to be passed in a sequence of buffers. In the          
+ * muliple-buffer interface, the client calls the routine nh_update() as     
+ * many times as necessary. When there is no more data to be fed to the   
+ * hash, the client calls nh_final() which calculates the hash output.    
+ * Before beginning another hash calculation the nh_reset() routine       
+ * must be called. The single-buffer routine, nh(), is equivalent to  
+ * the sequence of calls nh_update() and nh_final(); however it is        
+ * optimized and should be prefered whenever the multiple-buffer interface
+ * is not necessary. When using either interface, it is the client's         
+ * responsability to pass no more than L1_KEY_LEN bytes per hash result.            
+ *                                                                        
+ * The routine nh_init() initializes the nh_ctx data structure and        
+ * must be called once, before any other PDF routine.                     
+ */
+ /* The "nh_aux" routines do the actual NH hashing work. They
+  * expect buffers to be multiples of L1_PAD_BOUNDARY. These routines
+  * produce output for all STREAMS NH iterations in one call, 
+  * allowing the parallel implementation of the streams.
+  */
+
+#define STREAMS (UMAC_OUTPUT_LEN / 4) /* Number of times hash is applied  */
+#define L1_KEY_LEN         1024     /* Internal key bytes                 */
+#define L1_KEY_SHIFT         16     /* Toeplitz key shift between streams */
+#define L1_PAD_BOUNDARY      32     /* pad message to boundary multiple   */
+#define ALLOC_BOUNDARY       16     /* Keep buffers aligned to this       */
+#define HASH_BUF_BYTES       64     /* nh_aux_hb buffer multiple          */
+
+typedef struct {
+    UINT8  nh_key [L1_KEY_LEN + L1_KEY_SHIFT * (STREAMS - 1)]; /* NH Key */
+    UINT8  data   [HASH_BUF_BYTES];    /* Incomming data buffer           */
+    int next_data_empty;    /* Bookeeping variable for data buffer.       */
+    int bytes_hashed;        /* Bytes (out of L1_KEY_LEN) incorperated.   */
+    UINT64 state[STREAMS];               /* on-line state     */
+} nh_ctx;
+
+
+#if (UMAC_OUTPUT_LEN == 4)
+
+static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen)
+/* NH hashing primitive. Previous (partial) hash result is loaded and     
+* then stored via hp pointer. The length of the data pointed at by "dp",
+* "dlen", is guaranteed to be divisible by L1_PAD_BOUNDARY (32).  Key
+* is expected to be endian compensated in memory at key setup.    
+*/
+{
+    UINT64 h;
+    UWORD c = dlen / 32;
+    UINT32 *k = (UINT32 *)kp;
+    UINT32 *d = (UINT32 *)dp;
+    UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
+    UINT32 k0,k1,k2,k3,k4,k5,k6,k7;
+    
+    h = *((UINT64 *)hp);
+    do {
+        d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
+        d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
+        d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
+        d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
+        k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
+        k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
+        h += MUL64((k0 + d0), (k4 + d4));
+        h += MUL64((k1 + d1), (k5 + d5));
+        h += MUL64((k2 + d2), (k6 + d6));
+        h += MUL64((k3 + d3), (k7 + d7));
+        
+        d += 8;
+        k += 8;
+    } while (--c);
+  *((UINT64 *)hp) = h;
+}
+
+#elif (UMAC_OUTPUT_LEN == 8)
+
+static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen)
+/* Same as previous nh_aux, but two streams are handled in one pass,
+ * reading and writing 16 bytes of hash-state per call.
+ */
+{
+  UINT64 h1,h2;
+  UWORD c = dlen / 32;
+  UINT32 *k = (UINT32 *)kp;
+  UINT32 *d = (UINT32 *)dp;
+  UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
+  UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
+        k8,k9,k10,k11;
+
+  h1 = *((UINT64 *)hp);
+  h2 = *((UINT64 *)hp + 1);
+  k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
+  do {
+    d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
+    d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
+    d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
+    d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
+    k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
+    k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
+
+    h1 += MUL64((k0 + d0), (k4 + d4));
+    h2 += MUL64((k4 + d0), (k8 + d4));
+
+    h1 += MUL64((k1 + d1), (k5 + d5));
+    h2 += MUL64((k5 + d1), (k9 + d5));
+
+    h1 += MUL64((k2 + d2), (k6 + d6));
+    h2 += MUL64((k6 + d2), (k10 + d6));
+
+    h1 += MUL64((k3 + d3), (k7 + d7));
+    h2 += MUL64((k7 + d3), (k11 + d7));
+
+    k0 = k8; k1 = k9; k2 = k10; k3 = k11;
+
+    d += 8;
+    k += 8;
+  } while (--c);
+  ((UINT64 *)hp)[0] = h1;
+  ((UINT64 *)hp)[1] = h2;
+}
+
+#elif (UMAC_OUTPUT_LEN == 12)
+
+static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen)
+/* Same as previous nh_aux, but two streams are handled in one pass,
+ * reading and writing 24 bytes of hash-state per call.
+*/
+{
+    UINT64 h1,h2,h3;
+    UWORD c = dlen / 32;
+    UINT32 *k = (UINT32 *)kp;
+    UINT32 *d = (UINT32 *)dp;
+    UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
+    UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
+        k8,k9,k10,k11,k12,k13,k14,k15;
+    
+    h1 = *((UINT64 *)hp);
+    h2 = *((UINT64 *)hp + 1);
+    h3 = *((UINT64 *)hp + 2);
+    k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
+    k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
+    do {
+        d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
+        d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
+        d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
+        d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
+        k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
+        k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
+        
+        h1 += MUL64((k0 + d0), (k4 + d4));
+        h2 += MUL64((k4 + d0), (k8 + d4));
+        h3 += MUL64((k8 + d0), (k12 + d4));
+        
+        h1 += MUL64((k1 + d1), (k5 + d5));
+        h2 += MUL64((k5 + d1), (k9 + d5));
+        h3 += MUL64((k9 + d1), (k13 + d5));
+        
+        h1 += MUL64((k2 + d2), (k6 + d6));
+        h2 += MUL64((k6 + d2), (k10 + d6));
+        h3 += MUL64((k10 + d2), (k14 + d6));
+        
+        h1 += MUL64((k3 + d3), (k7 + d7));
+        h2 += MUL64((k7 + d3), (k11 + d7));
+        h3 += MUL64((k11 + d3), (k15 + d7));
+        
+        k0 = k8; k1 = k9; k2 = k10; k3 = k11;
+        k4 = k12; k5 = k13; k6 = k14; k7 = k15;
+        
+        d += 8;
+        k += 8;
+    } while (--c);
+    ((UINT64 *)hp)[0] = h1;
+    ((UINT64 *)hp)[1] = h2;
+    ((UINT64 *)hp)[2] = h3;
+}
+
+#elif (UMAC_OUTPUT_LEN == 16)
+
+static void nh_aux(void *kp, void *dp, void *hp, UINT32 dlen)
+/* Same as previous nh_aux, but two streams are handled in one pass,
+ * reading and writing 24 bytes of hash-state per call.
+*/
+{
+    UINT64 h1,h2,h3,h4;
+    UWORD c = dlen / 32;
+    UINT32 *k = (UINT32 *)kp;
+    UINT32 *d = (UINT32 *)dp;
+    UINT32 d0,d1,d2,d3,d4,d5,d6,d7;
+    UINT32 k0,k1,k2,k3,k4,k5,k6,k7,
+        k8,k9,k10,k11,k12,k13,k14,k15,
+        k16,k17,k18,k19;
+    
+    h1 = *((UINT64 *)hp);
+    h2 = *((UINT64 *)hp + 1);
+    h3 = *((UINT64 *)hp + 2);
+    h4 = *((UINT64 *)hp + 3);
+    k0 = *(k+0); k1 = *(k+1); k2 = *(k+2); k3 = *(k+3);
+    k4 = *(k+4); k5 = *(k+5); k6 = *(k+6); k7 = *(k+7);
+    do {
+        d0 = LOAD_UINT32_LITTLE(d+0); d1 = LOAD_UINT32_LITTLE(d+1);
+        d2 = LOAD_UINT32_LITTLE(d+2); d3 = LOAD_UINT32_LITTLE(d+3);
+        d4 = LOAD_UINT32_LITTLE(d+4); d5 = LOAD_UINT32_LITTLE(d+5);
+        d6 = LOAD_UINT32_LITTLE(d+6); d7 = LOAD_UINT32_LITTLE(d+7);
+        k8 = *(k+8); k9 = *(k+9); k10 = *(k+10); k11 = *(k+11);
+        k12 = *(k+12); k13 = *(k+13); k14 = *(k+14); k15 = *(k+15);
+        k16 = *(k+16); k17 = *(k+17); k18 = *(k+18); k19 = *(k+19);
+        
+        h1 += MUL64((k0 + d0), (k4 + d4));
+        h2 += MUL64((k4 + d0), (k8 + d4));
+        h3 += MUL64((k8 + d0), (k12 + d4));
+        h4 += MUL64((k12 + d0), (k16 + d4));
+        
+        h1 += MUL64((k1 + d1), (k5 + d5));
+        h2 += MUL64((k5 + d1), (k9 + d5));
+        h3 += MUL64((k9 + d1), (k13 + d5));
+        h4 += MUL64((k13 + d1), (k17 + d5));
+        
+        h1 += MUL64((k2 + d2), (k6 + d6));
+        h2 += MUL64((k6 + d2), (k10 + d6));
+        h3 += MUL64((k10 + d2), (k14 + d6));
+        h4 += MUL64((k14 + d2), (k18 + d6));
+        
+        h1 += MUL64((k3 + d3), (k7 + d7));
+        h2 += MUL64((k7 + d3), (k11 + d7));
+        h3 += MUL64((k11 + d3), (k15 + d7));
+        h4 += MUL64((k15 + d3), (k19 + d7));
+        
+        k0 = k8; k1 = k9; k2 = k10; k3 = k11;
+        k4 = k12; k5 = k13; k6 = k14; k7 = k15;
+        k8 = k16; k9 = k17; k10 = k18; k11 = k19;
+        
+        d += 8;
+        k += 8;
+    } while (--c);
+    ((UINT64 *)hp)[0] = h1;
+    ((UINT64 *)hp)[1] = h2;
+    ((UINT64 *)hp)[2] = h3;
+    ((UINT64 *)hp)[3] = h4;
+}
+
+/* ---------------------------------------------------------------------- */
+#endif  /* UMAC_OUTPUT_LENGTH */
+/* ---------------------------------------------------------------------- */
+
+
+/* ---------------------------------------------------------------------- */
+
+static void nh_transform(nh_ctx *hc, UINT8 *buf, UINT32 nbytes)
+/* This function is a wrapper for the primitive NH hash functions. It takes
+ * as argument "hc" the current hash context and a buffer which must be a
+ * multiple of L1_PAD_BOUNDARY. The key passed to nh_aux is offset
+ * appropriately according to how much message has been hashed already.
+ */
+{
+    UINT8 *key;
+  
+    key = hc->nh_key + hc->bytes_hashed;
+    nh_aux(key, buf, hc->state, nbytes);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if (__LITTLE_ENDIAN__)
+static void endian_convert(void *buf, UWORD bpw, UINT32 num_bytes)
+/* We endian convert the keys on little-endian computers to               */
+/* compensate for the lack of big-endian memory reads during hashing.     */
+{
+    UWORD iters = num_bytes / bpw;
+    if (bpw == 4) {
+        UINT32 *p = (UINT32 *)buf;
+        do {
+            *p = LOAD_UINT32_REVERSED(p);
+            p++;
+        } while (--iters);
+    } else if (bpw == 8) {
+        UINT32 *p = (UINT32 *)buf;
+        UINT32 t;
+        do {
+            t = LOAD_UINT32_REVERSED(p+1);
+            p[1] = LOAD_UINT32_REVERSED(p);
+            p[0] = t;
+            p += 2;
+        } while (--iters);
+    }
+}
+#define endian_convert_if_le(x,y,z) endian_convert((x),(y),(z))
+#else
+#define endian_convert_if_le(x,y,z) do{}while(0)  /* Do nothing */
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static void nh_reset(nh_ctx *hc)
+/* Reset nh_ctx to ready for hashing of new data */
+{
+    hc->bytes_hashed = 0;
+    hc->next_data_empty = 0;
+    hc->state[0] = 0;
+#if (UMAC_OUTPUT_LEN >= 8)
+    hc->state[1] = 0;
+#endif
+#if (UMAC_OUTPUT_LEN >= 12)
+    hc->state[2] = 0;
+#endif
+#if (UMAC_OUTPUT_LEN == 16)
+    hc->state[3] = 0;
+#endif
+
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void nh_init(nh_ctx *hc, aes_int_key prf_key)
+/* Generate nh_key, endian convert and reset to be ready for hashing.   */
+{
+    kdf(hc->nh_key, prf_key, 1, sizeof(hc->nh_key));
+    endian_convert_if_le(hc->nh_key, 4, sizeof(hc->nh_key));
+    nh_reset(hc);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void nh_update(nh_ctx *hc, UINT8 *buf, UINT32 nbytes)
+/* Incorporate nbytes of data into a nh_ctx, buffer whatever is not an    */
+/* even multiple of HASH_BUF_BYTES.                                       */
+{
+    UINT32 i,j;
+    
+    j = hc->next_data_empty;
+    if ((j + nbytes) >= HASH_BUF_BYTES) {
+        if (j) {
+            i = HASH_BUF_BYTES - j;
+            memcpy(hc->data+j, buf, i);
+            nh_transform(hc,hc->data,HASH_BUF_BYTES);
+            nbytes -= i;
+            buf += i;
+            hc->bytes_hashed += HASH_BUF_BYTES;
+        }
+        if (nbytes >= HASH_BUF_BYTES) {
+            i = nbytes & ~(HASH_BUF_BYTES - 1);
+            nh_transform(hc, buf, i);
+            nbytes -= i;
+            buf += i;
+            hc->bytes_hashed += i;
+        }
+        j = 0;
+    }
+    memcpy(hc->data + j, buf, nbytes);
+    hc->next_data_empty = j + nbytes;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void zero_pad(UINT8 *p, int nbytes)
+{
+/* Write "nbytes" of zeroes, beginning at "p" */
+    if (nbytes >= (int)sizeof(UWORD)) {
+        while ((ptrdiff_t)p % sizeof(UWORD)) {
+            *p = 0;
+            nbytes--;
+            p++;
+        }
+        while (nbytes >= (int)sizeof(UWORD)) {
+            *(UWORD *)p = 0;
+            nbytes -= sizeof(UWORD);
+            p += sizeof(UWORD);
+        }
+    }
+    while (nbytes) {
+        *p = 0;
+        nbytes--;
+        p++;
+    }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void nh_final(nh_ctx *hc, UINT8 *result)
+/* After passing some number of data buffers to nh_update() for integration
+ * into an NH context, nh_final is called to produce a hash result. If any
+ * bytes are in the buffer hc->data, incorporate them into the
+ * NH context. Finally, add into the NH accumulation "state" the total number
+ * of bits hashed. The resulting numbers are written to the buffer "result".
+ * If nh_update was never called, L1_PAD_BOUNDARY zeroes are incorporated.
+ */
+{
+    int nh_len, nbits;
+
+    if (hc->next_data_empty != 0) {
+        nh_len = ((hc->next_data_empty + (L1_PAD_BOUNDARY - 1)) &
+                                                ~(L1_PAD_BOUNDARY - 1));
+        zero_pad(hc->data + hc->next_data_empty, 
+                                          nh_len - hc->next_data_empty);
+        nh_transform(hc, hc->data, nh_len);
+        hc->bytes_hashed += hc->next_data_empty;
+    } else if (hc->bytes_hashed == 0) {
+       nh_len = L1_PAD_BOUNDARY;
+        zero_pad(hc->data, L1_PAD_BOUNDARY);
+        nh_transform(hc, hc->data, nh_len);
+    }
+
+    nbits = (hc->bytes_hashed << 3);
+    ((UINT64 *)result)[0] = ((UINT64 *)hc->state)[0] + nbits;
+#if (UMAC_OUTPUT_LEN >= 8)
+    ((UINT64 *)result)[1] = ((UINT64 *)hc->state)[1] + nbits;
+#endif
+#if (UMAC_OUTPUT_LEN >= 12)
+    ((UINT64 *)result)[2] = ((UINT64 *)hc->state)[2] + nbits;
+#endif
+#if (UMAC_OUTPUT_LEN == 16)
+    ((UINT64 *)result)[3] = ((UINT64 *)hc->state)[3] + nbits;
+#endif
+    nh_reset(hc);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void nh(nh_ctx *hc, UINT8 *buf, UINT32 padded_len,
+               UINT32 unpadded_len, UINT8 *result)
+/* All-in-one nh_update() and nh_final() equivalent.
+ * Assumes that padded_len is divisible by L1_PAD_BOUNDARY and result is
+ * well aligned
+ */
+{
+    UINT32 nbits;
+    
+    /* Initialize the hash state */
+    nbits = (unpadded_len << 3);
+    
+    ((UINT64 *)result)[0] = nbits;
+#if (UMAC_OUTPUT_LEN >= 8)
+    ((UINT64 *)result)[1] = nbits;
+#endif
+#if (UMAC_OUTPUT_LEN >= 12)
+    ((UINT64 *)result)[2] = nbits;
+#endif
+#if (UMAC_OUTPUT_LEN == 16)
+    ((UINT64 *)result)[3] = nbits;
+#endif
+    
+    nh_aux(hc->nh_key, buf, result, padded_len);
+}
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Begin UHASH Section -------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* UHASH is a multi-layered algorithm. Data presented to UHASH is first
+ * hashed by NH. The NH output is then hashed by a polynomial-hash layer
+ * unless the initial data to be hashed is short. After the polynomial-
+ * layer, an inner-product hash is used to produce the final UHASH output.
+ *
+ * UHASH provides two interfaces, one all-at-once and another where data
+ * buffers are presented sequentially. In the sequential interface, the
+ * UHASH client calls the routine uhash_update() as many times as necessary.
+ * When there is no more data to be fed to UHASH, the client calls
+ * uhash_final() which          
+ * calculates the UHASH output. Before beginning another UHASH calculation    
+ * the uhash_reset() routine must be called. The all-at-once UHASH routine,   
+ * uhash(), is equivalent to the sequence of calls uhash_update() and         
+ * uhash_final(); however it is optimized and should be                     
+ * used whenever the sequential interface is not necessary.              
+ *                                                                        
+ * The routine uhash_init() initializes the uhash_ctx data structure and    
+ * must be called once, before any other UHASH routine.
+ */                                                        
+
+/* ---------------------------------------------------------------------- */
+/* ----- Constants and uhash_ctx ---------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------- */
+/* ----- Poly hash and Inner-Product hash Constants --------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* Primes and masks */
+#define p36    ((UINT64)0x0000000FFFFFFFFBull)              /* 2^36 -  5 */
+#define p64    ((UINT64)0xFFFFFFFFFFFFFFC5ull)              /* 2^64 - 59 */
+#define m36    ((UINT64)0x0000000FFFFFFFFFull)  /* The low 36 of 64 bits */
+
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct uhash_ctx {
+    nh_ctx hash;                          /* Hash context for L1 NH hash  */
+    UINT64 poly_key_8[STREAMS];           /* p64 poly keys                */
+    UINT64 poly_accum[STREAMS];           /* poly hash result             */
+    UINT64 ip_keys[STREAMS*4];            /* Inner-product keys           */
+    UINT32 ip_trans[STREAMS];             /* Inner-product translation    */
+    UINT32 msg_len;                       /* Total length of data passed  */
+                                          /* to uhash */
+} uhash_ctx;
+typedef struct uhash_ctx *uhash_ctx_t;
+
+/* ---------------------------------------------------------------------- */
+
+
+/* The polynomial hashes use Horner's rule to evaluate a polynomial one
+ * word at a time. As described in the specification, poly32 and poly64
+ * require keys from special domains. The following implementations exploit
+ * the special domains to avoid overflow. The results are not guaranteed to
+ * be within Z_p32 and Z_p64, but the Inner-Product hash implementation
+ * patches any errant values.
+ */
+
+static UINT64 poly64(UINT64 cur, UINT64 key, UINT64 data)
+{
+    UINT32 key_hi = (UINT32)(key >> 32),
+           key_lo = (UINT32)key,
+           cur_hi = (UINT32)(cur >> 32),
+           cur_lo = (UINT32)cur,
+           x_lo,
+           x_hi;
+    UINT64 X,T,res;
+    
+    X =  MUL64(key_hi, cur_lo) + MUL64(cur_hi, key_lo);
+    x_lo = (UINT32)X;
+    x_hi = (UINT32)(X >> 32);
+    
+    res = (MUL64(key_hi, cur_hi) + x_hi) * 59 + MUL64(key_lo, cur_lo);
+     
+    T = ((UINT64)x_lo << 32);
+    res += T;
+    if (res < T)
+        res += 59;
+
+    res += data;
+    if (res < data)
+        res += 59;
+
+    return res;
+}
+
+
+/* Although UMAC is specified to use a ramped polynomial hash scheme, this
+ * implementation does not handle all ramp levels. Because we don't handle
+ * the ramp up to p128 modulus in this implementation, we are limited to
+ * 2^14 poly_hash() invocations per stream (for a total capacity of 2^24
+ * bytes input to UMAC per tag, ie. 16MB).
+ */
+static void poly_hash(uhash_ctx_t hc, UINT32 data_in[])
+{
+    int i;
+    UINT64 *data=(UINT64*)data_in;
+    
+    for (i = 0; i < STREAMS; i++) {
+        if ((UINT32)(data[i] >> 32) == 0xfffffffful) {
+            hc->poly_accum[i] = poly64(hc->poly_accum[i], 
+                                       hc->poly_key_8[i], p64 - 1);
+            hc->poly_accum[i] = poly64(hc->poly_accum[i],
+                                       hc->poly_key_8[i], (data[i] - 59));
+        } else {
+            hc->poly_accum[i] = poly64(hc->poly_accum[i],
+                                       hc->poly_key_8[i], data[i]);
+        }
+    }
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/* The final step in UHASH is an inner-product hash. The poly hash
+ * produces a result not neccesarily WORD_LEN bytes long. The inner-
+ * product hash breaks the polyhash output into 16-bit chunks and
+ * multiplies each with a 36 bit key.
+ */
+
+static UINT64 ip_aux(UINT64 t, UINT64 *ipkp, UINT64 data)
+{
+    t = t + ipkp[0] * (UINT64)(UINT16)(data >> 48);
+    t = t + ipkp[1] * (UINT64)(UINT16)(data >> 32);
+    t = t + ipkp[2] * (UINT64)(UINT16)(data >> 16);
+    t = t + ipkp[3] * (UINT64)(UINT16)(data);
+    
+    return t;
+}
+
+static UINT32 ip_reduce_p36(UINT64 t)
+{
+/* Divisionless modular reduction */
+    UINT64 ret;
+    
+    ret = (t & m36) + 5 * (t >> 36);
+    if (ret >= p36)
+        ret -= p36;
+
+    /* return least significant 32 bits */
+    return (UINT32)(ret);
+}
+
+
+/* If the data being hashed by UHASH is no longer than L1_KEY_LEN, then
+ * the polyhash stage is skipped and ip_short is applied directly to the
+ * NH output.
+ */
+static void ip_short(uhash_ctx_t ahc, UINT8 *nh_res, u_char *res)
+{
+    UINT64 t;
+    UINT64 *nhp = (UINT64 *)nh_res;
+    
+    t  = ip_aux(0,ahc->ip_keys, nhp[0]);
+    STORE_UINT32_BIG((UINT32 *)res+0, ip_reduce_p36(t) ^ ahc->ip_trans[0]);
+#if (UMAC_OUTPUT_LEN >= 8)
+    t  = ip_aux(0,ahc->ip_keys+4, nhp[1]);
+    STORE_UINT32_BIG((UINT32 *)res+1, ip_reduce_p36(t) ^ ahc->ip_trans[1]);
+#endif
+#if (UMAC_OUTPUT_LEN >= 12)
+    t  = ip_aux(0,ahc->ip_keys+8, nhp[2]);
+    STORE_UINT32_BIG((UINT32 *)res+2, ip_reduce_p36(t) ^ ahc->ip_trans[2]);
+#endif
+#if (UMAC_OUTPUT_LEN == 16)
+    t  = ip_aux(0,ahc->ip_keys+12, nhp[3]);
+    STORE_UINT32_BIG((UINT32 *)res+3, ip_reduce_p36(t) ^ ahc->ip_trans[3]);
+#endif
+}
+
+/* If the data being hashed by UHASH is longer than L1_KEY_LEN, then
+ * the polyhash stage is not skipped and ip_long is applied to the
+ * polyhash output.
+ */
+static void ip_long(uhash_ctx_t ahc, u_char *res)
+{
+    int i;
+    UINT64 t;
+
+    for (i = 0; i < STREAMS; i++) {
+        /* fix polyhash output not in Z_p64 */
+        if (ahc->poly_accum[i] >= p64)
+            ahc->poly_accum[i] -= p64;
+        t  = ip_aux(0,ahc->ip_keys+(i*4), ahc->poly_accum[i]);
+        STORE_UINT32_BIG((UINT32 *)res+i, 
+                         ip_reduce_p36(t) ^ ahc->ip_trans[i]);
+    }
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------- */
+
+/* Reset uhash context for next hash session */
+static int uhash_reset(uhash_ctx_t pc)
+{
+    nh_reset(&pc->hash);
+    pc->msg_len = 0;
+    pc->poly_accum[0] = 1;
+#if (UMAC_OUTPUT_LEN >= 8)
+    pc->poly_accum[1] = 1;
+#endif
+#if (UMAC_OUTPUT_LEN >= 12)
+    pc->poly_accum[2] = 1;
+#endif
+#if (UMAC_OUTPUT_LEN == 16)
+    pc->poly_accum[3] = 1;
+#endif
+    return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Given a pointer to the internal key needed by kdf() and a uhash context,
+ * initialize the NH context and generate keys needed for poly and inner-
+ * product hashing. All keys are endian adjusted in memory so that native
+ * loads cause correct keys to be in registers during calculation.
+ */
+static void uhash_init(uhash_ctx_t ahc, aes_int_key prf_key)
+{
+    int i;
+    UINT8 buf[(8*STREAMS+4)*sizeof(UINT64)];
+    
+    /* Zero the entire uhash context */
+    memset(ahc, 0, sizeof(uhash_ctx));
+
+    /* Initialize the L1 hash */
+    nh_init(&ahc->hash, prf_key);
+    
+    /* Setup L2 hash variables */
+    kdf(buf, prf_key, 2, sizeof(buf));    /* Fill buffer with index 1 key */
+    for (i = 0; i < STREAMS; i++) {
+        /* Fill keys from the buffer, skipping bytes in the buffer not
+         * used by this implementation. Endian reverse the keys if on a
+         * little-endian computer.
+         */
+        memcpy(ahc->poly_key_8+i, buf+24*i, 8);
+        endian_convert_if_le(ahc->poly_key_8+i, 8, 8);
+        /* Mask the 64-bit keys to their special domain */
+        ahc->poly_key_8[i] &= ((UINT64)0x01ffffffu << 32) + 0x01ffffffu;
+        ahc->poly_accum[i] = 1;  /* Our polyhash prepends a non-zero word */
+    }
+    
+    /* Setup L3-1 hash variables */
+    kdf(buf, prf_key, 3, sizeof(buf)); /* Fill buffer with index 2 key */
+    for (i = 0; i < STREAMS; i++)
+          memcpy(ahc->ip_keys+4*i, buf+(8*i+4)*sizeof(UINT64),
+                                                 4*sizeof(UINT64));
+    endian_convert_if_le(ahc->ip_keys, sizeof(UINT64), 
+                                                  sizeof(ahc->ip_keys));
+    for (i = 0; i < STREAMS*4; i++)
+        ahc->ip_keys[i] %= p36;  /* Bring into Z_p36 */
+    
+    /* Setup L3-2 hash variables    */
+    /* Fill buffer with index 4 key */
+    kdf(ahc->ip_trans, prf_key, 4, STREAMS * sizeof(UINT32));
+    endian_convert_if_le(ahc->ip_trans, sizeof(UINT32),
+                         STREAMS * sizeof(UINT32));
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+static uhash_ctx_t uhash_alloc(u_char key[])
+{
+/* Allocate memory and force to a 16-byte boundary. */
+    uhash_ctx_t ctx;
+    u_char bytes_to_add;
+    aes_int_key prf_key;
+    
+    ctx = (uhash_ctx_t)malloc(sizeof(uhash_ctx)+ALLOC_BOUNDARY);
+    if (ctx) {
+        if (ALLOC_BOUNDARY) {
+            bytes_to_add = ALLOC_BOUNDARY -
+                              ((ptrdiff_t)ctx & (ALLOC_BOUNDARY -1));
+            ctx = (uhash_ctx_t)((u_char *)ctx + bytes_to_add);
+            *((u_char *)ctx - 1) = bytes_to_add;
+        }
+        aes_key_setup(key,prf_key);
+        uhash_init(ctx, prf_key);
+    }
+    return (ctx);
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+static int uhash_free(uhash_ctx_t ctx)
+{
+/* Free memory allocated by uhash_alloc */
+    u_char bytes_to_sub;
+    
+    if (ctx) {
+        if (ALLOC_BOUNDARY) {
+            bytes_to_sub = *((u_char *)ctx - 1);
+            ctx = (uhash_ctx_t)((u_char *)ctx - bytes_to_sub);
+        }
+        free(ctx);
+    }
+    return (1);
+}
+#endif
+/* ---------------------------------------------------------------------- */
+
+static int uhash_update(uhash_ctx_t ctx, u_char *input, long len)
+/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and
+ * hash each one with NH, calling the polyhash on each NH output.
+ */
+{
+    UWORD bytes_hashed, bytes_remaining;
+    UINT64 result_buf[STREAMS];
+    UINT8 *nh_result = (UINT8 *)&result_buf;
+    
+    if (ctx->msg_len + len <= L1_KEY_LEN) {
+        nh_update(&ctx->hash, (UINT8 *)input, len);
+        ctx->msg_len += len;
+    } else {
+    
+         bytes_hashed = ctx->msg_len % L1_KEY_LEN;
+         if (ctx->msg_len == L1_KEY_LEN)
+             bytes_hashed = L1_KEY_LEN;
+
+         if (bytes_hashed + len >= L1_KEY_LEN) {
+
+             /* If some bytes have been passed to the hash function      */
+             /* then we want to pass at most (L1_KEY_LEN - bytes_hashed) */
+             /* bytes to complete the current nh_block.                  */
+             if (bytes_hashed) {
+                 bytes_remaining = (L1_KEY_LEN - bytes_hashed);
+                 nh_update(&ctx->hash, (UINT8 *)input, bytes_remaining);
+                 nh_final(&ctx->hash, nh_result);
+                 ctx->msg_len += bytes_remaining;
+                 poly_hash(ctx,(UINT32 *)nh_result);
+                 len -= bytes_remaining;
+                 input += bytes_remaining;
+             }
+
+             /* Hash directly from input stream if enough bytes */
+             while (len >= L1_KEY_LEN) {
+                 nh(&ctx->hash, (UINT8 *)input, L1_KEY_LEN,
+                                   L1_KEY_LEN, nh_result);
+                 ctx->msg_len += L1_KEY_LEN;
+                 len -= L1_KEY_LEN;
+                 input += L1_KEY_LEN;
+                 poly_hash(ctx,(UINT32 *)nh_result);
+             }
+         }
+
+         /* pass remaining < L1_KEY_LEN bytes of input data to NH */
+         if (len) {
+             nh_update(&ctx->hash, (UINT8 *)input, len);
+             ctx->msg_len += len;
+         }
+     }
+
+    return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int uhash_final(uhash_ctx_t ctx, u_char *res)
+/* Incorporate any pending data, pad, and generate tag */
+{
+    UINT64 result_buf[STREAMS];
+    UINT8 *nh_result = (UINT8 *)&result_buf;
+
+    if (ctx->msg_len > L1_KEY_LEN) {
+        if (ctx->msg_len % L1_KEY_LEN) {
+            nh_final(&ctx->hash, nh_result);
+            poly_hash(ctx,(UINT32 *)nh_result);
+        }
+        ip_long(ctx, res);
+    } else {
+        nh_final(&ctx->hash, nh_result);
+        ip_short(ctx,nh_result, res);
+    }
+    uhash_reset(ctx);
+    return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+static int uhash(uhash_ctx_t ahc, u_char *msg, long len, u_char *res)
+/* assumes that msg is in a writable buffer of length divisible by */
+/* L1_PAD_BOUNDARY. Bytes beyond msg[len] may be zeroed.           */
+{
+    UINT8 nh_result[STREAMS*sizeof(UINT64)];
+    UINT32 nh_len;
+    int extra_zeroes_needed;
+        
+    /* If the message to be hashed is no longer than L1_HASH_LEN, we skip
+     * the polyhash.
+     */
+    if (len <= L1_KEY_LEN) {
+       if (len == 0)                  /* If zero length messages will not */
+               nh_len = L1_PAD_BOUNDARY;  /* be seen, comment out this case   */ 
+       else
+               nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
+        extra_zeroes_needed = nh_len - len;
+        zero_pad((UINT8 *)msg + len, extra_zeroes_needed);
+        nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
+        ip_short(ahc,nh_result, res);
+    } else {
+        /* Otherwise, we hash each L1_KEY_LEN chunk with NH, passing the NH
+         * output to poly_hash().
+         */
+        do {
+            nh(&ahc->hash, (UINT8 *)msg, L1_KEY_LEN, L1_KEY_LEN, nh_result);
+            poly_hash(ahc,(UINT32 *)nh_result);
+            len -= L1_KEY_LEN;
+            msg += L1_KEY_LEN;
+        } while (len >= L1_KEY_LEN);
+        if (len) {
+            nh_len = ((len + (L1_PAD_BOUNDARY - 1)) & ~(L1_PAD_BOUNDARY - 1));
+            extra_zeroes_needed = nh_len - len;
+            zero_pad((UINT8 *)msg + len, extra_zeroes_needed);
+            nh(&ahc->hash, (UINT8 *)msg, nh_len, len, nh_result);
+            poly_hash(ahc,(UINT32 *)nh_result);
+        }
+
+        ip_long(ahc, res);
+    }
+    
+    uhash_reset(ahc);
+    return 1;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- Begin UMAC Section --------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+
+/* The UMAC interface has two interfaces, an all-at-once interface where
+ * the entire message to be authenticated is passed to UMAC in one buffer,
+ * and a sequential interface where the message is presented a little at a   
+ * time. The all-at-once is more optimaized than the sequential version and
+ * should be preferred when the sequential interface is not required. 
+ */
+struct umac_ctx {
+    uhash_ctx hash;          /* Hash function for message compression    */
+    pdf_ctx pdf;             /* PDF for hashed output                    */
+    void *free_ptr;          /* Address to free this struct via          */
+} umac_ctx;
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+int umac_reset(struct umac_ctx *ctx)
+/* Reset the hash function to begin a new authentication.        */
+{
+    uhash_reset(&ctx->hash);
+    return (1);
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+int umac_delete(struct umac_ctx *ctx)
+/* Deallocate the ctx structure */
+{
+    if (ctx) {
+        if (ALLOC_BOUNDARY)
+            ctx = (struct umac_ctx *)ctx->free_ptr;
+        xfree(ctx);
+    }
+    return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct umac_ctx *umac_new(u_char key[])
+/* Dynamically allocate a umac_ctx struct, initialize variables, 
+ * generate subkeys from key. Align to 16-byte boundary.
+ */
+{
+    struct umac_ctx *ctx, *octx;
+    size_t bytes_to_add;
+    aes_int_key prf_key;
+    
+    octx = ctx = xmalloc(sizeof(*ctx) + ALLOC_BOUNDARY);
+    if (ctx) {
+        if (ALLOC_BOUNDARY) {
+            bytes_to_add = ALLOC_BOUNDARY -
+                              ((ptrdiff_t)ctx & (ALLOC_BOUNDARY - 1));
+            ctx = (struct umac_ctx *)((u_char *)ctx + bytes_to_add);
+        }
+        ctx->free_ptr = octx;
+        aes_key_setup(key,prf_key);
+        pdf_init(&ctx->pdf, prf_key);
+        uhash_init(&ctx->hash, prf_key);
+    }
+        
+    return (ctx);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int umac_final(struct umac_ctx *ctx, u_char tag[], u_char nonce[8])
+/* Incorporate any pending data, pad, and generate tag */
+{
+    uhash_final(&ctx->hash, (u_char *)tag);
+    pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag);
+    
+    return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+int umac_update(struct umac_ctx *ctx, u_char *input, long len)
+/* Given len bytes of data, we parse it into L1_KEY_LEN chunks and   */
+/* hash each one, calling the PDF on the hashed output whenever the hash- */
+/* output buffer is full.                                                 */
+{
+    uhash_update(&ctx->hash, input, len);
+    return (1);
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if 0
+int umac(struct umac_ctx *ctx, u_char *input, 
+         long len, u_char tag[],
+         u_char nonce[8])
+/* All-in-one version simply calls umac_update() and umac_final().        */
+{
+    uhash(&ctx->hash, input, len, (u_char *)tag);
+    pdf_gen_xor(&ctx->pdf, (UINT8 *)nonce, (UINT8 *)tag);
+    
+    return (1);
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ----- End UMAC Section ----------------------------------------------- */
+/* ---------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------- */
diff --git a/umac.h b/umac.h
new file mode 100644 (file)
index 0000000..055c705
--- /dev/null
+++ b/umac.h
@@ -0,0 +1,123 @@
+/* $OpenBSD: umac.h,v 1.1 2007/06/07 19:37:34 pvalchev Exp $ */
+/* -----------------------------------------------------------------------
+ * 
+ * umac.h -- C Implementation UMAC Message Authentication
+ *
+ * Version 0.93a of rfc4418.txt -- 2006 July 14
+ *
+ * For a full description of UMAC message authentication see the UMAC
+ * world-wide-web page at http://www.cs.ucdavis.edu/~rogaway/umac
+ * Please report bugs and suggestions to the UMAC webpage.
+ *
+ * Copyright (c) 1999-2004 Ted Krovetz
+ *                                                                 
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and with or without fee, is hereby
+ * granted provided that the above copyright notice appears in all copies
+ * and in supporting documentation, and that the name of the copyright
+ * holder not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ * Comments should be directed to Ted Krovetz (tdk@acm.org)                                        
+ *                                                                   
+ * ---------------------------------------------------------------------- */
+ /* ////////////////////// IMPORTANT NOTES /////////////////////////////////
+  *
+  * 1) This version does not work properly on messages larger than 16MB
+  *
+  * 2) If you set the switch to use SSE2, then all data must be 16-byte
+  *    aligned
+  *
+  * 3) When calling the function umac(), it is assumed that msg is in
+  * a writable buffer of length divisible by 32 bytes. The message itself
+  * does not have to fill the entire buffer, but bytes beyond msg may be
+  * zeroed.
+  *
+  * 4) Two free AES implementations are supported by this implementation of
+  * UMAC. Paulo Barreto's version is in the public domain and can be found
+  * at http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ (search for
+  * "Barreto"). The only two files needed are rijndael-alg-fst.c and
+  * rijndael-alg-fst.h.
+  * Brian Gladman's version is distributed with GNU Public lisence
+  * and can be found at http://fp.gladman.plus.com/AES/index.htm. It
+  * includes a fast IA-32 assembly version.
+  *
+  /////////////////////////////////////////////////////////////////////// */
+#ifndef HEADER_UMAC_H
+#define HEADER_UMAC_H
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+struct umac_ctx *umac_new(u_char key[]);
+/* Dynamically allocate a umac_ctx struct, initialize variables, 
+ * generate subkeys from key.
+ */
+
+#if 0
+int umac_reset(struct umac_ctx *ctx);
+/* Reset a umac_ctx to begin authenicating a new message */
+#endif
+
+int umac_update(struct umac_ctx *ctx, u_char *input, long len);
+/* Incorporate len bytes pointed to by input into context ctx */
+
+int umac_final(struct umac_ctx *ctx, u_char tag[], u_char nonce[8]);
+/* Incorporate any pending data and the ctr value, and return tag. 
+ * This function returns error code if ctr < 0. 
+ */
+
+int umac_delete(struct umac_ctx *ctx);
+/* Deallocate the context structure */
+
+#if 0
+int umac(struct umac_ctx *ctx, u_char *input, 
+         long len, u_char tag[],
+         u_char nonce[8]);
+/* All-in-one implementation of the functions Reset, Update and Final */
+#endif
+
+/* uhash.h */
+
+
+#if 0
+typedef struct uhash_ctx *uhash_ctx_t;
+  /* The uhash_ctx structure is defined by the implementation of the    */
+  /* UHASH functions.                                                   */
+uhash_ctx_t uhash_alloc(u_char key[16]);
+  /* Dynamically allocate a uhash_ctx struct and generate subkeys using */
+  /* the kdf and kdf_key passed in. If kdf_key_len is 0 then RC6 is     */
+  /* used to generate key with a fixed key. If kdf_key_len > 0 but kdf  */
+  /* is NULL then the first 16 bytes pointed at by kdf_key is used as a */
+  /* key for an RC6 based KDF.                                          */
+  
+int uhash_free(uhash_ctx_t ctx);
+
+int uhash_set_params(uhash_ctx_t ctx,
+                   void       *params);
+
+int uhash_reset(uhash_ctx_t ctx);
+
+int uhash_update(uhash_ctx_t ctx,
+               u_char       *input,
+               long        len);
+
+int uhash_final(uhash_ctx_t ctx,
+              u_char        ouput[]);
+
+int uhash(uhash_ctx_t ctx,
+        u_char       *input,
+        long        len,
+        u_char        output[]);
+
+#endif
+
+#ifdef __cplusplus
+    }
+#endif
+
+#endif /* HEADER_UMAC_H */
diff --git a/uuencode.c b/uuencode.c
new file mode 100644 (file)
index 0000000..09d80d2
--- /dev/null
@@ -0,0 +1,94 @@
+/* $OpenBSD: uuencode.c,v 1.26 2010/08/31 11:54:45 djm 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 <sys/types.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <stdio.h>
+
+#include "xmalloc.h"
+#include "uuencode.h"
+
+/*
+ * Encode binary 'src' of length 'srclength', writing base64-encoded text
+ * to 'target' of size 'targsize'. Will always nul-terminate 'target'.
+ * Returns the number of bytes stored in 'target' or -1 on error (inc.
+ * 'targsize' too small).
+ */
+int
+uuencode(const u_char *src, u_int srclength,
+    char *target, size_t targsize)
+{
+       return __b64_ntop(src, srclength, target, targsize);
+}
+
+/*
+ * Decode base64-encoded 'src' into buffer 'target' of 'targsize' bytes.
+ * Will skip leading and trailing whitespace. Returns the number of bytes
+ * stored in 'target' or -1 on error (inc. targsize too small).
+ */
+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 remove trailing whitespace because __b64_pton needs this */
+       *p = '\0';
+       len = __b64_pton(encoded, target, targsize);
+       xfree(encoded);
+       return len;
+}
+
+void
+dump_base64(FILE *fp, const u_char *data, u_int len)
+{
+       char *buf;
+       int i, n;
+
+       if (len > 65536) {
+               fprintf(fp, "dump_base64: len > 65536\n");
+               return;
+       }
+       buf = xmalloc(2*len);
+       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/uuencode.h b/uuencode.h
new file mode 100644 (file)
index 0000000..4d98881
--- /dev/null
@@ -0,0 +1,29 @@
+/* $OpenBSD: uuencode.h,v 1.14 2010/08/31 11:54:45 djm 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.
+ */
+
+int     uuencode(const u_char *, u_int, char *, size_t);
+int     uudecode(const char *, u_char *, size_t);
+void    dump_base64(FILE *, const u_char *, u_int);
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..bf1c712
--- /dev/null
+++ b/version.h
@@ -0,0 +1,6 @@
+/* $OpenBSD: version.h,v 1.61 2011/02/04 00:44:43 djm Exp $ */
+
+#define SSH_VERSION    "OpenSSH_5.8"
+
+#define SSH_PORTABLE   "p1"
+#define SSH_RELEASE    SSH_VERSION SSH_PORTABLE
diff --git a/xmalloc.c b/xmalloc.c
new file mode 100644 (file)
index 0000000..9985b4c
--- /dev/null
+++ b/xmalloc.c
@@ -0,0 +1,110 @@
+/* $OpenBSD: xmalloc.c,v 1.27 2006/08/03 03:34:42 deraadt Exp $ */
+/*
+ * 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"
+
+#include <sys/param.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 *
+xcalloc(size_t nmemb, size_t size)
+{
+       void *ptr;
+
+       if (size == 0 || nmemb == 0)
+               fatal("xcalloc: zero size");
+       if (SIZE_T_MAX / nmemb < size)
+               fatal("xcalloc: nmemb * size > SIZE_T_MAX");
+       ptr = calloc(nmemb, size);
+       if (ptr == NULL)
+               fatal("xcalloc: out of memory (allocating %lu bytes)",
+                   (u_long)(size * nmemb));
+       return ptr;
+}
+
+void *
+xrealloc(void *ptr, size_t nmemb, size_t size)
+{
+       void *new_ptr;
+       size_t new_size = nmemb * size;
+
+       if (new_size == 0)
+               fatal("xrealloc: zero size");
+       if (SIZE_T_MAX / nmemb < size)
+               fatal("xrealloc: nmemb * size > SIZE_T_MAX");
+       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;
+}
+
+int
+xasprintf(char **ret, const char *fmt, ...)
+{
+       va_list ap;
+       int i;
+
+       va_start(ap, fmt);
+       i = vasprintf(ret, fmt, ap);
+       va_end(ap);
+
+       if (i < 0 || *ret == NULL)
+               fatal("xasprintf: could not allocate memory");
+
+       return (i);
+}
diff --git a/xmalloc.h b/xmalloc.h
new file mode 100644 (file)
index 0000000..fb217a4
--- /dev/null
+++ b/xmalloc.h
@@ -0,0 +1,26 @@
+/* $OpenBSD: xmalloc.h,v 1.13 2006/08/03 03:34:42 deraadt Exp $ */
+
+/*
+ * 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".
+ */
+
+void   *xmalloc(size_t);
+void   *xcalloc(size_t, size_t);
+void   *xrealloc(void *, size_t, size_t);
+void     xfree(void *);
+char   *xstrdup(const char *);
+int     xasprintf(char **, const char *, ...)
+                __attribute__((__format__ (printf, 2, 3)))
+                __attribute__((__nonnull__ (2)));