summaryrefslogtreecommitdiffstats
path: root/crypto/openssh
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh')
-rw-r--r--crypto/openssh/CREDITS105
-rw-r--r--crypto/openssh/ChangeLog1648
-rw-r--r--crypto/openssh/FREEBSD-tricks14
-rw-r--r--crypto/openssh/FREEBSD-upgrade124
-rw-r--r--crypto/openssh/FREEBSD-vendor6
-rw-r--r--crypto/openssh/INSTALL269
-rw-r--r--crypto/openssh/LICENCE338
-rw-r--r--crypto/openssh/OVERVIEW168
-rw-r--r--crypto/openssh/PROTOCOL254
-rw-r--r--crypto/openssh/PROTOCOL.agent516
-rw-r--r--crypto/openssh/README65
-rw-r--r--crypto/openssh/README.dns47
-rw-r--r--crypto/openssh/README.platform96
-rw-r--r--crypto/openssh/README.privsep63
-rw-r--r--crypto/openssh/README.smartcard93
-rw-r--r--crypto/openssh/README.tun132
-rw-r--r--crypto/openssh/TODO86
-rw-r--r--crypto/openssh/WARNING.RNG95
-rw-r--r--crypto/openssh/aclocal.m486
-rw-r--r--crypto/openssh/acss.c267
-rw-r--r--crypto/openssh/acss.h47
-rw-r--r--crypto/openssh/addrmatch.c424
-rw-r--r--crypto/openssh/atomicio.c142
-rw-r--r--crypto/openssh/atomicio.h45
-rw-r--r--crypto/openssh/audit-bsm.c380
-rw-r--r--crypto/openssh/audit.c186
-rw-r--r--crypto/openssh/audit.h54
-rw-r--r--crypto/openssh/auth-bsdauth.c138
-rw-r--r--crypto/openssh/auth-chall.c123
-rw-r--r--crypto/openssh/auth-krb5.c249
-rw-r--r--crypto/openssh/auth-options.c376
-rw-r--r--crypto/openssh/auth-options.h37
-rw-r--r--crypto/openssh/auth-pam.c1221
-rw-r--r--crypto/openssh/auth-pam.h50
-rw-r--r--crypto/openssh/auth-passwd.c214
-rw-r--r--crypto/openssh/auth-rh-rsa.c100
-rw-r--r--crypto/openssh/auth-rhosts.c327
-rw-r--r--crypto/openssh/auth-rsa.c324
-rw-r--r--crypto/openssh/auth-shadow.c142
-rw-r--r--crypto/openssh/auth-sia.c114
-rw-r--r--crypto/openssh/auth-sia.h31
-rw-r--r--crypto/openssh/auth-skey.c107
-rw-r--r--crypto/openssh/auth.c623
-rw-r--r--crypto/openssh/auth.h202
-rw-r--r--crypto/openssh/auth1.c437
-rw-r--r--crypto/openssh/auth2-chall.c374
-rw-r--r--crypto/openssh/auth2-gss.c301
-rw-r--r--crypto/openssh/auth2-hostbased.c192
-rw-r--r--crypto/openssh/auth2-jpake.c558
-rw-r--r--crypto/openssh/auth2-kbdint.c68
-rw-r--r--crypto/openssh/auth2-none.c73
-rw-r--r--crypto/openssh/auth2-passwd.c80
-rw-r--r--crypto/openssh/auth2-pubkey.c274
-rw-r--r--crypto/openssh/auth2.c437
-rw-r--r--crypto/openssh/authfd.c671
-rw-r--r--crypto/openssh/authfd.h95
-rw-r--r--crypto/openssh/authfile.c679
-rw-r--r--crypto/openssh/authfile.h26
-rw-r--r--crypto/openssh/bufaux.c265
-rw-r--r--crypto/openssh/bufbn.c223
-rw-r--r--crypto/openssh/buffer.c252
-rw-r--r--crypto/openssh/buffer.h86
-rw-r--r--crypto/openssh/canohost.c426
-rw-r--r--crypto/openssh/canohost.h29
-rw-r--r--crypto/openssh/channels.c3461
-rw-r--r--crypto/openssh/channels.h280
-rw-r--r--crypto/openssh/cipher-3des1.c182
-rw-r--r--crypto/openssh/cipher-acss.c85
-rw-r--r--crypto/openssh/cipher-aes.c164
-rw-r--r--crypto/openssh/cipher-bf1.c106
-rw-r--r--crypto/openssh/cipher-ctr.c146
-rw-r--r--crypto/openssh/cipher.c431
-rw-r--r--crypto/openssh/cipher.h92
-rw-r--r--crypto/openssh/cleanup.c32
-rw-r--r--crypto/openssh/clientloop.c2058
-rw-r--r--crypto/openssh/clientloop.h73
-rw-r--r--crypto/openssh/compat.c237
-rw-r--r--crypto/openssh/compat.h71
-rw-r--r--crypto/openssh/compress.c166
-rw-r--r--crypto/openssh/compress.h25
-rwxr-xr-xcrypto/openssh/config.guess1526
-rw-r--r--crypto/openssh/config.h1452
-rw-r--r--crypto/openssh/config.h.in1458
-rw-r--r--crypto/openssh/crc32.c105
-rw-r--r--crypto/openssh/crc32.h30
-rw-r--r--crypto/openssh/deattack.c160
-rw-r--r--crypto/openssh/deattack.h31
-rw-r--r--crypto/openssh/defines.h756
-rw-r--r--crypto/openssh/dh.c346
-rw-r--r--crypto/openssh/dh.h73
-rw-r--r--crypto/openssh/dispatch.c104
-rw-r--r--crypto/openssh/dispatch.h41
-rw-r--r--crypto/openssh/dns.c305
-rw-r--r--crypto/openssh/dns.h52
-rw-r--r--crypto/openssh/entropy.c194
-rw-r--r--crypto/openssh/entropy.h38
-rw-r--r--crypto/openssh/fatal.c45
-rwxr-xr-xcrypto/openssh/fixpaths22
-rwxr-xr-xcrypto/openssh/fixprogs72
-rw-r--r--crypto/openssh/groupaccess.c129
-rw-r--r--crypto/openssh/groupaccess.h35
-rw-r--r--crypto/openssh/gss-genr.c281
-rw-r--r--crypto/openssh/gss-serv-krb5.c199
-rw-r--r--crypto/openssh/gss-serv.c365
-rw-r--r--crypto/openssh/hostfile.c353
-rw-r--r--crypto/openssh/hostfile.h33
-rw-r--r--crypto/openssh/includes.h175
-rw-r--r--crypto/openssh/jpake.c449
-rw-r--r--crypto/openssh/jpake.h114
-rw-r--r--crypto/openssh/kex.c567
-rw-r--r--crypto/openssh/kex.h161
-rw-r--r--crypto/openssh/kexdh.c88
-rw-r--r--crypto/openssh/kexdhc.c159
-rw-r--r--crypto/openssh/kexdhs.c161
-rw-r--r--crypto/openssh/kexgex.c98
-rw-r--r--crypto/openssh/kexgexc.c205
-rw-r--r--crypto/openssh/kexgexs.c205
-rw-r--r--crypto/openssh/key.c982
-rw-r--r--crypto/openssh/key.h88
-rw-r--r--crypto/openssh/log.c401
-rw-r--r--crypto/openssh/log.h69
-rw-r--r--crypto/openssh/loginrec.c1688
-rw-r--r--crypto/openssh/loginrec.h131
-rw-r--r--crypto/openssh/logintest.c308
-rw-r--r--crypto/openssh/mac.c188
-rw-r--r--crypto/openssh/mac.h30
-rw-r--r--crypto/openssh/match.c278
-rw-r--r--crypto/openssh/match.h27
-rw-r--r--crypto/openssh/md-sha256.c86
-rw-r--r--crypto/openssh/md5crypt.c167
-rw-r--r--crypto/openssh/md5crypt.h24
-rw-r--r--crypto/openssh/misc.c851
-rw-r--r--crypto/openssh/misc.h93
-rwxr-xr-xcrypto/openssh/mkinstalldirs40
-rw-r--r--crypto/openssh/moduli188
-rw-r--r--crypto/openssh/moduli.5124
-rw-r--r--crypto/openssh/moduli.c650
-rw-r--r--crypto/openssh/monitor.c2211
-rw-r--r--crypto/openssh/monitor.h97
-rw-r--r--crypto/openssh/monitor_fdpass.c169
-rw-r--r--crypto/openssh/monitor_fdpass.h34
-rw-r--r--crypto/openssh/monitor_mm.c352
-rw-r--r--crypto/openssh/monitor_mm.h62
-rw-r--r--crypto/openssh/monitor_wrap.c1430
-rw-r--r--crypto/openssh/monitor_wrap.h130
-rw-r--r--crypto/openssh/msg.c89
-rw-r--r--crypto/openssh/msg.h31
-rw-r--r--crypto/openssh/mux.c728
-rw-r--r--crypto/openssh/myproposal.h69
-rw-r--r--crypto/openssh/nchan.c522
-rw-r--r--crypto/openssh/openbsd-compat/base64.c315
-rw-r--r--crypto/openssh/openbsd-compat/base64.h65
-rw-r--r--crypto/openssh/openbsd-compat/basename.c67
-rw-r--r--crypto/openssh/openbsd-compat/bindresvport.c118
-rw-r--r--crypto/openssh/openbsd-compat/bsd-arc4random.c150
-rw-r--r--crypto/openssh/openbsd-compat/bsd-asprintf.c101
-rw-r--r--crypto/openssh/openbsd-compat/bsd-closefrom.c109
-rw-r--r--crypto/openssh/openbsd-compat/bsd-cray.c817
-rw-r--r--crypto/openssh/openbsd-compat/bsd-cray.h61
-rw-r--r--crypto/openssh/openbsd-compat/bsd-cygwin_util.c131
-rw-r--r--crypto/openssh/openbsd-compat/bsd-cygwin_util.h54
-rw-r--r--crypto/openssh/openbsd-compat/bsd-getpeereid.c73
-rw-r--r--crypto/openssh/openbsd-compat/bsd-misc.c242
-rw-r--r--crypto/openssh/openbsd-compat/bsd-misc.h98
-rw-r--r--crypto/openssh/openbsd-compat/bsd-nextstep.c103
-rw-r--r--crypto/openssh/openbsd-compat/bsd-nextstep.h59
-rw-r--r--crypto/openssh/openbsd-compat/bsd-openpty.c220
-rw-r--r--crypto/openssh/openbsd-compat/bsd-poll.c119
-rw-r--r--crypto/openssh/openbsd-compat/bsd-poll.h61
-rw-r--r--crypto/openssh/openbsd-compat/bsd-snprintf.c850
-rw-r--r--crypto/openssh/openbsd-compat/bsd-statvfs.c37
-rw-r--r--crypto/openssh/openbsd-compat/bsd-statvfs.h68
-rw-r--r--crypto/openssh/openbsd-compat/bsd-waitpid.c53
-rw-r--r--crypto/openssh/openbsd-compat/bsd-waitpid.h51
-rw-r--r--crypto/openssh/openbsd-compat/daemon.c82
-rw-r--r--crypto/openssh/openbsd-compat/dirname.c72
-rw-r--r--crypto/openssh/openbsd-compat/fake-rfc2553.c235
-rw-r--r--crypto/openssh/openbsd-compat/fake-rfc2553.h175
-rw-r--r--crypto/openssh/openbsd-compat/fmt_scaled.c274
-rw-r--r--crypto/openssh/openbsd-compat/getcwd.c240
-rw-r--r--crypto/openssh/openbsd-compat/getgrouplist.c95
-rw-r--r--crypto/openssh/openbsd-compat/getopt.c123
-rw-r--r--crypto/openssh/openbsd-compat/getrrsetbyname.c610
-rw-r--r--crypto/openssh/openbsd-compat/getrrsetbyname.h110
-rw-r--r--crypto/openssh/openbsd-compat/glob.c874
-rw-r--r--crypto/openssh/openbsd-compat/glob.h100
-rw-r--r--crypto/openssh/openbsd-compat/inet_aton.c179
-rw-r--r--crypto/openssh/openbsd-compat/inet_ntoa.c59
-rw-r--r--crypto/openssh/openbsd-compat/inet_ntop.c211
-rw-r--r--crypto/openssh/openbsd-compat/mktemp.c178
-rw-r--r--crypto/openssh/openbsd-compat/openbsd-compat.h221
-rw-r--r--crypto/openssh/openbsd-compat/openssl-compat.c71
-rw-r--r--crypto/openssh/openbsd-compat/openssl-compat.h99
-rw-r--r--crypto/openssh/openbsd-compat/port-aix.c449
-rw-r--r--crypto/openssh/openbsd-compat/port-aix.h123
-rw-r--r--crypto/openssh/openbsd-compat/port-irix.c90
-rw-r--r--crypto/openssh/openbsd-compat/port-irix.h39
-rw-r--r--crypto/openssh/openbsd-compat/port-linux.c171
-rw-r--r--crypto/openssh/openbsd-compat/port-linux.h28
-rw-r--r--crypto/openssh/openbsd-compat/port-solaris.c199
-rw-r--r--crypto/openssh/openbsd-compat/port-solaris.h27
-rw-r--r--crypto/openssh/openbsd-compat/port-tun.c271
-rw-r--r--crypto/openssh/openbsd-compat/port-tun.h33
-rw-r--r--crypto/openssh/openbsd-compat/port-uw.c149
-rw-r--r--crypto/openssh/openbsd-compat/port-uw.h30
-rw-r--r--crypto/openssh/openbsd-compat/readpassphrase.c191
-rw-r--r--crypto/openssh/openbsd-compat/readpassphrase.h44
-rw-r--r--crypto/openssh/openbsd-compat/realpath.c197
-rw-r--r--crypto/openssh/openbsd-compat/rresvport.c108
-rw-r--r--crypto/openssh/openbsd-compat/setenv.c145
-rw-r--r--crypto/openssh/openbsd-compat/setproctitle.c164
-rwxr-xr-xcrypto/openssh/openbsd-compat/sha2.c882
-rwxr-xr-xcrypto/openssh/openbsd-compat/sha2.h133
-rw-r--r--crypto/openssh/openbsd-compat/sigact.c132
-rw-r--r--crypto/openssh/openbsd-compat/sigact.h90
-rw-r--r--crypto/openssh/openbsd-compat/strlcat.c62
-rw-r--r--crypto/openssh/openbsd-compat/strlcpy.c58
-rw-r--r--crypto/openssh/openbsd-compat/strmode.c148
-rw-r--r--crypto/openssh/openbsd-compat/strsep.c79
-rw-r--r--crypto/openssh/openbsd-compat/strtoll.c148
-rw-r--r--crypto/openssh/openbsd-compat/strtonum.c72
-rw-r--r--crypto/openssh/openbsd-compat/strtoul.c108
-rw-r--r--crypto/openssh/openbsd-compat/sys-queue.h612
-rw-r--r--crypto/openssh/openbsd-compat/sys-tree.h679
-rw-r--r--crypto/openssh/openbsd-compat/vis.c225
-rw-r--r--crypto/openssh/openbsd-compat/vis.h95
-rw-r--r--crypto/openssh/openbsd-compat/xcrypt.c117
-rw-r--r--crypto/openssh/openbsd-compat/xmmap.c88
-rw-r--r--crypto/openssh/packet.c1939
-rw-r--r--crypto/openssh/packet.h118
-rw-r--r--crypto/openssh/pathnames.h174
-rw-r--r--crypto/openssh/platform.c46
-rw-r--r--crypto/openssh/platform.h23
-rw-r--r--crypto/openssh/progressmeter.c305
-rw-r--r--crypto/openssh/progressmeter.h27
-rw-r--r--crypto/openssh/readconf.c1342
-rw-r--r--crypto/openssh/readconf.h147
-rw-r--r--crypto/openssh/readpass.c188
-rw-r--r--crypto/openssh/rijndael.c1244
-rw-r--r--crypto/openssh/rijndael.h51
-rw-r--r--crypto/openssh/roaming.h38
-rw-r--r--crypto/openssh/roaming_common.c201
-rw-r--r--crypto/openssh/roaming_dummy.c61
-rw-r--r--crypto/openssh/rsa.c151
-rw-r--r--crypto/openssh/rsa.h26
-rw-r--r--crypto/openssh/scard-opensc.c532
-rw-r--r--crypto/openssh/scard.c571
-rw-r--r--crypto/openssh/scard.h39
-rw-r--r--crypto/openssh/schnorr.c653
-rw-r--r--crypto/openssh/schnorr.h60
-rw-r--r--crypto/openssh/scp.1231
-rw-r--r--crypto/openssh/scp.c1287
-rw-r--r--crypto/openssh/servconf.c1669
-rw-r--r--crypto/openssh/servconf.h168
-rw-r--r--crypto/openssh/serverloop.c1254
-rw-r--r--crypto/openssh/serverloop.h27
-rw-r--r--crypto/openssh/session.c2781
-rw-r--r--crypto/openssh/session.h83
-rw-r--r--crypto/openssh/sftp-client.c1315
-rw-r--r--crypto/openssh/sftp-client.h114
-rw-r--r--crypto/openssh/sftp-common.c223
-rw-r--r--crypto/openssh/sftp-common.h51
-rw-r--r--crypto/openssh/sftp-glob.c149
-rw-r--r--crypto/openssh/sftp-server-main.c51
-rw-r--r--crypto/openssh/sftp-server.8104
-rw-r--r--crypto/openssh/sftp-server.c1467
-rw-r--r--crypto/openssh/sftp.1472
-rw-r--r--crypto/openssh/sftp.c1843
-rw-r--r--crypto/openssh/sftp.h101
-rw-r--r--crypto/openssh/ssh-add.1186
-rw-r--r--crypto/openssh/ssh-add.c439
-rw-r--r--crypto/openssh/ssh-agent.1208
-rw-r--r--crypto/openssh/ssh-agent.c1292
-rw-r--r--crypto/openssh/ssh-dss.c185
-rw-r--r--crypto/openssh/ssh-gss.h131
-rw-r--r--crypto/openssh/ssh-keygen.1470
-rw-r--r--crypto/openssh/ssh-keygen.c1483
-rw-r--r--crypto/openssh/ssh-keyscan.1169
-rw-r--r--crypto/openssh/ssh-keyscan.c851
-rw-r--r--crypto/openssh/ssh-keysign.882
-rw-r--r--crypto/openssh/ssh-keysign.c254
-rw-r--r--crypto/openssh/ssh-rand-helper.894
-rw-r--r--crypto/openssh/ssh-rand-helper.c925
-rw-r--r--crypto/openssh/ssh-rsa.c263
-rw-r--r--crypto/openssh/ssh.11481
-rw-r--r--crypto/openssh/ssh.c1305
-rw-r--r--crypto/openssh/ssh.h102
-rw-r--r--crypto/openssh/ssh1.h92
-rw-r--r--crypto/openssh/ssh2.h168
-rw-r--r--crypto/openssh/ssh_config48
-rw-r--r--crypto/openssh/ssh_config.51156
-rw-r--r--crypto/openssh/ssh_namespace.h418
-rw-r--r--crypto/openssh/sshconnect.c1189
-rw-r--r--crypto/openssh/sshconnect.h71
-rw-r--r--crypto/openssh/sshconnect1.c753
-rw-r--r--crypto/openssh/sshconnect2.c1828
-rw-r--r--crypto/openssh/sshd.8905
-rw-r--r--crypto/openssh/sshd.c2273
-rw-r--r--crypto/openssh/sshd_config126
-rw-r--r--crypto/openssh/sshd_config.51092
-rw-r--r--crypto/openssh/sshlogin.c163
-rw-r--r--crypto/openssh/sshlogin.h23
-rw-r--r--crypto/openssh/sshpty.c258
-rw-r--r--crypto/openssh/sshpty.h27
-rw-r--r--crypto/openssh/sshtty.c93
-rw-r--r--crypto/openssh/ttymodes.c490
-rw-r--r--crypto/openssh/ttymodes.h175
-rw-r--r--crypto/openssh/uidswap.c288
-rw-r--r--crypto/openssh/uidswap.h18
-rw-r--r--crypto/openssh/umac.c1277
-rw-r--r--crypto/openssh/umac.h123
-rw-r--r--crypto/openssh/uuencode.c94
-rw-r--r--crypto/openssh/uuencode.h29
-rw-r--r--crypto/openssh/version.c62
-rw-r--r--crypto/openssh/version.h13
-rw-r--r--crypto/openssh/xmalloc.c110
-rw-r--r--crypto/openssh/xmalloc.h26
317 files changed, 105057 insertions, 0 deletions
diff --git a/crypto/openssh/CREDITS b/crypto/openssh/CREDITS
new file mode 100644
index 0000000..eaf105a
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/ChangeLog b/crypto/openssh/ChangeLog
new file mode 100644
index 0000000..b2df660
--- /dev/null
+++ b/crypto/openssh/ChangeLog
@@ -0,0 +1,1648 @@
+20090926
+ - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+ [contrib/suse/openssh.spec] Update for release
+ - (djm) [README] update relnotes URL
+ - (djm) [packet.c] Restore EWOULDBLOCK handling that got lost somewhere
+ - (djm) Release 5.3p1
+
+20090911
+ - (dtucker) [configure.ac] Change the -lresolv check so it works on Mac OS X
+ 10.6 (which doesn't have BIND8_COMPAT and thus uses res_9_query). Patch
+ from jbasney at ncsa uiuc edu.
+
+20090908
+ - (djm) [serverloop.c] Fix test for server-assigned remote forwarding port
+ (-R 0:...); bz#1578, spotted and fix by gavin AT emf.net; ok dtucker@
+
+20090901
+ - (dtucker) [configure.ac] Bug #1639: use AC_PATH_PROG to search the path for
+ krb5-config if it's not in the location specified by --with-kerberos5.
+ Patch from jchadima at redhat.
+
+20090829
+ - (dtucker) [README.platform] Add text about development packages, based on
+ text from Chris Pepper in bug #1631.
+
+20090828
+ - dtucker [auth-sia.c] Roll back the change for bug #1241 as it apparently
+ causes problems in some Tru64 configurations.
+ - (djm) [sshd_config.5] downgrade mention of login.conf to be an example
+ and mention PAM as another provider for ChallengeResponseAuthentication;
+ bz#1408; ok dtucker@
+ - (djm) [sftp-server.c] bz#1535: accept ENOSYS as a fallback error when
+ attempting atomic rename(); ok dtucker@
+ - (djm) [Makefile.in] bz#1505: Solaris make(1) doesn't accept make variables
+ in argv, so pass them in the environment; ok dtucker@
+ - (dtucker) [channels.c configure.ac] Bug #1528: skip the tcgetattr call on
+ the pty master on Solaris, since it never succeeds and can hang if large
+ amounts of data is sent to the slave (eg a copy-paste). Based on a patch
+ originally from Doke Scott, ok djm@
+ - (dtucker) [clientloop.c configure.ac defines.h] Make the client's IO buffer
+ size a compile-time option and set it to 64k on Cygwin, since Corinna
+ reports that it makes a significant difference to performance. ok djm@
+ - (dtucker) [configure.ac] Fix the syntax of the Solaris tcgetattr entry.
+
+20090820
+ - (dtucker) [includes.h] Bug #1634: do not include system glob.h if we're not
+ using it since the type conflicts can cause problems on FreeBSD. Patch
+ from Jonathan Chen.
+ - (dtucker) [session.c openbsd-compat/port-aix.h] Bugs #1249 and #1567: move
+ the setpcred call on AIX to immediately before the permanently_set_uid().
+ Ensures that we still have privileges when we call chroot and
+ pam_open_sesson. Based on a patch from David Leonard.
+
+20090817
+ - (dtucker) [configure.ac] Check for headers before libraries for openssl an
+ zlib, which should make the errors slightly more meaningful on platforms
+ where there's separate "-devel" packages for those.
+ - (dtucker) [sshlogin.c openbsd-compat/port-aix.{c,h}] Bug #1595: make
+ PrintLastLog work on AIX. Based in part on a patch from Miguel Sanders.
+
+20090729
+ - (tim) [contrib/cygwin/ssh-user-config] Change script to call correct error
+ function. Patch from Corinna Vinschen.
+
+20090713
+ - (dtucker) [openbsd-compat/getrrsetbyname.c] Reduce answer buffer size so it
+ fits into 16 bits to work around a bug in glibc's resolver where it masks
+ off the buffer size at 16 bits. Patch from Hauke Lampe, ok djm jakob.
+
+20090712
+ - (dtucker) [configure.ac] Include sys/param.h for the sys/mount.h test,
+ prevents configure complaining on older BSDs.
+ - (dtucker [contrib/cygwin/ssh-{host,user}-config] Add license text. Patch
+ from Corinna Vinschen.
+ - (dtucker) [auth-pam.c] Bug #1534: move the deletion of PAM credentials on
+ logout to after the session close. Patch from Anicka Bernathova,
+ originally from Andreas Schwab via Novelll ok djm.
+
+20090707
+ - (dtucker) [contrib/cygwin/ssh-host-config] better support for automated
+ scripts and fix usage of eval. Patch from Corinna Vinschen.
+
+20090705
+ - (dtucker) OpenBSD CVS Sync
+ - andreas@cvs.openbsd.org 2009/06/27 09:29:06
+ [packet.h packet.c]
+ packet_bacup_state() and packet_restore_state() will be used to
+ temporarily save the current state ren resuming a suspended connection.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/06/27 09:32:43
+ [roaming_common.c roaming.h]
+ It may be necessary to retransmit some data when resuming, so add it
+ to a buffer when roaming is enabled.
+ Most of this code was written by Martin Forssen, maf at appgate dot com.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/06/27 09:35:06
+ [readconf.h readconf.c]
+ Add client option UseRoaming. It doesn't do anything yet but will
+ control whether the client tries to use roaming if enabled on the
+ server. From Martin Forssen.
+ ok markus@
+ - markus@cvs.openbsd.org 2009/06/30 14:54:40
+ [version.h]
+ crank version; ok deraadt
+ - dtucker@cvs.openbsd.org 2009/07/02 02:11:47
+ [ssh.c]
+ allow for long home dir paths (bz #1615). ok deraadt
+ (based in part on a patch from jchadima at redhat)
+ - stevesk@cvs.openbsd.org 2009/07/05 19:28:33
+ [clientloop.c]
+ only send SSH2_MSG_DISCONNECT if we're in compat20; from dtucker@
+ ok deraadt@ markus@
+
+20090622
+ - (dtucker) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2009/06/22 05:39:28
+ [monitor_wrap.c monitor_mm.c ssh-keygen.c auth2.c gss-genr.c sftp-client.c]
+ alphabetize includes; reduces diff vs portable and style(9).
+ ok stevesk djm
+ (Id sync only; these were already in order in -portable)
+
+20090621
+ - (dtucker) OpenBSD CVS Sync
+ - markus@cvs.openbsd.org 2009/03/17 21:37:00
+ [ssh.c]
+ pass correct argv[0] to openlog(); ok djm@
+ - jmc@cvs.openbsd.org 2009/03/19 15:15:09
+ [ssh.1]
+ for "Ciphers", just point the reader to the keyword in ssh_config(5), just
+ as we do for "MACs": this stops us getting out of sync when the lists
+ change;
+ fixes documentation/6102, submitted by Peter J. Philipp
+ alternative fix proposed by djm
+ ok markus
+ - tobias@cvs.openbsd.org 2009/03/23 08:31:19
+ [ssh-agent.c]
+ Fixed a possible out-of-bounds memory access if the environment variable
+ SHELL is shorter than 3 characters.
+ with input by and ok dtucker
+ - tobias@cvs.openbsd.org 2009/03/23 19:38:04
+ [ssh-agent.c]
+ My previous commit didn't fix the problem at all, so stick at my first
+ version of the fix presented to dtucker.
+ Issue notified by Matthias Barkhoff (matthias dot barkhoff at gmx dot de).
+ ok dtucker
+ - sobrado@cvs.openbsd.org 2009/03/26 08:38:39
+ [sftp-server.8 sshd.8 ssh-agent.1]
+ fix a few typographical errors found by spell(1).
+ ok dtucker@, jmc@
+ - stevesk@cvs.openbsd.org 2009/04/13 19:07:44
+ [sshd_config.5]
+ fix possessive; ok djm@
+ - stevesk@cvs.openbsd.org 2009/04/14 16:33:42
+ [sftp-server.c]
+ remove unused option character from getopt() optstring; ok markus@
+ - jj@cvs.openbsd.org 2009/04/14 21:10:54
+ [servconf.c]
+ Fixed a few the-the misspellings in comments. Skipped a bunch in
+ binutils,gcc and so on. ok jmc@
+ - stevesk@cvs.openbsd.org 2009/04/17 19:23:06
+ [session.c]
+ use INTERNAL_SFTP_NAME for setproctitle() of in-process sftp-server;
+ ok djm@ markus@
+ - stevesk@cvs.openbsd.org 2009/04/17 19:40:17
+ [sshd_config.5]
+ clarify that even internal-sftp needs /dev/log for logging to work; ok
+ markus@
+ - jmc@cvs.openbsd.org 2009/04/18 18:39:10
+ [sshd_config.5]
+ tweak previous; ok stevesk
+ - stevesk@cvs.openbsd.org 2009/04/21 15:13:17
+ [sshd_config.5]
+ clarify we cd to user's home after chroot; ok markus@ on
+ earlier version; tweaks and ok jmc@
+ - andreas@cvs.openbsd.org 2009/05/25 06:48:01
+ [channels.c packet.c clientloop.c packet.h serverloop.c monitor_wrap.c
+ monitor.c]
+ Put the globals in packet.c into a struct and don't access it directly
+ from other files. No functional changes.
+ ok markus@ djm@
+ - andreas@cvs.openbsd.org 2009/05/27 06:31:25
+ [canohost.h canohost.c]
+ Add clear_cached_addr(), needed for upcoming changes allowing the peer
+ address to change.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/05/27 06:33:39
+ [clientloop.c]
+ Send SSH2_MSG_DISCONNECT when the client disconnects. From a larger
+ change from Martin Forssen, maf at appgate dot com.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/05/27 06:34:36
+ [kex.c kex.h]
+ Move the KEX_COOKIE_LEN define to kex.h
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/05/27 06:36:07
+ [packet.h packet.c]
+ Add packet_put_int64() and packet_get_int64(), part of a larger change
+ from Martin Forssen.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/05/27 06:38:16
+ [sshconnect.h sshconnect.c]
+ Un-static ssh_exchange_identification(), part of a larger change from
+ Martin Forssen and needed for upcoming changes.
+ ok markus@
+ - andreas@cvs.openbsd.org 2009/05/28 16:50:16
+ [sshd.c packet.c serverloop.c monitor_wrap.c clientloop.c sshconnect.c
+ monitor.c Added roaming.h roaming_common.c roaming_dummy.c]
+ Keep track of number of bytes read and written. Needed for upcoming
+ changes. Most code from Martin Forssen, maf at appgate dot com.
+ ok markus@
+ Also, applied appropriate changes to Makefile.in
+ - andreas@cvs.openbsd.org 2009/06/12 20:43:22
+ [monitor.c packet.c]
+ Fix warnings found by chl@ and djm@ and change roaming_atomicio's
+ return type to match atomicio's
+ Diff from djm@, ok markus@
+ - andreas@cvs.openbsd.org 2009/06/12 20:58:32
+ [packet.c]
+ Move some more statics into session_state
+ ok markus@ djm@
+ - dtucker@cvs.openbsd.org 2009/06/21 07:37:15
+ [kexdhs.c kexgexs.c]
+ abort if key_sign fails, preventing possible null deref. Based on report
+ from Paolo Ganci, ok markus@ djm@
+ - dtucker@cvs.openbsd.org 2009/06/21 09:04:03
+ [roaming.h roaming_common.c roaming_dummy.c]
+ Add tags for the benefit of the sync scripts
+ Also: pull in the changes for 1.1->1.2 missed in the previous sync.
+ - (dtucker) [auth2-jpake.c auth2.c canohost.h session.c] Whitespace and
+ header-order changes to reduce diff vs OpenBSD.
+ - (dtucker) [servconf.c sshd.c] More whitespace sync.
+ - (dtucker) [roaming_common.c roaming_dummy.c] Wrap #include <inttypes.h> in
+ ifdef.
+
+20090616
+ - (dtucker) [configure.ac defines.h] Bug #1607: handle the case where fsid_t
+ is a struct with a __val member. Fixes build on, eg, Redhat 6.2.
+
+20090504
+ - (dtucker) [sshlogin.c] Move the NO_SSH_LASTLOG #ifndef line to include
+ variable declarations. Should prevent unused warnings anywhere it's set
+ (only Crays as far as I can tell) and be a no-op everywhere else.
+
+20090318
+ - (tim) [configure.ac] Remove setting IP_TOS_IS_BROKEN for Cygwin. The problem
+ that setsockopt(IP_TOS) doesn't work on Cygwin has been fixed since 2005.
+ Based on patch from vinschen at redhat com.
+
+20090308
+ - (dtucker) [auth-passwd.c auth1.c auth2-kbdint.c auth2-none.c auth2-passwd.c
+ auth2-pubkey.c session.c openbsd-compat/bsd-cygwin_util.{c,h}
+ openbsd-compat/daemon.c] Remove support for Windows 95/98/ME and very old
+ version of Cygwin. Patch from vinschen at redhat com.
+
+20090307
+ - (dtucker) [contrib/aix/buildbff.sh] Only try to rename ssh_prng_cmds if it
+ exists (it's not created if OpenSSL's PRNG is self-seeded, eg if the OS
+ has a /dev/random).
+ - (dtucker) [schnorr.c openbsd-compat/openssl-compat.{c,h}] Add
+ EVP_DigestUpdate to the OLD_EVP compatibility functions and tell schnorr.c
+ to use them. Allows building with older OpenSSL versions.
+ - (dtucker) [configure.ac defines.h] Check for in_port_t and typedef if needed.
+ - (dtucker) [configure.ac] Missing comma in type list.
+ - (dtucker) [configure.ac openbsd-compat/openssl-compat.{c,h}]
+ EVP_DigestUpdate does not exactly match the other OLD_EVP functions (eg
+ in openssl 0.9.6) so add an explicit test for it.
+
+20090306
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2009/03/05 07:18:19
+ [auth2-jpake.c jpake.c jpake.h monitor_wrap.c monitor_wrap.h schnorr.c]
+ [sshconnect2.c]
+ refactor the (disabled) Schnorr proof code to make it a little more
+ generally useful
+ - djm@cvs.openbsd.org 2009/03/05 11:30:50
+ [uuencode.c]
+ document what these functions do so I don't ever have to recuse into
+ b64_pton/ntop to remember their return values
+
+20090223
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2009/02/22 23:50:57
+ [ssh_config.5 sshd_config.5]
+ don't advertise experimental options
+ - djm@cvs.openbsd.org 2009/02/22 23:59:25
+ [sshd_config.5]
+ missing period
+ - djm@cvs.openbsd.org 2009/02/23 00:06:15
+ [version.h]
+ openssh-5.2
+ - (djm) [README] update for 5.2
+ - (djm) Release openssh-5.2p1
+
+20090222
+ - (djm) OpenBSD CVS Sync
+ - tobias@cvs.openbsd.org 2009/02/21 19:32:04
+ [misc.c sftp-server-main.c ssh-keygen.c]
+ Added missing newlines in error messages.
+ ok dtucker
+
+20090221
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2009/02/17 01:28:32
+ [ssh_config]
+ sync with revised default ciphers; pointed out by dkrause@
+ - djm@cvs.openbsd.org 2009/02/18 04:31:21
+ [schnorr.c]
+ signature should hash over the entire group, not just the generator
+ (this is still disabled code)
+ - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+ [contrib/suse/openssh.spec] Prepare for 5.2p1
+
+20090216
+ - (djm) [regress/conch-ciphers.sh regress/putty-ciphers.sh]
+ [regress/putty-kex.sh regress/putty-transfer.sh] Downgrade disabled
+ interop tests from FATAL error to a warning. Allows some interop
+ tests to proceed if others are missing necessary prerequisites.
+ - (djm) [configure.ac] support GNU/kFreeBSD and GNU/kOpensolaris
+ systems; patch from Aurelien Jarno via rmh AT aybabtu.com
+
+20090214
+ - (djm) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2009/02/02 11:15:14
+ [sftp.c]
+ Initialize a few variables to prevent spurious "may be used
+ uninitialized" warnings from newer gcc's. ok djm@
+ - djm@cvs.openbsd.org 2009/02/12 03:00:56
+ [canohost.c canohost.h channels.c channels.h clientloop.c readconf.c]
+ [readconf.h serverloop.c ssh.c]
+ support remote port forwarding with a zero listen port (-R0:...) to
+ dyamically allocate a listen port at runtime (this is actually
+ specified in rfc4254); bz#1003 ok markus@
+ - djm@cvs.openbsd.org 2009/02/12 03:16:01
+ [serverloop.c]
+ tighten check for -R0:... forwarding: only allow dynamic allocation
+ if want_reply is set in the packet
+ - djm@cvs.openbsd.org 2009/02/12 03:26:22
+ [monitor.c]
+ some paranoia: check that the serialised key is really KEY_RSA before
+ diddling its internals
+ - djm@cvs.openbsd.org 2009/02/12 03:42:09
+ [ssh.1]
+ document -R0:... usage
+ - djm@cvs.openbsd.org 2009/02/12 03:44:25
+ [ssh.1]
+ consistency: Dq => Ql
+ - djm@cvs.openbsd.org 2009/02/12 03:46:17
+ [ssh_config.5]
+ document RemoteForward usage with 0 listen port
+ - jmc@cvs.openbsd.org 2009/02/12 07:34:20
+ [ssh_config.5]
+ kill trailing whitespace;
+ - markus@cvs.openbsd.org 2009/02/13 11:50:21
+ [packet.c]
+ check for enc !=NULL in packet_start_discard
+ - djm@cvs.openbsd.org 2009/02/14 06:35:49
+ [PROTOCOL]
+ mention that eow and no-more-sessions extensions are sent only to
+ OpenSSH peers
+
+20090212
+ - (djm) [sshpty.c] bz#1419: OSX uses cloning ptys that automagically
+ set ownership and modes, so avoid explicitly setting them
+ - (djm) [configure.ac loginrec.c] bz#1421: fix lastlog support for OSX.
+ OSX provides a getlastlogxbyname function that automates the reading of
+ a lastlog file. Also, the pututxline function will update lastlog so
+ there is no need for loginrec.c to do it explicitly. Collapse some
+ overly verbose code while I'm in there.
+
+20090201
+ - (dtucker) [defines.h sshconnect.c] INET6_ADDRSTRLEN is now needed in
+ channels.c too, so move the definition for non-IP6 platforms to defines.h
+ where it can be shared.
+
+20090129
+ - (tim) [contrib/cygwin/ssh-host-config] Patch from Corinna Vinschen.
+ If the CYGWIN environment variable is empty, the installer script
+ should not install the service with an empty CYGWIN variable, but
+ rather without setting CYGWNI entirely.
+ - (tim) [contrib/cygwin/ssh-host-config] Whitespace cleanup. No code changes.
+
+20090128
+ - (tim) [contrib/cygwin/ssh-host-config] Patch from Corinna Vinschen.
+ Changes to work on Cygwin 1.5.x as well as on the new Cygwin 1.7.x.
+ The information given for the setting of the CYGWIN environment variable
+ is wrong for both releases so I just removed it, together with the
+ unnecessary (Cygwin 1.5.x) or wrong (Cygwin 1.7.x) default setting.
+
+20081228
+ - (djm) OpenBSD CVS Sync
+ - stevesk@cvs.openbsd.org 2008/12/09 03:20:42
+ [channels.c servconf.c]
+ channel_print_adm_permitted_opens() should deal with all the printing
+ for that config option. suggested by markus@; ok markus@ djm@
+ dtucker@
+ - djm@cvs.openbsd.org 2008/12/09 04:32:22
+ [auth2-chall.c]
+ replace by-hand string building with xasprinf(); ok deraadt@
+ - sobrado@cvs.openbsd.org 2008/12/09 15:35:00
+ [sftp.1 sftp.c]
+ update for the synopses displayed by the 'help' command, there are a
+ few missing flags; add 'bye' to the output of 'help'; sorting and spacing.
+ jmc@ suggested replacing .Oo/.Oc with a single .Op macro.
+ ok jmc@
+ - stevesk@cvs.openbsd.org 2008/12/09 22:37:33
+ [clientloop.c]
+ fix typo in error message
+ - stevesk@cvs.openbsd.org 2008/12/10 03:55:20
+ [addrmatch.c]
+ o cannot be NULL here but use xfree() to be consistent; ok djm@
+ - stevesk@cvs.openbsd.org 2008/12/29 01:12:36
+ [ssh-keyscan.1]
+ fix example, default key type is rsa for 3+ years; from
+ frederic.perrin@resel.fr
+ - stevesk@cvs.openbsd.org 2008/12/29 02:23:26
+ [pathnames.h]
+ no need to escape single quotes in comments
+ - okan@cvs.openbsd.org 2008/12/30 00:46:56
+ [sshd_config.5]
+ add AllowAgentForwarding to available Match keywords list
+ ok djm
+ - djm@cvs.openbsd.org 2009/01/01 21:14:35
+ [channels.c]
+ call channel destroy callbacks on receipt of open failure messages.
+ fixes client hangs when connecting to a server that has MaxSessions=0
+ set spotted by imorgan AT nas.nasa.gov; ok markus@
+ - djm@cvs.openbsd.org 2009/01/01 21:17:36
+ [kexgexs.c]
+ fix hash calculation for KEXGEX: hash over the original client-supplied
+ values and not the sanity checked versions that we acutally use;
+ bz#1540 reported by john.smith AT arrows.demon.co.uk
+ ok markus@
+ - djm@cvs.openbsd.org 2009/01/14 01:38:06
+ [channels.c]
+ support SOCKS4A protocol, from dwmw2 AT infradead.org via bz#1482;
+ "looks ok" markus@
+ - stevesk@cvs.openbsd.org 2009/01/15 17:38:43
+ [readconf.c]
+ 1) use obsolete instead of alias for consistency
+ 2) oUserKnownHostsFile not obsolete but oGlobalKnownHostsFile2 is
+ so move the comment.
+ 3) reorder so like options are together
+ ok djm@
+ - djm@cvs.openbsd.org 2009/01/22 09:46:01
+ [channels.c channels.h session.c]
+ make Channel->path an allocated string, saving a few bytes here and
+ there and fixing bz#1380 in the process; ok markus@
+ - djm@cvs.openbsd.org 2009/01/22 09:49:57
+ [channels.c]
+ oops! I committed the wrong version of the Channel->path diff,
+ it was missing some tweaks suggested by stevesk@
+ - djm@cvs.openbsd.org 2009/01/22 10:02:34
+ [clientloop.c misc.c readconf.c readconf.h servconf.c servconf.h]
+ [serverloop.c ssh-keyscan.c ssh.c sshd.c]
+ make a2port() return -1 when it encounters an invalid port number
+ rather than 0, which it will now treat as valid (needed for future work)
+ adjust current consumers of a2port() to check its return value is <= 0,
+ which in turn required some things to be converted from u_short => int
+ make use of int vs. u_short consistent in some other places too
+ feedback & ok markus@
+ - djm@cvs.openbsd.org 2009/01/22 10:09:16
+ [auth-options.c]
+ another chunk of a2port() diff that got away. wtfdjm??
+ - djm@cvs.openbsd.org 2009/01/23 07:58:11
+ [myproposal.h]
+ prefer CTR modes and revised arcfour (i.e w/ discard) modes to CBC
+ modes; ok markus@
+ - naddy@cvs.openbsd.org 2009/01/24 17:10:22
+ [ssh_config.5 sshd_config.5]
+ sync list of preferred ciphers; ok djm@
+ - markus@cvs.openbsd.org 2009/01/26 09:58:15
+ [cipher.c cipher.h packet.c]
+ Work around the CPNI-957037 Plaintext Recovery Attack by always
+ reading 256K of data on packet size or HMAC errors (in CBC mode only).
+ Help, feedback and ok djm@
+ Feedback from Martin Albrecht and Paterson Kenny
+
+20090107
+ - (djm) [uidswap.c] bz#1412: Support >16 supplemental groups in OS X.
+ Patch based on one from vgiffin AT apple.com; ok dtucker@
+ - (djm) [channels.c] bz#1419: support "on demand" X11 forwarding via
+ launchd on OS X; patch from vgiffin AT apple.com, slightly tweaked;
+ ok dtucker@
+ - (djm) [contrib/ssh-copy-id.1 contrib/ssh-copy-id] bz#1492: Make
+ ssh-copy-id copy id_rsa.pub by default (instead of the legacy "identity"
+ key). Patch from cjwatson AT debian.org
+
+20090107
+ - (tim) [configure.ac defines.h openbsd-compat/port-uw.c
+ openbsd-compat/xcrypt.c] Add SECUREWARE support to OpenServer 6 SVR5 ABI.
+ OK djm@ dtucker@
+ - (tim) [configure.ac] Move check_for_libcrypt_later=1 in *-*-sysv5*) section.
+ OpenServer 6 doesn't need libcrypt.
+
+20081209
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/12/09 02:38:18
+ [clientloop.c]
+ The ~C escape handler does not work correctly for multiplexed sessions -
+ it opens a commandline on the master session, instead of on the slave
+ that requested it. Disable it on slave sessions until such time as it
+ is fixed; bz#1543 report from Adrian Bridgett via Colin Watson
+ ok markus@
+ - djm@cvs.openbsd.org 2008/12/09 02:39:59
+ [sftp.c]
+ Deal correctly with failures in remote stat() operation in sftp,
+ correcting fail-on-error behaviour in batchmode. bz#1541 report and
+ fix from anedvedicky AT gmail.com; ok markus@
+ - djm@cvs.openbsd.org 2008/12/09 02:58:16
+ [readconf.c]
+ don't leave junk (free'd) pointers around in Forward *fwd argument on
+ failure; avoids double-free in ~C -L handler when given an invalid
+ forwarding specification; bz#1539 report from adejong AT debian.org
+ via Colin Watson; ok markus@ dtucker@
+ - djm@cvs.openbsd.org 2008/12/09 03:02:37
+ [sftp.1 sftp.c]
+ correct sftp(1) and corresponding usage syntax;
+ bz#1518 patch from imorgan AT nas.nasa.gov; ok deraadt@ improved diff jmc@
+
+20081208
+ - (djm) [configure.ac] bz#1538: better test for ProPolice/SSP: actually
+ use some stack in main().
+ Report and suggested fix from vapier AT gentoo.org
+ - (djm) OpenBSD CVS Sync
+ - markus@cvs.openbsd.org 2008/12/02 19:01:07
+ [clientloop.c]
+ we have to use the recipient's channel number (RFC 4254) for
+ SSH2_MSG_CHANNEL_SUCCESS/SSH2_MSG_CHANNEL_FAILURE messages,
+ otherwise we trigger 'Non-public channel' error messages on sshd
+ systems with clientkeepalive enabled; noticed by sturm; ok djm;
+ - markus@cvs.openbsd.org 2008/12/02 19:08:59
+ [serverloop.c]
+ backout 1.149, since it's not necessary and openssh clients send
+ broken CHANNEL_FAILURE/SUCCESS messages since about 2004; ok djm@
+ - markus@cvs.openbsd.org 2008/12/02 19:09:38
+ [channels.c]
+ s/remote_id/id/ to be more consistent with other code; ok djm@
+
+20081201
+ - (dtucker) [contrib/cygwin/{Makefile,ssh-host-config}] Add new doc files
+ and tweak the is-sshd-running check in ssh-host-config. Patch from
+ vinschen at redhat com.
+ - (dtucker) OpenBSD CVS Sync
+ - markus@cvs.openbsd.org 2008/11/21 15:47:38
+ [packet.c]
+ packet_disconnect() on padding error, too. should reduce the success
+ probability for the CPNI-957037 Plaintext Recovery Attack to 2^-18
+ ok djm@
+ - dtucker@cvs.openbsd.org 2008/11/30 11:59:26
+ [monitor_fdpass.c]
+ Retry sendmsg/recvmsg on EAGAIN and EINTR; ok djm@
+
+20081123
+ - (dtucker) [monitor_fdpass.c] Reduce diff vs OpenBSD by moving some
+ declarations, removing an unnecessary union member and adding whitespace.
+ cmsgbuf.tmp thing spotted by des at des no, ok djm some time ago.
+
+20081118
+ - (tim) [addrmatch.c configure.ac] Some platforms do not have sin6_scope_id
+ member of sockaddr_in6. Also reported in Bug 1491 by David Leonard. OK and
+ feedback by djm@
+
+20081111
+ - (dtucker) OpenBSD CVS Sync
+ - jmc@cvs.openbsd.org 2008/11/05 11:22:54
+ [servconf.c]
+ passord -> password;
+ fixes user/5975 from Rene Maroufi
+ - stevesk@cvs.openbsd.org 2008/11/07 00:42:12
+ [ssh-keygen.c]
+ spelling/typo in comment
+ - stevesk@cvs.openbsd.org 2008/11/07 18:50:18
+ [nchan.c]
+ add space to some log/debug messages for readability; ok djm@ markus@
+ - dtucker@cvs.openbsd.org 2008/11/07 23:34:48
+ [auth2-jpake.c]
+ Move JPAKE define to make life easier for portable. ok djm@
+ - tobias@cvs.openbsd.org 2008/11/09 12:34:47
+ [session.c ssh.1]
+ typo fixed (overriden -> overridden)
+ ok espie, jmc
+ - stevesk@cvs.openbsd.org 2008/11/11 02:58:09
+ [servconf.c]
+ USE_AFS not referenced so remove #ifdef. fixes sshd -T not printing
+ kerberosgetafstoken. ok dtucker@
+ (Id sync only, we still want the ifdef in portable)
+ - stevesk@cvs.openbsd.org 2008/11/11 03:55:11
+ [channels.c]
+ for sshd -T print 'permitopen any' vs. 'permitopen' for case of no
+ permitopen's; ok and input dtucker@
+ - djm@cvs.openbsd.org 2008/11/10 02:06:35
+ [regress/putty-ciphers.sh]
+ PuTTY supports AES CTR modes, so interop test against them too
+
+20081105
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/11/03 08:59:41
+ [servconf.c]
+ include MaxSessions in sshd -T output; patch from imorgan AT nas.nasa.gov
+ - djm@cvs.openbsd.org 2008/11/04 07:58:09
+ [auth.c]
+ need unistd.h for close() prototype
+ (ID sync only)
+ - djm@cvs.openbsd.org 2008/11/04 08:22:13
+ [auth.h auth2.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h]
+ [readconf.c readconf.h servconf.c servconf.h ssh2.h ssh_config.5]
+ [sshconnect2.c sshd_config.5 jpake.c jpake.h schnorr.c auth2-jpake.c]
+ [Makefile.in]
+ Add support for an experimental zero-knowledge password authentication
+ method using the J-PAKE protocol described in F. Hao, P. Ryan,
+ "Password Authenticated Key Exchange by Juggling", 16th Workshop on
+ Security Protocols, Cambridge, April 2008.
+
+ This method allows password-based authentication without exposing
+ the password to the server. Instead, the client and server exchange
+ cryptographic proofs to demonstrate of knowledge of the password while
+ revealing nothing useful to an attacker or compromised endpoint.
+
+ This is experimental, work-in-progress code and is presently
+ compiled-time disabled (turn on -DJPAKE in Makefile.inc).
+
+ "just commit it. It isn't too intrusive." deraadt@
+ - stevesk@cvs.openbsd.org 2008/11/04 19:18:00
+ [readconf.c]
+ because parse_forward() is now used to parse all forward types (DLR),
+ and it malloc's space for host variables, we don't need to malloc
+ here. fixes small memory leaks.
+
+ previously dynamic forwards were not parsed in parse_forward() and
+ space was not malloc'd in that case.
+
+ ok djm@
+ - stevesk@cvs.openbsd.org 2008/11/05 03:23:09
+ [clientloop.c ssh.1]
+ add dynamic forward escape command line; ok djm@
+
+20081103
+ - OpenBSD CVS Sync
+ - sthen@cvs.openbsd.org 2008/07/24 23:55:30
+ [ssh-keygen.1]
+ Add "ssh-keygen -F -l" to synopsis (displays fingerprint from
+ known_hosts). ok djm@
+ - grunk@cvs.openbsd.org 2008/07/25 06:56:35
+ [ssh_config]
+ Add VisualHostKey to example file, ok djm@
+ - grunk@cvs.openbsd.org 2008/07/25 07:05:16
+ [key.c]
+ In random art visualization, make sure to use the end marker only at the
+ end. Initial diff by Dirk Loss, tweaks and ok djm@
+ - markus@cvs.openbsd.org 2008/07/31 14:48:28
+ [sshconnect2.c]
+ don't allocate space for empty banners; report t8m at centrum.cz;
+ ok deraadt
+ - krw@cvs.openbsd.org 2008/08/02 04:29:51
+ [ssh_config.5]
+ whitepsace -> whitespace. From Matthew Clarke via bugs@.
+ - djm@cvs.openbsd.org 2008/08/21 04:09:57
+ [session.c]
+ allow ForceCommand internal-sftp with arguments. based on patch from
+ michael.barabanov AT gmail.com; ok markus@
+ - djm@cvs.openbsd.org 2008/09/06 12:24:13
+ [kex.c]
+ OpenSSL 0.9.8h supplies a real EVP_sha256 so we do not need our
+ replacement anymore
+ (ID sync only for portable - we still need this)
+ - markus@cvs.openbsd.org 2008/09/11 14:22:37
+ [compat.c compat.h nchan.c ssh.c]
+ only send eow and no-more-sessions requests to openssh 5 and newer;
+ fixes interop problems with broken ssh v2 implementations; ok djm@
+ - millert@cvs.openbsd.org 2008/10/02 14:39:35
+ [session.c]
+ Convert an unchecked strdup to xstrdup. OK deraadt@
+ - jmc@cvs.openbsd.org 2008/10/03 13:08:12
+ [sshd.8]
+ do not give an example of how to chmod files: we can presume the user
+ knows that. removes an ambiguity in the permission of authorized_keys;
+ ok deraadt
+ - deraadt@cvs.openbsd.org 2008/10/03 23:56:28
+ [sshconnect2.c]
+ Repair strnvis() buffersize of 4*n+1, with termination gauranteed by the
+ function.
+ spotted by des@freebsd, who commited an incorrect fix to the freebsd tree
+ and (as is fairly typical) did not report the problem to us. But this fix
+ is correct.
+ ok djm
+ - djm@cvs.openbsd.org 2008/10/08 23:34:03
+ [ssh.1 ssh.c]
+ Add -y option to force logging via syslog rather than stderr.
+ Useful for daemonised ssh connection (ssh -f). Patch originally from
+ and ok'd by markus@
+ - djm@cvs.openbsd.org 2008/10/09 03:50:54
+ [servconf.c sshd_config.5]
+ support setting PermitEmptyPasswords in a Match block
+ requested in PR3891; ok dtucker@
+ - jmc@cvs.openbsd.org 2008/10/09 06:54:22
+ [ssh.c]
+ add -y to usage();
+ - stevesk@cvs.openbsd.org 2008/10/10 04:55:16
+ [scp.c]
+ spelling in comment; ok djm@
+ - stevesk@cvs.openbsd.org 2008/10/10 05:00:12
+ [key.c]
+ typo in error message; ok djm@
+ - stevesk@cvs.openbsd.org 2008/10/10 16:43:27
+ [ssh_config.5]
+ use 'Privileged ports can be forwarded only when logging in as root on
+ the remote machine.' for RemoteForward just like ssh.1 -R.
+ ok djm@ jmc@
+ - stevesk@cvs.openbsd.org 2008/10/14 18:11:33
+ [sshconnect.c]
+ use #define ROQUIET here; no binary change. ok dtucker@
+ - stevesk@cvs.openbsd.org 2008/10/17 18:36:24
+ [ssh_config.5]
+ correct and clarify VisualHostKey; ok jmc@
+ - stevesk@cvs.openbsd.org 2008/10/30 19:31:16
+ [clientloop.c sshd.c]
+ don't need to #include "monitor_fdpass.h"
+ - stevesk@cvs.openbsd.org 2008/10/31 15:05:34
+ [dispatch.c]
+ remove unused #define DISPATCH_MIN; ok markus@
+ - djm@cvs.openbsd.org 2008/11/01 04:50:08
+ [sshconnect2.c]
+ sprinkle ARGSUSED on dispatch handlers
+ nuke stale unusued prototype
+ - stevesk@cvs.openbsd.org 2008/11/01 06:43:33
+ [channels.c]
+ fix some typos in log messages; ok djm@
+ - sobrado@cvs.openbsd.org 2008/11/01 11:14:36
+ [ssh-keyscan.1 ssh-keyscan.c]
+ the ellipsis is not an optional argument; while here, improve spacing.
+ - stevesk@cvs.openbsd.org 2008/11/01 17:40:33
+ [clientloop.c readconf.c readconf.h ssh.c]
+ merge dynamic forward parsing into parse_forward();
+ 'i think this is OK' djm@
+ - stevesk@cvs.openbsd.org 2008/11/02 00:16:16
+ [ttymodes.c]
+ protocol 2 tty modes support is now 7.5 years old so remove these
+ debug3()s; ok deraadt@
+ - stevesk@cvs.openbsd.org 2008/11/03 01:07:02
+ [readconf.c]
+ remove valueless comment
+ - stevesk@cvs.openbsd.org 2008/11/03 02:44:41
+ [readconf.c]
+ fix comment
+ - (djm) [contrib/caldera/ssh-host-keygen contrib/suse/rc.sshd]
+ Make example scripts generate keys with default sizes rather than fixed,
+ non-default 1024 bits; patch from imorgan AT nas.nasa.gov
+ - (djm) [contrib/sshd.pam.generic contrib/caldera/sshd.pam]
+ [contrib/redhat/sshd.pam] Move pam_nologin to account group from
+ incorrect auth group in example files;
+ patch from imorgan AT nas.nasa.gov
+
+20080906
+ - (dtucker) [config.guess config.sub] Update to latest versions from
+ http://git.savannah.gnu.org/gitweb/ (2008-04-14 and 2008-06-16
+ respectively).
+
+20080830
+ - (dtucker) [openbsd-compat/bsd-poll.c] correctly check for number of FDs
+ larger than FD_SETSIZE (OpenSSH only ever uses poll with one fd). Patch
+ from Nicholas Marriott.
+
+20080721
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/23 07:36:55
+ [servconf.c]
+ do not try to print options that have been compile-time disabled
+ in config test mode (sshd -T); report from nix-corp AT esperi.org.uk
+ ok dtucker@
+ - (djm) [servconf.c] Print UsePAM option in config test mode (when it
+ has been compiled in); report from nix-corp AT esperi.org.uk
+ ok dtucker@
+
+20080721
+ - (djm) OpenBSD CVS Sync
+ - jmc@cvs.openbsd.org 2008/07/18 22:51:01
+ [sftp-server.8]
+ no need for .Pp before or after .Sh;
+ - djm@cvs.openbsd.org 2008/07/21 08:19:07
+ [version.h]
+ openssh-5.1
+ - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+ [contrib/suse/openssh.spec] Update version number in README and RPM specs
+ - (djm) Release OpenSSH-5.1
+
+20080717
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/17 08:48:00
+ [sshconnect2.c]
+ strnvis preauth banner; pointed out by mpf@ ok markus@
+ - djm@cvs.openbsd.org 2008/07/17 08:51:07
+ [auth2-hostbased.c]
+ strip trailing '.' from hostname when HostbasedUsesNameFromPacketOnly=yes
+ report and patch from res AT qoxp.net (bz#1200); ok markus@
+ - (dtucker) [openbsd-compat/bsd-cygwin_util.c] Remove long-unneeded compat
+ code, replace with equivalent cygwin library call. Patch from vinschen
+ at redhat.com, ok djm@.
+ - (djm) [sshconnect2.c] vis.h isn't available everywhere
+
+20080716
+ - OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/15 02:23:14
+ [sftp.1]
+ number of pipelined requests is now 64;
+ prodded by Iain.Morgan AT nasa.gov
+ - djm@cvs.openbsd.org 2008/07/16 11:51:14
+ [clientloop.c]
+ rename variable first_gc -> last_gc (since it is actually the last
+ in the list).
+ - djm@cvs.openbsd.org 2008/07/16 11:52:19
+ [channels.c]
+ this loop index should be automatic, not static
+
+20080714
+ - (djm) OpenBSD CVS Sync
+ - sthen@cvs.openbsd.org 2008/07/13 21:22:52
+ [ssh-keygen.c]
+ Change "ssh-keygen -F [host] -l" to not display random art unless
+ -v is also specified, making it consistent with the manual and other
+ uses of -l.
+ ok grunk@
+ - djm@cvs.openbsd.org 2008/07/13 22:13:07
+ [channels.c]
+ use struct sockaddr_storage instead of struct sockaddr for accept(2)
+ address argument. from visibilis AT yahoo.com in bz#1485; ok markus@
+ - djm@cvs.openbsd.org 2008/07/13 22:16:03
+ [sftp.c]
+ increase number of piplelined requests so they properly fill the
+ (recently increased) channel window. prompted by rapier AT psc.edu;
+ ok markus@
+ - djm@cvs.openbsd.org 2008/07/14 01:55:56
+ [sftp-server.8]
+ mention requirement for /dev/log inside chroot when using sftp-server
+ with ChrootDirectory
+ - (djm) [openbsd-compat/bindresvport.c] Rename variables s/sin/in/ to
+ avoid clash with sin(3) function; reported by
+ cristian.ionescu-idbohrn AT axis.com
+ - (djm) [openbsd-compat/rresvport.c] Add unistd.h for missing close()
+ prototype; reported by cristian.ionescu-idbohrn AT axis.com
+ - (djm) [umac.c] Rename variable s/buffer_ptr/bufp/ to avoid clash;
+ reported by cristian.ionescu-idbohrn AT axis.com
+ - (djm) [contrib/cygwin/Makefile contrib/cygwin/ssh-host-config]
+ [contrib/cygwin/ssh-user-config contrib/cygwin/sshd-inetd]
+ Revamped and simplified Cygwin ssh-host-config script that uses
+ unified csih configuration tool. Requires recent Cygwin.
+ Patch from vinschen AT redhat.com
+
+20080712
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/12 04:52:50
+ [channels.c]
+ unbreak; move clearing of cctx struct to before first use
+ reported by dkrause@
+ - djm@cvs.openbsd.org 2008/07/12 05:33:41
+ [scp.1]
+ better description for -i flag:
+ s/RSA authentication/public key authentication/
+ - (djm) [openbsd-compat/fake-rfc2553.c openbsd-compat/fake-rfc2553.h]
+ return EAI_FAMILY when trying to lookup unsupported address family;
+ from vinschen AT redhat.com
+
+20080711
+ - (djm) OpenBSD CVS Sync
+ - stevesk@cvs.openbsd.org 2008/07/07 00:31:41
+ [ttymodes.c]
+ we don't need arg after the debug3() was removed. from lint.
+ ok djm@
+ - stevesk@cvs.openbsd.org 2008/07/07 23:32:51
+ [key.c]
+ /*NOTREACHED*/ for lint warning:
+ warning: function key_equal falls off bottom without returning value
+ ok djm@
+ - markus@cvs.openbsd.org 2008/07/10 18:05:58
+ [channels.c]
+ missing bzero; from mickey; ok djm@
+ - markus@cvs.openbsd.org 2008/07/10 18:08:11
+ [clientloop.c monitor.c monitor_wrap.c packet.c packet.h sshd.c]
+ sync v1 and v2 traffic accounting; add it to sshd, too;
+ ok djm@, dtucker@
+
+20080709
+ - (djm) [Makefile.in] Print "all tests passed" when all regress tests pass
+ - (djm) [auth1.c] Fix format string vulnerability in protocol 1 PAM
+ account check failure path. The vulnerable format buffer is supplied
+ from PAM and should not contain attacker-supplied data.
+ - (djm) [auth.c] Missing unistd.h for close()
+ - (djm) [configure.ac] Add -Wformat-security to CFLAGS for gcc 3.x and 4.x
+
+20080705
+ - (djm) [auth.c] Fixed test for locked account on HP/UX with shadowed
+ passwords disabled. bz#1083 report & patch from senthilkumar_sen AT
+ hotpop.com, w/ dtucker@
+ - (djm) [atomicio.c configure.ac] Disable poll() fallback in atomiciov for
+ Tru64. readv doesn't seem to be a comparable object there.
+ bz#1386, patch from dtucker@ ok me
+ - (djm) [Makefile.in] Pass though pass to conch for interop tests
+ - (djm) [configure.ac] unbreak: remove extra closing brace
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/04 23:08:25
+ [packet.c]
+ handle EINTR in packet_write_poll()l ok dtucker@
+ - djm@cvs.openbsd.org 2008/07/04 23:30:16
+ [auth1.c auth2.c]
+ Make protocol 1 MaxAuthTries logic match protocol 2's.
+ Do not treat the first protocol 2 authentication attempt as
+ a failure IFF it is for method "none".
+ Makes MaxAuthTries' user-visible behaviour identical for
+ protocol 1 vs 2.
+ ok dtucker@
+ - djm@cvs.openbsd.org 2008/07/05 05:16:01
+ [PROTOCOL]
+ grammar
+
+20080704
+ - (dtucker) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/07/02 13:30:34
+ [auth2.c]
+ really really remove the freebie "none" auth try for protocol 2
+ - djm@cvs.openbsd.org 2008/07/02 13:47:39
+ [ssh.1 ssh.c]
+ When forking after authentication ("ssh -f") with ExitOnForwardFailure
+ enabled, delay the fork until after replies for any -R forwards have
+ been seen. Allows for robust detection of -R forward failure when
+ using -f (similar to bz#92); ok dtucker@
+ - otto@cvs.openbsd.org 2008/07/03 21:46:58
+ [auth2-pubkey.c]
+ avoid nasty double free; ok dtucker@ djm@
+ - djm@cvs.openbsd.org 2008/07/04 03:44:59
+ [servconf.c groupaccess.h groupaccess.c]
+ support negation of groups in "Match group" block (bz#1315); ok dtucker@
+ - dtucker@cvs.openbsd.org 2008/07/04 03:47:02
+ [monitor.c]
+ Make debug a little clearer. ok djm@
+ - djm@cvs.openbsd.org 2008/06/30 08:07:34
+ [regress/key-options.sh]
+ shell portability: use "=" instead of "==" in test(1) expressions,
+ double-quote string with backslash escaped /
+ - djm@cvs.openbsd.org 2008/06/30 10:31:11
+ [regress/{putty-transfer,putty-kex,putty-ciphers}.sh]
+ remove "set -e" left over from debugging
+ - djm@cvs.openbsd.org 2008/06/30 10:43:03
+ [regress/conch-ciphers.sh]
+ explicitly disable conch options that could interfere with the test
+ - (dtucker) [sftp-server.c] Bug #1447: fall back to racy rename if link
+ returns EXDEV. Patch from Mike Garrison, ok djm@
+ - (djm) [atomicio.c channels.c clientloop.c defines.h includes.h]
+ [packet.c scp.c serverloop.c sftp-client.c ssh-agent.c ssh-keyscan.c]
+ [sshd.c] Explicitly handle EWOULDBLOCK wherever we handle EAGAIN, on
+ some platforms (HP nonstop) it is a distinct errno;
+ bz#1467 reported by sconeu AT yahoo.com; ok dtucker@
+
+20080702
+ - (dtucker) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/06/30 08:05:59
+ [PROTOCOL.agent]
+ typo: s/constraint_date/constraint_data/
+ - djm@cvs.openbsd.org 2008/06/30 12:15:39
+ [serverloop.c]
+ only pass channel requests on session channels through to the session
+ channel handler, avoiding spurious log messages; ok! markus@
+ - djm@cvs.openbsd.org 2008/06/30 12:16:02
+ [nchan.c]
+ only send eow@openssh.com notifications for session channels; ok! markus@
+ - djm@cvs.openbsd.org 2008/06/30 12:18:34
+ [PROTOCOL]
+ clarify that eow@openssh.com is only sent on session channels
+ - dtucker@cvs.openbsd.org 2008/07/01 07:20:52
+ [sshconnect.c]
+ Check ExitOnForwardFailure if forwardings are disabled due to a failed
+ host key check. ok djm@
+ - dtucker@cvs.openbsd.org 2008/07/01 07:24:22
+ [sshconnect.c sshd.c]
+ Send CR LF during protocol banner exchanges, but only for Protocol 2 only,
+ in order to comply with RFC 4253. bz #1443, ok djm@
+ - stevesk@cvs.openbsd.org 2008/07/01 23:12:47
+ [PROTOCOL.agent]
+ fix some typos; ok djm@
+ - djm@cvs.openbsd.org 2008/07/02 02:24:18
+ [sshd_config sshd_config.5 sshd.8 servconf.c]
+ increase default size of ssh protocol 1 ephemeral key from 768 to 1024
+ bits; prodded by & ok dtucker@ ok deraadt@
+ - dtucker@cvs.openbsd.org 2008/07/02 12:03:51
+ [auth-rsa.c auth.c auth2-pubkey.c auth.h]
+ Merge duplicate host key file checks, based in part on a patch from Rob
+ Holland via bz #1348 . Also checks for non-regular files during protocol
+ 1 RSA auth. ok djm@
+ - djm@cvs.openbsd.org 2008/07/02 12:36:39
+ [auth2-none.c auth2.c]
+ Make protocol 2 MaxAuthTries behaviour a little more sensible:
+ Check whether client has exceeded MaxAuthTries before running
+ an authentication method and skip it if they have, previously it
+ would always allow one try (for "none" auth).
+ Preincrement failure count before post-auth test - previously this
+ checked and postincremented, also to allow one "none" try.
+ Together, these two changes always count the "none" auth method
+ which could be skipped by a malicious client (e.g. an SSH worm)
+ to get an extra attempt at a real auth method. They also make
+ MaxAuthTries=0 a useful way to block users entirely (esp. in a
+ sshd_config Match block).
+ Also, move sending of any preauth banner from "none" auth method
+ to the first call to input_userauth_request(), so worms that skip
+ the "none" method get to see it too.
+
+20080630
+ - (djm) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2008/06/10 23:13:43
+ [regress/Makefile regress/key-options.sh]
+ Add regress test for key options. ok djm@
+ - dtucker@cvs.openbsd.org 2008/06/11 23:11:40
+ [regress/Makefile]
+ Don't run cipher-speed test by default; mistakenly enabled by me
+ - djm@cvs.openbsd.org 2008/06/28 13:57:25
+ [regress/Makefile regress/test-exec.sh regress/conch-ciphers.sh]
+ very basic regress test against Twisted Conch in "make interop"
+ target (conch is available in ports/devel/py-twisted/conch);
+ ok markus@
+ - (djm) [regress/Makefile] search for conch by path, like we do putty
+
+20080629
+ - (djm) OpenBSD CVS Sync
+ - martynas@cvs.openbsd.org 2008/06/21 07:46:46
+ [sftp.c]
+ use optopt to get invalid flag, instead of return value of getopt,
+ which is always '?'; ok djm@
+ - otto@cvs.openbsd.org 2008/06/25 11:13:43
+ [key.c]
+ add key length to visual fingerprint; zap magical constants;
+ ok grunk@ djm@
+ - djm@cvs.openbsd.org 2008/06/26 06:10:09
+ [sftp-client.c sftp-server.c]
+ allow the sftp chmod(2)-equivalent operation to set set[ug]id/sticky
+ bits. Note that this only affects explicit setting of modes (e.g. via
+ sftp(1)'s chmod command) and not file transfers. (bz#1310)
+ ok deraadt@ at c2k8
+ - djm@cvs.openbsd.org 2008/06/26 09:19:40
+ [dh.c dh.h moduli.c]
+ when loading moduli from /etc/moduli in sshd(8), check that they
+ are of the expected "safe prime" structure and have had
+ appropriate primality tests performed;
+ feedback and ok dtucker@
+ - grunk@cvs.openbsd.org 2008/06/26 11:46:31
+ [readconf.c readconf.h ssh.1 ssh_config.5 sshconnect.c]
+ Move SSH Fingerprint Visualization away from sharing the config option
+ CheckHostIP to an own config option named VisualHostKey.
+ While there, fix the behaviour that ssh would draw a random art picture
+ on every newly seen host even when the option was not enabled.
+ prodded by deraadt@, discussions,
+ help and ok markus@ djm@ dtucker@
+ - jmc@cvs.openbsd.org 2008/06/26 21:11:46
+ [ssh.1]
+ add VisualHostKey to the list of options listed in -o;
+ - djm@cvs.openbsd.org 2008/06/28 07:25:07
+ [PROTOCOL]
+ spelling fixes
+ - djm@cvs.openbsd.org 2008/06/28 13:58:23
+ [ssh-agent.c]
+ refuse to add a key that has unknown constraints specified;
+ ok markus
+ - djm@cvs.openbsd.org 2008/06/28 14:05:15
+ [ssh-agent.c]
+ reset global compat flag after processing a protocol 2 signature
+ request with the legacy DSA encoding flag set; ok markus
+ - djm@cvs.openbsd.org 2008/06/28 14:08:30
+ [PROTOCOL PROTOCOL.agent]
+ document the protocol used by ssh-agent; "looks ok" markus@
+
+20080628
+ - (djm) [RFC.nroff contrib/cygwin/Makefile contrib/suse/openssh.spec]
+ RFC.nroff lacks a license, remove it (it is long gone in OpenBSD).
+
+20080626
+ - (djm) [Makefile.in moduli.5] Include moduli(5) manpage from OpenBSD.
+ (bz#1372)
+ - (djm) [ contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+ [contrib/suse/openssh.spec] Include moduli.5 in RPM spec files.
+
+20080616
+ - (dtucker) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2008/06/16 13:22:53
+ [session.c channels.c]
+ Rename the isatty argument to is_tty so we don't shadow
+ isatty(3). ok markus@
+ - (dtucker) [channels.c] isatty -> is_tty here too.
+
+20080615
+ - (dtucker) [configure.ac] Enable -fno-builtin-memset when using gcc.
+ - OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2008/06/14 15:49:48
+ [sshd.c]
+ wrap long line at 80 chars
+ - dtucker@cvs.openbsd.org 2008/06/14 17:07:11
+ [sshd.c]
+ ensure default umask disallows at least group and world write; ok djm@
+ - djm@cvs.openbsd.org 2008/06/14 18:33:43
+ [session.c]
+ suppress the warning message from chdir(homedir) failures
+ when chrooted (bz#1461); ok dtucker
+ - dtucker@cvs.openbsd.org 2008/06/14 19:42:10
+ [scp.1]
+ Mention that scp follows symlinks during -r. bz #1466,
+ from nectar at apple
+ - dtucker@cvs.openbsd.org 2008/06/15 16:55:38
+ [sshd_config.5]
+ MaxSessions is allowed in a Match block too
+ - dtucker@cvs.openbsd.org 2008/06/15 16:58:40
+ [servconf.c sshd_config.5]
+ Allow MaxAuthTries within a Match block. ok djm@
+ - djm@cvs.openbsd.org 2008/06/15 20:06:26
+ [channels.c channels.h session.c]
+ don't call isatty() on a pty master, instead pass a flag down to
+ channel_set_fds() indicating that te fds refer to a tty. Fixes a
+ hang on exit on Solaris (bz#1463) in portable but is actually
+ a generic bug; ok dtucker deraadt markus
+
+20080614
+ - (djm) [openbsd-compat/sigact.c] Avoid NULL derefs in ancient sigaction
+ replacement code; patch from ighighi AT gmail.com in bz#1240;
+ ok dtucker
+
+20080613
+ - (dtucker) OpenBSD CVS Sync
+ - deraadt@cvs.openbsd.org 2008/06/13 09:44:36
+ [packet.c]
+ compile on older gcc; no decl after code
+ - dtucker@cvs.openbsd.org 2008/06/13 13:56:59
+ [monitor.c]
+ Clear key options in the monitor on failed authentication, prevents
+ applying additional restrictions to non-pubkey authentications in
+ the case where pubkey fails but another method subsequently succeeds.
+ bz #1472, found by Colin Watson, ok markus@ djm@
+ - dtucker@cvs.openbsd.org 2008/06/13 14:18:51
+ [auth2-pubkey.c auth-rhosts.c]
+ Include unistd.h for close(), prevents warnings in -portable
+ - dtucker@cvs.openbsd.org 2008/06/13 17:21:20
+ [mux.c]
+ Friendlier error messages for mux fallback. ok djm@
+ - dtucker@cvs.openbsd.org 2008/06/13 18:55:22
+ [scp.c]
+ Prevent -Wsign-compare warnings on LP64 systems. bz #1192, ok deraadt@
+ - grunk@cvs.openbsd.org 2008/06/13 20:13:26
+ [ssh.1]
+ Explain the use of SSH fpr visualization using random art, and cite the
+ original scientific paper inspiring that technique.
+ Much help with English and nroff by jmc@, thanks.
+ - (dtucker) [configure.ac] Bug #1276: avoid linking against libgssapi, which
+ despite its name doesn't seem to implement all of GSSAPI. Patch from
+ Jan Engelhardt, sanity checked by Simon Wilkinson.
+
+20080612
+ - (dtucker) OpenBSD CVS Sync
+ - jmc@cvs.openbsd.org 2008/06/11 07:30:37
+ [sshd.8]
+ kill trailing whitespace;
+ - grunk@cvs.openbsd.org 2008/06/11 21:01:35
+ [ssh_config.5 key.h readconf.c readconf.h ssh-keygen.1 ssh-keygen.c key.c
+ sshconnect.c]
+ Introduce SSH Fingerprint ASCII Visualization, a technique inspired by the
+ graphical hash visualization schemes known as "random art", and by
+ Dan Kaminsky's musings on the subject during a BlackOp talk at the
+ 23C3 in Berlin.
+ Scientific publication (original paper):
+ "Hash Visualization: a New Technique to improve Real-World Security",
+ Perrig A. and Song D., 1999, International Workshop on Cryptographic
+ Techniques and E-Commerce (CrypTEC '99)
+ http://sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
+ The algorithm used here is a worm crawling over a discrete plane,
+ leaving a trace (augmenting the field) everywhere it goes.
+ Movement is taken from dgst_raw 2bit-wise. Bumping into walls
+ makes the respective movement vector be ignored for this turn,
+ thus switching to the other color of the chessboard.
+ Graphs are not unambiguous for now, because circles in graphs can be
+ walked in either direction.
+ discussions with several people,
+ help, corrections and ok markus@ djm@
+ - grunk@cvs.openbsd.org 2008/06/11 21:38:25
+ [ssh-keygen.c]
+ ssh-keygen -lv -f /etc/ssh/ssh_host_rsa_key.pub
+ would not display you the random art as intended, spotted by canacar@
+ - grunk@cvs.openbsd.org 2008/06/11 22:20:46
+ [ssh-keygen.c ssh-keygen.1]
+ ssh-keygen would write fingerprints to STDOUT, and random art to STDERR,
+ that is not how it was envisioned.
+ Also correct manpage saying that -v is needed along with -l for it to work.
+ spotted by naddy@
+ - otto@cvs.openbsd.org 2008/06/11 23:02:22
+ [key.c]
+ simpler way of computing the augmentations; ok grunk@
+ - grunk@cvs.openbsd.org 2008/06/11 23:03:56
+ [ssh_config.5]
+ CheckHostIP set to ``fingerprint'' will display both hex and random art
+ spotted by naddy@
+ - grunk@cvs.openbsd.org 2008/06/11 23:51:57
+ [key.c]
+ #define statements that are not atoms need braces around them, else they
+ will cause trouble in some cases.
+ Also do a computation of -1 once, and not in a loop several times.
+ spotted by otto@
+ - dtucker@cvs.openbsd.org 2008/06/12 00:03:49
+ [dns.c canohost.c sshconnect.c]
+ Do not pass "0" strings as ports to getaddrinfo because the lookups
+ can slow things down and we never use the service info anyway. bz
+ #859, patch from YOSHIFUJI Hideaki and John Devitofranceschi. ok
+ deraadt@ djm@
+ djm belives that the reason for the "0" strings is to ensure that
+ it's not possible to call getaddrinfo with both host and port being
+ NULL. In the case of canohost.c host is a local array. In the
+ case of sshconnect.c, it's checked for null immediately before use.
+ In dns.c it ultimately comes from ssh.c:main() and is guaranteed to
+ be non-null but it's not obvious, so I added a warning message in
+ case it is ever passed a null.
+ - grunk@cvs.openbsd.org 2008/06/12 00:13:55
+ [sshconnect.c]
+ Make ssh print the random art also when ssh'ing to a host using IP only.
+ spotted by naddy@, ok and help djm@ dtucker@
+ - otto@cvs.openbsd.org 2008/06/12 00:13:13
+ [key.c]
+ use an odd number of rows and columns and a separate start marker, looks
+ better; ok grunk@
+ - djm@cvs.openbsd.org 2008/06/12 03:40:52
+ [clientloop.h mux.c channels.c clientloop.c channels.h]
+ Enable ~ escapes for multiplex slave sessions; give each channel
+ its own escape state and hook the escape filters up to muxed
+ channels. bz #1331
+ Mux slaves do not currently support the ~^Z and ~& escapes.
+ NB. this change cranks the mux protocol version, so a new ssh
+ mux client will not be able to connect to a running old ssh
+ mux master.
+ ok dtucker@
+ - djm@cvs.openbsd.org 2008/06/12 04:06:00
+ [clientloop.h ssh.c clientloop.c]
+ maintain an ordered queue of outstanding global requests that we
+ expect replies to, similar to the per-channel confirmation queue.
+ Use this queue to verify success or failure for remote forward
+ establishment in a race free way.
+ ok dtucker@
+ - djm@cvs.openbsd.org 2008/06/12 04:17:47
+ [clientloop.c]
+ thall shalt not code past the eightieth column
+ - djm@cvs.openbsd.org 2008/06/12 04:24:06
+ [ssh.c]
+ thal shalt not code past the eightieth column
+ - djm@cvs.openbsd.org 2008/06/12 05:15:41
+ [PROTOCOL]
+ document tun@openssh.com forwarding method
+ - djm@cvs.openbsd.org 2008/06/12 05:32:30
+ [mux.c]
+ some more TODO for me
+ - grunk@cvs.openbsd.org 2008/06/12 05:42:46
+ [key.c]
+ supply the key type (rsa1, rsa, dsa) as a caption in the frame of the
+ random art. while there, stress the fact that the field base should at
+ least be 8 characters for the pictures to make sense.
+ comment and ok djm@
+ - grunk@cvs.openbsd.org 2008/06/12 06:32:59
+ [key.c]
+ We already mark the start of the worm, now also mark the end of the worm
+ in our random art drawings.
+ ok djm@
+ - djm@cvs.openbsd.org 2008/06/12 15:19:17
+ [clientloop.h channels.h clientloop.c channels.c mux.c]
+ The multiplexing escape char handler commit last night introduced a
+ small memory leak per session; plug it.
+ - dtucker@cvs.openbsd.org 2008/06/12 16:35:31
+ [ssh_config.5 ssh.c]
+ keyword expansion for localcommand. ok djm@
+ - jmc@cvs.openbsd.org 2008/06/12 19:10:09
+ [ssh_config.5 ssh-keygen.1]
+ tweak the ascii art text; ok grunk
+ - dtucker@cvs.openbsd.org 2008/06/12 20:38:28
+ [sshd.c sshconnect.c packet.h misc.c misc.h packet.c]
+ Make keepalive timeouts apply while waiting for a packet, particularly
+ during key renegotiation (bz #1363). With djm and Matt Day, ok djm@
+ - djm@cvs.openbsd.org 2008/06/12 20:47:04
+ [sftp-client.c]
+ print extension revisions for extensions that we understand
+ - djm@cvs.openbsd.org 2008/06/12 21:06:25
+ [clientloop.c]
+ I was coalescing expected global request confirmation replies at
+ the wrong end of the queue - fix; prompted by markus@
+ - grunk@cvs.openbsd.org 2008/06/12 21:14:46
+ [ssh-keygen.c]
+ make ssh-keygen -lf show the key type just as ssh-add -l would do it
+ ok djm@ markus@
+ - grunk@cvs.openbsd.org 2008/06/12 22:03:36
+ [key.c]
+ add my copyright, ok djm@
+ - ian@cvs.openbsd.org 2008/06/12 23:24:58
+ [sshconnect.c]
+ tweak wording in message, ok deraadt@ jmc@
+ - dtucker@cvs.openbsd.org 2008/06/13 00:12:02
+ [sftp.h log.h]
+ replace __dead with __attribute__((noreturn)), makes things
+ a little easier to port. Also, add it to sigdie(). ok djm@
+ - djm@cvs.openbsd.org 2008/06/13 00:16:49
+ [mux.c]
+ fall back to creating a new TCP connection on most multiplexing errors
+ (socket connect fail, invalid version, refused permittion, corrupted
+ messages, etc.); bz #1329 ok dtucker@
+ - dtucker@cvs.openbsd.org 2008/06/13 00:47:53
+ [mux.c]
+ upcast size_t to u_long to match format arg; ok djm@
+ - dtucker@cvs.openbsd.org 2008/06/13 00:51:47
+ [mac.c]
+ upcast another size_t to u_long to match format
+ - dtucker@cvs.openbsd.org 2008/06/13 01:38:23
+ [misc.c]
+ upcast uid to long with matching %ld, prevents warnings in portable
+ - djm@cvs.openbsd.org 2008/06/13 04:40:22
+ [auth2-pubkey.c auth-rhosts.c]
+ refuse to read ~/.shosts or ~/.ssh/authorized_keys that are not
+ regular files; report from Solar Designer via Colin Watson in bz#1471
+ ok dtucker@ deraadt
+ - (dtucker) [clientloop.c serverloop.c] channel_register_filter now
+ takes 2 more args. with djm@
+ - (dtucker) [defines.h] Bug #1112: __dead is, well dead. Based on a patch
+ from Todd Vierling.
+ - (dtucker) [auth-sia.c] Bug #1241: support password expiry on Tru64 SIA
+ systems. Patch from R. Scott Bailey.
+ - (dtucker) [umac.c] STORE_UINT32_REVERSED and endian_convert are never used
+ on big endian machines, so ifdef them for little-endian only to prevent
+ unused function warnings on big-endians.
+ - (dtucker) [openbsd-compat/setenv.c] Make offsets size_t to prevent
+ compiler warnings on some platforms. Based on a discussion with otto@
+
+20080611
+ - (djm) [channels.c configure.ac]
+ Do not set SO_REUSEADDR on wildcard X11 listeners (X11UseLocalhost=no)
+ bz#1464; ok dtucker
+
+20080610
+ - (dtucker) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/06/10 03:57:27
+ [servconf.c match.h sshd_config.5]
+ support CIDR address matching in sshd_config "Match address" blocks, with
+ full support for negation and fall-back to classic wildcard matching.
+ For example:
+ Match address 192.0.2.0/24,3ffe:ffff::/32,!10.*
+ PasswordAuthentication yes
+ addrmatch.c code mostly lifted from flowd's addr.c
+ feedback and ok dtucker@
+ - djm@cvs.openbsd.org 2008/06/10 04:17:46
+ [sshd_config.5]
+ better reference for pattern-list
+ - dtucker@cvs.openbsd.org 2008/06/10 04:50:25
+ [sshd.c channels.h channels.c log.c servconf.c log.h servconf.h sshd.8]
+ Add extended test mode (-T) and connection parameters for test mode (-C).
+ -T causes sshd to write its effective configuration to stdout and exit.
+ -C causes any relevant Match rules to be applied before output. The
+ combination allows tesing of the parser and config files. ok deraadt djm
+ - jmc@cvs.openbsd.org 2008/06/10 07:12:00
+ [sshd_config.5]
+ tweak previous;
+ - jmc@cvs.openbsd.org 2008/06/10 08:17:40
+ [sshd.8 sshd.c]
+ - update usage()
+ - fix SYNOPSIS, and sort options
+ - some minor additional fixes
+ - dtucker@cvs.openbsd.org 2008/06/09 18:06:32
+ [regress/test-exec.sh]
+ Don't generate putty keys if we're not going to use them. ok djm
+ - dtucker@cvs.openbsd.org 2008/06/10 05:23:32
+ [regress/addrmatch.sh regress/Makefile]
+ Regress test for Match CIDR rules. ok djm@
+ - dtucker@cvs.openbsd.org 2008/06/10 15:21:41
+ [test-exec.sh]
+ Use a more portable construct for checking if we're running a putty test
+ - dtucker@cvs.openbsd.org 2008/06/10 15:28:49
+ [test-exec.sh]
+ Add quotes
+ - dtucker@cvs.openbsd.org 2008/06/10 18:21:24
+ [ssh_config.5]
+ clarify that Host patterns are space-separated. ok deraadt
+ - djm@cvs.openbsd.org 2008/06/10 22:15:23
+ [PROTOCOL ssh.c serverloop.c]
+ Add a no-more-sessions@openssh.com global request extension that the
+ client sends when it knows that it will never request another session
+ (i.e. when session multiplexing is disabled). This allows a server to
+ disallow further session requests and terminate the session.
+ Why would a non-multiplexing client ever issue additional session
+ requests? It could have been attacked with something like SSH'jack:
+ http://www.storm.net.nz/projects/7
+ feedback & ok markus
+ - djm@cvs.openbsd.org 2008/06/10 23:06:19
+ [auth-options.c match.c servconf.c addrmatch.c sshd.8]
+ support CIDR address matching in .ssh/authorized_keys from="..." stanzas
+ ok and extensive testing dtucker@
+ - dtucker@cvs.openbsd.org 2008/06/10 23:21:34
+ [bufaux.c]
+ Use '\0' for a nul byte rather than unadorned 0. ok djm@
+ - dtucker@cvs.openbsd.org 2008/06/10 23:13:43
+ [Makefile regress/key-options.sh]
+ Add regress test for key options. ok djm@
+ - (dtucker) [openbsd-compat/fake-rfc2553.h] Add sin6_scope_id to sockaddr_in6
+ since the new CIDR code in addmatch.c references it.
+ - (dtucker) [Makefile.in configure.ac regress/addrmatch.sh] Skip IPv6
+ specific tests on platforms that don't do IPv6.
+ - (dtucker) [Makefile.in] Define TEST_SSH_IPV6 in make's arguments as well
+ as environment.
+ - (dtucker) [Makefile.in] Move addrmatch.o to libssh.a where it's needed now.
+
+20080609
+ - (dtucker) OpenBSD CVS Sync
+ - dtucker@cvs.openbsd.org 2008/06/08 17:04:41
+ [sftp-server.c]
+ Add case for ENOSYS in errno_to_portable; ok deraadt
+ - dtucker@cvs.openbsd.org 2008/06/08 20:15:29
+ [sftp.c sftp-client.c sftp-client.h]
+ Have the sftp client store the statvfs replies in wire format,
+ which prevents problems when the server's native sizes exceed the
+ client's.
+ Also extends the sizes of the remaining 32bit wire format to 64bit,
+ they're specified as unsigned long in the standard.
+ - dtucker@cvs.openbsd.org 2008/06/09 13:02:39
+ [sftp-server.c]
+ Extend 32bit -> 64bit values for statvfs extension missed in previous
+ commit.
+ - dtucker@cvs.openbsd.org 2008/06/09 13:38:46
+ [PROTOCOL]
+ Use a $OpenBSD tag so our scripts will sync changes.
+
+20080608
+ - (dtucker) [configure.ac defines.h sftp-client.c sftp-server.c sftp.c
+ openbsd-compat/Makefile.in openbsd-compat/openbsd-compat.h
+ openbsd-compat/bsd-statvfs.{c,h}] Add a null implementation of statvfs and
+ fstatvfs and remove #defines around statvfs code. ok djm@
+ - (dtucker) [configure.ac defines.h sftp-client.c M sftp-server.c] Add a
+ macro to convert fsid to unsigned long for platforms where fsid is a
+ 2-member array.
+
+20080607
+ - (dtucker) [mux.c] Include paths.h inside ifdef HAVE_PATHS_H.
+ - (dtucker) [configure.ac defines.h sftp-client.c sftp-server.c sftp.c]
+ Do not enable statvfs extensions on platforms that do not have statvfs.
+ - (dtucker) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/05/19 06:14:02
+ [packet.c] unbreak protocol keepalive timeouts bz#1465; ok dtucker@
+ - djm@cvs.openbsd.org 2008/05/19 15:45:07
+ [sshtty.c ttymodes.c sshpty.h]
+ Fix sending tty modes when stdin is not a tty (bz#1199). Previously
+ we would send the modes corresponding to a zeroed struct termios,
+ whereas we should have been sending an empty list of modes.
+ Based on patch from daniel.ritz AT alcatel.ch; ok dtucker@ markus@
+ - djm@cvs.openbsd.org 2008/05/19 15:46:31
+ [ssh-keygen.c]
+ support -l (print fingerprint) in combination with -F (find host) to
+ search for a host in ~/.ssh/known_hosts and display its fingerprint;
+ ok markus@
+ - djm@cvs.openbsd.org 2008/05/19 20:53:52
+ [clientloop.c]
+ unbreak tree by committing this bit that I missed from:
+ Fix sending tty modes when stdin is not a tty (bz#1199). Previously
+ we would send the modes corresponding to a zeroed struct termios,
+ whereas we should have been sending an empty list of modes.
+ Based on patch from daniel.ritz AT alcatel.ch; ok dtucker@ markus@
+
+20080604
+ - (djm) [openbsd-compat/bsd-arc4random.c] Fix math bug that caused bias
+ in arc4random_uniform with upper_bound in (2^30,2*31). Note that
+ OpenSSH did not make requests with upper bounds in this range.
+
+20080519
+ - (djm) [configure.ac mux.c sftp.c openbsd-compat/Makefile.in]
+ [openbsd-compat/fmt_scaled.c openbsd-compat/openbsd-compat.h]
+ Fix compilation on Linux, including pulling in fmt_scaled(3)
+ implementation from OpenBSD's libutil.
+
+20080518
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/04/04 05:14:38
+ [sshd_config.5]
+ ChrootDirectory is supported in Match blocks (in fact, it is most useful
+ there). Spotted by Minstrel AT minstrel.org.uk
+ - djm@cvs.openbsd.org 2008/04/04 06:44:26
+ [sshd_config.5]
+ oops, some unrelated stuff crept into that commit - backout.
+ spotted by jmc@
+ - djm@cvs.openbsd.org 2008/04/05 02:46:02
+ [sshd_config.5]
+ HostbasedAuthentication is supported under Match too
+ - (djm) [openbsd-compat/bsd-arc4random.c openbsd-compat/openbsd-compat.c]
+ [configure.ac] Implement arc4random_buf(), import implementation of
+ arc4random_uniform() from OpenBSD
+ - (djm) [openbsd-compat/bsd-arc4random.c] Warning fixes
+ - (djm) [openbsd-compat/port-tun.c] needs sys/queue.h
+ - (djm) OpenBSD CVS Sync
+ - djm@cvs.openbsd.org 2008/04/13 00:22:17
+ [dh.c sshd.c]
+ Use arc4random_buf() when requesting more than a single word of output
+ Use arc4random_uniform() when the desired random number upper bound
+ is not a power of two
+ ok deraadt@ millert@
+ - djm@cvs.openbsd.org 2008/04/18 12:32:11
+ [sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h]
+ introduce sftp extension methods statvfs@openssh.com and
+ fstatvfs@openssh.com that implement statvfs(2)-like operations,
+ based on a patch from miklos AT szeredi.hu (bz#1399)
+ also add a "df" command to the sftp client that uses the
+ statvfs@openssh.com to produce a df(1)-like display of filesystem
+ space and inode utilisation
+ ok markus@
+ - jmc@cvs.openbsd.org 2008/04/18 17:15:47
+ [sftp.1]
+ macro fixage;
+ - djm@cvs.openbsd.org 2008/04/18 22:01:33
+ [session.c]
+ remove unneccessary parentheses
+ - otto@cvs.openbsd.org 2008/04/29 11:20:31
+ [monitor_mm.h]
+ garbage collect two unused fields in struct mm_master; ok markus@
+ - djm@cvs.openbsd.org 2008/04/30 10:14:03
+ [ssh-keyscan.1 ssh-keyscan.c]
+ default to rsa (protocol 2) keys, instead of rsa1 keys; spotted by
+ larsnooden AT openoffice.org
+ - pyr@cvs.openbsd.org 2008/05/07 05:49:37
+ [servconf.c servconf.h session.c sshd_config.5]
+ Enable the AllowAgentForwarding option in sshd_config (global and match
+ context), to specify if agents should be permitted on the server.
+ As the man page states:
+ ``Note that disabling Agent forwarding does not improve security
+ unless users are also denied shell access, as they can always install
+ their own forwarders.''
+ ok djm@, ok and a mild frown markus@
+ - pyr@cvs.openbsd.org 2008/05/07 06:43:35
+ [sshd_config]
+ push the sshd_config bits in, spotted by ajacoutot@
+ - jmc@cvs.openbsd.org 2008/05/07 08:00:14
+ [sshd_config.5]
+ sort;
+ - markus@cvs.openbsd.org 2008/05/08 06:59:01
+ [bufaux.c buffer.h channels.c packet.c packet.h]
+ avoid extra malloc/copy/free when receiving data over the net;
+ ~10% speedup for localhost-scp; ok djm@
+ - djm@cvs.openbsd.org 2008/05/08 12:02:23
+ [auth-options.c auth1.c channels.c channels.h clientloop.c gss-serv.c]
+ [monitor.c monitor_wrap.c nchan.c servconf.c serverloop.c session.c]
+ [ssh.c sshd.c]
+ Implement a channel success/failure status confirmation callback
+ mechanism. Each channel maintains a queue of callbacks, which will
+ be drained in order (RFC4253 guarantees confirm messages are not
+ reordered within an channel).
+ Also includes a abandonment callback to clean up if a channel is
+ closed without sending confirmation messages. This probably
+ shouldn't happen in compliant implementations, but it could be
+ abused to leak memory.
+ ok markus@ (as part of a larger diff)
+ - djm@cvs.openbsd.org 2008/05/08 12:21:16
+ [monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c]
+ [sshd_config sshd_config.5]
+ Make the maximum number of sessions run-time controllable via
+ a sshd_config MaxSessions knob. This is useful for disabling
+ login/shell/subsystem access while leaving port-forwarding working
+ (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or
+ simply increasing the number of allows multiplexed sessions.
+ Because some bozos are sure to configure MaxSessions in excess of the
+ number of available file descriptors in sshd (which, at peak, might be
+ as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds
+ on error paths, and make it fail gracefully on out-of-fd conditions -
+ sending channel errors instead of than exiting with fatal().
+ bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com
+ ok markus@
+ - djm@cvs.openbsd.org 2008/05/08 13:06:11
+ [clientloop.c clientloop.h ssh.c]
+ Use new channel status confirmation callback system to properly deal
+ with "important" channel requests that fail, in particular command exec,
+ shell and subsystem requests. Previously we would optimistically assume
+ that the requests would always succeed, which could cause hangs if they
+ did not (e.g. when the server runs out of fds) or were unimplemented by
+ the server (bz #1384)
+ Also, properly report failing multiplex channel requests via the mux
+ client stderr (subject to LogLevel in the mux master) - better than
+ silently failing.
+ most bits ok markus@ (as part of a larger diff)
+ - djm@cvs.openbsd.org 2008/05/09 04:55:56
+ [channels.c channels.h clientloop.c serverloop.c]
+ Try additional addresses when connecting to a port forward destination
+ whose DNS name resolves to more than one address. The previous behaviour
+ was to try the first address and give up.
+ Reported by stig AT venaas.com in bz#343
+ great feedback and ok markus@
+ - djm@cvs.openbsd.org 2008/05/09 14:18:44
+ [clientloop.c clientloop.h ssh.c mux.c]
+ tidy up session multiplexing code, moving it into its own file and
+ making the function names more consistent - making ssh.c and
+ clientloop.c a fair bit more readable.
+ ok markus@
+ - djm@cvs.openbsd.org 2008/05/09 14:26:08
+ [ssh.c]
+ dingo stole my diff hunk
+ - markus@cvs.openbsd.org 2008/05/09 16:16:06
+ [session.c]
+ re-add the USE_PIPES code and enable it.
+ without pipes shutdown-read from the sshd does not trigger
+ a SIGPIPE when the forked program does a write.
+ ok djm@
+ (Id sync only, USE_PIPES never left portable OpenSSH)
+ - markus@cvs.openbsd.org 2008/05/09 16:17:51
+ [channels.c]
+ error-fd race: don't enable the error fd in the select bitmask
+ for channels with both in- and output closed, since the channel
+ will go away before we call select();
+ report, lots of debugging help and ok djm@
+ - markus@cvs.openbsd.org 2008/05/09 16:21:13
+ [channels.h clientloop.c nchan.c serverloop.c]
+ unbreak
+ ssh -2 localhost od /bin/ls | true
+ ignoring SIGPIPE by adding a new channel message (EOW) that signals
+ the peer that we're not interested in any data it might send.
+ fixes bz #85; discussion, debugging and ok djm@
+ - pvalchev@cvs.openbsd.org 2008/05/12 20:52:20
+ [umac.c]
+ Ensure nh_result lies on a 64-bit boundary (fixes warnings observed
+ on Itanium on Linux); from Dale Talcott (bug #1462); ok djm@
+ - djm@cvs.openbsd.org 2008/05/15 23:52:24
+ [nchan2.ms]
+ document eow message in ssh protocol 2 channel state machine;
+ feedback and ok markus@
+ - djm@cvs.openbsd.org 2008/05/18 21:29:05
+ [sftp-server.c]
+ comment extension announcement
+ - djm@cvs.openbsd.org 2008/05/16 08:30:42
+ [PROTOCOL]
+ document our protocol extensions and deviations; ok markus@
+ - djm@cvs.openbsd.org 2008/05/17 01:31:56
+ [PROTOCOL]
+ grammar and correctness fixes from stevesk@
+
+20080403
+ - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
+ time warnings on LynxOS. Patch from ops AT iki.fi
+ - (djm) Force string arguments to replacement setproctitle() though
+ strnvis first. Ok dtucker@
+
+20080403
+ - (djm) OpenBSD CVS sync:
+ - markus@cvs.openbsd.org 2008/04/02 15:36:51
+ [channels.c]
+ avoid possible hijacking of x11-forwarded connections (back out 1.183)
+ CVE-2008-1483; ok djm@
+ - jmc@cvs.openbsd.org 2008/03/27 22:37:57
+ [sshd.8]
+ remove trailing whitespace;
+ - djm@cvs.openbsd.org 2008/04/03 09:50:14
+ [version.h]
+ openssh-5.0
+ - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec]
+ [contrib/suse/openssh.spec] Crank version numbers in RPM spec files
+ - (djm) [README] Update link to release notes
+ - (djm) Release 5.0p1
diff --git a/crypto/openssh/FREEBSD-tricks b/crypto/openssh/FREEBSD-tricks
new file mode 100644
index 0000000..480bffc
--- /dev/null
+++ b/crypto/openssh/FREEBSD-tricks
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+# Shell code to remove FreeBSD tags before merging
+grep -rl '\$Fre[e]BSD:' . | grep -v FREEBSD >tags
+cat tags | while read f ; do
+ sed -i.orig -e '/\$Fre[e]BSD:/d' $f
+done
+
+# Shell + Perl code to add FreeBSD tags wherever an OpenBSD or Id tag occurs
+cat tags |
+xargs perl -n -i.orig -e 'print; s/\$(Id|OpenBSD): [^\$]*/\$FreeBSD/ && print'
+
+# Diff against vendor branch
+svn diff --no-diff-deleted --old=$FSVN/vendor-crypto/openssh/dist/ --new=.
diff --git a/crypto/openssh/FREEBSD-upgrade b/crypto/openssh/FREEBSD-upgrade
new file mode 100644
index 0000000..03b7dbf
--- /dev/null
+++ b/crypto/openssh/FREEBSD-upgrade
@@ -0,0 +1,124 @@
+
+
+ FreeBSD maintainer's guide to OpenSSH-portable
+ ==============================================
+
+[needs rewriting for svn]
+
+0) Make sure your mail spool has plenty of free space. It'll fill up
+ pretty fast once you're done with this checklist.
+
+1) Grab the latest OpenSSH-portable tarball from the OpenBSD FTP
+ site (ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/)
+
+2) Unpack the tarball in a suitable directory.
+
+ $ tar xf openssh-X.YpZ.tar.gz \
+ -X /usr/src/crypto/openssh/FREEBSD-Xlist
+
+3) Remove trash:
+
+ Make sure -X took care of everything, and if it didn't, make sure
+ to update FREEBSD-Xlist so you won't miss it the next time. A good
+ way to do this is to run a test import and see if any new files
+ show up:
+
+ $ cvs -n import src/crypto/openssh OPENSSH x | grep \^N
+
+4) Import the sources:
+
+ $ cvs import src/crypto/openssh OPENSSH OpenSSH_X_YpZ
+
+5) Resolve conflicts. Remember to bump the version number and
+ addendum in version.h, and update the default value in
+ ssh{,d}_config and ssh{,d}_config.5.
+
+6) Generate configure and config.h.in:
+
+ $ autoconf
+ $ autoheader
+
+ Note: this requires a recent version of autoconf, not autoconf213.
+
+7) Run configure with the appropriate arguments:
+
+ $ ./configure --prefix=/usr --sysconfdir=/etc/ssh \
+ --with-pam --with-tcp-wrappers --with-libedit \
+ --with-ssl-engine
+
+ This will regenerate config.h, which must be committed along with
+ the rest.
+
+ Note that we don't want to configure OpenSSH for Kerberos using
+ configure since we have to be able to turn it on or off depending
+ on the value of MK_KERBEROS. Our Makefiles take care of this.
+
+8) If source files have been added or removed, update the appropriate
+ makefiles to reflect changes in the vendor's Makefile.in.
+
+9) Build libssh. Follow the instructions in ssh_namespace.h to get a
+ list of new symbols. Update ssh_namespace.h, build everything,
+ install and test.
+
+A) Build and test the pam_ssh PAM module. It gropes around libssh's
+ internals and will break if something significant changes or if
+ ssh_namespace.h is out of whack.
+
+B) Re-commit everything on repoman (you *did* use a test repo for
+ this, didn't you?)
+
+
+
+ An overview of FreeBSD changes to OpenSSH-portable
+ ==================================================
+
+0) VersionAddendum
+
+ The SSH protocol allows for a human-readable version string of up
+ to 40 characters to be appended to the protocol version string.
+ FreeBSD takes advantage of this to include a date indicating the
+ "patch level", so people can easily determine whether their system
+ is vulnerable when an OpenSSH advisory goes out. Some people,
+ however, dislike advertising their patch level in the protocol
+ handshake, so we've added a VersionAddendum configuration variable
+ to allow them to change or disable it.
+
+1) Modified server-side defaults
+
+ We've modified some configuration defaults in sshd:
+
+ - PasswordAuthentication defaults to "no".
+
+ - LoginGraceTime defaults to 120 seconds instead of 600.
+
+ - PermitRootLogin defaults to "no".
+
+ - X11Forwarding defaults to "yes" (it's a threat to the client,
+ not to the server.)
+
+2) Modified client-side defaults
+
+ We've modified some configuration defaults in ssh:
+
+ - CheckHostIP defaults to "no".
+
+3) Canonic host names
+
+ We've added code to ssh.c to canonicize the target host name after
+ reading options but before trying to connect. This eliminates the
+ usual problem with duplicate known_hosts entries.
+
+4) setusercontext() environment
+
+ Our setusercontext(3) can set environment variables, which we must
+ take care to transfer to the child's environment.
+
+
+
+This port was brought to you by (in no particular order) DARPA, NAI
+Labs, ThinkSec, Nescafé, the Aberlour Glenlivet Distillery Co.,
+Suzanne Vega, and a Sanford's #69 Deluxe Marker.
+
+ -- des@FreeBSD.org
+
+$FreeBSD$
diff --git a/crypto/openssh/FREEBSD-vendor b/crypto/openssh/FREEBSD-vendor
new file mode 100644
index 0000000..0fa56d0
--- /dev/null
+++ b/crypto/openssh/FREEBSD-vendor
@@ -0,0 +1,6 @@
+# $FreeBSD$
+Project: Portable OpenSSH
+ProjectURL: http://www.openssh.com/portable.html
+Version: 5.2p1
+License: BSD
+Maintainer: des
diff --git a/crypto/openssh/INSTALL b/crypto/openssh/INSTALL
new file mode 100644
index 0000000..001ebb6
--- /dev/null
+++ b/crypto/openssh/INSTALL
@@ -0,0 +1,269 @@
+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.
+
+--with-opensc=DIR
+--with-sectok=DIR allows for OpenSC or sectok smartcard libraries to
+be used with OpenSSH. See 'README.smartcard' for more details.
+
+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.84 2007/08/17 12:52:05 dtucker Exp $
diff --git a/crypto/openssh/LICENCE b/crypto/openssh/LICENCE
new file mode 100644
index 0000000..3964b1d
--- /dev/null
+++ b/crypto/openssh/LICENCE
@@ -0,0 +1,338 @@
+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
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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/crypto/openssh/OVERVIEW b/crypto/openssh/OVERVIEW
new file mode 100644
index 0000000..2e1cc0b
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/PROTOCOL b/crypto/openssh/PROTOCOL
new file mode 100644
index 0000000..5aada63
--- /dev/null
+++ b/crypto/openssh/PROTOCOL
@@ -0,0 +1,254 @@
+This documents OpenSSH's deviations and extensions to the published SSH
+protocol.
+
+Note that OpenSSH's sftp and sftp-server implement revision 3 of the SSH
+filexfer protocol described in:
+
+http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
+
+Features from newer versions of the draft are not supported, unless
+explicitly implemented as extensions described below.
+
+The protocol used by OpenSSH's ssh-agent is described in the file
+PROTOCOL.agent
+
+1. transport: Protocol 2 MAC algorithm "umac-64@openssh.com"
+
+This is a new transport-layer MAC method using the UMAC algorithm
+(rfc4418). This method is identical to the "umac-64" method documented
+in:
+
+http://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
+
+2. transport: Protocol 2 compression algorithm "zlib@openssh.com"
+
+This transport-layer compression method uses the zlib compression
+algorithm (identical to the "zlib" method in rfc4253), but delays the
+start of compression until after authentication has completed. This
+avoids exposing compression code to attacks from unauthenticated users.
+
+The method is documented in:
+
+http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
+
+3. connection: Channel write close extension "eow@openssh.com"
+
+The SSH connection protocol (rfc4254) provides the SSH_MSG_CHANNEL_EOF
+message to allow an endpoint to signal its peer that it will send no
+more data over a channel. Unfortunately, there is no symmetric way for
+an endpoint to request that its peer should cease sending data to it
+while still keeping the channel open for the endpoint to send data to
+the peer.
+
+This is desirable, since it saves the transmission of data that would
+otherwise need to be discarded and it allows an endpoint to signal local
+processes of the condition, e.g. by closing the corresponding file
+descriptor.
+
+OpenSSH implements a channel extension message to perform this
+signalling: "eow@openssh.com" (End Of Write). This message is sent by
+an endpoint when the local output of a session channel is closed or
+experiences a write error. The message is formatted as follows:
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "eow@openssh.com"
+ boolean FALSE
+
+On receiving this message, the peer SHOULD cease sending data of
+the channel and MAY signal the process from which the channel data
+originates (e.g. by closing its read file descriptor).
+
+As with the symmetric SSH_MSG_CHANNEL_EOF message, the channel does
+remain open after a "eow@openssh.com" has been sent and more data may
+still be sent in the other direction. This message does not consume
+window space and may be sent even if no window space is available.
+
+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.
+
+4. connection: disallow additional sessions extension
+ "no-more-sessions@openssh.com"
+
+Most SSH connections will only ever request a single session, but a
+attacker may abuse a running ssh client to surreptitiously open
+additional sessions under their control. OpenSSH provides a global
+request "no-more-sessions@openssh.com" to mitigate this attack.
+
+When an OpenSSH client expects that it will never open another session
+(i.e. it has been started with connection multiplexing disabled), it
+will send the following global request:
+
+ byte SSH_MSG_GLOBAL_REQUEST
+ string "no-more-sessions@openssh.com"
+ char want-reply
+
+On receipt of such a message, an OpenSSH server will refuse to open
+future channels of type "session" and instead immediately abort the
+connection.
+
+Note that this is not a general defence against compromised clients
+(that is impossible), but it thwarts a simple attack.
+
+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.
+
+5. connection: Tunnel forward extension "tun@openssh.com"
+
+OpenSSH supports layer 2 and layer 3 tunnelling via the "tun@openssh.com"
+channel type. This channel type supports forwarding of network packets
+with datagram boundaries intact between endpoints equipped with
+interfaces like the BSD tun(4) device. Tunnel forwarding channels are
+requested by the client with the following packet:
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "tun@openssh.com"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ uint32 tunnel mode
+ uint32 remote unit number
+
+The "tunnel mode" parameter specifies whether the tunnel should forward
+layer 2 frames or layer 3 packets. It may take one of the following values:
+
+ SSH_TUNMODE_POINTOPOINT 1 /* layer 3 packets */
+ SSH_TUNMODE_ETHERNET 2 /* layer 2 frames */
+
+The "tunnel unit number" specifies the remote interface number, or may
+be zero to allow the server to automatically chose an interface. A server
+that is not willing to open a client-specified unit should refuse the
+request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful open,
+the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS.
+
+Once established the client and server may exchange packet or frames
+over the tunnel channel by encapsulating them in SSH protocol strings
+and sending them as channel data. This ensures that packet boundaries
+are kept intact. Specifically, packets are transmitted using normal
+SSH_MSG_CHANNEL_DATA packets:
+
+ byte SSH_MSG_CHANNEL_DATA
+ uint32 recipient channel
+ string data
+
+The contents of the "data" field for layer 3 packets is:
+
+ uint32 packet length
+ uint32 address family
+ byte[packet length - 4] packet data
+
+The "address family" field identifies the type of packet in the message.
+It may be one of:
+
+ SSH_TUN_AF_INET 2 /* IPv4 */
+ SSH_TUN_AF_INET6 24 /* IPv6 */
+
+The "packet data" field consists of the IPv4/IPv6 datagram itself
+without any link layer header.
+
+The contents of the "data" field for layer 3 packets is:
+
+ uint32 packet length
+ byte[packet length] frame
+
+The "frame" field contains an IEEE 802.3 Ethernet frame, including
+header.
+
+6. sftp: Reversal of arguments to SSH_FXP_SYMLINK
+
+When OpenSSH's sftp-server was implemented, the order of the arguments
+to the SSH_FXP_SYMLINK method was inadvertently reversed. Unfortunately,
+the reversal was not noticed until the server was widely deployed. Since
+fixing this to follow the specification would cause incompatibility, the
+current order was retained. For correct operation, clients should send
+SSH_FXP_SYMLINK as follows:
+
+ uint32 id
+ string targetpath
+ string linkpath
+
+7. sftp: Server extension announcement in SSH_FXP_VERSION
+
+OpenSSH's sftp-server lists the extensions it supports using the
+standard extension announcement mechanism in the SSH_FXP_VERSION server
+hello packet:
+
+ uint32 3 /* protocol version */
+ string ext1-name
+ string ext1-version
+ string ext2-name
+ string ext2-version
+ ...
+ string extN-name
+ string extN-version
+
+Each extension reports its integer version number as an ASCII encoded
+string, e.g. "1". The version will be incremented if the extension is
+ever changed in an incompatible way. The server MAY advertise the same
+extension with multiple versions (though this is unlikely). Clients MUST
+check the version number before attempting to use the extension.
+
+8. sftp: Extension request "posix-rename@openssh.com"
+
+This operation provides a rename operation with POSIX semantics, which
+are different to those provided by the standard SSH_FXP_RENAME in
+draft-ietf-secsh-filexfer-02.txt. This request is implemented as a
+SSH_FXP_EXTENDED request with the following format:
+
+ uint32 id
+ string "posix-rename@openssh.com"
+ string oldpath
+ string newpath
+
+On receiving this request the server will perform the POSIX operation
+rename(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+9. sftp: Extension requests "statvfs@openssh.com" and
+ "fstatvfs@openssh.com"
+
+These requests correspond to the statvfs and fstatvfs POSIX system
+interfaces. The "statvfs@openssh.com" request operates on an explicit
+pathname, and is formatted as follows:
+
+ uint32 id
+ string "statvfs@openssh.com"
+ string path
+
+The "fstatvfs@openssh.com" operates on an open file handle:
+
+ uint32 id
+ string "fstatvfs@openssh.com"
+ string handle
+
+These requests return a SSH_FXP_STATUS reply on failure. On success they
+return the following SSH_FXP_EXTENDED_REPLY reply:
+
+ uint32 id
+ uint64 f_bsize /* file system block size */
+ uint64 f_frsize /* fundamental fs block size */
+ uint64 f_blocks /* number of blocks (unit f_frsize) */
+ uint64 f_bfree /* free blocks in file system */
+ uint64 f_bavail /* free blocks for non-root */
+ uint64 f_files /* total file inodes */
+ uint64 f_ffree /* free file inodes */
+ uint64 f_favail /* free file inodes for to non-root */
+ uint64 f_fsid /* file system id */
+ uint64 f_flag /* bit mask of f_flag values */
+ uint64 f_namemax /* maximum filename length */
+
+The values of the f_flag bitmask are as follows:
+
+ #define SSH_FXE_STATVFS_ST_RDONLY 0x1 /* read-only */
+ #define SSH_FXE_STATVFS_ST_NOSUID 0x2 /* no setuid */
+
+Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
+advertised in the SSH_FXP_VERSION hello with version "2".
+
+$OpenBSD: PROTOCOL,v 1.12 2009/02/14 06:35:49 djm Exp $
diff --git a/crypto/openssh/PROTOCOL.agent b/crypto/openssh/PROTOCOL.agent
new file mode 100644
index 0000000..49adbdd
--- /dev/null
+++ b/crypto/openssh/PROTOCOL.agent
@@ -0,0 +1,516 @@
+This describes the protocol used by OpenSSH's ssh-agent.
+
+OpenSSH's agent supports managing keys for the standard SSH protocol
+2 as well as the legacy SSH protocol 1. Support for these key types
+is almost completely disjoint - in all but a few cases, operations on
+protocol 2 keys cannot see or affect protocol 1 keys and vice-versa.
+
+Protocol 1 and protocol 2 keys are separated because of the differing
+cryptographic usage: protocol 1 private RSA keys are used to decrypt
+challenges that were encrypted with the corresponding public key,
+whereas protocol 2 RSA private keys are used to sign challenges with
+a private key for verification with the corresponding public key. It
+is considered unsound practice to use the same key for signing and
+encryption.
+
+With a couple of exceptions, the protocol message names used in this
+document indicate which type of key the message relates to. SSH_*
+messages refer to protocol 1 keys only. SSH2_* messages refer to
+protocol 2 keys. Furthermore, the names also indicate whether the
+message is a request to the agent (*_AGENTC_*) or a reply from the
+agent (*_AGENT_*). Section 3 below contains the mapping of the
+protocol message names to their integer values.
+
+1. Data types
+
+Because of support for legacy SSH protocol 1 keys, OpenSSH's agent
+protocol makes use of some data types not defined in RFC 4251.
+
+1.1 uint16
+
+The "uint16" data type is a simple MSB-first 16 bit unsigned integer
+encoded in two bytes.
+
+1.2 mpint1
+
+The "mpint1" type represents an arbitrary precision integer (bignum).
+Its format is as follows:
+
+ uint16 bits
+ byte[(bits + 7) / 8] bignum
+
+"bignum" contains an unsigned arbitrary precision integer encoded as
+eight bits per byte in big-endian (MSB first) format.
+
+Note the difference between the "mpint1" encoding and the "mpint"
+encoding defined in RFC 4251. Also note that the length of the encoded
+integer is specified in bits, not bytes and that the byte length of
+the integer must be calculated by rounding up the number of bits to the
+nearest eight.
+
+2. Protocol Messages
+
+All protocol messages are prefixed with their length in bytes, encoded
+as a 32 bit unsigned integer. Specifically:
+
+ uint32 message_length
+ byte[message_length] message
+
+The following message descriptions refer only to the content the
+"message" field.
+
+2.1 Generic server responses
+
+The following generic messages may be sent by the server in response to
+requests from the client. On success the agent may reply either with:
+
+ byte SSH_AGENT_SUCCESS
+
+or a request-specific success message.
+
+On failure, the agent may reply with:
+
+ byte SSH_AGENT_FAILURE
+
+SSH_AGENT_FAILURE messages are also sent in reply to unknown request
+types.
+
+2.2 Adding keys to the agent
+
+Keys are added to the agent using the SSH_AGENTC_ADD_RSA_IDENTITY and
+SSH2_AGENTC_ADD_IDENTITY requests for protocol 1 and protocol 2 keys
+respectively.
+
+Two variants of these requests are SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+and SSH2_AGENTC_ADD_ID_CONSTRAINED - these add keys with optional
+"constraints" on their usage.
+
+OpenSSH may be built with support for keys hosted on a smartcard
+or other hardware security module. These keys may be added
+to the agent using the SSH_AGENTC_ADD_SMARTCARD_KEY and
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED requests.
+
+2.2.1 Key constraints
+
+The OpenSSH agent supports some basic optional constraints on key usage.
+At present there are two constraints defined.
+
+The first constraint limits the validity duration of a key. It is
+encoded as:
+
+ byte SSH_AGENT_CONSTRAIN_LIFETIME
+ uint32 seconds
+
+Where "seconds" contains the number of seconds that the key shall remain
+valid measured from the moment that the agent receives it. After the
+validity period has expired, OpenSSH's agent will erase these keys from
+memory.
+
+The second constraint requires the agent to seek explicit user
+confirmation before performing private key operations with the loaded
+key. This constraint is encoded as:
+
+ byte SSH_AGENT_CONSTRAIN_CONFIRM
+
+Zero or more constraints may be specified when adding a key with one
+of the *_CONSTRAINED requests. Multiple constraints are appended
+consecutively to the end of the request:
+
+ byte constraint1_type
+ .... constraint1_data
+ byte constraint2_type
+ .... constraint2_data
+ ....
+ byte constraintN_type
+ .... constraintN_data
+
+Such a sequence of zero or more constraints will be referred to below
+as "constraint[]". Agents may determine whether there are constraints
+by checking whether additional data exists in the "add key" request
+after the key data itself. OpenSSH will refuse to add a key if it
+contains unknown constraints.
+
+2.2.2 Add protocol 1 key
+
+A client may add a protocol 1 key to an agent with the following
+request:
+
+ byte SSH_AGENTC_ADD_RSA_IDENTITY or
+ SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
+ uint32 ignored
+ mpint1 rsa_n
+ mpint1 rsa_e
+ mpint1 rsa_d
+ mpint1 rsa_iqmp
+ mpint1 rsa_q
+ mpint1 rsa_p
+ string key_comment
+ constraint[] key_constraints
+
+Note that there is some redundancy in the key parameters; a key could be
+fully specified using just rsa_q, rsa_p and rsa_e at the cost of extra
+computation.
+
+"key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_RSA_IDENTITY.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.3 Add protocol 2 key
+
+The OpenSSH agent supports DSA and RSA keys for protocol 2. DSA keys may
+be added using the following request
+
+ byte SSH2_AGENTC_ADD_IDENTITY or
+ SSH2_AGENTC_ADD_ID_CONSTRAINED
+ string "ssh-dss"
+ mpint dsa_p
+ mpint dsa_q
+ mpint dsa_g
+ mpint dsa_public_key
+ mpint dsa_private_key
+ string key_comment
+ constraint[] key_constraints
+
+RSA keys may be added with this request:
+
+ byte SSH2_AGENTC_ADD_IDENTITY or
+ SSH2_AGENTC_ADD_ID_CONSTRAINED
+ string "ssh-rsa"
+ mpint rsa_n
+ mpint rsa_e
+ mpint rsa_d
+ mpint rsa_iqmp
+ mpint rsa_p
+ mpint rsa_q
+ string key_comment
+ constraint[] key_constraints
+
+Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
+order to the protocol 1 add keys message. As with the corresponding
+protocol 1 "add key" request, the private key is overspecified to avoid
+redundant processing.
+
+For both DSA and RSA key add requests, "key_constraints" may only be
+present if the request type is SSH2_AGENTC_ADD_ID_CONSTRAINED.
+
+The agent will reply with a SSH_AGENT_SUCCESS if the key has been
+successfully added or a SSH_AGENT_FAILURE if an error occurred.
+
+2.2.4 Loading keys from a smartcard
+
+The OpenSSH agent may have optional smartcard support built in to it. If
+so, it supports an operation to load keys from a smartcard. Technically,
+only the public components of the keys are loaded into the agent so
+this operation really arranges for future private key operations to be
+delegated to the smartcard.
+
+ byte SSH_AGENTC_ADD_SMARTCARD_KEY or
+ SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
+ string reader_id
+ string pin
+ constraint[] key_constraints
+
+"reader_id" is an identifier to a smartcard reader and "pin"
+is a PIN or passphrase used to unlock the private key(s) on the
+device. "key_constraints" may only be present if the request type is
+SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED.
+
+This operation may load all SSH keys that are unlocked using the
+"pin" on the specified reader. The type of key loaded (protocol 1
+or protocol 2) will be specified by the smartcard itself, it is not
+client-specified.
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully loaded or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.3 Removing multiple keys
+
+A client may request that an agent delete all protocol 1 keys using the
+following request:
+
+ byte SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES
+
+This message requests the deletion of all protocol 2 keys:
+
+ byte SSH2_AGENTC_REMOVE_ALL_IDENTITIES
+
+On success, the agent will delete all keys of the requested type and
+reply with a SSH_AGENT_SUCCESS message. If an error occurred, the agent
+will reply with SSH_AGENT_FAILURE.
+
+Note that, to delete all keys (both protocol 1 and 2), a client
+must send both a SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES and a
+SSH2_AGENTC_REMOVE_ALL_IDENTITIES request.
+
+2.4 Removing specific keys
+
+2.4.1 Removing a protocol 1 key
+
+Removal of a protocol 1 key may be requested with the following message:
+
+ byte SSH_AGENTC_REMOVE_RSA_IDENTITY
+ uint32 key_bits
+ mpint1 rsa_e
+ mpint1 rsa_n
+
+Note that key_bits is strictly redundant, as it may be inferred by the
+length of rsa_n.
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.2 Removing a protocol 2 key
+
+Protocol 2 keys may be removed with the following request:
+
+ byte SSH2_AGENTC_REMOVE_IDENTITY
+ string key_blob
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa".
+
+The agent will delete any private key matching the specified public key
+and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
+return SSH_AGENT_FAILURE.
+
+2.4.3 Removing keys loaded from a smartcard
+
+A client may request that a server remove one or more smartcard-hosted
+keys using this message:
+
+ byte SSH_AGENTC_REMOVE_SMARTCARD_KEY
+ string reader_id
+ string pin
+
+"reader_id" the an identifier to a smartcard reader and "pin" is a PIN
+or passphrase used to unlock the private key(s) on the device.
+
+When this message is received, and if the agent supports
+smartcard-hosted keys, it will delete all keys that are hosted on the
+specified smartcard that may be accessed with the given "pin".
+
+The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
+been successfully removed or a SSH_AGENT_FAILURE if an error occurred.
+The agent will also return SSH_AGENT_FAILURE if it does not support
+smartcards.
+
+2.5 Requesting a list of known keys
+
+An agent may be requested to list which keys it holds. Different
+requests exist for protocol 1 and protocol 2 keys.
+
+2.5.1 Requesting a list of protocol 1 keys
+
+To request a list of protocol 1 keys that are held in the agent, a
+client may send the following message:
+
+ byte SSH_AGENTC_REQUEST_RSA_IDENTITIES
+
+The agent will reply with the following message:
+
+ byte SSH_AGENT_RSA_IDENTITIES_ANSWER
+ uint32 num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+ uint32 bits
+ mpint1 rsa_e
+ mpint1 rsa_n
+ string key_comment
+
+2.5.2 Requesting a list of protocol 2 keys
+
+A client may send the following message to request a list of
+protocol 2 keys that are stored in the agent:
+
+ byte SSH2_AGENTC_REQUEST_IDENTITIES
+
+The agent will reply with the following message header:
+
+ byte SSH2_AGENT_IDENTITIES_ANSWER
+ uint32 num_keys
+
+Followed by zero or more consecutive keys, encoded as:
+
+ string key_blob
+ string key_comment
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa".
+
+2.6 Private key operations
+
+The purpose of the agent is to perform private key operations, such as
+signing and encryption without requiring a passphrase to unlock the
+key and without allowing the private key itself to be exposed. There
+are separate requests for the protocol 1 and protocol 2 private key
+operations.
+
+2.6.1 Protocol 1 private key challenge
+
+The private key operation used in version 1 of the SSH protocol is
+decrypting a challenge that has been encrypted with a public key.
+It may be requested using this message:
+
+ byte SSH_AGENTC_RSA_CHALLENGE
+ uint32 ignored
+ mpint1 rsa_e
+ mpint1 rsa_n
+ mpint1 encrypted_challenge
+ byte[16] session_id
+ uint32 response_type /* must be 1 */
+
+"rsa_e" and "rsa_n" are used to identify which private key to use.
+"encrypted_challenge" is a challenge blob that has (presumably)
+been encrypted with the public key and must be in the range
+1 <= encrypted_challenge < 2^256. "session_id" is the SSH protocol 1
+session ID (computed from the server host key, the server semi-ephemeral
+key and the session cookie).
+
+"ignored" and "response_type" exist for compatibility with legacy
+implementations. "response_type" must be equal to 1; other response
+types are not supported.
+
+On receiving this request, the server decrypts the "encrypted_challenge"
+using the private key matching the supplied (rsa_e, rsa_n) values. For
+the response derivation, the decrypted challenge is represented as an
+unsigned, big-endian integer encoded in a 32 byte buffer (i.e. values
+smaller than 2^248 will have leading 0 bytes).
+
+The response value is then calculated as:
+
+ response = MD5(decrypted_challenge || session_id)
+
+and returned in the following message
+
+ byte SSH_AGENT_RSA_RESPONSE
+ byte[16] response
+
+If the agent cannot find the key specified by the supplied (rsa_e,
+rsa_n) then it will return SSH_AGENT_FAILURE.
+
+2.6.2 Protocol 2 private key signature request
+
+A client may use the following message to request signing of data using
+a protocol 2 key:
+
+ byte SSH2_AGENTC_SIGN_REQUEST
+ string key_blob
+ string data
+ uint32 flags
+
+Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
+Algorithms" for either of the supported key types: "ssh-dss" or
+"ssh-rsa". "flags" is a bit-mask, but at present only one possible value
+is defined (see below for its meaning):
+
+ SSH_AGENT_OLD_SIGNATURE 1
+
+Upon receiving this request, the agent will look up the private key that
+corresponds to the public key contained in key_blob. It will use this
+private key to sign the "data" and produce a signature blob using the
+key type-specific method described in RFC 4253 section 6.6 "Public Key
+Algorithms".
+
+An exception to this is for "ssh-dss" keys where the "flags" word
+contains the value SSH_AGENT_OLD_SIGNATURE. In this case, a legacy
+signature encoding is used in lieu of the standard one. In this case,
+the DSA signature blob is encoded as:
+
+ byte[40] signature
+
+The signature will be returned in the response message:
+
+ byte SSH2_AGENT_SIGN_RESPONSE
+ string signature_blob
+
+If the agent cannot find the key specified by the supplied key_blob then
+it will return SSH_AGENT_FAILURE.
+
+2.7 Locking or unlocking an agent
+
+The agent supports temporary locking with a passphrase to suspend
+processing of sensitive operations until it has been unlocked with the
+same passphrase. To lock an agent, a client send the following request:
+
+ byte SSH_AGENTC_LOCK
+ string passphrase
+
+Upon receipt of this message and if the agent is not already locked,
+it will suspend processing requests and return a SSH_AGENT_SUCCESS
+reply. If the agent is already locked, it will return SSH_AGENT_FAILURE.
+
+While locked, the agent will refuse all requests except
+SSH_AGENTC_UNLOCK, SSH_AGENTC_REQUEST_RSA_IDENTITIES and
+SSH2_AGENTC_REQUEST_IDENTITIES. The "request identities" requests are
+treated specially by a locked agent: it will always return an empty list
+of keys.
+
+To unlock an agent, a client may request:
+
+ byte SSH_AGENTC_UNLOCK
+ string passphrase
+
+If the passphrase matches and the agent is locked, then it will resume
+processing all requests and return SSH_AGENT_SUCCESS. If the agent
+is not locked or the passphrase does not match then it will return
+SSH_AGENT_FAILURE.
+
+Locking and unlocking affects both protocol 1 and protocol 2 keys.
+
+3. Protocol message numbers
+
+3.1 Requests from client to agent for protocol 1 key operations
+
+ SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
+ SSH_AGENTC_RSA_CHALLENGE 3
+ SSH_AGENTC_ADD_RSA_IDENTITY 7
+ SSH_AGENTC_REMOVE_RSA_IDENTITY 8
+ SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
+ SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24
+
+3.2 Requests from client to agent for protocol 2 key operations
+
+ SSH2_AGENTC_REQUEST_IDENTITIES 11
+ SSH2_AGENTC_SIGN_REQUEST 13
+ SSH2_AGENTC_ADD_IDENTITY 17
+ SSH2_AGENTC_REMOVE_IDENTITY 18
+ SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
+ SSH2_AGENTC_ADD_ID_CONSTRAINED 25
+
+3.3 Key-type independent requests from client to agent
+
+ SSH_AGENTC_ADD_SMARTCARD_KEY 20
+ SSH_AGENTC_REMOVE_SMARTCARD_KEY 21
+ SSH_AGENTC_LOCK 22
+ SSH_AGENTC_UNLOCK 23
+ SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
+
+3.4 Generic replies from agent to client
+
+ SSH_AGENT_FAILURE 5
+ SSH_AGENT_SUCCESS 6
+
+3.5 Replies from agent to client for protocol 1 key operations
+
+ SSH_AGENT_RSA_IDENTITIES_ANSWER 2
+ SSH_AGENT_RSA_RESPONSE 4
+
+3.6 Replies from agent to client for protocol 2 key operations
+
+ SSH2_AGENT_IDENTITIES_ANSWER 12
+ SSH2_AGENT_SIGN_RESPONSE 14
+
+3.7 Key constraint identifiers
+
+ SSH_AGENT_CONSTRAIN_LIFETIME 1
+ SSH_AGENT_CONSTRAIN_CONFIRM 2
+
+$OpenBSD: PROTOCOL.agent,v 1.4 2008/07/01 23:12:47 stevesk Exp $
diff --git a/crypto/openssh/README b/crypto/openssh/README
new file mode 100644
index 0000000..8538e8c
--- /dev/null
+++ b/crypto/openssh/README
@@ -0,0 +1,65 @@
+See http://www.openssh.com/txt/release-5.3 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.70.4.1 2009/09/26 04:11:47 djm Exp $
diff --git a/crypto/openssh/README.dns b/crypto/openssh/README.dns
new file mode 100644
index 0000000..9787918
--- /dev/null
+++ b/crypto/openssh/README.dns
@@ -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/crypto/openssh/README.platform b/crypto/openssh/README.platform
new file mode 100644
index 0000000..d198232
--- /dev/null
+++ b/crypto/openssh/README.platform
@@ -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/crypto/openssh/README.privsep b/crypto/openssh/README.privsep
new file mode 100644
index 0000000..f565e72
--- /dev/null
+++ b/crypto/openssh/README.privsep
@@ -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/crypto/openssh/README.smartcard b/crypto/openssh/README.smartcard
new file mode 100644
index 0000000..fdf83ec
--- /dev/null
+++ b/crypto/openssh/README.smartcard
@@ -0,0 +1,93 @@
+How to use smartcards with OpenSSH?
+
+OpenSSH contains experimental support for authentication using
+Cyberflex smartcards and TODOS card readers, in addition to the cards
+with PKCS#15 structure supported by OpenSC. To enable this you
+need to:
+
+Using libsectok:
+
+(1) enable sectok support in OpenSSH:
+
+ $ ./configure --with-sectok
+
+(2) If you have used a previous version of ssh with your card, you
+ must remove the old applet and keys.
+
+ $ sectok
+ sectok> login -d
+ sectok> junload Ssh.bin
+ sectok> delete 0012
+ sectok> delete sh
+ sectok> quit
+
+(3) load the Java Cardlet to the Cyberflex card and set card passphrase:
+
+ $ sectok
+ sectok> login -d
+ sectok> jload /usr/libdata/ssh/Ssh.bin
+ sectok> setpass
+ Enter new AUT0 passphrase:
+ Re-enter passphrase:
+ sectok> quit
+
+ Do not forget the passphrase. There is no way to
+ recover if you do.
+
+ IMPORTANT WARNING: If you attempt to login with the
+ wrong passphrase three times in a row, you will
+ destroy your card.
+
+(4) load a RSA key to the card:
+
+ $ ssh-keygen -f /path/to/rsakey -U 1
+ (where 1 is the reader number, you can also try 0)
+
+ In spite of the name, this does not generate a key.
+ It just loads an already existing key on to the card.
+
+(5) Optional: If you don't want to use a card passphrase, change the
+ acl on the private key file:
+
+ $ sectok
+ sectok> login -d
+ sectok> acl 0012 world: w
+ world: w
+ AUT0: w inval
+ sectok> quit
+
+ If you do this, anyone who has access to your card
+ can assume your identity. This is not recommended.
+
+
+Using OpenSC:
+
+(1) install OpenSC:
+
+ Sources and instructions are available from
+ http://www.opensc.org/
+
+(2) enable OpenSC support in OpenSSH:
+
+ $ ./configure --with-opensc[=/path/to/opensc] [options]
+
+(3) load a RSA key to the card:
+
+ Not supported yet.
+
+
+Common operations:
+
+(1) tell the ssh client to use the card reader:
+
+ $ ssh -I 1 otherhost
+
+(2) or tell the agent (don't forget to restart) to use the smartcard:
+
+ $ ssh-add -s 1
+
+
+-markus,
+Tue Jul 17 23:54:51 CEST 2001
+
+$OpenBSD: README.smartcard,v 1.9 2003/11/21 11:57:02 djm Exp $
diff --git a/crypto/openssh/README.tun b/crypto/openssh/README.tun
new file mode 100644
index 0000000..5e1cb07
--- /dev/null
+++ b/crypto/openssh/README.tun
@@ -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/crypto/openssh/TODO b/crypto/openssh/TODO
new file mode 100644
index 0000000..e8aaa4b
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/WARNING.RNG b/crypto/openssh/WARNING.RNG
new file mode 100644
index 0000000..97da74f
--- /dev/null
+++ b/crypto/openssh/WARNING.RNG
@@ -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/crypto/openssh/aclocal.m4 b/crypto/openssh/aclocal.m4
new file mode 100644
index 0000000..b68a470
--- /dev/null
+++ b/crypto/openssh/aclocal.m4
@@ -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/crypto/openssh/acss.c b/crypto/openssh/acss.c
new file mode 100644
index 0000000..86e2c01
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/acss.h b/crypto/openssh/acss.h
new file mode 100644
index 0000000..91b4895
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/addrmatch.c b/crypto/openssh/addrmatch.c
new file mode 100644
index 0000000..d39885b
--- /dev/null
+++ b/crypto/openssh/addrmatch.c
@@ -0,0 +1,424 @@
+/* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk 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;
+ 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;
+}
diff --git a/crypto/openssh/atomicio.c b/crypto/openssh/atomicio.c
new file mode 100644
index 0000000..a6b2d12
--- /dev/null
+++ b/crypto/openssh/atomicio.c
@@ -0,0 +1,142 @@
+/* $OpenBSD: atomicio.c,v 1.25 2007/06/25 12:02:27 dtucker 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
+atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
+{
+ 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;
+ }
+ }
+ return (pos);
+}
+
+/*
+ * ensure all of data on socket comes through. f==readv || f==writev
+ */
+size_t
+atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
+ const struct iovec *_iov, int iovcnt)
+{
+ 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;
+ }
+ }
+ return pos;
+}
diff --git a/crypto/openssh/atomicio.h b/crypto/openssh/atomicio.h
new file mode 100644
index 0000000..2fcd25d
--- /dev/null
+++ b/crypto/openssh/atomicio.h
@@ -0,0 +1,45 @@
+/* $OpenBSD: atomicio.h,v 1.10 2006/08/03 03:34:41 deraadt 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 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 atomiciov(ssize_t (*)(int, const struct iovec *, int),
+ int, const struct iovec *, int);
+
+#endif /* _ATOMICIO_H */
diff --git a/crypto/openssh/audit-bsm.c b/crypto/openssh/audit-bsm.c
new file mode 100644
index 0000000..2c417bc
--- /dev/null
+++ b/crypto/openssh/audit-bsm.c
@@ -0,0 +1,380 @@
+/* $Id: audit-bsm.c,v 1.6 2008/02/25 10:05:04 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(const char *ttyn)
+{
+ /* not implemented */
+}
+
+void
+audit_session_close(const char *ttyn)
+{
+ /* 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/crypto/openssh/audit.c b/crypto/openssh/audit.c
new file mode 100644
index 0000000..dbea34c
--- /dev/null
+++ b/crypto/openssh/audit.c
@@ -0,0 +1,186 @@
+/* $Id: audit.c,v 1.5 2006/09/01 05:38:36 djm 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(const char *ttyn)
+{
+ const char *t = ttyn ? ttyn : "(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(const char *ttyn)
+{
+ const char *t = ttyn ? ttyn : "(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/crypto/openssh/audit.h b/crypto/openssh/audit.h
new file mode 100644
index 0000000..695f723
--- /dev/null
+++ b/crypto/openssh/audit.h
@@ -0,0 +1,54 @@
+/* $Id: audit.h,v 1.3 2006/08/05 14:05:10 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
+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(const char *);
+void audit_session_close(const char *);
+void audit_run_command(const char *);
+ssh_audit_event_t audit_classify_auth(const char *);
+
+#endif /* _SSH_AUDIT_H */
diff --git a/crypto/openssh/auth-bsdauth.c b/crypto/openssh/auth-bsdauth.c
new file mode 100644
index 0000000..0b3262b
--- /dev/null
+++ b/crypto/openssh/auth-bsdauth.c
@@ -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/crypto/openssh/auth-chall.c b/crypto/openssh/auth-chall.c
new file mode 100644
index 0000000..919b1ea
--- /dev/null
+++ b/crypto/openssh/auth-chall.c
@@ -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/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c
new file mode 100644
index 0000000..8682881
--- /dev/null
+++ b/crypto/openssh/auth-krb5.c
@@ -0,0 +1,249 @@
+/* $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;
+
+ temporarily_use_uid(authctxt->pw);
+
+ problem = krb5_init(authctxt);
+ if (problem)
+ goto out;
+
+ problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
+ &authctxt->krb5_user);
+ if (problem)
+ goto out;
+
+#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,
+ authctxt->pw->pw_name)) {
+ 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 (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/crypto/openssh/auth-options.c b/crypto/openssh/auth-options.c
new file mode 100644
index 0000000..ab085c2
--- /dev/null
+++ b/crypto/openssh/auth-options.c
@@ -0,0 +1,376 @@
+/* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 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 "auth-options.h"
+#include "servconf.h"
+#include "misc.h"
+#include "key.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;
+
+/* "command=" option. */
+char *forced_command = NULL;
+
+/* "environment=" options. */
+struct envstring *custom_environment = NULL;
+
+/* "tunnel=" option. */
+int forced_tun_device = -1;
+
+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;
+ 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;
+ }
+ forced_tun_device = -1;
+ channel_clear_permitted_opens();
+ auth_debug_reset();
+}
+
+/*
+ * return 1 if access is granted, 0 if not.
+ * side effect: sets key option flags
+ */
+int
+auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
+{
+ const char *cp;
+ int i;
+
+ /* reset options */
+ auth_clear_options();
+
+ if (!opts)
+ return 1;
+
+ while (*opts && *opts != ' ' && *opts != '\t') {
+ cp = "no-port-forwarding";
+ if (strncasecmp(opts, cp, strlen(cp)) == 0) {
+ 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);
+ 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: %.900s", forced_command);
+ 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. */
+ }
+
+ if (!use_privsep)
+ auth_debug_send();
+
+ /* 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);
+
+ if (!use_privsep)
+ auth_debug_send();
+
+ /* deny access */
+ return 0;
+}
diff --git a/crypto/openssh/auth-options.h b/crypto/openssh/auth-options.h
new file mode 100644
index 0000000..14488f7
--- /dev/null
+++ b/crypto/openssh/auth-options.h
@@ -0,0 +1,37 @@
+/* $OpenBSD: auth-options.h,v 1.17 2008/03/26 21:28:14 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;
+
+int auth_parse_options(struct passwd *, char *, char *, u_long);
+void auth_clear_options(void);
+
+#endif
diff --git a/crypto/openssh/auth-pam.c b/crypto/openssh/auth-pam.c
new file mode 100644
index 0000000..fc79dee
--- /dev/null
+++ b/crypto/openssh/auth-pam.c
@@ -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$ */
+#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/crypto/openssh/auth-pam.h b/crypto/openssh/auth-pam.h
new file mode 100644
index 0000000..a1a2b52
--- /dev/null
+++ b/crypto/openssh/auth-pam.h
@@ -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/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c
new file mode 100644
index 0000000..b1c6ce0
--- /dev/null
+++ b/crypto/openssh/auth-passwd.c
@@ -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/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c
new file mode 100644
index 0000000..eca7502
--- /dev/null
+++ b/crypto/openssh/auth-rh-rsa.c
@@ -0,0 +1,100 @@
+/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt 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;
+
+ /* 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/crypto/openssh/auth-rhosts.c b/crypto/openssh/auth-rhosts.c
new file mode 100644
index 0000000..5c12967
--- /dev/null
+++ b/crypto/openssh/auth-rhosts.c
@@ -0,0 +1,327 @@
+/* $OpenBSD: auth-rhosts.c,v 1.43 2008/06/13 14:18:51 dtucker Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * 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)
+{
+ int ret;
+
+ auth_debug_reset();
+ ret = auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
+ if (!use_privsep)
+ auth_debug_send();
+ return ret;
+}
diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c
new file mode 100644
index 0000000..bf54620
--- /dev/null
+++ b/crypto/openssh/auth-rsa.c
@@ -0,0 +1,324 @@
+/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * 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 "auth-options.h"
+#include "pathnames.h"
+#include "log.h"
+#include "servconf.h"
+#include "key.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 (memcmp(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);
+
+ /* 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;
+
+ /* 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/crypto/openssh/auth-shadow.c b/crypto/openssh/auth-shadow.c
new file mode 100644
index 0000000..2190916
--- /dev/null
+++ b/crypto/openssh/auth-shadow.c
@@ -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/crypto/openssh/auth-sia.c b/crypto/openssh/auth-sia.c
new file mode 100644
index 0000000..a9e1c25
--- /dev/null
+++ b/crypto/openssh/auth-sia.c
@@ -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/crypto/openssh/auth-sia.h b/crypto/openssh/auth-sia.h
new file mode 100644
index 0000000..27cbb93
--- /dev/null
+++ b/crypto/openssh/auth-sia.h
@@ -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/crypto/openssh/auth-skey.c b/crypto/openssh/auth-skey.c
new file mode 100644
index 0000000..cb43dba
--- /dev/null
+++ b/crypto/openssh/auth-skey.c
@@ -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/crypto/openssh/auth.c b/crypto/openssh/auth.c
new file mode 100644
index 0000000..02f9175
--- /dev/null
+++ b/crypto/openssh/auth.c
@@ -0,0 +1,623 @@
+/* $OpenBSD: auth.c,v 1.80 2008/11/04 07:58: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 "includes.h"
+__RCSID("$FreeBSD$");
+
+#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 "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;
+ char *shell;
+ 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(passwd);
+#endif /* USE_LIBIAF */
+ if (locked) {
+ logit("User %.100s not allowed because account is locked",
+ pw->pw_name);
+ return 0;
+ }
+ }
+
+ /*
+ * Get the shell from the password data. An empty shell field is
+ * legal, and means /bin/sh.
+ */
+ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
+
+ /* deny if shell does not exists or is not executable */
+ if (stat(shell, &st) != 0) {
+ logit("User %.100s not allowed because shell %.100s does not exist",
+ pw->pw_name, 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);
+ return 0;
+ }
+
+ 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);
+}
+
+/* return ok if key exists in sysfile or userfile */
+HostStatus
+check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
+ const char *sysfile, const char *userfile)
+{
+ Key *found;
+ char *user_hostfile;
+ struct stat st;
+ HostStatus host_status;
+
+ /* Check if we know the host and its host key. */
+ found = key_new(key->type);
+ host_status = check_host_in_hostfile(sysfile, host, key, found, NULL);
+
+ if (host_status != HOST_OK && userfile != NULL) {
+ user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
+ if (options.strict_modes &&
+ (stat(user_hostfile, &st) == 0) &&
+ ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
+ (st.st_mode & 022) != 0)) {
+ logit("Authentication refused for %.100s: "
+ "bad owner or modes for %.200s",
+ pw->pw_name, user_hostfile);
+ } else {
+ temporarily_use_uid(pw);
+ host_status = check_host_in_hostfile(user_hostfile,
+ host, key, found, NULL);
+ restore_uid();
+ }
+ xfree(user_hostfile);
+ }
+ key_free(found);
+
+ debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ?
+ "ok" : "not found", host);
+ return host_status;
+}
+
+
+/*
+ * Check a given file for security. This is defined as all components
+ * of the path to the file must 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 passed 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;
+}
+
+FILE *
+auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
+{
+ char line[1024];
+ struct stat st;
+ int fd;
+ FILE *f;
+
+ /*
+ * Open the file containing the authorized keys
+ * Fail quietly if file does not exist
+ */
+ if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1)
+ return NULL;
+
+ if (fstat(fd, &st) < 0) {
+ close(fd);
+ return NULL;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ logit("User %s authorized keys %s is not a regular file",
+ pw->pw_name, file);
+ close(fd);
+ return NULL;
+ }
+ unset_nonblock(fd);
+ if ((f = fdopen(fd, "r")) == NULL) {
+ close(fd);
+ return NULL;
+ }
+ if (options.strict_modes &&
+ secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+ fclose(f);
+ logit("Authentication refused: %s", line);
+ return NULL;
+ }
+
+ return f;
+}
+
+struct passwd *
+getpwnamallow(const char *user)
+{
+#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());
+
+ pw = getpwnam(user);
+ 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_getpwclass(pw)) == 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);
+}
+
+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/crypto/openssh/auth.h b/crypto/openssh/auth.h
new file mode 100644
index 0000000..3a70f44
--- /dev/null
+++ b/crypto/openssh/auth.h
@@ -0,0 +1,202 @@
+/* $OpenBSD: auth.h,v 1.62 2008/11/04 08:22:12 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 *);
+
+FILE *auth_openkeyfile(const char *, struct passwd *, int);
+
+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_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/crypto/openssh/auth1.c b/crypto/openssh/auth1.c
new file mode 100644
index 0000000..1801661
--- /dev/null
+++ b/crypto/openssh/auth1.c
@@ -0,0 +1,437 @@
+/* $OpenBSD: auth1.c,v 1.73 2008/07/04 23:30:16 djm Exp $ */
+/*
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ *
+ * 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_string(&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.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_string(&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/crypto/openssh/auth2-chall.c b/crypto/openssh/auth2-chall.c
new file mode 100644
index 0000000..e6dbffe
--- /dev/null
+++ b/crypto/openssh/auth2-chall.c
@@ -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/crypto/openssh/auth2-gss.c b/crypto/openssh/auth2-gss.c
new file mode 100644
index 0000000..0e08d88
--- /dev/null
+++ b/crypto/openssh/auth2-gss.c
@@ -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/crypto/openssh/auth2-hostbased.c b/crypto/openssh/auth2-hostbased.c
new file mode 100644
index 0000000..041051c
--- /dev/null
+++ b/crypto/openssh/auth2-hostbased.c
@@ -0,0 +1,192 @@
+/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 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;
+ HostStatus host_status;
+ int len;
+
+ 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");
+
+ host_status = check_key_in_hostfiles(pw, key, lookup,
+ _PATH_SSH_SYSTEM_HOSTFILE,
+ options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
+
+ /* backward compat if no key has been found. */
+ if (host_status == HOST_NEW)
+ host_status = check_key_in_hostfiles(pw, key, lookup,
+ _PATH_SSH_SYSTEM_HOSTFILE2,
+ options.ignore_user_known_hosts ? NULL :
+ _PATH_SSH_USER_HOSTFILE2);
+
+ return (host_status == HOST_OK);
+}
+
+Authmethod method_hostbased = {
+ "hostbased",
+ userauth_hostbased,
+ &options.hostbased_authentication
+};
diff --git a/crypto/openssh/auth2-jpake.c b/crypto/openssh/auth2-jpake.c
new file mode 100644
index 0000000..5de5506
--- /dev/null
+++ b/crypto/openssh/auth2-jpake.c
@@ -0,0 +1,558 @@
+/* $OpenBSD: auth2-jpake.c,v 1.3 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.
+ */
+
+/*
+ * 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;
+ 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/crypto/openssh/auth2-kbdint.c b/crypto/openssh/auth2-kbdint.c
new file mode 100644
index 0000000..fae67da
--- /dev/null
+++ b/crypto/openssh/auth2-kbdint.c
@@ -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/crypto/openssh/auth2-none.c b/crypto/openssh/auth2-none.c
new file mode 100644
index 0000000..08f2f93
--- /dev/null
+++ b/crypto/openssh/auth2-none.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: auth2-none.c,v 1.15 2008/07/02 12:36:39 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.password_authentication)
+ return (PRIVSEP(auth_password(authctxt, "")));
+ return (0);
+}
+
+Authmethod method_none = {
+ "none",
+ userauth_none,
+ &none_enabled
+};
diff --git a/crypto/openssh/auth2-passwd.c b/crypto/openssh/auth2-passwd.c
new file mode 100644
index 0000000..5f1f363
--- /dev/null
+++ b/crypto/openssh/auth2-passwd.c
@@ -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/crypto/openssh/auth2-pubkey.c b/crypto/openssh/auth2-pubkey.c
new file mode 100644
index 0000000..2886f12
--- /dev/null
+++ b/crypto/openssh/auth2-pubkey.c
@@ -0,0 +1,274 @@
+/* $OpenBSD: auth2-pubkey.c,v 1.19 2008/07/03 21:46:58 otto 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 <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"
+
+/* 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;
+}
+
+/* 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];
+ 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->type);
+
+ while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+ char *cp, *key_options = NULL;
+
+ /* 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_equal(found, key) &&
+ auth_parse_options(pw, key_options, file, linenum) == 1) {
+ 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;
+}
+
+/* check whether given key is in .ssh/authorized_keys* */
+int
+user_key_allowed(struct passwd *pw, Key *key)
+{
+ int success;
+ char *file;
+
+ file = authorized_keys_file(pw);
+ success = user_key_allowed2(pw, key, file);
+ xfree(file);
+ if (success)
+ return success;
+
+ /* try suffix "2" for backward compat, too */
+ file = authorized_keys_file2(pw);
+ success = user_key_allowed2(pw, key, file);
+ xfree(file);
+ return success;
+}
+
+Authmethod method_pubkey = {
+ "publickey",
+ userauth_pubkey,
+ &options.pubkey_authentication
+};
diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c
new file mode 100644
index 0000000..50fb339
--- /dev/null
+++ b/crypto/openssh/auth2.c
@@ -0,0 +1,437 @@
+/* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+__RCSID("$FreeBSD$");
+
+#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"
+#include "canohost.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_string(&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;
+#ifdef HAVE_LOGIN_CAP
+ login_cap_t *lc;
+ const char *from_host, *from_ip;
+
+ from_host = get_canonical_hostname(options.use_dns);
+ from_ip = get_remote_ipaddr();
+#endif
+
+ if (authctxt == NULL)
+ fatal("input_userauth_request: no authctxt");
+
+ user = packet_get_string(NULL);
+ service = packet_get_string(NULL);
+ method = packet_get_string(NULL);
+ debug("userauth-request for user %s service %s method %s", user, service, method);
+ debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
+
+ if ((style = strchr(user, ':')) != NULL)
+ *style++ = 0;
+
+ if (authctxt->attempt++ == 0) {
+ /* setup auth context */
+ 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);
+ }
+
+#ifdef HAVE_LOGIN_CAP
+ if (authctxt->pw != NULL) {
+ lc = login_getpwclass(authctxt->pw);
+ if (lc == NULL)
+ lc = login_getclassbyname(NULL, authctxt->pw);
+ if (!auth_hostok(lc, from_host, from_ip)) {
+ logit("Denied connection for %.200s from %.200s [%.200s].",
+ authctxt->pw->pw_name, from_host, from_ip);
+ packet_disconnect("Sorry, you are not allowed to connect.");
+ }
+ if (!auth_timeok(lc, time(NULL))) {
+ logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
+ authctxt->pw->pw_name, from_host);
+ packet_disconnect("Logins not available right now.");
+ }
+ login_close(lc);
+ lc = NULL;
+ }
+#endif /* HAVE_LOGIN_CAP */
+
+ /* 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/crypto/openssh/authfd.c b/crypto/openssh/authfd.c
new file mode 100644
index 0000000..61faad1
--- /dev/null
+++ b/crypto/openssh/authfd.c
@@ -0,0 +1,671 @@
+/* $OpenBSD: authfd.c,v 1.80 2006/08/03 03:34:41 deraadt 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_DSA:
+ buffer_put_bignum2(b, key->dsa->p);
+ buffer_put_bignum2(b, key->dsa->q);
+ buffer_put_bignum2(b, key->dsa->g);
+ buffer_put_bignum2(b, key->dsa->pub_key);
+ buffer_put_bignum2(b, key->dsa->priv_key);
+ break;
+ }
+ buffer_put_cstring(b, comment);
+}
+
+/*
+ * Adds an identity to the authentication server. This call is not meant to
+ * be used by normal applications.
+ */
+
+int
+ssh_add_identity_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_DSA:
+ 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);
+}
+
+int
+ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment)
+{
+ return ssh_add_identity_constrained(auth, key, comment, 0, 0);
+}
+
+/*
+ * Removes an identity from the authentication server. This call is not
+ * meant to be used by normal applications.
+ */
+
+int
+ssh_remove_identity(AuthenticationConnection *auth, Key *key)
+{
+ Buffer msg;
+ int type;
+ u_char *blob;
+ u_int blen;
+
+ buffer_init(&msg);
+
+ if (key->type == KEY_RSA1) {
+ buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY);
+ buffer_put_int(&msg, BN_num_bits(key->rsa->n));
+ buffer_put_bignum(&msg, key->rsa->e);
+ buffer_put_bignum(&msg, key->rsa->n);
+ } else if (key->type == KEY_DSA || key->type == KEY_RSA) {
+ key_to_blob(key, &blob, &blen);
+ buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY);
+ buffer_put_string(&msg, blob, blen);
+ xfree(blob);
+ } else {
+ buffer_free(&msg);
+ return 0;
+ }
+ if (ssh_request_reply(auth, &msg, &msg) == 0) {
+ buffer_free(&msg);
+ return 0;
+ }
+ type = buffer_get_char(&msg);
+ buffer_free(&msg);
+ return decode_reply(type);
+}
+
+int
+ssh_update_card(AuthenticationConnection *auth, int add,
+ const char *reader_id, 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/crypto/openssh/authfd.h b/crypto/openssh/authfd.h
new file mode 100644
index 0000000..3da2561
--- /dev/null
+++ b/crypto/openssh/authfd.h
@@ -0,0 +1,95 @@
+/* $OpenBSD: authfd.h,v 1.36 2006/08/03 03:34:41 deraadt 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(AuthenticationConnection *, Key *, const char *);
+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/crypto/openssh/authfile.c b/crypto/openssh/authfile.c
new file mode 100644
index 0000000..735c647
--- /dev/null
+++ b/crypto/openssh/authfile.c
@@ -0,0 +1,679 @@
+/* $OpenBSD: authfile.c,v 1.76 2006/08/03 03:34:41 deraadt 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>
+
+#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";
+
+/*
+ * Saves the authentication (private) key in a file, encrypting it with
+ * passphrase. The identification of the file (lowest 64 bits of n) will
+ * precede the key to provide identification of the key without needing a
+ * passphrase.
+ */
+
+static int
+key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
+ const char *comment)
+{
+ Buffer buffer, encrypted;
+ u_char buf[100], *cp;
+ int fd, 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);
+
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0) {
+ error("open %s failed: %s.", filename, strerror(errno));
+ buffer_free(&encrypted);
+ return 0;
+ }
+ if (atomicio(vwrite, fd, buffer_ptr(&encrypted),
+ buffer_len(&encrypted)) != buffer_len(&encrypted)) {
+ error("write to key file %s failed: %s", filename,
+ strerror(errno));
+ buffer_free(&encrypted);
+ close(fd);
+ unlink(filename);
+ return 0;
+ }
+ close(fd);
+ buffer_free(&encrypted);
+ return 1;
+}
+
+/* save SSH v2 key in OpenSSL PEM format */
+static int
+key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
+ const char *comment)
+{
+ FILE *fp;
+ int fd;
+ int success = 0;
+ int len = strlen(_passphrase);
+ u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
+ const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
+
+ if (len > 0 && len <= 4) {
+ error("passphrase too short: have %d bytes, need > 4", len);
+ return 0;
+ }
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0) {
+ error("open %s failed: %s.", filename, strerror(errno));
+ return 0;
+ }
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ error("fdopen %s failed: %s.", filename, strerror(errno));
+ close(fd);
+ return 0;
+ }
+ switch (key->type) {
+ case KEY_DSA:
+ success = PEM_write_DSAPrivateKey(fp, key->dsa,
+ cipher, passphrase, len, NULL, NULL);
+ break;
+ case KEY_RSA:
+ success = PEM_write_RSAPrivateKey(fp, key->rsa,
+ cipher, passphrase, len, NULL, NULL);
+ break;
+ }
+ fclose(fp);
+ return success;
+}
+
+int
+key_save_private(Key *key, const char *filename, const char *passphrase,
+ const char *comment)
+{
+ switch (key->type) {
+ case KEY_RSA1:
+ return key_save_private_rsa1(key, filename, passphrase,
+ comment);
+ case KEY_DSA:
+ case KEY_RSA:
+ return key_save_private_pem(key, filename, passphrase,
+ comment);
+ default:
+ break;
+ }
+ error("key_save_private: cannot save key type %d", key->type);
+ return 0;
+}
+
+/*
+ * Loads the public part of the ssh v1 key file. Returns NULL if an error was
+ * encountered (the file does not exist or is not readable), and the key
+ * otherwise.
+ */
+
+static Key *
+key_load_public_rsa1(int fd, const char *filename, char **commentp)
+{
+ Buffer buffer;
+ Key *pub;
+ struct stat st;
+ char *cp;
+ u_int i;
+ size_t len;
+
+ if (fstat(fd, &st) < 0) {
+ error("fstat for key file %.200s failed: %.100s",
+ filename, strerror(errno));
+ return NULL;
+ }
+ if (st.st_size > 1*1024*1024) {
+ error("key file %.200s too large", filename);
+ return NULL;
+ }
+ len = (size_t)st.st_size; /* truncated */
+
+ buffer_init(&buffer);
+ cp = buffer_append_space(&buffer, len);
+
+ if (atomicio(read, fd, cp, len) != len) {
+ debug("Read from key file %.200s failed: %.100s", filename,
+ strerror(errno));
+ buffer_free(&buffer);
+ return NULL;
+ }
+
+ /* Check that it is at least big enough to contain the ID string. */
+ if (len < sizeof(authfile_id_string)) {
+ debug3("Not a RSA1 key file %.200s.", filename);
+ buffer_free(&buffer);
+ return NULL;
+ }
+ /*
+ * Make sure it begins with the id string. Consume the id string
+ * from the buffer.
+ */
+ for (i = 0; i < sizeof(authfile_id_string); i++)
+ if (buffer_get_char(&buffer) != authfile_id_string[i]) {
+ debug3("Not a RSA1 key file %.200s.", filename);
+ buffer_free(&buffer);
+ return NULL;
+ }
+ /* Skip cipher type and reserved data. */
+ (void) buffer_get_char(&buffer); /* cipher type */
+ (void) buffer_get_int(&buffer); /* reserved */
+
+ /* Read the public key from the buffer. */
+ (void) buffer_get_int(&buffer);
+ pub = key_new(KEY_RSA1);
+ buffer_get_bignum(&buffer, pub->rsa->n);
+ buffer_get_bignum(&buffer, pub->rsa->e);
+ if (commentp)
+ *commentp = buffer_get_string(&buffer, NULL);
+ /* The encrypted private part is not parsed by this function. */
+
+ buffer_free(&buffer);
+ return pub;
+}
+
+/* load public key from private-key file, works only for SSH v1 */
+Key *
+key_load_public_type(int type, const char *filename, char **commentp)
+{
+ Key *pub;
+ int fd;
+
+ if (type == KEY_RSA1) {
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ pub = key_load_public_rsa1(fd, filename, commentp);
+ close(fd);
+ return pub;
+ }
+ return NULL;
+}
+
+/*
+ * Loads the private key from the file. Returns 0 if an error is encountered
+ * (file does not exist or is not readable, or passphrase is bad). This
+ * initializes the private key.
+ * Assumes we are called under uid of the owner of the file.
+ */
+
+static Key *
+key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
+ char **commentp)
+{
+ u_int i;
+ int check1, check2, cipher_type;
+ size_t len;
+ Buffer buffer, decrypted;
+ u_char *cp;
+ CipherContext ciphercontext;
+ Cipher *cipher;
+ Key *prv = NULL;
+ struct stat st;
+
+ if (fstat(fd, &st) < 0) {
+ error("fstat for key file %.200s failed: %.100s",
+ filename, strerror(errno));
+ close(fd);
+ return NULL;
+ }
+ if (st.st_size > 1*1024*1024) {
+ error("key file %.200s too large", filename);
+ close(fd);
+ return (NULL);
+ }
+ len = (size_t)st.st_size; /* truncated */
+
+ buffer_init(&buffer);
+ cp = buffer_append_space(&buffer, len);
+
+ if (atomicio(read, fd, cp, len) != len) {
+ debug("Read from key file %.200s failed: %.100s", filename,
+ strerror(errno));
+ buffer_free(&buffer);
+ close(fd);
+ return NULL;
+ }
+
+ /* Check that it is at least big enough to contain the ID string. */
+ if (len < sizeof(authfile_id_string)) {
+ debug3("Not a RSA1 key file %.200s.", filename);
+ buffer_free(&buffer);
+ close(fd);
+ return NULL;
+ }
+ /*
+ * Make sure it begins with the id string. Consume the id string
+ * from the buffer.
+ */
+ for (i = 0; i < sizeof(authfile_id_string); i++)
+ if (buffer_get_char(&buffer) != authfile_id_string[i]) {
+ debug3("Not a RSA1 key file %.200s.", filename);
+ buffer_free(&buffer);
+ close(fd);
+ return NULL;
+ }
+
+ /* Read cipher type. */
+ cipher_type = buffer_get_char(&buffer);
+ (void) buffer_get_int(&buffer); /* Reserved data. */
+
+ /* Read the public key from the buffer. */
+ (void) buffer_get_int(&buffer);
+ prv = key_new_private(KEY_RSA1);
+
+ buffer_get_bignum(&buffer, prv->rsa->n);
+ buffer_get_bignum(&buffer, prv->rsa->e);
+ if (commentp)
+ *commentp = buffer_get_string(&buffer, NULL);
+ else
+ xfree(buffer_get_string(&buffer, NULL));
+
+ /* Check that it is a supported cipher. */
+ cipher = cipher_by_number(cipher_type);
+ if (cipher == NULL) {
+ debug("Unsupported cipher %d used in key file %.200s.",
+ cipher_type, filename);
+ buffer_free(&buffer);
+ goto fail;
+ }
+ /* Initialize space for decrypted data. */
+ buffer_init(&decrypted);
+ cp = buffer_append_space(&decrypted, buffer_len(&buffer));
+
+ /* 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(&buffer), buffer_len(&buffer));
+ cipher_cleanup(&ciphercontext);
+ memset(&ciphercontext, 0, sizeof(ciphercontext));
+ buffer_free(&buffer);
+
+ check1 = buffer_get_char(&decrypted);
+ check2 = buffer_get_char(&decrypted);
+ if (check1 != buffer_get_char(&decrypted) ||
+ check2 != buffer_get_char(&decrypted)) {
+ if (strcmp(passphrase, "") != 0)
+ debug("Bad passphrase supplied for key file %.200s.",
+ filename);
+ /* Bad passphrase. */
+ buffer_free(&decrypted);
+ goto fail;
+ }
+ /* Read the rest of the private key. */
+ buffer_get_bignum(&decrypted, prv->rsa->d);
+ buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
+ /* in SSL and SSH v1 p and q are exchanged */
+ buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
+ buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
+
+ /* calculate p-1 and q-1 */
+ rsa_generate_additional_parameters(prv->rsa);
+
+ buffer_free(&decrypted);
+
+ /* enable blinding */
+ if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+ error("key_load_private_rsa1: RSA_blinding_on failed");
+ goto fail;
+ }
+ close(fd);
+ return prv;
+
+fail:
+ if (commentp)
+ xfree(*commentp);
+ close(fd);
+ key_free(prv);
+ return NULL;
+}
+
+Key *
+key_load_private_pem(int fd, int type, const char *passphrase,
+ char **commentp)
+{
+ FILE *fp;
+ EVP_PKEY *pk = NULL;
+ Key *prv = NULL;
+ char *name = "<no key>";
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ error("fdopen failed: %s", strerror(errno));
+ close(fd);
+ return NULL;
+ }
+ pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
+ if (pk == NULL) {
+ debug("PEM_read_PrivateKey failed");
+ (void)ERR_get_error();
+ } else if (pk->type == EVP_PKEY_RSA &&
+ (type == KEY_UNSPEC||type==KEY_RSA)) {
+ prv = key_new(KEY_UNSPEC);
+ prv->rsa = EVP_PKEY_get1_RSA(pk);
+ prv->type = KEY_RSA;
+ name = "rsa w/o comment";
+#ifdef DEBUG_PK
+ RSA_print_fp(stderr, prv->rsa, 8);
+#endif
+ if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+ error("key_load_private_pem: RSA_blinding_on failed");
+ 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
+ } else {
+ error("PEM_read_PrivateKey: mismatch or "
+ "unknown EVP_PKEY save_type %d", pk->save_type);
+ }
+ fclose(fp);
+ if (pk != NULL)
+ EVP_PKEY_free(pk);
+ if (prv != NULL && commentp)
+ *commentp = xstrdup(name);
+ debug("read PEM private key done: type %s",
+ prv ? key_type(prv) : "<unknown>");
+ return prv;
+}
+
+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;
+}
+
+Key *
+key_load_private_type(int type, const char *filename, const char *passphrase,
+ char **commentp, int *perm_ok)
+{
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 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;
+ switch (type) {
+ case KEY_RSA1:
+ return key_load_private_rsa1(fd, filename, passphrase,
+ commentp);
+ /* closes fd */
+ case KEY_DSA:
+ case KEY_RSA:
+ case KEY_UNSPEC:
+ return key_load_private_pem(fd, type, passphrase, commentp);
+ /* closes fd */
+ default:
+ close(fd);
+ break;
+ }
+ return NULL;
+}
+
+Key *
+key_load_private(const char *filename, const char *passphrase,
+ char **commentp)
+{
+ Key *pub, *prv;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (!key_perm_ok(fd, filename)) {
+ error("bad permissions: ignore key: %s", filename);
+ close(fd);
+ return NULL;
+ }
+ pub = key_load_public_rsa1(fd, filename, commentp);
+ lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
+ if (pub == NULL) {
+ /* closes fd */
+ prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
+ /* use the filename as a comment for PEM */
+ if (commentp && prv)
+ *commentp = xstrdup(filename);
+ } else {
+ /* it's a SSH v1 key if the public key part is readable */
+ key_free(pub);
+ /* closes fd */
+ prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
+ }
+ return prv;
+}
+
+static int
+key_try_load_public(Key *k, const char *filename, char **commentp)
+{
+ FILE *f;
+ char line[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;
+}
diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h
new file mode 100644
index 0000000..a6c7493
--- /dev/null
+++ b/crypto/openssh/authfile.h
@@ -0,0 +1,26 @@
+/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 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 AUTHFILE_H
+#define AUTHFILE_H
+
+int key_save_private(Key *, const char *, const char *, const char *);
+Key *key_load_public(const char *, char **);
+Key *key_load_public_type(int, const char *, char **);
+Key *key_load_private(const char *, const char *, char **);
+Key *key_load_private_type(int, const char *, const char *, char **, int *);
+Key *key_load_private_pem(int, int, const char *, char **);
+int key_perm_ok(int, const char *);
+
+#endif
diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c
new file mode 100644
index 0000000..cd9a35d
--- /dev/null
+++ b/crypto/openssh/bufaux.c
@@ -0,0 +1,265 @@
+/* $OpenBSD: bufaux.c,v 1.46 2008/06/10 23:21:34 dtucker Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * 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);
+ *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);
+ *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. */
+ len = buffer_get_int(buffer);
+ 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);
+}
+
+void *
+buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr)
+{
+ void *ptr;
+ u_int len;
+
+ len = buffer_get_int(buffer);
+ if (len > 256 * 1024)
+ fatal("buffer_get_string_ptr: bad string length %u", len);
+ ptr = buffer_ptr(buffer);
+ buffer_consume(buffer, len);
+ if (length_ptr)
+ *length_ptr = len;
+ return (ptr);
+}
+
+/*
+ * Stores and arbitrary binary string in the buffer.
+ */
+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/crypto/openssh/bufbn.c b/crypto/openssh/bufbn.c
new file mode 100644
index 0000000..251cd09
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/buffer.c b/crypto/openssh/buffer.c
new file mode 100644
index 0000000..e02e1e3
--- /dev/null
+++ b/crypto/openssh/buffer.c
@@ -0,0 +1,252 @@
+/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt 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(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(Buffer *buffer)
+{
+ return buffer->buf + buffer->offset;
+}
+
+/* Dumps the contents of the buffer to stderr. */
+
+void
+buffer_dump(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/crypto/openssh/buffer.h b/crypto/openssh/buffer.h
new file mode 100644
index 0000000..d0f354e
--- /dev/null
+++ b/crypto/openssh/buffer.h
@@ -0,0 +1,86 @@
+/* $OpenBSD: buffer.h,v 1.17 2008/05/08 06:59:01 markus 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(Buffer *);
+void *buffer_ptr(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(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);
+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 *);
+int buffer_get_char_ret(char *, Buffer *);
+
+#endif /* BUFFER_H */
diff --git a/crypto/openssh/canohost.c b/crypto/openssh/canohost.c
new file mode 100644
index 0000000..22b19bb
--- /dev/null
+++ b/crypto/openssh/canohost.c
@@ -0,0 +1,426 @@
+/* $OpenBSD: canohost.c,v 1.65 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
+ * 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 "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;
+
+ memset(addr, 0, 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 sock)
+{
+ return get_socket_address(sock, 0, NI_NAMEREQD);
+}
+
+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/crypto/openssh/canohost.h b/crypto/openssh/canohost.h
new file mode 100644
index 0000000..4c8636f
--- /dev/null
+++ b/crypto/openssh/canohost.h
@@ -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/crypto/openssh/channels.c b/crypto/openssh/channels.c
new file mode 100644
index 0000000..e8b8aa0
--- /dev/null
+++ b/crypto/openssh/channels.c
@@ -0,0 +1,3461 @@
+/* $OpenBSD: channels.c,v 1.296 2009/05/25 06:48:00 andreas 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 <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[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+/* List of all permitted host/port pairs to connect by the admin. */
+static ForwardPermission permitted_adm_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+/* 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);
+
+ /* XXX set close-on-exec -markus */
+
+ c->rfd = rfd;
+ c->wfd = wfd;
+ c->sock = (rfd == wfd) ? rfd : -1;
+ c->ctl_fd = -1; /* XXX: set elsewhere */
+ 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;
+ 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)
+{
+ debug3("channel %d: close_fds r %d w %d e %d c %d",
+ c->self, c->rfd, c->wfd, c->efd, c->ctl_fd);
+
+ channel_close_fd(&c->sock);
+ channel_close_fd(&c->ctl_fd);
+ 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);
+ if (c->ctl_fd != -1)
+ shutdown(c->ctl_fd, 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_CLOSED:
+ case SSH_CHANNEL_AUTH_SOCKET:
+ case SSH_CHANNEL_DYNAMIC:
+ case SSH_CHANNEL_CONNECTING:
+ case SSH_CHANNEL_ZOMBIE:
+ continue;
+ case SSH_CHANNEL_LARVAL:
+ if (!compat20)
+ fatal("cannot happen: SSH_CHANNEL_LARVAL");
+ continue;
+ case SSH_CHANNEL_OPENING:
+ case SSH_CHANNEL_OPEN:
+ case SSH_CHANNEL_X11_OPEN:
+ return 1;
+ case SSH_CHANNEL_INPUT_DRAINING:
+ case SSH_CHANNEL_OUTPUT_DRAINING:
+ if (!compat13)
+ fatal("cannot happen: OUT_DRAIN");
+ return 1;
+ default:
+ fatal("channel_still_open: bad channel type %d", c->type);
+ /* NOTREACHED */
+ }
+ }
+ return 0;
+}
+
+/* Returns the id of an open channel suitable for keepaliving */
+int
+channel_find_open(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_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:
+ 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 cfd %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_fd);
+ 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_callback_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->flags & CHAN_EOF_SENT) &&
+ c->extended_usage == CHAN_EXTENDED_READ &&
+ buffer_len(&c->extended) < c->remote_window)
+ FD_SET(c->efd, readset);
+ }
+ /* XXX: What about efd? races? */
+ if (compat20 && c->ctl_fd != -1 &&
+ c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN)
+ FD_SET(c->ctl_fd, readset);
+}
+
+/* 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 ||
+ memcmp(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);
+ }
+}
+
+/* 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;
+}
+
+/* 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);
+ c->delayed = 0;
+ debug2("channel %d: pre_dynamic: have %d", c->self, have);
+ /* buffer_dump(&c->input); */
+ /* check if the fixed size part of the packet is in buffer. */
+ if (have < 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);
+
+ 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) {
+ /*
+ * do not call the channel_post handler until
+ * this flag has been reset by a pre-handler.
+ * otherwise the FD_ISSET calls might overflow
+ */
+ nc->delayed = 1;
+ } else {
+ port_open_helper(nc, rtype);
+ }
+ }
+}
+
+/*
+ * This is the authentication agent socket listening for connections from
+ * clients.
+ */
+/* 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;
+ int len;
+
+ /* Send buffered output data to the socket. */
+ if (c->wfd != -1 &&
+ FD_ISSET(c->wfd, writeset) &&
+ buffer_len(&c->output) > 0) {
+ 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 */
+ c->local_consumed += dlen + 4;
+ 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;
+ }
+ return 1;
+ }
+#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);
+ if (compat20 && len > 0) {
+ c->local_consumed += len;
+ }
+ }
+ return 1;
+}
+
+static int
+channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset)
+{
+ char buf[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->extended_usage == CHAN_EXTENDED_READ &&
+ (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 {
+ buffer_append(&c->extended, buf, len);
+ }
+ }
+ }
+ return 1;
+}
+
+/* ARGSUSED */
+static int
+channel_handle_ctl(Channel *c, fd_set *readset, fd_set *writeset)
+{
+ char buf[16];
+ int len;
+
+ /* Monitor control fd to detect if the slave client exits */
+ if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) {
+ len = read(c->ctl_fd, buf, sizeof(buf));
+ if (len < 0 &&
+ (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
+ return 1;
+ if (len <= 0) {
+ debug2("channel %d: ctl read<=0", c->self);
+ if (c->type != SSH_CHANNEL_OPEN) {
+ debug2("channel %d: not open", c->self);
+ chan_mark_dead(c);
+ return -1;
+ } else {
+ chan_read_failed(c);
+ chan_write_failed(c);
+ }
+ return -1;
+ } else
+ fatal("%s: unexpected data on ctl fd", __func__);
+ }
+ 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)
+{
+ if (c->delayed)
+ return;
+ channel_handle_rfd(c, readset, writeset);
+ channel_handle_wfd(c, readset, writeset);
+ if (!compat20)
+ return;
+ channel_handle_efd(c, readset, writeset);
+ channel_handle_ctl(c, readset, writeset);
+ channel_check_window(c);
+}
+
+/* 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_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;
+}
+
+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;
+ Channel *c;
+
+ if (!did_init) {
+ channel_handler_init();
+ did_init = 1;
+ }
+ for (i = 0; i < channels_alloc; i++) {
+ c = channels[i];
+ if (c == NULL)
+ continue;
+ if (ftab[c->type] != NULL)
+ (*ftab[c->type])(c, readset, writeset);
+ channel_garbage_collect(c);
+ }
+}
+
+/*
+ * Allocate/update select bitmasks and add any bits relevant to channels in
+ * select bitmasks.
+ */
+void
+channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp,
+ 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);
+ 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;
+ 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);
+
+ /*
+ * 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 -= data_len;
+ c->local_consumed += data_len;
+ }
+ return;
+ }
+
+ if (compat20) {
+ if (data_len > c->local_maxpacket) {
+ logit("channel %d: rcvd big packet %d, maxpack %d",
+ c->self, data_len, c->local_maxpacket);
+ }
+ if (data_len > c->local_window) {
+ logit("channel %d: rcvd too much data %d, win %d",
+ c->self, data_len, c->local_window);
+ return;
+ }
+ c->local_window -= data_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, 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);
+ }
+ 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);
+
+ 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;
+
+ /* Record locally that connection to this host/port is permitted. */
+ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+ fatal("channel_request_remote_forwarding: too many forwards");
+
+ /* Send the forward request to the remote side. */
+ if (compat20) {
+ const char *address_to_bind;
+ 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) {
+ 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)
+{
+ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+ fatal("channel_add_permitted_opens: too many forwards");
+ debug("allow port forwarding to host %s port %d", host, port);
+
+ permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
+ permitted_opens[num_permitted_opens].port_to_connect = port;
+ num_permitted_opens++;
+
+ all_opens_permitted = 0;
+}
+
+int
+channel_add_adm_permitted_opens(char *host, int port)
+{
+ if (num_adm_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
+ fatal("channel_add_adm_permitted_opens: too many forwards");
+ debug("config allows port forwarding to host %s port %d", host, port);
+
+ 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);
+ 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);
+ 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)) {
+ error("socket: %.100s", strerror(errno));
+ freeaddrinfo(aitop);
+ return -1;
+ } else {
+ debug("x11_create_display_inet: Socket family %d not supported",
+ ai->ai_family);
+ continue;
+ }
+ }
+#ifdef IPV6_V6ONLY
+ if (ai->ai_family == AF_INET6) {
+ int on = 1;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
+ error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno));
+ }
+#endif
+ 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/crypto/openssh/channels.h b/crypto/openssh/channels.h
new file mode 100644
index 0000000..1488ed7
--- /dev/null
+++ b/crypto/openssh/channels.h
@@ -0,0 +1,280 @@
+/* $OpenBSD: channels.h,v 1.98 2009/02/12 03:00:56 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_MAX_TYPE 15
+
+struct Channel;
+typedef struct Channel Channel;
+
+typedef void channel_callback_fn(int, void *);
+typedef int channel_infilter_fn(struct Channel *, char *, int);
+typedef void channel_filter_cleanup_fn(int, void *);
+typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
+
+/* Channel success/failure callbacks */
+typedef void channel_confirm_cb(int, struct Channel *, void *);
+typedef void channel_confirm_abandon_cb(struct Channel *, void *);
+struct channel_confirm {
+ TAILQ_ENTRY(channel_confirm) entry;
+ channel_confirm_cb *cb;
+ channel_confirm_abandon_cb *abandon_cb;
+ void *ctx;
+};
+TAILQ_HEAD(channel_confirms, channel_confirm);
+
+/* Context for non-blocking connects */
+struct channel_connect {
+ char *host;
+ int port;
+ struct addrinfo *ai, *aitop;
+};
+
+struct Channel {
+ int type; /* channel type/state */
+ int self; /* my own channel identifier */
+ 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_fd; /* control fd (client sharing) */
+ 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; /* fdset hack */
+ Buffer input; /* data read from socket, to be sent over
+ * encrypted connection */
+ Buffer output; /* data received over encrypted connection for
+ * send on socket */
+ Buffer extended;
+ char *path;
+ /* 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_callback_fn *open_confirm;
+ void *open_confirm_ctx;
+ channel_callback_fn *detach_user;
+ int detach_close;
+ struct channel_confirms status_confirms;
+
+ /* filter */
+ channel_infilter_fn *input_filter;
+ channel_outfilter_fn *output_filter;
+ void *filter_ctx;
+ channel_filter_cleanup_fn *filter_cleanup;
+
+ /* keep boundaries */
+ int datagram;
+
+ /* non-blocking connect */
+ struct channel_connect connect_ctx;
+};
+
+#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_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_callback_fn *, void *);
+void channel_register_filter(int, channel_infilter_fn *,
+ channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
+void channel_register_status_confirm(int, channel_confirm_cb *,
+ channel_confirm_abandon_cb *, void *);
+void channel_cancel_cleanup(int);
+int channel_close_fd(int *);
+void channel_send_window_changes(void);
+
+/* 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_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/crypto/openssh/cipher-3des1.c b/crypto/openssh/cipher-3des1.c
new file mode 100644
index 0000000..17a13a1
--- /dev/null
+++ b/crypto/openssh/cipher-3des1.c
@@ -0,0 +1,182 @@
+/* $OpenBSD: cipher-3des1.c,v 1.6 2006/08/03 03:34:42 deraadt 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, u_int 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/crypto/openssh/cipher-acss.c b/crypto/openssh/cipher-acss.c
new file mode 100644
index 0000000..cb0bf73
--- /dev/null
+++ b/crypto/openssh/cipher-acss.c
@@ -0,0 +1,85 @@
+/*
+ * 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"
+
+#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,
+ unsigned int 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/crypto/openssh/cipher-aes.c b/crypto/openssh/cipher-aes.c
new file mode 100644
index 0000000..3ea5949
--- /dev/null
+++ b/crypto/openssh/cipher-aes.c
@@ -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,
+ u_int 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/crypto/openssh/cipher-bf1.c b/crypto/openssh/cipher-bf1.c
new file mode 100644
index 0000000..e0e33b4
--- /dev/null
+++ b/crypto/openssh/cipher-bf1.c
@@ -0,0 +1,106 @@
+/* $OpenBSD: cipher-bf1.c,v 1.5 2006/08/03 03:34:42 deraadt 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 *, u_int) = NULL;
+
+static int
+bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int 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/crypto/openssh/cipher-ctr.c b/crypto/openssh/cipher-ctr.c
new file mode 100644
index 0000000..3b86cc1
--- /dev/null
+++ b/crypto/openssh/cipher-ctr.c
@@ -0,0 +1,146 @@
+/* $OpenBSD: cipher-ctr.c,v 1.10 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 <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 *, u_int);
+
+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, u_int 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,
+ u_int len)
+{
+ struct ssh_aes_ctr_ctx *c;
+ u_int 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, u_int 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/crypto/openssh/cipher.c b/crypto/openssh/cipher.c
new file mode 100644
index 0000000..bb5c0ac
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/cipher.h b/crypto/openssh/cipher.h
new file mode 100644
index 0000000..3dd2270
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/cleanup.c b/crypto/openssh/cleanup.c
new file mode 100644
index 0000000..238f965
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c
new file mode 100644
index 0000000..9a7dc0a
--- /dev/null
+++ b/crypto/openssh/clientloop.c
@@ -0,0 +1,2058 @@
+/* $OpenBSD: clientloop.c,v 1.213 2009/07/05 19:28:33 stevesk 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;
+
+/*
+ * Name of the host we are connecting to. This is the name given on the
+ * command line, or the HostName specified for the user-supplied name in a
+ * configuration file.
+ */
+extern char *host;
+
+/*
+ * Flag to indicate that we have received a window change signal which has
+ * not yet been processed. This will cause a message indicating the new
+ * window size to be sent to the server a little later. This is volatile
+ * because this is updated in a signal handler.
+ */
+static volatile 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;
+
+/* Common data for the client loop code. */
+static 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 = 0; /* In SSH2: login session closed. */
+
+static void client_init_dispatch(void);
+int session_ident = -1;
+
+/* 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;
+}
+
+#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
+void
+client_x11_get_proto(const char *display, const char *xauth_path,
+ u_int trusted, 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;
+
+ 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);
+ strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", 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 1200 2>" _PATH_DEVNULL,
+ xauth_path, xauthfile, display);
+ debug2("x11_get_proto: %s", cmd);
+ if (system(cmd) == 0)
+ generated = 1;
+ }
+ }
+
+ /*
+ * 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 not responding.");
+ 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 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);
+
+ if (muxserver_sock != -1)
+ FD_SET(muxserver_sock, *readsetp);
+
+ /*
+ * Wait for something to happen. This will suspend the process until
+ * some selected descriptor can be read, written, or has some other
+ * event pending.
+ */
+
+ if (options.server_alive_interval == 0 || !compat20)
+ tvp = NULL;
+ else {
+ tv.tv_sec = options.server_alive_interval;
+ 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();
+
+ /*
+ * 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();
+}
+
+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_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE;
+
+ if (type == SSH2_MSG_CHANNEL_SUCCESS) {
+ debug2("%s request accepted on channel %d",
+ cr->request_type, c->self);
+ } else if (type == SSH2_MSG_CHANNEL_FAILURE) {
+ if (tochan) {
+ snprintf(errmsg, sizeof(errmsg),
+ "%s request failed\r\n", cr->request_type);
+ } else {
+ snprintf(errmsg, sizeof(errmsg),
+ "%s request failed on channel %d",
+ cr->request_type, c->self);
+ }
+ /* If error occurred on primary session channel, then exit */
+ if (cr->do_close && c->self == session_ident)
+ fatal("%s", errmsg);
+ /* If error occurred on mux client, append to their stderr */
+ if (tochan)
+ buffer_append(&c->extended, errmsg, strlen(errmsg));
+ else
+ error("%s", errmsg);
+ if (cr->do_close) {
+ chan_read_failed(c);
+ chan_write_failed(c);
+ }
+ }
+ xfree(cr);
+}
+
+static void
+client_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();
+ 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))
+ ;
+
+ 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();
+ 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_fd != -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_fd != -1) {
+ noescape:
+ snprintf(string, sizeof string,
+ "%c%c escape not available to "
+ "multiplexed sessions\r\n",
+ escape_char, ch);
+ buffer_append(berr, string,
+ strlen(string));
+ continue;
+ }
+ /* Suspend the program. Inform the user */
+ snprintf(string, sizeof string,
+ "%c^Z [suspend ssh]\r\n", escape_char);
+ buffer_append(berr, string, strlen(string));
+
+ /* Restore terminal modes and suspend. */
+ 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_fd != -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();
+
+ /* 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_fd != -1) {
+ snprintf(string, sizeof string,
+"%c?\r\n\
+Supported escape sequences:\r\n\
+ %c. - terminate session\r\n\
+ %cB - send a BREAK to the remote system\r\n\
+ %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_fd != -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();
+}
+
+/*
+ * 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 (muxserver_sock != -1)
+ max_fd = MAX(max_fd, muxserver_sock);
+
+ 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();
+
+ 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);
+
+ /* Accept control connections. */
+ if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) {
+ if (muxserver_accept_control())
+ quit_pending = 1;
+ }
+
+ if (quit_pending)
+ break;
+
+ if (!compat20) {
+ /* Buffer data from stdin */
+ client_process_input(readset);
+ /*
+ * Process output to stdout and stderr. Output to
+ * the connection is processed elsewhere (above).
+ */
+ client_process_output(writeset);
+ }
+
+ /*
+ * Send as much buffered packet data as possible to the
+ * sender.
+ */
+ if (FD_ISSET(connection_out, writeset))
+ packet_write_poll();
+ }
+ if (readset)
+ xfree(readset);
+ if (writeset)
+ xfree(writeset);
+
+ /* Terminate the session. */
+
+ /* Stop watching for window change. */
+ 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_send();
+ packet_write_wait();
+ }
+
+ channel_free_all();
+
+ if (have_pty)
+ leave_raw_mode();
+
+ /* restore blocking io */
+ if (!isatty(fileno(stdin)))
+ unset_nonblock(fileno(stdin));
+ if (!isatty(fileno(stdout)))
+ unset_nonblock(fileno(stdout));
+ if (!isatty(fileno(stderr)))
+ unset_nonblock(fileno(stderr));
+
+ /*
+ * If 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. */
+ while (buffer_len(&stdout_buffer) > 0) {
+ len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
+ buffer_len(&stdout_buffer));
+ if (len <= 0) {
+ error("Write failed flushing stdout buffer.");
+ break;
+ }
+ buffer_consume(&stdout_buffer, len);
+ }
+
+ /* Output any buffered data for stderr. */
+ while (buffer_len(&stderr_buffer) > 0) {
+ len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
+ buffer_len(&stderr_buffer));
+ if (len <= 0) {
+ error("Write failed flushing stderr buffer.");
+ break;
+ }
+ buffer_consume(&stderr_buffer, len);
+ }
+
+ /* 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",
+ obytes, 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;
+ }
+ 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 (id == session_ident) {
+ success = 1;
+ exit_status = exitval;
+ } else if (c->ctl_fd == -1) {
+ error("client_input_channel_req: unexpected channel %d",
+ session_ident);
+ } else {
+ atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval));
+ success = 1;
+ }
+ packet_check_eom();
+ }
+ if (reply) {
+ packet_start(success ?
+ SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
+ packet_put_int(c->remote_id);
+ packet_send();
+ }
+ xfree(rtype);
+}
+static void
+client_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);
+
+ 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", 0);
+ packet_put_cstring(term != NULL ? term : "");
+ packet_put_int((u_int)ws.ws_col);
+ packet_put_int((u_int)ws.ws_row);
+ packet_put_int((u_int)ws.ws_xpixel);
+ packet_put_int((u_int)ws.ws_ypixel);
+ 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();
+ leave_non_blocking();
+ if (options.control_path != NULL && muxserver_sock != -1)
+ unlink(options.control_path);
+ _exit(i);
+}
diff --git a/crypto/openssh/clientloop.h b/crypto/openssh/clientloop.h
new file mode 100644
index 0000000..8bb874b
--- /dev/null
+++ b/crypto/openssh/clientloop.h
@@ -0,0 +1,73 @@
+/* $OpenBSD: clientloop.h,v 1.22 2008/06/12 15:19:17 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,
+ 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 2
+
+/* 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_FLAG_TTY (1) /* Request tty on open */
+#define SSHMUX_FLAG_SUBSYS (1<<1) /* Subsystem request on open */
+#define SSHMUX_FLAG_X11_FWD (1<<2) /* Request X11 forwarding */
+#define SSHMUX_FLAG_AGENT_FWD (1<<3) /* Request agent forwarding */
+
+void muxserver_listen(void);
+int muxserver_accept_control(void);
+void muxclient(const char *);
diff --git a/crypto/openssh/compat.c b/crypto/openssh/compat.c
new file mode 100644
index 0000000..df3541d
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/compat.h b/crypto/openssh/compat.h
new file mode 100644
index 0000000..16cf282
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/compress.c b/crypto/openssh/compress.c
new file mode 100644
index 0000000..c058d22
--- /dev/null
+++ b/crypto/openssh/compress.c
@@ -0,0 +1,166 @@
+/* $OpenBSD: compress.c,v 1.25 2006/08/06 01:13:32 stevesk 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 <zlib.h>
+
+#include "log.h"
+#include "buffer.h"
+#include "compress.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/crypto/openssh/compress.h b/crypto/openssh/compress.h
new file mode 100644
index 0000000..418d6fd
--- /dev/null
+++ b/crypto/openssh/compress.h
@@ -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/crypto/openssh/config.guess b/crypto/openssh/config.guess
new file mode 100755
index 0000000..c7607c7
--- /dev/null
+++ b/crypto/openssh/config.guess
@@ -0,0 +1,1526 @@
+#! /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
+# Free Software Foundation, Inc.
+
+timestamp='2008-04-14'
+
+# 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 <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted 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.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 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 __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # 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 ;;
+ 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:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ echo i386-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 __LP64__ >/dev/null
+ 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*:[3456]*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T | authenticamd)
+ 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 ;;
+ 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 ;;
+ 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 ;;
+ 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:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ 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 ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ 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 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-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:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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.0*:*)
+ 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 i386.
+ echo i386-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; } ;;
+ 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.0*:*)
+ 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
+ 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 ;;
+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/crypto/openssh/config.h b/crypto/openssh/config.h
new file mode 100644
index 0000000..5430244
--- /dev/null
+++ b/crypto/openssh/config.h
@@ -0,0 +1,1452 @@
+/* config.h. Generated from config.h.in by configure. */
+/* 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 */
+#define BROKEN_GLOB 1
+
+/* 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 utmpx file */
+/* #undef CONF_UTMPX_FILE */
+
+/* Define if you want to specify the path to your utmp file */
+#define CONF_UTMP_FILE "/var/run/utmp"
+
+/* 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 */
+#define CONF_WTMP_FILE "/var/log/wtmp"
+
+/* 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 */
+#define DISABLE_UTMPX 1
+
+/* Define if you don't want to use wtmp */
+/* #undef DISABLE_WTMP */
+
+/* Define if you don't want to use wtmpx */
+#define DISABLE_WTMPX 1
+
+/* Builtin PRNG command timeout */
+#define ENTROPY_TIMEOUT_MSEC 200
+
+/* 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. */
+#define GETPGRP_VOID 1
+
+/* Conflicting defs for getspnam */
+/* #undef GETSPNAM_CONFLICTING_DEFS */
+
+/* Define if your system glob() function has the GLOB_ALTDIRFUNC extension */
+#define GLOB_HAS_ALTDIRFUNC 1
+
+/* Define if your system glob() function has gl_matchc options in glob_t */
+#define GLOB_HAS_GL_MATCHC 1
+
+/* 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. */
+#define HAVE_ARC4RANDOM 1
+
+/* Define to 1 if you have the `arc4random_buf' function. */
+#define HAVE_ARC4RANDOM_BUF 1
+
+/* Define to 1 if you have the `arc4random_uniform' function. */
+#define HAVE_ARC4RANDOM_UNIFORM 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* OpenBSD's gcc has bounded */
+/* #undef HAVE_ATTRIBUTE__BOUNDED__ */
+
+/* Have attribute nonnull */
+#define HAVE_ATTRIBUTE__NONNULL__ 1
+
+/* 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. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if you have the `bcopy' function. */
+#define HAVE_BCOPY 1
+
+/* Define to 1 if you have the `bindresvport_sa' function. */
+#define HAVE_BINDRESVPORT_SA 1
+
+/* 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. */
+#define HAVE_CLOCK 1
+
+/* define if you have clock_t data type */
+#define HAVE_CLOCK_T 1
+
+/* Define to 1 if you have the `closefrom' function. */
+#define HAVE_CLOSEFROM 1
+
+/* Define if gai_strerror() returns const char * */
+#define HAVE_CONST_GAI_STRERROR_PROTO 1
+
+/* Define if your system uses ancillary data style file descriptor passing */
+#define HAVE_CONTROL_IN_MSGHDR 1
+
+/* 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() */
+#define HAVE_DAEMON 1
+
+/* 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. */
+#define HAVE_DECL_GLOB_NOMATCH 1
+
+/* Define to 1 if you have the declaration of `h_errno', and to 0 if you
+ don't. */
+#define HAVE_DECL_H_ERRNO 1
+
+/* 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. */
+#define HAVE_DECL_MAXSYMLINKS 1
+
+/* Define to 1 if you have the declaration of `offsetof', and to 0 if you
+ don't. */
+#define HAVE_DECL_OFFSETOF 1
+
+/* Define to 1 if you have the declaration of `O_NONBLOCK', and to 0 if you
+ don't. */
+#define HAVE_DECL_O_NONBLOCK 1
+
+/* 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. */
+#define HAVE_DECL_SHUT_RD 1
+
+/* Define to 1 if you have the declaration of `writev', and to 0 if you don't.
+ */
+#define HAVE_DECL_WRITEV 1
+
+/* Define to 1 if you have the declaration of `_getlong', and to 0 if you
+ don't. */
+#define HAVE_DECL__GETLONG 0
+
+/* Define to 1 if you have the declaration of `_getshort', and to 0 if you
+ don't. */
+#define HAVE_DECL__GETSHORT 0
+
+/* Define if you have /dev/ptmx */
+#define HAVE_DEV_PTMX 1
+
+/* Define if you have /dev/ptc */
+/* #undef HAVE_DEV_PTS_AND_PTC */
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the `dirfd' function. */
+/* #undef HAVE_DIRFD */
+
+/* Define to 1 if you have the `dirname' function. */
+#define HAVE_DIRNAME 1
+
+/* 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. */
+#define HAVE_EVP_SHA256 1
+
+/* Define if you have ut_exit in utmp.h */
+/* #undef HAVE_EXIT_IN_UTMP */
+
+/* Define to 1 if you have the `fchmod' function. */
+#define HAVE_FCHMOD 1
+
+/* Define to 1 if you have the `fchown' function. */
+#define HAVE_FCHOWN 1
+
+/* Use F_CLOSEM fcntl for closefrom */
+/* #undef HAVE_FCNTL_CLOSEM */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* 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. */
+#define HAVE_FLOATINGPOINT_H 1
+
+/* Define to 1 if you have the `fmt_scaled' function. */
+/* #undef HAVE_FMT_SCALED */
+
+/* Define to 1 if you have the `freeaddrinfo' function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if the system has the type `fsblkcnt_t'. */
+#define HAVE_FSBLKCNT_T 1
+
+/* Define to 1 if the system has the type `fsfilcnt_t'. */
+#define HAVE_FSFILCNT_T 1
+
+/* Define to 1 if you have the `fstatvfs' function. */
+#define HAVE_FSTATVFS 1
+
+/* Define to 1 if you have the `futimes' function. */
+#define HAVE_FUTIMES 1
+
+/* Define to 1 if you have the `gai_strerror' function. */
+#define HAVE_GAI_STRERROR 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* 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. */
+#define HAVE_GETCWD 1
+
+/* Define to 1 if you have the `getgrouplist' function. */
+#define HAVE_GETGROUPLIST 1
+
+/* 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. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getopt' function. */
+#define HAVE_GETOPT 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define if your getopt(3) defines and uses optreset */
+#define HAVE_GETOPT_OPTRESET 1
+
+/* Define if your libraries define getpagesize() */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `getpeereid' function. */
+#define HAVE_GETPEEREID 1
+
+/* 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. */
+#define HAVE_GETRLIMIT 1
+
+/* 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. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `getttyent' function. */
+#define HAVE_GETTTYENT 1
+
+/* 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 `get_default_context_with_level' function. */
+/* #undef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL */
+
+/* Define to 1 if you have the `glob' function. */
+#define HAVE_GLOB 1
+
+/* Define to 1 if you have the <glob.h> header file. */
+#define HAVE_GLOB_H 1
+
+/* 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 */
+#define HAVE_HEADER_AD 1
+
+/* Define if you have ut_host in utmp.h */
+#define HAVE_HOST_IN_UTMP 1
+
+/* 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. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the `innetgr' function. */
+#define HAVE_INNETGR 1
+
+/* define if you have int64_t data type */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* define if you have intxx_t data type */
+#define HAVE_INTXX_T 1
+
+/* Define to 1 if the system has the type `in_addr_t'. */
+#define HAVE_IN_ADDR_T 1
+
+/* Define to 1 if the system has the type `in_port_t'. */
+#define HAVE_IN_PORT_T 1
+
+/* Define to 1 if you have the <lastlog.h> header file. */
+/* #undef HAVE_LASTLOG_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. */
+#define HAVE_LIBGEN_H 1
+
+/* Define if system has libiaf that supports set_id */
+/* #undef HAVE_LIBIAF */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `pam' library (-lpam). */
+#define HAVE_LIBPAM 1
+
+/* Define to 1 if you have the `sectok' library (-lsectok). */
+/* #undef HAVE_LIBSECTOK */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <libutil.h> header file. */
+#define HAVE_LIBUTIL_H 1
+
+/* Define to 1 if you have the `xnet' library (-lxnet). */
+/* #undef HAVE_LIBXNET */
+
+/* Define to 1 if you have the `z' library (-lz). */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* 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() */
+#define HAVE_LOGIN 1
+
+/* Define to 1 if you have the <login_cap.h> header file. */
+#define HAVE_LOGIN_CAP_H 1
+
+/* Define to 1 if you have the `login_getcapbool' function. */
+#define HAVE_LOGIN_GETCAPBOOL 1
+
+/* Define to 1 if you have the <login.h> header file. */
+/* #undef HAVE_LOGIN_H */
+
+/* Define to 1 if you have the `logout' function. */
+#define HAVE_LOGOUT 1
+
+/* Define to 1 if you have the `logwtmp' function. */
+#define HAVE_LOGWTMP 1
+
+/* Define to 1 if the system has the type `long double'. */
+#define HAVE_LONG_DOUBLE 1
+
+/* Define to 1 if the system has the type `long long'. */
+#define HAVE_LONG_LONG 1
+
+/* 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. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkdtemp' function. */
+#define HAVE_MKDTEMP 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* define if you have mode_t data type */
+#define HAVE_MODE_T 1
+
+/* Some systems put nanosleep outside of libc */
+#define HAVE_NANOSLEEP 1
+
+/* 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. */
+#define HAVE_NETDB_H 1
+
+/* 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. */
+#define HAVE_NET_IF_TUN_H 1
+
+/* 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. */
+#define HAVE_OPENPTY 1
+
+/* Define if your ssl headers are included with #include <openssl/header.h> */
+#define HAVE_OPENSSL 1
+
+/* Define if you have Digital Unix Security Integration Architecture */
+/* #undef HAVE_OSF_SIA */
+
+/* Define to 1 if you have the `pam_getenvlist' function. */
+#define HAVE_PAM_GETENVLIST 1
+
+/* 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. */
+#define HAVE_PAM_PUTENV 1
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Define if you have ut_pid in utmp.h */
+/* #undef HAVE_PID_IN_UTMP */
+
+/* define if you have pid_t data type */
+#define HAVE_PID_T 1
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* 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 */
+#define HAVE_PW_CHANGE_IN_PASSWD 1
+
+/* Define if your password has a pw_class field */
+#define HAVE_PW_CLASS_IN_PASSWD 1
+
+/* Define if your password has a pw_expire field */
+#define HAVE_PW_EXPIRE_IN_PASSWD 1
+
+/* Define to 1 if you have the `readpassphrase' function. */
+#define HAVE_READPASSPHRASE 1
+
+/* Define to 1 if you have the <readpassphrase.h> header file. */
+#define HAVE_READPASSPHRASE_H 1
+
+/* Define to 1 if you have the `realpath' function. */
+#define HAVE_REALPATH 1
+
+/* Define to 1 if you have the `recvmsg' function. */
+#define HAVE_RECVMSG 1
+
+/* Define to 1 if you have the <rpc/types.h> header file. */
+#define HAVE_RPC_TYPES_H 1
+
+/* Define to 1 if you have the `rresvport_af' function. */
+#define HAVE_RRESVPORT_AF 1
+
+/* define if you have sa_family_t data type */
+#define HAVE_SA_FAMILY_T 1
+
+/* Define to 1 if you have the <sectok.h> header file. */
+/* #undef HAVE_SECTOK_H */
+
+/* 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. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the `sendmsg' function. */
+#define HAVE_SENDMSG 1
+
+/* 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. */
+#define HAVE_SETEGID 1
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define to 1 if you have the `seteuid' function. */
+#define HAVE_SETEUID 1
+
+/* Define to 1 if you have the `setgroups' function. */
+#define HAVE_SETGROUPS 1
+
+/* Define to 1 if you have the `setlogin' function. */
+#define HAVE_SETLOGIN 1
+
+/* Define to 1 if you have the `setluid' function. */
+/* #undef HAVE_SETLUID */
+
+/* Define to 1 if you have the `setpcred' function. */
+/* #undef HAVE_SETPCRED */
+
+/* Define to 1 if you have the `setproctitle' function. */
+#define HAVE_SETPROCTITLE 1
+
+/* Define to 1 if you have the `setregid' function. */
+#define HAVE_SETREGID 1
+
+/* Define to 1 if you have the `setresgid' function. */
+#define HAVE_SETRESGID 1
+
+/* Define to 1 if you have the `setresuid' function. */
+#define HAVE_SETRESUID 1
+
+/* Define to 1 if you have the `setreuid' function. */
+#define HAVE_SETREUID 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the `setsid' function. */
+#define HAVE_SETSID 1
+
+/* Define to 1 if you have the `setutent' function. */
+/* #undef HAVE_SETUTENT */
+
+/* Define to 1 if you have the `setutxent' function. */
+/* #undef HAVE_SETUTXENT */
+
+/* Define to 1 if you have the `setvbuf' function. */
+#define HAVE_SETVBUF 1
+
+/* Define to 1 if you have the `set_id' function. */
+/* #undef HAVE_SET_ID */
+
+/* Define to 1 if you have the `SHA256_Update' function. */
+#define HAVE_SHA256_UPDATE 1
+
+/* 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. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `sigvec' function. */
+#define HAVE_SIGVEC 1
+
+/* Define to 1 if the system has the type `sig_atomic_t'. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* define if you have size_t data type */
+#define HAVE_SIZE_T 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the `socketpair' function. */
+#define HAVE_SOCKETPAIR 1
+
+/* Have PEERCRED socket option */
+/* #undef HAVE_SO_PEERCRED */
+
+/* define if you have ssize_t data type */
+#define HAVE_SSIZE_T 1
+
+/* Fields in struct sockaddr_storage */
+#define HAVE_SS_FAMILY_IN_SS 1
+
+/* Define to 1 if you have the `statfs' function. */
+#define HAVE_STATFS 1
+
+/* Define to 1 if you have the `statvfs' function. */
+#define HAVE_STATVFS 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Silly mkstemp() */
+/* #undef HAVE_STRICT_MKSTEMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strmode' function. */
+#define HAVE_STRMODE 1
+
+/* Define to 1 if you have the `strnvis' function. */
+/* #undef HAVE_STRNVIS */
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtonum' function. */
+#define HAVE_STRTONUM 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* define if you have struct addrinfo data type */
+#define HAVE_STRUCT_ADDRINFO 1
+
+/* define if you have struct in6_addr data type */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* define if you have struct sockaddr_in6 data type */
+#define HAVE_STRUCT_SOCKADDR_IN6 1
+
+/* Define to 1 if `sin6_scope_id' is member of `struct sockaddr_in6'. */
+#define HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* define if you have struct sockaddr_storage data type */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if `st_blksize' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+
+/* Define to 1 if the system has the type `struct timespec'. */
+#define HAVE_STRUCT_TIMESPEC 1
+
+/* define if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the `swap32' function. */
+/* #undef HAVE_SWAP32 */
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* 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. */
+#define HAVE_SYS_CDEFS_H 1
+
+/* Define to 1 if you have the <sys/dir.h> header file. */
+#define HAVE_SYS_DIR_H 1
+
+/* Define if your system defines sys_errlist[] */
+#define HAVE_SYS_ERRLIST 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#define HAVE_SYS_MOUNT_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if your system defines sys_nerr */
+#define HAVE_SYS_NERR 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* 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. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/statvfs.h> header file. */
+#define HAVE_SYS_STATVFS_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* 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. */
+#define HAVE_SYS_TIMERS_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the `tcgetpgrp' function. */
+#define HAVE_TCGETPGRP 1
+
+/* Define to 1 if you have the `tcsendbreak' function. */
+#define HAVE_TCSENDBREAK 1
+
+/* Define to 1 if you have the `time' function. */
+#define HAVE_TIME 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have ut_time in utmp.h */
+#define HAVE_TIME_IN_UTMP 1
+
+/* Define if you have ut_time in utmpx.h */
+/* #undef HAVE_TIME_IN_UTMPX */
+
+/* Define to 1 if you have the <tmpdir.h> header file. */
+/* #undef HAVE_TMPDIR_H */
+
+/* Define to 1 if you have the `truncate' function. */
+#define HAVE_TRUNCATE 1
+
+/* Define to 1 if you have the <ttyent.h> header file. */
+#define HAVE_TTYENT_H 1
+
+/* 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 */
+#define HAVE_UINTXX_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `unsetenv' function. */
+#define HAVE_UNSETENV 1
+
+/* Define to 1 if the system has the type `unsigned long long'. */
+#define HAVE_UNSIGNED_LONG_LONG 1
+
+/* 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 <util.h> header file. */
+/* #undef HAVE_UTIL_H */
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* 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. */
+#define HAVE_UTMP_H 1
+
+/* define if you have u_char data type */
+#define HAVE_U_CHAR 1
+
+/* define if you have u_int data type */
+#define HAVE_U_INT 1
+
+/* define if you have u_int64_t data type */
+#define HAVE_U_INT64_T 1
+
+/* define if you have u_intxx_t data type */
+#define HAVE_U_INTXX_T 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if va_copy exists */
+#define HAVE_VA_COPY 1
+
+/* Define to 1 if you have the `vhangup' function. */
+/* #undef HAVE_VHANGUP */
+
+/* Define to 1 if you have the <vis.h> header file. */
+#define HAVE_VIS_H 1
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if you have the `waitpid' function. */
+#define HAVE_WAITPID 1
+
+/* Define to 1 if you have the `_getlong' function. */
+#define HAVE__GETLONG 1
+
+/* Define to 1 if you have the `_getpty' function. */
+/* #undef HAVE__GETPTY */
+
+/* Define to 1 if you have the `_getshort' function. */
+#define HAVE__GETSHORT 1
+
+/* Define if you have struct __res_state _res as an extern */
+#define HAVE__RES_EXTERN 1
+
+/* Define to 1 if you have the `__b64_ntop' function. */
+#define HAVE___B64_NTOP 1
+
+/* Define to 1 if you have the `__b64_pton' function. */
+#define HAVE___B64_PTON 1
+
+/* Define if compiler implements __FUNCTION__ */
+#define HAVE___FUNCTION__ 1
+
+/* Define if libc defines __progname */
+#define HAVE___PROGNAME 1
+
+/* Fields in struct sockaddr_storage */
+/* #undef HAVE___SS_FAMILY_IN_SS */
+
+/* Define if __va_copy exists */
+#define HAVE___VA_COPY 1
+
+/* Define if compiler implements __func__ */
+#define HAVE___func__ 1
+
+/* 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 */
+#define LIBWRAP 1
+
+/* Define to whatever link() returns for "not supported" if it doesn't return
+ EOPNOTSUPP. */
+/* #undef LINK_OPNOTSUPP_ERRNO */
+
+/* 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) */
+#define LOCKED_PASSWD_PREFIX "*LOCKED*"
+
+/* 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 */
+#define LOGIN_PROGRAM_FALLBACK "/usr/bin/login"
+
+/* 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 is missing AES 192 and 256 bit functions */
+/* #undef OPENSSL_LOBOTOMISED_AES */
+
+/* Define if you want OpenSSL's internally seeded PRNG only */
+#define OPENSSL_PRNG_ONLY 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "openssh-unix-dev@mindrot.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "OpenSSH"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "OpenSSH Portable"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "openssh"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "Portable"
+
+/* 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. */
+#define SIZEOF_CHAR 1
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long int', as computed by sizeof. */
+#define SIZEOF_LONG_INT 4
+
+/* The size of `long long int', as computed by sizeof. */
+#define SIZEOF_LONG_LONG_INT 8
+
+/* The size of `short int', as computed by sizeof. */
+#define SIZEOF_SHORT_INT 2
+
+/* Define if you want S/Key support */
+/* #undef SKEY */
+
+/* Define if your skeychallenge() function takes 4 arguments (NetBSD) */
+/* #undef SKEYCHALLENGE_4ARG */
+
+/* Define if you want smartcard support */
+/* #undef SMARTCARD */
+
+/* Define as const if snprintf() can declare const char *fmt */
+#define SNPRINTF_CONST 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 */
+#define SSH_PRIVSEP_USER "sshd"
+
+/* Use tunnel device compatibility to OpenBSD */
+/* #undef SSH_TUN_COMPAT_AF */
+
+/* Open tunnel devices the FreeBSD way */
+#define SSH_TUN_FREEBSD 1
+
+/* 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. */
+#define STDC_HEADERS 1
+
+/* 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 */
+#define USE_LIBEDIT 1
+
+/* Define if you want smartcard support using OpenSC */
+/* #undef USE_OPENSC */
+
+/* Enable OpenSSL engine support */
+#define USE_OPENSSL_ENGINE 1
+
+/* Define if you want to enable PAM support */
+#define USE_PAM 1
+
+/* Use PIPES instead of a socketpair() */
+/* #undef USE_PIPES */
+
+/* Define if you want smartcard support using sectok */
+/* #undef USE_SECTOK */
+
+/* Define if you have Solaris process contracts */
+/* #undef USE_SOLARIS_PROCESS_CONTRACTS */
+
+/* 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 WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel and VAX). */
+#if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+#elif ! defined __LITTLE_ENDIAN__
+/* # undef WORDS_BIGENDIAN */
+#endif
+
+/* 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 */
+#define _PATH_PASSWD_PROG "/usr/bin/passwd"
+
+/* Specify location of ssh.pid */
+#define _PATH_SSH_PIDDIR "/var/run"
+
+/* 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/crypto/openssh/config.h.in b/crypto/openssh/config.h.in
new file mode 100644
index 0000000..fc195ba
--- /dev/null
+++ b/crypto/openssh/config.h.in
@@ -0,0 +1,1458 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* 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 utmpx file */
+#undef CONF_UTMPX_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
+
+/* Builtin PRNG command timeout */
+#undef ENTROPY_TIMEOUT_MSEC
+
+/* 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 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 <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 <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 `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 <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 to 1 if you have the <lastlog.h> header file. */
+#undef HAVE_LASTLOG_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 `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 `sectok' library (-lsectok). */
+#undef HAVE_LIBSECTOK
+
+/* 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 if you have sa_family_t data type */
+#undef HAVE_SA_FAMILY_T
+
+/* Define to 1 if you have the <sectok.h> header file. */
+#undef HAVE_SECTOK_H
+
+/* 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 `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 `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 `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 `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 <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 <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
+
+/* 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 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 if you want smartcard support */
+#undef SMARTCARD
+
+/* 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
+
+/* Define if you want smartcard support using OpenSC */
+#undef USE_OPENSC
+
+/* 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 want smartcard support using sectok */
+#undef USE_SECTOK
+
+/* Define if you have Solaris process contracts */
+#undef USE_SOLARIS_PROCESS_CONTRACTS
+
+/* 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 WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* 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/crypto/openssh/crc32.c b/crypto/openssh/crc32.c
new file mode 100644
index 0000000..c192eb4
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/crc32.h b/crypto/openssh/crc32.h
new file mode 100644
index 0000000..5d7131a
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/deattack.c b/crypto/openssh/deattack.c
new file mode 100644
index 0000000..1b37e4d
--- /dev/null
+++ b/crypto/openssh/deattack.c
@@ -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/crypto/openssh/deattack.h b/crypto/openssh/deattack.h
new file mode 100644
index 0000000..0316fb2
--- /dev/null
+++ b/crypto/openssh/deattack.h
@@ -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/crypto/openssh/defines.h b/crypto/openssh/defines.h
new file mode 100644
index 0000000..2ddfd96
--- /dev/null
+++ b/crypto/openssh/defines.h
@@ -0,0 +1,756 @@
+/*
+ * 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.156 2009/08/28 01:21:07 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
+
+#ifndef IPTOS_LOWDELAY
+# define IPTOS_LOWDELAY 0x10
+# define IPTOS_THROUGHPUT 0x08
+# define IPTOS_RELIABILITY 0x04
+# define IPTOS_LOWCOST 0x02
+# define IPTOS_MINCOST IPTOS_LOWCOST
+#endif /* IPTOS_LOWDELAY */
+
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else /* PATH_MAX */
+# define MAXPATHLEN 64
+/* 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 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
+
+#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(UTMPX_FILE) && !defined(DISABLE_UTMPX)
+# define USE_UTMPX
+# endif
+# if defined(UTMP_FILE) && !defined(DISABLE_UTMP)
+# define USE_UTMP
+# endif
+# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX)
+# define USE_WTMPX
+# endif
+# if defined(WTMP_FILE) && !defined(DISABLE_WTMP)
+# define USE_WTMP
+# endif
+
+#endif
+
+#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
+
+#endif /* _DEFINES_H */
diff --git a/crypto/openssh/dh.c b/crypto/openssh/dh.c
new file mode 100644
index 0000000..b766053
--- /dev/null
+++ b/crypto/openssh/dh.c
@@ -0,0 +1,346 @@
+/* $OpenBSD: dh.c,v 1.47 2008/06/26 09:19:39 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.
+ */
+
+#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 = (u_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/crypto/openssh/dh.h b/crypto/openssh/dh.h
new file mode 100644
index 0000000..dfc1480
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/dispatch.c b/crypto/openssh/dispatch.c
new file mode 100644
index 0000000..64bb809
--- /dev/null
+++ b/crypto/openssh/dispatch.c
@@ -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/crypto/openssh/dispatch.h b/crypto/openssh/dispatch.h
new file mode 100644
index 0000000..3e3d1a1
--- /dev/null
+++ b/crypto/openssh/dispatch.h
@@ -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/crypto/openssh/dns.c b/crypto/openssh/dns.c
new file mode 100644
index 0000000..a7da03f
--- /dev/null
+++ b/crypto/openssh/dns.c
@@ -0,0 +1,305 @@
+/* $OpenBSD: dns.c,v 1.25 2008/06/12 00:03:49 dtucker 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, const Key *key)
+{
+ int success = 0;
+
+ switch (key->type) {
+ case KEY_RSA:
+ *algorithm = SSHFP_KEY_RSA;
+ break;
+ case KEY_DSA:
+ *algorithm = SSHFP_KEY_DSA;
+ break;
+ 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,
+ const 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, const 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/crypto/openssh/dns.h b/crypto/openssh/dns.h
new file mode 100644
index 0000000..b2633a1
--- /dev/null
+++ b/crypto/openssh/dns.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: dns.h,v 1.10 2006/08/03 03:34:42 deraadt 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 *, const Key *, int *);
+int export_dns_rr(const char *, const Key *, FILE *, int);
+
+#endif /* DNS_H */
diff --git a/crypto/openssh/entropy.c b/crypto/openssh/entropy.c
new file mode 100644
index 0000000..8b70539
--- /dev/null
+++ b/crypto/openssh/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", 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/crypto/openssh/entropy.h b/crypto/openssh/entropy.h
new file mode 100644
index 0000000..ec1ebcc
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/fatal.c b/crypto/openssh/fatal.c
new file mode 100644
index 0000000..5e5aa3f
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/fixpaths b/crypto/openssh/fixpaths
new file mode 100755
index 0000000..60a6799
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/fixprogs b/crypto/openssh/fixprogs
new file mode 100755
index 0000000..af76ee3
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/groupaccess.c b/crypto/openssh/groupaccess.c
new file mode 100644
index 0000000..2381aeb
--- /dev/null
+++ b/crypto/openssh/groupaccess.c
@@ -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/crypto/openssh/groupaccess.h b/crypto/openssh/groupaccess.h
new file mode 100644
index 0000000..000578e
--- /dev/null
+++ b/crypto/openssh/groupaccess.h
@@ -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/crypto/openssh/gss-genr.c b/crypto/openssh/gss-genr.c
new file mode 100644
index 0000000..842f385
--- /dev/null
+++ b/crypto/openssh/gss-genr.c
@@ -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/crypto/openssh/gss-serv-krb5.c b/crypto/openssh/gss-serv-krb5.c
new file mode 100644
index 0000000..5a625ac
--- /dev/null
+++ b/crypto/openssh/gss-serv-krb5.c
@@ -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/crypto/openssh/gss-serv.c b/crypto/openssh/gss-serv.c
new file mode 100644
index 0000000..2ec7ea1
--- /dev/null
+++ b/crypto/openssh/gss-serv.c
@@ -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/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c
new file mode 100644
index 0000000..2cceb35
--- /dev/null
+++ b/crypto/openssh/hostfile.c
@@ -0,0 +1,353 @@
+/* $OpenBSD: hostfile.c,v 1.45 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
+ * 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"
+
+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;
+ *bitsp = key_size(ret);
+ return 1;
+}
+
+static int
+hostfile_check_key(int bits, const Key *key, const char *host, const char *filename, int linenum)
+{
+ if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
+ return 1;
+ if (bits != BN_num_bits(key->rsa->n)) {
+ logit("Warning: %s, line %d: 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 %d.",
+ bits, BN_num_bits(key->rsa->n), filename, linenum);
+ }
+ return 1;
+}
+
+/*
+ * Checks whether the given host (which must be in all lowercase) is already
+ * in the list of our known hosts. Returns HOST_OK if the host is known and
+ * has the specified key, HOST_NEW if the host is not known, and HOST_CHANGED
+ * if the host is known but used to have a different host key.
+ *
+ * If no 'key' has been specified and a key of type 'keytype' is known
+ * for the specified host, then HOST_FOUND is returned.
+ */
+
+static HostStatus
+check_host_in_hostfile_by_key_or_type(const char *filename,
+ const char *host, const Key *key, int keytype, Key *found, int *numret)
+{
+ FILE *f;
+ char line[8192];
+ int linenum = 0;
+ u_int kbits;
+ char *cp, *cp2, *hashed_host;
+ HostStatus end_return;
+
+ debug3("check_host_in_hostfile: filename %s", filename);
+
+ /* Open the file containing the list of known hosts. */
+ f = fopen(filename, "r");
+ if (!f)
+ return HOST_NEW;
+
+ /*
+ * Return value when the loop terminates. This is set to
+ * HOST_CHANGED if we have seen a different key for the host and have
+ * not found the proper one.
+ */
+ end_return = HOST_NEW;
+
+ /* Go through the file. */
+ while (fgets(line, sizeof(line), f)) {
+ cp = line;
+ linenum++;
+
+ /* Skip any leading whitespace, comments and empty lines. */
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (!*cp || *cp == '#' || *cp == '\n')
+ continue;
+
+ /* Find the end of the host name portion. */
+ for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
+ ;
+
+ /* Check if the host name matches. */
+ if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) {
+ if (*cp != HASH_DELIM)
+ continue;
+ hashed_host = host_hash(host, cp, (u_int) (cp2 - cp));
+ if (hashed_host == NULL) {
+ debug("Invalid hashed host line %d of %s",
+ linenum, filename);
+ 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.
+ */
+ if (!hostfile_read_key(&cp, &kbits, found))
+ continue;
+
+ if (numret != NULL)
+ *numret = linenum;
+
+ if (key == NULL) {
+ /* we found a key of the requested type */
+ if (found->type == keytype) {
+ fclose(f);
+ return HOST_FOUND;
+ }
+ continue;
+ }
+
+ if (!hostfile_check_key(kbits, found, host, filename, linenum))
+ continue;
+
+ /* Check if the current key is the same as the given key. */
+ if (key_equal(key, found)) {
+ /* Ok, they match. */
+ debug3("check_host_in_hostfile: match line %d", linenum);
+ fclose(f);
+ return HOST_OK;
+ }
+ /*
+ * They do not match. We will continue to go through the
+ * file; however, we note that we will not return that it is
+ * new.
+ */
+ end_return = HOST_CHANGED;
+ }
+ /* Clear variables and close the file. */
+ fclose(f);
+
+ /*
+ * Return either HOST_NEW or HOST_CHANGED, depending on whether we
+ * saw a different key for the host.
+ */
+ return end_return;
+}
+
+HostStatus
+check_host_in_hostfile(const char *filename, const char *host, const Key *key,
+ Key *found, int *numret)
+{
+ if (key == NULL)
+ fatal("no key to look up");
+ return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0,
+ found, numret));
+}
+
+int
+lookup_key_in_hostfile_by_type(const char *filename, const char *host,
+ int keytype, Key *found, int *numret)
+{
+ return (check_host_in_hostfile_by_key_or_type(filename, host, NULL,
+ keytype, found, numret) == 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/crypto/openssh/hostfile.h b/crypto/openssh/hostfile.h
new file mode 100644
index 0000000..d1983b3
--- /dev/null
+++ b/crypto/openssh/hostfile.h
@@ -0,0 +1,33 @@
+/* $OpenBSD: hostfile.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
+ *
+ * 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_FOUND
+} HostStatus;
+
+int hostfile_read_key(char **, u_int *, Key *);
+HostStatus check_host_in_hostfile(const char *, const char *,
+ const Key *, Key *, int *);
+int add_host_to_hostfile(const char *, const char *, const Key *, int);
+int lookup_key_in_hostfile_by_type(const char *, const char *,
+ int, Key *, int *);
+
+#define HASH_MAGIC "|1|"
+#define HASH_DELIM '|'
+
+char *host_hash(const char *, const char *, u_int);
+
+#endif
diff --git a/crypto/openssh/includes.h b/crypto/openssh/includes.h
new file mode 100644
index 0000000..6bb9878
--- /dev/null
+++ b/crypto/openssh/includes.h
@@ -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(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/crypto/openssh/jpake.c b/crypto/openssh/jpake.c
new file mode 100644
index 0000000..1306610
--- /dev/null
+++ b/crypto/openssh/jpake.c
@@ -0,0 +1,449 @@
+/* $OpenBSD: jpake.c,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.
+ */
+
+/*
+ * 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 "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(theirpub2, BN_value_one()) <= 0)
+ fatal("%s: theirpub2 <= 1", __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__);
+
+ /*
+ * 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 (memcmp(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/crypto/openssh/jpake.h b/crypto/openssh/jpake.h
new file mode 100644
index 0000000..a3f2cf0
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/kex.c b/crypto/openssh/kex.c
new file mode 100644
index 0000000..f4f44f0
--- /dev/null
+++ b/crypto/openssh/kex.c
@@ -0,0 +1,567 @@
+/* $OpenBSD: kex.c,v 1.81 2009/05/27 06:34:36 andreas 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"
+
+#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 *);
+
+/* 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_string(&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();
+#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;
+ }
+
+ /* 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)
+void
+dump_digest(char *msg, u_char *digest, int len)
+{
+ u_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/crypto/openssh/kex.h b/crypto/openssh/kex.h
new file mode 100644
index 0000000..68c80c5
--- /dev/null
+++ b/crypto/openssh/kex.h
@@ -0,0 +1,161 @@
+/* $OpenBSD: kex.h,v 1.47 2009/05/27 06:34:36 andreas 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>
+
+#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 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_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;
+ 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_key)(int);
+ int (*host_key_index)(Key *);
+ void (*kex[KEX_MAX])(Kex *);
+};
+
+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
+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 *);
+
+void
+derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
+
+#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
+void dump_digest(char *, u_char *, int);
+#endif
+
+#endif
diff --git a/crypto/openssh/kexdh.c b/crypto/openssh/kexdh.c
new file mode 100644
index 0000000..56e22f5
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/kexdhc.c b/crypto/openssh/kexdhc.c
new file mode 100644
index 0000000..d384c80
--- /dev/null
+++ b/crypto/openssh/kexdhc.c
@@ -0,0 +1,159 @@
+/* $OpenBSD: kexdhc.c,v 1.11 2006/11/06 21:25:28 markus Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.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/crypto/openssh/kexdhs.c b/crypto/openssh/kexdhs.c
new file mode 100644
index 0000000..a6719f6
--- /dev/null
+++ b/crypto/openssh/kexdhs.c
@@ -0,0 +1,161 @@
+/* $OpenBSD: kexdhs.c,v 1.10 2009/06/21 07:37:15 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 <stdarg.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"
+
+void
+kexdh_server(Kex *kex)
+{
+ BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+ DH *dh;
+ Key *server_host_key;
+ u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
+ u_int sbloblen, klen, 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_key == NULL)
+ fatal("Cannot load hostkey");
+ server_host_key = kex->load_host_key(kex->hostkey_type);
+ if (server_host_key == NULL)
+ fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+ /* key, cert */
+ 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_key, &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_key, &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/crypto/openssh/kexgex.c b/crypto/openssh/kexgex.c
new file mode 100644
index 0000000..b60ab5c
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/kexgexc.c b/crypto/openssh/kexgexc.c
new file mode 100644
index 0000000..adb973d
--- /dev/null
+++ b/crypto/openssh/kexgexc.c
@@ -0,0 +1,205 @@
+/* $OpenBSD: kexgexc.c,v 1.11 2006/11/06 21:25:28 markus 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 <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/crypto/openssh/kexgexs.c b/crypto/openssh/kexgexs.c
new file mode 100644
index 0000000..8515568
--- /dev/null
+++ b/crypto/openssh/kexgexs.c
@@ -0,0 +1,205 @@
+/* $OpenBSD: kexgexs.c,v 1.12 2009/06/21 07:37:15 dtucker 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 "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_key;
+ 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_key == NULL)
+ fatal("Cannot load hostkey");
+ server_host_key = kex->load_host_key(kex->hostkey_type);
+ if (server_host_key == NULL)
+ fatal("Unsupported hostkey type %d", kex->hostkey_type);
+
+ type = packet_read();
+ 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_key, &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_key, &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/crypto/openssh/key.c b/crypto/openssh/key.c
new file mode 100644
index 0000000..3e17da6
--- /dev/null
+++ b/crypto/openssh/key.c
@@ -0,0 +1,982 @@
+/* $OpenBSD: key.c,v 1.80 2008/10/10 05:00:12 stevesk 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"
+
+Key *
+key_new(int type)
+{
+ Key *k;
+ RSA *rsa;
+ DSA *dsa;
+ k = xcalloc(1, sizeof(*k));
+ k->type = type;
+ k->dsa = NULL;
+ k->rsa = NULL;
+ switch (k->type) {
+ case KEY_RSA1:
+ case KEY_RSA:
+ 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:
+ 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;
+ case KEY_UNSPEC:
+ break;
+ default:
+ fatal("key_new: bad key type %d", k->type);
+ break;
+ }
+ return k;
+}
+
+Key *
+key_new_private(int type)
+{
+ Key *k = key_new(type);
+ switch (k->type) {
+ case KEY_RSA1:
+ case KEY_RSA:
+ 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:
+ if ((k->dsa->priv_key = BN_new()) == NULL)
+ fatal("key_new_private: BN_new failed");
+ break;
+ case KEY_UNSPEC:
+ break;
+ default:
+ break;
+ }
+ return k;
+}
+
+void
+key_free(Key *k)
+{
+ if (k == NULL)
+ fatal("key_free: key is NULL");
+ switch (k->type) {
+ case KEY_RSA1:
+ case KEY_RSA:
+ if (k->rsa != NULL)
+ RSA_free(k->rsa);
+ k->rsa = NULL;
+ break;
+ case KEY_DSA:
+ if (k->dsa != NULL)
+ DSA_free(k->dsa);
+ k->dsa = NULL;
+ break;
+ case KEY_UNSPEC:
+ break;
+ default:
+ fatal("key_free: bad key type %d", k->type);
+ break;
+ }
+ xfree(k);
+}
+
+int
+key_equal(const Key *a, const Key *b)
+{
+ if (a == NULL || b == NULL || a->type != b->type)
+ return 0;
+ switch (a->type) {
+ case KEY_RSA1:
+ case KEY_RSA:
+ return a->rsa != NULL && b->rsa != NULL &&
+ BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
+ BN_cmp(a->rsa->n, b->rsa->n) == 0;
+ 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;
+ default:
+ fatal("key_equal: bad key type %d", a->type);
+ }
+ /* NOTREACHED */
+}
+
+u_char*
+key_fingerprint_raw(const 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;
+
+ *dgst_raw_length = 0;
+
+ switch (dgst_type) {
+ case SSH_FP_MD5:
+ md = EVP_md5();
+ break;
+ case SSH_FP_SHA1:
+ md = EVP_sha1();
+ break;
+ default:
+ fatal("key_fingerprint_raw: bad digest type %d",
+ dgst_type);
+ }
+ switch (k->type) {
+ case KEY_RSA1:
+ nlen = BN_num_bytes(k->rsa->n);
+ elen = BN_num_bytes(k->rsa->e);
+ len = nlen + elen;
+ blob = xmalloc(len);
+ BN_bn2bin(k->rsa->n, blob);
+ BN_bn2bin(k->rsa->e, blob + nlen);
+ break;
+ case KEY_DSA:
+ case KEY_RSA:
+ key_to_blob(k, &blob, &len);
+ break;
+ case KEY_UNSPEC:
+ return retval;
+ 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(const 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;
+
+ cp = *cpp;
+
+ switch (ret->type) {
+ case KEY_RSA1:
+ /* Get number of bits. */
+ if (*cp < '0' || *cp > '9')
+ return -1; /* Bad bit count... */
+ for (bits = 0; *cp >= '0' && *cp <= '9'; cp++)
+ bits = 10 * bits + *cp - '0';
+ if (bits == 0)
+ return -1;
+ *cpp = cp;
+ /* Get public exponent, public modulus. */
+ if (!read_bignum(cpp, ret->rsa->e))
+ return -1;
+ if (!read_bignum(cpp, ret->rsa->n))
+ return -1;
+ success = 1;
+ break;
+ case KEY_UNSPEC:
+ case KEY_RSA:
+ case KEY_DSA:
+ space = strchr(cp, ' ');
+ if (space == NULL) {
+ debug3("key_read: missing whitespace");
+ return -1;
+ }
+ *space = '\0';
+ type = key_type_from_name(cp);
+ *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;
+ }
+/*XXXX*/
+ if (ret->type == KEY_RSA) {
+ if (ret->rsa != NULL)
+ RSA_free(ret->rsa);
+ ret->rsa = k->rsa;
+ k->rsa = NULL;
+ success = 1;
+#ifdef DEBUG_PK
+ RSA_print_fp(stderr, ret->rsa, 8);
+#endif
+ } else {
+ if (ret->dsa != NULL)
+ DSA_free(ret->dsa);
+ ret->dsa = k->dsa;
+ k->dsa = NULL;
+ success = 1;
+#ifdef DEBUG_PK
+ DSA_print_fp(stderr, ret->dsa, 8);
+#endif
+ }
+/*XXXX*/
+ 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->type == KEY_RSA1 && key->rsa != NULL) {
+ /* size of modulus 'n' */
+ bits = BN_num_bits(key->rsa->n);
+ fprintf(f, "%u", bits);
+ if (write_bignum(f, key->rsa->e) &&
+ write_bignum(f, key->rsa->n)) {
+ success = 1;
+ } else {
+ error("key_write: failed for RSA key");
+ }
+ } else if ((key->type == KEY_DSA && key->dsa != NULL) ||
+ (key->type == KEY_RSA && key->rsa != NULL)) {
+ 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";
+ }
+ return "unknown";
+}
+
+const char *
+key_ssh_name(const Key *k)
+{
+ switch (k->type) {
+ case KEY_RSA:
+ return "ssh-rsa";
+ case KEY_DSA:
+ return "ssh-dss";
+ }
+ return "ssh-unknown";
+}
+
+u_int
+key_size(const Key *k)
+{
+ switch (k->type) {
+ case KEY_RSA1:
+ case KEY_RSA:
+ return BN_num_bits(k->rsa->n);
+ case KEY_DSA:
+ return BN_num_bits(k->dsa->p);
+ }
+ return 0;
+}
+
+static RSA *
+rsa_generate_private_key(u_int bits)
+{
+ RSA *private;
+
+ private = RSA_generate_key(bits, 35, NULL, NULL);
+ if (private == NULL)
+ fatal("rsa_generate_private_key: key generation failed.");
+ return private;
+}
+
+static DSA*
+dsa_generate_private_key(u_int bits)
+{
+ DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
+
+ if (private == NULL)
+ fatal("dsa_generate_private_key: DSA_generate_parameters failed");
+ if (!DSA_generate_key(private))
+ fatal("dsa_generate_private_key: DSA_generate_key failed.");
+ if (private == NULL)
+ fatal("dsa_generate_private_key: NULL.");
+ return private;
+}
+
+Key *
+key_generate(int type, u_int bits)
+{
+ Key *k = key_new(KEY_UNSPEC);
+ switch (type) {
+ case KEY_DSA:
+ k->dsa = dsa_generate_private_key(bits);
+ break;
+ case KEY_RSA:
+ case KEY_RSA1:
+ k->rsa = rsa_generate_private_key(bits);
+ break;
+ default:
+ fatal("key_generate: unknown type %d", type);
+ }
+ k->type = type;
+ return k;
+}
+
+Key *
+key_from_private(const Key *k)
+{
+ Key *n = NULL;
+ switch (k->type) {
+ case KEY_DSA:
+ 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;
+ case KEY_RSA:
+ case KEY_RSA1:
+ 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;
+ }
+ return n;
+}
+
+int
+key_type_from_name(char *name)
+{
+ if (strcmp(name, "rsa1") == 0) {
+ return KEY_RSA1;
+ } else if (strcmp(name, "rsa") == 0) {
+ return KEY_RSA;
+ } else if (strcmp(name, "dsa") == 0) {
+ return KEY_DSA;
+ } else if (strcmp(name, "ssh-rsa") == 0) {
+ return KEY_RSA;
+ } else if (strcmp(name, "ssh-dss") == 0) {
+ return KEY_DSA;
+ }
+ debug2("key_type_from_name: unknown key type '%s'", name);
+ return KEY_UNSPEC;
+}
+
+int
+key_names_valid2(const char *names)
+{
+ char *s, *cp, *p;
+
+ if (names == NULL || strcmp(names, "") == 0)
+ return 0;
+ s = cp = xstrdup(names);
+ for ((p = strsep(&cp, ",")); p && *p != '\0';
+ (p = strsep(&cp, ","))) {
+ switch (key_type_from_name(p)) {
+ case KEY_RSA1:
+ case KEY_UNSPEC:
+ xfree(s);
+ return 0;
+ }
+ }
+ debug3("key names ok: [%s]", names);
+ xfree(s);
+ return 1;
+}
+
+Key *
+key_from_blob(const u_char *blob, u_int blen)
+{
+ Buffer b;
+ int rlen, type;
+ char *ktype = NULL;
+ Key *key = NULL;
+
+#ifdef DEBUG_PK
+ dump_base64(stderr, blob, blen);
+#endif
+ buffer_init(&b);
+ buffer_append(&b, blob, blen);
+ if ((ktype = buffer_get_string_ret(&b, NULL)) == NULL) {
+ error("key_from_blob: can't read key type");
+ goto out;
+ }
+
+ type = key_type_from_name(ktype);
+
+ switch (type) {
+ case KEY_RSA:
+ 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");
+ key_free(key);
+ key = NULL;
+ goto out;
+ }
+#ifdef DEBUG_PK
+ RSA_print_fp(stderr, key->rsa, 8);
+#endif
+ break;
+ case KEY_DSA:
+ 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");
+ key_free(key);
+ key = NULL;
+ goto out;
+ }
+#ifdef DEBUG_PK
+ DSA_print_fp(stderr, key->dsa, 8);
+#endif
+ break;
+ case KEY_UNSPEC:
+ key = key_new(type);
+ break;
+ default:
+ error("key_from_blob: cannot handle type %s", ktype);
+ goto out;
+ }
+ 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);
+ 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:
+ buffer_put_cstring(&b, key_ssh_name(key));
+ buffer_put_bignum2(&b, key->dsa->p);
+ buffer_put_bignum2(&b, key->dsa->q);
+ buffer_put_bignum2(&b, key->dsa->g);
+ buffer_put_bignum2(&b, key->dsa->pub_key);
+ break;
+ case KEY_RSA:
+ buffer_put_cstring(&b, key_ssh_name(key));
+ buffer_put_bignum2(&b, key->rsa->e);
+ buffer_put_bignum2(&b, key->rsa->n);
+ break;
+ default:
+ error("key_to_blob: unsupported key type %d", key->type);
+ buffer_free(&b);
+ return 0;
+ }
+ len = buffer_len(&b);
+ 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:
+ return ssh_dss_sign(key, sigp, lenp, data, datalen);
+ 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:
+ return ssh_dss_verify(key, signature, signaturelen, data, datalen);
+ 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->dsa = NULL;
+ pk->rsa = NULL;
+
+ switch (k->type) {
+ 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:
+ 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;
+ default:
+ fatal("key_free: bad key type %d", k->type);
+ break;
+ }
+
+ return (pk);
+}
diff --git a/crypto/openssh/key.h b/crypto/openssh/key.h
new file mode 100644
index 0000000..14aac79
--- /dev/null
+++ b/crypto/openssh/key.h
@@ -0,0 +1,88 @@
+/* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */
+
+/*
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef KEY_H
+#define KEY_H
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+
+typedef struct Key Key;
+enum types {
+ KEY_RSA1,
+ KEY_RSA,
+ KEY_DSA,
+ KEY_UNSPEC
+};
+enum fp_type {
+ SSH_FP_SHA1,
+ SSH_FP_MD5
+};
+enum fp_rep {
+ SSH_FP_HEX,
+ SSH_FP_BUBBLEBABBLE,
+ SSH_FP_RANDOMART
+};
+
+/* key is stored in external hardware */
+#define KEY_FLAG_EXT 0x0001
+
+struct Key {
+ int type;
+ int flags;
+ RSA *rsa;
+ DSA *dsa;
+};
+
+Key *key_new(int);
+Key *key_new_private(int);
+void key_free(Key *);
+Key *key_demote(const Key *);
+int key_equal(const Key *, const Key *);
+char *key_fingerprint(const Key *, enum fp_type, enum fp_rep);
+u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *);
+const char *key_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 *);
+
+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 *);
+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_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);
+
+#endif
diff --git a/crypto/openssh/log.c b/crypto/openssh/log.c
new file mode 100644
index 0000000..4a8239b
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/log.h b/crypto/openssh/log.h
new file mode 100644
index 0000000..6505827
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/loginrec.c b/crypto/openssh/loginrec.c
new file mode 100644
index 0000000..f4af067
--- /dev/null
+++ b/crypto/openssh/loginrec.c
@@ -0,0 +1,1688 @@
+/*
+ * 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 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 int uid)
+{
+ struct logininfo li;
+
+ if (login_get_lastlog(&li, uid))
+ return (li.tv_sec);
+ else
+ return (0);
+}
+
+/*
+ * login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry
+ *
+ * Retrieve a logininfo structure populated (only partially) with
+ * information from the system lastlog data, or from wtmp/wtmpx if no
+ * system lastlog information exists.
+ *
+ * Note this routine must be given a pre-allocated logininfo.
+ *
+ * Returns:
+ * >0: A pointer to your struct logininfo if successful
+ * 0 on failure (will use OpenSSH's logging facilities for diagnostics)
+ */
+struct logininfo *
+login_get_lastlog(struct logininfo *li, const int uid)
+{
+ struct passwd *pw;
+
+ memset(li, '\0', sizeof(*li));
+ li->uid = uid;
+
+ /*
+ * If we don't have a 'real' lastlog, we need the username to
+ * reliably search wtmp(x) for the last login (see
+ * wtmp_get_entry().)
+ */
+ pw = getpwuid(uid);
+ if (pw == NULL)
+ fatal("%s: Cannot find account for uid %i", __func__, 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(int 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, int pid, const char *username,
+ const char *hostname, const char *line)
+{
+ struct passwd *pw;
+
+ memset(li, 0, sizeof(*li));
+
+ li->pid = pid;
+
+ /* set the line information */
+ if (line)
+ line_fullname(li->line, line, sizeof(li->line));
+
+ if (username) {
+ strlcpy(li->username, username, sizeof(li->username));
+ pw = getpwnam(li->username);
+ if (pw == NULL) {
+ fatal("%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->line);
+ else if (li->type == LTYPE_LOGOUT)
+ audit_session_close(li->line);
+#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(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_name, li->username,
+ MIN_SIZEOF(utx->ut_name, 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));
+ return (0);
+ }
+ if (ret != pos) {
+ logit("%s: Couldn't seek to tty %d slot in %s",
+ __func__, tty, UTMP_FILE);
+ 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));
+ return (0);
+ }
+ if (ret != pos) {
+ logit("%s: Couldn't seek to tty %d slot in %s",
+ __func__, tty, UTMP_FILE);
+ 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 (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_name,
+ MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) {
+# ifdef HAVE_TYPE_IN_UTMPX
+ if (utx->ut_type == USER_PROCESS)
+ return (1);
+# else
+ return (1);
+# endif
+ }
+ return (0);
+}
+
+
+int
+wtmpx_get_entry(struct logininfo *li)
+{
+ struct stat st;
+ struct utmpx utx;
+ int fd, found=0;
+
+ /* Clear the time entries */
+ li->tv_sec = li->tv_usec = 0;
+
+ if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) {
+ 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) ((long)li->uid * sizeof(struct lastlog));
+
+ if (lseek(*fd, offset, SEEK_SET) != offset) {
+ logit("%s: %s->lseek(): %s", __func__,
+ lastlog_file, strerror(errno));
+ 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 */
+
+#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_IRWXG | 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/crypto/openssh/loginrec.h b/crypto/openssh/loginrec.h
new file mode 100644
index 0000000..859e1a6
--- /dev/null
+++ b/crypto/openssh/loginrec.h
@@ -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 128
+#define LINFO_HOSTSIZE 256
+
+struct logininfo {
+ char progname[LINFO_PROGSIZE]; /* name of program (for PAM) */
+ int progname_null;
+ short int type; /* type of login (LTYPE_*) */
+ int pid; /* PID of login process */
+ int uid; /* UID of this user */
+ char line[LINFO_LINESIZE]; /* tty/pty name */
+ char username[LINFO_NAMESIZE]; /* login username */
+ char hostname[LINFO_HOSTSIZE]; /* remote hostname */
+ /* 'exit_status' structure components */
+ int exit; /* process exit status */
+ int termination; /* process termination status */
+ /* struct timeval (sys/time.h) isn't always available, if it isn't we'll
+ * use time_t's value as tv_sec and set tv_usec to 0
+ */
+ unsigned int tv_sec;
+ unsigned int tv_usec;
+ union login_netinfo hostaddr; /* caller's host address(es) */
+}; /* struct logininfo */
+
+/*
+ * login recording functions
+ */
+
+/** 'public' functions */
+
+/* construct a new login entry */
+struct logininfo *login_alloc_entry(int pid, const char *username,
+ const char *hostname, const char *line);
+/* free a structure */
+void login_free_entry(struct logininfo *li);
+/* fill out a pre-allocated structure with useful information */
+int login_init_entry(struct logininfo *li, int pid, const char *username,
+ const char *hostname, const char *line);
+/* place the current time in a logininfo struct */
+void login_set_current_time(struct logininfo *li);
+
+/* record the entry */
+int login_login (struct logininfo *li);
+int login_logout(struct logininfo *li);
+#ifdef LOGIN_NEEDS_UTMPX
+int login_utmp_only(struct logininfo *li);
+#endif
+
+/** End of public functions */
+
+/* record the entry */
+int login_write (struct logininfo *li);
+int login_log_entry(struct logininfo *li);
+
+/* set the network address based on network address type */
+void login_set_addr(struct logininfo *li, const struct sockaddr *sa,
+ const unsigned int sa_size);
+
+/*
+ * lastlog retrieval functions
+ */
+/* lastlog *entry* functions fill out a logininfo */
+struct logininfo *login_get_lastlog(struct logininfo *li, const int uid);
+/* lastlog *time* functions return time_t equivalent (uint) */
+unsigned int login_get_lastlog_time(const int uid);
+
+/* produce various forms of the line filename */
+char *line_fullname(char *dst, const char *src, 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/crypto/openssh/logintest.c b/crypto/openssh/logintest.c
new file mode 100644
index 0000000..7e9fbbf
--- /dev/null
+++ b/crypto/openssh/logintest.c
@@ -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 (UTMPX_FILE=%s)\n", UTMPX_FILE);
+#endif
+#ifdef USE_WTMP
+ printf("\tUSE_WTMP (WTMP_FILE=%s)\n", WTMP_FILE);
+#endif
+#ifdef USE_WTMPX
+ printf("\tUSE_WTMPX (WTMPX_FILE=%s)\n", WTMPX_FILE);
+#endif
+#ifdef USE_LASTLOG
+ printf("\tUSE_LASTLOG (LASTLOG_FILE=%s)\n", LASTLOG_FILE);
+#endif
+ printf("\n");
+
+} /* showOptions() */
+
+
+int
+main(int argc, char *argv[])
+{
+ printf("Platform-independent login recording test driver\n");
+
+ __progname = 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/crypto/openssh/mac.c b/crypto/openssh/mac.c
new file mode 100644
index 0000000..fabc3ed
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/mac.h b/crypto/openssh/mac.h
new file mode 100644
index 0000000..39f564d
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/match.c b/crypto/openssh/match.c
new file mode 100644
index 0000000..2389477
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/match.h b/crypto/openssh/match.h
new file mode 100644
index 0000000..18f6830
--- /dev/null
+++ b/crypto/openssh/match.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: match.h,v 1.14 2008/06/10 03:57:27 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 *);
+
+#endif
diff --git a/crypto/openssh/md-sha256.c b/crypto/openssh/md-sha256.c
new file mode 100644
index 0000000..8c1b3b9
--- /dev/null
+++ b/crypto/openssh/md-sha256.c
@@ -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/crypto/openssh/md5crypt.c b/crypto/openssh/md5crypt.c
new file mode 100644
index 0000000..22ef989
--- /dev/null
+++ b/crypto/openssh/md5crypt.c
@@ -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/crypto/openssh/md5crypt.h b/crypto/openssh/md5crypt.h
new file mode 100644
index 0000000..2341e2c
--- /dev/null
+++ b/crypto/openssh/md5crypt.h
@@ -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/crypto/openssh/misc.c b/crypto/openssh/misc.c
new file mode 100644
index 0000000..143dbf0
--- /dev/null
+++ b/crypto/openssh/misc.c
@@ -0,0 +1,851 @@
+/* $OpenBSD: misc.c,v 1.71 2009/02/21 19:32:04 tobias 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 <unistd.h>
+
+#include <netinet/in.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';
+ 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 (0);
+ if (*cp == '[')
+ flag = 1;
+
+ for (; *cp; ++cp) {
+ if (*cp == '@' && *(cp+1) == '[')
+ flag = 1;
+ if (*cp == ']' && *(cp+1) == ':' && flag)
+ return (cp+1);
+ if (*cp == ':' && !flag)
+ return (cp);
+ if (*cp == '/')
+ return (0);
+ }
+ return (0);
+}
+
+/* function to assist building execv() arguments */
+void
+addargs(arglist *args, char *fmt, ...)
+{
+ va_list ap;
+ char *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
+ struct {
+ const char *key;
+ const char *repl;
+ } keys[EXPAND_MAX_KEYS];
+ u_int num_keys, i, j;
+ 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("percent_expand: NULL replacement");
+ }
+ va_end(ap);
+
+ if (num_keys >= EXPAND_MAX_KEYS)
+ fatal("percent_expand: too many keys");
+
+ /* Expand string */
+ *buf = '\0';
+ for (i = 0; *string != '\0'; string++) {
+ if (*string != '%') {
+ append:
+ buf[i++] = *string;
+ if (i >= sizeof(buf))
+ fatal("percent_expand: string too long");
+ buf[i] = '\0';
+ continue;
+ }
+ string++;
+ 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("percent_expand: string too long");
+ break;
+ }
+ }
+ if (j >= num_keys)
+ fatal("percent_expand: unknown key %%%c", *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;
+}
+
diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h
new file mode 100644
index 0000000..5da170d
--- /dev/null
+++ b/crypto/openssh/misc.h
@@ -0,0 +1,93 @@
+/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 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 _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);
+
+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)));
+
+
+/* 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/crypto/openssh/mkinstalldirs b/crypto/openssh/mkinstalldirs
new file mode 100755
index 0000000..47d5f43
--- /dev/null
+++ b/crypto/openssh/mkinstalldirs
@@ -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/crypto/openssh/moduli b/crypto/openssh/moduli
new file mode 100644
index 0000000..65d2814
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/moduli.5 b/crypto/openssh/moduli.5
new file mode 100644
index 0000000..d8c9464
--- /dev/null
+++ b/crypto/openssh/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 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/crypto/openssh/moduli.c b/crypto/openssh/moduli.c
new file mode 100644
index 0000000..f737cb3
--- /dev/null
+++ b/crypto/openssh/moduli.c
@@ -0,0 +1,650 @@
+/* $OpenBSD: moduli.c,v 1.21 2008/06/26 09:19:40 djm Exp $ */
+/*
+ * Copyright 1994 Phil Karn <karn@qualcomm.com>
+ * Copyright 1996-1998, 2003 William Allen Simpson <wsimpson@greendragon.com>
+ * 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"
+
+/*
+ * 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(q, 1, NULL, 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(p, trials, NULL, 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(q, trials - 1, NULL, 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/crypto/openssh/monitor.c b/crypto/openssh/monitor.c
new file mode 100644
index 0000000..ace25c4
--- /dev/null
+++ b/crypto/openssh/monitor.c
@@ -0,0 +1,2211 @@
+/* $OpenBSD: monitor.c,v 1.104 2009/06/12 20:43:22 andreas 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 ||
+ memcmp(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 will only return SHA1 (20 byte) or
+ * SHA256 (32 byte) hashes
+ */
+ if (datlen != 20 && datlen != 32)
+ 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, *info, **prompts;
+ u_int i, num, *echo_on;
+ 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
+
+static void
+mm_append_debug(Buffer *m)
+{
+ if (auth_debug_init && buffer_len(&auth_debug)) {
+ debug3("%s: Appending debug messages for child", __func__);
+ buffer_append(m, buffer_ptr(&auth_debug),
+ buffer_len(&auth_debug));
+ buffer_clear(&auth_debug);
+ }
+}
+
+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_append_debug(m);
+
+ 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) ||
+ (memcmp(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) ||
+ (memcmp(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) ||
+ (memcmp(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_append_debug(m);
+
+ 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) ||
+ (memcmp(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->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_key=&get_hostkey_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/crypto/openssh/monitor.h b/crypto/openssh/monitor.h
new file mode 100644
index 0000000..a8a2c0c
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/monitor_fdpass.c b/crypto/openssh/monitor_fdpass.c
new file mode 100644
index 0000000..4b9a066
--- /dev/null
+++ b/crypto/openssh/monitor_fdpass.c
@@ -0,0 +1,169 @@
+/* $OpenBSD: monitor_fdpass.c,v 1.18 2008/11/30 11:59:26 dtucker 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>
+#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;
+
+ 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;
+
+ while ((n = sendmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN ||
+ errno == EINTR))
+ debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno));
+ 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;
+
+ 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
+
+ while ((n = recvmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN ||
+ errno == EINTR))
+ debug3("%s: recvmsg: %s", __func__, strerror(errno));
+ 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/crypto/openssh/monitor_fdpass.h b/crypto/openssh/monitor_fdpass.h
new file mode 100644
index 0000000..a4b1f63
--- /dev/null
+++ b/crypto/openssh/monitor_fdpass.h
@@ -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/crypto/openssh/monitor_mm.c b/crypto/openssh/monitor_mm.c
new file mode 100644
index 0000000..faf9f3d
--- /dev/null
+++ b/crypto/openssh/monitor_mm.c
@@ -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/crypto/openssh/monitor_mm.h b/crypto/openssh/monitor_mm.h
new file mode 100644
index 0000000..c890f77
--- /dev/null
+++ b/crypto/openssh/monitor_mm.h
@@ -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/crypto/openssh/monitor_wrap.c b/crypto/openssh/monitor_wrap.c
new file mode 100644
index 0000000..b8e8710
--- /dev/null
+++ b/crypto/openssh/monitor_wrap.c
@@ -0,0 +1,1430 @@
+/* $OpenBSD: monitor_wrap.c,v 1.68 2009/06/22 05:39:28 dtucker 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 "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);
+}
+
+static void
+mm_send_debug(Buffer *m)
+{
+ char *msg;
+
+ while (buffer_len(m)) {
+ msg = buffer_get_string(m, NULL);
+ debug3("%s: Sending debug: %s", __func__, msg);
+ packet_send_debug("%s", msg);
+ xfree(msg);
+ }
+}
+
+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;
+
+ /* Send potential debug messages */
+ mm_send_debug(&m);
+
+ 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);
+ }
+ mm_send_debug(&m);
+ 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/crypto/openssh/monitor_wrap.h b/crypto/openssh/monitor_wrap.h
new file mode 100644
index 0000000..de2d16f
--- /dev/null
+++ b/crypto/openssh/monitor_wrap.h
@@ -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/crypto/openssh/msg.c b/crypto/openssh/msg.c
new file mode 100644
index 0000000..cd5f98c
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/msg.h b/crypto/openssh/msg.h
new file mode 100644
index 0000000..b0cb9b5
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/mux.c b/crypto/openssh/mux.c
new file mode 100644
index 0000000..79f8376
--- /dev/null
+++ b/crypto/openssh/mux.c
@@ -0,0 +1,728 @@
+/* $OpenBSD: mux.c,v 1.7 2008/06/13 17:21:20 dtucker Exp $ */
+/*
+ * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* ssh session multiplexing support */
+
+#include "includes.h"
+
+/*
+ * TODO:
+ * 1. partial reads in muxserver_accept_control (maybe make channels
+ * from accepted connections)
+ * 2. Better signalling from master to slave, especially passing of
+ * error messages
+ * 3. Better fall-back from mux slave error to new connection.
+ * 3. Add/delete forwardings via slave
+ * 4. ExitOnForwardingFailure (after #3 obviously)
+ * 5. Maybe extension mechanisms for multi-X11/multi-agent forwarding
+ * 6. Document the mux mini-protocol somewhere.
+ * 7. Support ~^Z in mux slaves.
+ * 8. Inspect or control sessions in master.
+ * 9. If we ever support the "signal" channel request, send signals on
+ * sessions in master.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
+#include "openbsd-compat/sys-queue.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "ssh.h"
+#include "pathnames.h"
+#include "misc.h"
+#include "match.h"
+#include "buffer.h"
+#include "channels.h"
+#include "msg.h"
+#include "packet.h"
+#include "monitor_fdpass.h"
+#include "sshpty.h"
+#include "key.h"
+#include "readconf.h"
+#include "clientloop.h"
+
+/* from ssh.c */
+extern int tty_flag;
+extern Options options;
+extern int stdin_null_flag;
+extern char *host;
+int subsystem_flag;
+extern Buffer command;
+
+/* Context for session open confirmation callback */
+struct mux_session_confirm_ctx {
+ int want_tty;
+ int want_subsys;
+ int want_x_fwd;
+ int want_agent_fwd;
+ Buffer cmd;
+ char *term;
+ struct termios tio;
+ char **env;
+};
+
+/* fd to control socket */
+int muxserver_sock = -1;
+
+/* Multiplexing control command */
+u_int muxclient_command = 0;
+
+/* Set when signalled. */
+static volatile sig_atomic_t muxclient_terminate = 0;
+
+/* PID of multiplex server */
+static u_int muxserver_pid = 0;
+
+
+/* ** Multiplexing master support */
+
+/* Prepare a mux master to listen on a Unix domain socket. */
+void
+muxserver_listen(void)
+{
+ struct sockaddr_un addr;
+ mode_t old_umask;
+ int addr_len;
+
+ if (options.control_path == NULL ||
+ options.control_master == SSHCTL_MASTER_NO)
+ return;
+
+ debug("setting up multiplex master socket");
+
+ memset(&addr, '\0', sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr_len = offsetof(struct sockaddr_un, sun_path) +
+ strlen(options.control_path) + 1;
+
+ if (strlcpy(addr.sun_path, options.control_path,
+ sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+ fatal("ControlPath too long");
+
+ if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ fatal("%s socket(): %s", __func__, strerror(errno));
+
+ old_umask = umask(0177);
+ if (bind(muxserver_sock, (struct sockaddr *)&addr, addr_len) == -1) {
+ muxserver_sock = -1;
+ if (errno == EINVAL || errno == EADDRINUSE) {
+ error("ControlSocket %s already exists, "
+ "disabling multiplexing", options.control_path);
+ close(muxserver_sock);
+ muxserver_sock = -1;
+ xfree(options.control_path);
+ options.control_path = NULL;
+ options.control_master = SSHCTL_MASTER_NO;
+ return;
+ } else
+ fatal("%s bind(): %s", __func__, strerror(errno));
+ }
+ umask(old_umask);
+
+ if (listen(muxserver_sock, 64) == -1)
+ fatal("%s listen(): %s", __func__, strerror(errno));
+
+ set_nonblock(muxserver_sock);
+}
+
+/* Callback on open confirmation in mux master for a mux client session. */
+static void
+mux_session_confirm(int id, void *arg)
+{
+ struct mux_session_confirm_ctx *cctx = arg;
+ const char *display;
+ Channel *c;
+ int i;
+
+ if (cctx == NULL)
+ fatal("%s: cctx == NULL", __func__);
+ if ((c = channel_lookup(id)) == NULL)
+ fatal("%s: no channel for id %d", __func__, id);
+
+ display = getenv("DISPLAY");
+ if (cctx->want_x_fwd && options.forward_x11 && display != NULL) {
+ char *proto, *data;
+ /* Get reasonable local authentication information. */
+ client_x11_get_proto(display, options.xauth_location,
+ options.forward_x11_trusted, &proto, &data);
+ /* Request forwarding with authentication spoofing. */
+ debug("Requesting X11 forwarding with authentication spoofing.");
+ x11_request_forwarding_with_spoofing(id, display, proto, data);
+ /* XXX wait for reply */
+ }
+
+ if (cctx->want_agent_fwd && options.forward_agent) {
+ debug("Requesting authentication agent forwarding.");
+ channel_request_start(id, "auth-agent-req@openssh.com", 0);
+ packet_send();
+ }
+
+ client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
+ cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
+
+ c->open_confirm_ctx = NULL;
+ buffer_free(&cctx->cmd);
+ xfree(cctx->term);
+ if (cctx->env != NULL) {
+ for (i = 0; cctx->env[i] != NULL; i++)
+ xfree(cctx->env[i]);
+ xfree(cctx->env);
+ }
+ xfree(cctx);
+}
+
+/*
+ * Accept a connection on the mux master socket and process the
+ * client's request. Returns flag indicating whether mux master should
+ * begin graceful close.
+ */
+int
+muxserver_accept_control(void)
+{
+ Buffer m;
+ Channel *c;
+ int client_fd, new_fd[3], ver, allowed, window, packetmax;
+ socklen_t addrlen;
+ struct sockaddr_storage addr;
+ struct mux_session_confirm_ctx *cctx;
+ char *cmd;
+ u_int i, j, len, env_len, mux_command, flags, escape_char;
+ uid_t euid;
+ gid_t egid;
+ int start_close = 0;
+
+ /*
+ * Accept connection on control socket
+ */
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+ if ((client_fd = accept(muxserver_sock,
+ (struct sockaddr*)&addr, &addrlen)) == -1) {
+ error("%s accept: %s", __func__, strerror(errno));
+ return 0;
+ }
+
+ if (getpeereid(client_fd, &euid, &egid) < 0) {
+ error("%s getpeereid failed: %s", __func__, strerror(errno));
+ close(client_fd);
+ return 0;
+ }
+ if ((euid != 0) && (getuid() != euid)) {
+ error("control mode uid mismatch: peer euid %u != uid %u",
+ (u_int) euid, (u_int) getuid());
+ close(client_fd);
+ return 0;
+ }
+
+ /* XXX handle asynchronously */
+ unset_nonblock(client_fd);
+
+ /* Read command */
+ buffer_init(&m);
+ if (ssh_msg_recv(client_fd, &m) == -1) {
+ error("%s: client msg_recv failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return 0;
+ }
+ if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
+ error("%s: wrong client version %d", __func__, ver);
+ buffer_free(&m);
+ close(client_fd);
+ return 0;
+ }
+
+ allowed = 1;
+ mux_command = buffer_get_int(&m);
+ flags = buffer_get_int(&m);
+
+ buffer_clear(&m);
+
+ switch (mux_command) {
+ case SSHMUX_COMMAND_OPEN:
+ if (options.control_master == SSHCTL_MASTER_ASK ||
+ options.control_master == SSHCTL_MASTER_AUTO_ASK)
+ allowed = ask_permission("Allow shared connection "
+ "to %s? ", host);
+ /* continue below */
+ break;
+ case SSHMUX_COMMAND_TERMINATE:
+ if (options.control_master == SSHCTL_MASTER_ASK ||
+ options.control_master == SSHCTL_MASTER_AUTO_ASK)
+ allowed = ask_permission("Terminate shared connection "
+ "to %s? ", host);
+ if (allowed)
+ start_close = 1;
+ /* FALLTHROUGH */
+ case SSHMUX_COMMAND_ALIVE_CHECK:
+ /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */
+ buffer_clear(&m);
+ buffer_put_int(&m, allowed);
+ buffer_put_int(&m, getpid());
+ if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+ error("%s: client msg_send failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return start_close;
+ }
+ buffer_free(&m);
+ close(client_fd);
+ return start_close;
+ default:
+ error("Unsupported command %d", mux_command);
+ buffer_free(&m);
+ close(client_fd);
+ return 0;
+ }
+
+ /* Reply for SSHMUX_COMMAND_OPEN */
+ buffer_clear(&m);
+ buffer_put_int(&m, allowed);
+ buffer_put_int(&m, getpid());
+ if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+ error("%s: client msg_send failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return 0;
+ }
+
+ if (!allowed) {
+ error("Refused control connection");
+ close(client_fd);
+ buffer_free(&m);
+ return 0;
+ }
+
+ buffer_clear(&m);
+ if (ssh_msg_recv(client_fd, &m) == -1) {
+ error("%s: client msg_recv failed", __func__);
+ close(client_fd);
+ buffer_free(&m);
+ return 0;
+ }
+ if ((ver = buffer_get_char(&m)) != SSHMUX_VER) {
+ error("%s: wrong client version %d", __func__, ver);
+ buffer_free(&m);
+ close(client_fd);
+ return 0;
+ }
+
+ cctx = xcalloc(1, sizeof(*cctx));
+ cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0;
+ cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0;
+ cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0;
+ cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0;
+ cctx->term = buffer_get_string(&m, &len);
+ escape_char = buffer_get_int(&m);
+
+ cmd = buffer_get_string(&m, &len);
+ buffer_init(&cctx->cmd);
+ buffer_append(&cctx->cmd, cmd, strlen(cmd));
+
+ env_len = buffer_get_int(&m);
+ env_len = MIN(env_len, 4096);
+ debug3("%s: receiving %d env vars", __func__, env_len);
+ if (env_len != 0) {
+ cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env));
+ for (i = 0; i < env_len; i++)
+ cctx->env[i] = buffer_get_string(&m, &len);
+ cctx->env[i] = NULL;
+ }
+
+ debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__,
+ cctx->want_tty, cctx->want_subsys, cmd);
+ xfree(cmd);
+
+ /* Gather fds from client */
+ for(i = 0; i < 3; i++) {
+ if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) {
+ error("%s: failed to receive fd %d from slave",
+ __func__, i);
+ for (j = 0; j < i; j++)
+ close(new_fd[j]);
+ for (j = 0; j < env_len; j++)
+ xfree(cctx->env[j]);
+ if (env_len > 0)
+ xfree(cctx->env);
+ xfree(cctx->term);
+ buffer_free(&cctx->cmd);
+ close(client_fd);
+ xfree(cctx);
+ return 0;
+ }
+ }
+
+ debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__,
+ new_fd[0], new_fd[1], new_fd[2]);
+
+ /* Try to pick up ttymodes from client before it goes raw */
+ if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1)
+ error("%s: tcgetattr: %s", __func__, strerror(errno));
+
+ /* This roundtrip is just for synchronisation of ttymodes */
+ buffer_clear(&m);
+ if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) {
+ error("%s: client msg_send failed", __func__);
+ close(client_fd);
+ close(new_fd[0]);
+ close(new_fd[1]);
+ close(new_fd[2]);
+ buffer_free(&m);
+ xfree(cctx->term);
+ if (env_len != 0) {
+ for (i = 0; i < env_len; i++)
+ xfree(cctx->env[i]);
+ xfree(cctx->env);
+ }
+ return 0;
+ }
+ buffer_free(&m);
+
+ /* enable nonblocking unless tty */
+ if (!isatty(new_fd[0]))
+ set_nonblock(new_fd[0]);
+ if (!isatty(new_fd[1]))
+ set_nonblock(new_fd[1]);
+ if (!isatty(new_fd[2]))
+ set_nonblock(new_fd[2]);
+
+ set_nonblock(client_fd);
+
+ window = CHAN_SES_WINDOW_DEFAULT;
+ packetmax = CHAN_SES_PACKET_DEFAULT;
+ if (cctx->want_tty) {
+ window >>= 1;
+ packetmax >>= 1;
+ }
+
+ c = channel_new("session", SSH_CHANNEL_OPENING,
+ new_fd[0], new_fd[1], new_fd[2], window, packetmax,
+ CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
+
+ c->ctl_fd = client_fd;
+ if (cctx->want_tty && escape_char != 0xffffffff) {
+ channel_register_filter(c->self,
+ client_simple_escape_filter, NULL,
+ client_filter_cleanup,
+ client_new_escape_filter_ctx((int)escape_char));
+ }
+
+ debug3("%s: channel_new: %d", __func__, c->self);
+
+ channel_send_open(c->self);
+ channel_register_open_confirm(c->self, mux_session_confirm, cctx);
+ return 0;
+}
+
+/* ** Multiplexing client support */
+
+/* Exit signal handler */
+static void
+control_client_sighandler(int signo)
+{
+ muxclient_terminate = signo;
+}
+
+/*
+ * Relay signal handler - used to pass some signals from mux client to
+ * mux master.
+ */
+static void
+control_client_sigrelay(int signo)
+{
+ int save_errno = errno;
+
+ if (muxserver_pid > 1)
+ kill(muxserver_pid, signo);
+
+ errno = save_errno;
+}
+
+/* Check mux client environment variables before passing them to mux master. */
+static int
+env_permitted(char *env)
+{
+ int i, ret;
+ char name[1024], *cp;
+
+ if ((cp = strchr(env, '=')) == NULL || cp == env)
+ return (0);
+ ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env);
+ if (ret <= 0 || (size_t)ret >= sizeof(name))
+ fatal("env_permitted: name '%.100s...' too long", env);
+
+ for (i = 0; i < options.num_send_env; i++)
+ if (match_pattern(name, options.send_env[i]))
+ return (1);
+
+ return (0);
+}
+
+/* Multiplex client main loop. */
+void
+muxclient(const char *path)
+{
+ struct sockaddr_un addr;
+ int i, r, fd, sock, exitval[2], num_env, addr_len;
+ Buffer m;
+ char *term;
+ extern char **environ;
+ u_int allowed, flags;
+
+ if (muxclient_command == 0)
+ muxclient_command = SSHMUX_COMMAND_OPEN;
+
+ switch (options.control_master) {
+ case SSHCTL_MASTER_AUTO:
+ case SSHCTL_MASTER_AUTO_ASK:
+ debug("auto-mux: Trying existing master");
+ /* FALLTHROUGH */
+ case SSHCTL_MASTER_NO:
+ break;
+ default:
+ return;
+ }
+
+ memset(&addr, '\0', sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr_len = offsetof(struct sockaddr_un, sun_path) +
+ strlen(path) + 1;
+
+ if (strlcpy(addr.sun_path, path,
+ sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
+ fatal("ControlPath too long");
+
+ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
+ fatal("%s socket(): %s", __func__, strerror(errno));
+
+ if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) {
+ if (muxclient_command != SSHMUX_COMMAND_OPEN) {
+ fatal("Control socket connect(%.100s): %s", path,
+ strerror(errno));
+ }
+ if (errno == ENOENT)
+ debug("Control socket \"%.100s\" does not exist", path);
+ else {
+ error("Control socket connect(%.100s): %s", path,
+ strerror(errno));
+ }
+ close(sock);
+ return;
+ }
+
+ if (stdin_null_flag) {
+ if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)
+ fatal("open(/dev/null): %s", strerror(errno));
+ if (dup2(fd, STDIN_FILENO) == -1)
+ fatal("dup2: %s", strerror(errno));
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+
+ term = getenv("TERM");
+
+ flags = 0;
+ if (tty_flag)
+ flags |= SSHMUX_FLAG_TTY;
+ if (subsystem_flag)
+ flags |= SSHMUX_FLAG_SUBSYS;
+ if (options.forward_x11)
+ flags |= SSHMUX_FLAG_X11_FWD;
+ if (options.forward_agent)
+ flags |= SSHMUX_FLAG_AGENT_FWD;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ buffer_init(&m);
+
+ /* Send our command to server */
+ buffer_put_int(&m, muxclient_command);
+ buffer_put_int(&m, flags);
+ if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+ error("%s: msg_send", __func__);
+ muxerr:
+ close(sock);
+ buffer_free(&m);
+ if (muxclient_command != SSHMUX_COMMAND_OPEN)
+ cleanup_exit(255);
+ logit("Falling back to non-multiplexed connection");
+ xfree(options.control_path);
+ options.control_path = NULL;
+ options.control_master = SSHCTL_MASTER_NO;
+ return;
+ }
+ buffer_clear(&m);
+
+ /* Get authorisation status and PID of controlee */
+ if (ssh_msg_recv(sock, &m) == -1) {
+ error("%s: Did not receive reply from master", __func__);
+ goto muxerr;
+ }
+ if (buffer_get_char(&m) != SSHMUX_VER) {
+ error("%s: Master replied with wrong version", __func__);
+ goto muxerr;
+ }
+ if (buffer_get_int_ret(&allowed, &m) != 0) {
+ error("%s: bad server reply", __func__);
+ goto muxerr;
+ }
+ if (allowed != 1) {
+ error("Connection to master denied");
+ goto muxerr;
+ }
+ muxserver_pid = buffer_get_int(&m);
+
+ buffer_clear(&m);
+
+ switch (muxclient_command) {
+ case SSHMUX_COMMAND_ALIVE_CHECK:
+ fprintf(stderr, "Master running (pid=%d)\r\n",
+ muxserver_pid);
+ exit(0);
+ case SSHMUX_COMMAND_TERMINATE:
+ fprintf(stderr, "Exit request sent.\r\n");
+ exit(0);
+ case SSHMUX_COMMAND_OPEN:
+ buffer_put_cstring(&m, term ? term : "");
+ if (options.escape_char == SSH_ESCAPECHAR_NONE)
+ buffer_put_int(&m, 0xffffffff);
+ else
+ buffer_put_int(&m, options.escape_char);
+ buffer_append(&command, "\0", 1);
+ buffer_put_cstring(&m, buffer_ptr(&command));
+
+ if (options.num_send_env == 0 || environ == NULL) {
+ buffer_put_int(&m, 0);
+ } else {
+ /* Pass environment */
+ num_env = 0;
+ for (i = 0; environ[i] != NULL; i++) {
+ if (env_permitted(environ[i]))
+ num_env++; /* Count */
+ }
+ buffer_put_int(&m, num_env);
+ for (i = 0; environ[i] != NULL && num_env >= 0; i++) {
+ if (env_permitted(environ[i])) {
+ num_env--;
+ buffer_put_cstring(&m, environ[i]);
+ }
+ }
+ }
+ break;
+ default:
+ fatal("unrecognised muxclient_command %d", muxclient_command);
+ }
+
+ if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) {
+ error("%s: msg_send", __func__);
+ goto muxerr;
+ }
+
+ if (mm_send_fd(sock, STDIN_FILENO) == -1 ||
+ mm_send_fd(sock, STDOUT_FILENO) == -1 ||
+ mm_send_fd(sock, STDERR_FILENO) == -1) {
+ error("%s: send fds failed", __func__);
+ goto muxerr;
+ }
+
+ /*
+ * Mux errors are non-recoverable from this point as the master
+ * has ownership of the session now.
+ */
+
+ /* Wait for reply, so master has a chance to gather ttymodes */
+ buffer_clear(&m);
+ if (ssh_msg_recv(sock, &m) == -1)
+ fatal("%s: msg_recv", __func__);
+ if (buffer_get_char(&m) != SSHMUX_VER)
+ fatal("%s: wrong version", __func__);
+ buffer_free(&m);
+
+ signal(SIGHUP, control_client_sighandler);
+ signal(SIGINT, control_client_sighandler);
+ signal(SIGTERM, control_client_sighandler);
+ signal(SIGWINCH, control_client_sigrelay);
+
+ if (tty_flag)
+ enter_raw_mode();
+
+ /*
+ * Stick around until the controlee closes the client_fd.
+ * Before it does, it is expected to write this process' exit
+ * value (one int). This process must read the value and wait for
+ * the closure of the client_fd; if this one closes early, the
+ * multiplex master will terminate early too (possibly losing data).
+ */
+ exitval[0] = 0;
+ for (i = 0; !muxclient_terminate && i < (int)sizeof(exitval);) {
+ r = read(sock, (char *)exitval + i, sizeof(exitval) - i);
+ if (r == 0) {
+ debug2("Received EOF from master");
+ break;
+ }
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+ fatal("%s: read %s", __func__, strerror(errno));
+ }
+ i += r;
+ }
+
+ close(sock);
+ leave_raw_mode();
+ if (i > (int)sizeof(int))
+ fatal("%s: master returned too much data (%d > %lu)",
+ __func__, i, (u_long)sizeof(int));
+ if (muxclient_terminate) {
+ debug2("Exiting on signal %d", muxclient_terminate);
+ exitval[0] = 255;
+ } else if (i < (int)sizeof(int)) {
+ debug2("Control master terminated unexpectedly");
+ exitval[0] = 255;
+ } else
+ debug2("Received exit status from master %d", exitval[0]);
+
+ if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)
+ fprintf(stderr, "Shared connection to %s closed.\r\n", host);
+
+ exit(exitval[0]);
+}
diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h
new file mode 100644
index 0000000..7bca3bc
--- /dev/null
+++ b/crypto/openssh/myproposal.h
@@ -0,0 +1,69 @@
+/* $OpenBSD: myproposal.h,v 1.23 2009/01/23 07:58:11 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>
+
+/* Old OpenSSL doesn't support what we need for DHGEX-sha256 */
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+# define KEX_DEFAULT_KEX \
+ "diffie-hellman-group-exchange-sha1," \
+ "diffie-hellman-group14-sha1," \
+ "diffie-hellman-group1-sha1"
+#else
+# define KEX_DEFAULT_KEX \
+ "diffie-hellman-group-exchange-sha256," \
+ "diffie-hellman-group-exchange-sha1," \
+ "diffie-hellman-group14-sha1," \
+ "diffie-hellman-group1-sha1"
+#endif
+
+#define KEX_DEFAULT_PK_ALG "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/crypto/openssh/nchan.c b/crypto/openssh/nchan.c
new file mode 100644
index 0000000..160445e
--- /dev/null
+++ b/crypto/openssh/nchan.c
@@ -0,0 +1,522 @@
+/* $OpenBSD: nchan.c,v 1.62 2008/11/07 18:50:18 stevesk 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_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_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:
+ 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_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/crypto/openssh/openbsd-compat/base64.c b/crypto/openssh/openbsd-compat/base64.c
new file mode 100644
index 0000000..9e74667
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/base64.c
@@ -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/crypto/openssh/openbsd-compat/base64.h b/crypto/openssh/openbsd-compat/base64.h
new file mode 100644
index 0000000..732c6b3
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/base64.h
@@ -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/crypto/openssh/openbsd-compat/basename.c b/crypto/openssh/openbsd-compat/basename.c
new file mode 100644
index 0000000..ffa5c89
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/basename.c
@@ -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/crypto/openssh/openbsd-compat/bindresvport.c b/crypto/openssh/openbsd-compat/bindresvport.c
new file mode 100644
index 0000000..c0d5bdb
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bindresvport.c
@@ -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() % 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/crypto/openssh/openbsd-compat/bsd-arc4random.c b/crypto/openssh/openbsd-compat/bsd-arc4random.c
new file mode 100644
index 0000000..9d4c869
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-arc4random.c
@@ -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 ARC4RANDOM_BUF
+void
+arc4random_buf(void *_buf, size_t n)
+{
+ size_t i;
+ u_int32_t r = 0;
+ char *buf = (char *)_buf;
+
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ r = arc4random();
+ buf[i] = r & 0xff;
+ r >>= 8;
+ }
+ i = r = 0;
+}
+#endif /* !HAVE_ARC4RANDOM_BUF */
+
+#ifndef ARC4RANDOM_UNIFORM
+/*
+ * Calculate a uniformly distributed random number less than upper_bound
+ * avoiding "modulo bias".
+ *
+ * Uniformity is achieved by generating new random numbers until the one
+ * returned is outside the range [0, 2**32 % upper_bound). This
+ * guarantees the selected random number will be inside
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
+ * after reduction modulo upper_bound.
+ */
+u_int32_t
+arc4random_uniform(u_int32_t upper_bound)
+{
+ u_int32_t r, min;
+
+ if (upper_bound < 2)
+ return 0;
+
+#if (ULONG_MAX > 0xffffffffUL)
+ min = 0x100000000UL % upper_bound;
+#else
+ /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+ if (upper_bound > 0x80000000)
+ min = 1 + ~upper_bound; /* 2**32 - upper_bound */
+ else {
+ /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+ min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+ }
+#endif
+
+ /*
+ * This could theoretically loop forever but each retry has
+ * p > 0.5 (worst case, usually far better) of selecting a
+ * number inside the range we need, so it should rarely need
+ * to re-roll.
+ */
+ for (;;) {
+ r = arc4random();
+ if (r >= min)
+ break;
+ }
+
+ return r % upper_bound;
+}
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
diff --git a/crypto/openssh/openbsd-compat/bsd-asprintf.c b/crypto/openssh/openbsd-compat/bsd-asprintf.c
new file mode 100644
index 0000000..3368195
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-asprintf.c
@@ -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/crypto/openssh/openbsd-compat/bsd-closefrom.c b/crypto/openssh/openbsd-compat/bsd-closefrom.c
new file mode 100644
index 0000000..9380b33
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-closefrom.c
@@ -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/crypto/openssh/openbsd-compat/bsd-cray.c b/crypto/openssh/openbsd-compat/bsd-cray.c
new file mode 100644
index 0000000..f1bbd7d
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-cray.c
@@ -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/crypto/openssh/openbsd-compat/bsd-cray.h b/crypto/openssh/openbsd-compat/bsd-cray.h
new file mode 100644
index 0000000..774eceb
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-cray.h
@@ -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/crypto/openssh/openbsd-compat/bsd-cygwin_util.c b/crypto/openssh/openbsd-compat/bsd-cygwin_util.c
new file mode 100644
index 0000000..e90c159
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-cygwin_util.c
@@ -0,0 +1,131 @@
+/*
+ * 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("COMMONPROGRAMFILES=") },
+ { NL("COMPUTERNAME=") },
+ { NL("COMSPEC=") },
+ { NL("CYGWIN=") },
+ { NL("NUMBER_OF_PROCESSORS=") },
+ { NL("OS=") },
+ { NL("PATH=") },
+ { NL("PATHEXT=") },
+ { NL("PROCESSOR_ARCHITECTURE=") },
+ { NL("PROCESSOR_IDENTIFIER=") },
+ { NL("PROCESSOR_LEVEL=") },
+ { NL("PROCESSOR_REVISION=") },
+ { NL("PROGRAMFILES=") },
+ { NL("SYSTEMDRIVE=") },
+ { NL("SYSTEMROOT=") },
+ { NL("TMP=") },
+ { NL("TEMP=") },
+ { 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/crypto/openssh/openbsd-compat/bsd-cygwin_util.h b/crypto/openssh/openbsd-compat/bsd-cygwin_util.h
new file mode 100644
index 0000000..39b8eb7
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-cygwin_util.h
@@ -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/crypto/openssh/openbsd-compat/bsd-getpeereid.c b/crypto/openssh/openbsd-compat/bsd-getpeereid.c
new file mode 100644
index 0000000..5f7e677
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-getpeereid.c
@@ -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/crypto/openssh/openbsd-compat/bsd-misc.c b/crypto/openssh/openbsd-compat/bsd-misc.c
new file mode 100644
index 0000000..55f100a
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-misc.c
@@ -0,0 +1,242 @@
+
+/*
+ * 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
diff --git a/crypto/openssh/openbsd-compat/bsd-misc.h b/crypto/openssh/openbsd-compat/bsd-misc.h
new file mode 100644
index 0000000..b61ec42
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-misc.h
@@ -0,0 +1,98 @@
+/* $Id: bsd-misc.h,v 1.18 2005/02/25 23:07:38 dtucker 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)
+
+#endif /* _BSD_MISC_H */
diff --git a/crypto/openssh/openbsd-compat/bsd-nextstep.c b/crypto/openssh/openbsd-compat/bsd-nextstep.c
new file mode 100644
index 0000000..8195af8
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-nextstep.c
@@ -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/crypto/openssh/openbsd-compat/bsd-nextstep.h b/crypto/openssh/openbsd-compat/bsd-nextstep.h
new file mode 100644
index 0000000..ca5b4b5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-nextstep.h
@@ -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/crypto/openssh/openbsd-compat/bsd-openpty.c b/crypto/openssh/openbsd-compat/bsd-openpty.c
new file mode 100644
index 0000000..9777eb5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-openpty.c
@@ -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/crypto/openssh/openbsd-compat/bsd-poll.c b/crypto/openssh/openbsd-compat/bsd-poll.c
new file mode 100644
index 0000000..f899d7a
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-poll.c
@@ -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/crypto/openssh/openbsd-compat/bsd-poll.h b/crypto/openssh/openbsd-compat/bsd-poll.h
new file mode 100644
index 0000000..dcbb9ca
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-poll.h
@@ -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/crypto/openssh/openbsd-compat/bsd-snprintf.c b/crypto/openssh/openbsd-compat/bsd-snprintf.c
new file mode 100644
index 0000000..41d2be23
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-snprintf.c
@@ -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/crypto/openssh/openbsd-compat/bsd-statvfs.c b/crypto/openssh/openbsd-compat/bsd-statvfs.c
new file mode 100644
index 0000000..844d5b4
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-statvfs.c
@@ -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/crypto/openssh/openbsd-compat/bsd-statvfs.h b/crypto/openssh/openbsd-compat/bsd-statvfs.h
new file mode 100644
index 0000000..da215ff
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-statvfs.h
@@ -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/crypto/openssh/openbsd-compat/bsd-waitpid.c b/crypto/openssh/openbsd-compat/bsd-waitpid.c
new file mode 100644
index 0000000..40e6ffa
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-waitpid.c
@@ -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/crypto/openssh/openbsd-compat/bsd-waitpid.h b/crypto/openssh/openbsd-compat/bsd-waitpid.h
new file mode 100644
index 0000000..2d853db
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/bsd-waitpid.h
@@ -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/crypto/openssh/openbsd-compat/daemon.c b/crypto/openssh/openbsd-compat/daemon.c
new file mode 100644
index 0000000..3efe14c
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/daemon.c
@@ -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/crypto/openssh/openbsd-compat/dirname.c b/crypto/openssh/openbsd-compat/dirname.c
new file mode 100644
index 0000000..30fcb49
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/dirname.c
@@ -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/crypto/openssh/openbsd-compat/fake-rfc2553.c b/crypto/openssh/openbsd-compat/fake-rfc2553.c
new file mode 100644
index 0000000..096d9e0
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/fake-rfc2553.c
@@ -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/crypto/openssh/openbsd-compat/fake-rfc2553.h b/crypto/openssh/openbsd-compat/fake-rfc2553.h
new file mode 100644
index 0000000..3e9090f
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/fake-rfc2553.h
@@ -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/crypto/openssh/openbsd-compat/fmt_scaled.c b/crypto/openssh/openbsd-compat/fmt_scaled.c
new file mode 100644
index 0000000..edd682a
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/fmt_scaled.c
@@ -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/crypto/openssh/openbsd-compat/getcwd.c b/crypto/openssh/openbsd-compat/getcwd.c
new file mode 100644
index 0000000..711cb9c
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/getcwd.c
@@ -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/crypto/openssh/openbsd-compat/getgrouplist.c b/crypto/openssh/openbsd-compat/getgrouplist.c
new file mode 100644
index 0000000..a57d7d3
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/getgrouplist.c
@@ -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/crypto/openssh/openbsd-compat/getopt.c b/crypto/openssh/openbsd-compat/getopt.c
new file mode 100644
index 0000000..5450e43
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/getopt.c
@@ -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/crypto/openssh/openbsd-compat/getrrsetbyname.c b/crypto/openssh/openbsd-compat/getrrsetbyname.c
new file mode 100644
index 0000000..9887667
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/getrrsetbyname.c
@@ -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/crypto/openssh/openbsd-compat/getrrsetbyname.h b/crypto/openssh/openbsd-compat/getrrsetbyname.h
new file mode 100644
index 0000000..1283f55
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/getrrsetbyname.h
@@ -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/crypto/openssh/openbsd-compat/glob.c b/crypto/openssh/openbsd-compat/glob.c
new file mode 100644
index 0000000..74b5064
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/glob.c
@@ -0,0 +1,874 @@
+/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt 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 */
+
+#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(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
+ defined(BROKEN_GLOB)
+
+static long
+get_arg_max(void)
+{
+#ifdef ARG_MAX
+ return(ARG_MAX);
+#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
+ return(sysconf(_SC_ARG_MAX));
+#else
+ return(256); /* XXX: arbitrary */
+#endif
+}
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ * Escaping convention: \ inhibits any special meaning the following
+ * character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ * Same as GLOB_NOCHECK, but it will only append pattern if it did
+ * not contain any magic characters. [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ * Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ * expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ * expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ * Number of matches in the current invocation of glob.
+ */
+
+
+#define DOLLAR '$'
+#define DOT '.'
+#define EOS '\0'
+#define LBRACKET '['
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define RANGE '-'
+#define RBRACKET ']'
+#define SEP '/'
+#define STAR '*'
+#undef TILDE /* Some platforms may already define it */
+#define TILDE '~'
+#define UNDERSCORE '_'
+#define LBRACE '{'
+#define RBRACE '}'
+#define SLASH '/'
+#define COMMA ','
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000
+#define M_PROTECT 0x4000
+#define M_MASK 0xffff
+#define M_ASCII 0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_ASCII 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((Char)((c)&M_ASCII))
+#define META(c) ((Char)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_END META(']')
+#define M_NOT META('!')
+#define M_ONE META('?')
+#define M_RNG META('-')
+#define M_SET META('[')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int compare(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(Char *, int);
+static int g_stat(Char *, struct stat *, glob_t *);
+static int glob0(const Char *, glob_t *);
+static int glob1(Char *, Char *, glob_t *, size_t *);
+static int glob2(Char *, Char *, Char *, Char *, Char *, Char *,
+ glob_t *, size_t *);
+static int glob3(Char *, Char *, Char *, Char *, Char *,
+ Char *, Char *, glob_t *, size_t *);
+static int globextend(const Char *, glob_t *, size_t *);
+static const Char *
+ globtilde(const Char *, Char *, size_t, glob_t *);
+static int globexp1(const Char *, glob_t *);
+static int globexp2(const Char *, const Char *, glob_t *, int *);
+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];
+
+ patnext = (u_char *) pattern;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_offs = 0;
+ }
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN - 1;
+ if (flags & GLOB_NOESCAPE)
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ *bufnext++ = c;
+ else {
+ /* Protect the quoted characters. */
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ if (c == QUOTE) {
+ if ((c = *patnext++) == EOS) {
+ c = QUOTE;
+ --patnext;
+ }
+ *bufnext++ = c | M_PROTECT;
+ } else
+ *bufnext++ = c;
+ }
+ *bufnext = EOS;
+
+ if (flags & GLOB_BRACE)
+ return globexp1(patbuf, pglob);
+ else
+ return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int
+globexp1(const Char *pattern, glob_t *pglob)
+{
+ const Char* ptr = pattern;
+ int rv;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+ return glob0(pattern, pglob);
+
+ while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+ if (!globexp2(ptr, pattern, pglob, &rv))
+ return rv;
+
+ return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv)
+{
+ int i;
+ Char *lm, *ls;
+ const Char *pe, *pm, *pl;
+ Char patbuf[MAXPATHLEN];
+
+ /* copy part up to the brace */
+ for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+ ;
+ *lm = EOS;
+ ls = lm;
+
+ /* Find the balanced brace */
+ for (i = 0, pe = ++ptr; *pe; pe++)
+ if (*pe == LBRACKET) {
+ /* Ignore everything between [] */
+ for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+ ;
+ if (*pe == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pe = pm;
+ }
+ } else if (*pe == LBRACE)
+ i++;
+ else if (*pe == RBRACE) {
+ if (i == 0)
+ break;
+ i--;
+ }
+
+ /* Non matching braces; just glob the pattern */
+ if (i != 0 || *pe == EOS) {
+ *rv = glob0(patbuf, pglob);
+ return 0;
+ }
+
+ for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
+ switch (*pm) {
+ case LBRACKET:
+ /* Ignore everything between [] */
+ for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+ ;
+ if (*pm == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pm = pl;
+ }
+ break;
+
+ case LBRACE:
+ i++;
+ break;
+
+ case RBRACE:
+ if (i) {
+ i--;
+ break;
+ }
+ /* FALLTHROUGH */
+ case COMMA:
+ if (i && *pm == COMMA)
+ break;
+ else {
+ /* Append the current string */
+ for (lm = ls; (pl < pm); *lm++ = *pl++)
+ ;
+
+ /*
+ * Append the rest of the pattern after the
+ * closing brace
+ */
+ for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
+ ;
+
+ /* Expand the current pattern */
+#ifdef DEBUG
+ qprintf("globexp2:", patbuf);
+#endif
+ *rv = globexp1(patbuf, pglob);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ *rv = 0;
+ return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
+{
+ struct passwd *pwd;
+ char *h;
+ const Char *p;
+ Char *b, *eb;
+
+ if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+ return pattern;
+
+ /* Copy up to the end of the string or / */
+ eb = &patbuf[patbuf_len - 1];
+ for (p = pattern + 1, h = (char *) patbuf;
+ h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
+ ;
+
+ *h = EOS;
+
+#if 0
+ if (h == (char *)eb)
+ return what;
+#endif
+
+ if (((char *) patbuf)[0] == EOS) {
+ /*
+ * handle a plain ~ or ~/ by expanding $HOME
+ * first and then trying the password file
+ */
+#if 0
+ if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
+#endif
+ if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
+ if ((pwd = getpwuid(getuid())) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+ } else {
+ /*
+ * Expand a ~user
+ */
+ if ((pwd = getpwnam((char*) patbuf)) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+
+ /* Copy the home directory */
+ for (b = patbuf; b < eb && *h; *b++ = *h++)
+ ;
+
+ /* Append the rest of the pattern */
+ while (b < eb && (*b++ = *p++) != EOS)
+ ;
+ *b = EOS;
+
+ return patbuf;
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred. It is not an error
+ * to find no matches.
+ */
+static int
+glob0(const Char *pattern, glob_t *pglob)
+{
+ const Char *qpatnext;
+ int c, err, oldpathc;
+ Char *bufnext, patbuf[MAXPATHLEN];
+ size_t limit = 0;
+
+ qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case LBRACKET:
+ c = *qpatnext;
+ if (c == NOT)
+ ++qpatnext;
+ if (*qpatnext == EOS ||
+ g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+ *bufnext++ = LBRACKET;
+ if (c == NOT)
+ --qpatnext;
+ break;
+ }
+ *bufnext++ = M_SET;
+ if (c == NOT)
+ *bufnext++ = M_NOT;
+ c = *qpatnext++;
+ do {
+ *bufnext++ = CHAR(c);
+ if (*qpatnext == RANGE &&
+ (c = qpatnext[1]) != RBRACKET) {
+ *bufnext++ = M_RNG;
+ *bufnext++ = CHAR(c);
+ qpatnext += 2;
+ }
+ } while ((c = *qpatnext++) != RBRACKET);
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_END;
+ break;
+ case QUESTION:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
+ return(err);
+
+ /*
+ * If there was no match we are going to append the pattern
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the pattern did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if (pglob->gl_pathc == oldpathc) {
+ if ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR)))
+ return(globextend(pattern, pglob, &limit));
+ else
+ return(GLOB_NOMATCH);
+ }
+ if (!(pglob->gl_flags & GLOB_NOSORT))
+ qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+ pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+ return(0);
+}
+
+static int
+compare(const void *p, const void *q)
+{
+ return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
+{
+ Char pathbuf[MAXPATHLEN];
+
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return(0);
+ return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
+ pathbuf, pathbuf+MAXPATHLEN-1,
+ pattern, pattern_last, pglob, limitp));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last,
+ Char *pattern, Char *pattern_last, glob_t *pglob, size_t *limitp)
+{
+ struct stat sb;
+ Char *p, *q;
+ int anymeta;
+
+ /*
+ * Loop over pattern segments until end of pattern or until
+ * segment with meta character found.
+ */
+ for (anymeta = 0;;) {
+ if (*pattern == EOS) { /* End of pattern? */
+ *pathend = EOS;
+ if (g_lstat(pathbuf, &sb, pglob))
+ return(0);
+
+ if (((pglob->gl_flags & GLOB_MARK) &&
+ pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
+ (S_ISLNK(sb.st_mode) &&
+ (g_stat(pathbuf, &sb, pglob) == 0) &&
+ S_ISDIR(sb.st_mode)))) {
+ if (pathend+1 > pathend_last)
+ return (1);
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return(globextend(pathbuf, pglob, limitp));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && *p != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ if (q+1 > pathend_last)
+ return (1);
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (*pattern == SEP) {
+ if (pathend+1 > pathend_last)
+ return (1);
+ *pathend++ = *pattern++;
+ }
+ } else
+ /* Need expansion, recurse. */
+ return(glob3(pathbuf, pathbuf_last, pathend,
+ pathend_last, pattern, 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,
+ size_t *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;
+
+ /* 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, size_t *limitp)
+{
+ char **pathv;
+ int i;
+ u_int newsize, len;
+ char *copy;
+ const Char *p;
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
+ malloc(newsize);
+ if (pathv == NULL) {
+ if (pglob->gl_pathv) {
+ free(pglob->gl_pathv);
+ pglob->gl_pathv = NULL;
+ }
+ return(GLOB_NOSPACE);
+ }
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ ;
+ len = (size_t)(p - path);
+ *limitp += len;
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ return(GLOB_NOSPACE);
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ newsize + *limitp >= (u_int) get_arg_max()) {
+ errno = 0;
+ return(GLOB_NOSPACE);
+ }
+
+ return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(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 ((*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;
+ }
+}
+
+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(Char *str, int ch)
+{
+ do {
+ if (*str == ch)
+ return (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) */
+
diff --git a/crypto/openssh/openbsd-compat/glob.h b/crypto/openssh/openbsd-compat/glob.h
new file mode 100644
index 0000000..a2b36f9
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/glob.h
@@ -0,0 +1,100 @@
+/* $OpenBSD: glob.h,v 1.10 2005/12/13 00:35:22 millert 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(HAVE_DECL_GLOB_NOMATCH) || HAVE_DECL_GLOB_NOMATCH == 0 || \
+ defined(BROKEN_GLOB)
+
+#ifndef _GLOB_H_
+#define _GLOB_H_
+
+struct stat;
+typedef struct {
+ int gl_pathc; /* Count of total paths so far. */
+ int gl_matchc; /* Count of paths matching pattern. */
+ int gl_offs; /* Reserved at beginning of gl_pathv. */
+ int gl_flags; /* Copy of flags parameter to glob. */
+ char **gl_pathv; /* List of paths matching pattern. */
+ /* Copy of errfunc parameter to glob. */
+ int (*gl_errfunc)(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. */
+
+/* Error values returned by glob(3) */
+#define GLOB_NOSPACE (-1) /* Malloc call failed. */
+#define GLOB_ABORTED (-2) /* Unignored error. */
+#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */
+#define GLOB_NOSYS (-4) /* Function not supported. */
+#define GLOB_ABEND GLOB_ABORTED
+
+#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 */
+
+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 */
+
diff --git a/crypto/openssh/openbsd-compat/inet_aton.c b/crypto/openssh/openbsd-compat/inet_aton.c
new file mode 100644
index 0000000..130597e
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/inet_aton.c
@@ -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/crypto/openssh/openbsd-compat/inet_ntoa.c b/crypto/openssh/openbsd-compat/inet_ntoa.c
new file mode 100644
index 0000000..0eb7b3b
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/inet_ntoa.c
@@ -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/crypto/openssh/openbsd-compat/inet_ntop.c b/crypto/openssh/openbsd-compat/inet_ntop.c
new file mode 100644
index 0000000..e7ca4b7
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/inet_ntop.c
@@ -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/crypto/openssh/openbsd-compat/mktemp.c b/crypto/openssh/openbsd-compat/mktemp.c
new file mode 100644
index 0000000..2285c84
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/mktemp.c
@@ -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/crypto/openssh/openbsd-compat/openbsd-compat.h b/crypto/openssh/openbsd-compat/openbsd-compat.h
new file mode 100644
index 0000000..50c6d99
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/openbsd-compat.h
@@ -0,0 +1,221 @@
+/* $Id: openbsd-compat.h,v 1.46 2008/06/08 17:32:29 dtucker 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
+
+#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
+
+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/crypto/openssh/openbsd-compat/openssl-compat.c b/crypto/openssh/openbsd-compat/openssl-compat.c
new file mode 100644
index 0000000..dd326c0
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/openssl-compat.c
@@ -0,0 +1,71 @@
+/* $Id: openssl-compat.c,v 1.8 2009/03/07 11:22:35 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"
+
+#ifdef USE_OPENSSL_ENGINE
+# include <openssl/engine.h>
+#endif
+
+#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
+
+#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();
+}
+#endif
diff --git a/crypto/openssh/openbsd-compat/openssl-compat.h b/crypto/openssh/openbsd-compat/openssl-compat.h
new file mode 100644
index 0000000..fcc7628
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/openssl-compat.h
@@ -0,0 +1,99 @@
+/* $Id: openssl-compat.h,v 1.14 2009/03/07 11:22:35 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/evp.h>
+
+/* 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 < 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
+
+/*
+ * 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
+
+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/crypto/openssh/openbsd-compat/port-aix.c b/crypto/openssh/openbsd-compat/port-aix.c
new file mode 100644
index 0000000..d9c0876
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-aix.c
@@ -0,0 +1,449 @@
+/*
+ *
+ * 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 */
+
+# 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/crypto/openssh/openbsd-compat/port-aix.h b/crypto/openssh/openbsd-compat/port-aix.h
new file mode 100644
index 0000000..3ac76ae
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-aix.h
@@ -0,0 +1,123 @@
+/* $Id: port-aix.h,v 1.31 2009/08/20 06:20:50 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
+#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/crypto/openssh/openbsd-compat/port-irix.c b/crypto/openssh/openbsd-compat/port-irix.c
new file mode 100644
index 0000000..ba751a5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-irix.c
@@ -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/crypto/openssh/openbsd-compat/port-irix.h b/crypto/openssh/openbsd-compat/port-irix.h
new file mode 100644
index 0000000..67c4863
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-irix.h
@@ -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/crypto/openssh/openbsd-compat/port-linux.c b/crypto/openssh/openbsd-compat/port-linux.c
new file mode 100644
index 0000000..ad26275
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-linux.c
@@ -0,0 +1,171 @@
+/* $Id: port-linux.c,v 1.5 2008/03/26 20:27:21 dtucker 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"
+
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef WITH_SELINUX
+#include "log.h"
+#include "port-linux.h"
+
+#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();
+ 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__);
+}
+#endif /* WITH_SELINUX */
diff --git a/crypto/openssh/openbsd-compat/port-linux.h b/crypto/openssh/openbsd-compat/port-linux.h
new file mode 100644
index 0000000..5cd39bf
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-linux.h
@@ -0,0 +1,28 @@
+/* $Id: port-linux.h,v 1.2 2008/03/26 20:27:21 dtucker 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 *);
+#endif
+
+#endif /* ! _PORT_LINUX_H */
diff --git a/crypto/openssh/openbsd-compat/port-solaris.c b/crypto/openssh/openbsd-compat/port-solaris.c
new file mode 100644
index 0000000..2ab64d4
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-solaris.c
@@ -0,0 +1,199 @@
+/* $Id: port-solaris.c,v 1.3 2006/10/31 23:28:49 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
diff --git a/crypto/openssh/openbsd-compat/port-solaris.h b/crypto/openssh/openbsd-compat/port-solaris.h
new file mode 100644
index 0000000..4c32487
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-solaris.h
@@ -0,0 +1,27 @@
+/* $Id: port-solaris.h,v 1.1 2006/08/30 17:24:42 djm 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>
+
+void solaris_contract_pre_fork(void);
+void solaris_contract_post_fork_child(void);
+void solaris_contract_post_fork_parent(pid_t pid);
+
+#endif
diff --git a/crypto/openssh/openbsd-compat/port-tun.c b/crypto/openssh/openbsd-compat/port-tun.c
new file mode 100644
index 0000000..ddc92d0
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-tun.c
@@ -0,0 +1,271 @@
+/*
+ * 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;
+ 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/crypto/openssh/openbsd-compat/port-tun.h b/crypto/openssh/openbsd-compat/port-tun.h
new file mode 100644
index 0000000..c53df01
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-tun.h
@@ -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/crypto/openssh/openbsd-compat/port-uw.c b/crypto/openssh/openbsd-compat/port-uw.c
new file mode 100644
index 0000000..be9905a
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-uw.c
@@ -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 "auth-options.h"
+#include "log.h"
+#include "servconf.h"
+#include "key.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/crypto/openssh/openbsd-compat/port-uw.h b/crypto/openssh/openbsd-compat/port-uw.h
new file mode 100644
index 0000000..263d8b5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/port-uw.h
@@ -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/crypto/openssh/openbsd-compat/readpassphrase.c b/crypto/openssh/openbsd-compat/readpassphrase.c
new file mode 100644
index 0000000..11bd8f6
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/readpassphrase.c
@@ -0,0 +1,191 @@
+/* $OpenBSD: readpassphrase.c,v 1.18 2005/08/08 08:05:34 espie 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: 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;
+
+static void handler(int);
+
+char *
+readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
+{
+ ssize_t nr;
+ int input, output, save_errno;
+ 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:
+ signo = 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;
+ }
+
+ if (!(flags & RPP_STDIN))
+ (void)write(output, prompt, strlen(prompt));
+ end = buf + bufsiz - 1;
+ for (p = buf; (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 = tolower(ch);
+ if ((flags & RPP_FORCEUPPER))
+ ch = 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);
+ 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.
+ */
+ if (signo) {
+ kill(getpid(), signo);
+ switch (signo) {
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ goto restart;
+ }
+ }
+
+ 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;
+}
+#endif /* HAVE_READPASSPHRASE */
diff --git a/crypto/openssh/openbsd-compat/readpassphrase.h b/crypto/openssh/openbsd-compat/readpassphrase.h
new file mode 100644
index 0000000..5fd7c5d
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/readpassphrase.h
@@ -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/crypto/openssh/openbsd-compat/realpath.c b/crypto/openssh/openbsd-compat/realpath.c
new file mode 100644
index 0000000..b6120d0
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/realpath.c
@@ -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/crypto/openssh/openbsd-compat/rresvport.c b/crypto/openssh/openbsd-compat/rresvport.c
new file mode 100644
index 0000000..1cd61e5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/rresvport.c
@@ -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/crypto/openssh/openbsd-compat/setenv.c b/crypto/openssh/openbsd-compat/setenv.c
new file mode 100644
index 0000000..e2a8b6d
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/setenv.c
@@ -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/crypto/openssh/openbsd-compat/setproctitle.c b/crypto/openssh/openbsd-compat/setproctitle.c
new file mode 100644
index 0000000..2965f68
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/setproctitle.c
@@ -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/crypto/openssh/openbsd-compat/sha2.c b/crypto/openssh/openbsd-compat/sha2.c
new file mode 100755
index 0000000..cf8e0ad6
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sha2.c
@@ -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/crypto/openssh/openbsd-compat/sha2.h b/crypto/openssh/openbsd-compat/sha2.h
new file mode 100755
index 0000000..821f2dd
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sha2.h
@@ -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/crypto/openssh/openbsd-compat/sigact.c b/crypto/openssh/openbsd-compat/sigact.c
new file mode 100644
index 0000000..d67845c
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sigact.c
@@ -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/crypto/openssh/openbsd-compat/sigact.h b/crypto/openssh/openbsd-compat/sigact.h
new file mode 100644
index 0000000..db96d0a
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sigact.h
@@ -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/crypto/openssh/openbsd-compat/strlcat.c b/crypto/openssh/openbsd-compat/strlcat.c
new file mode 100644
index 0000000..bcc1b61
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strlcat.c
@@ -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/crypto/openssh/openbsd-compat/strlcpy.c b/crypto/openssh/openbsd-compat/strlcpy.c
new file mode 100644
index 0000000..679a5b2
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strlcpy.c
@@ -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/crypto/openssh/openbsd-compat/strmode.c b/crypto/openssh/openbsd-compat/strmode.c
new file mode 100644
index 0000000..4a81614
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strmode.c
@@ -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/crypto/openssh/openbsd-compat/strsep.c b/crypto/openssh/openbsd-compat/strsep.c
new file mode 100644
index 0000000..b36eb8f
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strsep.c
@@ -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/crypto/openssh/openbsd-compat/strtoll.c b/crypto/openssh/openbsd-compat/strtoll.c
new file mode 100644
index 0000000..f629303
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strtoll.c
@@ -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/crypto/openssh/openbsd-compat/strtonum.c b/crypto/openssh/openbsd-compat/strtonum.c
new file mode 100644
index 0000000..87f2f24
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strtonum.c
@@ -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/crypto/openssh/openbsd-compat/strtoul.c b/crypto/openssh/openbsd-compat/strtoul.c
new file mode 100644
index 0000000..8219c83
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/strtoul.c
@@ -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/crypto/openssh/openbsd-compat/sys-queue.h b/crypto/openssh/openbsd-compat/sys-queue.h
new file mode 100644
index 0000000..5cf0587
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sys-queue.h
@@ -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/crypto/openssh/openbsd-compat/sys-tree.h b/crypto/openssh/openbsd-compat/sys-tree.h
new file mode 100644
index 0000000..d4949b5
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/sys-tree.h
@@ -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/crypto/openssh/openbsd-compat/vis.c b/crypto/openssh/openbsd-compat/vis.c
new file mode 100644
index 0000000..3a087b3
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/vis.c
@@ -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/crypto/openssh/openbsd-compat/vis.h b/crypto/openssh/openbsd-compat/vis.h
new file mode 100644
index 0000000..3898a9e
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/vis.h
@@ -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/crypto/openssh/openbsd-compat/xcrypt.c b/crypto/openssh/openbsd-compat/xcrypt.c
new file mode 100644
index 0000000..6291e28
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/xcrypt.c
@@ -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/crypto/openssh/openbsd-compat/xmmap.c b/crypto/openssh/openbsd-compat/xmmap.c
new file mode 100644
index 0000000..04c6bab
--- /dev/null
+++ b/crypto/openssh/openbsd-compat/xmmap.c
@@ -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/crypto/openssh/packet.c b/crypto/openssh/packet.c
new file mode 100644
index 0000000..994e35b
--- /dev/null
+++ b/crypto/openssh/packet.c
@@ -0,0 +1,1939 @@
+/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas 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);
+}
+
+/*
+ * 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 (memcmp(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);
+}
+
+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);
+}
+
+/*
+ * 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 interactive)
+{
+#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN)
+ int tos = interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT;
+
+ if (!packet_connection_is_on_socket() ||
+ !packet_connection_is_ipv4())
+ return;
+ 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)
+{
+ 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);
+}
+
+/* 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/crypto/openssh/packet.h b/crypto/openssh/packet.h
new file mode 100644
index 0000000..33523d7
--- /dev/null
+++ b/crypto/openssh/packet.h
@@ -0,0 +1,118 @@
+/* $OpenBSD: packet.h,v 1.52 2009/06/27 09:29:06 andreas 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>
+
+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 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);
+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);
+void *packet_get_raw(u_int *length_ptr);
+void *packet_get_string(u_int *length_ptr);
+void *packet_get_string_ptr(u_int *length_ptr);
+void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
+
+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/crypto/openssh/pathnames.h b/crypto/openssh/pathnames.h
new file mode 100644
index 0000000..bc4f66a
--- /dev/null
+++ b/crypto/openssh/pathnames.h
@@ -0,0 +1,174 @@
+/* $OpenBSD: pathnames.h,v 1.17 2008/12/29 02:23:26 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".
+ */
+
+#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_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_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/local/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
+
+/* xauth for X11 forwarding */
+#ifndef _PATH_XAUTH
+#define _PATH_XAUTH "/usr/local/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/crypto/openssh/platform.c b/crypto/openssh/platform.c
new file mode 100644
index 0000000..aee4b01
--- /dev/null
+++ b/crypto/openssh/platform.c
@@ -0,0 +1,46 @@
+/* $Id: platform.c,v 1.1 2006/08/30 17:24:41 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 "config.h"
+#include "platform.h"
+
+#include "openbsd-compat/openbsd-compat.h"
+
+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
+}
diff --git a/crypto/openssh/platform.h b/crypto/openssh/platform.h
new file mode 100644
index 0000000..cf93bc5
--- /dev/null
+++ b/crypto/openssh/platform.h
@@ -0,0 +1,23 @@
+/* $Id: platform.h,v 1.1 2006/08/30 17:24:41 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 <sys/types.h>
+
+void platform_pre_fork(void);
+void platform_post_fork_parent(pid_t child_pid);
+void platform_post_fork_child(void);
diff --git a/crypto/openssh/progressmeter.c b/crypto/openssh/progressmeter.c
new file mode 100644
index 0000000..0f95222
--- /dev/null
+++ b/crypto/openssh/progressmeter.c
@@ -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/crypto/openssh/progressmeter.h b/crypto/openssh/progressmeter.h
new file mode 100644
index 0000000..10bab99
--- /dev/null
+++ b/crypto/openssh/progressmeter.h
@@ -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/crypto/openssh/readconf.c b/crypto/openssh/readconf.c
new file mode 100644
index 0000000..8d3fc40
--- /dev/null
+++ b/crypto/openssh/readconf.c
@@ -0,0 +1,1342 @@
+/* $OpenBSD: readconf.c,v 1.177 2009/06/27 09:35:06 andreas 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"
+__RCSID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.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"
+#include "version.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, 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, oSmartcardDevice,
+ oClearAllForwardings, oNoHostAuthenticationForLocalhost,
+ oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
+ oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+ oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
+ oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
+ oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
+ oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
+ oVersionAddendum,
+ oDeprecated, oUnsupported
+} OpCodes;
+
+/* Textual representations of the tokens. */
+
+static struct {
+ const char *name;
+ OpCodes opcode;
+} keywords[] = {
+ { "forwardagent", oForwardAgent },
+ { "forwardx11", oForwardX11 },
+ { "forwardx11trusted", oForwardX11Trusted },
+ { "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 SMARTCARD
+ { "smartcarddevice", oSmartcardDevice },
+#else
+ { "smartcarddevice", 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 },
+ { "hashknownhosts", oHashKnownHosts },
+ { "tunnel", oTunnel },
+ { "tunneldevice", oTunnelDevice },
+ { "localcommand", oLocalCommand },
+ { "permitlocalcommand", oPermitLocalCommand },
+ { "visualhostkey", oVisualHostKey },
+ { "useroaming", oUseRoaming },
+#ifdef JPAKE
+ { "zeroknowledgepasswordauthentication",
+ oZeroKnowledgePasswordAuthentication },
+#else
+ { "zeroknowledgepasswordauthentication", oUnsupported },
+#endif
+
+ { "versionaddendum", oVersionAddendum },
+ { 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;
+ int ipport_reserved;
+#ifdef __FreeBSD__
+ size_t len_ipport_reserved = sizeof(ipport_reserved);
+
+ if (sysctlbyname("net.inet.ip.portrange.reservedhigh",
+ &ipport_reserved, &len_ipport_reserved, NULL, 0) != 0)
+ ipport_reserved = IPPORT_RESERVED;
+ else
+ ipport_reserved++;
+#else
+ ipport_reserved = IPPORT_RESERVED;
+#endif
+ if (newfwd->listen_port < ipport_reserved && original_real_uid != 0)
+ fatal("Privileged ports can only be forwarded by root.");
+#endif
+ if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
+ fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION);
+ fwd = &options->local_forwards[options->num_local_forwards++];
+
+ fwd->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;
+ if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION)
+ fatal("Too many remote forwards (max %d).",
+ SSH_MAX_FORWARDS_PER_DIRECTION);
+ fwd = &options->remote_forwards[options->num_remote_forwards++];
+
+ fwd->listen_host = newfwd->listen_host;
+ fwd->listen_port = newfwd->listen_port;
+ fwd->connect_host = newfwd->connect_host;
+ fwd->connect_port = newfwd->connect_port;
+}
+
+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);
+ }
+ 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);
+ }
+ 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 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 oSmartcardDevice:
+ charptr = &options->smartcard_device;
+ 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 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 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 oUseRoaming:
+ intptr = &options->use_roaming;
+ goto parse_flag;
+
+ case oVersionAddendum:
+ ssh_version_set_addendum(strtok(s, "\n"));
+ do {
+ arg = strdelim(&s);
+ } while (arg != NULL && *arg != '\0');
+ break;
+
+ 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->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->hostkeyalgorithms = NULL;
+ options->protocol = SSH_PROTO_UNKNOWN;
+ options->num_identity_files = 0;
+ options->hostname = NULL;
+ options->host_key_alias = NULL;
+ options->proxy_command = NULL;
+ options->user = NULL;
+ options->escape_char = -1;
+ options->system_hostfile = NULL;
+ options->user_hostfile = NULL;
+ options->system_hostfile2 = NULL;
+ options->user_hostfile2 = NULL;
+ options->num_local_forwards = 0;
+ options->num_remote_forwards = 0;
+ options->clear_forwardings = -1;
+ options->log_level = SYSLOG_LEVEL_NOT_SET;
+ options->preferred_authentications = NULL;
+ options->bind_address = NULL;
+ options->smartcard_device = 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->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;
+}
+
+/*
+ * 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->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 = 0;
+ 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->hostkeyalgorithms, default set in myproposals.h */
+ if (options->protocol == SSH_PROTO_UNKNOWN)
+ options->protocol = SSH_PROTO_1|SSH_PROTO_2;
+ if (options->num_identity_files == 0) {
+ if (options->protocol & SSH_PROTO_1) {
+ len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
+ options->identity_files[options->num_identity_files] =
+ xmalloc(len);
+ snprintf(options->identity_files[options->num_identity_files++],
+ len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY);
+ }
+ if (options->protocol & SSH_PROTO_2) {
+ len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1;
+ options->identity_files[options->num_identity_files] =
+ xmalloc(len);
+ snprintf(options->identity_files[options->num_identity_files++],
+ len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA);
+
+ len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1;
+ options->identity_files[options->num_identity_files] =
+ xmalloc(len);
+ snprintf(options->identity_files[options->num_identity_files++],
+ len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA);
+ }
+ }
+ if (options->escape_char == -1)
+ options->escape_char = '~';
+ if (options->system_hostfile == NULL)
+ options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE;
+ if (options->user_hostfile == NULL)
+ options->user_hostfile = _PATH_SSH_USER_HOSTFILE;
+ if (options->system_hostfile2 == NULL)
+ options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2;
+ if (options->user_hostfile2 == NULL)
+ options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2;
+ if (options->log_level == 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->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;
+ /* 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/crypto/openssh/readconf.h b/crypto/openssh/readconf.h
new file mode 100644
index 0000000..2ebfebe
--- /dev/null
+++ b/crypto/openssh/readconf.h
@@ -0,0 +1,147 @@
+/* $OpenBSD: readconf.h,v 1.79 2009/06/27 09:35:06 andreas 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. */
+} 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_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. */
+ 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. */
+ 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 *smartcard_device; /* Smartcard reader device */
+ 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[SSH_MAX_FORWARDS_PER_DIRECTION];
+
+ /* Remote TCP/IP forward requests. */
+ int num_remote_forwards;
+ Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION];
+ int clear_forwardings;
+
+ int 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 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/crypto/openssh/readpass.c b/crypto/openssh/readpass.c
new file mode 100644
index 0000000..bd144c2
--- /dev/null
+++ b/crypto/openssh/readpass.c
@@ -0,0 +1,188 @@
+/* $OpenBSD: readpass.c,v 1.47 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 <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_PATHS_H
+# include <paths.h>
+#endif
+#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;
+ size_t len;
+ char *pass;
+ int p[2], status, ret;
+ char buf[1024];
+
+ if (fflush(stdout) != 0)
+ error("ssh_askpass: fflush: %s", strerror(errno));
+ if (askpass == NULL)
+ fatal("internal error: askpass undefined");
+ if (pipe(p) < 0) {
+ error("ssh_askpass: pipe: %s", strerror(errno));
+ return NULL;
+ }
+ if ((pid = fork()) < 0) {
+ error("ssh_askpass: fork: %s", strerror(errno));
+ 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 = ret = 0;
+ do {
+ ret = read(p[0], buf + len, sizeof(buf) - 1 - len);
+ if (ret == -1 && errno == EINTR)
+ continue;
+ if (ret <= 0)
+ break;
+ len += ret;
+ } while (sizeof(buf) - 1 - len > 0);
+ buf[len] = '\0';
+
+ close(p[0]);
+ while (waitpid(pid, &status, 0) < 0)
+ if (errno != EINTR)
+ break;
+
+ if (!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/crypto/openssh/rijndael.c b/crypto/openssh/rijndael.c
new file mode 100644
index 0000000..7432ea2
--- /dev/null
+++ b/crypto/openssh/rijndael.c
@@ -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/crypto/openssh/rijndael.h b/crypto/openssh/rijndael.h
new file mode 100644
index 0000000..c614bb1
--- /dev/null
+++ b/crypto/openssh/rijndael.h
@@ -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/crypto/openssh/roaming.h b/crypto/openssh/roaming.h
new file mode 100644
index 0000000..e517161
--- /dev/null
+++ b/crypto/openssh/roaming.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: roaming.h,v 1.4 2009/06/27 09:32:43 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
+
+extern int resume_in_progress;
+
+int get_snd_buf_size(void);
+int get_recv_buf_size(void);
+void add_recv_bytes(u_int64_t);
+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 *);
+int resume_kex(void);
+
+#endif /* ROAMING */
diff --git a/crypto/openssh/roaming_common.c b/crypto/openssh/roaming_common.c
new file mode 100644
index 0000000..73db09d
--- /dev/null
+++ b/crypto/openssh/roaming_common.c
@@ -0,0 +1,201 @@
+/* $OpenBSD: roaming_common.c,v 1.5 2009/06/27 09:32:43 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 <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, optvallen;
+
+ 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, optvallen;
+
+ 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);
+ }
+ debug3("Wrote %ld bytes for a total of %llu", (long)ret,
+ (unsigned long long)write_bytes);
+ 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;
+ }
+ }
+ 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);
+ }
+}
diff --git a/crypto/openssh/roaming_dummy.c b/crypto/openssh/roaming_dummy.c
new file mode 100644
index 0000000..45c4008
--- /dev/null
+++ b/crypto/openssh/roaming_dummy.c
@@ -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/crypto/openssh/rsa.c b/crypto/openssh/rsa.c
new file mode 100644
index 0000000..bec1d19
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/rsa.h b/crypto/openssh/rsa.h
new file mode 100644
index 0000000..b841ea4
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/scard-opensc.c b/crypto/openssh/scard-opensc.c
new file mode 100644
index 0000000..36dae05
--- /dev/null
+++ b/crypto/openssh/scard-opensc.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2002 Juha Yrjölä. All rights reserved.
+ * Copyright (c) 2001 Markus Friedl.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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(SMARTCARD) && defined(USE_OPENSC)
+
+#include <sys/types.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <opensc/opensc.h>
+#include <opensc/pkcs15.h>
+
+#include "key.h"
+#include "log.h"
+#include "xmalloc.h"
+#include "misc.h"
+#include "scard.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
+#define USE_ENGINE
+#define RSA_get_default_method RSA_get_default_openssl_method
+#else
+#endif
+
+#ifdef USE_ENGINE
+#include <openssl/engine.h>
+#define sc_get_rsa sc_get_engine
+#else
+#define sc_get_rsa sc_get_rsa_method
+#endif
+
+static int sc_reader_id;
+static sc_context_t *ctx = NULL;
+static sc_card_t *card = NULL;
+static sc_pkcs15_card_t *p15card = NULL;
+
+static char *sc_pin = NULL;
+
+struct sc_priv_data
+{
+ struct sc_pkcs15_id cert_id;
+ int ref_count;
+};
+
+void
+sc_close(void)
+{
+ if (p15card) {
+ sc_pkcs15_unbind(p15card);
+ p15card = NULL;
+ }
+ if (card) {
+ sc_disconnect_card(card, 0);
+ card = NULL;
+ }
+ if (ctx) {
+ sc_release_context(ctx);
+ ctx = NULL;
+ }
+}
+
+static int
+sc_init(void)
+{
+ int r;
+
+ r = sc_establish_context(&ctx, "openssh");
+ if (r)
+ goto err;
+ if (sc_reader_id >= ctx->reader_count) {
+ r = SC_ERROR_NO_READERS_FOUND;
+ error("Illegal reader number %d (max %d)", sc_reader_id,
+ ctx->reader_count -1);
+ goto err;
+ }
+ r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card);
+ if (r)
+ goto err;
+ r = sc_pkcs15_bind(card, &p15card);
+ if (r)
+ goto err;
+ return 0;
+err:
+ sc_close();
+ return r;
+}
+
+/* private key operations */
+
+static int
+sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out,
+ unsigned int usage)
+{
+ int r;
+ struct sc_priv_data *priv;
+ struct sc_pkcs15_object *key_obj;
+ struct sc_pkcs15_prkey_info *key;
+ struct sc_pkcs15_object *pin_obj;
+ struct sc_pkcs15_pin_info *pin;
+
+ priv = (struct sc_priv_data *) RSA_get_app_data(rsa);
+ if (priv == NULL)
+ return -1;
+ if (p15card == NULL) {
+ sc_close();
+ r = sc_init();
+ if (r) {
+ error("SmartCard init failed: %s", sc_strerror(r));
+ goto err;
+ }
+ }
+ r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id,
+ usage, &key_obj);
+ if (r) {
+ error("Unable to find private key from SmartCard: %s",
+ sc_strerror(r));
+ goto err;
+ }
+ key = key_obj->data;
+ r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id,
+ &pin_obj);
+ if (r == SC_ERROR_OBJECT_NOT_FOUND) {
+ /* no pin required */
+ r = sc_lock(card);
+ if (r) {
+ error("Unable to lock smartcard: %s", sc_strerror(r));
+ goto err;
+ }
+ *key_obj_out = key_obj;
+ return 0;
+ } else if (r) {
+ error("Unable to find PIN object from SmartCard: %s",
+ sc_strerror(r));
+ goto err;
+ }
+ pin = pin_obj->data;
+ r = sc_lock(card);
+ if (r) {
+ error("Unable to lock smartcard: %s", sc_strerror(r));
+ goto err;
+ }
+ if (sc_pin != NULL) {
+ r = sc_pkcs15_verify_pin(p15card, pin, sc_pin,
+ strlen(sc_pin));
+ if (r) {
+ sc_unlock(card);
+ error("PIN code verification failed: %s",
+ sc_strerror(r));
+ goto err;
+ }
+ }
+ *key_obj_out = key_obj;
+ return 0;
+err:
+ sc_close();
+ return -1;
+}
+
+#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \
+ SC_PKCS15_PRKEY_USAGE_UNWRAP
+
+static int
+sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
+ int padding)
+{
+ struct sc_pkcs15_object *key_obj;
+ int r;
+
+ if (padding != RSA_PKCS1_PADDING)
+ return -1;
+ r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT);
+ if (r)
+ return -1;
+ r = sc_pkcs15_decipher(p15card, key_obj, SC_ALGORITHM_RSA_PAD_PKCS1,
+ from, flen, to, flen);
+ sc_unlock(card);
+ if (r < 0) {
+ error("sc_pkcs15_decipher() failed: %s", sc_strerror(r));
+ goto err;
+ }
+ return r;
+err:
+ sc_close();
+ return -1;
+}
+
+#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \
+ SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
+
+static int
+sc_sign(int type, u_char *m, unsigned int m_len,
+ unsigned char *sigret, unsigned int *siglen, RSA *rsa)
+{
+ struct sc_pkcs15_object *key_obj;
+ int r;
+ unsigned long flags = 0;
+
+ /* XXX: sc_prkey_op_init will search for a pkcs15 private
+ * key object with the sign or signrecover usage flag set.
+ * If the signing key has only the non-repudiation flag set
+ * the key will be rejected as using a non-repudiation key
+ * for authentication is not recommended. Note: This does not
+ * prevent the use of a non-repudiation key for authentication
+ * if the sign or signrecover flag is set as well.
+ */
+ r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN);
+ if (r)
+ return -1;
+ /* FIXME: length of sigret correct? */
+ /* FIXME: check 'type' and modify flags accordingly */
+ flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1;
+ r = sc_pkcs15_compute_signature(p15card, key_obj, flags,
+ m, m_len, sigret, RSA_size(rsa));
+ sc_unlock(card);
+ if (r < 0) {
+ error("sc_pkcs15_compute_signature() failed: %s",
+ sc_strerror(r));
+ goto err;
+ }
+ *siglen = r;
+ return 1;
+err:
+ sc_close();
+ return 0;
+}
+
+static int
+sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
+ int padding)
+{
+ error("Private key encryption not supported");
+ return -1;
+}
+
+/* called on free */
+
+static int (*orig_finish)(RSA *rsa) = NULL;
+
+static int
+sc_finish(RSA *rsa)
+{
+ struct sc_priv_data *priv;
+
+ priv = RSA_get_app_data(rsa);
+ priv->ref_count--;
+ if (priv->ref_count == 0) {
+ free(priv);
+ sc_close();
+ }
+ if (orig_finish)
+ orig_finish(rsa);
+ return 1;
+}
+
+/* engine for overloading private key operations */
+
+static RSA_METHOD *
+sc_get_rsa_method(void)
+{
+ static RSA_METHOD smart_rsa;
+ const RSA_METHOD *def = RSA_get_default_method();
+
+ /* use the OpenSSL version */
+ memcpy(&smart_rsa, def, sizeof(smart_rsa));
+
+ smart_rsa.name = "opensc";
+
+ /* overload */
+ smart_rsa.rsa_priv_enc = sc_private_encrypt;
+ smart_rsa.rsa_priv_dec = sc_private_decrypt;
+ smart_rsa.rsa_sign = sc_sign;
+
+ /* save original */
+ orig_finish = def->finish;
+ smart_rsa.finish = sc_finish;
+
+ return &smart_rsa;
+}
+
+#ifdef USE_ENGINE
+static ENGINE *
+sc_get_engine(void)
+{
+ static ENGINE *smart_engine = NULL;
+
+ if ((smart_engine = ENGINE_new()) == NULL)
+ fatal("ENGINE_new failed");
+
+ ENGINE_set_id(smart_engine, "opensc");
+ ENGINE_set_name(smart_engine, "OpenSC");
+
+ ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
+ ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
+ ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
+ ENGINE_set_RAND(smart_engine, RAND_SSLeay());
+ ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
+
+ return smart_engine;
+}
+#endif
+
+static void
+convert_rsa_to_rsa1(Key * in, Key * out)
+{
+ struct sc_priv_data *priv;
+
+ out->rsa->flags = in->rsa->flags;
+ out->flags = in->flags;
+ RSA_set_method(out->rsa, RSA_get_method(in->rsa));
+ BN_copy(out->rsa->n, in->rsa->n);
+ BN_copy(out->rsa->e, in->rsa->e);
+ priv = RSA_get_app_data(in->rsa);
+ priv->ref_count++;
+ RSA_set_app_data(out->rsa, priv);
+ return;
+}
+
+static int
+sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj)
+{
+ int r;
+ sc_pkcs15_cert_t *cert = NULL;
+ struct sc_priv_data *priv = NULL;
+ sc_pkcs15_cert_info_t *cinfo = cert_obj->data;
+
+ X509 *x509 = NULL;
+ EVP_PKEY *pubkey = NULL;
+ u8 *p;
+ char *tmp;
+
+ debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]);
+ r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
+ if (r) {
+ logit("Certificate read failed: %s", sc_strerror(r));
+ goto err;
+ }
+ x509 = X509_new();
+ if (x509 == NULL) {
+ r = -1;
+ goto err;
+ }
+ p = cert->data;
+ if (!d2i_X509(&x509, &p, cert->data_len)) {
+ logit("Unable to parse X.509 certificate");
+ r = -1;
+ goto err;
+ }
+ sc_pkcs15_free_certificate(cert);
+ cert = NULL;
+ pubkey = X509_get_pubkey(x509);
+ X509_free(x509);
+ x509 = NULL;
+ if (pubkey->type != EVP_PKEY_RSA) {
+ logit("Public key is of unknown type");
+ r = -1;
+ goto err;
+ }
+ k->rsa = EVP_PKEY_get1_RSA(pubkey);
+ EVP_PKEY_free(pubkey);
+
+ k->rsa->flags |= RSA_FLAG_SIGN_VER;
+ RSA_set_method(k->rsa, sc_get_rsa_method());
+ priv = xmalloc(sizeof(struct sc_priv_data));
+ priv->cert_id = cinfo->id;
+ priv->ref_count = 1;
+ RSA_set_app_data(k->rsa, priv);
+
+ k->flags = KEY_FLAG_EXT;
+ tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+ debug("fingerprint %d %s", key_size(k), tmp);
+ xfree(tmp);
+
+ return 0;
+err:
+ if (cert)
+ sc_pkcs15_free_certificate(cert);
+ if (pubkey)
+ EVP_PKEY_free(pubkey);
+ if (x509)
+ X509_free(x509);
+ return r;
+}
+
+Key **
+sc_get_keys(const char *id, const char *pin)
+{
+ Key *k, **keys;
+ int i, r, real_count = 0, key_count;
+ sc_pkcs15_id_t cert_id;
+ sc_pkcs15_object_t *certs[32];
+ char *buf = xstrdup(id), *p;
+
+ debug("sc_get_keys called: id = %s", id);
+
+ if (sc_pin != NULL)
+ xfree(sc_pin);
+ sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
+
+ cert_id.len = 0;
+ if ((p = strchr(buf, ':')) != NULL) {
+ *p = 0;
+ p++;
+ sc_pkcs15_hex_string_to_id(p, &cert_id);
+ }
+ r = sscanf(buf, "%d", &sc_reader_id);
+ xfree(buf);
+ if (r != 1)
+ goto err;
+ if (p15card == NULL) {
+ sc_close();
+ r = sc_init();
+ if (r) {
+ error("Smartcard init failed: %s", sc_strerror(r));
+ goto err;
+ }
+ }
+ if (cert_id.len) {
+ r = sc_pkcs15_find_cert_by_id(p15card, &cert_id, &certs[0]);
+ if (r < 0)
+ goto err;
+ key_count = 1;
+ } else {
+ r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509,
+ certs, 32);
+ if (r == 0) {
+ logit("No certificates found on smartcard");
+ r = -1;
+ goto err;
+ } else if (r < 0) {
+ error("Certificate enumeration failed: %s",
+ sc_strerror(r));
+ goto err;
+ }
+ key_count = r;
+ }
+ if (key_count > 1024)
+ fatal("Too many keys (%u), expected <= 1024", key_count);
+ keys = xcalloc(key_count * 2 + 1, sizeof(Key *));
+ for (i = 0; i < key_count; i++) {
+ sc_pkcs15_object_t *tmp_obj = NULL;
+ cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id;
+ if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj))
+ /* skip the public key (certificate) if no
+ * corresponding private key is present */
+ continue;
+ k = key_new(KEY_RSA);
+ if (k == NULL)
+ break;
+ r = sc_read_pubkey(k, certs[i]);
+ if (r) {
+ error("sc_read_pubkey failed: %s", sc_strerror(r));
+ key_free(k);
+ continue;
+ }
+ keys[real_count] = k;
+ real_count++;
+ k = key_new(KEY_RSA1);
+ if (k == NULL)
+ break;
+ convert_rsa_to_rsa1(keys[real_count-1], k);
+ keys[real_count] = k;
+ real_count++;
+ }
+ keys[real_count] = NULL;
+
+ return keys;
+err:
+ sc_close();
+ return NULL;
+}
+
+int
+sc_put_key(Key *prv, const char *id)
+{
+ error("key uploading not yet supported");
+ return -1;
+}
+
+char *
+sc_get_key_label(Key *key)
+{
+ int r;
+ const struct sc_priv_data *priv;
+ struct sc_pkcs15_object *key_obj;
+
+ priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa);
+ if (priv == NULL || p15card == NULL) {
+ logit("SmartCard key not loaded");
+ /* internal error => return default label */
+ return xstrdup("smartcard key");
+ }
+ r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj);
+ if (r) {
+ logit("Unable to find private key from SmartCard: %s",
+ sc_strerror(r));
+ return xstrdup("smartcard key");
+ }
+ if (key_obj == NULL || key_obj->label == NULL)
+ /* the optional PKCS#15 label does not exists
+ * => return the default label */
+ return xstrdup("smartcard key");
+ return xstrdup(key_obj->label);
+}
+
+#endif /* SMARTCARD */
diff --git a/crypto/openssh/scard.c b/crypto/openssh/scard.c
new file mode 100644
index 0000000..9fd3ca1
--- /dev/null
+++ b/crypto/openssh/scard.c
@@ -0,0 +1,571 @@
+/* $OpenBSD: scard.c,v 1.36 2006/11/06 21:25:28 markus Exp $ */
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+#if defined(SMARTCARD) && defined(USE_SECTOK)
+
+#include <sys/types.h>
+
+#include <sectok.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include "xmalloc.h"
+#include "key.h"
+#include "log.h"
+#include "misc.h"
+#include "scard.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#define USE_ENGINE
+#define RSA_get_default_method RSA_get_default_openssl_method
+#else
+#endif
+
+#ifdef USE_ENGINE
+#include <openssl/engine.h>
+#define sc_get_rsa sc_get_engine
+#else
+#define sc_get_rsa sc_get_rsa_method
+#endif
+
+#define CLA_SSH 0x05
+#define INS_DECRYPT 0x10
+#define INS_GET_KEYLENGTH 0x20
+#define INS_GET_PUBKEY 0x30
+#define INS_GET_RESPONSE 0xc0
+
+#define MAX_BUF_SIZE 256
+
+u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63};
+
+static int sc_fd = -1;
+static char *sc_reader_id = NULL;
+static char *sc_pin = NULL;
+static int cla = 0x00; /* class */
+
+static void sc_mk_digest(const char *pin, u_char *digest);
+static int get_AUT0(u_char *aut0);
+static int try_AUT0(void);
+
+/* interface to libsectok */
+
+static int
+sc_open(void)
+{
+ int sw;
+
+ if (sc_fd >= 0)
+ return sc_fd;
+
+ sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw);
+ if (sc_fd < 0) {
+ error("sectok_open failed: %s", sectok_get_sw(sw));
+ return SCARD_ERROR_FAIL;
+ }
+ if (! sectok_cardpresent(sc_fd)) {
+ debug("smartcard in reader %s not present, skipping",
+ sc_reader_id);
+ sc_close();
+ return SCARD_ERROR_NOCARD;
+ }
+ if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) {
+ error("sectok_reset failed: %s", sectok_get_sw(sw));
+ sc_fd = -1;
+ return SCARD_ERROR_FAIL;
+ }
+ if ((cla = cyberflex_inq_class(sc_fd)) < 0)
+ cla = 0;
+
+ debug("sc_open ok %d", sc_fd);
+ return sc_fd;
+}
+
+static int
+sc_enable_applet(void)
+{
+ static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e};
+ int sw = 0;
+
+ /* select applet id */
+ sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw);
+ if (!sectok_swOK(sw)) {
+ error("sectok_apdu failed: %s", sectok_get_sw(sw));
+ sc_close();
+ return -1;
+ }
+ return 0;
+}
+
+static int
+sc_init(void)
+{
+ int status;
+
+ status = sc_open();
+ if (status == SCARD_ERROR_NOCARD) {
+ return SCARD_ERROR_NOCARD;
+ }
+ if (status < 0) {
+ error("sc_open failed");
+ return status;
+ }
+ if (sc_enable_applet() < 0) {
+ error("sc_enable_applet failed");
+ return SCARD_ERROR_APPLET;
+ }
+ return 0;
+}
+
+static int
+sc_read_pubkey(Key * k)
+{
+ u_char buf[2], *n;
+ char *p;
+ int len, sw, status = -1;
+
+ len = sw = 0;
+ n = NULL;
+
+ if (sc_fd < 0) {
+ if (sc_init() < 0)
+ goto err;
+ }
+
+ /* get key size */
+ sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL,
+ sizeof(buf), buf, &sw);
+ if (!sectok_swOK(sw)) {
+ error("could not obtain key length: %s", sectok_get_sw(sw));
+ goto err;
+ }
+ len = (buf[0] << 8) | buf[1];
+ len /= 8;
+ debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw));
+
+ n = xmalloc(len);
+ /* get n */
+ sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
+
+ if (sw == 0x6982) {
+ if (try_AUT0() < 0)
+ goto err;
+ sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw);
+ }
+ if (!sectok_swOK(sw)) {
+ error("could not obtain public key: %s", sectok_get_sw(sw));
+ goto err;
+ }
+
+ debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw));
+
+ if (BN_bin2bn(n, len, k->rsa->n) == NULL) {
+ error("c_read_pubkey: BN_bin2bn failed");
+ goto err;
+ }
+
+ /* currently the java applet just stores 'n' */
+ if (!BN_set_word(k->rsa->e, 35)) {
+ error("c_read_pubkey: BN_set_word(e, 35) failed");
+ goto err;
+ }
+
+ status = 0;
+ p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX);
+ debug("fingerprint %u %s", key_size(k), p);
+ xfree(p);
+
+err:
+ if (n != NULL)
+ xfree(n);
+ sc_close();
+ return status;
+}
+
+/* private key operations */
+
+static int
+sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa,
+ int padding)
+{
+ u_char *padded = NULL;
+ int sw, len, olen, status = -1;
+
+ debug("sc_private_decrypt called");
+
+ olen = len = sw = 0;
+ if (sc_fd < 0) {
+ status = sc_init();
+ if (status < 0)
+ goto err;
+ }
+ if (padding != RSA_PKCS1_PADDING)
+ goto err;
+
+ len = BN_num_bytes(rsa->n);
+ padded = xmalloc(len);
+
+ sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
+
+ if (sw == 0x6982) {
+ if (try_AUT0() < 0)
+ goto err;
+ sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw);
+ }
+ if (!sectok_swOK(sw)) {
+ error("sc_private_decrypt: INS_DECRYPT failed: %s",
+ sectok_get_sw(sw));
+ goto err;
+ }
+ olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1,
+ len);
+err:
+ if (padded)
+ xfree(padded);
+ sc_close();
+ return (olen >= 0 ? olen : status);
+}
+
+static int
+sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa,
+ int padding)
+{
+ u_char *padded = NULL;
+ int sw, len, status = -1;
+
+ len = sw = 0;
+ if (sc_fd < 0) {
+ status = sc_init();
+ if (status < 0)
+ goto err;
+ }
+ if (padding != RSA_PKCS1_PADDING)
+ goto err;
+
+ debug("sc_private_encrypt called");
+ len = BN_num_bytes(rsa->n);
+ padded = xmalloc(len);
+
+ if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) {
+ error("RSA_padding_add_PKCS1_type_1 failed");
+ goto err;
+ }
+ sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
+ if (sw == 0x6982) {
+ if (try_AUT0() < 0)
+ goto err;
+ sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw);
+ }
+ if (!sectok_swOK(sw)) {
+ error("sc_private_encrypt: INS_DECRYPT failed: %s",
+ sectok_get_sw(sw));
+ goto err;
+ }
+err:
+ if (padded)
+ xfree(padded);
+ sc_close();
+ return (len >= 0 ? len : status);
+}
+
+/* called on free */
+
+static int (*orig_finish)(RSA *rsa) = NULL;
+
+static int
+sc_finish(RSA *rsa)
+{
+ if (orig_finish)
+ orig_finish(rsa);
+ sc_close();
+ return 1;
+}
+
+/* engine for overloading private key operations */
+
+static RSA_METHOD *
+sc_get_rsa_method(void)
+{
+ static RSA_METHOD smart_rsa;
+ const RSA_METHOD *def = RSA_get_default_method();
+
+ /* use the OpenSSL version */
+ memcpy(&smart_rsa, def, sizeof(smart_rsa));
+
+ smart_rsa.name = "sectok";
+
+ /* overload */
+ smart_rsa.rsa_priv_enc = sc_private_encrypt;
+ smart_rsa.rsa_priv_dec = sc_private_decrypt;
+
+ /* save original */
+ orig_finish = def->finish;
+ smart_rsa.finish = sc_finish;
+
+ return &smart_rsa;
+}
+
+#ifdef USE_ENGINE
+static ENGINE *
+sc_get_engine(void)
+{
+ static ENGINE *smart_engine = NULL;
+
+ if ((smart_engine = ENGINE_new()) == NULL)
+ fatal("ENGINE_new failed");
+
+ ENGINE_set_id(smart_engine, "sectok");
+ ENGINE_set_name(smart_engine, "libsectok");
+
+ ENGINE_set_RSA(smart_engine, sc_get_rsa_method());
+ ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method());
+ ENGINE_set_DH(smart_engine, DH_get_default_openssl_method());
+ ENGINE_set_RAND(smart_engine, RAND_SSLeay());
+ ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp);
+
+ return smart_engine;
+}
+#endif
+
+void
+sc_close(void)
+{
+ if (sc_fd >= 0) {
+ sectok_close(sc_fd);
+ sc_fd = -1;
+ }
+}
+
+Key **
+sc_get_keys(const char *id, const char *pin)
+{
+ Key *k, *n, **keys;
+ int status, nkeys = 2;
+
+ if (sc_reader_id != NULL)
+ xfree(sc_reader_id);
+ sc_reader_id = xstrdup(id);
+
+ if (sc_pin != NULL)
+ xfree(sc_pin);
+ sc_pin = (pin == NULL) ? NULL : xstrdup(pin);
+
+ k = key_new(KEY_RSA);
+ if (k == NULL) {
+ return NULL;
+ }
+ status = sc_read_pubkey(k);
+ if (status == SCARD_ERROR_NOCARD) {
+ key_free(k);
+ return NULL;
+ }
+ if (status < 0) {
+ error("sc_read_pubkey failed");
+ key_free(k);
+ return NULL;
+ }
+ keys = xcalloc((nkeys+1), sizeof(Key *));
+
+ n = key_new(KEY_RSA1);
+ if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
+ (BN_copy(n->rsa->e, k->rsa->e) == NULL))
+ fatal("sc_get_keys: BN_copy failed");
+ RSA_set_method(n->rsa, sc_get_rsa());
+ n->flags |= KEY_FLAG_EXT;
+ keys[0] = n;
+
+ n = key_new(KEY_RSA);
+ if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
+ (BN_copy(n->rsa->e, k->rsa->e) == NULL))
+ fatal("sc_get_keys: BN_copy failed");
+ RSA_set_method(n->rsa, sc_get_rsa());
+ n->flags |= KEY_FLAG_EXT;
+ keys[1] = n;
+
+ keys[2] = NULL;
+
+ key_free(k);
+ return keys;
+}
+
+#define NUM_RSA_KEY_ELEMENTS 5+1
+#define COPY_RSA_KEY(x, i) \
+ do { \
+ len = BN_num_bytes(prv->rsa->x); \
+ elements[i] = xmalloc(len); \
+ debug("#bytes %d", len); \
+ if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \
+ goto done; \
+ } while (0)
+
+static void
+sc_mk_digest(const char *pin, u_char *digest)
+{
+ const EVP_MD *evp_md = EVP_sha1();
+ EVP_MD_CTX md;
+
+ EVP_DigestInit(&md, evp_md);
+ EVP_DigestUpdate(&md, pin, strlen(pin));
+ EVP_DigestFinal(&md, digest, NULL);
+}
+
+static int
+get_AUT0(u_char *aut0)
+{
+ char *pass;
+
+ pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
+ if (pass == NULL)
+ return -1;
+ if (!strcmp(pass, "-")) {
+ memcpy(aut0, DEFAUT0, sizeof DEFAUT0);
+ return 0;
+ }
+ sc_mk_digest(pass, aut0);
+ memset(pass, 0, strlen(pass));
+ xfree(pass);
+ return 0;
+}
+
+static int
+try_AUT0(void)
+{
+ u_char aut0[EVP_MAX_MD_SIZE];
+
+ /* permission denied; try PIN if provided */
+ if (sc_pin && strlen(sc_pin) > 0) {
+ sc_mk_digest(sc_pin, aut0);
+ if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
+ error("smartcard passphrase incorrect");
+ return (-1);
+ }
+ } else {
+ /* try default AUT0 key */
+ if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) {
+ /* default AUT0 key failed; prompt for passphrase */
+ if (get_AUT0(aut0) < 0 ||
+ cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) {
+ error("smartcard passphrase incorrect");
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+int
+sc_put_key(Key *prv, const char *id)
+{
+ u_char *elements[NUM_RSA_KEY_ELEMENTS];
+ u_char key_fid[2];
+ u_char AUT0[EVP_MAX_MD_SIZE];
+ int len, status = -1, i, fd = -1, ret;
+ int sw = 0, cla = 0x00;
+
+ for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
+ elements[i] = NULL;
+
+ COPY_RSA_KEY(q, 0);
+ COPY_RSA_KEY(p, 1);
+ COPY_RSA_KEY(iqmp, 2);
+ COPY_RSA_KEY(dmq1, 3);
+ COPY_RSA_KEY(dmp1, 4);
+ COPY_RSA_KEY(n, 5);
+ len = BN_num_bytes(prv->rsa->n);
+ fd = sectok_friendly_open(id, STONOWAIT, &sw);
+ if (fd < 0) {
+ error("sectok_open failed: %s", sectok_get_sw(sw));
+ goto done;
+ }
+ if (! sectok_cardpresent(fd)) {
+ error("smartcard in reader %s not present", id);
+ goto done;
+ }
+ ret = sectok_reset(fd, 0, NULL, &sw);
+ if (ret <= 0) {
+ error("sectok_reset failed: %s", sectok_get_sw(sw));
+ goto done;
+ }
+ if ((cla = cyberflex_inq_class(fd)) < 0) {
+ error("cyberflex_inq_class failed");
+ goto done;
+ }
+ memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0));
+ if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
+ if (get_AUT0(AUT0) < 0 ||
+ cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) {
+ memset(AUT0, 0, sizeof(DEFAUT0));
+ error("smartcard passphrase incorrect");
+ goto done;
+ }
+ }
+ memset(AUT0, 0, sizeof(DEFAUT0));
+ key_fid[0] = 0x00;
+ key_fid[1] = 0x12;
+ if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements,
+ &sw) < 0) {
+ error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw));
+ goto done;
+ }
+ if (!sectok_swOK(sw))
+ goto done;
+ logit("cyberflex_load_rsa_priv done");
+ key_fid[0] = 0x73;
+ key_fid[1] = 0x68;
+ if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5],
+ &sw) < 0) {
+ error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw));
+ goto done;
+ }
+ if (!sectok_swOK(sw))
+ goto done;
+ logit("cyberflex_load_rsa_pub done");
+ status = 0;
+
+done:
+ memset(elements[0], '\0', BN_num_bytes(prv->rsa->q));
+ memset(elements[1], '\0', BN_num_bytes(prv->rsa->p));
+ memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp));
+ memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1));
+ memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1));
+ memset(elements[5], '\0', BN_num_bytes(prv->rsa->n));
+
+ for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++)
+ if (elements[i])
+ xfree(elements[i]);
+ if (fd != -1)
+ sectok_close(fd);
+ return (status);
+}
+
+char *
+sc_get_key_label(Key *key)
+{
+ return xstrdup("smartcard key");
+}
+
+#endif /* SMARTCARD && USE_SECTOK */
diff --git a/crypto/openssh/scard.h b/crypto/openssh/scard.h
new file mode 100644
index 0000000..82efe48
--- /dev/null
+++ b/crypto/openssh/scard.h
@@ -0,0 +1,39 @@
+/* $OpenBSD: scard.h,v 1.14 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.
+ */
+
+#ifndef SCARD_H
+#define SCARD_H
+
+#define SCARD_ERROR_FAIL -1
+#define SCARD_ERROR_NOCARD -2
+#define SCARD_ERROR_APPLET -3
+
+Key **sc_get_keys(const char *, const char *);
+void sc_close(void);
+int sc_put_key(Key *, const char *);
+char *sc_get_key_label(Key *);
+
+#endif
diff --git a/crypto/openssh/schnorr.c b/crypto/openssh/schnorr.c
new file mode 100644
index 0000000..daeec06
--- /dev/null
+++ b/crypto/openssh/schnorr.c
@@ -0,0 +1,653 @@
+/* $OpenBSD: schnorr.c,v 1.3 2009/03/05 07:18:19 djm Exp $ */
+/* $FreeBSD$ */
+/*
+ * 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"
+
+#ifdef JPAKE
+
+#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;
+ }
+
+ 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, *g_xh, *g_r, *expected;
+ 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;
+ }
+
+ 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 ||
+ (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__));
+
+ /* 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);
+ BN_clear_free(g_xh);
+ BN_clear_free(g_r);
+ 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
+
+#endif
diff --git a/crypto/openssh/schnorr.h b/crypto/openssh/schnorr.h
new file mode 100644
index 0000000..9730b47
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/scp.1 b/crypto/openssh/scp.1
new file mode 100644
index 0000000..611beea
--- /dev/null
+++ b/crypto/openssh/scp.1
@@ -0,0 +1,231 @@
+.\" -*- nroff -*-
+.\"
+.\" scp.1
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\"
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" Created: Sun May 7 00:14:37 1995 ylo
+.\"
+.\" $OpenBSD: scp.1,v 1.46 2008/07/12 05:33:41 djm Exp $
+.\"
+.Dd July 12 2008
+.Dt SCP 1
+.Os
+.Sh NAME
+.Nm scp
+.Nd secure copy (remote file copy program)
+.Sh SYNOPSIS
+.Nm scp
+.Bk -words
+.Op Fl 1246BCpqrv
+.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 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 KbdInteractiveDevices
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It Port
+.It PreferredAuthentications
+.It Protocol
+.It ProxyCommand
+.It PubkeyAuthentication
+.It RekeyLimit
+.It RhostsRSAAuthentication
+.It RSAAuthentication
+.It SendEnv
+.It ServerAliveInterval
+.It ServerAliveCountMax
+.It SmartcardDevice
+.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
+.Pp
+.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/crypto/openssh/scp.c b/crypto/openssh/scp.c
new file mode 100644
index 0000000..3237478
--- /dev/null
+++ b/crypto/openssh/scp.c
@@ -0,0 +1,1287 @@
+/* $OpenBSD: scp.c,v 1.164 2008/10/10 04:55:16 stevesk 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);
+
+void bwlimit(int);
+
+/* Struct for addargs */
+arglist args;
+
+/* Bandwidth limit */
+off_t limit_rate = 0;
+
+/* Name of current file being transferred. */
+char *curfile;
+
+/* This is set to non-zero to enable verbose mode. */
+int verbose_mode = 0;
+
+/* This is set to zero if the progressmeter is not desired. */
+int showprogress = 1;
+
+/* This is the program to execute for the secured connection. ("ssh" or -S) */
+char *ssh_program = _PATH_SSH_PROGRAM;
+
+/* This 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 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]);
+
+ /* 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%s", remuser);
+ 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;
+}
+
+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 *[]);
+size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *);
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ int ch, fflag, tflag, status, n;
+ double speed;
+ char *targ, *endp, **newargv;
+ 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));
+ 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:q1246S:o:F:")) != -1)
+ switch (ch) {
+ /* User-visible flags. */
+ case '1':
+ case '2':
+ case '4':
+ case '6':
+ case 'C':
+ addargs(&args, "-%c", ch);
+ break;
+ case 'o':
+ case 'c':
+ case 'i':
+ case 'F':
+ addargs(&args, "-%c%s", ch, optarg);
+ break;
+ case 'P':
+ addargs(&args, "-p%s", optarg);
+ break;
+ case 'B':
+ addargs(&args, "-oBatchmode yes");
+ break;
+ case 'l':
+ speed = strtod(optarg, &endp);
+ if (speed <= 0 || *endp != '\0')
+ usage();
+ limit_rate = speed * 1024;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ iamrecursive = 1;
+ break;
+ case 'S':
+ ssh_program = xstrdup(optarg);
+ break;
+ case 'v':
+ addargs(&args, "-v");
+ verbose_mode = 1;
+ break;
+ case 'q':
+ addargs(&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);
+}
+
+/*
+ * atomicio-like wrapper that also applies bandwidth limits and updates
+ * the progressmeter counter.
+ */
+size_t
+scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c)
+{
+ u_char *p = (u_char *)_p;
+ size_t offset;
+ ssize_t r;
+ struct pollfd pfd;
+
+ pfd.fd = fd;
+ pfd.events = f == read ? POLLIN : POLLOUT;
+ for (offset = 0; offset < l;) {
+ r = f(fd, p + offset, l - offset);
+ if (r == 0) {
+ errno = EPIPE;
+ return offset;
+ }
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ (void)poll(&pfd, 1, -1); /* Ignore errors */
+ continue;
+ }
+ return offset;
+ }
+ offset += (size_t)r;
+ *c += (off_t)r;
+ if (limit_rate)
+ bwlimit(r);
+ }
+ return offset;
+}
+
+void
+toremote(char *targ, int argc, char **argv)
+{
+ char *bp, *host, *src, *suser, *thost, *tuser, *arg;
+ arglist alist;
+ int i;
+
+ 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) { /* remote to remote */
+ freeargs(&alist);
+ addargs(&alist, "%s", ssh_program);
+ if (verbose_mode)
+ addargs(&alist, "-v");
+ addargs(&alist, "-x");
+ addargs(&alist, "-oClearAllForwardings yes");
+ addargs(&alist, "-n");
+
+ *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, "%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, "%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 (scpio(vwrite, remout, bp->buf, amt,
+ &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
+bwlimit(int amount)
+{
+ static struct timeval bwstart, bwend;
+ static int lamt, thresh = 16384;
+ u_int64_t waitlen;
+ struct timespec ts, rm;
+
+ if (!timerisset(&bwstart)) {
+ gettimeofday(&bwstart, NULL);
+ return;
+ }
+
+ lamt += amount;
+ if (lamt < thresh)
+ return;
+
+ gettimeofday(&bwend, NULL);
+ timersub(&bwend, &bwstart, &bwend);
+ if (!timerisset(&bwend))
+ return;
+
+ lamt *= 8;
+ waitlen = (double)1000000L * lamt / limit_rate;
+
+ bwstart.tv_sec = waitlen / 1000000L;
+ bwstart.tv_usec = waitlen % 1000000L;
+
+ if (timercmp(&bwstart, &bwend, >)) {
+ timersub(&bwstart, &bwend, &bwend);
+
+ /* Adjust the wait time */
+ if (bwend.tv_sec) {
+ thresh /= 2;
+ if (thresh < 2048)
+ thresh = 2048;
+ } else if (bwend.tv_usec < 10000) {
+ thresh *= 2;
+ if (thresh > COPY_BUFLEN * 4)
+ thresh = COPY_BUFLEN * 4;
+ }
+
+ TIMEVAL_TO_TIMESPEC(&bwend, &ts);
+ while (nanosleep(&ts, &rm) == -1) {
+ if (errno != EINTR)
+ break;
+ ts = rm;
+ }
+ }
+
+ lamt = 0;
+ gettimeofday(&bwstart, NULL);
+}
+
+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 = scpio(read, remin, cp, amt, &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 [-1246BCpqrv] [-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/crypto/openssh/servconf.c b/crypto/openssh/servconf.c
new file mode 100644
index 0000000..ad25fef
--- /dev/null
+++ b/crypto/openssh/servconf.c
@@ -0,0 +1,1669 @@
+/* $OpenBSD: servconf.c,v 1.195 2009/04/14 21:10:54 jj 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"
+__RCSID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.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->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->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;
+}
+
+void
+fill_default_server_options(ServerOptions *options)
+{
+ /* Portable-specific options */
+ if (options->use_pam == -1)
+ options->use_pam = 1;
+
+ /* 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;
+ }
+ }
+ 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_NO;
+ 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 = 1;
+ 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 = 0;
+ 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 = options->authorized_keys_file;
+ else
+ options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2;
+ }
+ if (options->authorized_keys_file == NULL)
+ options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS;
+ if (options->permit_tun == -1)
+ options->permit_tun = SSH_TUNMODE_NO;
+ if (options->zero_knowledge_password_authentication == -1)
+ options->zero_knowledge_password_authentication = 0;
+
+ /* 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,
+ sVersionAddendum,
+ 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_GLOBAL },
+ { "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_GLOBAL },
+ { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
+ { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL},
+ { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
+ { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
+ { "match", sMatch, SSHCFG_ALL },
+ { "permitopen", sPermitOpen, SSHCFG_ALL },
+ { "forcecommand", sForceCommand, SSHCFG_ALL },
+ { "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
+ { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
+ { 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;
+}
+
+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, 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 = tilde_expand_filename(arg, getuid());
+ /* increase optional counter */
+ if (intptr != NULL)
+ *intptr = *intptr + 1;
+ }
+ break;
+
+ case sPidFile:
+ charptr = &options->pid_file;
+ goto parse_filename;
+
+ case sPermitRootLogin:
+ intptr = &options->permit_root_login;
+ arg = strdelim(&cp);
+ if (!arg || *arg == '\0')
+ fatal("%s line %d: missing yes/"
+ "without-password/forced-commands-only/no "
+ "argument.", filename, linenum);
+ value = 0; /* silence compiler */
+ if (strcmp(arg, "without-password") == 0)
+ value = PERMIT_NO_PASSWD;
+ else if (strcmp(arg, "forced-commands-only") == 0)
+ value = PERMIT_FORCED_ONLY;
+ else if (strcmp(arg, "yes") == 0)
+ value = PERMIT_YES;
+ else if (strcmp(arg, "no") == 0)
+ value = PERMIT_NO;
+ else
+ fatal("%s line %d: Bad yes/"
+ "without-password/forced-commands-only/no "
+ "argument: %s", filename, linenum, arg);
+ if (*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 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:
+ case sAuthorizedKeysFile2:
+ charptr = (opcode == sAuthorizedKeysFile) ?
+ &options->authorized_keys_file :
+ &options->authorized_keys_file2;
+ goto parse_filename;
+
+ case sClientAliveInterval:
+ intptr = &options->client_alive_interval;
+ goto parse_time;
+
+ case sClientAliveCountMax:
+ intptr = &options->client_alive_count_max;
+ goto parse_int;
+
+ case 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 sVersionAddendum:
+ ssh_version_set_addendum(strtok(cp, "\n"));
+ do {
+ arg = strdelim(&cp);
+ } while (arg != NULL && *arg != '\0');
+ 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(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(gateway_ports);
+ M_CP_INTOPT(x11_display_offset);
+ M_CP_INTOPT(x11_forwarding);
+ M_CP_INTOPT(x11_use_localhost);
+ M_CP_INTOPT(max_sessions);
+ M_CP_INTOPT(max_authtries);
+
+ M_CP_STROPT(banner);
+ if (preauth)
+ return;
+ M_CP_STROPT(adm_forced_command);
+ M_CP_STROPT(chroot_directory);
+}
+
+#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);
+
+ /* string arguments requiring a lookup */
+ dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+ dump_cfg_string(sLogFacility, log_facility_name(o->log_facility));
+
+ /* string array arguments */
+ dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
+ o->host_key_files);
+ dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users);
+ dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users);
+ dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups);
+ dump_cfg_strarray(sDenyGroups, o->num_deny_groups, o->deny_groups);
+ dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env);
+
+ /* other arguments */
+ for (i = 0; i < o->num_subsystems; i++)
+ printf("subsystem %s %s\n", o->subsystem_name[i],
+ o->subsystem_args[i]);
+
+ printf("maxstartups %d:%d:%d\n", o->max_startups_begin,
+ o->max_startups_rate, o->max_startups);
+
+ for (i = 0; tunmode_desc[i].val != -1; i++)
+ if (tunmode_desc[i].val == o->permit_tun) {
+ s = tunmode_desc[i].text;
+ break;
+ }
+ dump_cfg_string(sPermitTunnel, s);
+
+ channel_print_adm_permitted_opens();
+}
diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h
new file mode 100644
index 0000000..b3ac7da
--- /dev/null
+++ b/crypto/openssh/servconf.h
@@ -0,0 +1,168 @@
+/* $OpenBSD: servconf.h,v 1.87 2009/01/22 10:02:34 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_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 *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. */
+ char *ciphers; /* Supported SSH2 ciphers. */
+ char *macs; /* Supported SSH2 macs. */
+ int protocol; /* Supported protocol versions. */
+ int gateway_ports; /* If true, allow remote connects to forwarded ports. */
+ SyslogFacility log_facility; /* Facility for system logging. */
+ LogLevel log_level; /* Level for system logging. */
+ int rhosts_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;
+} 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 *);
+
+#endif /* SERVCONF_H */
diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c
new file mode 100644
index 0000000..8be01c5
--- /dev/null
+++ b/crypto/openssh/serverloop.c
@@ -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/crypto/openssh/serverloop.h b/crypto/openssh/serverloop.h
new file mode 100644
index 0000000..7311558
--- /dev/null
+++ b/crypto/openssh/serverloop.h
@@ -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/crypto/openssh/session.c b/crypto/openssh/session.c
new file mode 100644
index 0000000..51cca49
--- /dev/null
+++ b/crypto/openssh/session.c
@@ -0,0 +1,2781 @@
+/* $OpenBSD: session.c,v 1.246 2009/04/17 19:23:06 stevesk 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"
+__RCSID("$FreeBSD$");
+
+#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 <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);
+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
+
+#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();
+
+ 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];
+
+ /* 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];
+
+ /* 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
+
+ if (s == NULL)
+ fatal("do_exec_no_pty: no session");
+
+ 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);
+
+ /*
+ * 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) {
+ if (s->is_subsystem) {
+ close(perr[0]);
+ perr[0] = -1;
+ }
+ session_set_fds(s, pin[1], pout[0], perr[0], 0);
+ } else {
+ /* Enter the interactive session. */
+ server_loop(pid, pin[1], pout[0], perr[0]);
+ /* server_loop has closed pin[1], pout[0], and perr[0]. */
+ }
+#else
+ /* We are the parent. Close the child sides of the socket pairs. */
+ close(inout[0]);
+ close(err[0]);
+
+ /*
+ * Enter the interactive session. Note: server_loop must be able to
+ * handle the case that fdin and fdout are the same.
+ */
+ if (compat20) {
+ session_set_fds(s, inout[1], inout[1],
+ s->is_subsystem ? -1 : err[1], 0);
+ if (s->is_subsystem)
+ close(err[1]);
+ } else {
+ server_loop(pid, inout[1], inout[1], err[1]);
+ /* server_loop has closed inout[1] and err[1]. */
+ }
+#endif
+ 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);
+ if (compat20) {
+ session_set_fds(s, ptyfd, fdout, -1, 1);
+ } else {
+ server_loop(pid, ptyfd, fdout, -1);
+ /* server_loop _has_ closed ptyfd and fdout. */
+ }
+ return 0;
+}
+
+#ifdef LOGIN_NEEDS_UTMPX
+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 = SUBSYSTEM_INT_SFTP;
+ 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 = SUBSYSTEM_INT_SFTP;
+ 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];
+#ifdef HAVE_LOGIN_CAP
+ const char *fname;
+#endif
+
+#ifdef HAVE_LOGIN_CAP
+ fname = login_getcapstr(lc, "copyright", NULL, NULL);
+ if (fname != NULL && (f = fopen(fname, "r")) != NULL) {
+ while (fgets(buf, sizeof(buf), f) != NULL)
+ fputs(buf, stdout);
+ fclose(f);
+ } else
+#endif /* HAVE_LOGIN_CAP */
+ (void)printf("%s\n\t%s %s\n",
+ "Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994",
+ "The Regents of the University of California. ",
+ "All rights reserved.");
+
+ (void)printf("\n");
+
+ 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;
+#else
+ extern char **environ;
+ char **senv, **var;
+#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
+
+ if (getenv("TZ"))
+ child_set_env(&env, &envsize, "TZ", getenv("TZ"));
+
+#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);
+ snprintf(buf, sizeof buf, "%.200s/%.50s",
+ _PATH_MAILDIR, pw->pw_name);
+ child_set_env(&env, &envsize, "MAIL", buf);
+#ifdef HAVE_LOGIN_CAP
+ child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+ child_set_env(&env, &envsize, "TERM", "su");
+ senv = environ;
+ environ = xmalloc(sizeof(char *));
+ *environ = NULL;
+ (void) setusercontext(lc, pw, pw->pw_uid,
+ LOGIN_SETENV|LOGIN_SETPATH);
+ copy_environment(environ, &env, &envsize);
+ for (var = environ; *var != NULL; ++var)
+ xfree(*var);
+ xfree(environ);
+ environ = senv;
+#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 */
+
+ /* Normal systems set SHELL by default. */
+ child_set_env(&env, &envsize, "SHELL", shell);
+ }
+
+ /* 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];
+
+#ifdef HAVE_LOGIN_CAP
+ if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
+ f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
+ _PATH_NOLOGIN), "r");
+#else
+ if (pw->pw_uid)
+ f = fopen(_PATH_NOLOGIN, "r");
+#endif
+ if (f) {
+ /* /etc/nologin exists. Print its contents and exit. */
+ logit("User %.100s not allowed because %s exists",
+ pw->pw_name, _PATH_NOLOGIN);
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ fflush(NULL);
+ 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;
+
+#ifdef WITH_SELINUX
+ /* Cache selinux status for later use */
+ (void)ssh_selinux_enabled();
+#endif
+
+#ifndef HAVE_CYGWIN
+ if (getuid() == 0 || geteuid() == 0)
+#endif /* HAVE_CYGWIN */
+ {
+#ifdef HAVE_LOGIN_CAP
+# ifdef __bsdi__
+ setpgid(0, 0);
+# endif
+# ifdef USE_PAM
+ if (options.use_pam) {
+ do_pam_setcred(use_privsep);
+ }
+# endif /* USE_PAM */
+ if (setusercontext(lc, pw, pw->pw_uid,
+ (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
+ perror("unable to set user context");
+ exit(1);
+ }
+#else
+# if defined(HAVE_GETLUID) && defined(HAVE_SETLUID)
+ /* Sets login uid for accounting */
+ if (getluid() == -1 && setluid(pw->pw_uid) == -1)
+ error("setluid: %s", strerror(errno));
+# endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */
+
+ if (setlogin(pw->pw_name) < 0)
+ error("setlogin failed: %s", strerror(errno));
+ if (setgid(pw->pw_gid) < 0) {
+ perror("setgid");
+ exit(1);
+ }
+ /* Initialize the group list. */
+ if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
+ perror("initgroups");
+ exit(1);
+ }
+ endgrent();
+# ifdef USE_PAM
+ /*
+ * PAM credentials may take the form of supplementary groups.
+ * These will have been wiped by the above initgroups() call.
+ * Reestablish them here.
+ */
+ if (options.use_pam) {
+ do_pam_setcred(use_privsep);
+ }
+# endif /* USE_PAM */
+# if 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 */
+# ifdef USE_LIBIAF
+ if (set_id(pw->pw_name) != 0) {
+ exit(1);
+ }
+# endif /* USE_LIBIAF */
+#endif
+
+ 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_SETPCRED
+ if (setpcred(pw->pw_name, (char **)NULL) == -1)
+ fatal("Failed to set process credentials");
+#endif /* HAVE_SETPCRED */
+#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);
+
+#ifdef WITH_SELINUX
+ ssh_selinux_setup_exec_context(pw->pw_name);
+#endif
+}
+
+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)
+{
+ int i;
+
+ if (packet_get_connection_in() == packet_get_connection_out())
+ close(packet_get_connection_in());
+ else {
+ close(packet_get_connection_in());
+ close(packet_get_connection_out());
+ }
+ /*
+ * Close all descriptors related to channels. They will still remain
+ * open in the parent.
+ */
+ /* XXX better use close-on-exec? -markus */
+ channel_close_all();
+
+ /*
+ * Close any extra file descriptors. Note that there may still be
+ * descriptors left by system functions. They will be closed later.
+ */
+ endpwent();
+
+ /*
+ * Close any extra open file descriptors so that we don't have them
+ * hanging around in clients. Note that we want to do this after
+ * initgroups, because at least on Solaris 2.3 it leaves file
+ * descriptors open.
+ */
+ for (i = 3; i < 64; i++)
+ close(i);
+}
+
+/*
+ * 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)
+ 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) {
+ 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];
+ exit(sftp_server_main(i, argv, s->pw));
+ }
+
+ 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", subsys);
+
+ 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)) {
+ s->is_subsystem = SUBSYSTEM_INT_SFTP;
+ } else if (stat(prog, &st) < 0) {
+ error("subsystem: cannot stat %s: %s", prog,
+ strerror(errno));
+ break;
+ } else {
+ 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 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,
+ fderr == -1 ? 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/crypto/openssh/session.h b/crypto/openssh/session.h
new file mode 100644
index 0000000..cbb8e3a
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c
new file mode 100644
index 0000000..0990b79
--- /dev/null
+++ b/crypto/openssh/sftp-client.c
@@ -0,0 +1,1315 @@
+/* $OpenBSD: sftp-client.c,v 1.87 2009/06/22 05:39:28 dtucker 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 <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
+
+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
+ u_int exts;
+};
+
+static void
+send_msg(int fd, 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 (atomiciov(writev, fd, iov, 2) != buffer_len(m) + sizeof(mlen))
+ fatal("Couldn't send packet: %s", strerror(errno));
+
+ buffer_clear(m);
+}
+
+static void
+get_msg(int fd, Buffer *m)
+{
+ u_int msg_len;
+
+ buffer_append_space(m, 4);
+ if (atomicio(read, fd, buffer_ptr(m), 4) != 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 (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
+ if (errno == EPIPE)
+ fatal("Connection closed");
+ else
+ fatal("Read packet: %s", strerror(errno));
+ }
+}
+
+static void
+send_string_request(int fd, u_int id, u_int code, char *s,
+ u_int len)
+{
+ Buffer msg;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, code);
+ buffer_put_int(&msg, id);
+ buffer_put_string(&msg, s, len);
+ send_msg(fd, &msg);
+ debug3("Sent message fd %d T:%u I:%u", fd, code, id);
+ buffer_free(&msg);
+}
+
+static void
+send_string_attrs_request(int fd, u_int id, u_int code, char *s,
+ u_int len, Attrib *a)
+{
+ Buffer msg;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, code);
+ buffer_put_int(&msg, id);
+ buffer_put_string(&msg, s, len);
+ encode_attrib(&msg, a);
+ send_msg(fd, &msg);
+ debug3("Sent message fd %d T:%u I:%u", fd, code, id);
+ buffer_free(&msg);
+}
+
+static u_int
+get_status(int fd, u_int expected_id)
+{
+ Buffer msg;
+ u_int type, id, status;
+
+ buffer_init(&msg);
+ get_msg(fd, &msg);
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ if (id != expected_id)
+ fatal("ID mismatch (%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(int fd, u_int expected_id, u_int *len)
+{
+ Buffer msg;
+ u_int type, id;
+ char *handle;
+
+ buffer_init(&msg);
+ get_msg(fd, &msg);
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ if (id != expected_id)
+ fatal("ID mismatch (%u != %u)", id, expected_id);
+ if (type == SSH2_FXP_STATUS) {
+ int status = buffer_get_int(&msg);
+
+ error("Couldn't get handle: %s", fx2txt(status));
+ buffer_free(&msg);
+ return(NULL);
+ } else if (type != SSH2_FXP_HANDLE)
+ fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
+ SSH2_FXP_HANDLE, type);
+
+ handle = buffer_get_string(&msg, len);
+ buffer_free(&msg);
+
+ return(handle);
+}
+
+static Attrib *
+get_decode_stat(int fd, u_int expected_id, int quiet)
+{
+ Buffer msg;
+ u_int type, id;
+ Attrib *a;
+
+ buffer_init(&msg);
+ get_msg(fd, &msg);
+
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ debug3("Received stat reply T:%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(int fd, struct sftp_statvfs *st, u_int expected_id,
+ int quiet)
+{
+ Buffer msg;
+ u_int type, id, flag;
+
+ buffer_init(&msg);
+ get_msg(fd, &msg);
+
+ type = buffer_get_char(&msg);
+ id = buffer_get_int(&msg);
+
+ debug3("Received statvfs reply T:%u I:%u", type, id);
+ if (id != expected_id)
+ fatal("ID mismatch (%u != %u)", id, expected_id);
+ if (type == SSH2_FXP_STATUS) {
+ int status = buffer_get_int(&msg);
+
+ if (quiet)
+ debug("Couldn't statvfs: %s", fx2txt(status));
+ else
+ error("Couldn't statvfs: %s", fx2txt(status));
+ buffer_free(&msg);
+ return -1;
+ } else if (type != SSH2_FXP_EXTENDED_REPLY) {
+ fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
+ SSH2_FXP_EXTENDED_REPLY, type);
+ }
+
+ bzero(st, sizeof(*st));
+ st->f_bsize = buffer_get_int64(&msg);
+ st->f_frsize = buffer_get_int64(&msg);
+ st->f_blocks = buffer_get_int64(&msg);
+ st->f_bfree = buffer_get_int64(&msg);
+ st->f_bavail = buffer_get_int64(&msg);
+ st->f_files = buffer_get_int64(&msg);
+ st->f_ffree = buffer_get_int64(&msg);
+ st->f_favail = buffer_get_int64(&msg);
+ st->f_fsid = buffer_get_int64(&msg);
+ flag = buffer_get_int64(&msg);
+ st->f_namemax = buffer_get_int64(&msg);
+
+ st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
+ st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
+
+ buffer_free(&msg);
+
+ return 0;
+}
+
+struct sftp_conn *
+do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
+{
+ u_int type, exts = 0;
+ int version;
+ Buffer msg;
+ struct sftp_conn *ret;
+
+ buffer_init(&msg);
+ buffer_put_char(&msg, SSH2_FXP_INIT);
+ buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
+ send_msg(fd_out, &msg);
+
+ buffer_clear(&msg);
+
+ get_msg(fd_in, &msg);
+
+ /* Expecting a VERSION reply */
+ if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
+ error("Invalid packet back from SSH2_FXP_INIT (type %u)",
+ type);
+ buffer_free(&msg);
+ return(NULL);
+ }
+ version = buffer_get_int(&msg);
+
+ debug2("Remote version: %d", version);
+
+ /* Check for extensions */
+ while (buffer_len(&msg) > 0) {
+ char *name = buffer_get_string(&msg, NULL);
+ char *value = buffer_get_string(&msg, NULL);
+ int known = 0;
+
+ if (strcmp(name, "posix-rename@openssh.com") == 0 &&
+ strcmp(value, "1") == 0) {
+ exts |= SFTP_EXT_POSIX_RENAME;
+ known = 1;
+ } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
+ strcmp(value, "2") == 0) {
+ exts |= SFTP_EXT_STATVFS;
+ known = 1;
+ } if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
+ strcmp(value, "2") == 0) {
+ exts |= SFTP_EXT_FSTATVFS;
+ known = 1;
+ }
+ if (known) {
+ debug2("Server supports extension \"%s\" revision %s",
+ name, value);
+ } else {
+ debug2("Unrecognised server extension \"%s\"", name);
+ }
+ xfree(name);
+ xfree(value);
+ }
+
+ buffer_free(&msg);
+
+ 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->version = version;
+ ret->msg_id = 1;
+ ret->exts = exts;
+
+ /* Some filexfer v.0 servers don't support large packets */
+ if (version == 0)
+ ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
+
+ 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->fd_out, &msg);
+ debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
+
+ status = get_status(conn->fd_in, id);
+ if (status != SSH2_FX_OK)
+ error("Couldn't close file: %s", fx2txt(status));
+
+ buffer_free(&msg);
+
+ return(status);
+}
+
+
+static int
+do_lsreaddir(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->fd_out, &msg);
+
+ buffer_clear(&msg);
+
+ handle = get_handle(conn->fd_in, id, &handle_len);
+ 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->fd_out, &msg);
+
+ buffer_clear(&msg);
+
+ get_msg(conn->fd_in, &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);
+
+ 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;
+ }
+
+ 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->fd_out, id, SSH2_FXP_REMOVE, path,
+ strlen(path));
+ status = get_status(conn->fd_in, 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)
+{
+ u_int status, id;
+
+ id = conn->msg_id++;
+ send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
+ strlen(path), a);
+
+ status = get_status(conn->fd_in, id);
+ if (status != SSH2_FX_OK)
+ 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->fd_out, id, SSH2_FXP_RMDIR, path,
+ strlen(path));
+
+ status = get_status(conn->fd_in, 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->fd_out, id,
+ conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
+ path, strlen(path));
+
+ return(get_decode_stat(conn->fd_in, 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->fd_out, id, SSH2_FXP_LSTAT, path,
+ strlen(path));
+
+ return(get_decode_stat(conn->fd_in, 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->fd_out, id, SSH2_FXP_FSTAT, handle,
+ handle_len);
+
+ return(get_decode_stat(conn->fd_in, 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->fd_out, id, SSH2_FXP_SETSTAT, path,
+ strlen(path), a);
+
+ status = get_status(conn->fd_in, 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->fd_out, id, SSH2_FXP_FSETSTAT, handle,
+ handle_len, a);
+
+ status = get_status(conn->fd_in, 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->fd_out, id, SSH2_FXP_REALPATH, path,
+ strlen(path));
+
+ buffer_init(&msg);
+
+ get_msg(conn->fd_in, &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));
+ 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->fd_out, &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->fd_in, id);
+ if (status != SSH2_FX_OK)
+ error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
+ newpath, fx2txt(status));
+
+ return(status);
+}
+
+int
+do_symlink(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->fd_out, &msg);
+ debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
+ newpath);
+ buffer_free(&msg);
+
+ status = get_status(conn->fd_in, 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->fd_out, id, SSH2_FXP_READLINK, path,
+ strlen(path));
+
+ buffer_init(&msg);
+
+ get_msg(conn->fd_in, &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->fd_out, &msg);
+ buffer_free(&msg);
+
+ return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+
+#ifdef notyet
+int
+do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
+ struct sftp_statvfs *st, int quiet)
+{
+ Buffer msg;
+ u_int id;
+
+ if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
+ error("Server does not support fstatvfs@openssh.com extension");
+ return -1;
+ }
+
+ id = conn->msg_id++;
+
+ buffer_init(&msg);
+ buffer_clear(&msg);
+ buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+ buffer_put_int(&msg, id);
+ buffer_put_cstring(&msg, "fstatvfs@openssh.com");
+ buffer_put_string(&msg, handle, handle_len);
+ send_msg(conn->fd_out, &msg);
+ buffer_free(&msg);
+
+ return get_decode_statvfs(conn->fd_in, st, id, quiet);
+}
+#endif
+
+static void
+send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
+ char *handle, u_int handle_len)
+{
+ 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(fd_out, &msg);
+ buffer_free(&msg);
+}
+
+int
+do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
+ int pflag)
+{
+ Attrib junk, *a;
+ 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);
+
+ a = do_stat(conn, remote_path, 0);
+ if (a == 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->fd_out, &msg);
+ debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
+
+ handle = get_handle(conn->fd_in, id, &handle_len);
+ 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->fd_out, req->id, req->offset,
+ req->len, handle, handle_len);
+ }
+
+ buffer_clear(&msg);
+ get_msg(conn->fd_in, &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->fd_out, 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);
+}
+
+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->fd_out, &msg);
+ debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
+
+ buffer_clear(&msg);
+
+ handle = get_handle(conn->fd_in, id, &handle_len);
+ 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->fd_out, &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->fd_in, &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;
+}
diff --git a/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h
new file mode 100644
index 0000000..edb4679
--- /dev/null
+++ b/crypto/openssh/sftp-client.h
@@ -0,0 +1,114 @@
+/* $OpenBSD: sftp-client.h,v 1.17 2008/06/08 20:15:29 dtucker 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_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 *);
+
+/* 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 *);
+
+/* 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 *, int);
+
+/*
+ * Upload 'local_path' to 'remote_path'. Preserve permissions and times
+ * if 'pflag' is set
+ */
+int do_upload(struct sftp_conn *, char *, char *, int);
+
+#endif
diff --git a/crypto/openssh/sftp-common.c b/crypto/openssh/sftp-common.c
new file mode 100644
index 0000000..7ebadcc
--- /dev/null
+++ b/crypto/openssh/sftp-common.c
@@ -0,0 +1,223 @@
+/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt 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>
+
+#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 ulen, glen, sz = 0;
+ struct passwd *pw;
+ struct group *gr;
+ struct tm *ltime = localtime(&st->st_mtime);
+ char *user, *group;
+ char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
+
+ strmode(st->st_mode, mode);
+ if (!remote && (pw = getpwuid(st->st_uid)) != NULL) {
+ user = pw->pw_name;
+ } else {
+ snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
+ user = ubuf;
+ }
+ if (!remote && (gr = getgrgid(st->st_gid)) != NULL) {
+ group = gr->gr_name;
+ } 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);
+ 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/crypto/openssh/sftp-common.h b/crypto/openssh/sftp-common.h
new file mode 100644
index 0000000..9b58484
--- /dev/null
+++ b/crypto/openssh/sftp-common.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: sftp-common.h,v 1.10 2006/08/03 03:34:42 deraadt 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);
+
+const char *fx2txt(int);
diff --git a/crypto/openssh/sftp-glob.c b/crypto/openssh/sftp-glob.c
new file mode 100644
index 0000000..cdc2708
--- /dev/null
+++ b/crypto/openssh/sftp-glob.c
@@ -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/crypto/openssh/sftp-server-main.c b/crypto/openssh/sftp-server-main.c
new file mode 100644
index 0000000..7e644ab
--- /dev/null
+++ b/crypto/openssh/sftp-server-main.c
@@ -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/crypto/openssh/sftp-server.8 b/crypto/openssh/sftp-server.8
new file mode 100644
index 0000000..0201d4b
--- /dev/null
+++ b/crypto/openssh/sftp-server.8
@@ -0,0 +1,104 @@
+.\" $OpenBSD: sftp-server.8,v 1.15 2009/03/26 08:38:39 sobrado Exp $
+.\" $FreeBSD$
+.\"
+.\" 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 March 26 2009
+.Dt SFTP-SERVER 8
+.Os
+.Sh NAME
+.Nm sftp-server
+.Nd SFTP server subsystem
+.Sh SYNOPSIS
+.Nm sftp-server
+.Op Fl f Ar log_facility
+.Op Fl l Ar log_level
+.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 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 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.
+.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/crypto/openssh/sftp-server.c b/crypto/openssh/sftp-server.c
new file mode 100644
index 0000000..d984e60
--- /dev/null
+++ b/crypto/openssh/sftp-server.c
@@ -0,0 +1,1467 @@
+/* $OpenBSD: sftp-server.c,v 1.85 2009/04/14 16:33:42 stevesk 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;
+
+/* 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 */
+ 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);
+ 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 = SSH2_FX_FAILURE;
+ 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) {
+ 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");
+ }
+ }
+ }
+ 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 (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 {
+ 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);
+ 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);
+ 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);
+ 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);
+ 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 (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 */
+ 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;
+
+ oldpath = get_string(NULL);
+ newpath = get_string(NULL);
+ debug3("request %u: posix-rename", id);
+ logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath);
+ if (rename(oldpath, newpath) == -1)
+ send_status(id, errno_to_portable(errno));
+ else
+ send_status(id, SSH2_FX_OK);
+ 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(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
+ 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 [-he] [-l log_level] [-f log_facility]\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];
+
+ 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:che")) != -1) {
+ switch (ch) {
+ 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 '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 = dup(STDIN_FILENO);
+ out = dup(STDOUT_FILENO);
+
+#ifdef HAVE_CYGWIN
+ setmode(in, O_BINARY);
+ setmode(out, O_BINARY);
+#endif
+
+ max = 0;
+ if (in > max)
+ max = in;
+ if (out > max)
+ max = out;
+
+ buffer_init(&iqueue);
+ buffer_init(&oqueue);
+
+ set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask);
+ rset = (fd_set *)xmalloc(set_size);
+ wset = (fd_set *)xmalloc(set_size);
+
+ for (;;) {
+ memset(rset, 0, set_size);
+ memset(wset, 0, set_size);
+
+ /*
+ * 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/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1
new file mode 100644
index 0000000..ea56e50
--- /dev/null
+++ b/crypto/openssh/sftp.1
@@ -0,0 +1,472 @@
+.\" $OpenBSD: sftp.1,v 1.69 2008/12/09 15:35:00 sobrado Exp $
+.\" $FreeBSD$
+.\"
+.\" 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 December 9 2008
+.Dt SFTP 1
+.Os
+.Sh NAME
+.Nm sftp
+.Nd secure file transfer program
+.Sh SYNOPSIS
+.Nm sftp
+.Bk -words
+.Op Fl 1Cv
+.Op Fl B Ar buffer_size
+.Op Fl b Ar batchfile
+.Op Fl F Ar ssh_config
+.Op Fl o Ar ssh_option
+.Op Fl P Ar sftp_server_path
+.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 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 ,
+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 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 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 KbdInteractiveDevices
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It Port
+.It PreferredAuthentications
+.It Protocol
+.It ProxyCommand
+.It PubkeyAuthentication
+.It RekeyLimit
+.It RhostsRSAAuthentication
+.It RSAAuthentication
+.It SendEnv
+.It ServerAliveInterval
+.It ServerAliveCountMax
+.It SmartcardDevice
+.It StrictHostKeyChecking
+.It TCPKeepAlive
+.It UsePrivilegedPort
+.It User
+.It UserKnownHostsFile
+.It VerifyHostKeyDNS
+.El
+.It Fl P 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 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 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 P
+.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.
+If the
+.Fl P
+flag is specified, then full file permissions and access times are
+copied too.
+.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 Ic ln Ar oldpath Ar newpath
+Create a symbolic link from
+.Ar oldpath
+to
+.Ar newpath .
+.It Ic lpwd
+Print local working directory.
+.It Xo Ic ls
+.Op Fl 1aflnrSt
+.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 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 P
+.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.
+If the
+.Fl P
+flag is specified, then the file's full permission and access time are
+copied too.
+.It Ic pwd
+Display remote working directory.
+.It Ic quit
+Quit
+.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/crypto/openssh/sftp.c b/crypto/openssh/sftp.c
new file mode 100644
index 0000000..66bd111
--- /dev/null
+++ b/crypto/openssh/sftp.c
@@ -0,0 +1,1843 @@
+/* $OpenBSD: sftp.c,v 1.107 2009/02/02 11:15:14 dtucker 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 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"
+
+/* File to read commands from */
+FILE* infile;
+
+/* Are we in batchfile mode? */
+int batchmode = 0;
+
+/* Size of buffer used when copying files */
+size_t copy_buffer_len = 32768;
+
+/* Number of concurrent outstanding requests */
+size_t num_requests = 64;
+
+/* PID of ssh transport process */
+static pid_t sshpid = -1;
+
+/* This is set to 0 if the progressmeter is not desired. */
+int showprogress = 1;
+
+/* 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;
+
+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 0x01 /* Full view ala ls -l */
+#define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */
+#define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */
+#define LS_NAME_SORT 0x08 /* Sort by name (default) */
+#define LS_TIME_SORT 0x10 /* Sort by mtime */
+#define LS_SIZE_SORT 0x20 /* Sort by file size */
+#define LS_REVERSE_SORT 0x40 /* Reverse sort order */
+#define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */
+
+#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW)
+#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_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;
+};
+
+static const struct CMD cmds[] = {
+ { "bye", I_QUIT },
+ { "cd", I_CHDIR },
+ { "chdir", I_CHDIR },
+ { "chgrp", I_CHGRP },
+ { "chmod", I_CHMOD },
+ { "chown", I_CHOWN },
+ { "df", I_DF },
+ { "dir", I_LS },
+ { "exit", I_QUIT },
+ { "get", I_GET },
+ { "mget", I_GET },
+ { "help", I_HELP },
+ { "lcd", I_LCHDIR },
+ { "lchdir", I_LCHDIR },
+ { "lls", I_LLS },
+ { "lmkdir", I_LMKDIR },
+ { "ln", I_SYMLINK },
+ { "lpwd", I_LPWD },
+ { "ls", I_LS },
+ { "lumask", I_LUMASK },
+ { "mkdir", I_MKDIR },
+ { "progress", I_PROGRESS },
+ { "put", I_PUT },
+ { "mput", I_PUT },
+ { "pwd", I_PWD },
+ { "quit", I_QUIT },
+ { "rename", I_RENAME },
+ { "rm", I_RM },
+ { "rmdir", I_RMDIR },
+ { "symlink", I_SYMLINK },
+ { "version", I_VERSION },
+ { "!", I_SHELL },
+ { "?", I_HELP },
+ { NULL, -1}
+};
+
+int interactive_loop(int fd_in, int fd_out, 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 [-P] remote-path [local-path] 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 oldpath newpath Symlink remote file\n"
+ "lpwd Print local working directory\n"
+ "ls [-1aflnrSt] [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 [-P] local-path [remote-path] 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 = _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 *
+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);
+}
+
+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
+infer_path(const char *p, char **ifp)
+{
+ char *cp;
+
+ cp = strrchr(p, '/');
+ if (cp == NULL) {
+ *ifp = xstrdup(p);
+ return(0);
+ }
+
+ if (!cp[1]) {
+ error("Invalid path");
+ return(-1);
+ }
+
+ *ifp = xstrdup(cp + 1);
+ return(0);
+}
+
+static int
+parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
+{
+ extern int opterr, optind, optopt, optreset;
+ int ch;
+
+ optind = optreset = 1;
+ opterr = 0;
+
+ *pflag = 0;
+ while ((ch = getopt(argc, argv, "Pp")) != -1) {
+ switch (ch) {
+ case 'p':
+ case 'P':
+ *pflag = 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, "1Saflnrt")) != -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 'l':
+ *lflag &= ~VIEW_FLAGS;
+ *lflag |= LS_LONG_VIEW;
+ break;
+ case 'n':
+ *lflag &= ~VIEW_FLAGS;
+ *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));
+}
+
+static int
+process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
+{
+ char *abs_src = NULL;
+ char *abs_dst = NULL;
+ char *tmp;
+ glob_t g;
+ int err = 0;
+ int i;
+
+ abs_src = xstrdup(src);
+ abs_src = make_absolute(abs_src, pwd);
+
+ memset(&g, 0, sizeof(g));
+ debug3("Looking up %s", abs_src);
+ if (remote_glob(conn, abs_src, 0, NULL, &g)) {
+ error("File \"%s\" not found.", abs_src);
+ err = -1;
+ goto out;
+ }
+
+ /* If multiple matches, dst must be a directory or unspecified */
+ if (g.gl_matchc > 1 && dst && !is_dir(dst)) {
+ error("Multiple files match, but \"%s\" is not a directory",
+ dst);
+ err = -1;
+ goto out;
+ }
+
+ for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+ if (infer_path(g.gl_pathv[i], &tmp)) {
+ err = -1;
+ goto out;
+ }
+
+ if (g.gl_matchc == 1 && dst) {
+ /* If directory specified, append filename */
+ xfree(tmp);
+ if (is_dir(dst)) {
+ if (infer_path(g.gl_pathv[0], &tmp)) {
+ err = 1;
+ goto out;
+ }
+ abs_dst = path_append(dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = xstrdup(dst);
+ } else if (dst) {
+ abs_dst = path_append(dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = tmp;
+
+ printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
+ if (do_download(conn, g.gl_pathv[i], abs_dst, 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)
+{
+ char *tmp_dst = NULL;
+ char *abs_dst = NULL;
+ char *tmp;
+ glob_t g;
+ int err = 0;
+ int i;
+ 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, NULL, &g)) {
+ error("File \"%s\" not found.", src);
+ err = -1;
+ goto out;
+ }
+
+ /* If multiple matches, dst may be directory or unspecified */
+ if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) {
+ error("Multiple files match, but \"%s\" is not a directory",
+ tmp_dst);
+ err = -1;
+ goto out;
+ }
+
+ for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
+ if (stat(g.gl_pathv[i], &sb) == -1) {
+ err = -1;
+ error("stat %s: %s", g.gl_pathv[i], strerror(errno));
+ continue;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ error("skipping non-regular file %s",
+ g.gl_pathv[i]);
+ continue;
+ }
+ if (infer_path(g.gl_pathv[i], &tmp)) {
+ err = -1;
+ goto out;
+ }
+
+ if (g.gl_matchc == 1 && tmp_dst) {
+ /* If directory specified, append filename */
+ if (remote_is_dir(conn, tmp_dst)) {
+ if (infer_path(g.gl_pathv[0], &tmp)) {
+ err = 1;
+ goto out;
+ }
+ abs_dst = path_append(tmp_dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = xstrdup(tmp_dst);
+
+ } else if (tmp_dst) {
+ abs_dst = path_append(tmp_dst, tmp);
+ xfree(tmp);
+ } else
+ abs_dst = make_absolute(tmp, pwd);
+
+ printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
+ if (do_upload(conn, g.gl_pathv[i], abs_dst, 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) {
+ char *lname;
+ struct stat sb;
+
+ memset(&sb, 0, sizeof(sb));
+ attrib_to_stat(&d[n]->a, &sb);
+ lname = ls_file(fname, &sb, 1);
+ 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)
+{
+ glob_t g;
+ u_int i, c = 1, colspace = 0, columns = 1;
+ Attrib *a = NULL;
+
+ memset(&g, 0, sizeof(g));
+
+ if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
+ 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) {
+ if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) {
+ globfree(&g);
+ return (-1);
+ }
+ if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+ S_ISDIR(a->perm)) {
+ int err;
+
+ err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
+ globfree(&g);
+ return (err);
+ }
+ }
+
+ if (!(lflag & LS_SHORT_VIEW)) {
+ u_int m = 0, width = 80;
+ struct winsize ws;
+
+ /* Count entries for sort and find longest filename */
+ for (i = 0; g.gl_pathv[i]; i++)
+ m = MAX(m, strlen(g.gl_pathv[i]));
+
+ if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+ width = ws.ws_col;
+
+ columns = width / (m + 2);
+ columns = MAX(columns, 1);
+ colspace = width / columns;
+ }
+
+ for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
+ char *fname;
+
+ fname = path_strip(g.gl_pathv[i], strip_path);
+
+ if (lflag & LS_LONG_VIEW) {
+ char *lname;
+ struct stat sb;
+
+ /*
+ * XXX: this is slow - 1 roundtrip per path
+ * A solution to this is to fork glob() and
+ * build a sftp specific version which keeps the
+ * attribs (which currently get thrown away)
+ * that the server returns as well as the filenames.
+ */
+ memset(&sb, 0, sizeof(sb));
+ if (a == NULL)
+ a = do_lstat(conn, g.gl_pathv[i], 1);
+ if (a != NULL)
+ attrib_to_stat(a, &sb);
+ lname = ls_file(fname, &sb, 1);
+ 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];
+
+ if (do_statvfs(conn, path, &st, 1) == -1)
+ return -1;
+ if (iflag) {
+ printf(" Inodes Used Avail "
+ "(root) %%Capacity\n");
+ printf("%11llu %11llu %11llu %11llu %3llu%%\n",
+ (unsigned long long)st.f_files,
+ (unsigned long long)(st.f_files - st.f_ffree),
+ (unsigned long long)st.f_favail,
+ (unsigned long long)st.f_ffree,
+ (unsigned long long)(100 * (st.f_files - st.f_ffree) /
+ st.f_files));
+ } else if (hflag) {
+ strlcpy(s_used, "error", sizeof(s_used));
+ strlcpy(s_avail, "error", sizeof(s_avail));
+ strlcpy(s_root, "error", sizeof(s_root));
+ strlcpy(s_total, "error", sizeof(s_total));
+ fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
+ fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
+ fmt_scaled(st.f_bfree * st.f_frsize, s_root);
+ fmt_scaled(st.f_blocks * st.f_frsize, s_total);
+ printf(" Size Used Avail (root) %%Capacity\n");
+ printf("%7sB %7sB %7sB %7sB %3llu%%\n",
+ s_total, s_used, s_avail, s_root,
+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+ st.f_blocks));
+ } else {
+ printf(" Size Used Avail "
+ "(root) %%Capacity\n");
+ printf("%12llu %12llu %12llu %12llu %3llu%%\n",
+ (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
+ (unsigned long long)(st.f_frsize *
+ (st.f_blocks - st.f_bfree) / 1024),
+ (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
+ (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
+ st.f_blocks));
+ }
+ return 0;
+}
+
+/*
+ * Undo escaping of glob sequences in place. Used to undo extra escaping
+ * applied in makeargv() when the string is destined for a function that
+ * 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.
+ * Returns NULL on error or a NULL-terminated array of arguments.
+ */
+#define MAXARGS 128
+#define MAXARGLEN 8192
+static char **
+makeargv(const char *arg, int *argcp)
+{
+ 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;
+ }
+ 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;
+ } 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 (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) {
+ 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 ((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 *lflag, int *iflag, int *hflag,
+ 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);
+
+ /* Ignore blank lines and lines which begin with comment '#' char */
+ if (*cp == '\0' || *cp == '#')
+ return (0);
+
+ /* Check for leading '-' (disable error processing) */
+ *iflag = 0;
+ if (*cp == '-') {
+ *iflag = 1;
+ cp++;
+ }
+
+ if ((argv = makeargv(cp, &argc)) == 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 = *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)) == -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_RENAME:
+ case I_SYMLINK:
+ 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, lflag = 0, iflag = 0, hflag = 0, 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, &lflag, &iflag, &hflag, &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);
+ break;
+ case I_PUT:
+ err = process_put(conn, path1, path2, *pwd, pflag);
+ break;
+ case I_RENAME:
+ path1 = make_absolute(path1, *pwd);
+ path2 = make_absolute(path2, *pwd);
+ err = do_rename(conn, path1, path2);
+ break;
+ case I_SYMLINK:
+ path2 = make_absolute(path2, *pwd);
+ err = do_symlink(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);
+ 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_globbed_ls(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> ");
+}
+#endif
+
+int
+interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
+{
+ char *pwd;
+ char *dir = NULL;
+ char cmd[2048];
+ struct sftp_conn *conn;
+ int err, interactive;
+ EditLine *el = NULL;
+#ifdef USE_LIBEDIT
+ History *hl = NULL;
+ HistEvent hev;
+ extern char *__progname;
+
+ 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);
+ }
+#endif /* USE_LIBEDIT */
+
+ conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);
+ if (conn == NULL)
+ fatal("Couldn't initialise connection to server");
+
+ pwd = do_realpath(conn, ".");
+ if (pwd == NULL)
+ fatal("Need cwd");
+
+ if (file1 != NULL) {
+ dir = xstrdup(file1);
+ dir = make_absolute(dir, pwd);
+
+ 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, &pwd, 1) != 0) {
+ xfree(dir);
+ xfree(pwd);
+ 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, &pwd, 1);
+ xfree(dir);
+ xfree(pwd);
+ 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, &pwd, batchmode);
+ if (err != 0)
+ break;
+ }
+ xfree(pwd);
+ 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
+ */
+ signal(SIGINT, SIG_IGN);
+ 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 [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n"
+ " [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n"
+ " [-S program] [-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, *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;
+ LogLevel ll = SYSLOG_LEVEL_INFO;
+ arglist args;
+ 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]);
+ 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, "1hvCo:s:S:b:B:F:P:R:")) != -1) {
+ switch (ch) {
+ case 'C':
+ addargs(&args, "-C");
+ break;
+ case 'v':
+ if (debug_level < 3) {
+ addargs(&args, "-v");
+ ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
+ }
+ debug_level++;
+ break;
+ case 'F':
+ case 'o':
+ addargs(&args, "-%c%s", ch, optarg);
+ break;
+ case '1':
+ sshver = 1;
+ if (sftp_server == NULL)
+ sftp_server = _PATH_SFTP_SERVER;
+ break;
+ case 's':
+ sftp_server = optarg;
+ break;
+ case 'S':
+ ssh_program = optarg;
+ replacearg(&args, 0, "%s", ssh_program);
+ 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':
+ sftp_direct = optarg;
+ 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 'R':
+ num_requests = strtol(optarg, &cp, 10);
+ if (num_requests == 0 || *cp != '\0')
+ fatal("Invalid number of requests \"%s\"",
+ optarg);
+ 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%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, "%s", host);
+ addargs(&args, "%s", (sftp_server != NULL ?
+ sftp_server : "sftp"));
+
+ if (!batchmode)
+ fprintf(stderr, "Connecting to %s...\n", host);
+ connect_to_server(ssh_program, args.list, &in, &out);
+ } else {
+ args.list = NULL;
+ addargs(&args, "sftp-server");
+
+ if (!batchmode)
+ fprintf(stderr, "Attaching to %s...\n", sftp_direct);
+ connect_to_server(sftp_direct, args.list, &in, &out);
+ }
+ freeargs(&args);
+
+ err = interactive_loop(in, out, 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/crypto/openssh/sftp.h b/crypto/openssh/sftp.h
new file mode 100644
index 0000000..2bde8bb
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/ssh-add.1 b/crypto/openssh/ssh-add.1
new file mode 100644
index 0000000..464070e
--- /dev/null
+++ b/crypto/openssh/ssh-add.1
@@ -0,0 +1,186 @@
+.\" $OpenBSD: ssh-add.1,v 1.46 2007/06/12 13:41:03 jmc Exp $
+.\"
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd June 12 2007
+.Dt SSH-ADD 1
+.Os
+.Sh NAME
+.Nm ssh-add
+.Nd adds RSA or DSA identities to the authentication agent
+.Sh SYNOPSIS
+.Nm ssh-add
+.Op Fl cDdLlXx
+.Op Fl t Ar life
+.Op Ar
+.Nm ssh-add
+.Fl s Ar reader
+.Nm ssh-add
+.Fl e Ar reader
+.Sh DESCRIPTION
+.Nm
+adds RSA or DSA identities to the authentication agent,
+.Xr ssh-agent 1 .
+When run without arguments, it adds the files
+.Pa ~/.ssh/id_rsa ,
+.Pa ~/.ssh/id_dsa
+and
+.Pa ~/.ssh/identity .
+Alternative file names can be given on the command line.
+If any file requires a passphrase,
+.Nm
+asks for the passphrase from the user.
+The passphrase is read from the user's tty.
+.Nm
+retries the last passphrase if multiple identity files are given.
+.Pp
+The authentication agent must be running and 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 reader
+Remove key in smartcard
+.Ar reader .
+.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 reader
+Add key in smartcard
+.Ar reader .
+.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 unix-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_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 DIAGNOSTICS
+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/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c
new file mode 100644
index 0000000..7a43282
--- /dev/null
+++ b/crypto/openssh/ssh-add.c
@@ -0,0 +1,439 @@
+/* $OpenBSD: ssh-add.c,v 1.90 2007/09/09 11:38:01 sobrado 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,
+ _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;
+ char *comment = NULL;
+ char msg[1024];
+ 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 has to confirm each use of the key\n");
+ } else if (ssh_add_identity(ac, private, comment)) {
+ fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
+ ret = 0;
+ } else {
+ fprintf(stderr, "Could not add identity: %s\n", filename);
+ }
+
+ xfree(comment);
+ key_free(private);
+
+ return ret;
+}
+
+static int
+update_card(AuthenticationConnection *ac, int add, const char *id)
+{
+ char *pin;
+ int ret = -1;
+
+ pin = read_passphrase("Enter passphrase for smartcard: ", 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");
+#ifdef SMARTCARD
+ fprintf(stderr, " -s reader Add key in smartcard reader.\n");
+ fprintf(stderr, " -e reader Remove key in smartcard reader.\n");
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ AuthenticationConnection *ac = NULL;
+ char *sc_reader_id = 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();
+
+ SSLeay_add_all_algorithms();
+
+ /* At first, get a connection to the authentication agent. */
+ ac = ssh_get_authentication_connection();
+ if (ac == NULL) {
+ fprintf(stderr,
+ "Could not open a connection to your authentication agent.\n");
+ exit(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':
+ sc_reader_id = optarg;
+ break;
+ case 'e':
+ deleting = 1;
+ sc_reader_id = 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 (sc_reader_id != NULL) {
+ if (update_card(ac, !deleting, sc_reader_id) == -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/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1
new file mode 100644
index 0000000..bc38900
--- /dev/null
+++ b/crypto/openssh/ssh-agent.1
@@ -0,0 +1,208 @@
+.\" $OpenBSD: ssh-agent.1,v 1.47 2009/03/26 08:38:39 sobrado Exp $
+.\" $FreeBSD$
+.\"
+.\" 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 March 26 2009
+.Dt SSH-AGENT 1
+.Os
+.Sh NAME
+.Nm ssh-agent
+.Nd authentication agent
+.Sh SYNOPSIS
+.Nm ssh-agent
+.Op Fl c Li | Fl s
+.Op Fl d
+.Op Fl a Ar bind_address
+.Op Fl t Ar life
+.Op Ar command Op Ar arg ...
+.Nm ssh-agent
+.Op Fl c Li | Fl s
+.Fl k
+.Sh DESCRIPTION
+.Nm
+is a program to hold private keys used for public key authentication
+(RSA, DSA).
+The idea is that
+.Nm
+is started in the beginning of an X-session or a login session, and
+all other windows or programs are started as clients to the ssh-agent
+program.
+Through use of environment variables the agent can be located
+and automatically used for authentication when logging in to other
+machines using
+.Xr ssh 1 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a Ar bind_address
+Bind the agent to the unix-domain socket
+.Ar bind_address .
+The default is
+.Pa /tmp/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
+and
+.Pa ~/.ssh/identity .
+If the identity has a passphrase,
+.Xr ssh-add 1
+asks for the passphrase (using a small X11 application if running
+under X11, or from the terminal if running without X).
+It then sends the identity to the agent.
+Several identities can be stored in the
+agent; the agent can automatically use any of these identities.
+.Ic ssh-add -l
+displays the identities currently held by the agent.
+.Pp
+The idea is that the agent is run in the user's local PC, laptop, or
+terminal.
+Authentication data need not be stored on any other
+machine, and authentication passphrases never go over the network.
+However, the connection to the agent is forwarded over SSH
+remote logins, and the user can thus use the privileges given by the
+identities anywhere in the network in a secure way.
+.Pp
+There are two main ways to get an agent 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 unix-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_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+.It Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt
+Unix-domain sockets used to contain the connection to the
+authentication agent.
+These sockets should only be readable by the owner.
+The sockets should get automatically removed when the agent exits.
+.El
+.Sh 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/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c
new file mode 100644
index 0000000..1fdf529
--- /dev/null
+++ b/crypto/openssh/ssh-agent.c
@@ -0,0 +1,1292 @@
+/* $OpenBSD: ssh-agent.c,v 1.161 2009/03/23 19:38:04 tobias Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * All rights reserved
+ * The authentication agent program.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose. Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ *
+ * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+__RCSID("$FreeBSD$");
+
+#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 SMARTCARD
+#include "scard.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;
+ 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);
+ 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;
+
+ 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);
+ xfree(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_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;
+ default:
+ buffer_clear(&e->request);
+ goto send;
+ }
+ break;
+ }
+ /* enable blinding */
+ switch (k->type) {
+ case KEY_RSA:
+ 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 = xmalloc(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 SMARTCARD
+static void
+process_add_smartcard_key(SocketEntry *e)
+{
+ char *sc_reader_id = NULL, *pin;
+ int i, type, version, success = 0, death = 0, confirm = 0;
+ Key **keys, *k;
+ Identity *id;
+ Idtab *tab;
+
+ sc_reader_id = 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);
+ xfree(sc_reader_id);
+ xfree(pin);
+ goto send;
+ }
+ }
+ if (lifetime && !death)
+ death = time(NULL) + lifetime;
+
+ keys = sc_get_keys(sc_reader_id, pin);
+ xfree(sc_reader_id);
+ xfree(pin);
+
+ if (keys == NULL || keys[0] == NULL) {
+ error("sc_get_keys failed");
+ goto send;
+ }
+ for (i = 0; keys[i] != NULL; i++) {
+ k = keys[i];
+ version = k->type == KEY_RSA1 ? 1 : 2;
+ tab = idtab_lookup(version);
+ if (lookup_identity(k, version) == NULL) {
+ id = xmalloc(sizeof(Identity));
+ id->key = k;
+ id->comment = sc_get_key_label(k);
+ id->death = death;
+ id->confirm = confirm;
+ TAILQ_INSERT_TAIL(&tab->idlist, id, next);
+ tab->nentries++;
+ success = 1;
+ } else {
+ key_free(k);
+ }
+ keys[i] = NULL;
+ }
+ xfree(keys);
+send:
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+
+static void
+process_remove_smartcard_key(SocketEntry *e)
+{
+ char *sc_reader_id = NULL, *pin;
+ int i, version, success = 0;
+ Key **keys, *k = NULL;
+ Identity *id;
+ Idtab *tab;
+
+ sc_reader_id = buffer_get_string(&e->request, NULL);
+ pin = buffer_get_string(&e->request, NULL);
+ keys = sc_get_keys(sc_reader_id, pin);
+ xfree(sc_reader_id);
+ xfree(pin);
+
+ if (keys == NULL || keys[0] == NULL) {
+ error("sc_get_keys failed");
+ goto send;
+ }
+ for (i = 0; keys[i] != NULL; i++) {
+ k = keys[i];
+ version = k->type == KEY_RSA1 ? 1 : 2;
+ if ((id = lookup_identity(k, version)) != NULL) {
+ tab = idtab_lookup(version);
+ TAILQ_REMOVE(&tab->idlist, id, next);
+ tab->nentries--;
+ free_identity(id);
+ success = 1;
+ }
+ key_free(k);
+ keys[i] = NULL;
+ }
+ xfree(keys);
+send:
+ buffer_put_int(&e->output, 1);
+ buffer_put_char(&e->output,
+ success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
+}
+#endif /* SMARTCARD */
+
+/* dispatch incoming messages */
+
+static void
+process_message(SocketEntry *e)
+{
+ u_int msg_len, 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 SMARTCARD
+ 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 /* SMARTCARD */
+ 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;
+ uid_t euid;
+ gid_t egid;
+
+ for (i = 0; i < sockets_alloc; i++)
+ switch (sockets[i].type) {
+ case AUTH_UNUSED:
+ break;
+ case AUTH_SOCKET:
+ if (FD_ISSET(sockets[i].fd, readset)) {
+ slen = sizeof(sunaddr);
+ sock = accept(sockets[i].fd,
+ (struct sockaddr *)&sunaddr, &slen);
+ if (sock < 0) {
+ 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)) {
+ do {
+ len = write(sockets[i].fd,
+ buffer_ptr(&sockets[i].output),
+ buffer_len(&sockets[i].output));
+ if (len == -1 && (errno == EAGAIN ||
+ errno == EINTR ||
+ errno == EWOULDBLOCK))
+ continue;
+ break;
+ } while (1);
+ if (len <= 0) {
+ close_socket(&sockets[i]);
+ break;
+ }
+ buffer_consume(&sockets[i].output, len);
+ }
+ if (FD_ISSET(sockets[i].fd, readset)) {
+ do {
+ len = read(sockets[i].fd, buf, sizeof(buf));
+ if (len == -1 && (errno == EAGAIN ||
+ errno == EINTR ||
+ errno == EWOULDBLOCK))
+ continue;
+ break;
+ } while (1);
+ 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();
+ _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());
+ setuid(geteuid());
+
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+ /* Disable ptrace on Linux without sgid bit */
+ prctl(PR_SET_DUMPABLE, 0);
+#endif
+
+ SSLeay_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 */
+ strlcpy(socket_dir, "/tmp/ssh-XXXXXXXXXX", 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:
+ 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/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c
new file mode 100644
index 0000000..51a06e9
--- /dev/null
+++ b/crypto/openssh/ssh-dss.c
@@ -0,0 +1,185 @@
+/* $OpenBSD: ssh-dss.c,v 1.24 2006/11/06 21:25:28 markus Exp $ */
+/*
+ * Copyright (c) 2000 Markus Friedl. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#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->type != KEY_DSA || key->dsa == NULL) {
+ 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->type != KEY_DSA || key->dsa == NULL) {
+ 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_string(&b, NULL);
+ if (strcmp("ssh-dss", ktype) != 0) {
+ error("ssh_dss_verify: cannot handle type %s", ktype);
+ buffer_free(&b);
+ xfree(ktype);
+ return -1;
+ }
+ xfree(ktype);
+ sigblob = buffer_get_string(&b, &len);
+ rlen = buffer_len(&b);
+ buffer_free(&b);
+ if (rlen != 0) {
+ error("ssh_dss_verify: "
+ "remaining bytes in signature %d", rlen);
+ xfree(sigblob);
+ return -1;
+ }
+ }
+
+ if (len != SIGBLOB_LEN) {
+ fatal("bad sigbloblen %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/crypto/openssh/ssh-gss.h b/crypto/openssh/ssh-gss.h
new file mode 100644
index 0000000..c29a1b7
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1
new file mode 100644
index 0000000..4247ea1
--- /dev/null
+++ b/crypto/openssh/ssh-keygen.1
@@ -0,0 +1,470 @@
+.\" $OpenBSD: ssh-keygen.1,v 1.79 2008/07/24 23:55:30 sthen Exp $
+.\" $FreeBSD$
+.\"
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd July 24 2008
+.Dt SSH-KEYGEN 1
+.Os
+.Sh NAME
+.Nm ssh-keygen
+.Nd authentication key generation, management and conversion
+.Sh SYNOPSIS
+.Nm ssh-keygen
+.Bk -words
+.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
+.Ek
+.Nm ssh-keygen
+.Fl p
+.Op Fl P Ar old_passphrase
+.Op Fl N Ar new_passphrase
+.Op Fl f Ar keyfile
+.Nm ssh-keygen
+.Fl i
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl e
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl y
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl c
+.Op Fl P Ar passphrase
+.Op Fl C Ar comment
+.Op Fl f Ar keyfile
+.Nm ssh-keygen
+.Fl l
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl B
+.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl D Ar reader
+.Nm ssh-keygen
+.Fl 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 U Ar reader
+.Op Fl f Ar input_keyfile
+.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
+.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 RSA or DSA
+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 RSA or DSA authentication runs this once to create the authentication
+key in
+.Pa ~/.ssh/identity ,
+.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 reader
+Download the RSA public key stored in the smartcard in
+.Ar reader .
+.It Fl e
+This option will read a private or public OpenSSH key file and
+print the key in
+RFC 4716 SSH Public Key File Format
+to stdout.
+This option allows exporting keys for use by 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 i
+This option will read an unencrypted private (or public) key file
+in SSH2-compatible format and print an OpenSSH compatible private
+(or public) key to stdout.
+.Nm
+also reads the
+RFC 4716 SSH Public Key File Format.
+This option allows importing keys from several commercial
+SSH implementations.
+.It Fl l
+Show fingerprint of specified public key file.
+Private RSA1 keys are also supported.
+For RSA and DSA keys
+.Nm
+tries to find the matching public key file and prints its fingerprint.
+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 N Ar new_passphrase
+Provides the new passphrase.
+.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 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 rsa
+or
+.Dq dsa
+for protocol version 2.
+.It Fl U Ar reader
+Upload an existing RSA private key into the smartcard in
+.Ar reader .
+.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.
+.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 FILES
+.Bl -tag -width Ds
+.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.
+.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.
+.It Pa ~/.ssh/id_dsa
+Contains the protocol version 2 DSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file using 3DES.
+This file is not automatically accessed by
+.Nm
+but it is offered as the default file for the private key.
+.Xr ssh 1
+will read this file when a login attempt is made.
+.It Pa ~/.ssh/id_dsa.pub
+Contains the protocol version 2 DSA 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.
+.It Pa ~/.ssh/id_rsa
+Contains the protocol version 2 RSA authentication identity of the user.
+This file should not be readable by anyone but the user.
+It is possible to
+specify a passphrase when generating the key; that passphrase will be
+used to encrypt the private part of this file using 3DES.
+This file is not automatically accessed by
+.Nm
+but it is offered as the default file for the private key.
+.Xr ssh 1
+will read this file when a login attempt is made.
+.It Pa ~/.ssh/id_rsa.pub
+Contains the protocol version 2 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.
+.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/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c
new file mode 100644
index 0000000..da5db98
--- /dev/null
+++ b/crypto/openssh/ssh-keygen.c
@@ -0,0 +1,1483 @@
+/* $OpenBSD: ssh-keygen.c,v 1.174 2009/06/22 05:39:28 dtucker 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"
+
+#ifdef SMARTCARD
+#include "scard.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
+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 just want to see the key fingerprint */
+int print_fingerprint = 0;
+int print_bubblebabble = 0;
+
+/* The identity file name, given on the command line or entered by the user. */
+char identity_file[1024];
+int have_identity = 0;
+
+/* This is set to the passphrase if given on the command line. */
+char *identity_passphrase = NULL;
+
+/* This is set to the new passphrase if given on the command line. */
+char *identity_new_passphrase = NULL;
+
+/* This is set to the new comment if given on the command line. */
+char *identity_comment = NULL;
+
+/* Dump public key file in format used by real and the original SSH 2 */
+int convert_to_ssh2 = 0;
+int convert_from_ssh2 = 0;
+int print_public = 0;
+int print_generic = 0;
+
+char *key_type_name = 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:
+ name = _PATH_SSH_CLIENT_ID_DSA;
+ break;
+ 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;
+ struct stat st;
+
+ if (!have_identity)
+ ask_filename(pw, "Enter file in which the key is");
+ if (stat(identity_file, &st) < 0) {
+ perror(identity_file);
+ exit(1);
+ }
+ if ((k = key_load_public(identity_file, NULL)) == NULL) {
+ if ((k = load_identity(identity_file)) == NULL) {
+ fprintf(stderr, "load failed\n");
+ exit(1);
+ }
+ }
+ if (k->type == KEY_RSA1) {
+ fprintf(stderr, "version 1 keys are not supported\n");
+ exit(1);
+ }
+ if (key_to_blob(k, &blob, &len) <= 0) {
+ fprintf(stderr, "key_to_blob failed\n");
+ exit(1);
+ }
+ fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
+ fprintf(stdout,
+ "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
+ key_size(k), key_type(k),
+ pw->pw_name, hostname);
+ dump_base64(stdout, blob, len);
+ fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
+ key_free(k);
+ xfree(blob);
+ exit(0);
+}
+
+static void
+buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
+{
+ 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 blen;
+ u_int len;
+ char line[1024];
+ u_char blob[8096];
+ char encoded[8096];
+ struct stat st;
+ int escaped = 0, private = 0, ok;
+ FILE *fp;
+
+ if (!have_identity)
+ ask_filename(pw, "Enter file in which the key is");
+ if (stat(identity_file, &st) < 0) {
+ perror(identity_file);
+ exit(1);
+ }
+ fp = fopen(identity_file, "r");
+ if (fp == NULL) {
+ perror(identity_file);
+ exit(1);
+ }
+ encoded[0] = '\0';
+ while ((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);
+ }
+ ok = private ?
+ (k->type == KEY_DSA ?
+ PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
+ PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
+ key_write(k, stdout);
+ if (!ok) {
+ fprintf(stderr, "key write failed\n");
+ exit(1);
+ }
+ key_free(k);
+ if (!private)
+ fprintf(stdout, "\n");
+ fclose(fp);
+ exit(0);
+}
+
+static void
+do_print_public(struct passwd *pw)
+{
+ Key *prv;
+ struct stat st;
+
+ if (!have_identity)
+ ask_filename(pw, "Enter file in which the key is");
+ if (stat(identity_file, &st) < 0) {
+ perror(identity_file);
+ exit(1);
+ }
+ prv = load_identity(identity_file);
+ if (prv == NULL) {
+ fprintf(stderr, "load failed\n");
+ exit(1);
+ }
+ if (!key_write(prv, stdout))
+ fprintf(stderr, "key_write failed");
+ key_free(prv);
+ fprintf(stdout, "\n");
+ exit(0);
+}
+
+#ifdef SMARTCARD
+static void
+do_upload(struct passwd *pw, const char *sc_reader_id)
+{
+ Key *prv = NULL;
+ struct stat st;
+ int ret;
+
+ 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) {
+ error("load failed");
+ exit(1);
+ }
+ ret = sc_put_key(prv, sc_reader_id);
+ key_free(prv);
+ if (ret < 0)
+ exit(1);
+ logit("loading key done");
+ exit(0);
+}
+
+static void
+do_download(struct passwd *pw, const char *sc_reader_id)
+{
+ Key **keys = NULL;
+ int i;
+
+ keys = sc_get_keys(sc_reader_id, NULL);
+ if (keys == NULL)
+ fatal("cannot read public key from smartcard");
+ for (i = 0; keys[i]; i++) {
+ key_write(keys[i], stdout);
+ key_free(keys[i]);
+ fprintf(stdout, "\n");
+ }
+ xfree(keys);
+ exit(0);
+}
+#endif /* SMARTCARD */
+
+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, fptype, SSH_FP_RANDOMART);
+ printf("%u %s %s (%s)\n", key_size(public), fp, comment,
+ key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+ key_free(public);
+ xfree(comment);
+ xfree(ra);
+ xfree(fp);
+ exit(0);
+ }
+ if (comment) {
+ xfree(comment);
+ comment = NULL;
+ }
+
+ f = fopen(identity_file, "r");
+ if (f != NULL) {
+ 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, fptype, SSH_FP_RANDOMART);
+ printf("%u %s %s (%s)\n", key_size(public), fp,
+ comment ? comment : "no comment", key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+ xfree(ra);
+ xfree(fp);
+ key_free(public);
+ invalid = 0;
+ }
+ fclose(f);
+ }
+ if (invalid) {
+ printf("%s is not a public key file.\n", identity_file);
+ exit(1);
+ }
+ exit(0);
+}
+
+static void
+print_host(FILE *f, const char *name, Key *public, 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, fptype, SSH_FP_RANDOMART);
+ printf("%u %s %s (%s)\n", key_size(public), fp, name,
+ key_type(public));
+ if (log_level >= SYSLOG_LEVEL_VERBOSE)
+ printf("%s\n", ra);
+ xfree(ra);
+ xfree(fp);
+ } else {
+ if (hash && (name = host_hash(name, NULL, 0)) == NULL)
+ fatal("hash_host failed");
+ fprintf(f, "%s ", name);
+ if (!key_write(public, f))
+ fatal("key_write failed");
+ fprintf(f, "\n");
+ }
+}
+
+static void
+do_known_hosts(struct passwd *pw, const char *name)
+{
+ FILE *in, *out = stdout;
+ Key *public;
+ 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;
+
+ 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("fopen: %s", 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;
+ }
+ /* 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;
+
+ public = key_new(KEY_RSA1);
+ if (key_read(public, &kp) != 1) {
+ kp = kp2;
+ key_free(public);
+ public = key_new(KEY_UNSPEC);
+ if (key_read(public, &kp) != 1) {
+ error("line %d invalid key: %.40s...",
+ num, line);
+ key_free(public);
+ 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\n", name,
+ num, key_type(public));
+ print_host(out, cp, public, 0);
+ }
+ if (delete_host && !c)
+ print_host(out, cp, public, 0);
+ } else if (hash_hosts)
+ print_host(out, cp, public, 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\n", name,
+ num, key_type(public));
+ print_host(out, name, public,
+ hash_hosts);
+ }
+ if (delete_host && !c)
+ print_host(out, cp, public, 0);
+ } else if (hash_hosts) {
+ for (cp2 = strsep(&cp, ",");
+ cp2 != NULL && *cp2 != '\0';
+ cp2 = strsep(&cp, ",")) {
+ if (strcspn(cp2, "*?!") != strlen(cp2))
+ fprintf(stderr, "Warning: "
+ "ignoring host name with "
+ "metacharacters: %.64s\n",
+ cp2);
+ else
+ print_host(out, cp2, public, 1);
+ }
+ has_unhashed = 1;
+ }
+ }
+ key_free(public);
+ }
+ 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 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 SMARTCARD
+ fprintf(stderr, " -D reader Download public key from smartcard.\n");
+#endif /* SMARTCARD */
+ fprintf(stderr, " -e Convert OpenSSH to RFC 4716 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, " -i Convert RFC 4716 to OpenSSH key file.\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, " -N phrase Provide new passphrase.\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, " -T file Screen candidates for DH-GEX moduli.\n");
+ fprintf(stderr, " -t type Specify type of key to create.\n");
+#ifdef SMARTCARD
+ fprintf(stderr, " -U reader Upload private key to smartcard.\n");
+#endif /* SMARTCARD */
+ 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");
+
+ exit(1);
+}
+
+/*
+ * Main program for key management.
+ */
+int
+main(int argc, char **argv)
+{
+ char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
+ char out_file[MAXPATHLEN], *reader_id = NULL;
+ char *rr_hostname = NULL;
+ Key *private, *public;
+ struct passwd *pw;
+ struct stat st;
+ int opt, type, fd, download = 0;
+ u_int32_t memory = 0, generator_wanted = 0, trials = 100;
+ int do_gen_candidates = 0, do_screen_candidates = 0;
+ 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]);
+
+ SSLeay_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,
+ "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
+ switch (opt) {
+ case 'b':
+ bits = (u_int32_t)strtonum(optarg, 768, 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 'R':
+ delete_host = 1;
+ rr_hostname = optarg;
+ break;
+ case 'l':
+ print_fingerprint = 1;
+ break;
+ case 'B':
+ print_bubblebabble = 1;
+ break;
+ case 'p':
+ change_passphrase = 1;
+ break;
+ case 'c':
+ change_comment = 1;
+ break;
+ case 'f':
+ 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 'C':
+ identity_comment = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'e':
+ case 'x':
+ /* export key */
+ convert_to_ssh2 = 1;
+ break;
+ case 'i':
+ case 'X':
+ /* import key */
+ convert_from_ssh2 = 1;
+ break;
+ case 'y':
+ print_public = 1;
+ break;
+ case 'd':
+ key_type_name = "dsa";
+ break;
+ case 't':
+ key_type_name = optarg;
+ break;
+ case 'D':
+ download = 1;
+ /*FALLTHROUGH*/
+ case 'U':
+ reader_id = 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 '?':
+ default:
+ usage();
+ }
+ }
+
+ /* reinit */
+ log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
+
+ if (optind < argc) {
+ 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 (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_ssh2)
+ do_convert_to_ssh2(pw);
+ if (convert_from_ssh2)
+ do_convert_from_ssh2(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 (reader_id != NULL) {
+#ifdef SMARTCARD
+ if (download)
+ do_download(pw, reader_id);
+ else
+ do_upload(pw, reader_id);
+#else /* SMARTCARD */
+ fatal("no support for smartcards.");
+#endif /* SMARTCARD */
+ }
+
+ 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)
+ bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
+ if (type == KEY_DSA && bits != 1024)
+ fatal("DSA keys must be 1024 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 &&
+ stat(dotsshdir, &st) < 0) {
+ if (mkdir(dotsshdir, 0700) < 0)
+ error("Could not create directory '%s'.", dotsshdir);
+ else if (!quiet)
+ printf("Created directory '%s'.\n", dotsshdir);
+ }
+ /* If the file already exists, ask the user to confirm. */
+ if (stat(identity_file, &st) >= 0) {
+ char yesno[3];
+ printf("%s already exists.\n", identity_file);
+ printf("Overwrite (y/n)? ");
+ fflush(stdout);
+ if (fgets(yesno, sizeof(yesno), stdin) == NULL)
+ exit(1);
+ if (yesno[0] != 'y' && yesno[0] != 'Y')
+ exit(1);
+ }
+ /* Ask for a passphrase (twice). */
+ if (identity_passphrase)
+ passphrase1 = xstrdup(identity_passphrase);
+ else if (identity_new_passphrase)
+ passphrase1 = xstrdup(identity_new_passphrase);
+ else {
+passphrase_again:
+ passphrase1 =
+ read_passphrase("Enter passphrase (empty for no "
+ "passphrase): ", RP_ALLOW_STDIN);
+ passphrase2 = read_passphrase("Enter same passphrase again: ",
+ RP_ALLOW_STDIN);
+ if (strcmp(passphrase1, passphrase2) != 0) {
+ /*
+ * The passphrases do not match. Clear them and
+ * retry.
+ */
+ memset(passphrase1, 0, strlen(passphrase1));
+ memset(passphrase2, 0, strlen(passphrase2));
+ xfree(passphrase1);
+ xfree(passphrase2);
+ printf("Passphrases do not match. Try again.\n");
+ goto passphrase_again;
+ }
+ /* Clear the other copy of the passphrase. */
+ memset(passphrase2, 0, strlen(passphrase2));
+ xfree(passphrase2);
+ }
+
+ if (identity_comment) {
+ strlcpy(comment, identity_comment, sizeof(comment));
+ } else {
+ /* Create default 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/crypto/openssh/ssh-keyscan.1 b/crypto/openssh/ssh-keyscan.1
new file mode 100644
index 0000000..2c7ac10
--- /dev/null
+++ b/crypto/openssh/ssh-keyscan.1
@@ -0,0 +1,169 @@
+.\" $OpenBSD: ssh-keyscan.1,v 1.26 2008/12/29 01:12:36 stevesk Exp $
+.\" $FreeBSD$
+.\"
+.\" 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 December 29 2008
+.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 rsa
+or
+.Dq dsa
+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 and dsa keys:
+.Bd -literal
+host-or-namelist keytype base64-encoded-key
+.Ed
+.Pp
+Where
+.Pa keytype
+is either
+.Dq ssh-rsa
+or
+.Dq ssh-dss .
+.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 -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/crypto/openssh/ssh-keyscan.c b/crypto/openssh/ssh-keyscan.c
new file mode 100644
index 0000000..9a91be4
--- /dev/null
+++ b/crypto/openssh/ssh-keyscan.c
@@ -0,0 +1,851 @@
+/* $OpenBSD: ssh-keyscan.c,v 1.78 2009/01/22 10:02:34 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.
+ */
+
+#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
+
+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;
+
+/*
+ * This is just a wrapper around fgets() to make it usable.
+ */
+
+/* Stress-test. Increase this later. */
+#define LINEBUF_SIZE 16
+
+typedef struct {
+ char *buf;
+ u_int size;
+ int lineno;
+ const char *filename;
+ FILE *stream;
+ void (*errfun) (const char *,...);
+} Linebuf;
+
+static Linebuf *
+Linebuf_alloc(const char *filename, void (*errfun) (const char *,...))
+{
+ Linebuf *lb;
+
+ if (!(lb = malloc(sizeof(*lb)))) {
+ if (errfun)
+ (*errfun) ("linebuf (%s): malloc failed\n",
+ filename ? filename : "(stdin)");
+ return (NULL);
+ }
+ if (filename) {
+ lb->filename = filename;
+ if (!(lb->stream = fopen(filename, "r"))) {
+ xfree(lb);
+ if (errfun)
+ (*errfun) ("%s: %s\n", filename, strerror(errno));
+ return (NULL);
+ }
+ } else {
+ lb->filename = "(stdin)";
+ lb->stream = stdin;
+ }
+
+ if (!(lb->buf = malloc((lb->size = LINEBUF_SIZE)))) {
+ if (errfun)
+ (*errfun) ("linebuf (%s): malloc failed\n", lb->filename);
+ xfree(lb);
+ return (NULL);
+ }
+ lb->errfun = errfun;
+ lb->lineno = 0;
+ return (lb);
+}
+
+static void
+Linebuf_free(Linebuf * lb)
+{
+ fclose(lb->stream);
+ xfree(lb->buf);
+ xfree(lb);
+}
+
+#if 0
+static void
+Linebuf_restart(Linebuf * lb)
+{
+ clearerr(lb->stream);
+ rewind(lb->stream);
+ lb->lineno = 0;
+}
+
+static int
+Linebuf_lineno(Linebuf * lb)
+{
+ return (lb->lineno);
+}
+#endif
+
+static char *
+Linebuf_getline(Linebuf * lb)
+{
+ size_t n = 0;
+ void *p;
+
+ lb->lineno++;
+ for (;;) {
+ /* Read a line */
+ if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) {
+ if (ferror(lb->stream) && lb->errfun)
+ (*lb->errfun)("%s: %s\n", lb->filename,
+ strerror(errno));
+ return (NULL);
+ }
+ n = strlen(lb->buf);
+
+ /* Return it or an error if it fits */
+ if (n > 0 && lb->buf[n - 1] == '\n') {
+ lb->buf[n - 1] = '\0';
+ return (lb->buf);
+ }
+ if (n != lb->size - 1) {
+ if (lb->errfun)
+ (*lb->errfun)("%s: skipping incomplete last line\n",
+ lb->filename);
+ return (NULL);
+ }
+ /* Double the buffer if we need more space */
+ lb->size *= 2;
+ if ((p = realloc(lb->buf, lb->size)) == NULL) {
+ lb->size /= 2;
+ if (lb->errfun)
+ (*lb->errfun)("linebuf (%s): realloc failed\n",
+ lb->filename);
+ return (NULL);
+ }
+ lb->buf = p;
+ }
+}
+
+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": "ssh-rsa";
+ 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->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_RSA; 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;
+ char *tname;
+
+ 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_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));
+
+ if (fopt_count) {
+ Linebuf *lb;
+ char *line;
+ int j;
+
+ for (j = 0; j < fopt_count; j++) {
+ lb = Linebuf_alloc(argv[j], error);
+ if (!lb)
+ continue;
+ while ((line = Linebuf_getline(lb)) != NULL)
+ do_host(line);
+ Linebuf_free(lb);
+ }
+ }
+
+ while (optind < argc)
+ do_host(argv[optind++]);
+
+ while (ncon > 0)
+ conloop();
+
+ return (0);
+}
diff --git a/crypto/openssh/ssh-keysign.8 b/crypto/openssh/ssh-keysign.8
new file mode 100644
index 0000000..c56a98d
--- /dev/null
+++ b/crypto/openssh/ssh-keysign.8
@@ -0,0 +1,82 @@
+.\" $OpenBSD: ssh-keysign.8,v 1.9 2007/05/31 19:20:16 jmc 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 May 31 2007
+.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
+.It Pa /etc/ssh/ssh_config
+Controls whether
+.Nm
+is enabled.
+.It Pa /etc/ssh/ssh_host_dsa_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,
+.Nm
+must be set-uid root if host-based authentication is used.
+.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/crypto/openssh/ssh-keysign.c b/crypto/openssh/ssh-keysign.c
new file mode 100644
index 0000000..c4bc7e5
--- /dev/null
+++ b/crypto/openssh/ssh-keysign.c
@@ -0,0 +1,254 @@
+/* $OpenBSD: ssh-keysign.c,v 1.29 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 <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");
+
+ SSLeay_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 sockname 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(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/crypto/openssh/ssh-rand-helper.8 b/crypto/openssh/ssh-rand-helper.8
new file mode 100644
index 0000000..af5a72f
--- /dev/null
+++ b/crypto/openssh/ssh-rand-helper.8
@@ -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/crypto/openssh/ssh-rand-helper.c b/crypto/openssh/ssh-rand-helper.c
new file mode 100644
index 0000000..8b1c4b4
--- /dev/null
+++ b/crypto/openssh/ssh-rand-helper.c
@@ -0,0 +1,925 @@
+/*
+ * 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;
+ 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();
+ }
+ }
+
+ log_init(argv[0], ll, SYSLOG_FACILITY_USER, 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/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c
new file mode 100644
index 0000000..0e16ff8
--- /dev/null
+++ b/crypto/openssh/ssh-rsa.c
@@ -0,0 +1,263 @@
+/* $OpenBSD: ssh-rsa.c,v 1.39 2006/08/03 03:34:42 deraadt 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 "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->type != KEY_RSA || key->rsa == NULL) {
+ 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->type != KEY_RSA || key->rsa == NULL) {
+ 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_string(&b, NULL);
+ if (strcmp("ssh-rsa", ktype) != 0) {
+ error("ssh_rsa_verify: cannot handle type %s", ktype);
+ buffer_free(&b);
+ xfree(ktype);
+ return -1;
+ }
+ xfree(ktype);
+ sigblob = buffer_get_string(&b, &len);
+ rlen = buffer_len(&b);
+ buffer_free(&b);
+ if (rlen != 0) {
+ error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
+ xfree(sigblob);
+ return -1;
+ }
+ /* 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;
+ 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;
+ }
+ if (memcmp(decrypted, oid, oidlen) != 0) {
+ error("oid mismatch");
+ goto done;
+ }
+ if (memcmp(decrypted + oidlen, hash, hlen) != 0) {
+ error("hash mismatch");
+ goto done;
+ }
+ ret = 1;
+done:
+ if (decrypted)
+ xfree(decrypted);
+ return ret;
+}
diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1
new file mode 100644
index 0000000..e88cfe3
--- /dev/null
+++ b/crypto/openssh/ssh.1
@@ -0,0 +1,1481 @@
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: ssh.1,v 1.283 2009/03/19 15:15:09 jmc Exp $
+.\" $FreeBSD$
+.Dd March 19 2009
+.Dt SSH 1
+.Os
+.Sh NAME
+.Nm ssh
+.Nd OpenSSH SSH client (remote login program)
+.Sh SYNOPSIS
+.Nm ssh
+.Op Fl 1246AaCfgKkMNnqsTtVvXxYy
+.Op Fl b Ar bind_address
+.Op Fl c Ar cipher_spec
+.Oo Fl D\ \&
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port
+.Sm on
+.Oc
+.Op Fl e Ar escape_char
+.Op Fl F Ar configfile
+.Bk -words
+.Op Fl i Ar identity_file
+.Ek
+.Oo Fl L\ \&
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port : host : hostport
+.Sm on
+.Oc
+.Bk -words
+.Op Fl l Ar login_name
+.Ek
+.Op Fl m Ar mac_spec
+.Op Fl O Ar ctl_cmd
+.Op Fl o Ar option
+.Op Fl p Ar port
+.Oo Fl R\ \&
+.Sm off
+.Oo Ar bind_address : Oc
+.Ar port : host : hostport
+.Sm on
+.Oc
+.Op Fl S Ar ctl_path
+.Bk -words
+.Oo Fl w Ar local_tun Ns
+.Op : Ns Ar remote_tun Oc
+.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 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 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 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 with an alternative syntax:
+.Sm off
+.Xo
+.Op Ar bind_address No /
+.Ar port
+.Xc
+.Sm on
+or 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 smartcard_device
+Specify the device
+.Nm
+should use to communicate with a smartcard used for storing the user's
+private RSA key.
+This option is only available if support for smartcard devices
+is compiled in (default is no support).
+.It Fl i Ar identity_file
+Selects a file from which the identity (private key) for
+RSA or DSA authentication is read.
+The default is
+.Pa ~/.ssh/identity
+for protocol version 1, and
+.Pa ~/.ssh/id_rsa
+and
+.Pa ~/.ssh/id_dsa
+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).
+.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 with an alternative syntax:
+.Sm off
+.Xo
+.Op Ar bind_address No /
+.Ar port No / Ar host No /
+.Ar hostport
+.Xc
+.Sm on
+or 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) 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 KbdInteractiveDevices
+.It LocalCommand
+.It LocalForward
+.It LogLevel
+.It MACs
+.It NoHostAuthenticationForLocalhost
+.It NumberOfPasswordPrompts
+.It PasswordAuthentication
+.It PermitLocalCommand
+.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 SmartcardDevice
+.It StrictHostKeyChecking
+.It TCPKeepAlive
+.It Tunnel
+.It TunnelDevice
+.It UsePrivilegedPort
+.It User
+.It UserKnownHostsFile
+.It VerifyHostKeyDNS
+.It VersionAddendum
+.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 or
+using an alternative syntax:
+.Sm off
+.Xo
+.Op Ar bind_address No /
+.Ar host No / Ar port No /
+.Ar hostport
+.Xc .
+.Sm on
+.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.
+.It Fl S Ar ctl_path
+Specifies the location of a control socket for 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 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 .
+.Pp
+.Nm
+exits with the exit status of the remote command or with 255
+if an error occurred.
+.Sh AUTHENTICATION
+The OpenSSH SSH client supports SSH protocols 1 and 2.
+Protocol 2 is the default, with
+.Nm
+falling back to protocol 1 if it detects protocol 2 is unsupported.
+These settings may be altered using the
+.Cm Protocol
+option in
+.Xr ssh_config 5 ,
+or enforced using the
+.Fl 1
+and
+.Fl 2
+options (see above).
+Both protocols support similar authentication methods,
+but protocol 2 is preferred 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 either the RSA or DSA algorithms.
+Protocol 1 is restricted to using only RSA keys,
+but protocol 2 may use either.
+The
+.Sx HISTORY
+section of
+.Xr ssl 8
+contains a brief discussion of the two 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),
+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),
+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
+The most convenient way to use public key 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 ~/.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 ~/.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 ~/.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 ~/.ssh/authorized_keys
+Lists the public keys (RSA/DSA) that can be used for logging in as this user.
+The format of this file is described in the
+.Xr sshd 8
+manual page.
+This file is not highly sensitive, but the recommended
+permissions are read/write for the user, and not accessible by others.
+.Pp
+.It ~/.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 ~/.ssh/environment
+Contains additional definitions for environment variables; see
+.Sx ENVIRONMENT ,
+above.
+.Pp
+.It ~/.ssh/identity
+.It ~/.ssh/id_dsa
+.It ~/.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 ~/.ssh/identity.pub
+.It ~/.ssh/id_dsa.pub
+.It ~/.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 ~/.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 ~/.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 /etc/hosts.equiv
+This file is for host-based authentication (see above).
+It should only be writable by root.
+.Pp
+.It /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 /etc/ssh/ssh_host_key
+.It /etc/ssh/ssh_host_dsa_key
+.It /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 /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 /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 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
+.%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/crypto/openssh/ssh.c b/crypto/openssh/ssh.c
new file mode 100644
index 0000000..25dd863
--- /dev/null
+++ b/crypto/openssh/ssh.c
@@ -0,0 +1,1305 @@
+/* $OpenBSD: ssh.c,v 1.326 2009/07/02 02:11:47 dtucker 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"
+__RCSID("$FreeBSD$");
+
+#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 <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 "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 "version.h"
+
+#ifdef SMARTCARD
+#include "scard.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 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;
+
+/*
+ * 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;
+
+/* pid of proxycommand child process */
+pid_t proxy_command_pid = 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 identity_file] [-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 local_tun[:remote_tun]] [user@]hostname [command]\n"
+ );
+ exit(255);
+}
+
+static int ssh_session(void);
+static int ssh_session2(void);
+static void load_public_identity_files(void);
+
+/* 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];
+ 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();
+
+ /*
+ * 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: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 (strcmp(optarg, "check") == 0)
+ muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK;
+ 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 SMARTCARD
+ options.smartcard_device = xstrdup(optarg);
+#else
+ fprintf(stderr, "no support for smartcards.\n");
+#endif
+ break;
+ case 't':
+ if (tty_flag)
+ force_tty_flag = 1;
+ tty_flag = 1;
+ break;
+ case 'v':
+ if (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 '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 && **av != '-') {
+ 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();
+
+ SSLeay_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)
+ 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;
+ }
+
+ if (options.local_command != NULL) {
+ char thishost[NI_MAXHOST];
+
+ if (gethostname(thishost, sizeof(thishost)) == -1)
+ fatal("gethostname: %s", strerror(errno));
+ snprintf(buf, sizeof(buf), "%d", options.port);
+ debug3("expanding LocalCommand: %s", options.local_command);
+ cp = options.local_command;
+ options.local_command = percent_expand(cp, "d", pw->pw_dir,
+ "h", options.hostname? options.hostname : host,
+ "l", thishost, "n", host, "r", options.user, "p", buf,
+ "u", pw->pw_name, (char *)NULL);
+ debug3("expanded LocalCommand: %s", options.local_command);
+ xfree(cp);
+ }
+
+ if (options.hostname != NULL)
+ host = options.hostname;
+
+ /* Find canonic host name. */
+ if (strchr(host, '.') == 0) {
+ struct addrinfo hints;
+ struct addrinfo *ai = NULL;
+ int errgai;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = options.address_family;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_socktype = SOCK_STREAM;
+ errgai = getaddrinfo(host, NULL, &hints, &ai);
+ if (errgai == 0) {
+ if (ai->ai_canonname != NULL)
+ host = xstrdup(ai->ai_canonname);
+ freeaddrinfo(ai);
+ }
+ }
+
+ /* 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 = 3;
+ sensitive_data.keys = xcalloc(sensitive_data.nkeys,
+ sizeof(Key));
+
+ 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_type(KEY_DSA,
+ _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
+ sensitive_data.keys[2] = 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[1] == NULL &&
+ sensitive_data.keys[2] == NULL) {
+ sensitive_data.keys[1] = key_load_public(
+ _PATH_HOST_DSA_KEY_FILE, NULL);
+ sensitive_data.keys[2] = 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)
+ if (mkdir(buf, 0700) < 0)
+ error("Could not create directory '%.200s'.", buf);
+
+ /* load options.identity_files */
+ load_public_identity_files();
+
+ /* Expand ~ in known host file names. */
+ /* XXX mem-leaks: */
+ options.system_hostfile =
+ tilde_expand_filename(options.system_hostfile, original_real_uid);
+ options.user_hostfile =
+ tilde_expand_filename(options.user_hostfile, original_real_uid);
+ options.system_hostfile2 =
+ tilde_expand_filename(options.system_hostfile2, original_real_uid);
+ options.user_hostfile2 =
+ tilde_expand_filename(options.user_hostfile2, original_real_uid);
+
+ signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */
+
+ /* Log into the remote system. Never returns if the login fails. */
+ ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr,
+ pw, timeout_ms);
+
+ /* 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);
+
+ /*
+ * 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);
+
+ return exit_status;
+}
+
+/* Callback for remote forward global requests */
+static void
+ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
+{
+ Forward *rfwd = (Forward *)ctxt;
+
+ /* 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) {
+ logit("Allocated port %u for remote forward to %s:%d",
+ packet_get_int(),
+ rfwd->connect_host, rfwd->connect_port);
+ }
+
+ if (type == SSH2_MSG_REQUEST_FAILURE) {
+ if (options.exit_on_forward_failure)
+ fatal("Error: remote port forwarding failed for "
+ "listen port %d", rfwd->listen_port);
+ else
+ logit("Warning: remote port forwarding failed for "
+ "listen port %d", rfwd->listen_port);
+ }
+ if (++remote_forward_confirms_received == options.num_remote_forwards) {
+ debug("All remote forwarding requests processed");
+ if (fork_after_authentication_flag) {
+ fork_after_authentication_flag = 0;
+ if (daemon(1, 1) < 0)
+ fatal("daemon() failed: %.200s",
+ strerror(errno));
+ }
+ }
+}
+
+static void
+ssh_init_forwarding(void)
+{
+ int success = 0;
+ int i;
+
+ /* 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, &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);
+
+ /* 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 &&
+ (!options.exit_on_forward_failure ||
+ options.num_remote_forwards == 0)) {
+ fork_after_authentication_flag = 0;
+ if (daemon(1, 1) < 0)
+ fatal("daemon() failed: %.200s", strerror(errno));
+ }
+
+ /*
+ * If a command was specified on the command line, execute the
+ * 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, void *arg)
+{
+ extern char **environ;
+ const char *display;
+ int interactive = tty_flag;
+
+ 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, &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);
+
+ packet_set_interactive(interactive);
+}
+
+/* open new channel for a session */
+static int
+ssh_session2_open(void)
+{
+ Channel *c;
+ int window, packetmax, in, out, err;
+
+ if (stdin_null_flag) {
+ in = open(_PATH_DEVNULL, O_RDONLY);
+ } else {
+ in = dup(STDIN_FILENO);
+ }
+ out = dup(STDOUT_FILENO);
+ err = dup(STDERR_FILENO);
+
+ if (in < 0 || out < 0 || err < 0)
+ fatal("dup() in/out/err failed");
+
+ /* enable nonblocking unless tty */
+ if (!isatty(in))
+ set_nonblock(in);
+ if (!isatty(out))
+ set_nonblock(out);
+ if (!isatty(err))
+ set_nonblock(err);
+
+ window = CHAN_SES_WINDOW_DEFAULT;
+ packetmax = CHAN_SES_PACKET_DEFAULT;
+ if (tty_flag) {
+ window >>= 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();
+
+ 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);
+
+ /* Start listening for multiplex clients */
+ muxserver_listen();
+
+ /* If requested, let ssh continue in the background. */
+ if (fork_after_authentication_flag) {
+ fork_after_authentication_flag = 0;
+ if (daemon(1, 1) < 0)
+ fatal("daemon() failed: %.200s", strerror(errno));
+ }
+
+ return client_loop(tty_flag, tty_flag ?
+ options.escape_char : SSH_ESCAPECHAR_NONE, id);
+}
+
+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;
+#ifdef SMARTCARD
+ Key **keys;
+
+ if (options.smartcard_device != NULL &&
+ options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
+ (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) {
+ int count = 0;
+ for (i = 0; keys[i] != NULL; i++) {
+ count++;
+ memmove(&options.identity_files[1],
+ &options.identity_files[0],
+ sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));
+ memmove(&options.identity_keys[1],
+ &options.identity_keys[0],
+ sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));
+ options.num_identity_files++;
+ options.identity_keys[0] = keys[i];
+ options.identity_files[0] = sc_get_key_label(keys[i]);
+ }
+ if (options.num_identity_files > SSH_MAX_IDENTITY_FILES)
+ options.num_identity_files = SSH_MAX_IDENTITY_FILES;
+ i = count;
+ xfree(keys);
+ }
+#endif /* SMARTCARD */
+ 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 < options.num_identity_files; i++) {
+ 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]);
+ options.identity_files[i] = filename;
+ options.identity_keys[i] = public;
+ }
+ bzero(pwname, strlen(pwname));
+ xfree(pwname);
+ bzero(pwdir, strlen(pwdir));
+ xfree(pwdir);
+}
diff --git a/crypto/openssh/ssh.h b/crypto/openssh/ssh.h
new file mode 100644
index 0000000..186cfff
--- /dev/null
+++ b/crypto/openssh/ssh.h
@@ -0,0 +1,102 @@
+/* $OpenBSD: ssh.h,v 1.78 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".
+ */
+
+/* Cipher used for encrypting authentication files. */
+#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES
+
+/* Default port number. */
+#define SSH_DEFAULT_PORT 22
+
+/* Maximum number of TCP/IP ports forwarded per direction. */
+#define SSH_MAX_FORWARDS_PER_DIRECTION 100
+
+/*
+ * Maximum number of RSA authentication identity files that can be specified
+ * in configuration files or on the command line.
+ */
+#define SSH_MAX_IDENTITY_FILES 100
+
+/*
+ * 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/crypto/openssh/ssh1.h b/crypto/openssh/ssh1.h
new file mode 100644
index 0000000..353d930
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/ssh2.h b/crypto/openssh/ssh2.h
new file mode 100644
index 0000000..1c33dc2
--- /dev/null
+++ b/crypto/openssh/ssh2.h
@@ -0,0 +1,168 @@
+/* $OpenBSD: ssh2.h,v 1.11 2008/11/04 08:22: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.
+ */
+
+/*
+ * 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
+
+/* 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
+
diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config
new file mode 100644
index 0000000..e5045a5
--- /dev/null
+++ b/crypto/openssh/ssh_config
@@ -0,0 +1,48 @@
+# $OpenBSD: ssh_config,v 1.25 2009/02/17 01:28:32 djm Exp $
+# $FreeBSD$
+
+# 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 no
+# 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
+# VersionAddendum FreeBSD-20091001
diff --git a/crypto/openssh/ssh_config.5 b/crypto/openssh/ssh_config.5
new file mode 100644
index 0000000..b0497d1
--- /dev/null
+++ b/crypto/openssh/ssh_config.5
@@ -0,0 +1,1156 @@
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: ssh_config.5,v 1.119 2009/02/22 23:50:57 djm Exp $
+.\" $FreeBSD$
+.Dd February 22 2009
+.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 no .
+.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 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 or
+by using an alternative syntax:
+.Oo Ar bind_address Ns / Oc Ns Ar port .
+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 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:
+.Dq ssh-rsa,ssh-dss .
+.It Cm HostKeyAlias
+Specifies an alias that should be used instead of the
+real host name when looking up or saving the host key
+in the host key database files.
+This option is useful for tunneling SSH connections
+or for multiple servers running on a single host.
+.It Cm HostName
+Specifies the real host name to log into.
+This can be used to specify nicknames or abbreviations for hosts.
+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 RSA or DSA authentication identity
+is read.
+The default is
+.Pa ~/.ssh/identity
+for protocol version 1, and
+.Pa ~/.ssh/id_rsa
+and
+.Pa ~/.ssh/id_dsa
+for protocol version 2.
+Additionally, any identities represented by the authentication agent
+will be used for authentication.
+.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 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 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).
+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 or
+by using an alternative syntax:
+.Oo Ar bind_address Ns / Oc Ns Ar port
+and
+.Ar host Ns / Ns Ar hostport .
+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 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 for this option is:
+.Do gssapi-with-mic ,
+hostbased,
+publickey,
+keyboard-interactive,
+password
+.Dc .
+.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.
+The default is
+.Dq 2,1 .
+This means that ssh
+tries version 2 and falls back to version 1
+if version 2 is not available.
+.It Cm ProxyCommand
+Specifies the command to use to connect to the server.
+The command
+string extends to the end of the line, and is executed with
+the user's shell.
+In the command string,
+.Ql %h
+will be substituted by the host name to
+connect and
+.Ql %p
+by the port.
+The command can be basically anything,
+and should read from its standard input and write to its standard output.
+It should eventually connect an
+.Xr sshd 8
+server running on some machine, or execute
+.Ic sshd -i
+somewhere.
+Host key management will be done using the
+HostName of the host being connected (defaulting to the name typed by
+the user).
+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
+or by using an alternative syntax:
+.Oo Ar bind_address Ns / Oc Ns Ar port
+and
+.Ar host Ns / Ns Ar hostport .
+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 SmartcardDevice
+Specifies which smartcard device to use.
+The argument to this keyword is the device
+.Xr ssh 1
+should use to communicate with a smartcard used for storing the user's
+private RSA key.
+By default, no device is specified and smartcard support is not activated.
+.It Cm StrictHostKeyChecking
+If this flag is set to
+.Dq yes ,
+.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 VersionAddendum
+Specifies a string to append to the regular version string to identify
+OS- or site-specific modifications.
+The default is
+.Dq FreeBSD-20091001 .
+.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/local/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/crypto/openssh/ssh_namespace.h b/crypto/openssh/ssh_namespace.h
new file mode 100644
index 0000000..108a0a4
--- /dev/null
+++ b/crypto/openssh/ssh_namespace.h
@@ -0,0 +1,418 @@
+/*
+ * Namespace munging inspired by an equivalent hack in NetBSD's tree: add
+ * the "ssh_" prefix to every symbol in libssh which doesn't already have
+ * it. This prevents collisions between symbols in libssh and symbols in
+ * other libraries or applications which link with libssh, either directly
+ * or indirectly (e.g. through PAM loading pam_ssh).
+ *
+ * A list of symbols which need munging is obtained as follows:
+ *
+ * nm libssh.a | awk '$2 == "T" && $3 !~ /^ssh_/ { print "#define", $3, "ssh_" $3 }'
+ *
+ * $FreeBSD$
+ */
+
+#define a2port ssh_a2port
+#define a2tun ssh_a2tun
+#define acss ssh_acss
+#define acss_setkey ssh_acss_setkey
+#define acss_setsubkey ssh_acss_setsubkey
+#define add_host_to_hostfile ssh_add_host_to_hostfile
+#define addargs ssh_addargs
+#define addr_match_list ssh_addr_match_list
+#define ask_permission ssh_ask_permission
+#define atomicio ssh_atomicio
+#define atomiciov ssh_atomiciov
+#define auth_request_forwarding ssh_auth_request_forwarding
+#define buffer_append ssh_buffer_append
+#define buffer_append_space ssh_buffer_append_space
+#define buffer_check_alloc ssh_buffer_check_alloc
+#define buffer_clear ssh_buffer_clear
+#define buffer_compress ssh_buffer_compress
+#define buffer_compress_init_recv ssh_buffer_compress_init_recv
+#define buffer_compress_init_send ssh_buffer_compress_init_send
+#define buffer_compress_uninit ssh_buffer_compress_uninit
+#define buffer_consume ssh_buffer_consume
+#define buffer_consume_end ssh_buffer_consume_end
+#define buffer_consume_end_ret ssh_buffer_consume_end_ret
+#define buffer_consume_ret ssh_buffer_consume_ret
+#define buffer_dump ssh_buffer_dump
+#define buffer_free ssh_buffer_free
+#define buffer_get ssh_buffer_get
+#define buffer_get_bignum ssh_buffer_get_bignum
+#define buffer_get_bignum2 ssh_buffer_get_bignum2
+#define buffer_get_bignum2_ret ssh_buffer_get_bignum2_ret
+#define buffer_get_bignum_ret ssh_buffer_get_bignum_ret
+#define buffer_get_char ssh_buffer_get_char
+#define buffer_get_char_ret ssh_buffer_get_char_ret
+#define buffer_get_int ssh_buffer_get_int
+#define buffer_get_int64 ssh_buffer_get_int64
+#define buffer_get_int64_ret ssh_buffer_get_int64_ret
+#define buffer_get_int_ret ssh_buffer_get_int_ret
+#define buffer_get_ret ssh_buffer_get_ret
+#define buffer_get_short ssh_buffer_get_short
+#define buffer_get_short_ret ssh_buffer_get_short_ret
+#define buffer_get_string ssh_buffer_get_string
+#define buffer_get_string_ptr ssh_buffer_get_string_ptr
+#define buffer_get_string_ret ssh_buffer_get_string_ret
+#define buffer_init ssh_buffer_init
+#define buffer_len ssh_buffer_len
+#define buffer_ptr ssh_buffer_ptr
+#define buffer_put_bignum ssh_buffer_put_bignum
+#define buffer_put_bignum2 ssh_buffer_put_bignum2
+#define buffer_put_bignum2_ret ssh_buffer_put_bignum2_ret
+#define buffer_put_bignum_ret ssh_buffer_put_bignum_ret
+#define buffer_put_char ssh_buffer_put_char
+#define buffer_put_cstring ssh_buffer_put_cstring
+#define buffer_put_int ssh_buffer_put_int
+#define buffer_put_int64 ssh_buffer_put_int64
+#define buffer_put_short ssh_buffer_put_short
+#define buffer_put_string ssh_buffer_put_string
+#define buffer_uncompress ssh_buffer_uncompress
+#define chan_ibuf_empty ssh_chan_ibuf_empty
+#define chan_is_dead ssh_chan_is_dead
+#define chan_mark_dead ssh_chan_mark_dead
+#define chan_obuf_empty ssh_chan_obuf_empty
+#define chan_rcvd_eow ssh_chan_rcvd_eow
+#define chan_rcvd_ieof ssh_chan_rcvd_ieof
+#define chan_rcvd_oclose ssh_chan_rcvd_oclose
+#define chan_read_failed ssh_chan_read_failed
+#define chan_write_failed ssh_chan_write_failed
+#define channel_add_adm_permitted_opens ssh_channel_add_adm_permitted_opens
+#define channel_add_permitted_opens ssh_channel_add_permitted_opens
+#define channel_after_select ssh_channel_after_select
+#define channel_by_id ssh_channel_by_id
+#define channel_cancel_cleanup ssh_channel_cancel_cleanup
+#define channel_cancel_rport_listener ssh_channel_cancel_rport_listener
+#define channel_clear_adm_permitted_opens ssh_channel_clear_adm_permitted_opens
+#define channel_clear_permitted_opens ssh_channel_clear_permitted_opens
+#define channel_close_all ssh_channel_close_all
+#define channel_close_fd ssh_channel_close_fd
+#define channel_connect_by_listen_address ssh_channel_connect_by_listen_address
+#define channel_connect_to ssh_channel_connect_to
+#define channel_find_open ssh_channel_find_open
+#define channel_free ssh_channel_free
+#define channel_free_all ssh_channel_free_all
+#define channel_input_close ssh_channel_input_close
+#define channel_input_close_confirmation ssh_channel_input_close_confirmation
+#define channel_input_data ssh_channel_input_data
+#define channel_input_extended_data ssh_channel_input_extended_data
+#define channel_input_ieof ssh_channel_input_ieof
+#define channel_input_oclose ssh_channel_input_oclose
+#define channel_input_open_confirmation ssh_channel_input_open_confirmation
+#define channel_input_open_failure ssh_channel_input_open_failure
+#define channel_input_port_forward_request ssh_channel_input_port_forward_request
+#define channel_input_port_open ssh_channel_input_port_open
+#define channel_input_status_confirm ssh_channel_input_status_confirm
+#define channel_input_window_adjust ssh_channel_input_window_adjust
+#define channel_lookup ssh_channel_lookup
+#define channel_new ssh_channel_new
+#define channel_not_very_much_buffered_data ssh_channel_not_very_much_buffered_data
+#define channel_open_message ssh_channel_open_message
+#define channel_output_poll ssh_channel_output_poll
+#define channel_permit_all_opens ssh_channel_permit_all_opens
+#define channel_prepare_select ssh_channel_prepare_select
+#define channel_print_adm_permitted_opens ssh_channel_print_adm_permitted_opens
+#define channel_register_cleanup ssh_channel_register_cleanup
+#define channel_register_confirm ssh_channel_register_confirm
+#define channel_register_filter ssh_channel_register_filter
+#define channel_register_open_confirm ssh_channel_register_open_confirm
+#define channel_register_status_confirm ssh_channel_register_status_confirm
+#define channel_request_remote_forwarding ssh_channel_request_remote_forwarding
+#define channel_request_rforward_cancel ssh_channel_request_rforward_cancel
+#define channel_request_start ssh_channel_request_start
+#define channel_send_open ssh_channel_send_open
+#define channel_send_window_changes ssh_channel_send_window_changes
+#define channel_set_af ssh_channel_set_af
+#define channel_set_fds ssh_channel_set_fds
+#define channel_setup_local_fwd_listener ssh_channel_setup_local_fwd_listener
+#define channel_setup_remote_fwd_listener ssh_channel_setup_remote_fwd_listener
+#define channel_still_open ssh_channel_still_open
+#define channel_stop_listening ssh_channel_stop_listening
+#define check_host_in_hostfile ssh_check_host_in_hostfile
+#define choose_dh ssh_choose_dh
+#define chop ssh_chop
+#define cipher_blocksize ssh_cipher_blocksize
+#define cipher_by_name ssh_cipher_by_name
+#define cipher_by_number ssh_cipher_by_number
+#define cipher_cleanup ssh_cipher_cleanup
+#define cipher_crypt ssh_cipher_crypt
+#define cipher_get_keycontext ssh_cipher_get_keycontext
+#define cipher_get_keyiv ssh_cipher_get_keyiv
+#define cipher_get_keyiv_len ssh_cipher_get_keyiv_len
+#define cipher_get_number ssh_cipher_get_number
+#define cipher_init ssh_cipher_init
+#define cipher_is_cbc ssh_cipher_is_cbc
+#define cipher_keylen ssh_cipher_keylen
+#define cipher_mask_ssh1 ssh_cipher_mask_ssh1
+#define cipher_name ssh_cipher_name
+#define cipher_number ssh_cipher_number
+#define cipher_set_key_string ssh_cipher_set_key_string
+#define cipher_set_keycontext ssh_cipher_set_keycontext
+#define cipher_set_keyiv ssh_cipher_set_keyiv
+#define ciphers_valid ssh_ciphers_valid
+#define cleanhostname ssh_cleanhostname
+#define cleanup_exit ssh_cleanup_exit
+#define clear_cached_addr ssh_clear_cached_addr
+#define colon ssh_colon
+#define compat_cipher_proposal ssh_compat_cipher_proposal
+#define compat_datafellows ssh_compat_datafellows
+#define convtime ssh_convtime
+#define debug ssh_debug
+#define debug ssh_debug
+#define debug2 ssh_debug2
+#define debug2 ssh_debug2
+#define debug3 ssh_debug3
+#define debug3 ssh_debug3
+#define decode_reply ssh_decode_reply
+#define deny_input_open ssh_deny_input_open
+#define derive_ssh1_session_id ssh_derive_ssh1_session_id
+#define detect_attack ssh_detect_attack
+#define dh_estimate ssh_dh_estimate
+#define dh_gen_key ssh_dh_gen_key
+#define dh_new_group ssh_dh_new_group
+#define dh_new_group1 ssh_dh_new_group1
+#define dh_new_group14 ssh_dh_new_group14
+#define dh_new_group_asc ssh_dh_new_group_asc
+#define dh_pub_is_valid ssh_dh_pub_is_valid
+#define dispatch_init ssh_dispatch_init
+#define dispatch_protocol_error ssh_dispatch_protocol_error
+#define dispatch_protocol_ignore ssh_dispatch_protocol_ignore
+#define dispatch_range ssh_dispatch_range
+#define dispatch_run ssh_dispatch_run
+#define dispatch_set ssh_dispatch_set
+#define do_log ssh_do_log
+#define dump_base64 ssh_dump_base64
+#define enable_compat13 ssh_enable_compat13
+#define enable_compat20 ssh_enable_compat20
+#define error ssh_error
+#define error ssh_error
+#define evp_acss ssh_evp_acss
+#define evp_aes_128_ctr ssh_evp_aes_128_ctr
+#define evp_rijndael ssh_evp_rijndael
+#define evp_ssh1_3des ssh_evp_ssh1_3des
+#define evp_ssh1_bf ssh_evp_ssh1_bf
+#define export_dns_rr ssh_export_dns_rr
+#define fatal ssh_fatal
+#define fatal ssh_fatal
+#define fmt_scaled ssh_fmt_scaled
+#define freeargs ssh_freeargs
+#define freerrset ssh_freerrset
+#define gen_candidates ssh_gen_candidates
+#define get_canonical_hostname ssh_get_canonical_hostname
+#define get_local_ipaddr ssh_get_local_ipaddr
+#define get_local_name ssh_get_local_name
+#define get_local_port ssh_get_local_port
+#define get_peer_ipaddr ssh_get_peer_ipaddr
+#define get_peer_port ssh_get_peer_port
+#define get_remote_ipaddr ssh_get_remote_ipaddr
+#define get_remote_name_or_ip ssh_get_remote_name_or_ip
+#define get_remote_port ssh_get_remote_port
+#define get_sock_port ssh_get_sock_port
+#define get_u16 ssh_get_u16
+#define get_u32 ssh_get_u32
+#define get_u64 ssh_get_u64
+#define getrrsetbyname ssh_getrrsetbyname
+#define host_hash ssh_host_hash
+#define hostfile_read_key ssh_hostfile_read_key
+#define hpdelim ssh_hpdelim
+#define init_rng ssh_init_rng
+#define ipv64_normalise_mapped ssh_ipv64_normalise_mapped
+#define kex_derive_keys ssh_kex_derive_keys
+#define kex_dh_hash ssh_kex_dh_hash
+#define kex_finish ssh_kex_finish
+#define kex_get_newkeys ssh_kex_get_newkeys
+#define kex_input_kexinit ssh_kex_input_kexinit
+#define kex_send_kexinit ssh_kex_send_kexinit
+#define kex_setup ssh_kex_setup
+#define kexdh_client ssh_kexdh_client
+#define kexgex_client ssh_kexgex_client
+#define kexgex_hash ssh_kexgex_hash
+#define key_demote ssh_key_demote
+#define key_equal ssh_key_equal
+#define key_fingerprint ssh_key_fingerprint
+#define key_fingerprint_raw ssh_key_fingerprint_raw
+#define key_free ssh_key_free
+#define key_from_blob ssh_key_from_blob
+#define key_from_private ssh_key_from_private
+#define key_generate ssh_key_generate
+#define key_load_private ssh_key_load_private
+#define key_load_private_pem ssh_key_load_private_pem
+#define key_load_private_type ssh_key_load_private_type
+#define key_load_public ssh_key_load_public
+#define key_load_public_type ssh_key_load_public_type
+#define key_names_valid2 ssh_key_names_valid2
+#define key_new ssh_key_new
+#define key_new_private ssh_key_new_private
+#define key_perm_ok ssh_key_perm_ok
+#define key_read ssh_key_read
+#define key_save_private ssh_key_save_private
+#define key_sign ssh_key_sign
+#define key_size ssh_key_size
+#define key_ssh_name ssh_key_ssh_name
+#define key_to_blob ssh_key_to_blob
+#define key_type ssh_key_type
+#define key_type_from_name ssh_key_type_from_name
+#define key_verify ssh_key_verify
+#define key_write ssh_key_write
+#define log_facility_name ssh_log_facility_name
+#define log_facility_number ssh_log_facility_number
+#define log_init ssh_log_init
+#define log_level_name ssh_log_level_name
+#define log_level_number ssh_log_level_number
+#define logit ssh_logit
+#define logit ssh_logit
+#define lookup_key_in_hostfile_by_type ssh_lookup_key_in_hostfile_by_type
+#define mac_clear ssh_mac_clear
+#define mac_compute ssh_mac_compute
+#define mac_init ssh_mac_init
+#define mac_setup ssh_mac_setup
+#define mac_valid ssh_mac_valid
+#define match_host_and_ip ssh_match_host_and_ip
+#define match_hostname ssh_match_hostname
+#define match_list ssh_match_list
+#define match_pattern ssh_match_pattern
+#define match_pattern_list ssh_match_pattern_list
+#define match_user ssh_match_user
+#define mm_receive_fd ssh_mm_receive_fd
+#define mm_send_fd ssh_mm_send_fd
+#define ms_subtract_diff ssh_ms_subtract_diff
+#define ms_to_timeval ssh_ms_to_timeval
+#define mysignal ssh_mysignal
+#define packet_add_padding ssh_packet_add_padding
+#define packet_backup_state ssh_packet_backup_state
+#define packet_close ssh_packet_close
+#define packet_connection_is_ipv4 ssh_packet_connection_is_ipv4
+#define packet_connection_is_on_socket ssh_packet_connection_is_on_socket
+#define packet_disconnect ssh_packet_disconnect
+#define packet_get_bignum ssh_packet_get_bignum
+#define packet_get_bignum2 ssh_packet_get_bignum2
+#define packet_get_char ssh_packet_get_char
+#define packet_get_connection_in ssh_packet_get_connection_in
+#define packet_get_connection_out ssh_packet_get_connection_out
+#define packet_get_encryption_key ssh_packet_get_encryption_key
+#define packet_get_input ssh_packet_get_input
+#define packet_get_int ssh_packet_get_int
+#define packet_get_int64 ssh_packet_get_int64
+#define packet_get_keycontext ssh_packet_get_keycontext
+#define packet_get_keyiv ssh_packet_get_keyiv
+#define packet_get_keyiv_len ssh_packet_get_keyiv_len
+#define packet_get_maxsize ssh_packet_get_maxsize
+#define packet_get_newkeys ssh_packet_get_newkeys
+#define packet_get_output ssh_packet_get_output
+#define packet_get_protocol_flags ssh_packet_get_protocol_flags
+#define packet_get_raw ssh_packet_get_raw
+#define packet_get_ssh1_cipher ssh_packet_get_ssh1_cipher
+#define packet_get_state ssh_packet_get_state
+#define packet_get_string ssh_packet_get_string
+#define packet_get_string_ptr ssh_packet_get_string_ptr
+#define packet_have_data_to_write ssh_packet_have_data_to_write
+#define packet_inc_alive_timeouts ssh_packet_inc_alive_timeouts
+#define packet_is_interactive ssh_packet_is_interactive
+#define packet_need_rekeying ssh_packet_need_rekeying
+#define packet_not_very_much_data_to_write ssh_packet_not_very_much_data_to_write
+#define packet_process_incoming ssh_packet_process_incoming
+#define packet_put_bignum ssh_packet_put_bignum
+#define packet_put_bignum2 ssh_packet_put_bignum2
+#define packet_put_char ssh_packet_put_char
+#define packet_put_cstring ssh_packet_put_cstring
+#define packet_put_int ssh_packet_put_int
+#define packet_put_int64 ssh_packet_put_int64
+#define packet_put_raw ssh_packet_put_raw
+#define packet_put_string ssh_packet_put_string
+#define packet_read ssh_packet_read
+#define packet_read_expect ssh_packet_read_expect
+#define packet_read_poll ssh_packet_read_poll
+#define packet_read_poll_seqnr ssh_packet_read_poll_seqnr
+#define packet_read_seqnr ssh_packet_read_seqnr
+#define packet_remaining ssh_packet_remaining
+#define packet_restore_state ssh_packet_restore_state
+#define packet_send ssh_packet_send
+#define packet_send_debug ssh_packet_send_debug
+#define packet_send_ignore ssh_packet_send_ignore
+#define packet_set_alive_timeouts ssh_packet_set_alive_timeouts
+#define packet_set_authenticated ssh_packet_set_authenticated
+#define packet_set_connection ssh_packet_set_connection
+#define packet_set_encryption_key ssh_packet_set_encryption_key
+#define packet_set_interactive ssh_packet_set_interactive
+#define packet_set_iv ssh_packet_set_iv
+#define packet_set_keycontext ssh_packet_set_keycontext
+#define packet_set_maxsize ssh_packet_set_maxsize
+#define packet_set_nonblocking ssh_packet_set_nonblocking
+#define packet_set_protocol_flags ssh_packet_set_protocol_flags
+#define packet_set_rekey_limit ssh_packet_set_rekey_limit
+#define packet_set_server ssh_packet_set_server
+#define packet_set_state ssh_packet_set_state
+#define packet_set_timeout ssh_packet_set_timeout
+#define packet_start ssh_packet_start
+#define packet_start_compression ssh_packet_start_compression
+#define packet_write_poll ssh_packet_write_poll
+#define packet_write_wait ssh_packet_write_wait
+#define percent_expand ssh_percent_expand
+#define permanently_drop_suid ssh_permanently_drop_suid
+#define permanently_set_uid ssh_permanently_set_uid
+#define prime_test ssh_prime_test
+#define proto_spec ssh_proto_spec
+#define put_host_port ssh_put_host_port
+#define put_u16 ssh_put_u16
+#define put_u32 ssh_put_u32
+#define put_u64 ssh_put_u64
+#define pwcopy ssh_pwcopy
+#define read_keyfile_line ssh_read_keyfile_line
+#define read_passphrase ssh_read_passphrase
+#define refresh_progress_meter ssh_refresh_progress_meter
+#define replacearg ssh_replacearg
+#define restore_uid ssh_restore_uid
+#define rijndael_decrypt ssh_rijndael_decrypt
+#define rijndael_encrypt ssh_rijndael_encrypt
+#define rijndael_set_key ssh_rijndael_set_key
+#define rsa_generate_additional_parameters ssh_rsa_generate_additional_parameters
+#define rsa_private_decrypt ssh_rsa_private_decrypt
+#define rsa_public_encrypt ssh_rsa_public_encrypt
+#define sanitise_stdfd ssh_sanitise_stdfd
+#define scan_scaled ssh_scan_scaled
+#define schnorr_sign ssh_schnorr_sign
+#define schnorr_verify ssh_schnorr_verify
+#define seed_rng ssh_seed_rng
+#define set_newkeys ssh_set_newkeys
+#define set_nodelay ssh_set_nodelay
+#define set_nonblock ssh_set_nonblock
+#define shadow_pw ssh_shadow_pw
+#define sigdie ssh_sigdie
+#define ssh1_3des_iv ssh_ssh1_3des_iv
+#define start_progress_meter ssh_start_progress_meter
+#define stop_progress_meter ssh_stop_progress_meter
+#define strdelim ssh_strdelim
+#define strnvis ssh_strnvis
+#define strvis ssh_strvis
+#define strvisx ssh_strvisx
+#define sys_tun_open ssh_sys_tun_open
+#define temporarily_use_uid ssh_temporarily_use_uid
+#define tilde_expand_filename ssh_tilde_expand_filename
+#define tohex ssh_tohex
+#define tty_make_modes ssh_tty_make_modes
+#define tty_parse_modes ssh_tty_parse_modes
+#define tun_open ssh_tun_open
+#define umac_delete ssh_umac_delete
+#define umac_final ssh_umac_final
+#define umac_new ssh_umac_new
+#define umac_update ssh_umac_update
+#define unset_nonblock ssh_unset_nonblock
+#define uudecode ssh_uudecode
+#define uuencode ssh_uuencode
+#define verbose ssh_verbose
+#define verbose ssh_verbose
+#define verify_host_key_dns ssh_verify_host_key_dns
+#define vis ssh_vis
+#define x11_connect_display ssh_x11_connect_display
+#define x11_create_display_inet ssh_x11_create_display_inet
+#define x11_input_open ssh_x11_input_open
+#define x11_request_forwarding_with_spoofing ssh_x11_request_forwarding_with_spoofing
+#define xasprintf ssh_xasprintf
+#define xcalloc ssh_xcalloc
+#define xcrypt ssh_xcrypt
+#define xfree ssh_xfree
+#define xmalloc ssh_xmalloc
+#define xmmap ssh_xmmap
+#define xrealloc ssh_xrealloc
+#define xstrdup ssh_xstrdup
diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c
new file mode 100644
index 0000000..19009cd
--- /dev/null
+++ b/crypto/openssh/sshconnect.c
@@ -0,0 +1,1189 @@
+/* $OpenBSD: sshconnect.c,v 1.214 2009/05/28 16:50:16 andreas Exp $ */
+/* $FreeBSD$ */
+/*
+ * 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 <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 "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 "version.h"
+
+char *client_version_string = NULL;
+char *server_version_string = NULL;
+
+static int matching_host_key_dns = 0;
+
+/* import */
+extern Options options;
+extern char *__progname;
+extern uid_t original_real_uid;
+extern uid_t original_effective_uid;
+extern pid_t proxy_command_pid;
+
+static int show_other_keys(const char *, 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 = _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, (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. */
+ 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;
+}
+
+/*
+ * 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));
+
+ /* 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;
+ }
+}
+
+/*
+ * 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, const char *user_hostfile,
+ const char *system_hostfile)
+{
+ Key *file_key;
+ const char *type = key_type(host_key);
+ char *ip = NULL, *host = NULL;
+ char hostline[1000], *hostp, *fp, *ra;
+ HostStatus host_status;
+ HostStatus ip_status;
+ int r, local = 0, host_ip_differ = 0;
+ int salen;
+ char ntop[NI_MAXHOST];
+ char msg[1024];
+ int len, host_line, ip_line, cancelled_forwarding = 0;
+ const char *host_file = NULL, *ip_file = NULL;
+
+ /*
+ * Force accepting of the host key for loopback/localhost. The
+ * problem is that if the home directory is NFS-mounted to multiple
+ * machines, localhost will refer to a different machine in each of
+ * them, and the user will get bogus HOST_CHANGED warnings. This
+ * essentially disables host authentication for localhost; however,
+ * this is probably not a real problem.
+ */
+ /** hostaddr == 0! */
+ switch (hostaddr->sa_family) {
+ case AF_INET:
+ local = (ntohl(((struct sockaddr_in *)hostaddr)->
+ sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
+ salen = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ local = IN6_IS_ADDR_LOOPBACK(
+ &(((struct sockaddr_in6 *)hostaddr)->sin6_addr));
+ salen = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ local = 0;
+ salen = sizeof(struct sockaddr_storage);
+ break;
+ }
+ if (options.no_host_authentication_for_localhost == 1 && local &&
+ options.host_key_alias == NULL) {
+ debug("Forcing accepting of host key for "
+ "loopback/localhost.");
+ return 0;
+ }
+
+ /*
+ * We don't have the remote ip-address for connections
+ * using a proxy command
+ */
+ if (options.proxy_command == NULL) {
+ if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop),
+ NULL, 0, NI_NUMERICHOST) != 0)
+ fatal("check_host_key: getnameinfo failed");
+ ip = put_host_port(ntop, port);
+ } else {
+ ip = xstrdup("<no hostip for proxy command>");
+ }
+
+ /*
+ * Turn off check_host_ip if the connection is to localhost, via proxy
+ * command or if we don't have a hostname to compare with
+ */
+ if (options.check_host_ip && (local ||
+ strcmp(hostname, ip) == 0 || options.proxy_command != NULL))
+ options.check_host_ip = 0;
+
+ /*
+ * 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 (options.host_key_alias != NULL) {
+ host = xstrdup(options.host_key_alias);
+ debug("using hostkeyalias: %s", host);
+ } else {
+ host = put_host_port(hostname, port);
+ }
+
+ /*
+ * Store the host key from the known host file in here so that we can
+ * compare it with the key for the IP address.
+ */
+ file_key = key_new(host_key->type);
+
+ /*
+ * Check if the host key is present in the user's list of known
+ * hosts or in the systemwide list.
+ */
+ host_file = user_hostfile;
+ host_status = check_host_in_hostfile(host_file, host, host_key,
+ file_key, &host_line);
+ if (host_status == HOST_NEW) {
+ host_file = system_hostfile;
+ host_status = check_host_in_hostfile(host_file, host, host_key,
+ file_key, &host_line);
+ }
+ /*
+ * Also perform check for the ip address, skip the check if we are
+ * localhost or the hostname was an ip address to begin with
+ */
+ if (options.check_host_ip) {
+ Key *ip_key = key_new(host_key->type);
+
+ ip_file = user_hostfile;
+ ip_status = check_host_in_hostfile(ip_file, ip, host_key,
+ ip_key, &ip_line);
+ if (ip_status == HOST_NEW) {
+ ip_file = system_hostfile;
+ ip_status = check_host_in_hostfile(ip_file, ip,
+ host_key, ip_key, &ip_line);
+ }
+ if (host_status == HOST_CHANGED &&
+ (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key)))
+ host_ip_differ = 1;
+
+ key_free(ip_key);
+ } else
+ ip_status = host_status;
+
+ key_free(file_key);
+
+ switch (host_status) {
+ case HOST_OK:
+ /* The host is known and the key matches. */
+ debug("Host '%.200s' is known and matches the %s host key.",
+ host, type);
+ debug("Found key in %s:%d", host_file, host_line);
+ if (options.check_host_ip && ip_status == HOST_NEW) {
+ if (readonly)
+ 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)
+ 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, 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_CHANGED:
+ 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:%d", ip_file, ip_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 key in %s:%d", host_file, host_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;
+ }
+
+ /*
+ * 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 whishes 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:%d",
+ type, host, ip, ip_file, ip_line);
+ if (host_status == HOST_OK) {
+ len = strlen(msg);
+ snprintf(msg + len, sizeof(msg) - len,
+ "\nMatching host key in %s:%d",
+ host_file, host_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);
+ return 0;
+
+fail:
+ xfree(ip);
+ xfree(host);
+ 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;
+
+ if (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, 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);
+ 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);
+}
+
+static int
+show_key_from_file(const char *file, const char *host, int keytype)
+{
+ Key *found;
+ char *fp, *ra;
+ int line, ret;
+
+ found = key_new(keytype);
+ if ((ret = lookup_key_in_hostfile_by_type(file, host,
+ keytype, found, &line))) {
+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+ if (options.visual_host_key)
+ ra = key_fingerprint(found, SSH_FP_MD5, SSH_FP_RANDOMART);
+ logit("WARNING: %s key found for host %s\n"
+ "in %s:%d\n"
+ "%s key fingerprint %s.%s%s\n",
+ key_type(found), host, file, line,
+ key_type(found), fp,
+ options.visual_host_key ? "\n" : "",
+ options.visual_host_key ? ra : "");
+ if (options.visual_host_key)
+ xfree(ra);
+ xfree(fp);
+ }
+ key_free(found);
+ return (ret);
+}
+
+/* print all known host keys for a given host, but skip keys of given type */
+static int
+show_other_keys(const char *host, Key *key)
+{
+ int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1};
+ int i, found = 0;
+
+ for (i = 0; type[i] != -1; i++) {
+ if (type[i] == key->type)
+ continue;
+ if (type[i] != KEY_RSA1 &&
+ show_key_from_file(options.user_hostfile2, host, type[i])) {
+ found = 1;
+ continue;
+ }
+ if (type[i] != KEY_RSA1 &&
+ show_key_from_file(options.system_hostfile2, host, type[i])) {
+ found = 1;
+ continue;
+ }
+ if (show_key_from_file(options.user_hostfile, host, type[i])) {
+ found = 1;
+ continue;
+ }
+ if (show_key_from_file(options.system_hostfile, host, type[i])) {
+ found = 1;
+ continue;
+ }
+ debug2("no key of type %d for host %s", type[i], host);
+ }
+ return (found);
+}
+
+static void
+warn_changed_key(Key *host_key)
+{
+ char *fp;
+ const char *type = key_type(host_key);
+
+ fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
+ error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
+ error("It is also possible that the %s host key has just been changed.", type);
+ error("The fingerprint for the %s key sent by the remote host is\n%s.",
+ type, fp);
+ error("Please contact your system administrator.");
+
+ xfree(fp);
+}
+
+/*
+ * Execute a local command
+ */
+int
+ssh_local_cmd(const char *args)
+{
+ char *shell;
+ pid_t pid;
+ int status;
+
+ if (!options.permit_local_command ||
+ args == NULL || !*args)
+ return (1);
+
+ if ((shell = getenv("SHELL")) == NULL)
+ shell = _PATH_BSHELL;
+
+ pid = fork();
+ if (pid == 0) {
+ 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));
+
+ if (!WIFEXITED(status))
+ return (1);
+
+ return (WEXITSTATUS(status));
+}
diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h
new file mode 100644
index 0000000..c59a097
--- /dev/null
+++ b/crypto/openssh/sshconnect.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: sshconnect.h,v 1.25 2009/05/27 06:38:16 andreas 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_login(Sensitive *, const char *, struct sockaddr *, struct passwd *, int);
+
+void ssh_exchange_identification(int);
+
+int verify_host_key(char *, struct sockaddr *, Key *);
+
+void ssh_kex(char *, struct sockaddr *);
+void ssh_kex2(char *, struct sockaddr *);
+
+void ssh_userauth1(const char *, const char *, char *, 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/crypto/openssh/sshconnect1.c b/crypto/openssh/sshconnect1.c
new file mode 100644
index 0000000..fd07bbf
--- /dev/null
+++ b/crypto/openssh/sshconnect1.c
@@ -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/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c
new file mode 100644
index 0000000..260c630
--- /dev/null
+++ b/crypto/openssh/sshconnect2.c
@@ -0,0 +1,1828 @@
+/* $OpenBSD: sshconnect2.c,v 1.171 2009/03/05 07:18:19 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 <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 "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;
+}
+
+void
+ssh_kex2(char *host, struct sockaddr *hostaddr)
+{
+ 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;
+
+ 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->client_version_string=client_version_string;
+ kex->server_version_string=server_version_string;
+ kex->verify_host_key=&verify_host_key_callback;
+
+ xxx_kex = kex;
+
+ dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
+
+ session_id2 = kex->session_id;
+ session_id2_len = kex->session_id_len;
+
+#ifdef DEBUG_KEXDH
+ /* send 1st encrypted/maced/compressed message */
+ packet_start(SSH2_MSG_IGNORE);
+ packet_put_cstring("markus");
+ packet_send();
+ packet_write_wait();
+#endif
+}
+
+/*
+ * 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;
+ int 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_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);
+ 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->methoddata) {
+ xfree(authctxt->methoddata);
+ authctxt->methoddata = NULL;
+ }
+ authctxt->success = 1; /* break out */
+}
+
+/* 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;
+
+ if (attempt++ >= options.number_of_password_prompts)
+ return 0;
+
+ if (attempt != 1)
+ error("Permission denied, please try again.");
+
+ snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ",
+ authctxt->server_user, authctxt->host);
+ password = read_passphrase(prompt, 0);
+ packet_start(SSH2_MSG_USERAUTH_REQUEST);
+ packet_put_cstring(authctxt->server_user);
+ packet_put_cstring(authctxt->service);
+ packet_put_cstring(authctxt->method->name);
+ packet_put_char(0);
+ packet_put_cstring(password);
+ memset(password, 0, strlen(password));
+ xfree(password);
+ packet_add_padding(64);
+ packet_send();
+
+ 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];
+
+ 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, authctxt->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, authctxt->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, authctxt->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;
+
+ debug3("sign_and_send_pubkey");
+
+ 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, 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;
+ 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 public key: %s", 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: no 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) {
+ 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, myname[NI_MAXHOST];
+ const char *service;
+ u_int blen, slen;
+ int ok, i, len, 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 = NULL;
+ if (packet_connection_is_on_socket())
+ p = get_local_name(packet_get_connection_in());
+ if (p == NULL) {
+ if (gethostname(myname, sizeof(myname)) == -1) {
+ verbose("userauth_hostbased: gethostname: %s",
+ strerror(errno));
+ } else
+ p = xstrdup(myname);
+ }
+ if (p == NULL) {
+ error("userauth_hostbased: cannot get local ipaddr/name");
+ key_free(private);
+ xfree(blob);
+ return 0;
+ }
+ len = strlen(p) + 2;
+ 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);
+
+ return 1;
+}
+
+void
+userauth_jpake_cleanup(Authctxt *authctxt)
+{
+ debug3("%s: clean up", __func__);
+ if (authctxt->methoddata != NULL) {
+ jpake_free(authctxt->methoddata);
+ authctxt->methoddata = NULL;
+ }
+}
+#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/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8
new file mode 100644
index 0000000..2e3c0a5
--- /dev/null
+++ b/crypto/openssh/sshd.8
@@ -0,0 +1,905 @@
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: sshd.8,v 1.248 2009/03/26 08:38:39 sobrado Exp $
+.\" $FreeBSD$
+.Dd March 26 2009
+.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 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.d/sshd .
+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 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 the system
+log, and does not put itself in the background.
+The server also will not fork and will only process one connection.
+This option is only intended for debugging for the server.
+Multiple
+.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_rsa_key
+and
+.Pa /etc/ssh/ssh_host_dsa_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.
+Both protocols are supported by default,
+though this can be changed via the
+.Cm Protocol
+option in
+.Xr sshd_config 5 .
+Protocol 2 supports both RSA and DSA 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 and
+.Pa /var/run/nologin ;
+if one exists, it prints the 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
+.Xr xauth 1 .
+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 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 ,
+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 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.
+.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 with an alternative syntax:
+.Ar host Ns / Ns Ar port .
+Multiple
+.Cm permitopen
+options may be applied separated by commas.
+No pattern matching is performed on the specified hostnames,
+they must be literal domains or addresses.
+.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: hostnames,
+bits, exponent, modulus, comment.
+The fields are separated by spaces.
+.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.
+It is thus permissible (but not
+recommended) to have several lines or different host keys for the same
+names.
+This will inevitably happen when short forms of host names
+from different domains are put in the file.
+It is possible
+that the files contain conflicting information; authentication is
+accepted if valid information can be found from either file.
+.Pp
+Note that the lines in these files are typically hundreds of characters
+long, and you definitely don't want to type in the host keys by hand.
+Rather, generate them by a script
+or by taking
+.Pa /etc/ssh/ssh_host_key.pub
+and adding the host names at the front.
+.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.....=
+.Ed
+.Sh FILES
+.Bl -tag -width Ds -compact
+.It ~/.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 ~/.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 ~/.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 ~/.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 ~/.ssh/authorized_keys
+Lists the public keys (RSA/DSA) that can be used for logging in as this user.
+The format of this file is described 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 ~/.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 ~/.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 ~/.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 /etc/hosts.allow
+.It /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 /etc/hosts.equiv
+This file is for host-based authentication (see
+.Xr ssh 1 ) .
+It should only be writable by root.
+.Pp
+.It /etc/moduli
+Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange".
+The file format is described in
+.Xr moduli 5 .
+.Pp
+.It /etc/motd
+See
+.Xr motd 5 .
+.Pp
+.It /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 /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 /etc/ssh/ssh_host_key
+.It /etc/ssh/ssh_host_dsa_key
+.It /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 /etc/ssh/ssh_host_key.pub
+.It /etc/ssh/ssh_host_dsa_key.pub
+.It /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 /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 /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 /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 /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 /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/crypto/openssh/sshd.c b/crypto/openssh/sshd.c
new file mode 100644
index 0000000..249e20f
--- /dev/null
+++ b/crypto/openssh/sshd.c
@@ -0,0 +1,2273 @@
+/* $OpenBSD: sshd.c,v 1.367 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
+ * 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"
+__RCSID("$FreeBSD$");
+
+#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 <utmp.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
+
+#ifdef __FreeBSD__
+#include <resolv.h>
+#if defined(GSSAPI) && defined(HAVE_GSSAPI_H)
+#include <gssapi.h>
+#elif defined(GSSAPI) && defined(HAVE_GSSAPI_GSSAPI_H)
+#include <gssapi/gssapi.h>
+#endif
+#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 */
+ 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 = UT_HOSTSIZE;
+
+/* 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 */
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+
+ /* 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;
+
+ buffer_init(&b);
+ for (i = 0; i < options.num_host_key_files; i++) {
+ Key *key = sensitive_data.host_keys[i];
+ if (key == NULL)
+ continue;
+ switch (key->type) {
+ case KEY_RSA:
+ case KEY_DSA:
+ 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;
+}
+
+Key *
+get_hostkey_by_type(int type)
+{
+ int i;
+
+ for (i = 0; i < options.num_host_key_files; i++) {
+ Key *key = sensitive_data.host_keys[i];
+ if (key != NULL && key->type == type)
+ return key;
+ }
+ return NULL;
+}
+
+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 == 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] [-f config_file]\n"
+" [-g login_grace_time] [-h host_key_file] [-k key_gen_time]\n"
+" [-o option] [-p port] [-u len]\n"
+ );
+ exit(1);
+}
+
+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));
+
+#ifdef IPV6_V6ONLY
+ /* Only communicate in IPv6 over AF_INET6 sockets. */
+ if (ai->ai_family == AF_INET6) {
+ if (setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ &on, sizeof(on)) == -1)
+ error("setsockopt IPV6_V6ONLY: %s",
+ strerror(errno));
+ }
+#endif
+
+ 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, 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 '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++] = 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);
+
+ SSLeay_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:
+ 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);
+ }
+
+ /* 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 {
+ 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]);
+ }
+
+ /*
+ * 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);
+
+#ifdef __FreeBSD__
+ /*
+ * Initialize the resolver. This may not happen automatically
+ * before privsep chroot().
+ */
+ if ((_res.options & RES_INIT) == 0) {
+ debug("res_init()");
+ res_init();
+ }
+#ifdef GSSAPI
+ /*
+ * Force GSS-API to parse its configuration and load any
+ * mechanism plugins.
+ */
+ {
+ gss_OID_set mechs;
+ OM_uint32 minor_status;
+ gss_indicate_mechs(&minor_status, &mechs);
+ gss_release_oid_set(&minor_status, &mechs);
+ }
+#endif
+#endif
+
+ /*
+ * 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);
+
+ 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", obytes, 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";
+ }
+
+ 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->server = 1;
+ kex->client_version_string=client_version_string;
+ kex->server_version_string=server_version_string;
+ kex->load_host_key=&get_hostkey_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/crypto/openssh/sshd_config b/crypto/openssh/sshd_config
new file mode 100644
index 0000000..78e51ab
--- /dev/null
+++ b/crypto/openssh/sshd_config
@@ -0,0 +1,126 @@
+# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
+# $FreeBSD$
+
+# 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.
+
+# Note that some of FreeBSD's defaults differ from OpenBSD's, and
+# FreeBSD has a few additional options.
+
+#VersionAddendum FreeBSD-20091001
+
+#Port 22
+#Protocol 2
+#AddressFamily any
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# Disable legacy (protocol version 1) support in the server for new
+# installations. In future the default will change to require 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
+
+# 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 no
+#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
+
+# Change to yes to enable built-in password authentication.
+#PasswordAuthentication no
+#PermitEmptyPasswords no
+
+# Change to no to disable PAM authentication
+#ChallengeResponseAuthentication yes
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+#KerberosGetAFSToken no
+
+# GSSAPI options
+#GSSAPIAuthentication no
+#GSSAPICleanupCredentials yes
+
+# Set this to 'no' to disable 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 yes
+
+#AllowAgentForwarding yes
+#AllowTcpForwarding yes
+#GatewayPorts no
+#X11Forwarding yes
+#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/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5
new file mode 100644
index 0000000..84b0ae8
--- /dev/null
+++ b/crypto/openssh/sshd_config.5
@@ -0,0 +1,1092 @@
+.\" -*- nroff -*-
+.\"
+.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
+.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+.\" All rights reserved
+.\"
+.\" As far as I am concerned, the code I have written for this software
+.\" can be used freely for any purpose. Any derived versions of this
+.\" software must be clearly marked as such, and if the derived work is
+.\" incompatible with the protocol description in the RFC file, it must be
+.\" called by a name other than "ssh" or "Secure Shell".
+.\"
+.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
+.\" Copyright (c) 1999 Aaron Campbell. All rights reserved.
+.\" Copyright (c) 1999 Theo de Raadt. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $OpenBSD: sshd_config.5,v 1.106 2009/04/21 15:13:17 stevesk Exp $
+.\" $FreeBSD$
+.Dd April 21 2009
+.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.
+.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 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 a path to
+.Xr chroot 2
+to after authentication.
+This path, and all its components, 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 path 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 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_rsa_key
+and
+.Pa /etc/ssh/ssh_host_dsa_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
+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/ssh/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 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 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 Banner ,
+.Cm ChrootDirectory ,
+.Cm ForceCommand ,
+.Cm GatewayPorts ,
+.Cm GSSAPIAuthentication ,
+.Cm HostbasedAuthentication ,
+.Cm KbdInteractiveAuthentication ,
+.Cm KerberosAuthentication ,
+.Cm MaxAuthTries ,
+.Cm MaxSessions ,
+.Cm PasswordAuthentication ,
+.Cm PermitEmptyPasswords ,
+.Cm PermitOpen ,
+.Cm PermitRootLogin ,
+.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.
+See also
+.Cm UsePAM .
+The default is
+.Dq no .
+.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 no .
+Note that if
+.Cm ChallengeResponseAuthentication
+is
+.Dq yes ,
+the root user may be allowed in with its password even if
+.Cm PermitRootLogin is set to
+.Dq without-password .
+.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
+.Dq 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 RhostsRSAAuthentication
+Specifies whether rhosts or
+.Pa /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 .
+.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 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 yes .
+.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 VersionAddendum
+Specifies a string to append to the regular version string to identify
+OS- or site-specific modifications.
+The default is
+.Dq FreeBSD-20091001 .
+.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 yes .
+.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/local/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/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c
new file mode 100644
index 0000000..33bd652
--- /dev/null
+++ b/crypto/openssh/sshlogin.c
@@ -0,0 +1,163 @@
+/* $OpenBSD: sshlogin.c,v 1.26 2007/09/11 15:47:17 gilles 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/crypto/openssh/sshlogin.h b/crypto/openssh/sshlogin.h
new file mode 100644
index 0000000..500d3fe
--- /dev/null
+++ b/crypto/openssh/sshlogin.h
@@ -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/crypto/openssh/sshpty.c b/crypto/openssh/sshpty.c
new file mode 100644
index 0000000..bbbc0fe
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/sshpty.h b/crypto/openssh/sshpty.h
new file mode 100644
index 0000000..ac90035
--- /dev/null
+++ b/crypto/openssh/sshpty.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: sshpty.h,v 1.11 2008/05/19 15:45:07 djm Exp $ */
+
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * 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(void);
+void enter_raw_mode(void);
+
+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/crypto/openssh/sshtty.c b/crypto/openssh/sshtty.c
new file mode 100644
index 0000000..21ade4e
--- /dev/null
+++ b/crypto/openssh/sshtty.c
@@ -0,0 +1,93 @@
+/* $OpenBSD: sshtty.c,v 1.13 2008/05/19 15:45:07 djm Exp $ */
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+ * 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(void)
+{
+ if (!_in_raw_mode)
+ return;
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 0;
+}
+
+void
+enter_raw_mode(void)
+{
+ struct termios tio;
+
+ if (tcgetattr(fileno(stdin), &tio) == -1) {
+ perror("tcgetattr");
+ return;
+ }
+ _saved_tio = tio;
+ tio.c_iflag |= IGNPAR;
+ tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
+#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)
+ perror("tcsetattr");
+ else
+ _in_raw_mode = 1;
+}
diff --git a/crypto/openssh/ttymodes.c b/crypto/openssh/ttymodes.c
new file mode 100644
index 0000000..6f51b8a
--- /dev/null
+++ b/crypto/openssh/ttymodes.c
@@ -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/crypto/openssh/ttymodes.h b/crypto/openssh/ttymodes.h
new file mode 100644
index 0000000..4d848fe
--- /dev/null
+++ b/crypto/openssh/ttymodes.h
@@ -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/crypto/openssh/uidswap.c b/crypto/openssh/uidswap.c
new file mode 100644
index 0000000..8376483
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/uidswap.h b/crypto/openssh/uidswap.h
new file mode 100644
index 0000000..1c1163d
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/umac.c b/crypto/openssh/umac.c
new file mode 100644
index 0000000..92902bc
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/umac.h b/crypto/openssh/umac.h
new file mode 100644
index 0000000..055c705
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/uuencode.c b/crypto/openssh/uuencode.c
new file mode 100644
index 0000000..b9e57e9
--- /dev/null
+++ b/crypto/openssh/uuencode.c
@@ -0,0 +1,94 @@
+/* $OpenBSD: uuencode.c,v 1.25 2009/03/05 11:30:50 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, 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/crypto/openssh/uuencode.h b/crypto/openssh/uuencode.h
new file mode 100644
index 0000000..fec55b4
--- /dev/null
+++ b/crypto/openssh/uuencode.h
@@ -0,0 +1,29 @@
+/* $OpenBSD: uuencode.h,v 1.13 2006/08/03 03:34:42 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.
+ */
+
+int uuencode(const u_char *, u_int, char *, size_t);
+int uudecode(const char *, u_char *, size_t);
+void dump_base64(FILE *, u_char *, u_int);
diff --git a/crypto/openssh/version.c b/crypto/openssh/version.c
new file mode 100644
index 0000000..88361ae
--- /dev/null
+++ b/crypto/openssh/version.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2001 Brian Fundakowski Feldman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list 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.
+ *
+ */
+
+#include "includes.h"
+__RCSID("$FreeBSD$");
+
+#include <string.h>
+
+#include "version.h"
+#include "xmalloc.h"
+
+
+static char *version = NULL;
+
+const char *
+ssh_version_get(void) {
+
+ if (version == NULL)
+ version = xstrdup(SSH_VERSION_BASE " " SSH_VERSION_ADDENDUM);
+ return (version);
+}
+
+void
+ssh_version_set_addendum(const char *add) {
+ char *newvers;
+ size_t size;
+
+ if (add != NULL) {
+ size = strlen(SSH_VERSION_BASE) + 1 + strlen(add) + 1;
+ newvers = xmalloc(size);
+ snprintf(newvers, size, "%s %s", SSH_VERSION_BASE, add);
+ } else {
+ newvers = xstrdup(SSH_VERSION_BASE);
+ }
+ if (version != NULL)
+ xfree(version);
+ version = newvers;
+}
diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h
new file mode 100644
index 0000000..581decf
--- /dev/null
+++ b/crypto/openssh/version.h
@@ -0,0 +1,13 @@
+/* $OpenBSD: version.h,v 1.56 2009/06/30 14:54:40 markus Exp $ */
+/* $FreeBSD$ */
+
+#ifndef SSH_VERSION
+
+#define SSH_VERSION (ssh_version_get())
+#define SSH_RELEASE (ssh_version_get())
+#define SSH_VERSION_BASE "OpenSSH_5.3p1"
+#define SSH_VERSION_ADDENDUM "FreeBSD-20091001"
+
+const char *ssh_version_get(void);
+void ssh_version_set_addendum(const char *);
+#endif /* SSH_VERSION */
diff --git a/crypto/openssh/xmalloc.c b/crypto/openssh/xmalloc.c
new file mode 100644
index 0000000..9985b4c
--- /dev/null
+++ b/crypto/openssh/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/crypto/openssh/xmalloc.h b/crypto/openssh/xmalloc.h
new file mode 100644
index 0000000..fb217a4
--- /dev/null
+++ b/crypto/openssh/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)));
OpenPOWER on IntegriCloud