From 6b155c1c955b24e8c19bf74052835f0e3fb36b1a Mon Sep 17 00:00:00 2001 From: des Date: Wed, 21 Apr 2010 06:33:10 +0000 Subject: [PATCH] MFH OpenSSH 5.4p1 git-svn-id: svn://svn.freebsd.org/base/stable/8@206984 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- crypto/openssh/ChangeLog | 1258 +++++++++++ crypto/openssh/INSTALL | 6 +- crypto/openssh/PROTOCOL | 37 +- crypto/openssh/PROTOCOL.agent | 24 +- crypto/openssh/PROTOCOL.certkeys | 193 ++ crypto/openssh/PROTOCOL.mux | 196 ++ crypto/openssh/README | 4 +- crypto/openssh/README.platform | 14 +- crypto/openssh/README.smartcard | 93 - crypto/openssh/addrmatch.c | 78 +- crypto/openssh/auth-krb5.c | 13 +- crypto/openssh/auth-options.c | 169 +- crypto/openssh/auth-options.h | 4 +- crypto/openssh/auth-pam.c | 10 +- crypto/openssh/auth-passwd.c | 2 +- crypto/openssh/auth-rh-rsa.c | 5 +- crypto/openssh/auth-rhosts.c | 10 +- crypto/openssh/auth-rsa.c | 5 +- crypto/openssh/auth-sia.c | 53 - crypto/openssh/auth.c | 98 +- crypto/openssh/auth.h | 6 +- crypto/openssh/auth1.c | 10 +- crypto/openssh/auth2-hostbased.c | 5 +- crypto/openssh/auth2-jpake.c | 7 +- crypto/openssh/auth2-kbdint.c | 4 - crypto/openssh/auth2-none.c | 4 - crypto/openssh/auth2-passwd.c | 4 - crypto/openssh/auth2-pubkey.c | 92 +- crypto/openssh/auth2.c | 4 +- crypto/openssh/authfd.c | 30 +- crypto/openssh/authfd.h | 3 +- crypto/openssh/authfile.c | 83 +- crypto/openssh/authfile.h | 3 +- crypto/openssh/bufaux.c | 28 +- crypto/openssh/buffer.c | 8 +- crypto/openssh/buffer.h | 9 +- crypto/openssh/canohost.c | 42 +- crypto/openssh/canohost.h | 4 +- crypto/openssh/channels.c | 283 ++- crypto/openssh/channels.h | 23 +- crypto/openssh/clientloop.c | 98 +- crypto/openssh/clientloop.h | 12 +- crypto/openssh/config.guess | 238 +- crypto/openssh/config.h | 56 +- crypto/openssh/config.h.in | 50 +- crypto/openssh/defines.h | 21 +- crypto/openssh/dh.c | 4 +- crypto/openssh/dns.c | 8 +- crypto/openssh/dns.h | 6 +- crypto/openssh/gss-genr.c | 2 +- crypto/openssh/hostfile.c | 101 +- crypto/openssh/hostfile.h | 7 +- crypto/openssh/includes.h | 3 +- crypto/openssh/jpake.c | 181 +- crypto/openssh/jpake.h | 38 +- crypto/openssh/kex.c | 15 +- crypto/openssh/kex.h | 9 +- crypto/openssh/kexdhs.c | 21 +- crypto/openssh/kexgexs.c | 22 +- crypto/openssh/key.c | 613 +++++- crypto/openssh/key.h | 32 +- crypto/openssh/loginrec.c | 4 +- crypto/openssh/match.h | 4 +- crypto/openssh/misc.c | 29 +- crypto/openssh/misc.h | 3 +- crypto/openssh/monitor.c | 43 +- crypto/openssh/monitor_fdpass.c | 23 +- crypto/openssh/monitor_mm.c | 2 +- crypto/openssh/monitor_wrap.c | 48 +- crypto/openssh/monitor_wrap.h | 10 +- crypto/openssh/mux.c | 1941 +++++++++++++---- crypto/openssh/myproposal.h | 6 +- crypto/openssh/nchan.c | 21 +- .../openssh/openbsd-compat/bsd-cygwin_util.c | 133 -- .../openssh/openbsd-compat/bsd-cygwin_util.h | 5 +- crypto/openssh/openbsd-compat/daemon.c | 10 - .../openssh/openbsd-compat/getrrsetbyname.c | 2 +- .../openssh/openbsd-compat/openbsd-compat.h | 10 +- .../openssh/openbsd-compat/openssl-compat.c | 12 +- .../openssh/openbsd-compat/openssl-compat.h | 6 +- crypto/openssh/openbsd-compat/port-aix.c | 44 +- crypto/openssh/openbsd-compat/port-aix.h | 13 +- crypto/openssh/openbsd-compat/port-linux.c | 98 +- crypto/openssh/openbsd-compat/port-linux.h | 8 +- crypto/openssh/openbsd-compat/pwcache.c | 114 + .../openssh/openbsd-compat/readpassphrase.c | 78 +- crypto/openssh/packet.c | 973 +++++---- crypto/openssh/packet.h | 17 +- crypto/openssh/pathnames.h | 7 +- crypto/openssh/pkcs11.h | 1357 ++++++++++++ crypto/openssh/platform.c | 24 +- crypto/openssh/platform.h | 7 +- crypto/openssh/readconf.c | 28 +- crypto/openssh/readconf.h | 6 +- crypto/openssh/roaming.h | 44 + crypto/openssh/roaming_client.c | 280 +++ crypto/openssh/roaming_common.c | 244 +++ crypto/openssh/roaming_dummy.c | 61 + crypto/openssh/roaming_serv.c | 31 + crypto/openssh/scard-opensc.c | 532 ----- crypto/openssh/scard.c | 571 ----- crypto/openssh/scard.h | 39 - crypto/openssh/schnorr.c | 376 +++- crypto/openssh/schnorr.h | 60 + crypto/openssh/scp.1 | 6 +- crypto/openssh/scp.c | 21 +- crypto/openssh/servconf.c | 64 +- crypto/openssh/servconf.h | 8 +- crypto/openssh/serverloop.c | 15 +- crypto/openssh/session.c | 126 +- crypto/openssh/sftp-client.c | 301 ++- crypto/openssh/sftp-client.h | 21 +- crypto/openssh/sftp-common.c | 31 +- crypto/openssh/sftp-common.h | 4 +- crypto/openssh/sftp-server.8 | 28 +- crypto/openssh/sftp-server.c | 121 +- crypto/openssh/sftp.1 | 93 +- crypto/openssh/sftp.c | 858 ++++++-- crypto/openssh/ssh-add.1 | 32 +- crypto/openssh/ssh-add.c | 54 +- crypto/openssh/ssh-agent.1 | 25 +- crypto/openssh/ssh-agent.c | 163 +- crypto/openssh/ssh-dss.c | 10 +- crypto/openssh/ssh-keygen.1 | 210 +- crypto/openssh/ssh-keygen.c | 636 +++++- crypto/openssh/ssh-keyscan.1 | 4 +- crypto/openssh/ssh-keyscan.c | 2 +- crypto/openssh/ssh-keysign.c | 4 +- crypto/openssh/ssh-pkcs11-client.c | 238 ++ crypto/openssh/ssh-pkcs11-helper.0 | 25 + crypto/openssh/ssh-pkcs11-helper.8 | 43 + crypto/openssh/ssh-pkcs11-helper.c | 372 ++++ crypto/openssh/ssh-pkcs11.c | 564 +++++ crypto/openssh/ssh-pkcs11.h | 20 + crypto/openssh/ssh-rand-helper.c | 9 +- crypto/openssh/ssh-rsa.c | 10 +- crypto/openssh/ssh.1 | 92 +- crypto/openssh/ssh.c | 193 +- crypto/openssh/ssh2.h | 12 +- crypto/openssh/ssh_config | 5 +- crypto/openssh/ssh_config.5 | 42 +- crypto/openssh/ssh_namespace.h | 61 +- crypto/openssh/sshconnect.c | 114 +- crypto/openssh/sshconnect.h | 4 +- crypto/openssh/sshconnect2.c | 66 +- crypto/openssh/sshd.8 | 79 +- crypto/openssh/sshd.c | 144 +- crypto/openssh/sshd_config | 11 +- crypto/openssh/sshd_config.5 | 65 +- crypto/openssh/sshlogin.c | 10 +- crypto/openssh/sshpty.h | 6 +- crypto/openssh/sshtty.c | 23 +- crypto/openssh/uuencode.c | 13 +- crypto/openssh/version.h | 6 +- lib/libpam/modules/pam_ssh/Makefile | 3 + lib/libpam/modules/pam_ssh/pam_ssh.c | 3 + secure/lib/libssh/Makefile | 7 +- secure/libexec/Makefile | 2 +- secure/libexec/sftp-server/Makefile | 5 +- secure/libexec/ssh-keysign/Makefile | 2 +- secure/libexec/ssh-pkcs11-helper/Makefile | 16 + secure/usr.bin/scp/Makefile | 4 + secure/usr.bin/sftp/Makefile | 3 + secure/usr.bin/ssh-add/Makefile | 4 + secure/usr.bin/ssh-agent/Makefile | 4 + secure/usr.bin/ssh-keygen/Makefile | 4 + secure/usr.bin/ssh-keyscan/Makefile | 1 + secure/usr.bin/ssh/Makefile | 5 +- secure/usr.sbin/sshd/Makefile | 7 +- 169 files changed, 12858 insertions(+), 4061 deletions(-) create mode 100644 crypto/openssh/PROTOCOL.certkeys create mode 100644 crypto/openssh/PROTOCOL.mux delete mode 100644 crypto/openssh/README.smartcard create mode 100644 crypto/openssh/openbsd-compat/pwcache.c create mode 100644 crypto/openssh/pkcs11.h create mode 100644 crypto/openssh/roaming.h create mode 100644 crypto/openssh/roaming_client.c create mode 100644 crypto/openssh/roaming_common.c create mode 100644 crypto/openssh/roaming_dummy.c create mode 100644 crypto/openssh/roaming_serv.c delete mode 100644 crypto/openssh/scard-opensc.c delete mode 100644 crypto/openssh/scard.c delete mode 100644 crypto/openssh/scard.h create mode 100644 crypto/openssh/schnorr.h create mode 100644 crypto/openssh/ssh-pkcs11-client.c create mode 100644 crypto/openssh/ssh-pkcs11-helper.0 create mode 100644 crypto/openssh/ssh-pkcs11-helper.8 create mode 100644 crypto/openssh/ssh-pkcs11-helper.c create mode 100644 crypto/openssh/ssh-pkcs11.c create mode 100644 crypto/openssh/ssh-pkcs11.h create mode 100644 secure/libexec/ssh-pkcs11-helper/Makefile diff --git a/crypto/openssh/ChangeLog b/crypto/openssh/ChangeLog index f802c0d7f..d6e4a4a25 100644 --- a/crypto/openssh/ChangeLog +++ b/crypto/openssh/ChangeLog @@ -1,3 +1,1261 @@ +20100307 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/03/07 22:16:01 + [ssh-keygen.c] + make internal strptime string match strftime format; + suggested by vinschen AT redhat.com and markus@ + - djm@cvs.openbsd.org 2010/03/08 00:28:55 + [ssh-keygen.1] + document permit-agent-forwarding certificate constraint; patch from + stevesk@ + - djm@cvs.openbsd.org 2010/03/07 22:01:32 + [version.h] + openssh-5.4 + - (djm) [README contrib/caldera/openssh.spec contrib/redhat/openssh.spec] + crank version numbers + - (djm) Release OpenSSH-5.4p1 + +20100307 + - (dtucker) [auth.c] Bug #1710: call setauthdb on AIX before getpwuid so that + it gets the passwd struct from the LAM that knows about the user which is + not necessarily the default. Patch from Alexandre Letourneau. + - (dtucker) [session.c] Bug #1567: move setpcred call to before chroot and + do not set real uid, since that's needed for the chroot, and will be set + by permanently_set_uid. + - (dtucker) [session.c] Also initialize creds to NULL for handing to + setpcred. + - (dtucker) OpenBSD CVS Sync + - dtucker@cvs.openbsd.org 2010/03/07 11:57:13 + [auth-rhosts.c monitor.c monitor_wrap.c session.c auth-options.c sshd.c] + Hold authentication debug messages until after successful authentication. + Fixes an info leak of environment variables specified in authorized_keys, + reported by Jacob Appelbaum. ok djm@ + +20100305 + - OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/03/04 12:51:25 + [ssh.1 sshd_config.5] + tweak previous; + - djm@cvs.openbsd.org 2010/03/04 20:35:08 + [ssh-keygen.1 ssh-keygen.c] + Add a -L flag to print the contents of a certificate; ok markus@ + - jmc@cvs.openbsd.org 2010/03/04 22:52:40 + [ssh-keygen.1] + fix Bk/Ek; + - djm@cvs.openbsd.org 2010/03/04 23:17:25 + [sshd_config.5] + missing word; spotted by jmc@ + - djm@cvs.openbsd.org 2010/03/04 23:19:29 + [ssh.1 sshd.8] + move section on CA and revoked keys from ssh.1 to sshd.8's known hosts + format section and rework it a bit; requested by jmc@ + - djm@cvs.openbsd.org 2010/03/04 23:27:25 + [auth-options.c ssh-keygen.c] + "force-command" is not spelled "forced-command"; spotted by + imorgan AT nas.nasa.gov + - djm@cvs.openbsd.org 2010/03/05 02:58:11 + [auth.c] + make the warning for a revoked key louder and more noticable + - jmc@cvs.openbsd.org 2010/03/05 06:50:35 + [ssh.1 sshd.8] + tweak previous; + - jmc@cvs.openbsd.org 2010/03/05 08:31:20 + [ssh.1] + document certificate authentication; help/ok djm + - djm@cvs.openbsd.org 2010/03/05 10:28:21 + [ssh-add.1 ssh.1 ssh_config.5] + mention loading of certificate files from [private]-cert.pub when + they are present; feedback and ok jmc@ + - (tim) [ssh-pkcs11.c] Fix "non-constant initializer" errors in older + compilers. OK djm@ + - (djm) [ssh-rand-helper.c] declare optind, avoiding compilation failure + on some platforms + - (djm) [configure.ac] set -fno-strict-aliasing for gcc4; ok dtucker@ + +20100304 + - (djm) [ssh-keygen.c] Use correct local variable, instead of + maybe-undefined global "optarg" + - (djm) [contrib/redhat/openssh.spec] Replace obsolete BuildPreReq + on XFree86-devel with neutral /usr/include/X11/Xlib.h; + imorgan AT nas.nasa.gov in bz#1731 + - (djm) [.cvsignore] Ignore ssh-pkcs11-helper + - (djm) [regress/Makefile] Cleanup sshd_proxy_orig + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/03/03 01:44:36 + [auth-options.c key.c] + reject strings with embedded ASCII nul chars in certificate key IDs, + principal names and constraints + - djm@cvs.openbsd.org 2010/03/03 22:49:50 + [sshd.8] + the authorized_keys option for CA keys is "cert-authority", not + "from=cert-authority". spotted by imorgan AT nas.nasa.gov + - djm@cvs.openbsd.org 2010/03/03 22:50:40 + [PROTOCOL.certkeys] + s/similar same/similar/; from imorgan AT nas.nasa.gov + - djm@cvs.openbsd.org 2010/03/04 01:44:57 + [key.c] + use buffer_get_string_ptr_ret() where we are checking the return + value explicitly instead of the fatal()-causing buffer_get_string_ptr() + - djm@cvs.openbsd.org 2010/03/04 10:36:03 + [auth-rh-rsa.c auth-rsa.c auth.c auth.h auth2-hostbased.c auth2-pubkey.c] + [authfile.c authfile.h hostfile.c hostfile.h servconf.c servconf.h] + [ssh-keygen.c ssh.1 sshconnect.c sshd_config.5] + Add a TrustedUserCAKeys option to sshd_config to specify CA keys that + are trusted to authenticate users (in addition than doing it per-user + in authorized_keys). + + Add a RevokedKeys option to sshd_config and a @revoked marker to + known_hosts to allow keys to me revoked and banned for user or host + authentication. + + feedback and ok markus@ + - djm@cvs.openbsd.org 2010/03/03 00:47:23 + [regress/cert-hostkey.sh regress/cert-userkey.sh] + add an extra test to ensure that authentication with the wrong + certificate fails as it should (and it does) + - djm@cvs.openbsd.org 2010/03/04 10:38:23 + [regress/cert-hostkey.sh regress/cert-userkey.sh] + additional regression tests for revoked keys and TrustedUserCAKeys + +20100303 + - (djm) [PROTOCOL.certkeys] Add RCS Ident + - OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/02/26 22:09:28 + [ssh-keygen.1 ssh.1 sshd.8] + tweak previous; + - otto@cvs.openbsd.org 2010/03/01 11:07:06 + [ssh-add.c] + zap what seems to be a left-over debug message; ok markus@ + - djm@cvs.openbsd.org 2010/03/02 23:20:57 + [ssh-keygen.c] + POSIX strptime is stricter than OpenBSD's so do a little dance to + appease it. + - (djm) [regress/cert-userkey.sh] s/echo -n/echon/ here too + +20100302 + - (tim) [config.guess config.sub] Bug 1722: Update to latest versions from + http://git.savannah.gnu.org/gitweb/ (2009-12-30 and 2010-01-22 + respectively). + +20100301 + - (dtucker) [regress/{cert-hostkey,cfgmatch,cipher-speed}.sh} Replace + "echo -n" with "echon" for portability. + - (dtucker) [openbsd-compat/port-linux.c] Make failure to write to the OOM + adjust log at verbose only, since according to cjwatson in bug #1470 + some virtualization platforms don't allow writes. + +20100228 + - (djm) [auth.c] On Cygwin, refuse usernames that have differences in + case from that matched in the system password database. On this + platform, passwords are stored case-insensitively, but sshd requires + exact case matching for Match blocks in sshd_config(5). Based on + a patch from vinschen AT redhat.com. + - (tim) [ssh-pkcs11-helper.c] Move declarations before calling functions + to make older compilers (gcc 2.95) happy. + +20100227 + - (djm) [ssh-pkcs11-helper.c ] Ensure RNG is initialised and seeded + - (djm) [openbsd-compat/bsd-cygwin_util.c] Reduce the set of environment + variables copied into sshd child processes. From vinschen AT redhat.com + +20100226 + - OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/02/26 20:29:54 + [PROTOCOL PROTOCOL.agent PROTOCOL.certkeys addrmatch.c auth-options.c] + [auth-options.h auth.h auth2-pubkey.c authfd.c dns.c dns.h hostfile.c] + [hostfile.h kex.h kexdhs.c kexgexs.c key.c key.h match.h monitor.c] + [myproposal.h servconf.c servconf.h ssh-add.c ssh-agent.c ssh-dss.c] + [ssh-keygen.1 ssh-keygen.c ssh-rsa.c ssh.1 ssh.c ssh2.h sshconnect.c] + [sshconnect2.c sshd.8 sshd.c sshd_config.5] + Add support for certificate key types for users and hosts. + + OpenSSH certificate key types are not X.509 certificates, but a much + simpler format that encodes a public key, identity information and + some validity constraints and signs it with a CA key. CA keys are + regular SSH keys. This certificate style avoids the attack surface + of X.509 certificates and is very easy to deploy. + + Certified host keys allow automatic acceptance of new host keys + when a CA certificate is marked as trusted in ~/.ssh/known_hosts. + see VERIFYING HOST KEYS in ssh(1) for details. + + Certified user keys allow authentication of users when the signing + CA key is marked as trusted in authorized_keys. See "AUTHORIZED_KEYS + FILE FORMAT" in sshd(8) for details. + + Certificates are minted using ssh-keygen(1), documentation is in + the "CERTIFICATES" section of that manpage. + + Documentation on the format of certificates is in the file + PROTOCOL.certkeys + + feedback and ok markus@ + - djm@cvs.openbsd.org 2010/02/26 20:33:21 + [Makefile regress/cert-hostkey.sh regress/cert-userkey.sh] + regression tests for certified keys + +20100224 + - (djm) [pkcs11.h ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + [ssh-pkcs11.h] Add $OpenBSD$ RCS idents so we can sync portable + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/02/11 20:37:47 + [pathnames.h] + correct comment + - dtucker@cvs.openbsd.org 2009/11/09 04:20:04 + [regress/Makefile] + add regression test for ssh-keygen pubkey conversions + - dtucker@cvs.openbsd.org 2010/01/11 02:53:44 + [regress/forwarding.sh] + regress test for stdio forwarding + - djm@cvs.openbsd.org 2010/02/09 04:57:36 + [regress/addrmatch.sh] + clean up droppings + - djm@cvs.openbsd.org 2010/02/09 06:29:02 + [regress/Makefile] + turn on all the malloc(3) checking options when running regression + tests. this has caught a few bugs for me in the past; ok dtucker@ + - djm@cvs.openbsd.org 2010/02/24 06:21:56 + [regress/test-exec.sh] + wait for sshd to fully stop in cleanup() function; avoids races in tests + that do multiple start_sshd/cleanup cycles; "I hate pidfiles" deraadt@ + - markus@cvs.openbsd.org 2010/02/08 10:52:47 + [regress/agent-pkcs11.sh] + test for PKCS#11 support (currently disabled) + - (djm) [Makefile.in ssh-pkcs11-helper.8] Add manpage for PKCS#11 helper + - (djm) [contrib/caldera/openssh.spec contrib/redhat/openssh.spec] + [contrib/suse/openssh.spec] Add PKCS#11 helper binary and manpage + +20100212 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/02/02 22:49:34 + [bufaux.c] + make buffer_get_string_ret() really non-fatal in all cases (it was + using buffer_get_int(), which could fatal() on buffer empty); + ok markus dtucker + - markus@cvs.openbsd.org 2010/02/08 10:50:20 + [pathnames.h readconf.c readconf.h scp.1 sftp.1 ssh-add.1 ssh-add.c] + [ssh-agent.c ssh-keygen.1 ssh-keygen.c ssh.1 ssh.c ssh_config.5] + replace our obsolete smartcard code with PKCS#11. + ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf + ssh(1) and ssh-keygen(1) use dlopen(3) directly to talk to a PKCS#11 + provider (shared library) while ssh-agent(1) delegates PKCS#11 to + a forked a ssh-pkcs11-helper process. + PKCS#11 is currently a compile time option. + feedback and ok djm@; inspired by patches from Alon Bar-Lev + - jmc@cvs.openbsd.org 2010/02/08 22:03:05 + [ssh-add.1 ssh-keygen.1 ssh.1 ssh.c] + tweak previous; ok markus + - djm@cvs.openbsd.org 2010/02/09 00:50:36 + [ssh-agent.c] + fallout from PKCS#11: unbreak -D + - djm@cvs.openbsd.org 2010/02/09 00:50:59 + [ssh-keygen.c] + fix -Wall + - djm@cvs.openbsd.org 2010/02/09 03:56:28 + [buffer.c buffer.h] + constify the arguments to buffer_len, buffer_ptr and buffer_dump + - djm@cvs.openbsd.org 2010/02/09 06:18:46 + [auth.c] + unbreak ChrootDirectory+internal-sftp by skipping check for executable + shell when chrooting; reported by danh AT wzrd.com; ok dtucker@ + - markus@cvs.openbsd.org 2010/02/10 23:20:38 + [ssh-add.1 ssh-keygen.1 ssh.1 ssh_config.5] + pkcs#11 is no longer optional; improve wording; ok jmc@ + - jmc@cvs.openbsd.org 2010/02/11 13:23:29 + [ssh.1] + libarary -> library; + - (djm) [INSTALL Makefile.in README.smartcard configure.ac scard-opensc.c] + [scard.c scard.h pkcs11.h scard/Makefile.in scard/Ssh.bin.uu scard/Ssh.java] + Remove obsolete smartcard support + - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + Make it compile on OSX + - (djm) [ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c] + Use ssh_get_progname to fill __progname + - (djm) [configure.ac] Enable PKCS#11 support only when we find a working + dlopen() + +20100210 + - (djm) add -lselinux to LIBS before calling AC_CHECK_FUNCS for + getseuserbyname; patch from calebcase AT gmail.com via + cjwatson AT debian.org + +20100202 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/01/30 21:08:33 + [sshd.8] + debug output goes to stderr, not "the system log"; ok markus dtucker + - djm@cvs.openbsd.org 2010/01/30 21:12:08 + [channels.c] + fake local addr:port when stdio fowarding as some servers (Tectia at + least) validate that they are well-formed; + reported by imorgan AT nas.nasa.gov + ok dtucker + +20100130 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/01/28 00:21:18 + [clientloop.c] + downgrade an error() to a debug() - this particular case can be hit in + normal operation for certain sequences of mux slave vs session closure + and is harmless + - djm@cvs.openbsd.org 2010/01/29 00:20:41 + [sshd.c] + set FD_CLOEXEC on sock_in/sock_out; bz#1706 from jchadima AT redhat.com + ok dtucker@ + - djm@cvs.openbsd.org 2010/01/29 20:16:17 + [mux.c] + kill correct channel (was killing already-dead mux channel, not + its session channel) + - djm@cvs.openbsd.org 2010/01/30 02:54:53 + [mux.c] + don't mark channel as read failed if it is already closing; suppresses + harmless error messages when connecting to SSH.COM Tectia server + report by imorgan AT nas.nasa.gov + +20100129 + - (dtucker) [openbsd-compat/openssl-compat.c] Bug #1707: Call OPENSSL_config() + after registering the hardware engines, which causes the openssl.cnf file to + be processed. See OpenSSL's man page for OPENSSL_config(3) for details. + Patch from Solomon Peachy, ok djm@. + +20100128 + - (djm) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/01/26 02:15:20 + [mux.c] + -Wuninitialized and remove a // comment; from portable + (Id sync only) + - djm@cvs.openbsd.org 2010/01/27 13:26:17 + [mux.c] + fix bug introduced in mux rewrite: + + In a mux master, when a socket to a mux slave closes before its server + session (as may occur when the slave has been signalled), gracefully + close the server session rather than deleting its channel immediately. + A server may have more messages on that channel to send (e.g. an exit + message) that will fatal() the client if they are sent to a channel that + has been prematurely deleted. + + spotted by imorgan AT nas.nasa.gov + - djm@cvs.openbsd.org 2010/01/27 19:21:39 + [sftp.c] + add missing "p" flag to getopt optstring; + bz#1704 from imorgan AT nas.nasa.gov + +20100126 + - (djm) OpenBSD CVS Sync + - tedu@cvs.openbsd.org 2010/01/17 21:49:09 + [ssh-agent.1] + Correct and clarify ssh-add's password asking behavior. + Improved text dtucker and ok jmc + - dtucker@cvs.openbsd.org 2010/01/18 01:50:27 + [roaming_client.c] + s/long long unsigned/unsigned long long/, from tim via portable + (Id sync only, change already in portable) + - djm@cvs.openbsd.org 2010/01/26 01:28:35 + [channels.c channels.h clientloop.c clientloop.h mux.c nchan.c ssh.c] + rewrite ssh(1) multiplexing code to a more sensible protocol. + + The new multiplexing code uses channels for the listener and + accepted control sockets to make the mux master non-blocking, so + no stalls when processing messages from a slave. + + avoid use of fatal() in mux master protocol parsing so an errant slave + process cannot take down a running master. + + implement requesting of port-forwards over multiplexed sessions. Any + port forwards requested by the slave are added to those the master has + established. + + add support for stdio forwarding ("ssh -W host:port ...") in mux slaves. + + document master/slave mux protocol so that other tools can use it to + control a running ssh(1). Note: there are no guarantees that this + protocol won't be incompatibly changed (though it is versioned). + + feedback Salvador Fandino, dtucker@ + channel changes ok markus@ + +20100122 + - (tim) [configure.ac] Due to constraints in Windows Sockets in terms of + socket inheritance, reduce the default SO_RCVBUF/SO_SNDBUF buffer size + in Cygwin to 65535. Patch from Corinna Vinschen. + +20100117 + - (tim) [configure.ac] OpenServer 5 needs BROKEN_GETADDRINFO too. + - (tim) [configure.ac] On SVR5 systems, use the C99-conforming functions + snprintf() and vsnprintf() named _xsnprintf() and _xvsnprintf(). + +20100116 + - (dtucker) [openbsd-compat/pwcache.c] Pull in includes.h and thus defines.h + so we correctly detect whether or not we have a native user_from_uid. + - (dtucker) [openbsd-compat/openbsd-compat.h] Prototypes for user_from_uid + and group_from_gid. + - (dtucker) [openbsd-compat/openbsd-compat.h] Fix prototypes, spotted by + Tim. + - (dtucker) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2010/01/15 09:24:23 + [sftp-common.c] + unused + - (dtucker) [openbsd-compat/pwcache.c] Shrink ifdef area to prevent unused + variable warnings. + - (dtucker) [openbsd-compat/openbsd-compat.h] Typo. + - (tim) [regress/portnum.sh] Shell portability fix. + - (tim) [configure.ac] Define BROKEN_GETADDRINFO on SVR5 systems. The native + getaddrinfo() is too old and limited for addr_pton() in addrmatch.c. + - (tim) [roaming_client.c] Use of is not really portable so we + use "openbsd-compat/sys-queue.h". s/long long unsigned/unsigned long long/ + to keep USL compilers happy. + +20100115 + - (dtucker) OpenBSD CVS Sync + - jmc@cvs.openbsd.org 2010/01/13 12:48:34 + [sftp.1 sftp.c] + sftp.1: put ls -h in the right place + sftp.c: as above, plus add -p to get/put, and shorten their arg names + to keep the help usage nicely aligned + ok djm + - djm@cvs.openbsd.org 2010/01/13 23:47:26 + [auth.c] + when using ChrootDirectory, make sure we test for the existence of the + user's shell inside the chroot; bz #1679, patch from alex AT rtfs.hu; + ok dtucker + - dtucker@cvs.openbsd.org 2010/01/14 23:41:49 + [sftp-common.c] + use user_from{uid,gid} to lookup up ids since it keeps a small cache. + ok djm + - guenther@cvs.openbsd.org 2010/01/15 00:05:22 + [sftp.c] + Reset SIGTERM to SIG_DFL before executing ssh, so that even if sftp + inherited SIGTERM as ignored it will still be able to kill the ssh it + starts. + ok dtucker@ + - (dtucker) [openbsd-compat/pwcache.c] Pull in pwcache.c from OpenBSD (no + changes yet but there will be some to come). + - (dtucker) [configure.ac openbsd-compat/{Makefile.in,pwcache.c} Portability + for pwcache. Also, added caching of negative hits. + +20100114 + - (djm) [platform.h] Add missing prototype for + platform_krb5_get_principal_name + +20100113 + - (dtucker) [monitor_fdpass.c] Wrap poll.h include in ifdefs. + - (dtucker) [openbsd-compat/readpassphrase.c] Resync against OpenBSD's r1.18: + missing restore of SIGTTOU and some whitespace. + - (dtucker) [openbsd-compat/readpassphrase.c] Update to OpenBSD's r1.21. + - (dtucker) [openbsd-compat/readpassphrase.c] Update to OpenBSD's r1.22. + Fixes bz #1590, where sometimes you could not interrupt a connection while + ssh was prompting for a passphrase or password. + - (dtucker) OpenBSD CVS Sync + - dtucker@cvs.openbsd.org 2010/01/13 00:19:04 + [sshconnect.c auth.c] + Fix a couple of typos/mispellings in comments + - dtucker@cvs.openbsd.org 2010/01/13 01:10:56 + [key.c] + Ignore and log any Protocol 1 keys where the claimed size is not equal to + the actual size. Noted by Derek Martin, ok djm@ + - dtucker@cvs.openbsd.org 2010/01/13 01:20:20 + [canohost.c ssh-keysign.c sshconnect2.c] + Make HostBased authentication work with a ProxyCommand. bz #1569, patch + from imorgan at nas nasa gov, ok djm@ + - djm@cvs.openbsd.org 2010/01/13 01:40:16 + [sftp.c sftp-server.c sftp.1 sftp-common.c sftp-common.h] + support '-h' (human-readable units) for sftp's ls command, just like + ls(1); ok dtucker@ + - djm@cvs.openbsd.org 2010/01/13 03:48:13 + [servconf.c servconf.h sshd.c] + avoid run-time failures when specifying hostkeys via a relative + path by prepending the cwd in these cases; bz#1290; ok dtucker@ + - djm@cvs.openbsd.org 2010/01/13 04:10:50 + [sftp.c] + don't append a space after inserting a completion of a directory (i.e. + a path ending in '/') for a slightly better user experience; ok dtucker@ + - (dtucker) [sftp-common.c] Wrap include of util.h in an ifdef. + - (tim) [defines.h] openbsd-compat/readpassphrase.c now needs _NSIG. + feedback and ok dtucker@ + +20100112 + - (dtucker) OpenBSD CVS Sync + - dtucker@cvs.openbsd.org 2010/01/11 01:39:46 + [ssh_config channels.c ssh.1 channels.h ssh.c] + Add a 'netcat mode' (ssh -W). This connects stdio on the client to a + single port forward on the server. This allows, for example, using ssh as + a ProxyCommand to route connections via intermediate servers. + bz #1618, man page help from jmc@, ok markus@ + - dtucker@cvs.openbsd.org 2010/01/11 04:46:45 + [authfile.c sshconnect2.c] + Do not prompt for a passphrase if we fail to open a keyfile, and log the + reason the open failed to debug. + bz #1693, found by tj AT castaglia org, ok djm@ + - djm@cvs.openbsd.org 2010/01/11 10:51:07 + [ssh-keygen.c] + when converting keys, truncate key comments at 72 chars as per RFC4716; + bz#1630 reported by tj AT castaglia.org; ok markus@ + - dtucker@cvs.openbsd.org 2010/01/12 00:16:47 + [authfile.c] + Fix bug introduced in r1.78 (incorrect brace location) that broke key auth. + Patch from joachim joachimschipper nl. + - djm@cvs.openbsd.org 2010/01/12 00:58:25 + [monitor_fdpass.c] + avoid spinning when fd passing on nonblocking sockets by calling poll() + in the EINTR/EAGAIN path, much like we do in atomicio; ok dtucker@ + - djm@cvs.openbsd.org 2010/01/12 00:59:29 + [roaming_common.c] + delete with extreme prejudice a debug() that fired with every keypress; + ok dtucker deraadt + - dtucker@cvs.openbsd.org 2010/01/12 01:31:05 + [session.c] + Do not allow logins if /etc/nologin exists but is not readable by the user + logging in. Noted by Jan.Pechanec at Sun, ok djm@ deraadt@ + - djm@cvs.openbsd.org 2010/01/12 01:36:08 + [buffer.h bufaux.c] + add a buffer_get_string_ptr_ret() that does the same as + buffer_get_string_ptr() but does not fatal() on error; ok dtucker@ + - dtucker@cvs.openbsd.org 2010/01/12 08:33:17 + [session.c] + Add explicit stat so we reliably detect nologin with bad perms. + ok djm markus + +20100110 + - (dtucker) [configure.ac misc.c readconf.c servconf.c ssh-keyscan.c] + Remove hacks add for RoutingDomain in preparation for its removal. + - (dtucker) OpenBSD CVS Sync + - dtucker@cvs.openbsd.org 2010/01/09 23:04:13 + [channels.c ssh.1 servconf.c sshd_config.5 sshd.c channels.h servconf.h + ssh-keyscan.1 ssh-keyscan.c readconf.c sshconnect.c misc.c ssh.c + readconf.h scp.1 sftp.1 ssh_config.5 misc.h] + Remove RoutingDomain from ssh since it's now not needed. It can be + replaced with "route exec" or "nc -V" as a proxycommand. "route exec" + also ensures that trafic such as DNS lookups stays withing the specified + routingdomain. For example (from reyk): + # route -T 2 exec /usr/sbin/sshd + or inherited from the parent process + $ route -T 2 exec sh + $ ssh 10.1.2.3 + ok deraadt@ markus@ stevesk@ reyk@ + - dtucker@cvs.openbsd.org 2010/01/10 03:51:17 + [servconf.c] + Add ChrootDirectory to sshd.c test-mode output + - dtucker@cvs.openbsd.org 2010/01/10 07:15:56 + [auth.c] + Output a debug if we can't open an existing keyfile. bz#1694, ok djm@ + +20100109 + - (dtucker) Wrap use of IPPROTO_IPV6 in an ifdef for platforms that don't + have it. + - (dtucker) [defines.h] define PRIu64 for platforms that don't have it. + - (dtucker) [roaming_client.c] Wrap inttypes.h in an ifdef. + - (dtucker) [loginrec.c] Use the SUSv3 specified name for the user name + when using utmpx. Patch from Ed Schouten. + - (dtucker) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2010/01/09 00:20:26 + [sftp-server.c sftp-server.8] + add a 'read-only' mode to sftp-server(8) that disables open in write mode + and all other fs-modifying protocol methods. bz#430 ok dtucker@ + - djm@cvs.openbsd.org 2010/01/09 00:57:10 + [PROTOCOL] + tweak language + - jmc@cvs.openbsd.org 2010/01/09 03:36:00 + [sftp-server.8] + bad place to forget a comma... + - djm@cvs.openbsd.org 2010/01/09 05:04:24 + [mux.c sshpty.h clientloop.c sshtty.c] + quell tc[gs]etattr warnings when forcing a tty (ssh -tt), since we + usually don't actually have a tty to read/set; bz#1686 ok dtucker@ + - dtucker@cvs.openbsd.org 2010/01/09 05:17:00 + [roaming_client.c] + Remove a PRIu64 format string that snuck in with roaming. ok djm@ + - dtucker@cvs.openbsd.org 2010/01/09 11:13:02 + [sftp.c] + Prevent sftp from derefing a null pointer when given a "-" without a + command. Also, allow whitespace to follow a "-". bz#1691, path from + Colin Watson via Debian. ok djm@ deraadt@ + - dtucker@cvs.openbsd.org 2010/01/09 11:17:56 + [sshd.c] + Afer sshd receives a SIGHUP, ignore subsequent HUPs while sshd re-execs + itself. Prevents two HUPs in quick succession from resulting in sshd + dying. bz#1692, patch from Colin Watson via Ubuntu. + - (dtucker) [defines.h] Remove now-undeeded PRIu64 define. + +20100108 + - (dtucker) OpenBSD CVS Sync + - andreas@cvs.openbsd.org 2009/10/24 11:11:58 + [roaming.h] + Declarations needed for upcoming changes. + ok markus@ + - andreas@cvs.openbsd.org 2009/10/24 11:13:54 + [sshconnect2.c kex.h kex.c] + Let the client detect if the server supports roaming by looking + for the resume@appgate.com kex algorithm. + ok markus@ + - andreas@cvs.openbsd.org 2009/10/24 11:15:29 + [clientloop.c] + client_loop() must detect if the session has been suspended and resumed, + and take appropriate action in that case. + From Martin Forssen, maf at appgate dot com + - andreas@cvs.openbsd.org 2009/10/24 11:19:17 + [ssh2.h] + Define the KEX messages used when resuming a suspended connection. + ok markus@ + - andreas@cvs.openbsd.org 2009/10/24 11:22:37 + [roaming_common.c] + Do the actual suspend/resume in the client. This won't be useful until + the server side supports roaming. + Most code from Martin Forssen, maf at appgate dot com. Some changes by + me and markus@ + ok markus@ + - andreas@cvs.openbsd.org 2009/10/24 11:23:42 + [ssh.c] + Request roaming to be enabled if UseRoaming is true and the server + supports it. + ok markus@ + - reyk@cvs.openbsd.org 2009/10/28 16:38:18 + [ssh_config.5 sshd.c misc.h ssh-keyscan.1 readconf.h sshconnect.c + channels.c channels.h servconf.h servconf.c ssh.1 ssh-keyscan.c scp.1 + sftp.1 sshd_config.5 readconf.c ssh.c misc.c] + Allow to set the rdomain in ssh/sftp/scp/sshd and ssh-keyscan. + ok markus@ + - jmc@cvs.openbsd.org 2009/10/28 21:45:08 + [sshd_config.5 sftp.1] + tweak previous; + - djm@cvs.openbsd.org 2009/11/10 02:56:22 + [ssh_config.5] + explain the constraints on LocalCommand some more so people don't + try to abuse it. + - djm@cvs.openbsd.org 2009/11/10 02:58:56 + [sshd_config.5] + clarify that StrictModes does not apply to ChrootDirectory. Permissions + and ownership are always checked when chrooting. bz#1532 + - dtucker@cvs.openbsd.org 2009/11/10 04:30:45 + [sshconnect2.c channels.c sshconnect.c] + Set close-on-exec on various descriptors so they don't get leaked to + child processes. bz #1643, patch from jchadima at redhat, ok deraadt. + - markus@cvs.openbsd.org 2009/11/11 21:37:03 + [channels.c channels.h] + fix race condition in x11/agent channel allocation: don't read after + the end of the select read/write fdset and make sure a reused FD + is not touched before the pre-handlers are called. + with and ok djm@ + - djm@cvs.openbsd.org 2009/11/17 05:31:44 + [clientloop.c] + fix incorrect exit status when multiplexing and channel ID 0 is recycled + bz#1570 reported by peter.oliver AT eon-is.co.uk; ok dtucker + - djm@cvs.openbsd.org 2009/11/19 23:39:50 + [session.c] + bz#1606: error when an attempt is made to connect to a server + with ForceCommand=internal-sftp with a shell session (i.e. not a + subsystem session). Avoids stuck client when attempting to ssh to such a + service. ok dtucker@ + - dtucker@cvs.openbsd.org 2009/11/20 00:15:41 + [session.c] + Warn but do not fail if stat()ing the subsystem binary fails. This helps + with chrootdirectory+forcecommand=sftp-server and restricted shells. + bz #1599, ok djm. + - djm@cvs.openbsd.org 2009/11/20 00:54:01 + [sftp.c] + bz#1588 change "Connecting to host..." message to "Connected to host." + and delay it until after the sftp protocol connection has been established. + Avoids confusing sequence of messages when the underlying ssh connection + experiences problems. ok dtucker@ + - dtucker@cvs.openbsd.org 2009/11/20 00:59:36 + [sshconnect2.c] + Use the HostKeyAlias when prompting for passwords. bz#1039, ok djm@ + - djm@cvs.openbsd.org 2009/11/20 03:24:07 + [misc.c] + correct off-by-one in percent_expand(): we would fatal() when trying + to expand EXPAND_MAX_KEYS, allowing only EXPAND_MAX_KEYS-1 to actually + work. Note that nothing in OpenSSH actually uses close to this limit at + present. bz#1607 from Jan.Pechanec AT Sun.COM + - halex@cvs.openbsd.org 2009/11/22 13:18:00 + [sftp.c] + make passing of zero-length arguments to ssh safe by + passing "-" "" rather than "-" + ok dtucker@, guenther@, djm@ + - dtucker@cvs.openbsd.org 2009/12/06 23:41:15 + [sshconnect2.c] + zap unused variable and strlen; from Steve McClellan, ok djm + - djm@cvs.openbsd.org 2009/12/06 23:53:45 + [roaming_common.c] + use socklen_t for getsockopt optlen parameter; reported by + Steve.McClellan AT radisys.com, ok dtucker@ + - dtucker@cvs.openbsd.org 2009/12/06 23:53:54 + [sftp.c] + fix potential divide-by-zero in sftp's "df" output when talking to a server + that reports zero files on the filesystem (Unix filesystems always have at + least the root inode). From Steve McClellan at radisys, ok djm@ + - markus@cvs.openbsd.org 2009/12/11 18:16:33 + [key.c] + switch from 35 to the more common value of RSA_F4 == (2**16)+1 == 65537 + for the RSA public exponent; discussed with provos; ok djm@ + - guenther@cvs.openbsd.org 2009/12/20 07:28:36 + [ssh.c sftp.c scp.c] + When passing user-controlled options with arguments to other programs, + pass the option and option argument as separate argv entries and + not smashed into one (e.g., as -l foo and not -lfoo). Also, always + pass a "--" argument to stop option parsing, so that a positional + argument that starts with a '-' isn't treated as an option. This + fixes some error cases as well as the handling of hostnames and + filenames that start with a '-'. + Based on a diff by halex@ + ok halex@ djm@ deraadt@ + - djm@cvs.openbsd.org 2009/12/20 23:20:40 + [PROTOCOL] + fix an incorrect magic number and typo in PROTOCOL; bz#1688 + report and fix from ueno AT unixuser.org + - stevesk@cvs.openbsd.org 2009/12/25 19:40:21 + [readconf.c servconf.c misc.h ssh-keyscan.c misc.c] + validate routing domain is in range 0-RT_TABLEID_MAX. + 'Looks right' deraadt@ + - stevesk@cvs.openbsd.org 2009/12/29 16:38:41 + [sshd_config.5 readconf.c ssh_config.5 scp.1 servconf.c sftp.1 ssh.1] + Rename RDomain config option to RoutingDomain to be more clear and + consistent with other options. + NOTE: if you currently use RDomain in the ssh client or server config, + or ssh/sshd -o, you must update to use RoutingDomain. + ok markus@ djm@ + - jmc@cvs.openbsd.org 2009/12/29 18:03:32 + [sshd_config.5 ssh_config.5] + sort previous; + - dtucker@cvs.openbsd.org 2010/01/04 01:45:30 + [sshconnect2.c] + Don't escape backslashes in the SSH2 banner. bz#1533, patch from + Michal Gorny via Gentoo. + - djm@cvs.openbsd.org 2010/01/04 02:03:57 + [sftp.c] + Implement tab-completion of commands, local and remote filenames for sftp. + Hacked on and off for some time by myself, mouring, Carlos Silva (via 2009 + Google Summer of Code) and polished to a fine sheen by myself again. + It should deal more-or-less correctly with the ikky corner-cases presented + by quoted filenames, but the UI could still be slightly improved. + In particular, it is quite slow for remote completion on large directories. + bz#200; ok markus@ + - djm@cvs.openbsd.org 2010/01/04 02:25:15 + [sftp-server.c] + bz#1566 don't unnecessarily dup() in and out fds for sftp-server; + ok markus@ + - dtucker@cvs.openbsd.org 2010/01/08 21:50:49 + [sftp.c] + Fix two warnings: possibly used unitialized and use a nul byte instead of + NULL pointer. ok djm@ + - (dtucker) [Makefile.in added roaming_client.c roaming_serv.c] Import new + files for roaming and add to Makefile. + - (dtucker) [Makefile.in] .c files do not belong in the OBJ lines. + - (dtucker) [sftp.c] ifdef out the sftp completion bits for platforms that + don't have libedit. + - (dtucker) [configure.ac misc.c readconf.c servconf.c ssh-keyscan.c] Make + RoutingDomain an unsupported option on platforms that don't have it. + - (dtucker) [sftp.c] Expand ifdef for libedit to cover complete_is_remote + too. + - (dtucker) [misc.c] Move the routingdomain ifdef to allow the socket to + be created. + - (dtucker] [misc.c] Shrink the area covered by USE_ROUTINGDOMAIN more + to eliminate an unused variable warning. + - (dtucker) [roaming_serv.c] Include includes.h for u_intXX_t types. + +20091226 + - (tim) [contrib/cygwin/Makefile] Install ssh-copy-id and ssh-copy-id.1 + Gzip all man pages. Patch from Corinna Vinschen. + +20091221 + - (dtucker) [auth-krb5.c platform.{c,h} openbsd-compat/port-aix.{c,h}] + Bug #1583: Use system's kerberos principal name on AIX if it's available. + Based on a patch from and tested by Miguel Sanders + +20091208 + - (dtucker) Bug #1470: Disable OOM-killing of the listening sshd on Linux, + based on a patch from Vaclav Ovsik and Colin Watson. ok djm. + +20091207 + - (dtucker) Bug #1160: use pkg-config for opensc config if it's available. + Tested by Martin Paljak. + - (dtucker) Bug #1677: add conditionals around the source for ssh-askpass. + +20091121 + - (tim) [opensshd.init.in] If PidFile is set in sshd_config, use it. + Bug 1628. OK dtucker@ + +20091120 + - (djm) [ssh-rand-helper.c] Print error and usage() when passed command- + line arguments as none are supported. Exit when passed unrecognised + commandline flags. bz#1568 from gson AT araneus.fi + +20091118 + - (djm) [channels.c misc.c misc.h sshd.c] add missing setsockopt() to + set IPV6_V6ONLY for local forwarding with GatwayPorts=yes. Unify + setting IPV6_V6ONLY behind a new function misc.c:sock_set_v6only() + bz#1648, report and fix from jan.kratochvil AT redhat.com + - (djm) [contrib/gnome-ssh-askpass2.c] Make askpass dialog desktop-modal. + bz#1645, patch from jchadima AT redhat.com + +20091107 + - (dtucker) [authfile.c] Fall back to 3DES for the encryption of private + keys when built with OpenSSL versions that don't do AES. + +20091105 + - (dtucker) [authfile.c] Add OpenSSL compat header so this still builds with + older versions of OpenSSL. + +20091024 + - (dtucker) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2009/10/11 23:03:15 + [hostfile.c] + mention the host name that we are looking for in check_host_in_hostfile() + - sobrado@cvs.openbsd.org 2009/10/17 12:10:39 + [sftp-server.c] + sort flags. + - sobrado@cvs.openbsd.org 2009/10/22 12:35:53 + [ssh.1 ssh-agent.1 ssh-add.1] + use the UNIX-related macros (.At and .Ux) where appropriate. + ok jmc@ + - sobrado@cvs.openbsd.org 2009/10/22 15:02:12 + [ssh-agent.1 ssh-add.1 ssh.1] + write UNIX-domain in a more consistent way; while here, replace a + few remaining ".Tn UNIX" macros with ".Ux" ones. + pointed out by ratchov@, thanks! + ok jmc@ + - djm@cvs.openbsd.org 2009/10/22 22:26:13 + [authfile.c] + switch from 3DES to AES-128 for encryption of passphrase-protected + SSH protocol 2 private keys; ok several + - djm@cvs.openbsd.org 2009/10/23 01:57:11 + [sshconnect2.c] + disallow a hostile server from checking jpake auth by sending an + out-of-sequence success message. (doesn't affect code enabled by default) + - dtucker@cvs.openbsd.org 2009/10/24 00:48:34 + [ssh-keygen.1] + ssh-keygen now uses AES-128 for private keys + - (dtucker) [mdoc2man.awk] Teach it to understand the .Ux macro. + - (dtucker) [session.c openbsd-compat/port-linux.{c,h}] Bug #1637: if selinux + is enabled set the security context to "sftpd_t" before running the + internal sftp server Based on a patch from jchadima at redhat. + +20091011 + - (dtucker) [configure.ac sftp-client.c] Remove the gyrations required for + dirent d_type and DTTOIF as we've switched OpenBSD to the more portable + lstat. + - (dtucker) OpenBSD CVS Sync + - markus@cvs.openbsd.org 2009/10/08 14:03:41 + [sshd_config readconf.c ssh_config.5 servconf.c sshd_config.5] + disable protocol 1 by default (after a transition period of about 10 years) + ok deraadt + - jmc@cvs.openbsd.org 2009/10/08 20:42:12 + [sshd_config.5 ssh_config.5 sshd.8 ssh.1] + some tweaks now that protocol 1 is not offered by default; ok markus + - dtucker@cvs.openbsd.org 2009/10/11 10:41:26 + [sftp-client.c] + d_type isn't portable so use lstat to get dirent modes. Suggested by and + "looks sane" deraadt@ + - markus@cvs.openbsd.org 2009/10/08 18:04:27 + [regress/test-exec.sh] + re-enable protocol v1 for the tests. + +20091007 + - (dtucker) OpenBSD CVS Sync + - djm@cvs.openbsd.org 2009/08/12 00:13:00 + [sftp.c sftp.1] + support most of scp(1)'s commandline arguments in sftp(1), as a first + step towards making sftp(1) a drop-in replacement for scp(1). + One conflicting option (-P) has not been changed, pending further + discussion. + Patch from carlosvsilvapt@gmail.com as part of his work in the + Google Summer of Code + - jmc@cvs.openbsd.org 2009/08/12 06:31:42 + [sftp.1] + sort options; + - djm@cvs.openbsd.org 2009/08/13 01:11:19 + [sftp.1 sftp.c] + Swizzle options: "-P sftp_server_path" moves to "-D sftp_server_path", + add "-P port" to match scp(1). Fortunately, the -P option is only really + used by our regression scripts. + part of larger patch from carlosvsilvapt@gmail.com for his Google Summer + of Code work; ok deraadt markus + - jmc@cvs.openbsd.org 2009/08/13 13:39:54 + [sftp.1 sftp.c] + sync synopsis and usage(); + - djm@cvs.openbsd.org 2009/08/14 18:17:49 + [sftp-client.c] + make the "get_handle: ..." error messages vaguely useful by allowing + callers to specify their own error message strings. + - fgsch@cvs.openbsd.org 2009/08/15 18:56:34 + [auth.h] + remove unused define. markus@ ok. + (Id sync only, Portable still uses this.) + - dtucker@cvs.openbsd.org 2009/08/16 23:29:26 + [sshd_config.5] + Add PubkeyAuthentication to the list allowed in a Match block (bz #1577) + - djm@cvs.openbsd.org 2009/08/18 18:36:21 + [sftp-client.h sftp.1 sftp-client.c sftp.c] + recursive transfer support for get/put and on the commandline + work mostly by carlosvsilvapt@gmail.com for the Google Summer of Code + with some tweaks by me; "go for it" deraadt@ + - djm@cvs.openbsd.org 2009/08/18 21:15:59 + [sftp.1] + fix "get" command usage, spotted by jmc@ + - jmc@cvs.openbsd.org 2009/08/19 04:56:03 + [sftp.1] + ether -> either; + - dtucker@cvs.openbsd.org 2009/08/20 23:54:28 + [mux.c] + subsystem_flag is defined in ssh.c so it's extern; ok djm + - djm@cvs.openbsd.org 2009/08/27 17:28:52 + [sftp-server.c] + allow setting an explicit umask on the commandline to override whatever + default the user has. bz#1229; ok dtucker@ deraadt@ markus@ + - djm@cvs.openbsd.org 2009/08/27 17:33:49 + [ssh-keygen.c] + force use of correct hash function for random-art signature display + as it was inheriting the wrong one when bubblebabble signatures were + activated; bz#1611 report and patch from fwojcik+openssh AT besh.com; + ok markus@ + - djm@cvs.openbsd.org 2009/08/27 17:43:00 + [sftp-server.8] + allow setting an explicit umask on the commandline to override whatever + default the user has. bz#1229; ok dtucker@ deraadt@ markus@ + - djm@cvs.openbsd.org 2009/08/27 17:44:52 + [authfd.c ssh-add.c authfd.h] + Do not fall back to adding keys without contraints (ssh-add -c / -t ...) + when the agent refuses the constrained add request. This was a useful + migration measure back in 2002 when constraints were new, but just + adds risk now. + bz #1612, report and patch from dkg AT fifthhorseman.net; ok markus@ + - djm@cvs.openbsd.org 2009/08/31 20:56:02 + [sftp-server.c] + check correct variable for error message, spotted by martynas@ + - djm@cvs.openbsd.org 2009/08/31 21:01:29 + [sftp-server.8] + document -e and -h; prodded by jmc@ + - djm@cvs.openbsd.org 2009/09/01 14:43:17 + [ssh-agent.c] + fix a race condition in ssh-agent that could result in a wedged or + spinning agent: don't read off the end of the allocated fd_sets, and + don't issue blocking read/write on agent sockets - just fall back to + select() on retriable read/write errors. bz#1633 reported and tested + by "noodle10000 AT googlemail.com"; ok dtucker@ markus@ + - grunk@cvs.openbsd.org 2009/10/01 11:37:33 + [dh.c] + fix a cast + ok djm@ markus@ + - djm@cvs.openbsd.org 2009/10/06 04:46:40 + [session.c] + bz#1596: fflush(NULL) before exec() to ensure that everying (motd + in particular) has made it out before the streams go away. + - djm@cvs.openbsd.org 2008/12/07 22:17:48 + [regress/addrmatch.sh] + match string "passwordauthentication" only at start of line, not anywhere + in sshd -T output + - dtucker@cvs.openbsd.org 2009/05/05 07:51:36 + [regress/multiplex.sh] + Always specify ssh_config for multiplex tests: prevents breakage caused + by options in ~/.ssh/config. From Dan Peterson. + - djm@cvs.openbsd.org 2009/08/13 00:57:17 + [regress/Makefile] + regression test for port number parsing. written as part of the a2port + change that went into 5.2 but I forgot to commit it at the time... + - djm@cvs.openbsd.org 2009/08/13 01:11:55 + [regress/sftp-batch.sh regress/sftp-badcmds.sh regress/sftp.sh + regress/sftp-cmds.sh regres/sftp-glob.sh] + date: 2009/08/13 01:11:19; author: djm; state: Exp; lines: +10 -7 + Swizzle options: "-P sftp_server_path" moves to "-D sftp_server_path", + add "-P port" to match scp(1). Fortunately, the -P option is only really + used by our regression scripts. + part of larger patch from carlosvsilvapt@gmail.com for his Google Summer + of Code work; ok deraadt markus + - djm@cvs.openbsd.org 2009/08/20 18:43:07 + [regress/ssh-com-sftp.sh] + fix one sftp -D ... => sftp -P ... conversion that I missed; from Carlos + Silva for Google Summer of Code + - dtucker@cvs.openbsd.org 2009/10/06 23:51:49 + [regress/ssh2putty.sh] + Add OpenBSD tag to make syncs easier + - (dtucker) [regress/portnum.sh] Import new test. + - (dtucker) [configure.ac sftp-client.c] DTOTIF is in fs/ffs/dir.h on at + least dragonflybsd. + - (dtucker) d_type is not mandated by POSIX, so add fallback code using + stat(), needed on at least cygwin. + +20091002 + - (djm) [Makefile.in] Mention readconf.o in ssh-keysign's make deps. + spotted by des AT des.no + +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 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 diff --git a/crypto/openssh/INSTALL b/crypto/openssh/INSTALL index 001ebb666..09dfd666d 100644 --- a/crypto/openssh/INSTALL +++ b/crypto/openssh/INSTALL @@ -208,10 +208,6 @@ are installed. --with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to real (AF_INET) IPv4 addresses. Works around some quirks on Linux. ---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: @@ -266,4 +262,4 @@ 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 $ +$Id: INSTALL,v 1.85 2010/02/11 22:34:22 djm Exp $ diff --git a/crypto/openssh/PROTOCOL b/crypto/openssh/PROTOCOL index 5aada630d..5fc31eade 100644 --- a/crypto/openssh/PROTOCOL +++ b/crypto/openssh/PROTOCOL @@ -6,8 +6,8 @@ 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. +Newer versions of the draft will not be supported, though some features +are individually implemented as extensions described below. The protocol used by OpenSSH's ssh-agent is described in the file PROTOCOL.agent @@ -31,7 +31,14 @@ 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" +3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com" and + "ssh-dsa-cert-v00@openssh.com" + +OpenSSH introduces two new public key algorithms to support certificate +authentication for users and hostkeys. These methods are documented in +the file PROTOCOL.certkeys + +4. 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 @@ -70,7 +77,7 @@ 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 +5. connection: disallow additional sessions extension "no-more-sessions@openssh.com" Most SSH connections will only ever request a single session, but a @@ -98,7 +105,7 @@ 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" +6. 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 @@ -121,10 +128,10 @@ layer 2 frames or layer 3 packets. It may take one of the following values: 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. +be 0x7fffffff to allow the server to automatically chose an interface. A +server that is not willing to open a client-specified unit should refuse +the request with a SSH_MSG_CHANNEL_OPEN_FAILURE error. On successful +open, the server should reply with SSH_MSG_CHANNEL_OPEN_SUCCESS. Once established the client and server may exchange packet or frames over the tunnel channel by encapsulating them in SSH protocol strings @@ -151,7 +158,7 @@ It may be one of: 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: +The contents of the "data" field for layer 2 packets is: uint32 packet length byte[packet length] frame @@ -159,7 +166,7 @@ The contents of the "data" field for layer 3 packets is: The "frame" field contains an IEEE 802.3 Ethernet frame, including header. -6. sftp: Reversal of arguments to SSH_FXP_SYMLINK +7. 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, @@ -172,7 +179,7 @@ SSH_FXP_SYMLINK as follows: string targetpath string linkpath -7. sftp: Server extension announcement in SSH_FXP_VERSION +8. 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 @@ -193,7 +200,7 @@ 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" +9. 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 @@ -210,7 +217,7 @@ 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 +10. sftp: Extension requests "statvfs@openssh.com" and "fstatvfs@openssh.com" These requests correspond to the statvfs and fstatvfs POSIX system @@ -251,4 +258,4 @@ The values of the f_flag bitmask are as follows: 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 $ +$OpenBSD: PROTOCOL,v 1.15 2010/02/26 20:29:54 djm Exp $ diff --git a/crypto/openssh/PROTOCOL.agent b/crypto/openssh/PROTOCOL.agent index 49adbdd5c..b34fcd318 100644 --- a/crypto/openssh/PROTOCOL.agent +++ b/crypto/openssh/PROTOCOL.agent @@ -173,6 +173,15 @@ be added using the following request string key_comment constraint[] key_constraints +DSA certificates may be added with: + byte SSH2_AGENTC_ADD_IDENTITY or + SSH2_AGENTC_ADD_ID_CONSTRAINED + string "ssh-dss-cert-v00@openssh.com" + string certificate + mpint dsa_private_key + string key_comment + constraint[] key_constraints + RSA keys may be added with this request: byte SSH2_AGENTC_ADD_IDENTITY or @@ -187,6 +196,19 @@ RSA keys may be added with this request: string key_comment constraint[] key_constraints +RSA certificates may be added with this request: + + byte SSH2_AGENTC_ADD_IDENTITY or + SSH2_AGENTC_ADD_ID_CONSTRAINED + string "ssh-rsa-cert-v00@openssh.com" + string certificate + mpint rsa_d + mpint rsa_iqmp + mpint rsa_p + mpint rsa_q + string key_comment + constraint[] key_constraints + Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse order to the protocol 1 add keys message. As with the corresponding protocol 1 "add key" request, the private key is overspecified to avoid @@ -513,4 +535,4 @@ Locking and unlocking affects both protocol 1 and protocol 2 keys. SSH_AGENT_CONSTRAIN_LIFETIME 1 SSH_AGENT_CONSTRAIN_CONFIRM 2 -$OpenBSD: PROTOCOL.agent,v 1.4 2008/07/01 23:12:47 stevesk Exp $ +$OpenBSD: PROTOCOL.agent,v 1.5 2010/02/26 20:29:54 djm Exp $ diff --git a/crypto/openssh/PROTOCOL.certkeys b/crypto/openssh/PROTOCOL.certkeys new file mode 100644 index 000000000..1ed9e2064 --- /dev/null +++ b/crypto/openssh/PROTOCOL.certkeys @@ -0,0 +1,193 @@ +This document describes a simple public-key certificate authentication +system for use by SSH. + +Background +---------- + +The SSH protocol currently supports a simple public key authentication +mechanism. Unlike other public key implementations, SSH eschews the +use of X.509 certificates and uses raw keys. This approach has some +benefits relating to simplicity of configuration and minimisation +of attack surface, but it does not support the important use-cases +of centrally managed, passwordless authentication and centrally +certified host keys. + +These protocol extensions build on the simple public key authentication +system already in SSH to allow certificate-based authentication. +The certificates used are not traditional X.509 certificates, with +numerous options and complex encoding rules, but something rather +more minimal: a key, some identity information and usage constraints +that have been signed with some other trusted key. + +A sshd server may be configured to allow authentication via certified +keys, by extending the existing ~/.ssh/authorized_keys mechanism +to allow specification of certification authority keys in addition +to raw user keys. The ssh client will support automatic verification +of acceptance of certified host keys, by adding a similar ability +to specify CA keys in ~/.ssh/known_hosts. + +Certified keys are represented using two new key types: +ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com that +include certification information along with the public key that is used +to sign challenges. ssh-keygen performs the CA signing operation. + +Protocol extensions +------------------- + +The SSH wire protocol includes several extensibility mechanisms. +These modifications shall take advantage of namespaced public key +algorithm names to add support for certificate authentication without +breaking the protocol - implementations that do not support the +extensions will simply ignore them. + +Authentication using the new key formats described below proceeds +using the existing SSH "publickey" authentication method described +in RFC4252 section 7. + +New public key formats +---------------------- + +The ssh-rsa-cert-v00@openssh.com and ssh-dss-cert-v00@openssh.com key +types take a similar high-level format (note: data types and +encoding are as per RFC4251 section 5). The serialised wire encoding of +these certificates is also used for storing them on disk. + +#define SSH_CERT_TYPE_USER 1 +#define SSH_CERT_TYPE_HOST 2 + +RSA certificate + + string "ssh-rsa-cert-v00@openssh.com" + mpint e + mpint n + uint32 type + string key id + string valid principals + uint64 valid after + uint64 valid before + string constraints + string nonce + string reserved + string signature key + string signature + +DSA certificate + + string "ssh-dss-cert-v00@openssh.com" + mpint p + mpint q + mpint g + mpint y + uint32 type + string key id + string valid principals + uint64 valid after + uint64 valid before + string constraints + string nonce + string reserved + string signature key + string signature + +e and n are the RSA exponent and public modulus respectively. + +p, q, g, y are the DSA parameters as described in FIPS-186-2. + +type specifies whether this certificate is for identification of a user +or a host using a SSH_CERT_TYPE_... value. + +key id is a free-form text field that is filled in by the CA at the time +of signing; the intention is that the contents of this field are used to +identify the identity principal in log messages. + +"valid principals" is a string containing zero or more principals as +strings packed inside it. These principals list the names for which this +certificate is valid; hostnames for SSH_CERT_TYPE_HOST certificates and +usernames for SSH_CERT_TYPE_USER certificates. As a special case, a +zero-length "valid principals" field means the certificate is valid for +any principal of the specified type. XXX DNS wildcards? + +"valid after" and "valid before" specify a validity period for the +certificate. Each represents a time in seconds since 1970-01-01 +00:00:00. A certificate is considered valid if: + valid after <= current time < valid before + +constraints is a set of zero or more key constraints encoded as below. + +The nonce field is a CA-provided random bitstring of arbitrary length +(but typically 16 or 32 bytes) included to make attacks that depend on +inducing collisions in the signature hash infeasible. + +The reserved field is current unused and is ignored in this version of +the protocol. + +signature key contains the CA key used to sign the certificate. +The valid key types for CA keys are ssh-rsa and ssh-dss. "Chained" +certificates, where the signature key type is a certificate type itself +are NOT supported. Note that it is possible for a RSA certificate key to +be signed by a DSS CA key and vice-versa. + +signature is computed over all preceding fields from the initial string +up to, and including the signature key. Signatures are computed and +encoded according to the rules defined for the CA's public key algorithm +(RFC4253 section 6.6 for ssh-rsa and ssh-dss). + +Constraints +----------- + +The constraints section of the certificate specifies zero or more +constraints on the certificates validity. The format of this field +is a sequence of zero or more tuples: + + string name + string data + +The name field identifies the constraint and the data field encodes +constraint-specific information (see below). All constraints are +"critical", if an implementation does not recognise a constraint +then the validating party should refuse to accept the certificate. + +The supported constraints and the contents and structure of their +data fields are: + +Name Format Description +----------------------------------------------------------------------------- +force-command string Specifies a command that is executed + (replacing any the user specified on the + ssh command-line) whenever this key is + used for authentication. + +permit-X11-forwarding empty Flag indicating that X11 forwarding + should be permitted. X11 forwarding will + be refused if this constraint is absent. + +permit-agent-forwarding empty Flag indicating that agent forwarding + should be allowed. Agent forwarding + must not be permitted unless this + constraint is present. + +permit-port-forwarding empty Flag indicating that port-forwarding + should be allowed. If this constraint is + not present then no port forwarding will + be allowed. + +permit-pty empty Flag indicating that PTY allocation + should be permitted. In the absence of + this constraint PTY allocation will be + disabled. + +permit-user-rc empty Flag indicating that execution of + ~/.ssh/rc should be permitted. Execution + of this script will not be permitted if + this constraint is not present. + +source-address string Comma-separated list of source addresses + from which this certificate is accepted + for authentication. Addresses are + specified in CIDR format (nn.nn.nn.nn/nn + or hhhh::hhhh/nn). + If this constraint is not present then + certificates may be presented from any + source address. + +$OpenBSD: PROTOCOL.certkeys,v 1.3 2010/03/03 22:50:40 djm Exp $ diff --git a/crypto/openssh/PROTOCOL.mux b/crypto/openssh/PROTOCOL.mux new file mode 100644 index 000000000..d22f7379c --- /dev/null +++ b/crypto/openssh/PROTOCOL.mux @@ -0,0 +1,196 @@ +This document describes the multiplexing protocol used by ssh(1)'s +ControlMaster connection-sharing. + +Most messages from the client to the server contain a "request id" field. +This field is returned in replies as "client request id" to facilitate +matching of responses to requests. + +1. Connection setup + +When a multiplexing connection is made to a ssh(1) operating as a +ControlMaster from a ssh(1) in multiplex slave mode, the first +action of each is to exchange hello messages: + + uint32 MUX_MSG_HELLO + uint32 protocol version + string extension name [optional] + string extension value [optional] + ... + +The current version of the mux protocol is 4. A slave should refuse +to connect to a master that speaks an unsupported protocol version. +Following the version identifier are zero or more extensions +represented as a name/value pair. No extensions are currently +defined. + +2. Opening sessions + +To open a new multiplexed session, a client may send the following +request: + + uint32 MUX_C_MSG_NEW_SESSION + uint32 request id + string reserved + bool want tty flag + bool want X11 forwarding flag + bool want agent flag + bool subsystem flag + uint32 escape char + string terminal type + string command + string environment string 0 [optional] + ... + +To disable the use of an escape character, "escape char" may be set +to 0xffffffff. "terminal type" is generally set to the value of +$TERM. zero or more environment strings may follow the command. + +The client then sends its standard input, output and error file +descriptors (in that order) using Unix domain socket control messages. + +The contents of "reserved" are currently ignored. + +If successful, the server will reply with MUX_S_SESSION_OPENED + + uint32 MUX_S_SESSION_OPENED + uint32 client request id + uint32 session id + +Otherwise it will reply with an error: MUX_S_PERMISSION_DENIED or +MUX_S_FAILURE. + +Once the server has received the fds, it will respond with MUX_S_OK +indicating that the session is up. The client now waits for the +session to end. When it does, the server will send an exit status +message: + + uint32 MUX_S_EXIT_MESSAGE + uint32 session id + uint32 exit value + +The client should exit with this value to mimic the behaviour of a +non-multiplexed ssh(1) connection. Two additional cases that the +client must cope with are it receiving a signal itself and the +server disconnecting without sending an exit message. + +3. Health checks + +The client may request a health check/PID report from a server: + + uint32 MUX_C_ALIVE_CHECK + uint32 request id + +The server replies with: + + uint32 MUX_S_ALIVE + uint32 client request id + uint32 server pid + +4. Remotely terminating a master + +A client may request that a master terminate immediately: + + uint32 MUX_C_TERMINATE + uint32 request id + +The server will reply with one of MUX_S_OK or MUX_S_PERMISSION_DENIED. + +5. Requesting establishment of port forwards + +A client may request the master to establish a port forward: + + uint32 MUX_C_OPEN_FORWARD + uint32 request id + uint32 forwarding type + string listen host + string listen port + string connect host + string connect port + +forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC. + +A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a +MUX_S_FAILURE. + +5. Requesting closure of port forwards + +A client may request the master to establish a port forward: + + uint32 MUX_C_OPEN_FORWARD + uint32 request id + uint32 forwarding type + string listen host + string listen port + string connect host + string connect port + +forwarding type may be MUX_FWD_LOCAL, MUX_FWD_REMOTE, MUX_FWD_DYNAMIC. + +A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a +MUX_S_FAILURE. + +6. Requesting stdio forwarding + +A client may request the master to establish a stdio forwarding: + + uint32 MUX_C_NEW_STDIO_FWD + uint32 request id + string reserved + string connect host + string connect port + +The client then sends its standard input and output file descriptors +(in that order) using Unix domain socket control messages. + +The contents of "reserved" are currently ignored. + +A server may reply with a MUX_S_SESSION_OPEED, a MUX_S_PERMISSION_DENIED +or a MUX_S_FAILURE. + +7. Status messages + +The MUX_S_OK message is empty: + + uint32 MUX_S_OK + uint32 client request id + +The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason: + + uint32 MUX_S_PERMISSION_DENIED + uint32 client request id + string reason + + uint32 MUX_S_FAILURE + uint32 client request id + string reason + +7. Protocol numbers + +#define MUX_MSG_HELLO 0x00000001 +#define MUX_C_NEW_SESSION 0x10000002 +#define MUX_C_ALIVE_CHECK 0x10000004 +#define MUX_C_TERMINATE 0x10000005 +#define MUX_C_OPEN_FORWARD 0x10000006 +#define MUX_C_CLOSE_FORWARD 0x10000007 +#define MUX_S_OK 0x80000001 +#define MUX_S_PERMISSION_DENIED 0x80000002 +#define MUX_S_FAILURE 0x80000003 +#define MUX_S_EXIT_MESSAGE 0x80000004 +#define MUX_S_ALIVE 0x80000005 +#define MUX_S_SESSION_OPENED 0x80000006 + +#define MUX_FWD_LOCAL 1 +#define MUX_FWD_REMOTE 2 +#define MUX_FWD_DYNAMIC 3 + +XXX TODO +XXX extended status (e.g. report open channels / forwards) +XXX graceful close (delete listening socket, but keep existing sessions active) +XXX lock (maybe) +XXX watch in/out traffic (pre/post crypto) +XXX inject packet (what about replies) +XXX server->client error/warning notifications +XXX port0 rfwd (need custom response message) +XXX send signals via mux + +$OpenBSD: PROTOCOL.mux,v 1.1 2010/01/26 01:28:35 djm Exp $ diff --git a/crypto/openssh/README b/crypto/openssh/README index 9de00c093..0ecb670b6 100644 --- a/crypto/openssh/README +++ b/crypto/openssh/README @@ -1,4 +1,4 @@ -See http://www.openssh.com/txt/release-5.2 for the release notes. +See http://www.openssh.com/txt/release-5.4 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 @@ -62,4 +62,4 @@ References - [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 2009/02/23 00:11:57 djm Exp $ +$Id: README,v 1.72 2010/03/07 22:41:02 djm Exp $ diff --git a/crypto/openssh/README.platform b/crypto/openssh/README.platform index 3d7db1494..d1982321e 100644 --- a/crypto/openssh/README.platform +++ b/crypto/openssh/README.platform @@ -56,6 +56,18 @@ 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) @@ -81,4 +93,4 @@ account stacks which will prevent authentication entirely, but will still return the output from pam_nologin to the client. -$Id: README.platform,v 1.9 2007/08/09 04:31:53 dtucker Exp $ +$Id: README.platform,v 1.10 2009/08/28 23:14:48 dtucker Exp $ diff --git a/crypto/openssh/README.smartcard b/crypto/openssh/README.smartcard deleted file mode 100644 index fdf83ecab..000000000 --- a/crypto/openssh/README.smartcard +++ /dev/null @@ -1,93 +0,0 @@ -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/addrmatch.c b/crypto/openssh/addrmatch.c index d39885b7b..5b6773cce 100644 --- a/crypto/openssh/addrmatch.c +++ b/crypto/openssh/addrmatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: addrmatch.c,v 1.4 2008/12/10 03:55:20 stevesk Exp $ */ +/* $OpenBSD: addrmatch.c,v 1.5 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2004-2008 Damien Miller @@ -126,6 +126,8 @@ addr_netmask(int af, u_int l, struct xaddr *n) switch (af) { case AF_INET: n->af = AF_INET; + if (l == 0) + return 0; n->v4.s_addr = htonl((0xffffffff << (32 - l)) & 0xffffffff); return 0; case AF_INET6: @@ -422,3 +424,77 @@ addr_match_list(const char *addr, const char *_list) return ret; } + +/* + * Match "addr" against list CIDR list "_list". Lexical wildcards and + * negation are not supported. If "addr" == NULL, will verify structure + * of "_list". + * + * Returns 1 on match found (never returned when addr == NULL). + * Returns 0 on if no match found, or no errors found when addr == NULL. + * Returns -1 on error + */ +int +addr_match_cidr_list(const char *addr, const char *_list) +{ + char *list, *cp, *o; + struct xaddr try_addr, match_addr; + u_int masklen; + int ret = 0, r; + + if (addr != NULL && addr_pton(addr, &try_addr) != 0) { + debug2("%s: couldn't parse address %.100s", __func__, addr); + return 0; + } + if ((o = list = strdup(_list)) == NULL) + return -1; + while ((cp = strsep(&list, ",")) != NULL) { + if (*cp == '\0') { + error("%s: empty entry in list \"%.100s\"", + __func__, o); + ret = -1; + break; + } + + /* + * NB. This function is called in pre-auth with untrusted data, + * so be extra paranoid about junk reaching getaddrino (via + * addr_pton_cidr). + */ + + /* Stop junk from reaching getaddrinfo. +3 is for masklen */ + if (strlen(cp) > INET6_ADDRSTRLEN + 3) { + error("%s: list entry \"%.100s\" too long", + __func__, cp); + ret = -1; + break; + } +#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/" + if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) { + error("%s: list entry \"%.100s\" contains invalid " + "characters", __func__, cp); + ret = -1; + } + + /* Prefer CIDR address matching */ + r = addr_pton_cidr(cp, &match_addr, &masklen); + if (r == -1) { + error("Invalid network entry \"%.100s\"", cp); + ret = -1; + break; + } else if (r == -2) { + error("Inconsistent mask length for " + "network \"%.100s\"", cp); + ret = -1; + break; + } else if (r == 0 && addr != NULL) { + if (addr_netmatch(&try_addr, &match_addr, + masklen) == 0) + ret = 1; + continue; + } + } + xfree(o); + + return ret; +} diff --git a/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c index 868288126..d019fe202 100644 --- a/crypto/openssh/auth-krb5.c +++ b/crypto/openssh/auth-krb5.c @@ -78,6 +78,11 @@ auth_krb5_password(Authctxt *authctxt, const char *password) krb5_error_code problem; krb5_ccache ccache = NULL; int len; + char *client, *platform_client; + + /* get platform-specific kerberos client principal name (if it exists) */ + platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name); + client = platform_client ? platform_client : authctxt->pw->pw_name; temporarily_use_uid(authctxt->pw); @@ -85,7 +90,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password) if (problem) goto out; - problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, + problem = krb5_parse_name(authctxt->krb5_ctx, client, &authctxt->krb5_user); if (problem) goto out; @@ -141,8 +146,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password) if (problem) goto out; - if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, - authctxt->pw->pw_name)) { + if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, client)) { problem = -1; goto out; } @@ -176,6 +180,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) out: restore_uid(); + + if (platform_client != NULL) + xfree(platform_client); if (problem) { if (ccache) diff --git a/crypto/openssh/auth-options.c b/crypto/openssh/auth-options.c index ab085c233..129301765 100644 --- a/crypto/openssh/auth-options.c +++ b/crypto/openssh/auth-options.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.c,v 1.44 2009/01/22 10:09:16 djm Exp $ */ +/* $OpenBSD: auth-options.c,v 1.48 2010/03/07 11:57:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -44,6 +44,7 @@ int no_agent_forwarding_flag = 0; int no_x11_forwarding_flag = 0; int no_pty_flag = 0; int no_user_rc = 0; +int key_is_cert_authority = 0; /* "command=" option. */ char *forced_command = NULL; @@ -64,6 +65,7 @@ auth_clear_options(void) no_pty_flag = 0; no_x11_forwarding_flag = 0; no_user_rc = 0; + key_is_cert_authority = 0; while (custom_environment) { struct envstring *ce = custom_environment; custom_environment = ce->next; @@ -76,7 +78,6 @@ auth_clear_options(void) } forced_tun_device = -1; channel_clear_permitted_opens(); - auth_debug_reset(); } /* @@ -96,6 +97,12 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) return 1; while (*opts && *opts != ' ' && *opts != '\t') { + cp = "cert-authority"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + key_is_cert_authority = 1; + opts += strlen(cp); + goto next_option; + } cp = "no-port-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { auth_debug_add("Port forwarding disabled."); @@ -356,9 +363,6 @@ next_option: /* Process the next option. */ } - if (!use_privsep) - auth_debug_send(); - /* grant access */ return 1; @@ -368,9 +372,158 @@ bad_option: auth_debug_add("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); - if (!use_privsep) - auth_debug_send(); - /* deny access */ return 0; } + +/* + * Set options from certificate constraints. These supersede user key options + * so this must be called after auth_parse_options(). + */ +int +auth_cert_constraints(Buffer *c_orig, struct passwd *pw) +{ + u_char *name = NULL, *data_blob = NULL; + u_int nlen, dlen, clen; + Buffer c, data; + int ret = -1; + + int cert_no_port_forwarding_flag = 1; + int cert_no_agent_forwarding_flag = 1; + int cert_no_x11_forwarding_flag = 1; + int cert_no_pty_flag = 1; + int cert_no_user_rc = 1; + char *cert_forced_command = NULL; + int cert_source_address_done = 0; + + buffer_init(&data); + + /* Make copy to avoid altering original */ + buffer_init(&c); + buffer_append(&c, buffer_ptr(c_orig), buffer_len(c_orig)); + + while (buffer_len(&c) > 0) { + if ((name = buffer_get_string_ret(&c, &nlen)) == NULL || + (data_blob = buffer_get_string_ret(&c, &dlen)) == NULL) { + error("Certificate constraints corrupt"); + goto out; + } + buffer_append(&data, data_blob, dlen); + debug3("found certificate constraint \"%.100s\" len %u", + name, dlen); + if (strlen(name) != nlen) { + error("Certificate constraint name contains \\0"); + goto out; + } + if (strcmp(name, "permit-X11-forwarding") == 0) + cert_no_x11_forwarding_flag = 0; + else if (strcmp(name, "permit-agent-forwarding") == 0) + cert_no_agent_forwarding_flag = 0; + else if (strcmp(name, "permit-port-forwarding") == 0) + cert_no_port_forwarding_flag = 0; + else if (strcmp(name, "permit-pty") == 0) + cert_no_pty_flag = 0; + else if (strcmp(name, "permit-user-rc") == 0) + cert_no_user_rc = 0; + else if (strcmp(name, "force-command") == 0) { + char *command = buffer_get_string_ret(&data, &clen); + + if (command == NULL) { + error("Certificate constraint \"%s\" corrupt", + name); + goto out; + } + if (strlen(command) != clen) { + error("force-command constrain contains \\0"); + goto out; + } + if (cert_forced_command != NULL) { + error("Certificate has multiple " + "force-command constraints"); + xfree(command); + goto out; + } + cert_forced_command = command; + } else if (strcmp(name, "source-address") == 0) { + char *allowed = buffer_get_string_ret(&data, &clen); + const char *remote_ip = get_remote_ipaddr(); + + if (allowed == NULL) { + error("Certificate constraint \"%s\" corrupt", + name); + goto out; + } + if (strlen(allowed) != clen) { + error("source-address constrain contains \\0"); + goto out; + } + if (cert_source_address_done++) { + error("Certificate has multiple " + "source-address constraints"); + xfree(allowed); + goto out; + } + switch (addr_match_cidr_list(remote_ip, allowed)) { + case 1: + /* accepted */ + xfree(allowed); + break; + case 0: + /* no match */ + logit("Authentication tried for %.100s with " + "valid certificate but not from a " + "permitted host (ip=%.200s).", + pw->pw_name, remote_ip); + auth_debug_add("Your address '%.200s' is not " + "permitted to use this certificate for " + "login.", remote_ip); + xfree(allowed); + goto out; + case -1: + error("Certificate source-address contents " + "invalid"); + xfree(allowed); + goto out; + } + } else { + error("Certificate constraint \"%s\" is not supported", + name); + goto out; + } + + if (buffer_len(&data) != 0) { + error("Certificate constraint \"%s\" corrupt " + "(extra data)", name); + goto out; + } + buffer_clear(&data); + xfree(name); + xfree(data_blob); + name = data_blob = NULL; + } + + /* successfully parsed all constraints */ + ret = 0; + + no_port_forwarding_flag |= cert_no_port_forwarding_flag; + no_agent_forwarding_flag |= cert_no_agent_forwarding_flag; + no_x11_forwarding_flag |= cert_no_x11_forwarding_flag; + no_pty_flag |= cert_no_pty_flag; + no_user_rc |= cert_no_user_rc; + /* CA-specified forced command supersedes key option */ + if (cert_forced_command != NULL) { + if (forced_command != NULL) + xfree(forced_command); + forced_command = cert_forced_command; + } + + out: + if (name != NULL) + xfree(name); + if (data_blob != NULL) + xfree(data_blob); + buffer_free(&data); + buffer_free(&c); + return ret; +} + diff --git a/crypto/openssh/auth-options.h b/crypto/openssh/auth-options.h index 14488f72d..694edc842 100644 --- a/crypto/openssh/auth-options.h +++ b/crypto/openssh/auth-options.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-options.h,v 1.17 2008/03/26 21:28:14 djm Exp $ */ +/* $OpenBSD: auth-options.h,v 1.18 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -30,8 +30,10 @@ extern int no_user_rc; extern char *forced_command; extern struct envstring *custom_environment; extern int forced_tun_device; +extern int key_is_cert_authority; int auth_parse_options(struct passwd *, char *, char *, u_long); void auth_clear_options(void); +int auth_cert_constraints(Buffer *, struct passwd *); #endif diff --git a/crypto/openssh/auth-pam.c b/crypto/openssh/auth-pam.c index bbfafa67e..fc79dee80 100644 --- a/crypto/openssh/auth-pam.c +++ b/crypto/openssh/auth-pam.c @@ -602,16 +602,16 @@ sshpam_cleanup(void) return; debug("PAM: cleanup"); pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); - if (sshpam_cred_established) { - debug("PAM: deleting credentials"); - pam_setcred(sshpam_handle, PAM_DELETE_CRED); - sshpam_cred_established = 0; - } 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; diff --git a/crypto/openssh/auth-passwd.c b/crypto/openssh/auth-passwd.c index bdfced023..b1c6ce092 100644 --- a/crypto/openssh/auth-passwd.c +++ b/crypto/openssh/auth-passwd.c @@ -102,7 +102,7 @@ auth_password(Authctxt *authctxt, const char *password) } #endif #ifdef HAVE_CYGWIN - if (is_winnt) { + { HANDLE hToken = cygwin_logon_user(pw, password); if (hToken == INVALID_HANDLE_VALUE) diff --git a/crypto/openssh/auth-rh-rsa.c b/crypto/openssh/auth-rh-rsa.c index eca750275..b21a0f4a2 100644 --- a/crypto/openssh/auth-rh-rsa.c +++ b/crypto/openssh/auth-rh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -44,6 +44,9 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, { HostStatus host_status; + if (auth_key_is_revoked(client_host_key)) + return 0; + /* Check if we would accept it using rhosts authentication. */ if (!auth_rhosts(pw, cuser)) return 0; diff --git a/crypto/openssh/auth-rhosts.c b/crypto/openssh/auth-rhosts.c index 5c1296701..06ae7f0b9 100644 --- a/crypto/openssh/auth-rhosts.c +++ b/crypto/openssh/auth-rhosts.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rhosts.c,v 1.43 2008/06/13 14:18:51 dtucker Exp $ */ +/* $OpenBSD: auth-rhosts.c,v 1.44 2010/03/07 11:57:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -317,11 +317,5 @@ 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; + return auth_rhosts2_raw(pw, client_user, hostname, ipaddr); } diff --git a/crypto/openssh/auth-rsa.c b/crypto/openssh/auth-rsa.c index bf5462076..65571a890 100644 --- a/crypto/openssh/auth-rsa.c +++ b/crypto/openssh/auth-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */ +/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -94,6 +94,9 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) MD5_CTX md; int len; + if (auth_key_is_revoked(key)) + return 0; + /* 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", diff --git a/crypto/openssh/auth-sia.c b/crypto/openssh/auth-sia.c index debf30201..a9e1c258c 100644 --- a/crypto/openssh/auth-sia.c +++ b/crypto/openssh/auth-sia.c @@ -34,10 +34,6 @@ #include #include #include -#include -#include -#include -#include #include "ssh.h" #include "key.h" @@ -53,52 +49,6 @@ extern ServerOptions options; extern int saved_argc; extern char **saved_argv; -static int -sia_password_change_required(const char *user) -{ - struct es_passwd *acct; - time_t pw_life; - time_t pw_date; - - set_auth_parameters(saved_argc, saved_argv); - - if ((acct = getespwnam(user)) == NULL) { - error("Couldn't access protected database entry for %s", user); - endprpwent(); - return (0); - } - - /* If forced password change flag is set, honor it */ - if (acct->uflg->fg_psw_chg_reqd && acct->ufld->fd_psw_chg_reqd) { - endprpwent(); - return (1); - } - - /* Obtain password lifetime; if none, it can't have expired */ - if (acct->uflg->fg_expire) - pw_life = acct->ufld->fd_expire; - else if (acct->sflg->fg_expire) - pw_life = acct->sfld->fd_expire; - else { - endprpwent(); - return (0); - } - - /* Offset from last change; if none, it must be expired */ - if (acct->uflg->fg_schange) - pw_date = acct->ufld->fd_schange + pw_life; - else { - endprpwent(); - return (1); - } - - endprpwent(); - - /* If expiration date is prior to now, change password */ - - return (pw_date <= time((time_t *) NULL)); -} - int sys_auth_passwd(Authctxt *authctxt, const char *pass) { @@ -126,9 +76,6 @@ sys_auth_passwd(Authctxt *authctxt, const char *pass) sia_ses_release(&ent); - authctxt->force_pwchange = sia_password_change_required( - authctxt->user); - return (1); } diff --git a/crypto/openssh/auth.c b/crypto/openssh/auth.c index 02f9175ee..291741430 100644 --- a/crypto/openssh/auth.c +++ b/crypto/openssh/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.80 2008/11/04 07:58:09 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.86 2010/03/05 02:58:11 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -70,6 +70,7 @@ __RCSID("$FreeBSD$"); #ifdef GSSAPI #include "ssh-gss.h" #endif +#include "authfile.h" #include "monitor_wrap.h" /* import */ @@ -96,7 +97,6 @@ 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; @@ -154,22 +154,28 @@ allowed_user(struct passwd * pw) } /* - * Get the shell from the password data. An empty shell field is - * legal, and means /bin/sh. + * Deny if shell does not exist or is not executable unless we + * are chrooting. */ - 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.chroot_directory == NULL || + strcasecmp(options.chroot_directory, "none") == 0) { + char *shell = xstrdup((pw->pw_shell[0] == '\0') ? + _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */ + + if (stat(shell, &st) != 0) { + logit("User %.100s not allowed because shell %.100s " + "does not exist", pw->pw_name, shell); + xfree(shell); + return 0; + } + if (S_ISREG(st.st_mode) == 0 || + (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { + logit("User %.100s not allowed because shell %.100s " + "is not executable", pw->pw_name, shell); + xfree(shell); + return 0; + } + xfree(shell); } if (options.num_deny_users > 0 || options.num_allow_users > 0 || @@ -456,7 +462,7 @@ secure_filename(FILE *f, const char *file, struct passwd *pw, return -1; } - /* If are passed the homedir then we can stop */ + /* If are past the homedir then we can stop */ if (comparehome && strcmp(homedir, buf) == 0) { debug3("secure_filename: terminating check at '%s'", buf); @@ -484,8 +490,12 @@ auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes) * Open the file containing the authorized keys * Fail quietly if file does not exist */ - if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) + if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { + if (errno != ENOENT) + debug("Could not open keyfile '%s': %s", file, + strerror(errno)); return NULL; + } if (fstat(fd, &st) < 0) { close(fd); @@ -526,7 +536,28 @@ getpwnamallow(const char *user) parse_server_match_config(&options, user, get_canonical_hostname(options.use_dns), get_remote_ipaddr()); +#if defined(_AIX) && defined(HAVE_SETAUTHDB) + aix_setauthdb(user); +#endif + pw = getpwnam(user); + +#if defined(_AIX) && defined(HAVE_SETAUTHDB) + aix_restoreauthdb(); +#endif +#ifdef HAVE_CYGWIN + /* + * Windows usernames are case-insensitive. To avoid later problems + * when trying to match the username, the user is only allowed to + * login if the username is given in the same case as stored in the + * user database. + */ + if (pw != NULL && strcmp(user, pw->pw_name) != 0) { + logit("Login name %.100s does not match stored username %.100s", + user, pw->pw_name); + pw = NULL; + } +#endif if (pw == NULL) { logit("Invalid user %.100s from %.100s", user, get_remote_ipaddr()); @@ -561,6 +592,35 @@ getpwnamallow(const char *user) return (NULL); } +/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ +int +auth_key_is_revoked(Key *key) +{ + char *key_fp; + + if (options.revoked_keys_file == NULL) + return 0; + + switch (key_in_file(key, options.revoked_keys_file, 0)) { + case 0: + /* key not revoked */ + return 0; + case -1: + /* Error opening revoked_keys_file: refuse all keys */ + error("Revoked keys file is unreadable: refusing public key " + "authentication"); + return 1; + case 1: + /* Key revoked */ + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + error("WARNING: authentication attempt with a revoked " + "%s key %s ", key_type(key), key_fp); + xfree(key_fp); + return 1; + } + fatal("key_in_file returned junk"); +} + void auth_debug_add(const char *fmt,...) { diff --git a/crypto/openssh/auth.h b/crypto/openssh/auth.h index 3a70f4421..a65b87dd1 100644 --- a/crypto/openssh/auth.h +++ b/crypto/openssh/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.62 2008/11/04 08:22:12 djm Exp $ */ +/* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -171,6 +171,7 @@ char *authorized_keys_file(struct passwd *); char *authorized_keys_file2(struct passwd *); FILE *auth_openkeyfile(const char *, struct passwd *, int); +int auth_key_is_revoked(Key *); HostStatus check_key_in_hostfiles(struct passwd *, Key *, const char *, @@ -178,7 +179,8 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *, /* hostkey handling */ Key *get_hostkey_by_index(int); -Key *get_hostkey_by_type(int); +Key *get_hostkey_public_by_type(int); +Key *get_hostkey_private_by_type(int); int get_hostkey_index(Key *); int ssh1_session_key(BIGNUM *); diff --git a/crypto/openssh/auth1.c b/crypto/openssh/auth1.c index b8a255872..1801661fd 100644 --- a/crypto/openssh/auth1.c +++ b/crypto/openssh/auth1.c @@ -318,15 +318,7 @@ do_authloop(Authctxt *authctxt) } #endif /* _UNICOS */ -#ifdef HAVE_CYGWIN - if (authenticated && - !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, - authctxt->pw)) { - packet_disconnect("Authentication rejected for uid %d.", - authctxt->pw == NULL ? -1 : authctxt->pw->pw_uid); - authenticated = 0; - } -#else +#ifndef HAVE_CYGWIN /* Special handling for root */ if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed(meth->name)) { diff --git a/crypto/openssh/auth2-hostbased.c b/crypto/openssh/auth2-hostbased.c index 041051c53..721646520 100644 --- a/crypto/openssh/auth2-hostbased.c +++ b/crypto/openssh/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -145,6 +145,9 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, HostStatus host_status; int len; + if (auth_key_is_revoked(key)) + return 0; + resolvedname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); diff --git a/crypto/openssh/auth2-jpake.c b/crypto/openssh/auth2-jpake.c index efe7ff2a3..5de5506a6 100644 --- a/crypto/openssh/auth2-jpake.c +++ b/crypto/openssh/auth2-jpake.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-jpake.c,v 1.2 2008/11/07 23:34:48 dtucker Exp $ */ +/* $OpenBSD: auth2-jpake.c,v 1.3 2009/03/05 07:18:19 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. * @@ -42,8 +42,8 @@ #include "ssh2.h" #include "key.h" #include "hostfile.h" -#include "buffer.h" #include "auth.h" +#include "buffer.h" #include "packet.h" #include "dispatch.h" #include "log.h" @@ -55,6 +55,7 @@ #endif #include "monitor_wrap.h" +#include "schnorr.h" #include "jpake.h" /* @@ -359,7 +360,7 @@ auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s, } /* - * Being authentication attempt. + * Begin authentication attempt. * Note, sets authctxt->postponed while in subprotocol */ static int diff --git a/crypto/openssh/auth2-kbdint.c b/crypto/openssh/auth2-kbdint.c index a4fc9e6f7..fae67da6e 100644 --- a/crypto/openssh/auth2-kbdint.c +++ b/crypto/openssh/auth2-kbdint.c @@ -58,10 +58,6 @@ userauth_kbdint(Authctxt *authctxt) xfree(devs); xfree(lang); -#ifdef HAVE_CYGWIN - if (check_nt_auth(0, authctxt->pw) == 0) - authenticated = 0; -#endif return authenticated; } diff --git a/crypto/openssh/auth2-none.c b/crypto/openssh/auth2-none.c index 10accfe55..08f2f935f 100644 --- a/crypto/openssh/auth2-none.c +++ b/crypto/openssh/auth2-none.c @@ -61,10 +61,6 @@ userauth_none(Authctxt *authctxt) { none_enabled = 0; packet_check_eom(); -#ifdef HAVE_CYGWIN - if (check_nt_auth(1, authctxt->pw) == 0) - return (0); -#endif if (options.password_authentication) return (PRIVSEP(auth_password(authctxt, ""))); return (0); diff --git a/crypto/openssh/auth2-passwd.c b/crypto/openssh/auth2-passwd.c index 421c5c25d..5f1f3635f 100644 --- a/crypto/openssh/auth2-passwd.c +++ b/crypto/openssh/auth2-passwd.c @@ -68,10 +68,6 @@ userauth_passwd(Authctxt *authctxt) logit("password change not supported"); else if (PRIVSEP(auth_password(authctxt, password)) == 1) authenticated = 1; -#ifdef HAVE_CYGWIN - if (check_nt_auth(1, authctxt->pw) == 0) - authenticated = 0; -#endif memset(password, 0, len); xfree(password); return authenticated; diff --git a/crypto/openssh/auth2-pubkey.c b/crypto/openssh/auth2-pubkey.c index b1e38e5f5..51aa77487 100644 --- a/crypto/openssh/auth2-pubkey.c +++ b/crypto/openssh/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.19 2008/07/03 21:46:58 otto Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.21 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include "xmalloc.h" @@ -54,6 +56,7 @@ #endif #include "monitor_wrap.h" #include "misc.h" +#include "authfile.h" /* import */ extern ServerOptions options; @@ -170,10 +173,6 @@ done: key_free(key); xfree(pkalg); xfree(pkblob); -#ifdef HAVE_CYGWIN - if (check_nt_auth(0, authctxt->pw) == 0) - authenticated = 0; -#endif return authenticated; } @@ -182,6 +181,7 @@ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; + const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; @@ -200,11 +200,13 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) } found_key = 0; - found = key_new(key->type); + found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; + auth_clear_options(); + /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; @@ -231,8 +233,32 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) continue; } } - if (key_equal(found, key) && - auth_parse_options(pw, key_options, file, linenum) == 1) { + if (auth_parse_options(pw, key_options, file, linenum) != 1) + continue; + if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) { + if (!key_is_cert_authority) + continue; + if (!key_equal(found, key->cert->signature_key)) + continue; + debug("matching CA found: file %s, line %lu", + file, linenum); + fp = key_fingerprint(found, SSH_FP_MD5, + SSH_FP_HEX); + verbose("Found matching %s CA: %s", + key_type(found), fp); + xfree(fp); + if (key_cert_check_authority(key, 0, 0, pw->pw_name, + &reason) != 0) { + error("%s", reason); + auth_debug_add("%s", reason); + continue; + } + if (auth_cert_constraints(&key->cert->constraints, + pw) != 0) + continue; + found_key = 1; + break; + } else if (!key_is_cert_authority && key_equal(found, key)) { found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); @@ -251,6 +277,47 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) return found_key; } +/* Authenticate a certificate key against TrustedUserCAKeys */ +static int +user_cert_trusted_ca(struct passwd *pw, Key *key) +{ + char *key_fp, *ca_fp; + const char *reason; + int ret = 0; + + if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) + return 0; + + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + ca_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + + if (key_in_file(key->cert->signature_key, + options.trusted_user_ca_keys, 1) != 1) { + debug2("%s: CA %s %s is not listed in %s", __func__, + key_type(key->cert->signature_key), ca_fp, + options.trusted_user_ca_keys); + goto out; + } + if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { + error("%s", reason); + auth_debug_add("%s", reason); + goto out; + } + if (auth_cert_constraints(&key->cert->constraints, pw) != 0) + goto out; + + verbose("%s certificate %s allowed by trusted %s key %s", + key_type(key), key_fp, key_type(key->cert->signature_key), ca_fp); + ret = 1; + + out: + if (key_fp != NULL) + xfree(key_fp); + if (ca_fp != NULL) + xfree(ca_fp); + return ret; +} + /* check whether given key is in .ssh/authorized_keys* */ int user_key_allowed(struct passwd *pw, Key *key) @@ -258,6 +325,15 @@ user_key_allowed(struct passwd *pw, Key *key) int success; char *file; + if (auth_key_is_revoked(key)) + return 0; + if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) + return 0; + + success = user_cert_trusted_ca(pw, key); + if (success) + return success; + file = authorized_keys_file(pw); success = user_key_allowed2(pw, key, file); xfree(file); diff --git a/crypto/openssh/auth2.c b/crypto/openssh/auth2.c index 1c44bb5c9..50fb3396f 100644 --- a/crypto/openssh/auth2.c +++ b/crypto/openssh/auth2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2.c,v 1.120 2008/11/04 08:22:12 djm Exp $ */ +/* $OpenBSD: auth2.c,v 1.121 2009/06/22 05:39:28 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -36,8 +36,8 @@ __RCSID("$FreeBSD$"); #include #include -#include "xmalloc.h" #include "atomicio.h" +#include "xmalloc.h" #include "ssh2.h" #include "packet.h" #include "log.h" diff --git a/crypto/openssh/authfd.c b/crypto/openssh/authfd.c index 61faad123..28a8cf2d7 100644 --- a/crypto/openssh/authfd.c +++ b/crypto/openssh/authfd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.c,v 1.80 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: authfd.c,v 1.82 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -483,6 +483,16 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->rsa->p); buffer_put_bignum2(b, key->rsa->q); break; + case KEY_RSA_CERT: + if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) + fatal("%s: no cert/certblob", __func__); + buffer_put_string(b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + buffer_put_bignum2(b, key->rsa->d); + buffer_put_bignum2(b, key->rsa->iqmp); + buffer_put_bignum2(b, key->rsa->p); + buffer_put_bignum2(b, key->rsa->q); + break; case KEY_DSA: buffer_put_bignum2(b, key->dsa->p); buffer_put_bignum2(b, key->dsa->q); @@ -490,6 +500,13 @@ ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) buffer_put_bignum2(b, key->dsa->pub_key); buffer_put_bignum2(b, key->dsa->priv_key); break; + case KEY_DSA_CERT: + if (key->cert == NULL || buffer_len(&key->cert->certblob) == 0) + fatal("%s: no cert/certblob", __func__); + buffer_put_string(b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + buffer_put_bignum2(b, key->dsa->priv_key); + break; } buffer_put_cstring(b, comment); } @@ -517,7 +534,9 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, ssh_encode_identity_rsa1(&msg, key->rsa, comment); break; case KEY_RSA: + case KEY_RSA_CERT: case KEY_DSA: + case KEY_DSA_CERT: type = constrained ? SSH2_AGENTC_ADD_ID_CONSTRAINED : SSH2_AGENTC_ADD_IDENTITY; @@ -545,12 +564,6 @@ ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, 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. @@ -571,7 +584,8 @@ ssh_remove_identity(AuthenticationConnection *auth, Key *key) 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) { + } else if (key_type_plain(key->type) == KEY_DSA || + key_type_plain(key->type) == KEY_RSA) { key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); diff --git a/crypto/openssh/authfd.h b/crypto/openssh/authfd.h index 3da256112..2582a27aa 100644 --- a/crypto/openssh/authfd.h +++ b/crypto/openssh/authfd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfd.h,v 1.36 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: authfd.h,v 1.37 2009/08/27 17:44:52 djm Exp $ */ /* * Author: Tatu Ylonen @@ -75,7 +75,6 @@ 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 *); diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c index 735c64780..224c6aa80 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.76 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -47,6 +47,9 @@ #include #include +/* compatibility with old or broken OpenSSL versions */ +#include "openbsd-compat/openssl-compat.h" + #include #include #include @@ -184,7 +187,11 @@ key_save_private_pem(Key *key, const char *filename, const char *_passphrase, int success = 0; int len = strlen(_passphrase); u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; +#if (OPENSSL_VERSION_NUMBER < 0x00907000L) const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; +#else + const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; +#endif if (len > 0 && len <= 4) { error("passphrase too short: have %d bytes, need > 4", len); @@ -552,8 +559,13 @@ key_load_private_type(int type, const char *filename, const char *passphrase, int fd; fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd < 0) { + debug("could not open key file '%s': %s", filename, + strerror(errno)); + if (perm_ok != NULL) + *perm_ok = 0; return NULL; + } if (!key_perm_ok(fd, filename)) { if (perm_ok != NULL) *perm_ok = 0; @@ -588,8 +600,11 @@ key_load_private(const char *filename, const char *passphrase, int fd; fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd < 0) { + debug("could not open key file '%s': %s", filename, + strerror(errno)); return NULL; + } if (!key_perm_ok(fd, filename)) { error("bad permissions: ignore key: %s", filename); close(fd); @@ -677,3 +692,65 @@ key_load_public(const char *filename, char **commentp) key_free(pub); return NULL; } + +/* + * Returns 1 if the specified "key" is listed in the file "filename", + * 0 if the key is not listed or -1 on error. + * If strict_type is set then the key type must match exactly, + * otherwise a comparison that ignores certficiate data is performed. + */ +int +key_in_file(Key *key, const char *filename, int strict_type) +{ + FILE *f; + char line[SSH_MAX_PUBKEY_BYTES]; + char *cp; + u_long linenum = 0; + int ret = 0; + Key *pub; + int (*key_compare)(const Key *, const Key *) = strict_type ? + key_equal : key_equal_public; + + if ((f = fopen(filename, "r")) == NULL) { + if (errno == ENOENT) { + debug("%s: keyfile \"%s\" missing", __func__, filename); + return 0; + } else { + error("%s: could not open keyfile \"%s\": %s", __func__, + filename, strerror(errno)); + return -1; + } + } + + while (read_keyfile_line(f, filename, line, sizeof(line), + &linenum) != -1) { + cp = line; + + /* Skip leading whitespace. */ + for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) + ; + + /* Skip comments and empty lines */ + switch (*cp) { + case '#': + case '\n': + case '\0': + continue; + } + + pub = key_new(KEY_UNSPEC); + if (key_read(pub, &cp) != 1) { + key_free(pub); + continue; + } + if (key_compare(key, pub)) { + ret = 1; + key_free(pub); + break; + } + key_free(pub); + } + fclose(f); + return ret; +} + diff --git a/crypto/openssh/authfile.h b/crypto/openssh/authfile.h index a6c74934d..6dfa478e7 100644 --- a/crypto/openssh/authfile.h +++ b/crypto/openssh/authfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 dtucker Exp $ */ +/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -22,5 +22,6 @@ 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 *); +int key_in_file(Key *, const char *, int); #endif diff --git a/crypto/openssh/bufaux.c b/crypto/openssh/bufaux.c index cd9a35ded..4ef19c454 100644 --- a/crypto/openssh/bufaux.c +++ b/crypto/openssh/bufaux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bufaux.c,v 1.46 2008/06/10 23:21:34 dtucker Exp $ */ +/* $OpenBSD: bufaux.c,v 1.48 2010/02/02 22:49:34 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -166,7 +166,10 @@ buffer_get_string_ret(Buffer *buffer, u_int *length_ptr) u_int len; /* Get the length. */ - len = buffer_get_int(buffer); + if (buffer_get_int_ret(&len, buffer) != 0) { + error("buffer_get_string_ret: cannot extract length"); + return (NULL); + } if (len > 256 * 1024) { error("buffer_get_string_ret: bad string length %u", len); return (NULL); @@ -198,14 +201,17 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr) } void * -buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) +buffer_get_string_ptr_ret(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); + if (buffer_get_int_ret(&len, buffer) != 0) + return NULL; + if (len > 256 * 1024) { + error("buffer_get_string_ptr: bad string length %u", len); + return NULL; + } ptr = buffer_ptr(buffer); buffer_consume(buffer, len); if (length_ptr) @@ -213,6 +219,16 @@ buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) return (ptr); } +void * +buffer_get_string_ptr(Buffer *buffer, u_int *length_ptr) +{ + void *ret; + + if ((ret = buffer_get_string_ptr_ret(buffer, length_ptr)) == NULL) + fatal("buffer_get_string_ptr: buffer error"); + return (ret); +} + /* * Stores and arbitrary binary string in the buffer. */ diff --git a/crypto/openssh/buffer.c b/crypto/openssh/buffer.c index e02e1e35c..ae9700344 100644 --- a/crypto/openssh/buffer.c +++ b/crypto/openssh/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: buffer.c,v 1.32 2010/02/09 03:56:28 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -160,7 +160,7 @@ buffer_check_alloc(Buffer *buffer, u_int len) /* Returns the number of bytes of data in the buffer. */ u_int -buffer_len(Buffer *buffer) +buffer_len(const Buffer *buffer) { return buffer->end - buffer->offset; } @@ -228,7 +228,7 @@ buffer_consume_end(Buffer *buffer, u_int bytes) /* Returns a pointer to the first used byte in the buffer. */ void * -buffer_ptr(Buffer *buffer) +buffer_ptr(const Buffer *buffer) { return buffer->buf + buffer->offset; } @@ -236,7 +236,7 @@ buffer_ptr(Buffer *buffer) /* Dumps the contents of the buffer to stderr. */ void -buffer_dump(Buffer *buffer) +buffer_dump(const Buffer *buffer) { u_int i; u_char *ucp = buffer->buf; diff --git a/crypto/openssh/buffer.h b/crypto/openssh/buffer.h index d0f354ee7..4ef4f80b3 100644 --- a/crypto/openssh/buffer.h +++ b/crypto/openssh/buffer.h @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.h,v 1.17 2008/05/08 06:59:01 markus Exp $ */ +/* $OpenBSD: buffer.h,v 1.19 2010/02/09 03:56:28 djm Exp $ */ /* * Author: Tatu Ylonen @@ -27,8 +27,8 @@ void buffer_init(Buffer *); void buffer_clear(Buffer *); void buffer_free(Buffer *); -u_int buffer_len(Buffer *); -void *buffer_ptr(Buffer *); +u_int buffer_len(const Buffer *); +void *buffer_ptr(const Buffer *); void buffer_append(Buffer *, const void *, u_int); void *buffer_append_space(Buffer *, u_int); @@ -40,7 +40,7 @@ void buffer_get(Buffer *, void *, u_int); void buffer_consume(Buffer *, u_int); void buffer_consume_end(Buffer *, u_int); -void buffer_dump(Buffer *); +void buffer_dump(const Buffer *); int buffer_get_ret(Buffer *, void *, u_int); int buffer_consume_ret(Buffer *, u_int); @@ -81,6 +81,7 @@ 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 *); +void *buffer_get_string_ptr_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 index 7138f48d0..ef94d9155 100644 --- a/crypto/openssh/canohost.c +++ b/crypto/openssh/canohost.c @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.c,v 1.64 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: canohost.c,v 1.66 2010/01/13 01:20:20 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -27,6 +27,7 @@ #include #include #include +#include #include "xmalloc.h" #include "packet.h" @@ -35,6 +36,8 @@ #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 @@ -299,9 +302,32 @@ get_local_ipaddr(int sock) } char * -get_local_name(int sock) +get_local_name(int fd) { - return get_socket_address(sock, 0, NI_NAMEREQD); + char *host, myname[NI_MAXHOST]; + + /* Assume we were passed a socket */ + if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL) + return host; + + /* Handle the case where we were passed a pipe */ + if (gethostname(myname, sizeof(myname)) == -1) { + verbose("get_local_name: gethostname: %s", strerror(errno)); + } else { + host = xstrdup(myname); + } + + return host; +} + +void +clear_cached_addr(void) +{ + if (canonical_host_ip != NULL) { + xfree(canonical_host_ip); + canonical_host_ip = NULL; + } + cached_port = -1; } /* @@ -312,8 +338,6 @@ get_local_name(int sock) const char * get_remote_ipaddr(void) { - static char *canonical_host_ip = NULL; - /* Check whether we have cached the ipaddr. */ if (canonical_host_ip == NULL) { if (packet_connection_is_on_socket()) { @@ -402,13 +426,11 @@ get_peer_port(int sock) int get_remote_port(void) { - static int port = -1; - /* Cache to avoid getpeername() on a dead connection */ - if (port == -1) - port = get_port(0); + if (cached_port == -1) + cached_port = get_port(0); - return port; + return cached_port; } int diff --git a/crypto/openssh/canohost.h b/crypto/openssh/canohost.h index d9b41ffe5..4c8636f42 100644 --- a/crypto/openssh/canohost.h +++ b/crypto/openssh/canohost.h @@ -1,4 +1,4 @@ -/* $OpenBSD: canohost.h,v 1.10 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: canohost.h,v 1.11 2009/05/27 06:31:25 andreas Exp $ */ /* * Author: Tatu Ylonen @@ -24,6 +24,6 @@ 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 index dea60ba24..d8c53a4a8 100644 --- a/crypto/openssh/channels.c +++ b/crypto/openssh/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.295 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.303 2010/01/30 21:12:08 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -228,12 +229,16 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, channel_max_fd = MAX(channel_max_fd, wfd); channel_max_fd = MAX(channel_max_fd, efd); - /* XXX set close-on-exec -markus */ + if (rfd != -1) + fcntl(rfd, F_SETFD, FD_CLOEXEC); + if (wfd != -1 && wfd != rfd) + fcntl(wfd, F_SETFD, FD_CLOEXEC); + if (efd != -1 && efd != rfd && efd != wfd) + fcntl(efd, F_SETFD, FD_CLOEXEC); c->rfd = rfd; c->wfd = wfd; c->sock = (rfd == wfd) ? rfd : -1; - c->ctl_fd = -1; /* XXX: set elsewhere */ c->efd = efd; c->extended_usage = extusage; @@ -322,6 +327,10 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd, c->output_filter = NULL; c->filter_ctx = NULL; c->filter_cleanup = NULL; + c->ctl_chan = -1; + c->mux_rcb = NULL; + c->mux_ctx = NULL; + c->delayed = 1; /* prevent call to channel_post handler */ TAILQ_INIT(&c->status_confirms); debug("channel %d: new [%s]", found, remote_name); return c; @@ -363,11 +372,10 @@ channel_close_fd(int *fdp) 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); + debug3("channel %d: close_fds r %d w %d e %d", + c->self, c->rfd, c->wfd, c->efd); 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); @@ -393,8 +401,6 @@ channel_free(Channel *c) 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); @@ -516,6 +522,7 @@ channel_still_open(void) case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_MUX_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_DYNAMIC: @@ -529,6 +536,7 @@ channel_still_open(void) case SSH_CHANNEL_OPENING: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_MUX_CLIENT: return 1; case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING: @@ -560,6 +568,8 @@ channel_find_open(void) case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_MUX_LISTENER: + case SSH_CHANNEL_MUX_CLIENT: case SSH_CHANNEL_OPENING: case SSH_CHANNEL_CONNECTING: case SSH_CHANNEL_ZOMBIE: @@ -610,6 +620,8 @@ channel_open_message(void) case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_ZOMBIE: + case SSH_CHANNEL_MUX_CLIENT: + case SSH_CHANNEL_MUX_LISTENER: continue; case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_OPENING: @@ -620,12 +632,12 @@ channel_open_message(void) 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", + " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cc %d)\r\n", c->self, c->remote_name, c->type, c->remote_id, c->istate, buffer_len(&c->input), c->ostate, buffer_len(&c->output), - c->rfd, c->wfd, c->ctl_fd); + c->rfd, c->wfd, c->ctl_chan); buffer_append(&buffer, buf, strlen(buf)); continue; default: @@ -832,9 +844,6 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset) 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 */ @@ -979,6 +988,28 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset) } } +static void +channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset) +{ + if (c->istate == CHAN_INPUT_OPEN && + buffer_check_alloc(&c->input, CHAN_RBUF)) + FD_SET(c->rfd, readset); + if (c->istate == CHAN_INPUT_WAIT_DRAIN) { + /* clear buffer immediately (discard any partial packet) */ + buffer_clear(&c->input); + chan_ibuf_empty(c); + /* Start output drain. XXX just kill chan? */ + chan_rcvd_oclose(c); + } + if (c->ostate == CHAN_OUTPUT_OPEN || + c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (buffer_len(&c->output) > 0) + FD_SET(c->wfd, writeset); + else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) + chan_obuf_empty(c); + } +} + /* try to decode a socks4 header */ /* ARGSUSED */ static int @@ -1210,6 +1241,30 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) return 1; } +Channel * +channel_connect_stdio_fwd(const char *host_to_connect, u_short port_to_connect, + int in, int out) +{ + Channel *c; + + debug("channel_connect_stdio_fwd %s:%d", host_to_connect, + port_to_connect); + + c = channel_new("stdio-forward", SSH_CHANNEL_OPENING, in, out, + -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "stdio-forward", /*nonblock*/0); + + c->path = xstrdup(host_to_connect); + c->host_port = port_to_connect; + c->listening_port = 0; + c->force_drain = 1; + + channel_register_fds(c, in, out, -1, 0, 1, 0); + port_open_helper(c, "direct-tcpip"); + + return c; +} + /* dynamic port forwarding */ static void channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) @@ -1219,7 +1274,6 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) 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. */ @@ -1322,6 +1376,13 @@ port_open_helper(Channel *c, char *rtype) char *remote_ipaddr = get_peer_ipaddr(c->sock); int remote_port = get_peer_port(c->sock); + if (remote_port == -1) { + /* Fake addr/port to appease peers that validate it (Tectia) */ + xfree(remote_ipaddr); + remote_ipaddr = xstrdup("127.0.0.1"); + remote_port = 65535; + } + direct = (strcmp(rtype, "direct-tcpip") == 0); snprintf(buf, sizeof buf, @@ -1423,16 +1484,8 @@ channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset) 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 { + if (nextstate != SSH_CHANNEL_DYNAMIC) port_open_helper(nc, rtype); - } } } @@ -1653,6 +1706,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) } 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)) { @@ -1666,6 +1720,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset) packet_send(); } } +#endif buffer_consume(&c->output, len); if (compat20 && len > 0) { c->local_consumed += len; @@ -1720,36 +1775,6 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) 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) { @@ -1775,17 +1800,136 @@ channel_check_window(Channel *c) 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); } +static u_int +read_mux(Channel *c, u_int need) +{ + char buf[CHAN_RBUF]; + int len; + u_int rlen; + + if (buffer_len(&c->input) < need) { + rlen = need - buffer_len(&c->input); + len = read(c->rfd, buf, MIN(rlen, CHAN_RBUF)); + if (len <= 0) { + if (errno != EINTR && errno != EAGAIN) { + debug2("channel %d: ctl read<=0 rfd %d len %d", + c->self, c->rfd, len); + chan_read_failed(c); + return 0; + } + } else + buffer_append(&c->input, buf, len); + } + return buffer_len(&c->input); +} + +static void +channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset) +{ + u_int need; + ssize_t len; + + if (!compat20) + fatal("%s: entered with !compat20", __func__); + + if (c->rfd != -1 && FD_ISSET(c->rfd, readset) && + (c->istate == CHAN_INPUT_OPEN || + c->istate == CHAN_INPUT_WAIT_DRAIN)) { + /* + * Don't not read past the precise end of packets to + * avoid disrupting fd passing. + */ + if (read_mux(c, 4) < 4) /* read header */ + return; + need = get_u32(buffer_ptr(&c->input)); +#define CHANNEL_MUX_MAX_PACKET (256 * 1024) + if (need > CHANNEL_MUX_MAX_PACKET) { + debug2("channel %d: packet too big %u > %u", + c->self, CHANNEL_MUX_MAX_PACKET, need); + chan_rcvd_oclose(c); + return; + } + if (read_mux(c, need + 4) < need + 4) /* read body */ + return; + if (c->mux_rcb(c) != 0) { + debug("channel %d: mux_rcb failed", c->self); + chan_mark_dead(c); + return; + } + } + + if (c->wfd != -1 && FD_ISSET(c->wfd, writeset) && + buffer_len(&c->output) > 0) { + len = write(c->wfd, buffer_ptr(&c->output), + buffer_len(&c->output)); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return; + if (len <= 0) { + chan_mark_dead(c); + return; + } + buffer_consume(&c->output, len); + } +} + +static void +channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) +{ + Channel *nc; + struct sockaddr_storage addr; + socklen_t addrlen; + int newsock; + uid_t euid; + gid_t egid; + + if (!FD_ISSET(c->sock, readset)) + return; + + debug("multiplexing control connection"); + + /* + * Accept connection on control socket + */ + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); + if ((newsock = accept(c->sock, (struct sockaddr*)&addr, + &addrlen)) == -1) { + error("%s accept: %s", __func__, strerror(errno)); + return; + } + + if (getpeereid(newsock, &euid, &egid) < 0) { + error("%s getpeereid failed: %s", __func__, + strerror(errno)); + close(newsock); + return; + } + if ((euid != 0) && (getuid() != euid)) { + error("multiplex uid mismatch: peer euid %u != uid %u", + (u_int)euid, (u_int)getuid()); + close(newsock); + return; + } + nc = channel_new("multiplex client", SSH_CHANNEL_MUX_CLIENT, + newsock, newsock, -1, c->local_window_max, + c->local_maxpacket, 0, "mux-control", 1); + nc->mux_rcb = c->mux_rcb; + debug3("%s: new mux channel %d fd %d", __func__, + nc->self, nc->sock); + /* establish state */ + nc->mux_rcb(nc); + /* mux state transitions must not elicit protocol messages */ + nc->flags |= CHAN_LOCAL; +} + /* ARGSUSED */ static void channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) @@ -1814,6 +1958,8 @@ channel_handler_init_20(void) channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; + channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; @@ -1822,6 +1968,8 @@ channel_handler_init_20(void) channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; + channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; + channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; } static void @@ -1908,17 +2056,23 @@ static void channel_handler(chan_fn *ftab[], fd_set *readset, fd_set *writeset) { static int did_init = 0; - u_int i; + u_int i, oalloc; Channel *c; if (!did_init) { channel_handler_init(); did_init = 1; } - for (i = 0; i < channels_alloc; i++) { + for (i = 0, oalloc = channels_alloc; i < oalloc; i++) { c = channels[i]; if (c == NULL) continue; + if (c->delayed) { + if (ftab == channel_pre) + c->delayed = 0; + else + continue; + } if (ftab[c->type] != NULL) (*ftab[c->type])(c, readset, writeset); channel_garbage_collect(c); @@ -2431,7 +2585,7 @@ channel_input_status_confirm(int type, u_int32_t seq, void *ctxt) int id; /* Reset keepalive timeout */ - keep_alive_timeouts = 0; + packet_set_alive_timeouts(0); id = packet_get_int(); packet_check_eom(); @@ -2575,6 +2729,8 @@ channel_setup_fwd_listener(int type, const char *listen_addr, } channel_set_reuseaddr(sock); + if (ai->ai_family == AF_INET6) + sock_set_v6only(sock); debug("Local forwarding listening on %s port %s.", ntop, strport); @@ -3106,13 +3262,8 @@ x11_create_display_inet(int x11_display_offset, int x11_use_localhost, 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 (ai->ai_family == AF_INET6) + sock_set_v6only(sock); if (x11_use_localhost) channel_set_reuseaddr(sock); if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { diff --git a/crypto/openssh/channels.h b/crypto/openssh/channels.h index 1488ed7e5..cc71885f4 100644 --- a/crypto/openssh/channels.h +++ b/crypto/openssh/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.98 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.103 2010/01/26 01:28:35 djm Exp $ */ /* * Author: Tatu Ylonen @@ -53,7 +53,9 @@ #define SSH_CHANNEL_CONNECTING 12 #define SSH_CHANNEL_DYNAMIC 13 #define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */ -#define SSH_CHANNEL_MAX_TYPE 15 +#define SSH_CHANNEL_MUX_LISTENER 15 /* Listener for mux conn. */ +#define SSH_CHANNEL_MUX_CLIENT 16 /* Conn. to mux slave */ +#define SSH_CHANNEL_MAX_TYPE 17 struct Channel; typedef struct Channel Channel; @@ -81,6 +83,9 @@ struct channel_connect { struct addrinfo *ai, *aitop; }; +/* Callbacks for mux channels back into client-specific code */ +typedef int mux_callback_fn(struct Channel *); + struct Channel { int type; /* channel type/state */ int self; /* my own channel identifier */ @@ -92,12 +97,16 @@ struct Channel { int wfd; /* write fd */ int efd; /* extended fd */ int sock; /* sock fd */ - int ctl_fd; /* control fd (client sharing) */ + int ctl_chan; /* control channel (multiplexed connections) */ int isatty; /* rfd is a tty */ int wfd_isatty; /* wfd is a tty */ int client_tty; /* (client) TTY has been requested */ int force_drain; /* force close on iEOF */ - int delayed; /* fdset hack */ + int delayed; /* post-select handlers for newly created + * channels are delayed until the first call + * to a matching pre-select handler. + * this way post-select handlers are not + * accidenly called if a FD gets reused */ Buffer input; /* data read from socket, to be sent over * encrypted connection */ Buffer output; /* data received over encrypted connection for @@ -138,6 +147,10 @@ struct Channel { /* non-blocking connect */ struct channel_connect connect_ctx; + + /* multiplexing protocol hook, called for each packet received */ + mux_callback_fn *mux_rcb; + void *mux_ctx; }; #define CHAN_EXTENDED_IGNORE 0 @@ -168,6 +181,7 @@ struct Channel { #define CHAN_CLOSE_RCVD 0x02 #define CHAN_EOF_SENT 0x04 #define CHAN_EOF_RCVD 0x08 +#define CHAN_LOCAL 0x10 #define CHAN_RBUF 16*1024 @@ -239,6 +253,7 @@ void channel_clear_adm_permitted_opens(void); void channel_print_adm_permitted_opens(void); int channel_input_port_forward_request(int, int); Channel *channel_connect_to(const char *, u_short, char *, char *); +Channel *channel_connect_stdio_fwd(const char*, u_short, int, int); Channel *channel_connect_by_listen_address(u_short, char *, char *); int channel_request_remote_forwarding(const char *, u_short, const char *, u_short); diff --git a/crypto/openssh/clientloop.c b/crypto/openssh/clientloop.c index a2d2d1d07..6ffef95a2 100644 --- a/crypto/openssh/clientloop.c +++ b/crypto/openssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.209 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.218 2010/01/28 00:21:18 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -109,6 +109,7 @@ #include "misc.h" #include "match.h" #include "msg.h" +#include "roaming.h" /* import options */ extern Options options; @@ -120,7 +121,7 @@ extern int stdin_null_flag; extern int no_shell_flag; /* Control socket */ -extern int muxserver_sock; +extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */ /* * Name of the host we are connecting to. This is the name given on the @@ -129,6 +130,9 @@ extern int muxserver_sock; */ extern char *host; +/* Force TTY allocation */ +extern int force_tty_flag; + /* * Flag to indicate that we have received a window change signal which has * not yet been processed. This will cause a message indicating the new @@ -142,7 +146,7 @@ static volatile sig_atomic_t received_signal = 0; 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. */ +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. */ @@ -160,6 +164,8 @@ static int session_closed = 0; /* In SSH2: login session closed. */ static void client_init_dispatch(void); int session_ident = -1; +int session_resumed = 0; + /* Track escape per proto2 channel */ struct escape_filter_ctx { int escape_pending; @@ -491,13 +497,13 @@ client_global_request_reply(int type, u_int32_t seq, void *ctxt) xfree(gc); } - keep_alive_timeouts = 0; + packet_set_alive_timeouts(0); } static void server_alive_check(void) { - if (++keep_alive_timeouts > options.server_alive_count_max) { + if (packet_inc_alive_timeouts() > options.server_alive_count_max) { logit("Timeout, server not responding."); cleanup_exit(255); } @@ -558,9 +564,6 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, 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 @@ -607,7 +610,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); - leave_raw_mode(); + leave_raw_mode(force_tty_flag); /* * Free (and clear) the buffer to reduce the amount of data that gets @@ -628,14 +631,14 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) buffer_init(bout); buffer_init(berr); - enter_raw_mode(); + enter_raw_mode(force_tty_flag); } static void client_process_net_input(fd_set *readset) { - int len; - char buf[8192]; + int len, cont = 0; + char buf[SSH_IOBUFSZ]; /* * Read input from the server, and add any such data to the buffer of @@ -643,8 +646,8 @@ client_process_net_input(fd_set *readset) */ if (FD_ISSET(connection_in, readset)) { /* Read as much as possible. */ - len = read(connection_in, buf, sizeof(buf)); - if (len == 0) { + len = roaming_read(connection_in, buf, sizeof(buf), &cont); + if (len == 0 && cont == 0) { /* * Received EOF. The remote host has closed the * connection. @@ -689,7 +692,7 @@ client_status_confirm(int type, Channel *c, void *ctx) /* XXX supress on mux _client_ quietmode */ tochan = options.log_level >= SYSLOG_LEVEL_ERROR && - c->ctl_fd != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; + c->ctl_chan != -1 && c->extended_usage == CHAN_EXTENDED_WRITE; if (type == SSH2_MSG_CHANNEL_SUCCESS) { debug2("%s request accepted on channel %d", @@ -771,7 +774,7 @@ process_cmdline(void) bzero(&fwd, sizeof(fwd)); fwd.listen_host = fwd.connect_host = NULL; - leave_raw_mode(); + leave_raw_mode(force_tty_flag); handler = signal(SIGINT, SIG_IGN); cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); if (s == NULL) @@ -833,6 +836,7 @@ process_cmdline(void) while (isspace(*++s)) ; + /* XXX update list of forwards in options */ if (delete) { cancel_port = 0; cancel_host = hpdelim(&s); /* may be NULL */ @@ -874,7 +878,7 @@ process_cmdline(void) out: signal(SIGINT, handler); - enter_raw_mode(); + enter_raw_mode(force_tty_flag); if (cmd) xfree(cmd); if (fwd.listen_host != NULL) @@ -930,7 +934,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, escape_char); buffer_append(berr, string, strlen(string)); - if (c && c->ctl_fd != -1) { + if (c && c->ctl_chan != -1) { chan_read_failed(c); chan_write_failed(c); return 0; @@ -940,7 +944,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, case 'Z' - 64: /* XXX support this for mux clients */ - if (c && c->ctl_fd != -1) { + if (c && c->ctl_chan != -1) { noescape: snprintf(string, sizeof string, "%c%c escape not available to " @@ -985,7 +989,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, continue; case '&': - if (c && c->ctl_fd != -1) + if (c && c->ctl_chan != -1) goto noescape; /* * Detach the program (continue to serve @@ -993,7 +997,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, * more new connections). */ /* Restore tty modes. */ - leave_raw_mode(); + leave_raw_mode(force_tty_flag); /* Stop listening for new connections. */ channel_stop_listening(); @@ -1036,7 +1040,7 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr, continue; case '?': - if (c && c->ctl_fd != -1) { + if (c && c->ctl_chan != -1) { snprintf(string, sizeof string, "%c?\r\n\ Supported escape sequences:\r\n\ @@ -1085,7 +1089,7 @@ Supported escape sequences:\r\n\ continue; case 'C': - if (c && c->ctl_fd != -1) + if (c && c->ctl_chan != -1) goto noescape; process_cmdline(); continue; @@ -1128,7 +1132,7 @@ static void client_process_input(fd_set *readset) { int len; - char buf[8192]; + char buf[SSH_IOBUFSZ]; /* Read input from stdin. */ if (FD_ISSET(fileno(stdin), readset)) { @@ -1288,7 +1292,7 @@ client_channel_closed(int id, void *arg) { channel_cancel_cleanup(id); session_closed = 1; - leave_raw_mode(); + leave_raw_mode(force_tty_flag); } /* @@ -1321,8 +1325,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) connection_in = packet_get_connection_in(); connection_out = packet_get_connection_out(); max_fd = MAX(connection_in, connection_out); - if (muxserver_sock != -1) - max_fd = MAX(max_fd, muxserver_sock); if (!compat20) { /* enable nonblocking unless tty */ @@ -1361,7 +1363,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) signal(SIGWINCH, window_change_handler); if (have_pty) - enter_raw_mode(); + enter_raw_mode(force_tty_flag); if (compat20) { session_ident = ssh2_chan_id; @@ -1440,12 +1442,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /* 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; @@ -1459,6 +1455,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) client_process_output(writeset); } + if (session_resumed) { + connection_in = packet_get_connection_in(); + connection_out = packet_get_connection_out(); + max_fd = MAX(max_fd, connection_out); + max_fd = MAX(max_fd, connection_in); + session_resumed = 0; + } + /* * Send as much buffered packet data as possible to the * sender. @@ -1476,10 +1480,18 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) /* 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(); + leave_raw_mode(force_tty_flag); /* restore blocking io */ if (!isatty(fileno(stdin))) @@ -1837,15 +1849,17 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt) chan_rcvd_eow(c); } else if (strcmp(rtype, "exit-status") == 0) { exitval = packet_get_int(); - if (id == session_ident) { + if (c->ctl_chan != -1) { + mux_exit_message(c, exitval); + success = 1; + } else if (id == session_ident) { + /* Record exit value of local session */ success = 1; exit_status = exitval; - } else 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; + /* Probably for a mux channel that has already closed */ + debug("%s: no sink for exit-status on channel %d", + __func__, id); } packet_check_eom(); } @@ -2041,7 +2055,7 @@ client_init_dispatch(void) void cleanup_exit(int i) { - leave_raw_mode(); + leave_raw_mode(force_tty_flag); leave_non_blocking(); if (options.control_path != NULL && muxserver_sock != -1) unlink(options.control_path); diff --git a/crypto/openssh/clientloop.h b/crypto/openssh/clientloop.h index 8bb874b38..0b8257b99 100644 --- a/crypto/openssh/clientloop.h +++ b/crypto/openssh/clientloop.h @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.h,v 1.22 2008/06/12 15:19:17 djm Exp $ */ +/* $OpenBSD: clientloop.h,v 1.23 2010/01/26 01:28:35 djm Exp $ */ /* * Author: Tatu Ylonen @@ -56,18 +56,14 @@ 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 +#define SSHMUX_VER 4 /* Multiplexing control protocol flags */ #define SSHMUX_COMMAND_OPEN 1 /* Open new connection */ #define SSHMUX_COMMAND_ALIVE_CHECK 2 /* Check master is alive */ #define SSHMUX_COMMAND_TERMINATE 3 /* Ask master to exit */ - -#define SSHMUX_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 */ +#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ void muxserver_listen(void); -int muxserver_accept_control(void); void muxclient(const char *); +void mux_exit_message(Channel *, int); diff --git a/crypto/openssh/config.guess b/crypto/openssh/config.guess index c7607c74f..c2246a4f7 100755 --- a/crypto/openssh/config.guess +++ b/crypto/openssh/config.guess @@ -1,10 +1,10 @@ #! /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 +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 # Free Software Foundation, Inc. -timestamp='2008-04-14' +timestamp='2009-12-30' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -27,16 +27,16 @@ timestamp='2008-04-14' # the same distribution terms that you use for the rest of that program. -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` @@ -56,8 +56,9 @@ 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. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free +Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -170,7 +171,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 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 + | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? @@ -324,14 +325,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize @@ -640,7 +660,7 @@ EOF # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null + grep -q __LP64__ then HP_ARCH="hppa2.0w" else @@ -791,12 +811,12 @@ EOF i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - *:Interix*:[3456]*) + *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; - EM64T | authenticamd) + authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) @@ -806,6 +826,9 @@ EOF [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we @@ -835,6 +858,20 @@ EOF i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -857,6 +894,17 @@ EOF frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; @@ -866,74 +914,33 @@ EOF m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; - mips:Linux:*:*) + mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU - #undef mips - #undef mipsel + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel + CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips + CPU=${UNAME_MACHINE} #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 - }'`" + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu + padre:Linux:*:*) + echo sparc-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} + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level @@ -943,8 +950,11 @@ EOF *) echo hppa-unknown-linux-gnu ;; esac exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux @@ -967,66 +977,6 @@ EOF 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 - #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 @@ -1055,7 +1005,7 @@ EOF i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) @@ -1099,8 +1049,11 @@ EOF 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 + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 @@ -1138,6 +1091,16 @@ EOF 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; @@ -1150,7 +1113,7 @@ EOF rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) @@ -1243,6 +1206,16 @@ EOF *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} @@ -1324,6 +1297,9 @@ EOF i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 diff --git a/crypto/openssh/config.h b/crypto/openssh/config.h index d07ee699a..c975e019e 100644 --- a/crypto/openssh/config.h +++ b/crypto/openssh/config.h @@ -69,6 +69,9 @@ /* 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 */ @@ -120,12 +123,18 @@ /* Define if you don't want to use wtmpx */ #define DISABLE_WTMPX 1 +/* Enable for PKCS#11 support */ +#define ENABLE_PKCS11 + /* Builtin PRNG command timeout */ #define ENTROPY_TIMEOUT_MSEC 200 -/* f_fsid has members */ +/* 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 @@ -456,6 +465,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_GLOB_H 1 +/* Define to 1 if you have the `group_from_gid' function. */ +#define HAVE_GROUP_FROM_GID 1 + /* Define to 1 if you have the header file. */ /* #undef HAVE_GSSAPI_GENERIC_H */ @@ -519,6 +531,9 @@ /* 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 header file. */ /* #undef HAVE_LASTLOG_H */ @@ -543,9 +558,6 @@ /* 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 */ @@ -727,9 +739,6 @@ /* define if you have sa_family_t data type */ #define HAVE_SA_FAMILY_T 1 -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SECTOK_H */ - /* Define if you have SecureWare-based protected password database */ /* #undef HAVE_SECUREWARE */ @@ -754,6 +763,9 @@ /* Define to 1 if you have the `seteuid' function. */ #define HAVE_SETEUID 1 +/* Define to 1 if you have the `setgroupent' function. */ +#define HAVE_SETGROUPENT 1 + /* Define to 1 if you have the `setgroups' function. */ #define HAVE_SETGROUPS 1 @@ -763,6 +775,9 @@ /* Define to 1 if you have the `setluid' function. */ /* #undef HAVE_SETLUID */ +/* Define to 1 if you have the `setpassent' function. */ +#define HAVE_SETPASSENT 1 + /* Define to 1 if you have the `setpcred' function. */ /* #undef HAVE_SETPCRED */ @@ -1066,6 +1081,9 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_USERSEC_H */ +/* Define to 1 if you have the `user_from_uid' function. */ +#define HAVE_USER_FROM_UID 1 + /* Define to 1 if you have the header file. */ /* #undef HAVE_UTIL_H */ @@ -1175,6 +1193,9 @@ EOPNOTSUPP. */ /* #undef LINK_OPNOTSUPP_ERRNO */ +/* Adjust Linux out-of-memory killer */ +/* #undef LINUX_OOM_ADJUST */ + /* max value of long long calculated by configure */ /* #undef LLONG_MAX */ @@ -1227,6 +1248,9 @@ /* 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 */ @@ -1291,9 +1315,6 @@ /* 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 @@ -1310,6 +1331,9 @@ /* 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" @@ -1358,9 +1382,6 @@ /* 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 @@ -1370,9 +1391,6 @@ /* 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 */ @@ -1400,7 +1418,11 @@ /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ +#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 */ diff --git a/crypto/openssh/config.h.in b/crypto/openssh/config.h.in index 84967a461..a61dec609 100644 --- a/crypto/openssh/config.h.in +++ b/crypto/openssh/config.h.in @@ -68,6 +68,9 @@ /* 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 @@ -119,12 +122,18 @@ /* Define if you don't want to use wtmpx */ #undef DISABLE_WTMPX +/* Enable for PKCS#11 support */ +#undef ENABLE_PKCS11 + /* Builtin PRNG command timeout */ #undef ENTROPY_TIMEOUT_MSEC -/* f_fsid has members */ +/* 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 @@ -455,6 +464,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_GLOB_H +/* Define to 1 if you have the `group_from_gid' function. */ +#undef HAVE_GROUP_FROM_GID + /* Define to 1 if you have the header file. */ #undef HAVE_GSSAPI_GENERIC_H @@ -518,6 +530,9 @@ /* 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 header file. */ #undef HAVE_LASTLOG_H @@ -542,9 +557,6 @@ /* 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 @@ -726,9 +738,6 @@ /* define if you have sa_family_t data type */ #undef HAVE_SA_FAMILY_T -/* Define to 1 if you have the header file. */ -#undef HAVE_SECTOK_H - /* Define if you have SecureWare-based protected password database */ #undef HAVE_SECUREWARE @@ -753,6 +762,9 @@ /* Define to 1 if you have the `seteuid' function. */ #undef HAVE_SETEUID +/* Define to 1 if you have the `setgroupent' function. */ +#undef HAVE_SETGROUPENT + /* Define to 1 if you have the `setgroups' function. */ #undef HAVE_SETGROUPS @@ -762,6 +774,9 @@ /* Define to 1 if you have the `setluid' function. */ #undef HAVE_SETLUID +/* Define to 1 if you have the `setpassent' function. */ +#undef HAVE_SETPASSENT + /* Define to 1 if you have the `setpcred' function. */ #undef HAVE_SETPCRED @@ -1065,6 +1080,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_USERSEC_H +/* Define to 1 if you have the `user_from_uid' function. */ +#undef HAVE_USER_FROM_UID + /* Define to 1 if you have the header file. */ #undef HAVE_UTIL_H @@ -1174,6 +1192,9 @@ EOPNOTSUPP. */ #undef LINK_OPNOTSUPP_ERRNO +/* Adjust Linux out-of-memory killer */ +#undef LINUX_OOM_ADJUST + /* max value of long long calculated by configure */ #undef LLONG_MAX @@ -1226,6 +1247,9 @@ /* 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 @@ -1290,9 +1314,6 @@ /* 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 @@ -1309,6 +1330,9 @@ /* 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 @@ -1357,9 +1381,6 @@ /* 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 @@ -1369,9 +1390,6 @@ /* 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 diff --git a/crypto/openssh/defines.h b/crypto/openssh/defines.h index 536ec4978..c9b93bf71 100644 --- a/crypto/openssh/defines.h +++ b/crypto/openssh/defines.h @@ -25,7 +25,7 @@ #ifndef _DEFINES_H #define _DEFINES_H -/* $Id: defines.h,v 1.153 2009/02/01 11:19:54 dtucker Exp $ */ +/* $Id: defines.h,v 1.159 2010/01/13 23:44:34 tim Exp $ */ /* Constants */ @@ -300,6 +300,9 @@ struct sockaddr_un { #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 @@ -591,6 +594,10 @@ struct winsize { #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 @@ -742,4 +749,16 @@ struct winsize { #define INET6_ADDRSTRLEN 46 #endif +#ifndef SSH_IOBUFSZ +# define SSH_IOBUFSZ 8192 +#endif + +#ifndef _NSIG +# ifdef NSIG +# define _NSIG NSIG +# else +# define _NSIG 128 +# endif +#endif + #endif /* _DEFINES_H */ diff --git a/crypto/openssh/dh.c b/crypto/openssh/dh.c index b76605325..b9029d867 100644 --- a/crypto/openssh/dh.c +++ b/crypto/openssh/dh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dh.c,v 1.47 2008/06/26 09:19:39 djm Exp $ */ +/* $OpenBSD: dh.c,v 1.48 2009/10/01 11:37:33 grunk Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * @@ -83,7 +83,7 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) goto fail; strsize = strsep(&cp, " "); /* size */ if (cp == NULL || *strsize == '\0' || - (dhg->size = (u_int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 || + (dhg->size = (int)strtonum(strsize, 0, 64*1024, &errstr)) == 0 || errstr) goto fail; /* The whole group is one bit larger */ diff --git a/crypto/openssh/dns.c b/crypto/openssh/dns.c index a7da03fa3..2e7bb5aae 100644 --- a/crypto/openssh/dns.c +++ b/crypto/openssh/dns.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.c,v 1.25 2008/06/12 00:03:49 dtucker Exp $ */ +/* $OpenBSD: dns.c,v 1.26 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -75,7 +75,7 @@ dns_result_totext(unsigned int res) */ static int dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, - u_char **digest, u_int *digest_len, const Key *key) + u_char **digest, u_int *digest_len, Key *key) { int success = 0; @@ -172,7 +172,7 @@ is_numeric_hostname(const char *hostname) */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, - const Key *hostkey, int *flags) + Key *hostkey, int *flags) { u_int counter; int result; @@ -271,7 +271,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, * 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) +export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) { u_int8_t rdata_pubkey_algorithm = 0; u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; diff --git a/crypto/openssh/dns.h b/crypto/openssh/dns.h index b2633a1fe..90cfd7b92 100644 --- a/crypto/openssh/dns.h +++ b/crypto/openssh/dns.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dns.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: dns.h,v 1.11 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2003 Wesley Griffin. All rights reserved. @@ -46,7 +46,7 @@ enum sshfp_hashes { #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); +int verify_host_key_dns(const char *, struct sockaddr *, Key *, int *); +int export_dns_rr(const char *, Key *, FILE *, int); #endif /* DNS_H */ diff --git a/crypto/openssh/gss-genr.c b/crypto/openssh/gss-genr.c index e9190575d..842f38582 100644 --- a/crypto/openssh/gss-genr.c +++ b/crypto/openssh/gss-genr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gss-genr.c,v 1.19 2007/06/12 11:56:15 dtucker Exp $ */ +/* $OpenBSD: gss-genr.c,v 1.20 2009/06/22 05:39:28 dtucker Exp $ */ /* * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. diff --git a/crypto/openssh/hostfile.c b/crypto/openssh/hostfile.c index 2cceb352a..afab6dad1 100644 --- a/crypto/openssh/hostfile.c +++ b/crypto/openssh/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.45 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -183,6 +183,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen return 1; } +static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA } +check_markers(char **cpp) +{ + char marker[32], *sp, *cp = *cpp; + int ret = MRK_NONE; + + while (*cp == '@') { + /* Only one marker is allowed */ + if (ret != MRK_NONE) + return MRK_ERROR; + /* Markers are terminated by whitespace */ + if ((sp = strchr(cp, ' ')) == NULL && + (sp = strchr(cp, '\t')) == NULL) + return MRK_ERROR; + /* Extract marker for comparison */ + if (sp <= cp + 1 || sp >= cp + sizeof(marker)) + return MRK_ERROR; + memcpy(marker, cp, sp - cp); + marker[sp - cp] = '\0'; + if (strcmp(marker, CA_MARKER) == 0) + ret = MRK_CA; + else if (strcmp(marker, REVOKE_MARKER) == 0) + ret = MRK_REVOKE; + else + return MRK_ERROR; + + /* Skip past marker and any whitespace that follows it */ + cp = sp; + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + } + *cpp = cp; + return ret; +} + /* * 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 @@ -195,16 +230,20 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen 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) + const char *host, const Key *key, int keytype, Key *found, + int want_revocation, int *numret) { FILE *f; char line[8192]; - int linenum = 0; + int want, have, linenum = 0, want_cert = key_is_cert(key); u_int kbits; char *cp, *cp2, *hashed_host; HostStatus end_return; - debug3("check_host_in_hostfile: filename %s", filename); + debug3("check_host_in_hostfile: host %s filename %s", host, filename); + + if (want_revocation && (key == NULL || keytype != 0 || found != NULL)) + fatal("%s: invalid arguments", __func__); /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); @@ -229,6 +268,20 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!*cp || *cp == '#' || *cp == '\n') continue; + if (want_revocation) + want = MRK_REVOKE; + else if (want_cert) + want = MRK_CA; + else + want = MRK_NONE; + + if ((have = check_markers(&cp)) == MRK_ERROR) { + verbose("%s: invalid marker at %s:%d", + __func__, filename, linenum); + continue; + } else if (want != have) + continue; + /* Find the end of the host name portion. */ for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) ; @@ -250,6 +303,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename, /* Got a match. Skip host name. */ cp = cp2; + if (want_revocation) + found = key_new(KEY_UNSPEC); + /* * Extract the key from the line. This will skip any leading * whitespace. Ignore badly formatted lines. @@ -272,9 +328,33 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!hostfile_check_key(kbits, found, host, filename, linenum)) continue; + if (want_revocation) { + if (key_is_cert(key) && + key_equal_public(key->cert->signature_key, found)) { + verbose("check_host_in_hostfile: revoked CA " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + if (key_equal_public(key, found)) { + verbose("check_host_in_hostfile: revoked key " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + key_free(found); + continue; + } + /* Check if the current key is the same as the given key. */ - if (key_equal(key, found)) { - /* Ok, they match. */ + if (want_cert && key_equal(key->cert->signature_key, found)) { + /* Found CA cert for key */ + debug3("check_host_in_hostfile: CA match line %d", + linenum); + fclose(f); + return HOST_OK; + } else if (!want_cert && key_equal(key, found)) { + /* Found identical key */ debug3("check_host_in_hostfile: match line %d", linenum); fclose(f); return HOST_OK; @@ -302,8 +382,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key, { if (key == NULL) fatal("no key to look up"); - return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, - found, numret)); + if (check_host_in_hostfile_by_key_or_type(filename, host, + key, 0, NULL, 1, NULL) == HOST_REVOKED) + return HOST_REVOKED; + return check_host_in_hostfile_by_key_or_type(filename, host, key, 0, + found, 0, numret); } int @@ -311,7 +394,7 @@ 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); + keytype, found, 0, numret) == HOST_FOUND); } /* diff --git a/crypto/openssh/hostfile.h b/crypto/openssh/hostfile.h index d1983b3e0..1d460c1a9 100644 --- a/crypto/openssh/hostfile.h +++ b/crypto/openssh/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.16 2006/03/25 22:22:43 djm Exp $ */ +/* $OpenBSD: hostfile.h,v 1.18 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -15,7 +15,7 @@ #define HOSTFILE_H typedef enum { - HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND + HOST_OK, HOST_NEW, HOST_CHANGED, HOST_REVOKED, HOST_FOUND } HostStatus; int hostfile_read_key(char **, u_int *, Key *); @@ -28,6 +28,9 @@ int lookup_key_in_hostfile_by_type(const char *, const char *, #define HASH_MAGIC "|1|" #define HASH_DELIM '|' +#define CA_MARKER "@cert-authority" +#define REVOKE_MARKER "@revoked" + char *host_hash(const char *, const char *, u_int); #endif diff --git a/crypto/openssh/includes.h b/crypto/openssh/includes.h index f1b47f666..6bb987807 100644 --- a/crypto/openssh/includes.h +++ b/crypto/openssh/includes.h @@ -31,7 +31,8 @@ #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(HAVE_DECL_GLOB_NOMATCH) && HAVE_DECL_GLOB_NOMATCH != 0 && \ + !defined(BROKEN_GLOB) # include #endif #ifdef HAVE_ENDIAN_H diff --git a/crypto/openssh/jpake.c b/crypto/openssh/jpake.c index 565f2e255..130661069 100644 --- a/crypto/openssh/jpake.c +++ b/crypto/openssh/jpake.c @@ -1,4 +1,4 @@ -/* $OpenBSD: jpake.c,v 1.1 2008/11/04 08:22:12 djm Exp $ */ +/* $OpenBSD: jpake.c,v 1.2 2009/03/05 07:18:19 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. * @@ -47,6 +47,7 @@ #include "log.h" #include "jpake.h" +#include "schnorr.h" #ifdef JPAKE @@ -60,165 +61,10 @@ "98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB" \ "9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" -struct jpake_group * +struct modp_group * jpake_default_group(void) { - struct jpake_group *ret; - - ret = xmalloc(sizeof(*ret)); - ret->p = ret->q = ret->g = NULL; - if (BN_hex2bn(&ret->p, JPAKE_GROUP_P) == 0 || - BN_hex2bn(&ret->g, JPAKE_GROUP_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; -} - -/* - * 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 -jpake_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 -jpake_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; - } - } + return modp_group_from_g_and_safe_p(JPAKE_GROUP_G, JPAKE_GROUP_P); } struct jpake_ctx * @@ -243,7 +89,6 @@ jpake_new(void) return ret; } - void jpake_free(struct jpake_ctx *pctx) { @@ -344,7 +189,7 @@ jpake_dump(struct jpake_ctx *pctx, const char *fmt, ...) /* Shared parts of step 1 exchange calculation */ void -jpake_step1(struct jpake_group *grp, +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, @@ -383,11 +228,11 @@ jpake_step1(struct jpake_group *grp, fatal("%s: BN_mod_exp", __func__); /* Generate proofs for holding x1/x3 and x2/x4 */ - if (schnorr_sign(grp->p, grp->q, grp->g, + 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(grp->p, grp->q, grp->g, + 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__); @@ -397,7 +242,7 @@ jpake_step1(struct jpake_group *grp, /* Shared parts of step 2 exchange calculation */ void -jpake_step2(struct jpake_group *grp, BIGNUM *s, +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, @@ -415,10 +260,10 @@ jpake_step2(struct jpake_group *grp, BIGNUM *s, if (BN_cmp(theirpub2, BN_value_one()) <= 0) fatal("%s: theirpub2 <= 1", __func__); - if (schnorr_verify(grp->p, grp->q, grp->g, theirpub1, + 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(grp->p, grp->q, grp->g, theirpub2, + 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__); @@ -459,7 +304,7 @@ jpake_step2(struct jpake_group *grp, BIGNUM *s, JPAKE_DEBUG_BN((exponent, "%s: exponent = ", __func__)); /* Note the generator here is 'tmp', not g */ - if (schnorr_sign(grp->p, grp->q, tmp, exponent, *newpub, + 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__); @@ -496,7 +341,7 @@ jpake_confirm_hash(const BIGNUM *k, /* Shared parts of key derivation and confirmation calculation */ void -jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val, +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, @@ -531,7 +376,7 @@ jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val, JPAKE_DEBUG_BN((tmp, "%s: tmp = ", __func__)); - if (schnorr_verify(grp->p, grp->q, tmp, step2_val, + 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__); diff --git a/crypto/openssh/jpake.h b/crypto/openssh/jpake.h index a3d800cd3..a3f2cf025 100644 --- a/crypto/openssh/jpake.h +++ b/crypto/openssh/jpake.h @@ -1,4 +1,4 @@ -/* $OpenBSD: jpake.h,v 1.1 2008/11/04 08:22:13 djm Exp $ */ +/* $OpenBSD: jpake.h,v 1.2 2009/03/05 07:18:19 djm Exp $ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. * @@ -28,20 +28,16 @@ # define JPAKE_DEBUG_BUF(a) # define JPAKE_DEBUG_CTX(a) #else -# define JPAKE_DEBUG_BN(a) jpake_debug3_bn a -# define JPAKE_DEBUG_BUF(a) jpake_debug3_buf a +# 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 /* SCHNORR_DEBUG */ - -struct jpake_group { - BIGNUM *p, *q, *g; -}; +#endif /* JPAKE_DEBUG */ #define KZP_ID_LEN 16 /* Length of client and server IDs */ struct jpake_ctx { /* Parameters */ - struct jpake_group *grp; + struct modp_group *grp; /* Private values shared by client and server */ BIGNUM *s; /* Secret (salted, crypted password) */ @@ -83,26 +79,18 @@ struct jpake_ctx { }; /* jpake.c */ -struct jpake_group *jpake_default_group(void); -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 jpake_debug3_bn(const BIGNUM *, const char *, ...) - __attribute__((__nonnull__ (2))) - __attribute__((format(printf, 2, 3))); -void jpake_debug3_buf(const u_char *, u_int, const char *, ...) - __attribute__((__nonnull__ (3))) - __attribute__((format(printf, 3, 4))); +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 jpake_group *, u_char **, u_int *, +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 jpake_group *, BIGNUM *, +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, @@ -113,7 +101,7 @@ void jpake_confirm_hash(const BIGNUM *, const u_char *, u_int, u_char **, u_int *); -void jpake_key_confirm(struct jpake_group *, BIGNUM *, BIGNUM *, +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, @@ -122,13 +110,5 @@ void jpake_key_confirm(struct jpake_group *, BIGNUM *, BIGNUM *, int jpake_check_confirm(const BIGNUM *, const u_char *, u_int, const u_char *, u_int, const u_char *, u_int); -/* schnorr.c */ -int schnorr_sign(const BIGNUM *, const BIGNUM *, const BIGNUM *, - const BIGNUM *, const BIGNUM *, const u_char *, u_int , - u_char **, u_int *); -int schnorr_verify(const BIGNUM *, const BIGNUM *, const BIGNUM *, - const BIGNUM *, 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 index 48b54f5f7..148cfee80 100644 --- a/crypto/openssh/kex.c +++ b/crypto/openssh/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.80 2008/09/06 12:24:13 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.82 2009/10/24 11:13:54 andreas Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -48,8 +48,7 @@ #include "match.h" #include "dispatch.h" #include "monitor.h" - -#define KEX_COOKIE_LEN 16 +#include "roaming.h" #if OPENSSL_VERSION_NUMBER >= 0x00907000L # if defined(HAVE_EVP_SHA256) @@ -388,6 +387,16 @@ kex_choose_conf(Kex *kex) sprop=peer; } + /* Check whether server offers roaming */ + if (!kex->server) { + char *roaming; + roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); + if (roaming) { + kex->roaming = 1; + xfree(roaming); + } + } + /* Algorithm Negotiation */ for (mode = 0; mode < MODE_MAX; mode++) { newkeys = xcalloc(1, sizeof(*newkeys)); diff --git a/crypto/openssh/kex.h b/crypto/openssh/kex.h index 8e29c90e9..62fa2ea50 100644 --- a/crypto/openssh/kex.h +++ b/crypto/openssh/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.46 2007/06/07 19:37:34 pvalchev Exp $ */ +/* $OpenBSD: kex.h,v 1.49 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -30,10 +30,13 @@ #include #include +#define KEX_COOKIE_LEN 16 + #define KEX_DH1 "diffie-hellman-group1-sha1" #define KEX_DH14 "diffie-hellman-group14-sha1" #define KEX_DHGEX_SHA1 "diffie-hellman-group-exchange-sha1" #define KEX_DHGEX_SHA256 "diffie-hellman-group-exchange-sha256" +#define KEX_RESUME "resume@appgate.com" #define COMP_NONE 0 #define COMP_ZLIB 1 @@ -114,6 +117,7 @@ struct Kex { char *name; int hostkey_type; int kex_type; + int roaming; Buffer my; Buffer peer; sig_atomic_t done; @@ -122,7 +126,8 @@ struct Kex { char *client_version_string; char *server_version_string; int (*verify_host_key)(Key *); - Key *(*load_host_key)(int); + Key *(*load_host_public_key)(int); + Key *(*load_host_private_key)(int); int (*host_key_index)(Key *); void (*kex[KEX_MAX])(Kex *); }; diff --git a/crypto/openssh/kexdhs.c b/crypto/openssh/kexdhs.c index 861708818..e722877d5 100644 --- a/crypto/openssh/kexdhs.c +++ b/crypto/openssh/kexdhs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexdhs.c,v 1.9 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD: kexdhs.c,v 1.11 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * @@ -50,7 +50,7 @@ kexdh_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; DH *dh; - Key *server_host_key; + Key *server_host_public, *server_host_private; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, hashlen, slen; int kout; @@ -71,11 +71,16 @@ kexdh_server(Kex *kex) debug("expecting SSH2_MSG_KEXDH_INIT"); packet_read_expect(SSH2_MSG_KEXDH_INIT); - if (kex->load_host_key == NULL) + if (kex->load_host_public_key == NULL || + kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) + server_host_public = kex->load_host_public_key(kex->hostkey_type); + if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); + server_host_private = kex->load_host_private_key(kex->hostkey_type); + if (server_host_private == NULL) + fatal("Missing private key for hostkey type %d", + kex->hostkey_type); /* key, cert */ if ((dh_client_pub = BN_new()) == NULL) @@ -113,7 +118,7 @@ kexdh_server(Kex *kex) memset(kbuf, 0, klen); xfree(kbuf); - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); /* calc H */ kex_dh_hash( @@ -137,7 +142,9 @@ kexdh_server(Kex *kex) } /* sign H */ - PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, hashlen)); + if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, + hashlen)) < 0) + fatal("kexdh_server: key_sign failed"); /* destroy_sensitive_data(); */ diff --git a/crypto/openssh/kexgexs.c b/crypto/openssh/kexgexs.c index 76a0f8ca7..f4156af96 100644 --- a/crypto/openssh/kexgexs.c +++ b/crypto/openssh/kexgexs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kexgexs.c,v 1.11 2009/01/01 21:17:36 djm Exp $ */ +/* $OpenBSD: kexgexs.c,v 1.13 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -52,18 +52,24 @@ void kexgex_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; - Key *server_host_key; + Key *server_host_public, *server_host_private; DH *dh; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, slen, hashlen; int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; int type, kout; - if (kex->load_host_key == NULL) + if (kex->load_host_public_key == NULL || + kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); - server_host_key = kex->load_host_key(kex->hostkey_type); - if (server_host_key == NULL) + server_host_public = kex->load_host_public_key(kex->hostkey_type); + if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); + server_host_private = kex->load_host_private_key(kex->hostkey_type); + if (server_host_private == NULL) + fatal("Missing private key for hostkey type %d", + kex->hostkey_type); + type = packet_read(); switch (type) { @@ -149,7 +155,7 @@ kexgex_server(Kex *kex) memset(kbuf, 0, klen); xfree(kbuf); - key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) omin = min = omax = max = -1; @@ -179,7 +185,9 @@ kexgex_server(Kex *kex) } /* sign H */ - PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, hashlen)); + if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, + hashlen)) < 0) + fatal("kexgex_server: key_sign failed"); /* destroy_sensitive_data(); */ diff --git a/crypto/openssh/key.c b/crypto/openssh/key.c index 3e17da601..0d0c912e6 100644 --- a/crypto/openssh/key.c +++ b/crypto/openssh/key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: key.c,v 1.80 2008/10/10 05:00:12 stevesk Exp $ */ +/* $OpenBSD: key.c,v 1.85 2010/03/04 01:44:57 djm Exp $ */ /* * read_bignum(): * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -52,6 +52,21 @@ #include "uuencode.h" #include "buffer.h" #include "log.h" +#include "ssh2.h" + +static struct KeyCert * +cert_new(void) +{ + struct KeyCert *cert; + + cert = xcalloc(1, sizeof(*cert)); + buffer_init(&cert->certblob); + buffer_init(&cert->constraints); + cert->key_id = NULL; + cert->principals = NULL; + cert->signature_key = NULL; + return cert; +} Key * key_new(int type) @@ -63,9 +78,11 @@ key_new(int type) k->type = type; k->dsa = NULL; k->rsa = NULL; + k->cert = NULL; switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if ((rsa = RSA_new()) == NULL) fatal("key_new: RSA_new failed"); if ((rsa->n = BN_new()) == NULL) @@ -75,6 +92,7 @@ key_new(int type) k->rsa = rsa; break; case KEY_DSA: + case KEY_DSA_CERT: if ((dsa = DSA_new()) == NULL) fatal("key_new: DSA_new failed"); if ((dsa->p = BN_new()) == NULL) @@ -93,16 +111,20 @@ key_new(int type) fatal("key_new: bad key type %d", k->type); break; } + + if (key_is_cert(k)) + k->cert = cert_new(); + return k; } -Key * -key_new_private(int type) +void +key_add_private(Key *k) { - Key *k = key_new(type); switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if ((k->rsa->d = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); if ((k->rsa->iqmp = BN_new()) == NULL) @@ -117,6 +139,7 @@ key_new_private(int type) fatal("key_new_private: BN_new failed"); break; case KEY_DSA: + case KEY_DSA_CERT: if ((k->dsa->priv_key = BN_new()) == NULL) fatal("key_new_private: BN_new failed"); break; @@ -125,9 +148,34 @@ key_new_private(int type) default: break; } +} + +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + + key_add_private(k); return k; } +static void +cert_free(struct KeyCert *cert) +{ + u_int i; + + buffer_free(&cert->certblob); + buffer_free(&cert->constraints); + if (cert->key_id != NULL) + xfree(cert->key_id); + for (i = 0; i < cert->nprincipals; i++) + xfree(cert->principals[i]); + if (cert->principals != NULL) + xfree(cert->principals); + if (cert->signature_key != NULL) + key_free(cert->signature_key); +} + void key_free(Key *k) { @@ -136,11 +184,13 @@ key_free(Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: if (k->rsa != NULL) RSA_free(k->rsa); k->rsa = NULL; break; case KEY_DSA: + case KEY_DSA_CERT: if (k->dsa != NULL) DSA_free(k->dsa); k->dsa = NULL; @@ -151,20 +201,49 @@ key_free(Key *k) fatal("key_free: bad key type %d", k->type); break; } + if (key_is_cert(k)) { + if (k->cert != NULL) + cert_free(k->cert); + k->cert = NULL; + } + xfree(k); } +static int +cert_compare(struct KeyCert *a, struct KeyCert *b) +{ + if (a == NULL && b == NULL) + return 1; + if (a == NULL || b == NULL) + return 0; + if (buffer_len(&a->certblob) != buffer_len(&b->certblob)) + return 0; + if (memcmp(buffer_ptr(&a->certblob), buffer_ptr(&b->certblob), + buffer_len(&a->certblob)) != 0) + return 0; + return 1; +} + +/* + * Compare public portions of key only, allowing comparisons between + * certificates and plain keys too. + */ int -key_equal(const Key *a, const Key *b) +key_equal_public(const Key *a, const Key *b) { - if (a == NULL || b == NULL || a->type != b->type) + if (a == NULL || b == NULL || + key_type_plain(a->type) != key_type_plain(b->type)) return 0; + switch (a->type) { case KEY_RSA1: + case KEY_RSA_CERT: case KEY_RSA: return a->rsa != NULL && b->rsa != NULL && BN_cmp(a->rsa->e, b->rsa->e) == 0 && BN_cmp(a->rsa->n, b->rsa->n) == 0; + case KEY_DSA_CERT: case KEY_DSA: return a->dsa != NULL && b->dsa != NULL && BN_cmp(a->dsa->p, b->dsa->p) == 0 && @@ -177,16 +256,27 @@ key_equal(const Key *a, const Key *b) /* NOTREACHED */ } +int +key_equal(const Key *a, const Key *b) +{ + if (a == NULL || b == NULL || a->type != b->type) + return 0; + if (key_is_cert(a)) { + if (!cert_compare(a->cert, b->cert)) + return 0; + } + return key_equal_public(a, b); +} + u_char* -key_fingerprint_raw(const Key *k, enum fp_type dgst_type, - u_int *dgst_raw_length) +key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) { const EVP_MD *md = NULL; EVP_MD_CTX ctx; u_char *blob = NULL; u_char *retval = NULL; u_int len = 0; - int nlen, elen; + int nlen, elen, otype; *dgst_raw_length = 0; @@ -214,6 +304,14 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type, case KEY_RSA: key_to_blob(k, &blob, &len); break; + case KEY_DSA_CERT: + case KEY_RSA_CERT: + /* We want a fingerprint of the _key_ not of the cert */ + otype = k->type; + k->type = key_type_plain(k->type); + key_to_blob(k, &blob, &len); + k->type = otype; + break; case KEY_UNSPEC: return retval; default: @@ -408,7 +506,7 @@ key_fingerprint_randomart(u_char *dgst_raw, u_int dgst_raw_len, const Key *k) } char * -key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +key_fingerprint(Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) { char *retval = NULL; u_char *dgst_raw; @@ -522,11 +620,19 @@ key_read(Key *ret, char **cpp) return -1; if (!read_bignum(cpp, ret->rsa->n)) return -1; + /* validate the claimed number of bits */ + if ((u_int)BN_num_bits(ret->rsa->n) != bits) { + verbose("key_read: claimed key size %d does not match " + "actual %d", bits, BN_num_bits(ret->rsa->n)); + return -1; + } success = 1; break; case KEY_UNSPEC: case KEY_RSA: case KEY_DSA: + case KEY_DSA_CERT: + case KEY_RSA_CERT: space = strchr(cp, ' '); if (space == NULL) { debug3("key_read: missing whitespace"); @@ -571,25 +677,36 @@ key_read(Key *ret, char **cpp) return -1; } /*XXXX*/ - if (ret->type == KEY_RSA) { + if (key_is_cert(ret)) { + if (!key_is_cert(k)) { + error("key_read: loaded key is not a cert"); + key_free(k); + return -1; + } + if (ret->cert != NULL) + cert_free(ret->cert); + ret->cert = k->cert; + k->cert = NULL; + } + if (key_type_plain(ret->type) == KEY_RSA) { if (ret->rsa != NULL) RSA_free(ret->rsa); ret->rsa = k->rsa; k->rsa = NULL; - success = 1; #ifdef DEBUG_PK RSA_print_fp(stderr, ret->rsa, 8); #endif - } else { + } + if (key_type_plain(ret->type) == KEY_DSA) { 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 } + success = 1; /*XXXX*/ key_free(k); if (success != 1) @@ -616,28 +733,53 @@ key_write(const Key *key, FILE *f) u_char *blob; char *uu; - if (key->type == KEY_RSA1 && key->rsa != NULL) { + if (key_is_cert(key)) { + if (key->cert == NULL) { + error("%s: no cert data", __func__); + return 0; + } + if (buffer_len(&key->cert->certblob) == 0) { + error("%s: no signed certificate blob", __func__); + return 0; + } + } + + switch (key->type) { + case KEY_RSA1: + if (key->rsa == NULL) + return 0; /* size of modulus 'n' */ bits = BN_num_bits(key->rsa->n); fprintf(f, "%u", bits); if (write_bignum(f, key->rsa->e) && - write_bignum(f, key->rsa->n)) { - 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); + write_bignum(f, key->rsa->n)) + return 1; + error("key_write: failed for RSA key"); + return 0; + case KEY_DSA: + case KEY_DSA_CERT: + if (key->dsa == NULL) + return 0; + break; + case KEY_RSA: + case KEY_RSA_CERT: + if (key->rsa == NULL) + return 0; + break; + default: + return 0; + } + + key_to_blob(key, &blob, &len); + uu = xmalloc(2*len); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", key_ssh_name(key), uu); + success = 1; } + xfree(blob); + xfree(uu); + return success; } @@ -651,6 +793,10 @@ key_type(const Key *k) return "RSA"; case KEY_DSA: return "DSA"; + case KEY_RSA_CERT: + return "RSA-CERT"; + case KEY_DSA_CERT: + return "DSA-CERT"; } return "unknown"; } @@ -663,6 +809,10 @@ key_ssh_name(const Key *k) return "ssh-rsa"; case KEY_DSA: return "ssh-dss"; + case KEY_RSA_CERT: + return "ssh-rsa-cert-v00@openssh.com"; + case KEY_DSA_CERT: + return "ssh-dss-cert-v00@openssh.com"; } return "ssh-unknown"; } @@ -673,8 +823,10 @@ key_size(const Key *k) switch (k->type) { case KEY_RSA1: case KEY_RSA: + case KEY_RSA_CERT: return BN_num_bits(k->rsa->n); case KEY_DSA: + case KEY_DSA_CERT: return BN_num_bits(k->dsa->p); } return 0; @@ -685,7 +837,7 @@ rsa_generate_private_key(u_int bits) { RSA *private; - private = RSA_generate_key(bits, 35, NULL, NULL); + private = RSA_generate_key(bits, RSA_F4, NULL, NULL); if (private == NULL) fatal("rsa_generate_private_key: key generation failed."); return private; @@ -717,6 +869,9 @@ key_generate(int type, u_int bits) case KEY_RSA1: k->rsa = rsa_generate_private_key(bits); break; + case KEY_RSA_CERT: + case KEY_DSA_CERT: + fatal("key_generate: cert keys cannot be generated directly"); default: fatal("key_generate: unknown type %d", type); } @@ -724,12 +879,55 @@ key_generate(int type, u_int bits) return k; } +void +key_cert_copy(const Key *from_key, struct Key *to_key) +{ + u_int i; + const struct KeyCert *from; + struct KeyCert *to; + + if (to_key->cert != NULL) { + cert_free(to_key->cert); + to_key->cert = NULL; + } + + if ((from = from_key->cert) == NULL) + return; + + to = to_key->cert = cert_new(); + + buffer_append(&to->certblob, buffer_ptr(&from->certblob), + buffer_len(&from->certblob)); + + buffer_append(&to->constraints, buffer_ptr(&from->constraints), + buffer_len(&from->constraints)); + + to->type = from->type; + to->key_id = from->key_id == NULL ? NULL : xstrdup(from->key_id); + to->valid_after = from->valid_after; + to->valid_before = from->valid_before; + to->signature_key = from->signature_key == NULL ? + NULL : key_from_private(from->signature_key); + + to->nprincipals = from->nprincipals; + if (to->nprincipals > CERT_MAX_PRINCIPALS) + fatal("%s: nprincipals (%u) > CERT_MAX_PRINCIPALS (%u)", + __func__, to->nprincipals, CERT_MAX_PRINCIPALS); + if (to->nprincipals > 0) { + to->principals = xcalloc(from->nprincipals, + sizeof(*to->principals)); + for (i = 0; i < to->nprincipals; i++) + to->principals[i] = xstrdup(from->principals[i]); + } +} + Key * key_from_private(const Key *k) { Key *n = NULL; switch (k->type) { case KEY_DSA: + case KEY_DSA_CERT: n = key_new(k->type); if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || (BN_copy(n->dsa->q, k->dsa->q) == NULL) || @@ -739,6 +937,7 @@ key_from_private(const Key *k) break; case KEY_RSA: case KEY_RSA1: + case KEY_RSA_CERT: n = key_new(k->type); if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || (BN_copy(n->rsa->e, k->rsa->e) == NULL)) @@ -748,6 +947,8 @@ key_from_private(const Key *k) fatal("key_from_private: unknown type %d", k->type); break; } + if (key_is_cert(k)) + key_cert_copy(k, n); return n; } @@ -764,6 +965,10 @@ key_type_from_name(char *name) return KEY_RSA; } else if (strcmp(name, "ssh-dss") == 0) { return KEY_DSA; + } else if (strcmp(name, "ssh-rsa-cert-v00@openssh.com") == 0) { + return KEY_RSA_CERT; + } else if (strcmp(name, "ssh-dss-cert-v00@openssh.com") == 0) { + return KEY_DSA_CERT; } debug2("key_type_from_name: unknown key type '%s'", name); return KEY_UNSPEC; @@ -791,6 +996,127 @@ key_names_valid2(const char *names) return 1; } +static int +cert_parse(Buffer *b, Key *key, const u_char *blob, u_int blen) +{ + u_char *principals, *constraints, *sig_key, *sig; + u_int signed_len, plen, clen, sklen, slen, kidlen; + Buffer tmp; + char *principal; + int ret = -1; + + buffer_init(&tmp); + + /* Copy the entire key blob for verification and later serialisation */ + buffer_append(&key->cert->certblob, blob, blen); + + principals = constraints = sig_key = sig = NULL; + if (buffer_get_int_ret(&key->cert->type, b) != 0 || + (key->cert->key_id = buffer_get_string_ret(b, &kidlen)) == NULL || + (principals = buffer_get_string_ret(b, &plen)) == NULL || + buffer_get_int64_ret(&key->cert->valid_after, b) != 0 || + buffer_get_int64_ret(&key->cert->valid_before, b) != 0 || + (constraints = buffer_get_string_ret(b, &clen)) == NULL || + /* skip nonce */ buffer_get_string_ptr_ret(b, NULL) == NULL || + /* skip reserved */ buffer_get_string_ptr_ret(b, NULL) == NULL || + (sig_key = buffer_get_string_ret(b, &sklen)) == NULL) { + error("%s: parse error", __func__); + goto out; + } + + if (kidlen != strlen(key->cert->key_id)) { + error("%s: key ID contains \\0 character", __func__); + goto out; + } + + /* Signature is left in the buffer so we can calculate this length */ + signed_len = buffer_len(&key->cert->certblob) - buffer_len(b); + + if ((sig = buffer_get_string_ret(b, &slen)) == NULL) { + error("%s: parse error", __func__); + goto out; + } + + if (key->cert->type != SSH2_CERT_TYPE_USER && + key->cert->type != SSH2_CERT_TYPE_HOST) { + error("Unknown certificate type %u", key->cert->type); + goto out; + } + + buffer_append(&tmp, principals, plen); + while (buffer_len(&tmp) > 0) { + if (key->cert->nprincipals >= CERT_MAX_PRINCIPALS) { + error("%s: Too many principals", __func__); + goto out; + } + if ((principal = buffer_get_string_ret(&tmp, &plen)) == NULL) { + error("%s: Principals data invalid", __func__); + goto out; + } + if (strlen(principal) != plen) { + error("%s: Principal contains \\0 character", + __func__); + goto out; + } + key->cert->principals = xrealloc(key->cert->principals, + key->cert->nprincipals + 1, sizeof(*key->cert->principals)); + key->cert->principals[key->cert->nprincipals++] = principal; + } + + buffer_clear(&tmp); + + buffer_append(&key->cert->constraints, constraints, clen); + buffer_append(&tmp, constraints, clen); + /* validate structure */ + while (buffer_len(&tmp) != 0) { + if (buffer_get_string_ptr_ret(&tmp, NULL) == NULL || + buffer_get_string_ptr_ret(&tmp, NULL) == NULL) { + error("%s: Constraints data invalid", __func__); + goto out; + } + } + buffer_clear(&tmp); + + if ((key->cert->signature_key = key_from_blob(sig_key, + sklen)) == NULL) { + error("%s: Signature key invalid", __func__); + goto out; + } + if (key->cert->signature_key->type != KEY_RSA && + key->cert->signature_key->type != KEY_DSA) { + error("%s: Invalid signature key type %s (%d)", __func__, + key_type(key->cert->signature_key), + key->cert->signature_key->type); + goto out; + } + + switch (key_verify(key->cert->signature_key, sig, slen, + buffer_ptr(&key->cert->certblob), signed_len)) { + case 1: + ret = 0; + break; /* Good signature */ + case 0: + error("%s: Invalid signature on certificate", __func__); + goto out; + case -1: + error("%s: Certificate signature verification failed", + __func__); + goto out; + } + + out: + buffer_free(&tmp); + if (principals != NULL) + xfree(principals); + if (constraints != NULL) + xfree(constraints); + if (sig_key != NULL) + xfree(sig_key); + if (sig != NULL) + xfree(sig); + return ret; +} + Key * key_from_blob(const u_char *blob, u_int blen) { @@ -813,10 +1139,12 @@ key_from_blob(const u_char *blob, u_int blen) switch (type) { case KEY_RSA: + case KEY_RSA_CERT: key = key_new(type); if (buffer_get_bignum2_ret(&b, key->rsa->e) == -1 || buffer_get_bignum2_ret(&b, key->rsa->n) == -1) { error("key_from_blob: can't read rsa key"); + badkey: key_free(key); key = NULL; goto out; @@ -826,15 +1154,14 @@ key_from_blob(const u_char *blob, u_int blen) #endif break; case KEY_DSA: + case KEY_DSA_CERT: 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; + goto badkey; } #ifdef DEBUG_PK DSA_print_fp(stderr, key->dsa, 8); @@ -847,6 +1174,10 @@ key_from_blob(const u_char *blob, u_int blen) error("key_from_blob: cannot handle type %s", ktype); goto out; } + if (key_is_cert(key) && cert_parse(&b, key, blob, blen) == -1) { + error("key_from_blob: can't parse cert data"); + goto badkey; + } rlen = buffer_len(&b); if (key != NULL && rlen != 0) error("key_from_blob: remaining bytes in key blob %d", rlen); @@ -869,6 +1200,12 @@ key_to_blob(const Key *key, u_char **blobp, u_int *lenp) } buffer_init(&b); switch (key->type) { + case KEY_DSA_CERT: + case KEY_RSA_CERT: + /* Use the existing blob */ + buffer_append(&b, buffer_ptr(&key->cert->certblob), + buffer_len(&key->cert->certblob)); + break; case KEY_DSA: buffer_put_cstring(&b, key_ssh_name(key)); buffer_put_bignum2(&b, key->dsa->p); @@ -905,8 +1242,10 @@ key_sign( const u_char *data, u_int datalen) { switch (key->type) { + case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_sign(key, sigp, lenp, data, datalen); + case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_sign(key, sigp, lenp, data, datalen); default: @@ -929,8 +1268,10 @@ key_verify( return -1; switch (key->type) { + case KEY_DSA_CERT: case KEY_DSA: return ssh_dss_verify(key, signature, signaturelen, data, datalen); + case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_verify(key, signature, signaturelen, data, datalen); default: @@ -952,6 +1293,9 @@ key_demote(const Key *k) pk->rsa = NULL; switch (k->type) { + case KEY_RSA_CERT: + key_cert_copy(k, pk); + /* FALLTHROUGH */ case KEY_RSA1: case KEY_RSA: if ((pk->rsa = RSA_new()) == NULL) @@ -961,6 +1305,9 @@ key_demote(const Key *k) if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) fatal("key_demote: BN_dup failed"); break; + case KEY_DSA_CERT: + key_cert_copy(k, pk); + /* FALLTHROUGH */ case KEY_DSA: if ((pk->dsa = DSA_new()) == NULL) fatal("key_demote: DSA_new failed"); @@ -980,3 +1327,199 @@ key_demote(const Key *k) return (pk); } + +int +key_is_cert(const Key *k) +{ + return k != NULL && + (k->type == KEY_RSA_CERT || k->type == KEY_DSA_CERT); +} + +/* Return the cert-less equivalent to a certified key type */ +int +key_type_plain(int type) +{ + switch (type) { + case KEY_RSA_CERT: + return KEY_RSA; + case KEY_DSA_CERT: + return KEY_DSA; + default: + return type; + } +} + +/* Convert a KEY_RSA or KEY_DSA to their _CERT equivalent */ +int +key_to_certified(Key *k) +{ + switch (k->type) { + case KEY_RSA: + k->cert = cert_new(); + k->type = KEY_RSA_CERT; + return 0; + case KEY_DSA: + k->cert = cert_new(); + k->type = KEY_DSA_CERT; + return 0; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + return -1; + } +} + +/* Convert a KEY_RSA_CERT or KEY_DSA_CERT to their raw key equivalent */ +int +key_drop_cert(Key *k) +{ + switch (k->type) { + case KEY_RSA_CERT: + cert_free(k->cert); + k->type = KEY_RSA; + return 0; + case KEY_DSA_CERT: + cert_free(k->cert); + k->type = KEY_DSA; + return 0; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + return -1; + } +} + +/* Sign a KEY_RSA_CERT or KEY_DSA_CERT, (re-)generating the signed certblob */ +int +key_certify(Key *k, Key *ca) +{ + Buffer principals; + u_char *ca_blob, *sig_blob, nonce[32]; + u_int i, ca_len, sig_len; + + if (k->cert == NULL) { + error("%s: key lacks cert info", __func__); + return -1; + } + + if (!key_is_cert(k)) { + error("%s: certificate has unknown type %d", __func__, + k->cert->type); + return -1; + } + + if (ca->type != KEY_RSA && ca->type != KEY_DSA) { + error("%s: CA key has unsupported type %s", __func__, + key_type(ca)); + return -1; + } + + key_to_blob(ca, &ca_blob, &ca_len); + + buffer_clear(&k->cert->certblob); + buffer_put_cstring(&k->cert->certblob, key_ssh_name(k)); + + switch (k->type) { + case KEY_DSA_CERT: + buffer_put_bignum2(&k->cert->certblob, k->dsa->p); + buffer_put_bignum2(&k->cert->certblob, k->dsa->q); + buffer_put_bignum2(&k->cert->certblob, k->dsa->g); + buffer_put_bignum2(&k->cert->certblob, k->dsa->pub_key); + break; + case KEY_RSA_CERT: + buffer_put_bignum2(&k->cert->certblob, k->rsa->e); + buffer_put_bignum2(&k->cert->certblob, k->rsa->n); + break; + default: + error("%s: key has incorrect type %s", __func__, key_type(k)); + buffer_clear(&k->cert->certblob); + xfree(ca_blob); + return -1; + } + + buffer_put_int(&k->cert->certblob, k->cert->type); + buffer_put_cstring(&k->cert->certblob, k->cert->key_id); + + buffer_init(&principals); + for (i = 0; i < k->cert->nprincipals; i++) + buffer_put_cstring(&principals, k->cert->principals[i]); + buffer_put_string(&k->cert->certblob, buffer_ptr(&principals), + buffer_len(&principals)); + buffer_free(&principals); + + buffer_put_int64(&k->cert->certblob, k->cert->valid_after); + buffer_put_int64(&k->cert->certblob, k->cert->valid_before); + buffer_put_string(&k->cert->certblob, + buffer_ptr(&k->cert->constraints), + buffer_len(&k->cert->constraints)); + + arc4random_buf(&nonce, sizeof(nonce)); + buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); + buffer_put_string(&k->cert->certblob, NULL, 0); /* reserved */ + buffer_put_string(&k->cert->certblob, ca_blob, ca_len); + xfree(ca_blob); + + /* Sign the whole mess */ + if (key_sign(ca, &sig_blob, &sig_len, buffer_ptr(&k->cert->certblob), + buffer_len(&k->cert->certblob)) != 0) { + error("%s: signature operation failed", __func__); + buffer_clear(&k->cert->certblob); + return -1; + } + /* Append signature and we are done */ + buffer_put_string(&k->cert->certblob, sig_blob, sig_len); + xfree(sig_blob); + + return 0; +} + +int +key_cert_check_authority(const Key *k, int want_host, int require_principal, + const char *name, const char **reason) +{ + u_int i, principal_matches; + time_t now = time(NULL); + + if (want_host) { + if (k->cert->type != SSH2_CERT_TYPE_HOST) { + *reason = "Certificate invalid: not a host certificate"; + return -1; + } + } else { + if (k->cert->type != SSH2_CERT_TYPE_USER) { + *reason = "Certificate invalid: not a user certificate"; + return -1; + } + } + if (now < 0) { + error("%s: system clock lies before epoch", __func__); + *reason = "Certificate invalid: not yet valid"; + return -1; + } + if ((u_int64_t)now < k->cert->valid_after) { + *reason = "Certificate invalid: not yet valid"; + return -1; + } + if ((u_int64_t)now >= k->cert->valid_before) { + *reason = "Certificate invalid: expired"; + return -1; + } + if (k->cert->nprincipals == 0) { + if (require_principal) { + *reason = "Certificate lacks principal list"; + return -1; + } + } else { + principal_matches = 0; + for (i = 0; i < k->cert->nprincipals; i++) { + if (strcmp(name, k->cert->principals[i]) == 0) { + principal_matches = 1; + break; + } + } + if (!principal_matches) { + *reason = "Certificate invalid: name is not a listed " + "principal"; + return -1; + } + } + return 0; +} diff --git a/crypto/openssh/key.h b/crypto/openssh/key.h index 14aac79c2..6a2e049af 100644 --- a/crypto/openssh/key.h +++ b/crypto/openssh/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.27 2008/06/11 21:01:35 grunk Exp $ */ +/* $OpenBSD: key.h,v 1.28 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -26,6 +26,7 @@ #ifndef KEY_H #define KEY_H +#include "buffer.h" #include #include @@ -34,6 +35,8 @@ enum types { KEY_RSA1, KEY_RSA, KEY_DSA, + KEY_RSA_CERT, + KEY_DSA_CERT, KEY_UNSPEC }; enum fp_type { @@ -49,20 +52,35 @@ enum fp_rep { /* key is stored in external hardware */ #define KEY_FLAG_EXT 0x0001 +#define CERT_MAX_PRINCIPALS 256 +struct KeyCert { + Buffer certblob; /* Kept around for use on wire */ + u_int type; /* SSH2_CERT_TYPE_USER or SSH2_CERT_TYPE_HOST */ + char *key_id; + u_int nprincipals; + char **principals; + u_int64_t valid_after, valid_before; + Buffer constraints; + Key *signature_key; +}; + struct Key { int type; int flags; RSA *rsa; DSA *dsa; + struct KeyCert *cert; }; Key *key_new(int); +void key_add_private(Key *); Key *key_new_private(int); void key_free(Key *); Key *key_demote(const Key *); +int key_equal_public(const Key *, const Key *); int key_equal(const Key *, const Key *); -char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); -u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); +char *key_fingerprint(Key *, enum fp_type, enum fp_rep); +u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *); const char *key_type(const Key *); int key_write(const Key *, FILE *); int key_read(Key *, char **); @@ -71,6 +89,14 @@ u_int key_size(const Key *); Key *key_generate(int, u_int); Key *key_from_private(const Key *); int key_type_from_name(char *); +int key_is_cert(const Key *); +int key_type_plain(int); +int key_to_certified(Key *); +int key_drop_cert(Key *); +int key_certify(Key *, Key *); +void key_cert_copy(const Key *, struct Key *); +int key_cert_check_authority(const Key *, int, int, const char *, + const char **); Key *key_from_blob(const u_char *, u_int); int key_to_blob(const Key *, u_char **, u_int *); diff --git a/crypto/openssh/loginrec.c b/crypto/openssh/loginrec.c index f4af06736..57413db07 100644 --- a/crypto/openssh/loginrec.c +++ b/crypto/openssh/loginrec.c @@ -1316,8 +1316,8 @@ wtmpx_write_entry(struct logininfo *li) 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 ) { + if (strncmp(li->username, utx->ut_user, + MIN_SIZEOF(li->username, utx->ut_user)) == 0 ) { # ifdef HAVE_TYPE_IN_UTMPX if (utx->ut_type == USER_PROCESS) return (1); diff --git a/crypto/openssh/match.h b/crypto/openssh/match.h index 18f683070..3d7f70fc0 100644 --- a/crypto/openssh/match.h +++ b/crypto/openssh/match.h @@ -1,4 +1,4 @@ -/* $OpenBSD: match.h,v 1.14 2008/06/10 03:57:27 djm Exp $ */ +/* $OpenBSD: match.h,v 1.15 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen @@ -23,5 +23,5 @@ char *match_list(const char *, const char *, u_int *); /* addrmatch.c */ int addr_match_list(const char *, const char *); - +int addr_match_cidr_list(const char *, const char *); #endif diff --git a/crypto/openssh/misc.c b/crypto/openssh/misc.c index 143dbf0e2..e1f723123 100644 --- a/crypto/openssh/misc.c +++ b/crypto/openssh/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.71 2009/02/21 19:32:04 tobias Exp $ */ +/* $OpenBSD: misc.c,v 1.75 2010/01/09 23:04:13 dtucker Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -560,11 +560,11 @@ char * percent_expand(const char *string, ...) { #define EXPAND_MAX_KEYS 16 + u_int num_keys, i, j; struct { const char *key; const char *repl; } keys[EXPAND_MAX_KEYS]; - u_int num_keys, i, j; char buf[4096]; va_list ap; @@ -576,13 +576,12 @@ percent_expand(const char *string, ...) break; keys[num_keys].repl = va_arg(ap, char *); if (keys[num_keys].repl == NULL) - fatal("percent_expand: NULL replacement"); + fatal("%s: NULL replacement", __func__); } + if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) + fatal("%s: too many keys", __func__); va_end(ap); - if (num_keys >= EXPAND_MAX_KEYS) - fatal("percent_expand: too many keys"); - /* Expand string */ *buf = '\0'; for (i = 0; *string != '\0'; string++) { @@ -590,23 +589,24 @@ percent_expand(const char *string, ...) append: buf[i++] = *string; if (i >= sizeof(buf)) - fatal("percent_expand: string too long"); + fatal("%s: string too long", __func__); buf[i] = '\0'; continue; } string++; + /* %% case */ if (*string == '%') goto append; for (j = 0; j < num_keys; j++) { if (strchr(keys[j].key, *string) != NULL) { i = strlcat(buf, keys[j].repl, sizeof(buf)); if (i >= sizeof(buf)) - fatal("percent_expand: string too long"); + fatal("%s: string too long", __func__); break; } } if (j >= num_keys) - fatal("percent_expand: unknown key %%%c", *string); + fatal("%s: unknown key %%%c", __func__, *string); } return (xstrdup(buf)); #undef EXPAND_MAX_KEYS @@ -849,3 +849,14 @@ ms_to_timeval(struct timeval *tv, int ms) tv->tv_usec = (ms % 1000) * 1000; } +void +sock_set_v6only(int s) +{ +#ifdef IPV6_V6ONLY + int on = 1; + + debug3("%s: set socket %d IPV6_V6ONLY", __func__, s); + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) + error("setsockopt IPV6_V6ONLY: %s", strerror(errno)); +#endif +} diff --git a/crypto/openssh/misc.h b/crypto/openssh/misc.h index 5da170d2f..32073acd4 100644 --- a/crypto/openssh/misc.h +++ b/crypto/openssh/misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.h,v 1.38 2008/06/12 20:38:28 dtucker Exp $ */ +/* $OpenBSD: misc.h,v 1.41 2010/01/09 23:04:13 dtucker Exp $ */ /* * Author: Tatu Ylonen @@ -35,6 +35,7 @@ char *tohex(const void *, size_t); void sanitise_stdfd(void); void ms_subtract_diff(struct timeval *, int *); void ms_to_timeval(struct timeval *, int); +void sock_set_v6only(int); struct passwd *pwcopy(struct passwd *); const char *ssh_gai_strerror(int); diff --git a/crypto/openssh/monitor.c b/crypto/openssh/monitor.c index f57e74ba5..334aedde5 100644 --- a/crypto/openssh/monitor.c +++ b/crypto/openssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.101 2009/02/12 03:26:22 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.106 2010/03/07 11:57:13 dtucker Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -88,6 +88,7 @@ #include "compat.h" #include "ssh2.h" #include "jpake.h" +#include "roaming.h" #ifdef GSSAPI static Gssctxt *gsscontext = NULL; @@ -100,7 +101,6 @@ extern Newkeys *current_keys[]; extern z_stream incoming_stream; extern z_stream outgoing_stream; extern u_char session_id[]; -extern Buffer input, output; extern Buffer auth_debug; extern int auth_debug_init; extern Buffer loginmsg; @@ -126,6 +126,8 @@ struct { 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 */ @@ -995,17 +997,6 @@ mm_answer_pam_free_ctx(int sock, Buffer *m) } #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) { @@ -1088,8 +1079,6 @@ mm_answer_keyallowed(int sock, Buffer *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) @@ -1473,8 +1462,6 @@ mm_answer_rsa_keyallowed(int sock, Buffer *m) 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); @@ -1670,15 +1657,20 @@ monitor_apply_keystate(struct monitor *pmonitor) /* Network I/O buffers */ /* XXX inefficient for large buffers, need: buffer_init_from_string */ - buffer_clear(&input); - buffer_append(&input, child_state.input, child_state.ilen); + 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(&output); - buffer_append(&output, child_state.output, child_state.olen); + 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 * @@ -1714,7 +1706,8 @@ mm_get_kex(Buffer *m) 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->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; return (kex); @@ -1794,6 +1787,12 @@ mm_get_keystate(struct monitor *pmonitor) 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); } diff --git a/crypto/openssh/monitor_fdpass.c b/crypto/openssh/monitor_fdpass.c index 4b9a066bc..7eb6f5c6e 100644 --- a/crypto/openssh/monitor_fdpass.c +++ b/crypto/openssh/monitor_fdpass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_fdpass.c,v 1.18 2008/11/30 11:59:26 dtucker Exp $ */ +/* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 djm Exp $ */ /* * Copyright 2001 Niels Provos * All rights reserved. @@ -34,6 +34,9 @@ #endif #include +#ifdef HAVE_POLL_H +#include +#endif #include #include @@ -55,6 +58,7 @@ mm_send_fd(int sock, int fd) struct iovec vec; char ch = '\0'; ssize_t n; + struct pollfd pfd; memset(&msg, 0, sizeof(msg)); #ifdef HAVE_ACCRIGHTS_IN_MSGHDR @@ -75,9 +79,13 @@ mm_send_fd(int sock, int fd) msg.msg_iov = &vec; msg.msg_iovlen = 1; - while ((n = sendmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN || - errno == EINTR)) + pfd.fd = sock; + pfd.events = POLLOUT; + while ((n = sendmsg(sock, &msg, 0)) == -1 && + (errno == EAGAIN || errno == EINTR)) { debug3("%s: sendmsg(%d): %s", __func__, fd, strerror(errno)); + (void)poll(&pfd, 1, -1); + } if (n == -1) { error("%s: sendmsg(%d): %s", __func__, fd, strerror(errno)); @@ -112,6 +120,7 @@ mm_receive_fd(int sock) ssize_t n; char ch; int fd; + struct pollfd pfd; memset(&msg, 0, sizeof(msg)); vec.iov_base = &ch; @@ -126,9 +135,13 @@ mm_receive_fd(int sock) msg.msg_controllen = sizeof(cmsgbuf.buf); #endif - while ((n = recvmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN || - errno == EINTR)) + pfd.fd = sock; + pfd.events = POLLIN; + while ((n = recvmsg(sock, &msg, 0)) == -1 && + (errno == EAGAIN || errno == EINTR)) { debug3("%s: recvmsg: %s", __func__, strerror(errno)); + (void)poll(&pfd, 1, -1); + } if (n == -1) { error("%s: recvmsg: %s", __func__, strerror(errno)); return -1; diff --git a/crypto/openssh/monitor_mm.c b/crypto/openssh/monitor_mm.c index dab747532..faf9f3dcb 100644 --- a/crypto/openssh/monitor_mm.c +++ b/crypto/openssh/monitor_mm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_mm.c,v 1.15 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: monitor_mm.c,v 1.16 2009/06/22 05:39:28 dtucker Exp $ */ /* * Copyright 2002 Niels Provos * All rights reserved. diff --git a/crypto/openssh/monitor_wrap.c b/crypto/openssh/monitor_wrap.c index 0986fc518..faeb02cfa 100644 --- a/crypto/openssh/monitor_wrap.c +++ b/crypto/openssh/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.64 2008/11/04 08:22:13 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.69 2010/03/07 11:57:13 dtucker Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -71,19 +71,19 @@ #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 Newkeys *newkeys[]; extern z_stream incoming_stream; extern z_stream outgoing_stream; extern struct monitor *pmonitor; -extern Buffer input, output; extern Buffer loginmsg; extern ServerOptions options; @@ -347,19 +347,6 @@ mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, 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) { @@ -393,9 +380,6 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) 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); @@ -508,7 +492,7 @@ mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) Enc *enc; Mac *mac; Comp *comp; - Newkeys *newkey = newkeys[mode]; + Newkeys *newkey = (Newkeys *)packet_get_newkeys(mode); debug3("%s: converting %p", __func__, newkey); @@ -570,7 +554,7 @@ mm_send_kex(Buffer *m, Kex *kex) void mm_send_keystate(struct monitor *monitor) { - Buffer m; + Buffer m, *input, *output; u_char *blob, *p; u_int bloblen, plen; u_int32_t seqnr, packets; @@ -608,7 +592,8 @@ mm_send_keystate(struct monitor *monitor) } debug3("%s: Sending new keys: %p %p", - __func__, newkeys[MODE_OUT], newkeys[MODE_IN]); + __func__, packet_get_newkeys(MODE_OUT), + packet_get_newkeys(MODE_IN)); /* Keys from Kex */ if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) @@ -655,8 +640,16 @@ mm_send_keystate(struct monitor *monitor) buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); /* Network I/O buffers */ - buffer_put_string(&m, buffer_ptr(&input), buffer_len(&input)); - buffer_put_string(&m, buffer_ptr(&output), buffer_len(&output)); + 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__); @@ -1076,7 +1069,6 @@ mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) *rkey = key; xfree(blob); } - mm_send_debug(&m); buffer_free(&m); return (allowed); @@ -1282,7 +1274,7 @@ mm_auth2_jpake_get_pwdata(Authctxt *authctxt, BIGNUM **s, } void -mm_jpake_step1(struct jpake_group *grp, +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, @@ -1317,7 +1309,7 @@ mm_jpake_step1(struct jpake_group *grp, } void -mm_jpake_step2(struct jpake_group *grp, BIGNUM *s, +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, @@ -1357,7 +1349,7 @@ mm_jpake_step2(struct jpake_group *grp, BIGNUM *s, } void -mm_jpake_key_confirm(struct jpake_group *grp, BIGNUM *s, BIGNUM *step2_val, +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, diff --git a/crypto/openssh/monitor_wrap.h b/crypto/openssh/monitor_wrap.h index 55c4b99f3..de2d16f66 100644 --- a/crypto/openssh/monitor_wrap.h +++ b/crypto/openssh/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.21 2008/11/04 08:22:13 djm Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.22 2009/03/05 07:18:19 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -102,17 +102,17 @@ int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **); int mm_skey_respond(void *, u_int, char **); /* jpake */ -struct jpake_group; +struct modp_group; void mm_auth2_jpake_get_pwdata(struct Authctxt *, BIGNUM **, char **, char **); -void mm_jpake_step1(struct jpake_group *, u_char **, u_int *, +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 jpake_group *, BIGNUM *, +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 jpake_group *, BIGNUM *, BIGNUM *, +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, diff --git a/crypto/openssh/mux.c b/crypto/openssh/mux.c index 79f83768b..825fb7a9a 100644 --- a/crypto/openssh/mux.c +++ b/crypto/openssh/mux.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mux.c,v 1.7 2008/06/13 17:21:20 dtucker Exp $ */ +/* $OpenBSD: mux.c,v 1.14 2010/01/30 02:54:53 djm Exp $ */ /* * Copyright (c) 2002-2008 Damien Miller * @@ -17,25 +17,21 @@ /* 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 + * - 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. + * - Better fall-back from mux slave error to new connection. + * - ExitOnForwardingFailure + * - Maybe extension mechanisms for multi-X11/multi-agent forwarding + * - Support ~^Z in mux slaves. + * - Inspect or control sessions in master. + * - If we ever support the "signal" channel request, send signals on + * sessions in master. */ +#include "includes.h" + #include #include #include @@ -55,6 +51,14 @@ #include #endif +#ifdef HAVE_POLL_H +#include +#else +# ifdef HAVE_SYS_POLL_H +# include +# endif +#endif + #ifdef HAVE_UTIL_H # include #endif @@ -82,18 +86,22 @@ /* from ssh.c */ extern int tty_flag; +extern int force_tty_flag; extern Options options; extern int stdin_null_flag; extern char *host; -int subsystem_flag; +extern int subsystem_flag; extern Buffer command; +extern volatile sig_atomic_t quit_pending; +extern char *stdio_forward_host; +extern int stdio_forward_port; /* Context for session open confirmation callback */ struct mux_session_confirm_ctx { - int want_tty; - int want_subsys; - int want_x_fwd; - int want_agent_fwd; + u_int want_tty; + u_int want_subsys; + u_int want_x_fwd; + u_int want_agent_fwd; Buffer cmd; char *term; struct termios tio; @@ -103,6 +111,9 @@ struct mux_session_confirm_ctx { /* fd to control socket */ int muxserver_sock = -1; +/* client request id */ +u_int muxclient_request_id = 0; + /* Multiplexing control command */ u_int muxclient_command = 0; @@ -112,269 +123,242 @@ static volatile sig_atomic_t muxclient_terminate = 0; /* PID of multiplex server */ static u_int muxserver_pid = 0; +static Channel *mux_listener_channel = NULL; -/* ** 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"); +struct mux_master_state { + int hello_rcvd; +}; - if ((muxserver_sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - fatal("%s socket(): %s", __func__, strerror(errno)); +/* mux protocol messages */ +#define MUX_MSG_HELLO 0x00000001 +#define MUX_C_NEW_SESSION 0x10000002 +#define MUX_C_ALIVE_CHECK 0x10000004 +#define MUX_C_TERMINATE 0x10000005 +#define MUX_C_OPEN_FWD 0x10000006 +#define MUX_C_CLOSE_FWD 0x10000007 +#define MUX_C_NEW_STDIO_FWD 0x10000008 +#define MUX_S_OK 0x80000001 +#define MUX_S_PERMISSION_DENIED 0x80000002 +#define MUX_S_FAILURE 0x80000003 +#define MUX_S_EXIT_MESSAGE 0x80000004 +#define MUX_S_ALIVE 0x80000005 +#define MUX_S_SESSION_OPENED 0x80000006 + +/* type codes for MUX_C_OPEN_FWD and MUX_C_CLOSE_FWD */ +#define MUX_FWD_LOCAL 1 +#define MUX_FWD_REMOTE 2 +#define MUX_FWD_DYNAMIC 3 + +static void mux_session_confirm(int, void *); + +static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *); +static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *); + +static const struct { + u_int type; + int (*handler)(u_int, Channel *, Buffer *, Buffer *); +} mux_master_handlers[] = { + { MUX_MSG_HELLO, process_mux_master_hello }, + { MUX_C_NEW_SESSION, process_mux_new_session }, + { MUX_C_ALIVE_CHECK, process_mux_alive_check }, + { MUX_C_TERMINATE, process_mux_terminate }, + { MUX_C_OPEN_FWD, process_mux_open_fwd }, + { MUX_C_CLOSE_FWD, process_mux_close_fwd }, + { MUX_C_NEW_STDIO_FWD, process_mux_stdio_fwd }, + { 0, NULL } +}; - 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)); +/* Cleanup callback fired on closure of mux slave _session_ channel */ +/* ARGSUSED */ +static void +mux_master_session_cleanup_cb(int cid, void *unused) +{ + Channel *cc, *c = channel_by_id(cid); + + debug3("%s: entering for channel %d", __func__, cid); + if (c == NULL) + fatal("%s: channel_by_id(%i) == NULL", __func__, cid); + if (c->ctl_chan != -1) { + if ((cc = channel_by_id(c->ctl_chan)) == NULL) + fatal("%s: channel %d missing control channel %d", + __func__, c->self, c->ctl_chan); + c->ctl_chan = -1; + cc->remote_id = -1; + chan_rcvd_oclose(cc); } - umask(old_umask); - - if (listen(muxserver_sock, 64) == -1) - fatal("%s listen(): %s", __func__, strerror(errno)); - - set_nonblock(muxserver_sock); + channel_cancel_cleanup(c->self); } -/* Callback on open confirmation in mux master for a mux client session. */ +/* Cleanup callback fired on closure of mux slave _control_ channel */ +/* ARGSUSED */ static void -mux_session_confirm(int id, void *arg) +mux_master_control_cleanup_cb(int cid, void *unused) { - 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); + Channel *sc, *c = channel_by_id(cid); + + debug3("%s: entering for channel %d", __func__, cid); + if (c == NULL) + fatal("%s: channel_by_id(%i) == NULL", __func__, cid); + if (c->remote_id != -1) { + if ((sc = channel_by_id(c->remote_id)) == NULL) + debug2("%s: channel %d n session channel %d", + __func__, c->self, c->remote_id); + c->remote_id = -1; + sc->ctl_chan = -1; + if (sc->type != SSH_CHANNEL_OPEN) { + debug2("%s: channel %d: not open", __func__, sc->self); + chan_mark_dead(sc); + } else { + if (sc->istate == CHAN_INPUT_OPEN) + chan_read_failed(sc); + if (sc->ostate == CHAN_OUTPUT_OPEN) + chan_write_failed(sc); + } } - xfree(cctx); + channel_cancel_cleanup(c->self); } -/* - * 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) +/* Check mux client environment variables before passing them to mux master. */ +static int +env_permitted(char *env) { - 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; - } + int i, ret; + char name[1024], *cp; - if (getpeereid(client_fd, &euid, &egid) < 0) { - error("%s getpeereid failed: %s", __func__, strerror(errno)); - close(client_fd); + if ((cp = strchr(env, '=')) == NULL || cp == env) 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); + ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); + if (ret <= 0 || (size_t)ret >= sizeof(name)) { + error("env_permitted: name '%.100s...' too long", env); return 0; } - /* XXX handle asynchronously */ - unset_nonblock(client_fd); + for (i = 0; i < options.num_send_env; i++) + if (match_pattern(name, options.send_env[i])) + return 1; - /* 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; + return 0; +} + +/* Mux master protocol message handlers */ + +static int +process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r) +{ + u_int ver; + struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; + + if (state == NULL) + fatal("%s: channel %d: c->mux_ctx == NULL", __func__, c->self); + if (state->hello_rcvd) { + error("%s: HELLO received twice", __func__); + return -1; } - if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { - error("%s: wrong client version %d", __func__, ver); - buffer_free(&m); - close(client_fd); - return 0; + if (buffer_get_int_ret(&ver, m) != 0) { + malf: + error("%s: malformed message", __func__); + return -1; } + if (ver != SSHMUX_VER) { + error("Unsupported multiplexing protocol version %d " + "(expected %d)", ver, SSHMUX_VER); + return -1; + } + debug2("%s: channel %d slave version %u", __func__, c->self, ver); - allowed = 1; - mux_command = buffer_get_int(&m); - flags = buffer_get_int(&m); - - buffer_clear(&m); + /* No extensions are presently defined */ + while (buffer_len(m) > 0) { + char *name = buffer_get_string_ret(m, NULL); + char *value = buffer_get_string_ret(m, NULL); - 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; + if (name == NULL || value == NULL) { + if (name != NULL) + xfree(name); + goto malf; } - buffer_free(&m); - close(client_fd); - return start_close; - default: - error("Unsupported command %d", mux_command); - buffer_free(&m); - close(client_fd); - return 0; + debug2("Unrecognised slave extension \"%s\"", name); + xfree(name); + xfree(value); } + state->hello_rcvd = 1; + return 0; +} + +static int +process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r) +{ + Channel *nc; + struct mux_session_confirm_ctx *cctx; + char *reserved, *cmd, *cp; + u_int i, j, len, env_len, escape_char, window, packetmax; + int new_fd[3]; /* Reply for SSHMUX_COMMAND_OPEN */ - 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; + cctx = xcalloc(1, sizeof(*cctx)); + cctx->term = NULL; + cmd = reserved = NULL; + if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&cctx->want_tty, m) != 0 || + buffer_get_int_ret(&cctx->want_x_fwd, m) != 0 || + buffer_get_int_ret(&cctx->want_agent_fwd, m) != 0 || + buffer_get_int_ret(&cctx->want_subsys, m) != 0 || + buffer_get_int_ret(&escape_char, m) != 0 || + (cctx->term = buffer_get_string_ret(m, &len)) == NULL || + (cmd = buffer_get_string_ret(m, &len)) == NULL) { + malf: + if (cmd != NULL) + xfree(cmd); + if (reserved != NULL) + xfree(reserved); + if (cctx->term != NULL) + xfree(cctx->term); + error("%s: malformed message", __func__); + return -1; } - - if (!allowed) { - error("Refused control connection"); - close(client_fd); - buffer_free(&m); - return 0; + xfree(reserved); + reserved = NULL; + + cctx->env = NULL; + env_len = 0; + while (buffer_len(m) > 0) { +#define MUX_MAX_ENV_VARS 4096 + if ((cp = buffer_get_string_ret(m, &len)) == NULL) { + xfree(cmd); + goto malf; + } + if (!env_permitted(cp)) { + xfree(cp); + continue; + } + cctx->env = xrealloc(cctx->env, env_len + 2, + sizeof(*cctx->env)); + cctx->env[env_len++] = cp; + cctx->env[env_len] = NULL; + if (env_len > MUX_MAX_ENV_VARS) { + error(">%d environment variables received, ignoring " + "additional", MUX_MAX_ENV_VARS); + break; + } } - 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; - } + debug2("%s: channel %d: request tty %d, X %d, agent %d, subsys %d, " + "term \"%s\", cmd \"%s\", env %u", __func__, c->self, + cctx->want_tty, cctx->want_x_fwd, cctx->want_agent_fwd, + cctx->want_subsys, cctx->term, cmd, env_len); - 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); + cmd = NULL; /* Gather fds from client */ for(i = 0; i < 3; i++) { - if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) { + if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { error("%s: failed to receive fd %d from slave", __func__, i); for (j = 0; j < i; j++) @@ -385,37 +369,56 @@ muxserver_accept_control(void) xfree(cctx->env); xfree(cctx->term); buffer_free(&cctx->cmd); - close(client_fd); xfree(cctx); - return 0; + + /* prepare reply */ + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, + "did not receive file descriptors"); + return -1; } } - debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, + debug3("%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); + /* XXX support multiple child sessions in future */ + if (c->remote_id != -1) { + debug2("%s: session already open", __func__); + /* prepare reply */ + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Multiple sessions not supported"); + cleanup: close(new_fd[0]); close(new_fd[1]); close(new_fd[2]); - buffer_free(&m); xfree(cctx->term); if (env_len != 0) { for (i = 0; i < env_len; i++) xfree(cctx->env[i]); xfree(cctx->env); } + buffer_free(&cctx->cmd); return 0; } - buffer_free(&m); + + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) { + if (!ask_permission("Allow shared connection to %s? ", host)) { + debug2("%s: session refused by user", __func__); + /* prepare reply */ + buffer_put_int(r, MUX_S_PERMISSION_DENIED); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Permission denied"); + goto cleanup; + } + } + + /* Try to pick up ttymodes from client before it goes raw */ + if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) + error("%s: tcgetattr: %s", __func__, strerror(errno)); /* enable nonblocking unless tty */ if (!isatty(new_fd[0])) @@ -425,257 +428,1084 @@ muxserver_accept_control(void) 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, + + nc = channel_new("session", SSH_CHANNEL_OPENING, new_fd[0], new_fd[1], new_fd[2], window, packetmax, CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); - c->ctl_fd = client_fd; + nc->ctl_chan = c->self; /* link session -> control channel */ + c->remote_id = nc->self; /* link control -> session channel */ + if (cctx->want_tty && escape_char != 0xffffffff) { - channel_register_filter(c->self, + channel_register_filter(nc->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); + debug2("%s: channel_new: %d linked to control channel %d", + __func__, nc->self, nc->ctl_chan); - channel_send_open(c->self); - channel_register_open_confirm(c->self, mux_session_confirm, cctx); - return 0; -} + channel_send_open(nc->self); + channel_register_open_confirm(nc->self, mux_session_confirm, cctx); + channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); -/* ** Multiplexing client support */ + /* prepare reply */ + /* XXX defer until mux_session_confirm() fires */ + buffer_put_int(r, MUX_S_SESSION_OPENED); + buffer_put_int(r, rid); + buffer_put_int(r, nc->self); -/* Exit signal handler */ -static void -control_client_sighandler(int signo) -{ - muxclient_terminate = signo; + return 0; } -/* - * Relay signal handler - used to pass some signals from mux client to - * mux master. - */ -static void -control_client_sigrelay(int signo) +static int +process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r) { - int save_errno = errno; + debug2("%s: channel %d: alive check", __func__, c->self); - if (muxserver_pid > 1) - kill(muxserver_pid, signo); + /* prepare reply */ + buffer_put_int(r, MUX_S_ALIVE); + buffer_put_int(r, rid); + buffer_put_int(r, (u_int)getpid()); - errno = save_errno; + return 0; } -/* Check mux client environment variables before passing them to mux master. */ static int -env_permitted(char *env) +process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r) { - int i, ret; - char name[1024], *cp; + debug2("%s: channel %d: terminate request", __func__, c->self); + + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) { + if (!ask_permission("Terminate shared connection to %s? ", + host)) { + debug2("%s: termination refused by user", __func__); + buffer_put_int(r, MUX_S_PERMISSION_DENIED); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Permission denied"); + return 0; + } + } - 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); + quit_pending = 1; + buffer_put_int(r, MUX_S_OK); + buffer_put_int(r, rid); + /* XXX exit happens too soon - message never makes it to client */ + return 0; +} - for (i = 0; i < options.num_send_env; i++) - if (match_pattern(name, options.send_env[i])) - return (1); +static char * +format_forward(u_int ftype, Forward *fwd) +{ + char *ret; + + switch (ftype) { + case MUX_FWD_LOCAL: + xasprintf(&ret, "local forward %.200s:%d -> %.200s:%d", + (fwd->listen_host == NULL) ? + (options.gateway_ports ? "*" : "LOCALHOST") : + fwd->listen_host, fwd->listen_port, + fwd->connect_host, fwd->connect_port); + break; + case MUX_FWD_DYNAMIC: + xasprintf(&ret, "dynamic forward %.200s:%d -> *", + (fwd->listen_host == NULL) ? + (options.gateway_ports ? "*" : "LOCALHOST") : + fwd->listen_host, fwd->listen_port); + break; + case MUX_FWD_REMOTE: + xasprintf(&ret, "remote forward %.200s:%d -> %.200s:%d", + (fwd->listen_host == NULL) ? + "LOCALHOST" : fwd->listen_host, + fwd->listen_port, + fwd->connect_host, fwd->connect_port); + break; + default: + fatal("%s: unknown forward type %u", __func__, ftype); + } + return ret; +} - return (0); +static int +compare_host(const char *a, const char *b) +{ + if (a == NULL && b == NULL) + return 1; + if (a == NULL || b == NULL) + return 0; + return strcmp(a, b) == 0; } -/* Multiplex client main loop. */ -void -muxclient(const char *path) +static int +compare_forward(Forward *a, Forward *b) { - 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 (!compare_host(a->listen_host, b->listen_host)) + return 0; + if (a->listen_port != b->listen_port) + return 0; + if (!compare_host(a->connect_host, b->connect_host)) + return 0; + if (a->connect_port != b->connect_port) + return 0; - if (muxclient_command == 0) - muxclient_command = SSHMUX_COMMAND_OPEN; + return 1; +} - 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; +static int +process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) +{ + Forward fwd; + char *fwd_desc = NULL; + u_int ftype; + int i, ret = 0, freefwd = 1; + + fwd.listen_host = fwd.connect_host = NULL; + if (buffer_get_int_ret(&ftype, m) != 0 || + (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&fwd.listen_port, m) != 0 || + (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&fwd.connect_port, m) != 0) { + error("%s: malformed message", __func__); + ret = -1; + goto out; } + if (*fwd.listen_host == '\0') { + xfree(fwd.listen_host); + fwd.listen_host = NULL; + } + if (*fwd.connect_host == '\0') { + xfree(fwd.connect_host); + fwd.connect_host = NULL; + } + + debug2("%s: channel %d: request %s", __func__, c->self, + (fwd_desc = format_forward(ftype, &fwd))); + + if (ftype != MUX_FWD_LOCAL && ftype != MUX_FWD_REMOTE && + ftype != MUX_FWD_DYNAMIC) { + logit("%s: invalid forwarding type %u", __func__, ftype); + invalid: + xfree(fwd.listen_host); + xfree(fwd.connect_host); + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Invalid forwarding request"); + return 0; + } + /* XXX support rport0 forwarding with reply of port assigned */ + if (fwd.listen_port == 0 || fwd.listen_port >= 65536) { + logit("%s: invalid listen port %u", __func__, + fwd.listen_port); + goto invalid; + } + if (fwd.connect_port >= 65536 || (ftype != MUX_FWD_DYNAMIC && + ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) { + logit("%s: invalid connect port %u", __func__, + fwd.connect_port); + goto invalid; + } + if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL) { + logit("%s: missing connect host", __func__); + goto invalid; + } + + /* Skip forwards that have already been requested */ + switch (ftype) { + case MUX_FWD_LOCAL: + case MUX_FWD_DYNAMIC: + for (i = 0; i < options.num_local_forwards; i++) { + if (compare_forward(&fwd, + options.local_forwards + i)) { + exists: + debug2("%s: found existing forwarding", + __func__); + buffer_put_int(r, MUX_S_OK); + buffer_put_int(r, rid); + goto out; + } + } + break; + case MUX_FWD_REMOTE: + for (i = 0; i < options.num_remote_forwards; i++) { + if (compare_forward(&fwd, + options.remote_forwards + i)) + goto exists; + } + break; + } + + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) { + if (!ask_permission("Open %s on %s?", fwd_desc, host)) { + debug2("%s: forwarding refused by user", __func__); + buffer_put_int(r, MUX_S_PERMISSION_DENIED); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Permission denied"); + goto out; + } + } + + if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) { + if (options.num_local_forwards + 1 >= + SSH_MAX_FORWARDS_PER_DIRECTION || + channel_setup_local_fwd_listener(fwd.listen_host, + fwd.listen_port, fwd.connect_host, fwd.connect_port, + options.gateway_ports) < 0) { + fail: + logit("slave-requested %s failed", fwd_desc); + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Port forwarding failed"); + goto out; + } + add_local_forward(&options, &fwd); + freefwd = 0; + } else { + /* XXX wait for remote to confirm */ + if (options.num_remote_forwards + 1 >= + SSH_MAX_FORWARDS_PER_DIRECTION || + channel_request_remote_forwarding(fwd.listen_host, + fwd.listen_port, fwd.connect_host, fwd.connect_port) < 0) + goto fail; + add_remote_forward(&options, &fwd); + freefwd = 0; + } + buffer_put_int(r, MUX_S_OK); + buffer_put_int(r, rid); + out: + if (fwd_desc != NULL) + xfree(fwd_desc); + if (freefwd) { + if (fwd.listen_host != NULL) + xfree(fwd.listen_host); + if (fwd.connect_host != NULL) + xfree(fwd.connect_host); + } + return ret; +} + +static int +process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) +{ + Forward fwd; + char *fwd_desc = NULL; + u_int ftype; + int ret = 0; + + fwd.listen_host = fwd.connect_host = NULL; + if (buffer_get_int_ret(&ftype, m) != 0 || + (fwd.listen_host = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&fwd.listen_port, m) != 0 || + (fwd.connect_host = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&fwd.connect_port, m) != 0) { + error("%s: malformed message", __func__); + ret = -1; + goto out; + } + + if (*fwd.listen_host == '\0') { + xfree(fwd.listen_host); + fwd.listen_host = NULL; + } + if (*fwd.connect_host == '\0') { + xfree(fwd.connect_host); + fwd.connect_host = NULL; + } + + debug2("%s: channel %d: request %s", __func__, c->self, + (fwd_desc = format_forward(ftype, &fwd))); + + /* XXX implement this */ + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, "unimplemented"); + + out: + if (fwd_desc != NULL) + xfree(fwd_desc); + if (fwd.listen_host != NULL) + xfree(fwd.listen_host); + if (fwd.connect_host != NULL) + xfree(fwd.connect_host); + + return ret; +} + +static int +process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) +{ + Channel *nc; + char *reserved, *chost; + u_int cport, i, j; + int new_fd[2]; + + chost = reserved = NULL; + if ((reserved = buffer_get_string_ret(m, NULL)) == NULL || + (chost = buffer_get_string_ret(m, NULL)) == NULL || + buffer_get_int_ret(&cport, m) != 0) { + if (reserved != NULL) + xfree(reserved); + if (chost != NULL) + xfree(chost); + error("%s: malformed message", __func__); + return -1; + } + xfree(reserved); + + debug2("%s: channel %d: request stdio fwd to %s:%u", + __func__, c->self, chost, cport); + + /* Gather fds from client */ + for(i = 0; i < 2; i++) { + if ((new_fd[i] = mm_receive_fd(c->sock)) == -1) { + error("%s: failed to receive fd %d from slave", + __func__, i); + for (j = 0; j < i; j++) + close(new_fd[j]); + xfree(chost); + + /* prepare reply */ + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, + "did not receive file descriptors"); + return -1; + } + } + + debug3("%s: got fds stdin %d, stdout %d", __func__, + new_fd[0], new_fd[1]); + + /* XXX support multiple child sessions in future */ + if (c->remote_id != -1) { + debug2("%s: session already open", __func__); + /* prepare reply */ + buffer_put_int(r, MUX_S_FAILURE); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Multiple sessions not supported"); + cleanup: + close(new_fd[0]); + close(new_fd[1]); + xfree(chost); + return 0; + } + + if (options.control_master == SSHCTL_MASTER_ASK || + options.control_master == SSHCTL_MASTER_AUTO_ASK) { + if (!ask_permission("Allow forward to to %s:%u? ", + chost, cport)) { + debug2("%s: stdio fwd refused by user", __func__); + /* prepare reply */ + buffer_put_int(r, MUX_S_PERMISSION_DENIED); + buffer_put_int(r, rid); + buffer_put_cstring(r, "Permission denied"); + goto cleanup; + } + } + + /* enable nonblocking unless tty */ + if (!isatty(new_fd[0])) + set_nonblock(new_fd[0]); + if (!isatty(new_fd[1])) + set_nonblock(new_fd[1]); + + nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]); + + nc->ctl_chan = c->self; /* link session -> control channel */ + c->remote_id = nc->self; /* link control -> session channel */ + + debug2("%s: channel_new: %d linked to control channel %d", + __func__, nc->self, nc->ctl_chan); + + channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 0); + + /* prepare reply */ + /* XXX defer until channel confirmed */ + buffer_put_int(r, MUX_S_SESSION_OPENED); + buffer_put_int(r, rid); + buffer_put_int(r, nc->self); + + return 0; +} + +/* Channel callbacks fired on read/write from mux slave fd */ +static int +mux_master_read_cb(Channel *c) +{ + struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx; + Buffer in, out; + void *ptr; + u_int type, rid, have, i; + int ret = -1; + + /* Setup ctx and */ + if (c->mux_ctx == NULL) { + state = xcalloc(1, sizeof(state)); + c->mux_ctx = state; + channel_register_cleanup(c->self, + mux_master_control_cleanup_cb, 0); + + /* Send hello */ + buffer_init(&out); + buffer_put_int(&out, MUX_MSG_HELLO); + buffer_put_int(&out, SSHMUX_VER); + /* no extensions */ + buffer_put_string(&c->output, buffer_ptr(&out), + buffer_len(&out)); + buffer_free(&out); + debug3("%s: channel %d: hello sent", __func__, c->self); + return 0; + } + + buffer_init(&in); + buffer_init(&out); + + /* Channel code ensures that we receive whole packets */ + if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) { + malf: + error("%s: malformed message", __func__); + goto out; + } + buffer_append(&in, ptr, have); + + if (buffer_get_int_ret(&type, &in) != 0) + goto malf; + debug3("%s: channel %d packet type 0x%08x len %u", + __func__, c->self, type, buffer_len(&in)); + + if (type == MUX_MSG_HELLO) + rid = 0; + else { + if (!state->hello_rcvd) { + error("%s: expected MUX_MSG_HELLO(0x%08x), " + "received 0x%08x", __func__, MUX_MSG_HELLO, type); + goto out; + } + if (buffer_get_int_ret(&rid, &in) != 0) + goto malf; + } + + for (i = 0; mux_master_handlers[i].handler != NULL; i++) { + if (type == mux_master_handlers[i].type) { + ret = mux_master_handlers[i].handler(rid, c, &in, &out); + break; + } + } + if (mux_master_handlers[i].handler == NULL) { + error("%s: unsupported mux message 0x%08x", __func__, type); + buffer_put_int(&out, MUX_S_FAILURE); + buffer_put_int(&out, rid); + buffer_put_cstring(&out, "unsupported request"); + ret = 0; + } + /* Enqueue reply packet */ + if (buffer_len(&out) != 0) { + buffer_put_string(&c->output, buffer_ptr(&out), + buffer_len(&out)); + } + out: + buffer_free(&in); + buffer_free(&out); + return ret; +} + +void +mux_exit_message(Channel *c, int exitval) +{ + Buffer m; + Channel *mux_chan; + + debug3("%s: channel %d: exit message, evitval %d", __func__, c->self, + exitval); + + if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL) + fatal("%s: channel %d missing mux channel %d", + __func__, c->self, c->ctl_chan); + + /* Append exit message packet to control socket output queue */ + buffer_init(&m); + buffer_put_int(&m, MUX_S_EXIT_MESSAGE); + buffer_put_int(&m, c->self); + buffer_put_int(&m, exitval); + + buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m)); + buffer_free(&m); +} + +/* Prepare a mux master to listen on a Unix domain socket. */ +void +muxserver_listen(void) +{ + struct sockaddr_un addr; + socklen_t sun_len; + mode_t old_umask; + + 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(path) + 1; + sun_len = offsetof(struct sockaddr_un, sun_path) + + strlen(options.control_path) + 1; - if (strlcpy(addr.sun_path, path, + if (strlcpy(addr.sun_path, options.control_path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) fatal("ControlPath too long"); - if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + if ((muxserver_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)); + old_umask = umask(0177); + if (bind(muxserver_sock, (struct sockaddr *)&addr, sun_len) == -1) { + muxserver_sock = -1; + if (errno == EINVAL || errno == EADDRINUSE) { + error("ControlSocket %s already exists, " + "disabling multiplexing", options.control_path); + 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); + + mux_listener_channel = channel_new("mux listener", + SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, addr.sun_path, 1); + mux_listener_channel->mux_rcb = mux_master_read_cb; + debug3("%s: mux listener channel %d fd %d", __func__, + mux_listener_channel->self, mux_listener_channel->sock); +} + +/* Callback on open confirmation in mux master for a mux client session. */ +static void +mux_session_confirm(int id, 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_by_id(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); +} + +/* ** Multiplexing client support */ + +/* Exit signal handler */ +static void +control_client_sighandler(int signo) +{ + muxclient_terminate = signo; +} + +/* + * Relay signal handler - used to pass some signals from mux client to + * mux master. + */ +static void +control_client_sigrelay(int signo) +{ + int save_errno = errno; + + if (muxserver_pid > 1) + kill(muxserver_pid, signo); + + errno = save_errno; +} + +static int +mux_client_read(int fd, Buffer *b, u_int need) +{ + u_int have; + ssize_t len; + u_char *p; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = POLLIN; + p = buffer_append_space(b, need); + for (have = 0; have < need; ) { + if (muxclient_terminate) { + errno = EINTR; + return -1; } - if (errno == ENOENT) - debug("Control socket \"%.100s\" does not exist", path); - else { - error("Control socket connect(%.100s): %s", path, - strerror(errno)); + len = read(fd, p + have, need - have); + if (len < 0) { + switch (errno) { +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif + case EAGAIN: + (void)poll(&pfd, 1, -1); + /* FALLTHROUGH */ + case EINTR: + continue; + default: + return -1; + } } - close(sock); - return; + if (len == 0) { + errno = EPIPE; + return -1; + } + have += (u_int)len; } + return 0; +} - 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); +static int +mux_client_write_packet(int fd, Buffer *m) +{ + Buffer queue; + u_int have, need; + int oerrno, len; + u_char *ptr; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = POLLOUT; + buffer_init(&queue); + buffer_put_string(&queue, buffer_ptr(m), buffer_len(m)); + + need = buffer_len(&queue); + ptr = buffer_ptr(&queue); + + for (have = 0; have < need; ) { + if (muxclient_terminate) { + buffer_free(&queue); + errno = EINTR; + return -1; + } + len = write(fd, ptr + have, need - have); + if (len < 0) { + switch (errno) { +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif + case EAGAIN: + (void)poll(&pfd, 1, -1); + /* FALLTHROUGH */ + case EINTR: + continue; + default: + oerrno = errno; + buffer_free(&queue); + errno = oerrno; + return -1; + } + } + if (len == 0) { + buffer_free(&queue); + errno = EPIPE; + return -1; + } + have += (u_int)len; } + buffer_free(&queue); + return 0; +} - 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; +static int +mux_client_read_packet(int fd, Buffer *m) +{ + Buffer queue; + u_int need, have; + void *ptr; + int oerrno; + + buffer_init(&queue); + if (mux_client_read(fd, &queue, 4) != 0) { + if ((oerrno = errno) == EPIPE) + debug3("%s: read header failed: %s", __func__, strerror(errno)); + errno = oerrno; + return -1; + } + need = get_u32(buffer_ptr(&queue)); + if (mux_client_read(fd, &queue, need) != 0) { + oerrno = errno; + debug3("%s: read body failed: %s", __func__, strerror(errno)); + errno = oerrno; + return -1; + } + ptr = buffer_get_string_ptr(&queue, &have); + buffer_append(m, ptr, have); + buffer_free(&queue); + return 0; +} - signal(SIGPIPE, SIG_IGN); +static int +mux_client_hello_exchange(int fd) +{ + Buffer m; + u_int type, ver; buffer_init(&m); + buffer_put_int(&m, MUX_MSG_HELLO); + buffer_put_int(&m, SSHMUX_VER); + /* no extensions */ - /* 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); + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); + + buffer_clear(&m); + + /* Read their HELLO */ + if (mux_client_read_packet(fd, &m) != 0) { buffer_free(&m); - 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; + return -1; + } + + type = buffer_get_int(&m); + if (type != MUX_MSG_HELLO) + fatal("%s: expected HELLO (%u) received %u", + __func__, MUX_MSG_HELLO, type); + ver = buffer_get_int(&m); + if (ver != SSHMUX_VER) + fatal("Unsupported multiplexing protocol version %d " + "(expected %d)", ver, SSHMUX_VER); + debug2("%s: master version %u", __func__, ver); + /* No extensions are presently defined */ + while (buffer_len(&m) > 0) { + char *name = buffer_get_string(&m, NULL); + char *value = buffer_get_string(&m, NULL); + + debug2("Unrecognised master extension \"%s\"", name); + xfree(name); + xfree(value); } + buffer_free(&m); + return 0; +} + +static u_int +mux_client_request_alive(int fd) +{ + Buffer m; + char *e; + u_int pid, type, rid; + + debug3("%s: entering", __func__); + + buffer_init(&m); + buffer_put_int(&m, MUX_C_ALIVE_CHECK); + buffer_put_int(&m, muxclient_request_id); + + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); + buffer_clear(&m); - /* 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; + /* Read their reply */ + if (mux_client_read_packet(fd, &m) != 0) { + buffer_free(&m); + return 0; } - if (buffer_get_char(&m) != SSHMUX_VER) { - error("%s: Master replied with wrong version", __func__); - goto muxerr; + + type = buffer_get_int(&m); + if (type != MUX_S_ALIVE) { + e = buffer_get_string(&m, NULL); + fatal("%s: master returned error: %s", __func__, e); } - if (buffer_get_int_ret(&allowed, &m) != 0) { - error("%s: bad server reply", __func__); - goto muxerr; + + if ((rid = buffer_get_int(&m)) != muxclient_request_id) + fatal("%s: out of sequence reply: my id %u theirs %u", + __func__, muxclient_request_id, rid); + pid = buffer_get_int(&m); + buffer_free(&m); + + debug3("%s: done pid = %u", __func__, pid); + + muxclient_request_id++; + + return pid; +} + +static void +mux_client_request_terminate(int fd) +{ + Buffer m; + char *e; + u_int type, rid; + + debug3("%s: entering", __func__); + + buffer_init(&m); + buffer_put_int(&m, MUX_C_TERMINATE); + buffer_put_int(&m, muxclient_request_id); + + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); + + buffer_clear(&m); + + /* Read their reply */ + if (mux_client_read_packet(fd, &m) != 0) { + /* Remote end exited already */ + if (errno == EPIPE) { + buffer_free(&m); + return; + } + fatal("%s: read from master failed: %s", + __func__, strerror(errno)); } - if (allowed != 1) { - error("Connection to master denied"); - goto muxerr; + + type = buffer_get_int(&m); + if ((rid = buffer_get_int(&m)) != muxclient_request_id) + fatal("%s: out of sequence reply: my id %u theirs %u", + __func__, muxclient_request_id, rid); + switch (type) { + case MUX_S_OK: + break; + case MUX_S_PERMISSION_DENIED: + e = buffer_get_string(&m, NULL); + fatal("Master refused termination request: %s", e); + case MUX_S_FAILURE: + e = buffer_get_string(&m, NULL); + fatal("%s: termination request failed: %s", __func__, e); + default: + fatal("%s: unexpected response from master 0x%08x", + __func__, type); } - muxserver_pid = buffer_get_int(&m); + buffer_free(&m); + muxclient_request_id++; +} + +static int +mux_client_request_forward(int fd, u_int ftype, Forward *fwd) +{ + Buffer m; + char *e, *fwd_desc; + u_int type, rid; + + fwd_desc = format_forward(ftype, fwd); + debug("Requesting %s", fwd_desc); + xfree(fwd_desc); + + buffer_init(&m); + buffer_put_int(&m, MUX_C_OPEN_FWD); + buffer_put_int(&m, muxclient_request_id); + buffer_put_int(&m, ftype); + buffer_put_cstring(&m, + fwd->listen_host == NULL ? "" : fwd->listen_host); + buffer_put_int(&m, fwd->listen_port); + buffer_put_cstring(&m, + fwd->connect_host == NULL ? "" : fwd->connect_host); + buffer_put_int(&m, fwd->connect_port); + + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); buffer_clear(&m); - 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)); + /* Read their reply */ + if (mux_client_read_packet(fd, &m) != 0) { + buffer_free(&m); + return -1; + } - 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]); - } - } - } + type = buffer_get_int(&m); + if ((rid = buffer_get_int(&m)) != muxclient_request_id) + fatal("%s: out of sequence reply: my id %u theirs %u", + __func__, muxclient_request_id, rid); + switch (type) { + case MUX_S_OK: break; + case MUX_S_PERMISSION_DENIED: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + error("Master refused forwarding request: %s", e); + return -1; + case MUX_S_FAILURE: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + error("%s: session request failed: %s", __func__, e); + return -1; default: - fatal("unrecognised muxclient_command %d", muxclient_command); + fatal("%s: unexpected response from master 0x%08x", + __func__, type); + } + buffer_free(&m); + + muxclient_request_id++; + return 0; +} + +static int +mux_client_request_forwards(int fd) +{ + int i; + + debug3("%s: requesting forwardings: %d local, %d remote", __func__, + options.num_local_forwards, options.num_remote_forwards); + + /* XXX ExitOnForwardingFailure */ + for (i = 0; i < options.num_local_forwards; i++) { + if (mux_client_request_forward(fd, + options.local_forwards[i].connect_port == 0 ? + MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, + options.local_forwards + i) != 0) + return -1; } + for (i = 0; i < options.num_remote_forwards; i++) { + if (mux_client_request_forward(fd, MUX_FWD_REMOTE, + options.remote_forwards + i) != 0) + return -1; + } + return 0; +} + +static int +mux_client_request_session(int fd) +{ + Buffer m; + char *e, *term; + u_int i, rid, sid, esid, exitval, type, exitval_seen; + extern char **environ; + int devnull; + + debug3("%s: entering", __func__); + + if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { + error("%s: master alive request failed", __func__); + return -1; + } + + signal(SIGPIPE, SIG_IGN); - if (ssh_msg_send(sock, SSHMUX_VER, &m) == -1) { - error("%s: msg_send", __func__); - goto muxerr; + if (stdin_null_flag) { + if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) + fatal("open(/dev/null): %s", strerror(errno)); + if (dup2(devnull, STDIN_FILENO) == -1) + fatal("dup2: %s", strerror(errno)); + if (devnull > STDERR_FILENO) + close(devnull); } - 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; + term = getenv("TERM"); + + buffer_init(&m); + buffer_put_int(&m, MUX_C_NEW_SESSION); + buffer_put_int(&m, muxclient_request_id); + buffer_put_cstring(&m, ""); /* reserved */ + buffer_put_int(&m, tty_flag); + buffer_put_int(&m, options.forward_x11); + buffer_put_int(&m, options.forward_agent); + buffer_put_int(&m, subsystem_flag); + buffer_put_int(&m, options.escape_char == SSH_ESCAPECHAR_NONE ? + 0xffffffff : (u_int)options.escape_char); + buffer_put_cstring(&m, term == NULL ? "" : term); + buffer_put_string(&m, buffer_ptr(&command), buffer_len(&command)); + + if (options.num_send_env > 0 && environ != NULL) { + /* Pass environment */ + for (i = 0; environ[i] != NULL; i++) { + if (env_permitted(environ[i])) { + buffer_put_cstring(&m, environ[i]); + } + } } - /* - * Mux errors are non-recoverable from this point as the master - * has ownership of the session now. - */ + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); + + /* Send the stdio file descriptors */ + if (mm_send_fd(fd, STDIN_FILENO) == -1 || + mm_send_fd(fd, STDOUT_FILENO) == -1 || + mm_send_fd(fd, STDERR_FILENO) == -1) + fatal("%s: send fds failed", __func__); + + debug3("%s: session request sent", __func__); - /* Wait for reply, so master has a chance to gather ttymodes */ + /* Read their reply */ 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); + if (mux_client_read_packet(fd, &m) != 0) { + error("%s: read from master failed: %s", + __func__, strerror(errno)); + buffer_free(&m); + return -1; + } + + type = buffer_get_int(&m); + if ((rid = buffer_get_int(&m)) != muxclient_request_id) + fatal("%s: out of sequence reply: my id %u theirs %u", + __func__, muxclient_request_id, rid); + switch (type) { + case MUX_S_SESSION_OPENED: + sid = buffer_get_int(&m); + debug("%s: master session id: %u", __func__, sid); + break; + case MUX_S_PERMISSION_DENIED: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + error("Master refused forwarding request: %s", e); + return -1; + case MUX_S_FAILURE: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + error("%s: forwarding request failed: %s", __func__, e); + return -1; + default: + buffer_free(&m); + error("%s: unexpected response from master 0x%08x", + __func__, type); + return -1; + } + muxclient_request_id++; signal(SIGHUP, control_client_sighandler); signal(SIGINT, control_client_sighandler); @@ -683,46 +1513,235 @@ muxclient(const char *path) signal(SIGWINCH, control_client_sigrelay); if (tty_flag) - enter_raw_mode(); + enter_raw_mode(force_tty_flag); /* * 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). + * Before it does, it is expected to write an exit message. + * This process must read the value and wait for the closure of + * the client_fd; if this one closes early, the multiplex master will + * terminate early too (possibly losing data). */ - 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"); + for (exitval = 255, exitval_seen = 0;;) { + buffer_clear(&m); + if (mux_client_read_packet(fd, &m) != 0) break; + type = buffer_get_int(&m); + if (type != MUX_S_EXIT_MESSAGE) { + e = buffer_get_string(&m, NULL); + fatal("%s: master returned error: %s", __func__, e); } - if (r == -1) { - if (errno == EINTR) - continue; - fatal("%s: read %s", __func__, strerror(errno)); - } - i += r; + if ((esid = buffer_get_int(&m)) != sid) + fatal("%s: exit on unknown session: my id %u theirs %u", + __func__, sid, esid); + debug("%s: master session id: %u", __func__, sid); + if (exitval_seen) + fatal("%s: exitval sent twice", __func__); + exitval = buffer_get_int(&m); + exitval_seen = 1; } - close(sock); - leave_raw_mode(); - if (i > (int)sizeof(int)) - fatal("%s: master returned too much data (%d > %lu)", - __func__, i, (u_long)sizeof(int)); + close(fd); + leave_raw_mode(force_tty_flag); + if (muxclient_terminate) { debug2("Exiting on signal %d", muxclient_terminate); - exitval[0] = 255; - } else if (i < (int)sizeof(int)) { + exitval = 255; + } else if (!exitval_seen) { debug2("Control master terminated unexpectedly"); - exitval[0] = 255; + exitval = 255; } else - debug2("Received exit status from master %d", exitval[0]); + debug2("Received exit status from master %d", exitval); if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) fprintf(stderr, "Shared connection to %s closed.\r\n", host); - exit(exitval[0]); + exit(exitval); +} + +static int +mux_client_request_stdio_fwd(int fd) +{ + Buffer m; + char *e; + u_int type, rid, sid; + int devnull; + + debug3("%s: entering", __func__); + + if ((muxserver_pid = mux_client_request_alive(fd)) == 0) { + error("%s: master alive request failed", __func__); + return -1; + } + + signal(SIGPIPE, SIG_IGN); + + if (stdin_null_flag) { + if ((devnull = open(_PATH_DEVNULL, O_RDONLY)) == -1) + fatal("open(/dev/null): %s", strerror(errno)); + if (dup2(devnull, STDIN_FILENO) == -1) + fatal("dup2: %s", strerror(errno)); + if (devnull > STDERR_FILENO) + close(devnull); + } + + buffer_init(&m); + buffer_put_int(&m, MUX_C_NEW_STDIO_FWD); + buffer_put_int(&m, muxclient_request_id); + buffer_put_cstring(&m, ""); /* reserved */ + buffer_put_cstring(&m, stdio_forward_host); + buffer_put_int(&m, stdio_forward_port); + + if (mux_client_write_packet(fd, &m) != 0) + fatal("%s: write packet: %s", __func__, strerror(errno)); + + /* Send the stdio file descriptors */ + if (mm_send_fd(fd, STDIN_FILENO) == -1 || + mm_send_fd(fd, STDOUT_FILENO) == -1) + fatal("%s: send fds failed", __func__); + + debug3("%s: stdio forward request sent", __func__); + + /* Read their reply */ + buffer_clear(&m); + + if (mux_client_read_packet(fd, &m) != 0) { + error("%s: read from master failed: %s", + __func__, strerror(errno)); + buffer_free(&m); + return -1; + } + + type = buffer_get_int(&m); + if ((rid = buffer_get_int(&m)) != muxclient_request_id) + fatal("%s: out of sequence reply: my id %u theirs %u", + __func__, muxclient_request_id, rid); + switch (type) { + case MUX_S_SESSION_OPENED: + sid = buffer_get_int(&m); + debug("%s: master session id: %u", __func__, sid); + break; + case MUX_S_PERMISSION_DENIED: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + fatal("Master refused forwarding request: %s", e); + case MUX_S_FAILURE: + e = buffer_get_string(&m, NULL); + buffer_free(&m); + fatal("%s: stdio forwarding request failed: %s", __func__, e); + default: + buffer_free(&m); + error("%s: unexpected response from master 0x%08x", + __func__, type); + return -1; + } + muxclient_request_id++; + + signal(SIGHUP, control_client_sighandler); + signal(SIGINT, control_client_sighandler); + signal(SIGTERM, control_client_sighandler); + signal(SIGWINCH, control_client_sigrelay); + + /* + * Stick around until the controlee closes the client_fd. + */ + buffer_clear(&m); + if (mux_client_read_packet(fd, &m) != 0) { + if (errno == EPIPE || + (errno == EINTR && muxclient_terminate != 0)) + return 0; + fatal("%s: mux_client_read_packet: %s", + __func__, strerror(errno)); + } + fatal("%s: master returned unexpected message %u", __func__, type); +} + +/* Multiplex client main loop. */ +void +muxclient(const char *path) +{ + struct sockaddr_un addr; + socklen_t sun_len; + int sock; + u_int pid; + + if (muxclient_command == 0) { + if (stdio_forward_host != NULL) + muxclient_command = SSHMUX_COMMAND_STDIO_FWD; + else + muxclient_command = SSHMUX_COMMAND_OPEN; + } + + switch (options.control_master) { + case SSHCTL_MASTER_AUTO: + case SSHCTL_MASTER_AUTO_ASK: + debug("auto-mux: Trying existing master"); + /* FALLTHROUGH */ + case SSHCTL_MASTER_NO: + break; + default: + return; + } + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + sun_len = offsetof(struct sockaddr_un, sun_path) + + strlen(path) + 1; + + if (strlcpy(addr.sun_path, path, + sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) + fatal("ControlPath too long"); + + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + fatal("%s socket(): %s", __func__, strerror(errno)); + + if (connect(sock, (struct sockaddr *)&addr, sun_len) == -1) { + switch (muxclient_command) { + case SSHMUX_COMMAND_OPEN: + case SSHMUX_COMMAND_STDIO_FWD: + break; + default: + fatal("Control socket connect(%.100s): %s", path, + strerror(errno)); + } + if (errno == ENOENT) + debug("Control socket \"%.100s\" does not exist", path); + else { + error("Control socket connect(%.100s): %s", path, + strerror(errno)); + } + close(sock); + return; + } + set_nonblock(sock); + + if (mux_client_hello_exchange(sock) != 0) { + error("%s: master hello exchange failed", __func__); + close(sock); + return; + } + + switch (muxclient_command) { + case SSHMUX_COMMAND_ALIVE_CHECK: + if ((pid = mux_client_request_alive(sock)) == 0) + fatal("%s: master alive check failed", __func__); + fprintf(stderr, "Master running (pid=%d)\r\n", pid); + exit(0); + case SSHMUX_COMMAND_TERMINATE: + mux_client_request_terminate(sock); + fprintf(stderr, "Exit request sent.\r\n"); + exit(0); + case SSHMUX_COMMAND_OPEN: + if (mux_client_request_forwards(sock) != 0) { + error("%s: master forward request failed", __func__); + return; + } + mux_client_request_session(sock); + return; + case SSHMUX_COMMAND_STDIO_FWD: + mux_client_request_stdio_fwd(sock); + exit(0); + default: + fatal("unrecognised muxclient_command %d", muxclient_command); + } } diff --git a/crypto/openssh/myproposal.h b/crypto/openssh/myproposal.h index 7bca3bcae..98f27fd15 100644 --- a/crypto/openssh/myproposal.h +++ b/crypto/openssh/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.23 2009/01/23 07:58:11 djm Exp $ */ +/* $OpenBSD: myproposal.h,v 1.24 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -40,7 +40,9 @@ "diffie-hellman-group1-sha1" #endif -#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" +#define KEX_DEFAULT_PK_ALG "ssh-rsa-cert-v00@openssh.com," \ + "ssh-dss-cert-v00@openssh.com," \ + "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "aes128-ctr,aes192-ctr,aes256-ctr," \ diff --git a/crypto/openssh/nchan.c b/crypto/openssh/nchan.c index 160445e5a..20f6a2f49 100644 --- a/crypto/openssh/nchan.c +++ b/crypto/openssh/nchan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nchan.c,v 1.62 2008/11/07 18:50:18 stevesk Exp $ */ +/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -161,7 +161,7 @@ chan_ibuf_empty(Channel *c) switch (c->istate) { case CHAN_INPUT_WAIT_DRAIN: if (compat20) { - if (!(c->flags & CHAN_CLOSE_SENT)) + if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) chan_send_eof2(c); chan_set_istate(c, CHAN_INPUT_CLOSED); } else { @@ -278,9 +278,12 @@ 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->flags & CHAN_LOCAL)) { + if (c->flags & CHAN_CLOSE_RCVD) + error("channel %d: protocol error: close rcvd twice", + c->self); + c->flags |= CHAN_CLOSE_RCVD; + } if (c->type == SSH_CHANNEL_LARVAL) { /* tear down larval channels immediately */ chan_set_ostate(c, CHAN_OUTPUT_CLOSED); @@ -302,11 +305,13 @@ chan_rcvd_close2(Channel *c) chan_set_istate(c, CHAN_INPUT_CLOSED); break; case CHAN_INPUT_WAIT_DRAIN: - chan_send_eof2(c); + if (!(c->flags & CHAN_LOCAL)) + chan_send_eof2(c); chan_set_istate(c, CHAN_INPUT_CLOSED); break; } } + void chan_rcvd_eow(Channel *c) { @@ -454,6 +459,10 @@ chan_is_dead(Channel *c, int do_send) c->self, c->efd, buffer_len(&c->extended)); return 0; } + if (c->flags & CHAN_LOCAL) { + debug2("channel %d: is dead (local)", c->self); + return 1; + } if (!(c->flags & CHAN_CLOSE_SENT)) { if (do_send) { chan_send_close2(c); diff --git a/crypto/openssh/openbsd-compat/bsd-cygwin_util.c b/crypto/openssh/openbsd-compat/bsd-cygwin_util.c index 38be7e350..e9fa3a0e2 100644 --- a/crypto/openssh/openbsd-compat/bsd-cygwin_util.c +++ b/crypto/openssh/openbsd-compat/bsd-cygwin_util.c @@ -39,9 +39,6 @@ #endif #include -#include -#include -#include #include #include @@ -49,11 +46,6 @@ #include #include "xmalloc.h" -#define is_winnt (GetVersion() < 0x80000000) - -#define ntsec_on(c) ((c) && strstr((c),"ntsec") && !strstr((c),"nontsec")) -#define ntsec_off(c) ((c) && strstr((c),"nontsec")) -#define ntea_on(c) ((c) && strstr((c),"ntea") && !strstr((c),"nontea")) int binary_open(const char *filename, int flags, ...) @@ -79,128 +71,12 @@ binary_pipe(int fd[2]) return (ret); } -#define HAS_CREATE_TOKEN 1 -#define HAS_NTSEC_BY_DEFAULT 2 -#define HAS_CREATE_TOKEN_WO_NTSEC 3 - -static int -has_capability(int what) -{ - static int inited; - static int has_create_token; - static int has_ntsec_by_default; - static int has_create_token_wo_ntsec; - - /* - * has_capability() basically calls uname() and checks if - * specific capabilities of Cygwin can be evaluated from that. - * This simplifies the calling functions which only have to ask - * for a capability using has_capability() instead of having - * to figure that out by themselves. - */ - if (!inited) { - struct utsname uts; - - if (!uname(&uts)) { - int major_high = 0, major_low = 0, minor = 0; - int api_major_version = 0, api_minor_version = 0; - char *c; - - sscanf(uts.release, "%d.%d.%d", &major_high, - &major_low, &minor); - if ((c = strchr(uts.release, '(')) != NULL) { - sscanf(c + 1, "%d.%d", &api_major_version, - &api_minor_version); - } - if (major_high > 1 || - (major_high == 1 && (major_low > 3 || - (major_low == 3 && minor >= 2)))) - has_create_token = 1; - if (api_major_version > 0 || api_minor_version >= 56) - has_ntsec_by_default = 1; - if (major_high > 1 || - (major_high == 1 && major_low >= 5)) - has_create_token_wo_ntsec = 1; - inited = 1; - } - } - switch (what) { - case HAS_CREATE_TOKEN: - return (has_create_token); - case HAS_NTSEC_BY_DEFAULT: - return (has_ntsec_by_default); - case HAS_CREATE_TOKEN_WO_NTSEC: - return (has_create_token_wo_ntsec); - } - return (0); -} - -int -check_nt_auth(int pwd_authenticated, struct passwd *pw) -{ - /* - * The only authentication which is able to change the user - * context on NT systems is the password authentication. So - * we deny all requsts for changing the user context if another - * authentication method is used. - * - * This doesn't apply to Cygwin versions >= 1.3.2 anymore which - * uses the undocumented NtCreateToken() call to create a user - * token if the process has the appropriate privileges and if - * CYGWIN ntsec setting is on. - */ - static int has_create_token = -1; - - if (pw == NULL) - return 0; - if (is_winnt) { - if (has_create_token < 0) { - char *cygwin = getenv("CYGWIN"); - - has_create_token = 0; - if (has_capability(HAS_CREATE_TOKEN) && - (ntsec_on(cygwin) || - (has_capability(HAS_NTSEC_BY_DEFAULT) && - !ntsec_off(cygwin)) || - has_capability(HAS_CREATE_TOKEN_WO_NTSEC))) - has_create_token = 1; - } - if (has_create_token < 1 && - !pwd_authenticated && geteuid() != pw->pw_uid) - return (0); - } - return (1); -} - int check_ntsec(const char *filename) { return (pathconf(filename, _PC_POSIX_PERMISSIONS)); } -void -register_9x_service(void) -{ - HINSTANCE kerneldll; - DWORD (*RegisterServiceProcess)(DWORD, DWORD); - - /* The service register mechanism in 9x/Me is pretty different from - * NT/2K/XP. In NT/2K/XP we're using a special service starter - * application to register and control sshd as service. This method - * doesn't play nicely with 9x/Me. For that reason we register here - * as service when running under 9x/Me. This function is only called - * by the child sshd when it's going to daemonize. - */ - if (is_winnt) - return; - if (!(kerneldll = LoadLibrary("KERNEL32.DLL"))) - return; - if (!(RegisterServiceProcess = (DWORD (*)(DWORD, DWORD)) - GetProcAddress(kerneldll, "RegisterServiceProcess"))) - return; - RegisterServiceProcess(0, 1); -} - #define NL(x) x, (sizeof (x) - 1) #define WENV_SIZ (sizeof (wenv_arr) / sizeof (wenv_arr[0])) @@ -209,23 +85,14 @@ static struct wenv { 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=") } }; diff --git a/crypto/openssh/openbsd-compat/bsd-cygwin_util.h b/crypto/openssh/openbsd-compat/bsd-cygwin_util.h index 6719b8a49..39b8eb788 100644 --- a/crypto/openssh/openbsd-compat/bsd-cygwin_util.h +++ b/crypto/openssh/openbsd-compat/bsd-cygwin_util.h @@ -1,4 +1,4 @@ -/* $Id: bsd-cygwin_util.h,v 1.11 2004/08/30 10:42:08 dtucker Exp $ */ +/* $Id: bsd-cygwin_util.h,v 1.12 2009/03/08 00:40:28 dtucker Exp $ */ /* * Copyright (c) 2000, 2001, Corinna Vinschen @@ -35,7 +35,6 @@ #ifdef HAVE_CYGWIN #undef ERROR -#define is_winnt (GetVersion() < 0x80000000) #include #include @@ -43,9 +42,7 @@ int binary_open(const char *, int , ...); int binary_pipe(int fd[2]); -int check_nt_auth(int, struct passwd *); int check_ntsec(const char *); -void register_9x_service(void); char **fetch_windows_environment(void); void free_windows_environment(char **); diff --git a/crypto/openssh/openbsd-compat/daemon.c b/crypto/openssh/openbsd-compat/daemon.c index e3a6886bd..3efe14c68 100644 --- a/crypto/openssh/openbsd-compat/daemon.c +++ b/crypto/openssh/openbsd-compat/daemon.c @@ -57,18 +57,8 @@ daemon(int nochdir, int noclose) case -1: return (-1); case 0: -#ifdef HAVE_CYGWIN - register_9x_service(); -#endif break; default: -#ifdef HAVE_CYGWIN - /* - * This sleep avoids a race condition which kills the - * child process if parent is started by a NT/W2K service. - */ - sleep(1); -#endif _exit(0); } diff --git a/crypto/openssh/openbsd-compat/getrrsetbyname.c b/crypto/openssh/openbsd-compat/getrrsetbyname.c index 785b22569..98876673d 100644 --- a/crypto/openssh/openbsd-compat/getrrsetbyname.c +++ b/crypto/openssh/openbsd-compat/getrrsetbyname.c @@ -143,7 +143,7 @@ u_int32_t _getlong(register const u_char *); /* ************** */ -#define ANSWER_BUFFER_SIZE 1024*64 +#define ANSWER_BUFFER_SIZE 0xffff struct dns_query { char *name; diff --git a/crypto/openssh/openbsd-compat/openbsd-compat.h b/crypto/openssh/openbsd-compat/openbsd-compat.h index 50c6d990b..cad2408d6 100644 --- a/crypto/openssh/openbsd-compat/openbsd-compat.h +++ b/crypto/openssh/openbsd-compat/openbsd-compat.h @@ -1,4 +1,4 @@ -/* $Id: openbsd-compat.h,v 1.46 2008/06/08 17:32:29 dtucker Exp $ */ +/* $Id: openbsd-compat.h,v 1.49 2010/01/16 12:58:37 dtucker Exp $ */ /* * Copyright (c) 1999-2003 Damien Miller. All rights reserved. @@ -200,6 +200,14 @@ int vasprintf(char **, const char *, va_list); int vsnprintf(char *, size_t, const char *, va_list); #endif +#ifndef HAVE_USER_FROM_UID +char *user_from_uid(uid_t, int); +#endif + +#ifndef HAVE_GROUP_FROM_GID +char *group_from_gid(gid_t, int); +#endif + void *xmmap(size_t size); char *xcrypt(const char *password, const char *salt); char *shadow_pw(struct passwd *pw); diff --git a/crypto/openssh/openbsd-compat/openssl-compat.c b/crypto/openssh/openbsd-compat/openssl-compat.c index 49238ba80..420496caa 100644 --- a/crypto/openssh/openbsd-compat/openssl-compat.c +++ b/crypto/openssh/openbsd-compat/openssl-compat.c @@ -1,4 +1,4 @@ -/* $Id: openssl-compat.c,v 1.6 2008/02/28 08:13:52 dtucker Exp $ */ +/* $Id: openssl-compat.c,v 1.9 2010/01/28 23:54:11 dtucker Exp $ */ /* * Copyright (c) 2005 Darren Tucker @@ -49,6 +49,15 @@ ssh_EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *evp) } #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) @@ -58,5 +67,6 @@ ssh_SSLeay_add_all_algorithms(void) /* Enable use of crypto hardware */ ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); + OPENSSL_config(NULL); } #endif diff --git a/crypto/openssh/openbsd-compat/openssl-compat.h b/crypto/openssh/openbsd-compat/openssl-compat.h index 6a1bed5b2..fcc762867 100644 --- a/crypto/openssh/openbsd-compat/openssl-compat.h +++ b/crypto/openssh/openbsd-compat/openssl-compat.h @@ -1,4 +1,4 @@ -/* $Id: openssl-compat.h,v 1.12 2008/02/28 08:22:04 dtucker Exp $ */ +/* $Id: openssl-compat.h,v 1.14 2009/03/07 11:22:35 dtucker Exp $ */ /* * Copyright (c) 2005 Darren Tucker @@ -80,6 +80,10 @@ extern const EVP_CIPHER *evp_acss(void); # 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 diff --git a/crypto/openssh/openbsd-compat/port-aix.c b/crypto/openssh/openbsd-compat/port-aix.c index 5b1cb7387..0bdefbf6d 100644 --- a/crypto/openssh/openbsd-compat/port-aix.c +++ b/crypto/openssh/openbsd-compat/port-aix.c @@ -57,6 +57,8 @@ #include "port-aix.h" +static char *lastlogin_msg = NULL; + # ifdef HAVE_SETAUTHDB static char old_registry[REGISTRY_SIZE] = ""; # endif @@ -276,23 +278,30 @@ sys_auth_record_login(const char *user, const char *host, const char *ttynm, Buffer *loginmsg) { char *msg = NULL; - static int msg_done = 0; int success = 0; aix_setauthdb(user); if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) { success = 1; - if (msg != NULL && loginmsg != NULL && !msg_done) { + if (msg != NULL) { debug("AIX/loginsuccess: msg %s", msg); - buffer_append(loginmsg, msg, strlen(msg)); - xfree(msg); - msg_done = 1; + 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 @@ -365,6 +374,31 @@ aix_restoreauthdb(void) # endif /* WITH_AIXAUTHENTICATE */ +# ifdef USE_AIX_KRB_NAME +/* + * aix_krb5_get_principal_name: returns the user's kerberos client principal name if + * configured, otherwise NULL. Caller must free returned string. + */ +char * +aix_krb5_get_principal_name(char *pw_name) +{ + char *authname = NULL, *authdomain = NULL, *principal = NULL; + + setuserdb(S_READ); + if (getuserattr(pw_name, S_AUTHDOMAIN, &authdomain, SEC_CHAR) != 0) + debug("AIX getuserattr S_AUTHDOMAIN: %s", strerror(errno)); + if (getuserattr(pw_name, S_AUTHNAME, &authname, SEC_CHAR) != 0) + debug("AIX getuserattr S_AUTHNAME: %s", strerror(errno)); + + if (authdomain != NULL) + xasprintf(&principal, "%s@%s", authname ? authname : pw_name, authdomain); + else if (authname != NULL) + principal = xstrdup(authname); + enduserdb(); + return principal; +} +# endif /* USE_AIX_KRB_NAME */ + # if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) # undef getnameinfo /* diff --git a/crypto/openssh/openbsd-compat/port-aix.h b/crypto/openssh/openbsd-compat/port-aix.h index ecb9feae8..53e4e88a0 100644 --- a/crypto/openssh/openbsd-compat/port-aix.h +++ b/crypto/openssh/openbsd-compat/port-aix.h @@ -1,4 +1,4 @@ -/* $Id: port-aix.h,v 1.29 2008/03/09 05:36:55 dtucker Exp $ */ +/* $Id: port-aix.h,v 1.32 2009/12/20 23:49:22 dtucker Exp $ */ /* * @@ -71,6 +71,11 @@ int passwdexpired(char *, char **); # include #endif +/* for setpcred and friends */ +#ifdef HAVE_USERSEC_H +# include +#endif + /* * According to the setauthdb man page, AIX password registries must be 15 * chars or less plus terminating NUL. @@ -87,7 +92,13 @@ void aix_usrinfo(struct passwd *); int sys_auth_allowed_user(struct passwd *, Buffer *); # define CUSTOM_SYS_AUTH_RECORD_LOGIN 1 int sys_auth_record_login(const char *, const char *, const char *, Buffer *); +# define CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG +char *sys_auth_get_lastlogin_msg(const char *, uid_t); # define CUSTOM_FAILED_LOGIN 1 +# if defined(S_AUTHDOMAIN) && defined (S_AUTHNAME) +# define USE_AIX_KRB_NAME +char *aix_krb5_get_principal_name(char *); +# endif #endif void aix_setauthdb(const char *); diff --git a/crypto/openssh/openbsd-compat/port-linux.c b/crypto/openssh/openbsd-compat/port-linux.c index ad262758e..89b9a7340 100644 --- a/crypto/openssh/openbsd-compat/port-linux.c +++ b/crypto/openssh/openbsd-compat/port-linux.c @@ -1,4 +1,4 @@ -/* $Id: port-linux.c,v 1.5 2008/03/26 20:27:21 dtucker Exp $ */ +/* $Id: port-linux.c,v 1.8 2010/03/01 04:52:50 dtucker Exp $ */ /* * Copyright (c) 2005 Daniel Walsh @@ -23,14 +23,17 @@ #include "includes.h" +#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST) #include #include #include +#include -#ifdef WITH_SELINUX #include "log.h" +#include "xmalloc.h" #include "port-linux.h" +#ifdef WITH_SELINUX #include #include #include @@ -168,4 +171,95 @@ ssh_selinux_setup_pty(char *pwname, const char *tty) freecon(user_ctx); debug3("%s: done", __func__); } + +void +ssh_selinux_change_context(const char *newname) +{ + int len, newlen; + char *oldctx, *newctx, *cx; + + if (!ssh_selinux_enabled()) + return; + + if (getcon((security_context_t *)&oldctx) < 0) { + logit("%s: getcon failed with %s", __func__, strerror (errno)); + return; + } + if ((cx = index(oldctx, ':')) == NULL || (cx = index(cx + 1, ':')) == + NULL) { + logit ("%s: unparseable context %s", __func__, oldctx); + return; + } + + newlen = strlen(oldctx) + strlen(newname) + 1; + newctx = xmalloc(newlen); + len = cx - oldctx + 1; + memcpy(newctx, oldctx, len); + strlcpy(newctx + len, newname, newlen - len); + if ((cx = index(cx + 1, ':'))) + strlcat(newctx, cx, newlen); + debug3("%s: setting context from '%s' to '%s'", __func__, oldctx, + newctx); + if (setcon(newctx) < 0) + logit("%s: setcon failed with %s", __func__, strerror (errno)); + xfree(oldctx); + xfree(newctx); +} #endif /* WITH_SELINUX */ + +#ifdef LINUX_OOM_ADJUST +#define OOM_ADJ_PATH "/proc/self/oom_adj" +/* + * The magic "don't kill me", as documented in eg: + * http://lxr.linux.no/#linux+v2.6.32/Documentation/filesystems/proc.txt + */ +#define OOM_ADJ_NOKILL -17 + +static int oom_adj_save = INT_MIN; + +/* + * Tell the kernel's out-of-memory killer to avoid sshd. + * Returns the previous oom_adj value or zero. + */ +void +oom_adjust_setup(void) +{ + FILE *fp; + + debug3("%s", __func__); + if ((fp = fopen(OOM_ADJ_PATH, "r+")) != NULL) { + if (fscanf(fp, "%d", &oom_adj_save) != 1) + verbose("error reading %s: %s", OOM_ADJ_PATH, strerror(errno)); + else { + rewind(fp); + if (fprintf(fp, "%d\n", OOM_ADJ_NOKILL) <= 0) + verbose("error writing %s: %s", + OOM_ADJ_PATH, strerror(errno)); + else + verbose("Set %s from %d to %d", + OOM_ADJ_PATH, oom_adj_save, OOM_ADJ_NOKILL); + } + fclose(fp); + } +} + +/* Restore the saved OOM adjustment */ +void +oom_adjust_restore(void) +{ + FILE *fp; + + debug3("%s", __func__); + if (oom_adj_save == INT_MIN || (fp = fopen(OOM_ADJ_PATH, "w")) == NULL) + return; + + if (fprintf(fp, "%d\n", oom_adj_save) <= 0) + verbose("error writing %s: %s", OOM_ADJ_PATH, strerror(errno)); + else + verbose("Set %s to %d", OOM_ADJ_PATH, oom_adj_save); + + fclose(fp); + return; +} +#endif /* LINUX_OOM_ADJUST */ +#endif /* WITH_SELINUX || LINUX_OOM_ADJUST */ diff --git a/crypto/openssh/openbsd-compat/port-linux.h b/crypto/openssh/openbsd-compat/port-linux.h index 5cd39bf83..209d9a7a2 100644 --- a/crypto/openssh/openbsd-compat/port-linux.h +++ b/crypto/openssh/openbsd-compat/port-linux.h @@ -1,4 +1,4 @@ -/* $Id: port-linux.h,v 1.2 2008/03/26 20:27:21 dtucker Exp $ */ +/* $Id: port-linux.h,v 1.4 2009/12/08 02:39:48 dtucker Exp $ */ /* * Copyright (c) 2006 Damien Miller @@ -23,6 +23,12 @@ int ssh_selinux_enabled(void); void ssh_selinux_setup_pty(char *, const char *); void ssh_selinux_setup_exec_context(char *); +void ssh_selinux_change_context(const char *); +#endif + +#ifdef LINUX_OOM_ADJUST +void oom_adjust_restore(void); +void oom_adjust_setup(void); #endif #endif /* ! _PORT_LINUX_H */ diff --git a/crypto/openssh/openbsd-compat/pwcache.c b/crypto/openssh/openbsd-compat/pwcache.c new file mode 100644 index 000000000..5a8b78801 --- /dev/null +++ b/crypto/openssh/openbsd-compat/pwcache.c @@ -0,0 +1,114 @@ +/* $OpenBSD: pwcache.c,v 1.9 2005/08/08 08:05:34 espie Exp $ */ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/gen/pwcache.c */ + +#include "includes.h" + +#include + +#include +#include +#include +#include +#include + +#define NCACHE 64 /* power of 2 */ +#define MASK (NCACHE - 1) /* bits to store with */ + +#ifndef HAVE_USER_FROM_UID +char * +user_from_uid(uid_t uid, int nouser) +{ + static struct ncache { + uid_t uid; + char *name; + } c_uid[NCACHE]; + static int pwopen; + static char nbuf[15]; /* 32 bits == 10 digits */ + struct passwd *pw; + struct ncache *cp; + + cp = c_uid + (uid & MASK); + if (cp->uid != uid || cp->name == NULL) { + if (pwopen == 0) { +#ifdef HAVE_SETPASSENT + setpassent(1); +#endif + pwopen = 1; + } + if ((pw = getpwuid(uid)) == NULL) { + if (nouser) + return (NULL); + (void)snprintf(nbuf, sizeof(nbuf), "%u", uid); + } + cp->uid = uid; + if (cp->name != NULL) + free(cp->name); + cp->name = strdup(pw ? pw->pw_name : nbuf); + } + return (cp->name); +} +#endif + +#ifndef HAVE_GROUP_FROM_GID +char * +group_from_gid(gid_t gid, int nogroup) +{ + static struct ncache { + gid_t gid; + char *name; + } c_gid[NCACHE]; + static int gropen; + static char nbuf[15]; /* 32 bits == 10 digits */ + struct group *gr; + struct ncache *cp; + + cp = c_gid + (gid & MASK); + if (cp->gid != gid || cp->name == NULL) { + if (gropen == 0) { +#ifdef HAVE_SETGROUPENT + setgroupent(1); +#endif + gropen = 1; + } + if ((gr = getgrgid(gid)) == NULL) { + if (nogroup) + return (NULL); + (void)snprintf(nbuf, sizeof(nbuf), "%u", gid); + } + cp->gid = gid; + if (cp->name != NULL) + free(cp->name); + cp->name = strdup(gr ? gr->gr_name : nbuf); + } + return (cp->name); +} +#endif diff --git a/crypto/openssh/openbsd-compat/readpassphrase.c b/crypto/openssh/openbsd-compat/readpassphrase.c index 11bd8f646..62b6d0d84 100644 --- a/crypto/openssh/openbsd-compat/readpassphrase.c +++ b/crypto/openssh/openbsd-compat/readpassphrase.c @@ -1,7 +1,7 @@ -/* $OpenBSD: readpassphrase.c,v 1.18 2005/08/08 08:05:34 espie Exp $ */ +/* $OpenBSD: readpassphrase.c,v 1.22 2010/01/13 10:20:54 dtucker Exp $ */ /* - * Copyright (c) 2000-2002 Todd C. Miller + * Copyright (c) 2000-2002, 2007 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -46,7 +46,7 @@ # define _POSIX_VDISABLE VDISABLE #endif -static volatile sig_atomic_t signo; +static volatile sig_atomic_t signo[_NSIG]; static void handler(int); @@ -54,7 +54,7 @@ char * readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) { ssize_t nr; - int input, output, save_errno; + int input, output, save_errno, i, need_restart; char ch, *p, *end; struct termios term, oterm; struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; @@ -67,7 +67,11 @@ readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) } restart: - signo = 0; + for (i = 0; i < _NSIG; i++) + signo[i] = 0; + nr = -1; + save_errno = 0; + need_restart = 0; /* * Read and write to /dev/tty if available. If not, read from * stdin and write to stderr unless a tty is required. @@ -117,26 +121,30 @@ restart: 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); + /* No I/O if we are already backgrounded. */ + if (signo[SIGTTOU] != 1 && signo[SIGTTIN] != 1) { + if (!(flags & RPP_STDIN)) + (void)write(output, prompt, strlen(prompt)); + end = buf + bufsiz - 1; + p = buf; + while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { + if (p < end) { + if ((flags & RPP_SEVENBIT)) + ch &= 0x7f; + if (isalpha(ch)) { + if ((flags & RPP_FORCELOWER)) + ch = (char)tolower(ch); + if ((flags & RPP_FORCEUPPER)) + ch = (char)toupper(ch); + } + *p++ = ch; } - *p++ = ch; } + *p = '\0'; + save_errno = errno; + if (!(term.c_lflag & ECHO)) + (void)write(output, "\n", 1); } - *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) { @@ -152,6 +160,7 @@ restart: (void)sigaction(SIGTERM, &saveterm, NULL); (void)sigaction(SIGTSTP, &savetstp, NULL); (void)sigaction(SIGTTIN, &savettin, NULL); + (void)sigaction(SIGTTOU, &savettou, NULL); if (input != STDIN_FILENO) (void)close(input); @@ -159,20 +168,25 @@ restart: * 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; + for (i = 0; i < _NSIG; i++) { + if (signo[i]) { + kill(getpid(), i); + switch (i) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + need_restart = 1; + } } } + if (need_restart) + goto restart; - errno = save_errno; + if (save_errno) + errno = save_errno; return(nr == -1 ? NULL : buf); } - + #if 0 char * getpass(const char *prompt) @@ -186,6 +200,6 @@ getpass(const char *prompt) static void handler(int s) { - signo = s; + signo[s] = 1; } #endif /* HAVE_READPASSPHRASE */ diff --git a/crypto/openssh/packet.c b/crypto/openssh/packet.c index 5afc84ce0..994e35b6d 100644 --- a/crypto/openssh/packet.c +++ b/crypto/openssh/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.160 2009/02/13 11:50:21 markus Exp $ */ +/* $OpenBSD: packet.c,v 1.166 2009/06/27 09:29:06 andreas Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -77,6 +77,7 @@ #include "canohost.h" #include "misc.h" #include "ssh.h" +#include "roaming.h" #ifdef PACKET_DEBUG #define DBG(x) x @@ -86,92 +87,126 @@ #define PACKET_MAX_SIZE (256 * 1024) -/* - * This variable contains the file descriptors used for communicating with - * the other side. connection_in is used for reading; connection_out for - * writing. These can be the same descriptor, in which case it is assumed to - * be a socket. - */ -static int connection_in = -1; -static int connection_out = -1; +struct packet_state { + u_int32_t seqnr; + u_int32_t packets; + u_int64_t blocks; + u_int64_t bytes; +}; -/* Protocol flags for the remote side. */ -static u_int remote_protocol_flags = 0; +struct packet { + TAILQ_ENTRY(packet) next; + u_char type; + Buffer payload; +}; -/* Encryption context for receiving data. This is only used for decryption. */ -static CipherContext receive_context; +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; -/* Encryption context for sending data. This is only used for encryption. */ -static CipherContext send_context; + /* Protocol flags for the remote side. */ + u_int remote_protocol_flags; -/* Buffer for raw input data from the socket. */ -Buffer input; + /* Encryption context for receiving data. Only used for decryption. */ + CipherContext receive_context; -/* Buffer for raw output data going to the socket. */ -Buffer output; + /* Encryption context for sending data. Only used for encryption. */ + CipherContext send_context; -/* Buffer for the partial outgoing packet being constructed. */ -static Buffer outgoing_packet; + /* Buffer for raw input data from the socket. */ + Buffer input; -/* Buffer for the incoming packet currently being processed. */ -static Buffer incoming_packet; + /* Buffer for raw output data going to the socket. */ + Buffer output; -/* Scratch buffer for packet compression/decompression. */ -static Buffer compression_buffer; -static int compression_buffer_ready = 0; + /* Buffer for the partial outgoing packet being constructed. */ + Buffer outgoing_packet; -/* Flag indicating whether packet compression/decompression is enabled. */ -static int packet_compression = 0; + /* Buffer for the incoming packet currently being processed. */ + Buffer incoming_packet; -/* default maximum packet size */ -u_int max_packet_size = 32768; + /* Scratch buffer for packet compression/decompression. */ + Buffer compression_buffer; + int compression_buffer_ready; -/* Flag indicating whether this module has been initialized. */ -static int initialized = 0; + /* + * Flag indicating whether packet compression/decompression is + * enabled. + */ + int packet_compression; -/* Set to true if the connection is interactive. */ -static int interactive_mode = 0; + /* default maximum packet size */ + u_int max_packet_size; -/* Set to true if we are the server side. */ -static int server_side = 0; + /* Flag indicating whether this module has been initialized. */ + int initialized; -/* Set to true if we are authenticated. */ -static int after_authentication = 0; + /* Set to true if the connection is interactive. */ + int interactive_mode; -int keep_alive_timeouts = 0; + /* Set to true if we are the server side. */ + int server_side; -/* Set to the maximum time that we will wait to send or receive a packet */ -static int packet_timeout_ms = -1; + /* Set to true if we are authenticated. */ + int after_authentication; -/* Session key information for Encryption and MAC */ -Newkeys *newkeys[MODE_MAX]; -static struct packet_state { - u_int32_t seqnr; - u_int32_t packets; - u_int64_t blocks; - u_int64_t bytes; -} p_read, p_send; + int keep_alive_timeouts; -static u_int64_t max_blocks_in, max_blocks_out; -static u_int32_t rekey_limit; + /* The maximum time that we will wait to send or receive a packet */ + int packet_timeout_ms; -/* Session key for protocol v1 */ -static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; -static u_int ssh1_keylen; + /* Session key information for Encryption and MAC */ + Newkeys *newkeys[MODE_MAX]; + struct packet_state p_read, p_send; -/* roundup current message to extra_pad bytes */ -static u_char extra_pad = 0; + u_int64_t max_blocks_in, max_blocks_out; + u_int32_t rekey_limit; -/* XXX discard incoming data after MAC error */ -static u_int packet_discard = 0; -static Mac *packet_discard_mac = NULL; + /* Session key for protocol v1 */ + u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; + u_int ssh1_keylen; -struct packet { - TAILQ_ENTRY(packet) next; - u_char type; - Buffer payload; + /* 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; }; -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 @@ -184,21 +219,23 @@ packet_set_connection(int fd_in, int fd_out) if (none == NULL) fatal("packet_set_connection: cannot load cipher 'none'"); - connection_in = fd_in; - connection_out = fd_out; - cipher_init(&send_context, none, (const u_char *)"", + 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(&receive_context, none, (const u_char *)"", + cipher_init(&active_state->receive_context, none, (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT); - newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; - if (!initialized) { - initialized = 1; - buffer_init(&input); - buffer_init(&output); - buffer_init(&outgoing_packet); - buffer_init(&incoming_packet); - TAILQ_INIT(&outgoing); - p_send.packets = p_read.packets = 0; + 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; } } @@ -206,27 +243,29 @@ void packet_set_timeout(int timeout, int count) { if (timeout == 0 || count == 0) { - packet_timeout_ms = -1; + active_state->packet_timeout_ms = -1; return; } if ((INT_MAX / 1000) / count < timeout) - packet_timeout_ms = INT_MAX; + active_state->packet_timeout_ms = INT_MAX; else - packet_timeout_ms = timeout * count * 1000; + active_state->packet_timeout_ms = timeout * count * 1000; } static void packet_stop_discard(void) { - if (packet_discard_mac) { + if (active_state->packet_discard_mac) { char buf[1024]; memset(buf, 'a', sizeof(buf)); - while (buffer_len(&incoming_packet) < PACKET_MAX_SIZE) - buffer_append(&incoming_packet, buf, sizeof(buf)); - (void) mac_compute(packet_discard_mac, - p_read.seqnr, - buffer_ptr(&incoming_packet), + 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()); @@ -239,10 +278,11 @@ 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) - packet_discard_mac = mac; - if (buffer_len(&input) >= discard) + active_state->packet_discard_mac = mac; + if (buffer_len(&active_state->input) >= discard) packet_stop_discard(); - packet_discard = discard - buffer_len(&input); + active_state->packet_discard = discard - + buffer_len(&active_state->input); } /* Returns 1 if remote host is connected via socket, 0 if not. */ @@ -254,15 +294,17 @@ packet_connection_is_on_socket(void) socklen_t fromlen, tolen; /* filedescriptors in and out are the same, so it's a socket */ - if (connection_in == connection_out) + if (active_state->connection_in == active_state->connection_out) return 1; fromlen = sizeof(from); memset(&from, 0, sizeof(from)); - if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) + if (getpeername(active_state->connection_in, (struct sockaddr *)&from, + &fromlen) < 0) return 0; tolen = sizeof(to); memset(&to, 0, sizeof(to)); - if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) + if (getpeername(active_state->connection_out, (struct sockaddr *)&to, + &tolen) < 0) return 0; if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) return 0; @@ -283,9 +325,9 @@ packet_get_keyiv(int mode, u_char *iv, u_int len) CipherContext *cc; if (mode == MODE_OUT) - cc = &send_context; + cc = &active_state->send_context; else - cc = &receive_context; + cc = &active_state->receive_context; cipher_get_keyiv(cc, iv, len); } @@ -296,9 +338,9 @@ packet_get_keycontext(int mode, u_char *dat) CipherContext *cc; if (mode == MODE_OUT) - cc = &send_context; + cc = &active_state->send_context; else - cc = &receive_context; + cc = &active_state->receive_context; return (cipher_get_keycontext(cc, dat)); } @@ -309,9 +351,9 @@ packet_set_keycontext(int mode, u_char *dat) CipherContext *cc; if (mode == MODE_OUT) - cc = &send_context; + cc = &active_state->send_context; else - cc = &receive_context; + cc = &active_state->receive_context; cipher_set_keycontext(cc, dat); } @@ -322,9 +364,9 @@ packet_get_keyiv_len(int mode) CipherContext *cc; if (mode == MODE_OUT) - cc = &send_context; + cc = &active_state->send_context; else - cc = &receive_context; + cc = &active_state->receive_context; return (cipher_get_keyiv_len(cc)); } @@ -335,9 +377,9 @@ packet_set_iv(int mode, u_char *dat) CipherContext *cc; if (mode == MODE_OUT) - cc = &send_context; + cc = &active_state->send_context; else - cc = &receive_context; + cc = &active_state->receive_context; cipher_set_keyiv(cc, dat); } @@ -345,7 +387,7 @@ packet_set_iv(int mode, u_char *dat) int packet_get_ssh1_cipher(void) { - return (cipher_get_number(receive_context.cipher)); + return (cipher_get_number(active_state->receive_context.cipher)); } void @@ -354,7 +396,8 @@ packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packe { struct packet_state *state; - state = (mode == MODE_IN) ? &p_read : &p_send; + state = (mode == MODE_IN) ? + &active_state->p_read : &active_state->p_send; if (seqnr) *seqnr = state->seqnr; if (blocks) @@ -371,7 +414,8 @@ packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets, { struct packet_state *state; - state = (mode == MODE_IN) ? &p_read : &p_send; + state = (mode == MODE_IN) ? + &active_state->p_read : &active_state->p_send; state->seqnr = seqnr; state->blocks = blocks; state->packets = packets; @@ -387,7 +431,8 @@ packet_connection_is_ipv4(void) socklen_t tolen = sizeof(to); memset(&to, 0, sizeof(to)); - if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) + if (getsockname(active_state->connection_out, (struct sockaddr *)&to, + &tolen) < 0) return 0; if (to.ss_family == AF_INET) return 1; @@ -405,10 +450,10 @@ void packet_set_nonblocking(void) { /* Set the socket into non-blocking mode. */ - set_nonblock(connection_in); + set_nonblock(active_state->connection_in); - if (connection_out != connection_in) - set_nonblock(connection_out); + if (active_state->connection_out != active_state->connection_in) + set_nonblock(active_state->connection_out); } /* Returns the socket used for reading. */ @@ -416,7 +461,7 @@ packet_set_nonblocking(void) int packet_get_connection_in(void) { - return connection_in; + return active_state->connection_in; } /* Returns the descriptor used for writing. */ @@ -424,7 +469,7 @@ packet_get_connection_in(void) int packet_get_connection_out(void) { - return connection_out; + return active_state->connection_out; } /* Closes the connection and clears and frees internal data structures. */ @@ -432,26 +477,26 @@ packet_get_connection_out(void) void packet_close(void) { - if (!initialized) + if (!active_state->initialized) return; - initialized = 0; - if (connection_in == connection_out) { - shutdown(connection_out, SHUT_RDWR); - close(connection_out); + 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(connection_in); - close(connection_out); + close(active_state->connection_in); + close(active_state->connection_out); } - buffer_free(&input); - buffer_free(&output); - buffer_free(&outgoing_packet); - buffer_free(&incoming_packet); - if (compression_buffer_ready) { - buffer_free(&compression_buffer); + buffer_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(&send_context); - cipher_cleanup(&receive_context); + cipher_cleanup(&active_state->send_context); + cipher_cleanup(&active_state->receive_context); } /* Sets remote side protocol flags. */ @@ -459,7 +504,7 @@ packet_close(void) void packet_set_protocol_flags(u_int protocol_flags) { - remote_protocol_flags = protocol_flags; + active_state->remote_protocol_flags = protocol_flags; } /* Returns the remote protocol flags set earlier by the above function. */ @@ -467,7 +512,7 @@ packet_set_protocol_flags(u_int protocol_flags) u_int packet_get_protocol_flags(void) { - return remote_protocol_flags; + return active_state->remote_protocol_flags; } /* @@ -478,18 +523,18 @@ packet_get_protocol_flags(void) static void packet_init_compression(void) { - if (compression_buffer_ready == 1) + if (active_state->compression_buffer_ready == 1) return; - compression_buffer_ready = 1; - buffer_init(&compression_buffer); + active_state->compression_buffer_ready = 1; + buffer_init(&active_state->compression_buffer); } void packet_start_compression(int level) { - if (packet_compression && !compat20) + if (active_state->packet_compression && !compat20) fatal("Compression already enabled."); - packet_compression = 1; + active_state->packet_compression = 1; packet_init_compression(); buffer_compress_init_send(level); buffer_compress_init_recv(); @@ -513,19 +558,21 @@ packet_set_encryption_key(const u_char *key, u_int keylen, 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(ssh1_key, key, keylen); - ssh1_keylen = keylen; - cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT); - cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT); + 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 (ssh1_keylen); - memcpy(key, ssh1_key, ssh1_keylen); - return (ssh1_keylen); + 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. */ @@ -539,8 +586,8 @@ packet_start(u_char type) len = compat20 ? 6 : 9; memset(buf, 0, len - 1); buf[len - 1] = type; - buffer_clear(&outgoing_packet); - buffer_append(&outgoing_packet, buf, len); + buffer_clear(&active_state->outgoing_packet); + buffer_append(&active_state->outgoing_packet, buf, len); } /* Append payload. */ @@ -549,43 +596,49 @@ packet_put_char(int value) { char ch = value; - buffer_append(&outgoing_packet, &ch, 1); + buffer_append(&active_state->outgoing_packet, &ch, 1); } void packet_put_int(u_int value) { - buffer_put_int(&outgoing_packet, 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(&outgoing_packet, buf, len); + buffer_put_string(&active_state->outgoing_packet, buf, len); } void packet_put_cstring(const char *str) { - buffer_put_cstring(&outgoing_packet, str); + buffer_put_cstring(&active_state->outgoing_packet, str); } void packet_put_raw(const void *buf, u_int len) { - buffer_append(&outgoing_packet, buf, len); + buffer_append(&active_state->outgoing_packet, buf, len); } void packet_put_bignum(BIGNUM * value) { - buffer_put_bignum(&outgoing_packet, value); + buffer_put_bignum(&active_state->outgoing_packet, value); } void packet_put_bignum2(BIGNUM * value) { - buffer_put_bignum2(&outgoing_packet, value); + buffer_put_bignum2(&active_state->outgoing_packet, value); } /* @@ -605,24 +658,27 @@ packet_send1(void) * If using packet compression, compress the payload of the outgoing * packet. */ - if (packet_compression) { - buffer_clear(&compression_buffer); + if (active_state->packet_compression) { + buffer_clear(&active_state->compression_buffer); /* Skip padding. */ - buffer_consume(&outgoing_packet, 8); + buffer_consume(&active_state->outgoing_packet, 8); /* padding */ - buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); - buffer_compress(&outgoing_packet, &compression_buffer); - buffer_clear(&outgoing_packet); - buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), - buffer_len(&compression_buffer)); + 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(&outgoing_packet) + 4 - 8; + len = buffer_len(&active_state->outgoing_packet) + 4 - 8; /* Insert padding. Initialized to zero in packet_start1() */ padding = 8 - len % 8; - if (!send_context.plaintext) { - cp = buffer_ptr(&outgoing_packet); + 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(); @@ -630,33 +686,36 @@ packet_send1(void) rnd >>= 8; } } - buffer_consume(&outgoing_packet, 8 - padding); + buffer_consume(&active_state->outgoing_packet, 8 - padding); /* Add check bytes. */ - checksum = ssh_crc32(buffer_ptr(&outgoing_packet), - buffer_len(&outgoing_packet)); + checksum = ssh_crc32(buffer_ptr(&active_state->outgoing_packet), + buffer_len(&active_state->outgoing_packet)); put_u32(buf, checksum); - buffer_append(&outgoing_packet, buf, 4); + buffer_append(&active_state->outgoing_packet, buf, 4); #ifdef PACKET_DEBUG fprintf(stderr, "packet_send plain: "); - buffer_dump(&outgoing_packet); + buffer_dump(&active_state->outgoing_packet); #endif /* Append to output. */ put_u32(buf, len); - buffer_append(&output, buf, 4); - cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); - cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), - buffer_len(&outgoing_packet)); + 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(&output); + buffer_dump(&active_state->output); #endif - p_send.packets++; - p_send.bytes += len + buffer_len(&outgoing_packet); - buffer_clear(&outgoing_packet); + 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 @@ -678,22 +737,22 @@ set_newkeys(int mode) debug2("set_newkeys: mode %d", mode); if (mode == MODE_OUT) { - cc = &send_context; + cc = &active_state->send_context; crypt_type = CIPHER_ENCRYPT; - p_send.packets = p_send.blocks = 0; - max_blocks = &max_blocks_out; + active_state->p_send.packets = active_state->p_send.blocks = 0; + max_blocks = &active_state->max_blocks_out; } else { - cc = &receive_context; + cc = &active_state->receive_context; crypt_type = CIPHER_DECRYPT; - p_read.packets = p_read.blocks = 0; - max_blocks = &max_blocks_in; + active_state->p_read.packets = active_state->p_read.blocks = 0; + max_blocks = &active_state->max_blocks_in; } - if (newkeys[mode] != NULL) { + if (active_state->newkeys[mode] != NULL) { debug("set_newkeys: rekeying"); cipher_cleanup(cc); - enc = &newkeys[mode]->enc; - mac = &newkeys[mode]->mac; - comp = &newkeys[mode]->comp; + 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); @@ -701,14 +760,14 @@ set_newkeys(int mode) xfree(mac->name); xfree(mac->key); xfree(comp->name); - xfree(newkeys[mode]); + xfree(active_state->newkeys[mode]); } - newkeys[mode] = kex_get_newkeys(mode); - if (newkeys[mode] == NULL) + active_state->newkeys[mode] = kex_get_newkeys(mode); + if (active_state->newkeys[mode] == NULL) fatal("newkeys: no keys for mode %d", mode); - enc = &newkeys[mode]->enc; - mac = &newkeys[mode]->mac; - comp = &newkeys[mode]->comp; + 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)); @@ -719,8 +778,8 @@ set_newkeys(int mode) memset(enc->key, 0, enc->key_len); memset(mac->key, 0, mac->key_len); */ if ((comp->type == COMP_ZLIB || - (comp->type == COMP_DELAYED && after_authentication)) && - comp->enabled == 0) { + (comp->type == COMP_DELAYED && + active_state->after_authentication)) && comp->enabled == 0) { packet_init_compression(); if (mode == MODE_OUT) buffer_compress_init_send(6); @@ -736,8 +795,9 @@ set_newkeys(int mode) *max_blocks = (u_int64_t)1 << (enc->block_size*2); else *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; - if (rekey_limit) - *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); + if (active_state->rekey_limit) + *max_blocks = MIN(*max_blocks, + active_state->rekey_limit / enc->block_size); } /* @@ -755,12 +815,12 @@ packet_enable_delayed_compress(void) * Remember that we are past the authentication step, so rekeying * with COMP_DELAYED will turn on compression immediately. */ - after_authentication = 1; + active_state->after_authentication = 1; for (mode = 0; mode < MODE_MAX; mode++) { /* protocol error: USERAUTH_SUCCESS received before NEWKEYS */ - if (newkeys[mode] == NULL) + if (active_state->newkeys[mode] == NULL) continue; - comp = &newkeys[mode]->comp; + comp = &active_state->newkeys[mode]->comp; if (comp && !comp->enabled && comp->type == COMP_DELAYED) { packet_init_compression(); if (mode == MODE_OUT) @@ -788,37 +848,39 @@ packet_send2_wrapped(void) Comp *comp = NULL; int block_size; - if (newkeys[MODE_OUT] != NULL) { - enc = &newkeys[MODE_OUT]->enc; - mac = &newkeys[MODE_OUT]->mac; - comp = &newkeys[MODE_OUT]->comp; + 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(&outgoing_packet); + cp = buffer_ptr(&active_state->outgoing_packet); type = cp[5]; #ifdef PACKET_DEBUG fprintf(stderr, "plain: "); - buffer_dump(&outgoing_packet); + buffer_dump(&active_state->outgoing_packet); #endif if (comp && comp->enabled) { - len = buffer_len(&outgoing_packet); + len = buffer_len(&active_state->outgoing_packet); /* skip header, compress only payload */ - buffer_consume(&outgoing_packet, 5); - buffer_clear(&compression_buffer); - buffer_compress(&outgoing_packet, &compression_buffer); - buffer_clear(&outgoing_packet); - buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); - buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), - buffer_len(&compression_buffer)); + 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(&outgoing_packet))); + buffer_len(&active_state->outgoing_packet))); } /* sizeof (packet_len + pad_len + payload) */ - len = buffer_len(&outgoing_packet); + len = buffer_len(&active_state->outgoing_packet); /* * calc size of padding, alloc space, get random data, @@ -827,17 +889,19 @@ packet_send2_wrapped(void) padlen = block_size - (len % block_size); if (padlen < 4) padlen += block_size; - if (extra_pad) { + if (active_state->extra_pad) { /* will wrap if extra_pad+padlen > 255 */ - extra_pad = roundup(extra_pad, block_size); - pad = extra_pad - ((len + padlen) % extra_pad); + 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, extra_pad); + pad, len, padlen, active_state->extra_pad); padlen += pad; - extra_pad = 0; + active_state->extra_pad = 0; } - cp = buffer_append_space(&outgoing_packet, padlen); - if (enc && !send_context.plaintext) { + 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) @@ -850,86 +914,88 @@ packet_send2_wrapped(void) memset(cp, 0, padlen); } /* packet_length includes payload, padding and padding length field */ - packet_length = buffer_len(&outgoing_packet) - 4; - cp = buffer_ptr(&outgoing_packet); + 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, p_send.seqnr, - buffer_ptr(&outgoing_packet), - buffer_len(&outgoing_packet)); - DBG(debug("done calc MAC out #%d", p_send.seqnr)); + 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(&output, buffer_len(&outgoing_packet)); - cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), - buffer_len(&outgoing_packet)); + 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(&output, macbuf, mac->mac_len); + buffer_append(&active_state->output, macbuf, mac->mac_len); #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); - buffer_dump(&output); + buffer_dump(&active_state->output); #endif /* increment sequence number for outgoing packets */ - if (++p_send.seqnr == 0) + if (++active_state->p_send.seqnr == 0) logit("outgoing seqnr wraps around"); - if (++p_send.packets == 0) + if (++active_state->p_send.packets == 0) if (!(datafellows & SSH_BUG_NOREKEY)) fatal("XXX too many packets with same key"); - p_send.blocks += (packet_length + 4) / block_size; - p_send.bytes += packet_length + 4; - buffer_clear(&outgoing_packet); + 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 && server_side) + else if (type == SSH2_MSG_USERAUTH_SUCCESS && active_state->server_side) packet_enable_delayed_compress(); } static void packet_send2(void) { - static int rekeying = 0; struct packet *p; u_char type, *cp; - cp = buffer_ptr(&outgoing_packet); + cp = buffer_ptr(&active_state->outgoing_packet); type = cp[5]; /* during rekeying we can only send key exchange messages */ - if (rekeying) { + 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, &outgoing_packet, sizeof(Buffer)); - buffer_init(&outgoing_packet); - TAILQ_INSERT_TAIL(&outgoing, p, next); + 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) - rekeying = 1; + active_state->rekeying = 1; packet_send2_wrapped(); /* after a NEWKEYS message we can send the complete queue */ if (type == SSH2_MSG_NEWKEYS) { - rekeying = 0; - while ((p = TAILQ_FIRST(&outgoing))) { + active_state->rekeying = 0; + while ((p = TAILQ_FIRST(&active_state->outgoing))) { type = p->type; debug("dequeue packet: %u", type); - buffer_free(&outgoing_packet); - memcpy(&outgoing_packet, &p->payload, + buffer_free(&active_state->outgoing_packet); + memcpy(&active_state->outgoing_packet, &p->payload, sizeof(Buffer)); - TAILQ_REMOVE(&outgoing, p, next); + TAILQ_REMOVE(&active_state->outgoing, p, next); xfree(p); packet_send2_wrapped(); } @@ -955,15 +1021,15 @@ packet_send(void) int packet_read_seqnr(u_int32_t *seqnr_p) { - int type, len, ret, ms_remain; + 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(connection_in+1, NFDBITS), - sizeof(fd_mask)); + 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(); @@ -987,27 +1053,27 @@ packet_read_seqnr(u_int32_t *seqnr_p) * Otherwise, wait for some data to arrive, add it to the * buffer, and try again. */ - memset(setp, 0, howmany(connection_in + 1, NFDBITS) * - sizeof(fd_mask)); - FD_SET(connection_in, setp); + memset(setp, 0, howmany(active_state->connection_in + 1, + NFDBITS) * sizeof(fd_mask)); + FD_SET(active_state->connection_in, setp); - if (packet_timeout_ms > 0) { - ms_remain = packet_timeout_ms; + if (active_state->packet_timeout_ms > 0) { + ms_remain = active_state->packet_timeout_ms; timeoutp = &timeout; } /* Wait for some data to arrive. */ for (;;) { - if (packet_timeout_ms != -1) { + if (active_state->packet_timeout_ms != -1) { ms_to_timeval(&timeout, ms_remain); gettimeofday(&start, NULL); } - if ((ret = select(connection_in + 1, setp, NULL, - NULL, timeoutp)) >= 0) + if ((ret = select(active_state->connection_in + 1, setp, + NULL, NULL, timeoutp)) >= 0) break; - if (errno != EAGAIN && errno != EINTR && + if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) break; - if (packet_timeout_ms == -1) + if (active_state->packet_timeout_ms == -1) continue; ms_subtract_diff(&start, &ms_remain); if (ms_remain <= 0) { @@ -1021,7 +1087,11 @@ packet_read_seqnr(u_int32_t *seqnr_p) cleanup_exit(255); } /* Read data from the socket. */ - len = read(connection_in, buf, sizeof(buf)); + 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); @@ -1073,31 +1143,32 @@ packet_read_poll1(void) u_int checksum, stored_checksum; /* Check if input size is less than minimum packet size. */ - if (buffer_len(&input) < 4 + 8) + if (buffer_len(&active_state->input) < 4 + 8) return SSH_MSG_NONE; /* Get length of incoming packet. */ - cp = buffer_ptr(&input); + 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(&input) < 4 + padded_len) + if (buffer_len(&active_state->input) < 4 + padded_len) return SSH_MSG_NONE; /* The entire packet is in buffer. */ /* Consume packet length. */ - buffer_consume(&input, 4); + 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 (!receive_context.plaintext) { - switch (detect_attack(buffer_ptr(&input), padded_len)) { + 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"); @@ -1108,45 +1179,48 @@ packet_read_poll1(void) } /* Decrypt data to incoming_packet. */ - buffer_clear(&incoming_packet); - cp = buffer_append_space(&incoming_packet, padded_len); - cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len); + 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(&input, padded_len); + buffer_consume(&active_state->input, padded_len); #ifdef PACKET_DEBUG fprintf(stderr, "read_poll plain: "); - buffer_dump(&incoming_packet); + buffer_dump(&active_state->incoming_packet); #endif /* Compute packet checksum. */ - checksum = ssh_crc32(buffer_ptr(&incoming_packet), - buffer_len(&incoming_packet) - 4); + checksum = ssh_crc32(buffer_ptr(&active_state->incoming_packet), + buffer_len(&active_state->incoming_packet) - 4); /* Skip padding. */ - buffer_consume(&incoming_packet, 8 - len % 8); + buffer_consume(&active_state->incoming_packet, 8 - len % 8); /* Test check bytes. */ - if (len != buffer_len(&incoming_packet)) + if (len != buffer_len(&active_state->incoming_packet)) packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", - len, buffer_len(&incoming_packet)); + len, buffer_len(&active_state->incoming_packet)); - cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; + 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(&incoming_packet, 4); - - if (packet_compression) { - buffer_clear(&compression_buffer); - buffer_uncompress(&incoming_packet, &compression_buffer); - buffer_clear(&incoming_packet); - buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), - buffer_len(&compression_buffer)); + 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)); } - p_read.packets++; - p_read.bytes += padded_len + 4; - type = buffer_get_char(&incoming_packet); + 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; @@ -1155,7 +1229,6 @@ packet_read_poll1(void) static int packet_read_poll2(u_int32_t *seqnr_p) { - static u_int packet_length = 0; u_int padlen, need; u_char *macbuf, *cp, type; u_int maclen, block_size; @@ -1163,50 +1236,52 @@ packet_read_poll2(u_int32_t *seqnr_p) Mac *mac = NULL; Comp *comp = NULL; - if (packet_discard) + if (active_state->packet_discard) return SSH_MSG_NONE; - if (newkeys[MODE_IN] != NULL) { - enc = &newkeys[MODE_IN]->enc; - mac = &newkeys[MODE_IN]->mac; - comp = &newkeys[MODE_IN]->comp; + 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 (packet_length == 0) { + 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(&input) < block_size) + if (buffer_len(&active_state->input) < block_size) return SSH_MSG_NONE; - buffer_clear(&incoming_packet); - cp = buffer_append_space(&incoming_packet, block_size); - cipher_crypt(&receive_context, cp, buffer_ptr(&input), + buffer_clear(&active_state->incoming_packet); + cp = buffer_append_space(&active_state->incoming_packet, block_size); - cp = buffer_ptr(&incoming_packet); - packet_length = get_u32(cp); - if (packet_length < 1 + 4 || packet_length > PACKET_MAX_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(&incoming_packet); + buffer_dump(&active_state->incoming_packet); #endif - logit("Bad packet length %u.", packet_length); - packet_start_discard(enc, mac, packet_length, + 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", packet_length+4)); - buffer_consume(&input, block_size); + 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 + packet_length - block_size; + 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, packet_length, + packet_start_discard(enc, mac, active_state->packlen, PACKET_MAX_SIZE - block_size); return SSH_MSG_NONE; } @@ -1214,84 +1289,90 @@ packet_read_poll2(u_int32_t *seqnr_p) * check if the entire packet has been received and * decrypt into incoming_packet */ - if (buffer_len(&input) < need + maclen) + if (buffer_len(&active_state->input) < need + maclen) return SSH_MSG_NONE; #ifdef PACKET_DEBUG fprintf(stderr, "read_poll enc/full: "); - buffer_dump(&input); + buffer_dump(&active_state->input); #endif - cp = buffer_append_space(&incoming_packet, need); - cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); - buffer_consume(&input, need); + 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, p_read.seqnr, - buffer_ptr(&incoming_packet), - buffer_len(&incoming_packet)); - if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) { + 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, packet_length, + packet_start_discard(enc, mac, active_state->packlen, PACKET_MAX_SIZE - need); return SSH_MSG_NONE; } - DBG(debug("MAC #%d ok", p_read.seqnr)); - buffer_consume(&input, mac->mac_len); + 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 = p_read.seqnr; - if (++p_read.seqnr == 0) + *seqnr_p = active_state->p_read.seqnr; + if (++active_state->p_read.seqnr == 0) logit("incoming seqnr wraps around"); - if (++p_read.packets == 0) + if (++active_state->p_read.packets == 0) if (!(datafellows & SSH_BUG_NOREKEY)) fatal("XXX too many packets with same key"); - p_read.blocks += (packet_length + 4) / block_size; - p_read.bytes += packet_length + 4; + 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(&incoming_packet); + 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(&incoming_packet, 4 + 1); - buffer_consume_end(&incoming_packet, padlen); + 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(&incoming_packet))); + DBG(debug("input: len before de-compress %d", + buffer_len(&active_state->incoming_packet))); if (comp && comp->enabled) { - buffer_clear(&compression_buffer); - buffer_uncompress(&incoming_packet, &compression_buffer); - buffer_clear(&incoming_packet); - buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), - buffer_len(&compression_buffer)); + 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(&incoming_packet))); + buffer_len(&active_state->incoming_packet))); } /* * get packet type, implies consume. * return length of payload (without type field) */ - type = buffer_get_char(&incoming_packet); + 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 && !server_side) + 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(&incoming_packet); + buffer_dump(&active_state->incoming_packet); #endif /* reset for next packet */ - packet_length = 0; + active_state->packlen = 0; return type; } @@ -1306,7 +1387,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p) if (compat20) { type = packet_read_poll2(seqnr_p); if (type) { - keep_alive_timeouts = 0; + active_state->keep_alive_timeouts = 0; DBG(debug("received packet type %d", type)); } switch (type) { @@ -1376,14 +1457,14 @@ packet_read_poll(void) void packet_process_incoming(const char *buf, u_int len) { - if (packet_discard) { - keep_alive_timeouts = 0; /* ?? */ - if (len >= packet_discard) + if (active_state->packet_discard) { + active_state->keep_alive_timeouts = 0; /* ?? */ + if (len >= active_state->packet_discard) packet_stop_discard(); - packet_discard -= len; + active_state->packet_discard -= len; return; } - buffer_append(&input, buf, len); + buffer_append(&active_state->input, buf, len); } /* Returns a character from the packet. */ @@ -1393,7 +1474,7 @@ packet_get_char(void) { char ch; - buffer_get(&incoming_packet, &ch, 1); + buffer_get(&active_state->incoming_packet, &ch, 1); return (u_char) ch; } @@ -1402,7 +1483,15 @@ packet_get_char(void) u_int packet_get_int(void) { - return buffer_get_int(&incoming_packet); + 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); } /* @@ -1413,29 +1502,29 @@ packet_get_int(void) void packet_get_bignum(BIGNUM * value) { - buffer_get_bignum(&incoming_packet, value); + buffer_get_bignum(&active_state->incoming_packet, value); } void packet_get_bignum2(BIGNUM * value) { - buffer_get_bignum2(&incoming_packet, value); + buffer_get_bignum2(&active_state->incoming_packet, value); } void * packet_get_raw(u_int *length_ptr) { - u_int bytes = buffer_len(&incoming_packet); + u_int bytes = buffer_len(&active_state->incoming_packet); if (length_ptr != NULL) *length_ptr = bytes; - return buffer_ptr(&incoming_packet); + return buffer_ptr(&active_state->incoming_packet); } int packet_remaining(void) { - return buffer_len(&incoming_packet); + return buffer_len(&active_state->incoming_packet); } /* @@ -1448,13 +1537,13 @@ packet_remaining(void) void * packet_get_string(u_int *length_ptr) { - return buffer_get_string(&incoming_packet, 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(&incoming_packet, length_ptr); + return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr); } /* @@ -1547,23 +1636,25 @@ packet_disconnect(const char *fmt,...) void packet_write_poll(void) { - int len = buffer_len(&output); + int len = buffer_len(&active_state->output); + int cont; if (len > 0) { - len = write(connection_out, buffer_ptr(&output), len); + 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) + if (len == 0 && !cont) fatal("Write connection closed"); - buffer_consume(&output, len); + buffer_consume(&active_state->output, len); } } - /* * Calls packet_write_poll repeatedly until all pending output data has been * written. @@ -1576,30 +1667,30 @@ packet_write_wait(void) int ret, ms_remain; struct timeval start, timeout, *timeoutp = NULL; - setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), - sizeof(fd_mask)); + 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(connection_out + 1, NFDBITS) * - sizeof(fd_mask)); - FD_SET(connection_out, setp); + memset(setp, 0, howmany(active_state->connection_out + 1, + NFDBITS) * sizeof(fd_mask)); + FD_SET(active_state->connection_out, setp); - if (packet_timeout_ms > 0) { - ms_remain = packet_timeout_ms; + if (active_state->packet_timeout_ms > 0) { + ms_remain = active_state->packet_timeout_ms; timeoutp = &timeout; } for (;;) { - if (packet_timeout_ms != -1) { + if (active_state->packet_timeout_ms != -1) { ms_to_timeval(&timeout, ms_remain); gettimeofday(&start, NULL); } - if ((ret = select(connection_out + 1, NULL, setp, - NULL, timeoutp)) >= 0) + if ((ret = select(active_state->connection_out + 1, + NULL, setp, NULL, timeoutp)) >= 0) break; - if (errno != EAGAIN && errno != EINTR && + if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) break; - if (packet_timeout_ms == -1) + if (active_state->packet_timeout_ms == -1) continue; ms_subtract_diff(&start, &ms_remain); if (ms_remain <= 0) { @@ -1622,7 +1713,7 @@ packet_write_wait(void) int packet_have_data_to_write(void) { - return buffer_len(&output) != 0; + return buffer_len(&active_state->output) != 0; } /* Returns true if there is not too much data to write to the connection. */ @@ -1630,13 +1721,12 @@ packet_have_data_to_write(void) int packet_not_very_much_data_to_write(void) { - if (interactive_mode) - return buffer_len(&output) < 16384; + if (active_state->interactive_mode) + return buffer_len(&active_state->output) < 16384; else - return buffer_len(&output) < 128 * 1024; + return buffer_len(&active_state->output) < 128 * 1024; } - static void packet_set_tos(int interactive) { @@ -1646,7 +1736,7 @@ packet_set_tos(int interactive) if (!packet_connection_is_on_socket() || !packet_connection_is_ipv4()) return; - if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &tos, + if (setsockopt(active_state->connection_in, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) error("setsockopt IP_TOS %d: %.100s:", tos, strerror(errno)); @@ -1658,19 +1748,17 @@ packet_set_tos(int interactive) void packet_set_interactive(int interactive) { - static int called = 0; - - if (called) + if (active_state->set_interactive_called) return; - called = 1; + active_state->set_interactive_called = 1; /* Record that we are in interactive mode. */ - interactive_mode = interactive; + active_state->interactive_mode = interactive; /* Only set socket options if using a socket. */ if (!packet_connection_is_on_socket()) return; - set_nodelay(connection_in); + set_nodelay(active_state->connection_in); packet_set_tos(interactive); } @@ -1679,34 +1767,50 @@ packet_set_interactive(int interactive) int packet_is_interactive(void) { - return interactive_mode; + return active_state->interactive_mode; } int packet_set_maxsize(u_int s) { - static int called = 0; - - if (called) { + if (active_state->set_maxsize_called) { logit("packet_set_maxsize: called twice: old %d new %d", - max_packet_size, s); + 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; } - called = 1; + active_state->set_maxsize_called = 1; debug("packet_set_maxsize: setting to %d", s); - max_packet_size = 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) { - extra_pad = pad; + active_state->extra_pad = pad; } /* @@ -1743,26 +1847,93 @@ packet_need_rekeying(void) if (datafellows & SSH_BUG_NOREKEY) return 0; return - (p_send.packets > MAX_PACKETS) || - (p_read.packets > MAX_PACKETS) || - (max_blocks_out && (p_send.blocks > max_blocks_out)) || - (max_blocks_in && (p_read.blocks > max_blocks_in)); + (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) { - rekey_limit = bytes; + active_state->rekey_limit = bytes; } void packet_set_server(void) { - server_side = 1; + active_state->server_side = 1; } void packet_set_authenticated(void) { - after_authentication = 1; + 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 index 03bb87c9b..33523d750 100644 --- a/crypto/openssh/packet.h +++ b/crypto/openssh/packet.h @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.h,v 1.49 2008/07/10 18:08:11 markus Exp $ */ +/* $OpenBSD: packet.h,v 1.52 2009/06/27 09:29:06 andreas Exp $ */ /* * Author: Tatu Ylonen @@ -39,6 +39,7 @@ 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); @@ -55,6 +56,7 @@ 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); @@ -72,6 +74,7 @@ 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); @@ -87,10 +90,10 @@ void packet_add_padding(u_char); void tty_make_modes(int, struct termios *); void tty_parse_modes(int, int *); -extern u_int max_packet_size; -extern int keep_alive_timeouts; +void packet_set_alive_timeouts(int); +int packet_inc_alive_timeouts(void); int packet_set_maxsize(u_int); -#define packet_get_maxsize() max_packet_size +u_int packet_get_maxsize(void); /* don't allow remaining bytes after the end of the message */ #define packet_check_eom() \ @@ -106,4 +109,10 @@ do { \ 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 index bc4f66a66..0bb0c0626 100644 --- a/crypto/openssh/pathnames.h +++ b/crypto/openssh/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.17 2008/12/29 02:23:26 stevesk Exp $ */ +/* $OpenBSD: pathnames.h,v 1.19 2010/02/11 20:37:47 djm Exp $ */ /* * Author: Tatu Ylonen @@ -125,6 +125,11 @@ #define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign" #endif +/* Location of ssh-pkcs11-helper to support keys in tokens */ +#ifndef _PATH_SSH_PKCS11_HELPER +#define _PATH_SSH_PKCS11_HELPER "/usr/libexec/ssh-pkcs11-helper" +#endif + /* xauth for X11 forwarding */ #ifndef _PATH_XAUTH #define _PATH_XAUTH "/usr/local/bin/xauth" diff --git a/crypto/openssh/pkcs11.h b/crypto/openssh/pkcs11.h new file mode 100644 index 000000000..2cde5b3f4 --- /dev/null +++ b/crypto/openssh/pkcs11.h @@ -0,0 +1,1357 @@ +/* $OpenBSD: pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */ +/* pkcs11.h + Copyright 2006, 2007 g10 Code GmbH + Copyright 2006 Andreas Jellinghaus + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. */ + +/* Please submit changes back to the Scute project at + http://www.scute.org/ (or send them to marcus@g10code.com), so that + they can be picked up by other projects from there as well. */ + +/* This file is a modified implementation of the PKCS #11 standard by + RSA Security Inc. It is mostly a drop-in replacement, with the + following change: + + This header file does not require any macro definitions by the user + (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros + for you (if useful, some are missing, let me know if you need + more). + + There is an additional API available that does comply better to the + GNU coding standard. It can be switched on by defining + CRYPTOKI_GNU before including this header file. For this, the + following changes are made to the specification: + + All structure types are changed to a "struct ck_foo" where CK_FOO + is the type name in PKCS #11. + + All non-structure types are changed to ck_foo_t where CK_FOO is the + lowercase version of the type name in PKCS #11. The basic types + (CK_ULONG et al.) are removed without substitute. + + All members of structures are modified in the following way: Type + indication prefixes are removed, and underscore characters are + inserted before words. Then the result is lowercased. + + Note that function names are still in the original case, as they + need for ABI compatibility. + + CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use + . + + If CRYPTOKI_COMPAT is defined before including this header file, + then none of the API changes above take place, and the API is the + one defined by the PKCS #11 standard. */ + +#ifndef PKCS11_H +#define PKCS11_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The version of cryptoki we implement. The revision is changed with + each modification of this file. If you do not use the "official" + version of this file, please consider deleting the revision macro + (you may use a macro with a different name to keep track of your + versions). */ +#define CRYPTOKI_VERSION_MAJOR 2 +#define CRYPTOKI_VERSION_MINOR 20 +#define CRYPTOKI_VERSION_REVISION 6 + + +/* Compatibility interface is default, unless CRYPTOKI_GNU is + given. */ +#ifndef CRYPTOKI_GNU +#ifndef CRYPTOKI_COMPAT +#define CRYPTOKI_COMPAT 1 +#endif +#endif + +/* System dependencies. */ + +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) + +/* There is a matching pop below. */ +#pragma pack(push, cryptoki, 1) + +#ifdef CRYPTOKI_EXPORTS +#define CK_SPEC __declspec(dllexport) +#else +#define CK_SPEC __declspec(dllimport) +#endif + +#else + +#define CK_SPEC + +#endif + + +#ifdef CRYPTOKI_COMPAT + /* If we are in compatibility mode, switch all exposed names to the + PKCS #11 variant. There are corresponding #undefs below. */ + +#define ck_flags_t CK_FLAGS +#define ck_version _CK_VERSION + +#define ck_info _CK_INFO +#define cryptoki_version cryptokiVersion +#define manufacturer_id manufacturerID +#define library_description libraryDescription +#define library_version libraryVersion + +#define ck_notification_t CK_NOTIFICATION +#define ck_slot_id_t CK_SLOT_ID + +#define ck_slot_info _CK_SLOT_INFO +#define slot_description slotDescription +#define hardware_version hardwareVersion +#define firmware_version firmwareVersion + +#define ck_token_info _CK_TOKEN_INFO +#define serial_number serialNumber +#define max_session_count ulMaxSessionCount +#define session_count ulSessionCount +#define max_rw_session_count ulMaxRwSessionCount +#define rw_session_count ulRwSessionCount +#define max_pin_len ulMaxPinLen +#define min_pin_len ulMinPinLen +#define total_public_memory ulTotalPublicMemory +#define free_public_memory ulFreePublicMemory +#define total_private_memory ulTotalPrivateMemory +#define free_private_memory ulFreePrivateMemory +#define utc_time utcTime + +#define ck_session_handle_t CK_SESSION_HANDLE +#define ck_user_type_t CK_USER_TYPE +#define ck_state_t CK_STATE + +#define ck_session_info _CK_SESSION_INFO +#define slot_id slotID +#define device_error ulDeviceError + +#define ck_object_handle_t CK_OBJECT_HANDLE +#define ck_object_class_t CK_OBJECT_CLASS +#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE +#define ck_key_type_t CK_KEY_TYPE +#define ck_certificate_type_t CK_CERTIFICATE_TYPE +#define ck_attribute_type_t CK_ATTRIBUTE_TYPE + +#define ck_attribute _CK_ATTRIBUTE +#define value pValue +#define value_len ulValueLen + +#define ck_date _CK_DATE + +#define ck_mechanism_type_t CK_MECHANISM_TYPE + +#define ck_mechanism _CK_MECHANISM +#define parameter pParameter +#define parameter_len ulParameterLen + +#define ck_mechanism_info _CK_MECHANISM_INFO +#define min_key_size ulMinKeySize +#define max_key_size ulMaxKeySize + +#define ck_rv_t CK_RV +#define ck_notify_t CK_NOTIFY + +#define ck_function_list _CK_FUNCTION_LIST + +#define ck_createmutex_t CK_CREATEMUTEX +#define ck_destroymutex_t CK_DESTROYMUTEX +#define ck_lockmutex_t CK_LOCKMUTEX +#define ck_unlockmutex_t CK_UNLOCKMUTEX + +#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS +#define create_mutex CreateMutex +#define destroy_mutex DestroyMutex +#define lock_mutex LockMutex +#define unlock_mutex UnlockMutex +#define reserved pReserved + +#endif /* CRYPTOKI_COMPAT */ + + + +typedef unsigned long ck_flags_t; + +struct ck_version +{ + unsigned char major; + unsigned char minor; +}; + + +struct ck_info +{ + struct ck_version cryptoki_version; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + unsigned char library_description[32]; + struct ck_version library_version; +}; + + +typedef unsigned long ck_notification_t; + +#define CKN_SURRENDER (0) + + +typedef unsigned long ck_slot_id_t; + + +struct ck_slot_info +{ + unsigned char slot_description[64]; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + struct ck_version hardware_version; + struct ck_version firmware_version; +}; + + +#define CKF_TOKEN_PRESENT (1 << 0) +#define CKF_REMOVABLE_DEVICE (1 << 1) +#define CKF_HW_SLOT (1 << 2) +#define CKF_ARRAY_ATTRIBUTE (1 << 30) + + +struct ck_token_info +{ + unsigned char label[32]; + unsigned char manufacturer_id[32]; + unsigned char model[16]; + unsigned char serial_number[16]; + ck_flags_t flags; + unsigned long max_session_count; + unsigned long session_count; + unsigned long max_rw_session_count; + unsigned long rw_session_count; + unsigned long max_pin_len; + unsigned long min_pin_len; + unsigned long total_public_memory; + unsigned long free_public_memory; + unsigned long total_private_memory; + unsigned long free_private_memory; + struct ck_version hardware_version; + struct ck_version firmware_version; + unsigned char utc_time[16]; +}; + + +#define CKF_RNG (1 << 0) +#define CKF_WRITE_PROTECTED (1 << 1) +#define CKF_LOGIN_REQUIRED (1 << 2) +#define CKF_USER_PIN_INITIALIZED (1 << 3) +#define CKF_RESTORE_KEY_NOT_NEEDED (1 << 5) +#define CKF_CLOCK_ON_TOKEN (1 << 6) +#define CKF_PROTECTED_AUTHENTICATION_PATH (1 << 8) +#define CKF_DUAL_CRYPTO_OPERATIONS (1 << 9) +#define CKF_TOKEN_INITIALIZED (1 << 10) +#define CKF_SECONDARY_AUTHENTICATION (1 << 11) +#define CKF_USER_PIN_COUNT_LOW (1 << 16) +#define CKF_USER_PIN_FINAL_TRY (1 << 17) +#define CKF_USER_PIN_LOCKED (1 << 18) +#define CKF_USER_PIN_TO_BE_CHANGED (1 << 19) +#define CKF_SO_PIN_COUNT_LOW (1 << 20) +#define CKF_SO_PIN_FINAL_TRY (1 << 21) +#define CKF_SO_PIN_LOCKED (1 << 22) +#define CKF_SO_PIN_TO_BE_CHANGED (1 << 23) + +#define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1) +#define CK_EFFECTIVELY_INFINITE (0) + + +typedef unsigned long ck_session_handle_t; + +#define CK_INVALID_HANDLE (0) + + +typedef unsigned long ck_user_type_t; + +#define CKU_SO (0) +#define CKU_USER (1) +#define CKU_CONTEXT_SPECIFIC (2) + + +typedef unsigned long ck_state_t; + +#define CKS_RO_PUBLIC_SESSION (0) +#define CKS_RO_USER_FUNCTIONS (1) +#define CKS_RW_PUBLIC_SESSION (2) +#define CKS_RW_USER_FUNCTIONS (3) +#define CKS_RW_SO_FUNCTIONS (4) + + +struct ck_session_info +{ + ck_slot_id_t slot_id; + ck_state_t state; + ck_flags_t flags; + unsigned long device_error; +}; + +#define CKF_RW_SESSION (1 << 1) +#define CKF_SERIAL_SESSION (1 << 2) + + +typedef unsigned long ck_object_handle_t; + + +typedef unsigned long ck_object_class_t; + +#define CKO_DATA (0) +#define CKO_CERTIFICATE (1) +#define CKO_PUBLIC_KEY (2) +#define CKO_PRIVATE_KEY (3) +#define CKO_SECRET_KEY (4) +#define CKO_HW_FEATURE (5) +#define CKO_DOMAIN_PARAMETERS (6) +#define CKO_MECHANISM (7) +#define CKO_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + +typedef unsigned long ck_hw_feature_type_t; + +#define CKH_MONOTONIC_COUNTER (1) +#define CKH_CLOCK (2) +#define CKH_USER_INTERFACE (3) +#define CKH_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + +typedef unsigned long ck_key_type_t; + +#define CKK_RSA (0) +#define CKK_DSA (1) +#define CKK_DH (2) +#define CKK_ECDSA (3) +#define CKK_EC (3) +#define CKK_X9_42_DH (4) +#define CKK_KEA (5) +#define CKK_GENERIC_SECRET (0x10) +#define CKK_RC2 (0x11) +#define CKK_RC4 (0x12) +#define CKK_DES (0x13) +#define CKK_DES2 (0x14) +#define CKK_DES3 (0x15) +#define CKK_CAST (0x16) +#define CKK_CAST3 (0x17) +#define CKK_CAST128 (0x18) +#define CKK_RC5 (0x19) +#define CKK_IDEA (0x1a) +#define CKK_SKIPJACK (0x1b) +#define CKK_BATON (0x1c) +#define CKK_JUNIPER (0x1d) +#define CKK_CDMF (0x1e) +#define CKK_AES (0x1f) +#define CKK_BLOWFISH (0x20) +#define CKK_TWOFISH (0x21) +#define CKK_VENDOR_DEFINED ((unsigned long) (1 << 31)) + +typedef unsigned long ck_certificate_type_t; + +#define CKC_X_509 (0) +#define CKC_X_509_ATTR_CERT (1) +#define CKC_WTLS (2) +#define CKC_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + +typedef unsigned long ck_attribute_type_t; + +#define CKA_CLASS (0) +#define CKA_TOKEN (1) +#define CKA_PRIVATE (2) +#define CKA_LABEL (3) +#define CKA_APPLICATION (0x10) +#define CKA_VALUE (0x11) +#define CKA_OBJECT_ID (0x12) +#define CKA_CERTIFICATE_TYPE (0x80) +#define CKA_ISSUER (0x81) +#define CKA_SERIAL_NUMBER (0x82) +#define CKA_AC_ISSUER (0x83) +#define CKA_OWNER (0x84) +#define CKA_ATTR_TYPES (0x85) +#define CKA_TRUSTED (0x86) +#define CKA_CERTIFICATE_CATEGORY (0x87) +#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88) +#define CKA_URL (0x89) +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a) +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8b) +#define CKA_CHECK_VALUE (0x90) +#define CKA_KEY_TYPE (0x100) +#define CKA_SUBJECT (0x101) +#define CKA_ID (0x102) +#define CKA_SENSITIVE (0x103) +#define CKA_ENCRYPT (0x104) +#define CKA_DECRYPT (0x105) +#define CKA_WRAP (0x106) +#define CKA_UNWRAP (0x107) +#define CKA_SIGN (0x108) +#define CKA_SIGN_RECOVER (0x109) +#define CKA_VERIFY (0x10a) +#define CKA_VERIFY_RECOVER (0x10b) +#define CKA_DERIVE (0x10c) +#define CKA_START_DATE (0x110) +#define CKA_END_DATE (0x111) +#define CKA_MODULUS (0x120) +#define CKA_MODULUS_BITS (0x121) +#define CKA_PUBLIC_EXPONENT (0x122) +#define CKA_PRIVATE_EXPONENT (0x123) +#define CKA_PRIME_1 (0x124) +#define CKA_PRIME_2 (0x125) +#define CKA_EXPONENT_1 (0x126) +#define CKA_EXPONENT_2 (0x127) +#define CKA_COEFFICIENT (0x128) +#define CKA_PRIME (0x130) +#define CKA_SUBPRIME (0x131) +#define CKA_BASE (0x132) +#define CKA_PRIME_BITS (0x133) +#define CKA_SUB_PRIME_BITS (0x134) +#define CKA_VALUE_BITS (0x160) +#define CKA_VALUE_LEN (0x161) +#define CKA_EXTRACTABLE (0x162) +#define CKA_LOCAL (0x163) +#define CKA_NEVER_EXTRACTABLE (0x164) +#define CKA_ALWAYS_SENSITIVE (0x165) +#define CKA_KEY_GEN_MECHANISM (0x166) +#define CKA_MODIFIABLE (0x170) +#define CKA_ECDSA_PARAMS (0x180) +#define CKA_EC_PARAMS (0x180) +#define CKA_EC_POINT (0x181) +#define CKA_SECONDARY_AUTH (0x200) +#define CKA_AUTH_PIN_FLAGS (0x201) +#define CKA_ALWAYS_AUTHENTICATE (0x202) +#define CKA_WRAP_WITH_TRUSTED (0x210) +#define CKA_HW_FEATURE_TYPE (0x300) +#define CKA_RESET_ON_INIT (0x301) +#define CKA_HAS_RESET (0x302) +#define CKA_PIXEL_X (0x400) +#define CKA_PIXEL_Y (0x401) +#define CKA_RESOLUTION (0x402) +#define CKA_CHAR_ROWS (0x403) +#define CKA_CHAR_COLUMNS (0x404) +#define CKA_COLOR (0x405) +#define CKA_BITS_PER_PIXEL (0x406) +#define CKA_CHAR_SETS (0x480) +#define CKA_ENCODING_METHODS (0x481) +#define CKA_MIME_TYPES (0x482) +#define CKA_MECHANISM_TYPE (0x500) +#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501) +#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502) +#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503) +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212) +#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600) +#define CKA_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + +struct ck_attribute +{ + ck_attribute_type_t type; + void *value; + unsigned long value_len; +}; + + +struct ck_date +{ + unsigned char year[4]; + unsigned char month[2]; + unsigned char day[2]; +}; + + +typedef unsigned long ck_mechanism_type_t; + +#define CKM_RSA_PKCS_KEY_PAIR_GEN (0) +#define CKM_RSA_PKCS (1) +#define CKM_RSA_9796 (2) +#define CKM_RSA_X_509 (3) +#define CKM_MD2_RSA_PKCS (4) +#define CKM_MD5_RSA_PKCS (5) +#define CKM_SHA1_RSA_PKCS (6) +#define CKM_RIPEMD128_RSA_PKCS (7) +#define CKM_RIPEMD160_RSA_PKCS (8) +#define CKM_RSA_PKCS_OAEP (9) +#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xa) +#define CKM_RSA_X9_31 (0xb) +#define CKM_SHA1_RSA_X9_31 (0xc) +#define CKM_RSA_PKCS_PSS (0xd) +#define CKM_SHA1_RSA_PKCS_PSS (0xe) +#define CKM_DSA_KEY_PAIR_GEN (0x10) +#define CKM_DSA (0x11) +#define CKM_DSA_SHA1 (0x12) +#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20) +#define CKM_DH_PKCS_DERIVE (0x21) +#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30) +#define CKM_X9_42_DH_DERIVE (0x31) +#define CKM_X9_42_DH_HYBRID_DERIVE (0x32) +#define CKM_X9_42_MQV_DERIVE (0x33) +#define CKM_SHA256_RSA_PKCS (0x40) +#define CKM_SHA384_RSA_PKCS (0x41) +#define CKM_SHA512_RSA_PKCS (0x42) +#define CKM_SHA256_RSA_PKCS_PSS (0x43) +#define CKM_SHA384_RSA_PKCS_PSS (0x44) +#define CKM_SHA512_RSA_PKCS_PSS (0x45) +#define CKM_RC2_KEY_GEN (0x100) +#define CKM_RC2_ECB (0x101) +#define CKM_RC2_CBC (0x102) +#define CKM_RC2_MAC (0x103) +#define CKM_RC2_MAC_GENERAL (0x104) +#define CKM_RC2_CBC_PAD (0x105) +#define CKM_RC4_KEY_GEN (0x110) +#define CKM_RC4 (0x111) +#define CKM_DES_KEY_GEN (0x120) +#define CKM_DES_ECB (0x121) +#define CKM_DES_CBC (0x122) +#define CKM_DES_MAC (0x123) +#define CKM_DES_MAC_GENERAL (0x124) +#define CKM_DES_CBC_PAD (0x125) +#define CKM_DES2_KEY_GEN (0x130) +#define CKM_DES3_KEY_GEN (0x131) +#define CKM_DES3_ECB (0x132) +#define CKM_DES3_CBC (0x133) +#define CKM_DES3_MAC (0x134) +#define CKM_DES3_MAC_GENERAL (0x135) +#define CKM_DES3_CBC_PAD (0x136) +#define CKM_CDMF_KEY_GEN (0x140) +#define CKM_CDMF_ECB (0x141) +#define CKM_CDMF_CBC (0x142) +#define CKM_CDMF_MAC (0x143) +#define CKM_CDMF_MAC_GENERAL (0x144) +#define CKM_CDMF_CBC_PAD (0x145) +#define CKM_MD2 (0x200) +#define CKM_MD2_HMAC (0x201) +#define CKM_MD2_HMAC_GENERAL (0x202) +#define CKM_MD5 (0x210) +#define CKM_MD5_HMAC (0x211) +#define CKM_MD5_HMAC_GENERAL (0x212) +#define CKM_SHA_1 (0x220) +#define CKM_SHA_1_HMAC (0x221) +#define CKM_SHA_1_HMAC_GENERAL (0x222) +#define CKM_RIPEMD128 (0x230) +#define CKM_RIPEMD128_HMAC (0x231) +#define CKM_RIPEMD128_HMAC_GENERAL (0x232) +#define CKM_RIPEMD160 (0x240) +#define CKM_RIPEMD160_HMAC (0x241) +#define CKM_RIPEMD160_HMAC_GENERAL (0x242) +#define CKM_SHA256 (0x250) +#define CKM_SHA256_HMAC (0x251) +#define CKM_SHA256_HMAC_GENERAL (0x252) +#define CKM_SHA384 (0x260) +#define CKM_SHA384_HMAC (0x261) +#define CKM_SHA384_HMAC_GENERAL (0x262) +#define CKM_SHA512 (0x270) +#define CKM_SHA512_HMAC (0x271) +#define CKM_SHA512_HMAC_GENERAL (0x272) +#define CKM_CAST_KEY_GEN (0x300) +#define CKM_CAST_ECB (0x301) +#define CKM_CAST_CBC (0x302) +#define CKM_CAST_MAC (0x303) +#define CKM_CAST_MAC_GENERAL (0x304) +#define CKM_CAST_CBC_PAD (0x305) +#define CKM_CAST3_KEY_GEN (0x310) +#define CKM_CAST3_ECB (0x311) +#define CKM_CAST3_CBC (0x312) +#define CKM_CAST3_MAC (0x313) +#define CKM_CAST3_MAC_GENERAL (0x314) +#define CKM_CAST3_CBC_PAD (0x315) +#define CKM_CAST5_KEY_GEN (0x320) +#define CKM_CAST128_KEY_GEN (0x320) +#define CKM_CAST5_ECB (0x321) +#define CKM_CAST128_ECB (0x321) +#define CKM_CAST5_CBC (0x322) +#define CKM_CAST128_CBC (0x322) +#define CKM_CAST5_MAC (0x323) +#define CKM_CAST128_MAC (0x323) +#define CKM_CAST5_MAC_GENERAL (0x324) +#define CKM_CAST128_MAC_GENERAL (0x324) +#define CKM_CAST5_CBC_PAD (0x325) +#define CKM_CAST128_CBC_PAD (0x325) +#define CKM_RC5_KEY_GEN (0x330) +#define CKM_RC5_ECB (0x331) +#define CKM_RC5_CBC (0x332) +#define CKM_RC5_MAC (0x333) +#define CKM_RC5_MAC_GENERAL (0x334) +#define CKM_RC5_CBC_PAD (0x335) +#define CKM_IDEA_KEY_GEN (0x340) +#define CKM_IDEA_ECB (0x341) +#define CKM_IDEA_CBC (0x342) +#define CKM_IDEA_MAC (0x343) +#define CKM_IDEA_MAC_GENERAL (0x344) +#define CKM_IDEA_CBC_PAD (0x345) +#define CKM_GENERIC_SECRET_KEY_GEN (0x350) +#define CKM_CONCATENATE_BASE_AND_KEY (0x360) +#define CKM_CONCATENATE_BASE_AND_DATA (0x362) +#define CKM_CONCATENATE_DATA_AND_BASE (0x363) +#define CKM_XOR_BASE_AND_DATA (0x364) +#define CKM_EXTRACT_KEY_FROM_KEY (0x365) +#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370) +#define CKM_SSL3_MASTER_KEY_DERIVE (0x371) +#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372) +#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373) +#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374) +#define CKM_TLS_MASTER_KEY_DERIVE (0x375) +#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376) +#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377) +#define CKM_SSL3_MD5_MAC (0x380) +#define CKM_SSL3_SHA1_MAC (0x381) +#define CKM_MD5_KEY_DERIVATION (0x390) +#define CKM_MD2_KEY_DERIVATION (0x391) +#define CKM_SHA1_KEY_DERIVATION (0x392) +#define CKM_PBE_MD2_DES_CBC (0x3a0) +#define CKM_PBE_MD5_DES_CBC (0x3a1) +#define CKM_PBE_MD5_CAST_CBC (0x3a2) +#define CKM_PBE_MD5_CAST3_CBC (0x3a3) +#define CKM_PBE_MD5_CAST5_CBC (0x3a4) +#define CKM_PBE_MD5_CAST128_CBC (0x3a4) +#define CKM_PBE_SHA1_CAST5_CBC (0x3a5) +#define CKM_PBE_SHA1_CAST128_CBC (0x3a5) +#define CKM_PBE_SHA1_RC4_128 (0x3a6) +#define CKM_PBE_SHA1_RC4_40 (0x3a7) +#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8) +#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9) +#define CKM_PBE_SHA1_RC2_128_CBC (0x3aa) +#define CKM_PBE_SHA1_RC2_40_CBC (0x3ab) +#define CKM_PKCS5_PBKD2 (0x3b0) +#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0) +#define CKM_KEY_WRAP_LYNKS (0x400) +#define CKM_KEY_WRAP_SET_OAEP (0x401) +#define CKM_SKIPJACK_KEY_GEN (0x1000) +#define CKM_SKIPJACK_ECB64 (0x1001) +#define CKM_SKIPJACK_CBC64 (0x1002) +#define CKM_SKIPJACK_OFB64 (0x1003) +#define CKM_SKIPJACK_CFB64 (0x1004) +#define CKM_SKIPJACK_CFB32 (0x1005) +#define CKM_SKIPJACK_CFB16 (0x1006) +#define CKM_SKIPJACK_CFB8 (0x1007) +#define CKM_SKIPJACK_WRAP (0x1008) +#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009) +#define CKM_SKIPJACK_RELAYX (0x100a) +#define CKM_KEA_KEY_PAIR_GEN (0x1010) +#define CKM_KEA_KEY_DERIVE (0x1011) +#define CKM_FORTEZZA_TIMESTAMP (0x1020) +#define CKM_BATON_KEY_GEN (0x1030) +#define CKM_BATON_ECB128 (0x1031) +#define CKM_BATON_ECB96 (0x1032) +#define CKM_BATON_CBC128 (0x1033) +#define CKM_BATON_COUNTER (0x1034) +#define CKM_BATON_SHUFFLE (0x1035) +#define CKM_BATON_WRAP (0x1036) +#define CKM_ECDSA_KEY_PAIR_GEN (0x1040) +#define CKM_EC_KEY_PAIR_GEN (0x1040) +#define CKM_ECDSA (0x1041) +#define CKM_ECDSA_SHA1 (0x1042) +#define CKM_ECDH1_DERIVE (0x1050) +#define CKM_ECDH1_COFACTOR_DERIVE (0x1051) +#define CKM_ECMQV_DERIVE (0x1052) +#define CKM_JUNIPER_KEY_GEN (0x1060) +#define CKM_JUNIPER_ECB128 (0x1061) +#define CKM_JUNIPER_CBC128 (0x1062) +#define CKM_JUNIPER_COUNTER (0x1063) +#define CKM_JUNIPER_SHUFFLE (0x1064) +#define CKM_JUNIPER_WRAP (0x1065) +#define CKM_FASTHASH (0x1070) +#define CKM_AES_KEY_GEN (0x1080) +#define CKM_AES_ECB (0x1081) +#define CKM_AES_CBC (0x1082) +#define CKM_AES_MAC (0x1083) +#define CKM_AES_MAC_GENERAL (0x1084) +#define CKM_AES_CBC_PAD (0x1085) +#define CKM_DSA_PARAMETER_GEN (0x2000) +#define CKM_DH_PKCS_PARAMETER_GEN (0x2001) +#define CKM_X9_42_DH_PARAMETER_GEN (0x2002) +#define CKM_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + +struct ck_mechanism +{ + ck_mechanism_type_t mechanism; + void *parameter; + unsigned long parameter_len; +}; + + +struct ck_mechanism_info +{ + unsigned long min_key_size; + unsigned long max_key_size; + ck_flags_t flags; +}; + +#define CKF_HW (1 << 0) +#define CKF_ENCRYPT (1 << 8) +#define CKF_DECRYPT (1 << 9) +#define CKF_DIGEST (1 << 10) +#define CKF_SIGN (1 << 11) +#define CKF_SIGN_RECOVER (1 << 12) +#define CKF_VERIFY (1 << 13) +#define CKF_VERIFY_RECOVER (1 << 14) +#define CKF_GENERATE (1 << 15) +#define CKF_GENERATE_KEY_PAIR (1 << 16) +#define CKF_WRAP (1 << 17) +#define CKF_UNWRAP (1 << 18) +#define CKF_DERIVE (1 << 19) +#define CKF_EXTENSION ((unsigned long) (1 << 31)) + + +/* Flags for C_WaitForSlotEvent. */ +#define CKF_DONT_BLOCK (1) + + +typedef unsigned long ck_rv_t; + + +typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session, + ck_notification_t event, void *application); + +/* Forward reference. */ +struct ck_function_list; + +#define _CK_DECLARE_FUNCTION(name, args) \ +typedef ck_rv_t (*CK_ ## name) args; \ +ck_rv_t CK_SPEC name args + +_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args)); +_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved)); +_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info)); +_CK_DECLARE_FUNCTION (C_GetFunctionList, + (struct ck_function_list **function_list)); + +_CK_DECLARE_FUNCTION (C_GetSlotList, + (unsigned char token_present, ck_slot_id_t *slot_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetSlotInfo, + (ck_slot_id_t slot_id, struct ck_slot_info *info)); +_CK_DECLARE_FUNCTION (C_GetTokenInfo, + (ck_slot_id_t slot_id, struct ck_token_info *info)); +_CK_DECLARE_FUNCTION (C_WaitForSlotEvent, + (ck_flags_t flags, ck_slot_id_t *slot, void *reserved)); +_CK_DECLARE_FUNCTION (C_GetMechanismList, + (ck_slot_id_t slot_id, + ck_mechanism_type_t *mechanism_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetMechanismInfo, + (ck_slot_id_t slot_id, ck_mechanism_type_t type, + struct ck_mechanism_info *info)); +_CK_DECLARE_FUNCTION (C_InitToken, + (ck_slot_id_t slot_id, unsigned char *pin, + unsigned long pin_len, unsigned char *label)); +_CK_DECLARE_FUNCTION (C_InitPIN, + (ck_session_handle_t session, unsigned char *pin, + unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_SetPIN, + (ck_session_handle_t session, unsigned char *old_pin, + unsigned long old_len, unsigned char *new_pin, + unsigned long new_len)); + +_CK_DECLARE_FUNCTION (C_OpenSession, + (ck_slot_id_t slot_id, ck_flags_t flags, + void *application, ck_notify_t notify, + ck_session_handle_t *session)); +_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id)); +_CK_DECLARE_FUNCTION (C_GetSessionInfo, + (ck_session_handle_t session, + struct ck_session_info *info)); +_CK_DECLARE_FUNCTION (C_GetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long *operation_state_len)); +_CK_DECLARE_FUNCTION (C_SetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long operation_state_len, + ck_object_handle_t encryption_key, + ck_object_handle_t authentiation_key)); +_CK_DECLARE_FUNCTION (C_Login, + (ck_session_handle_t session, ck_user_type_t user_type, + unsigned char *pin, unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_CreateObject, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count, ck_object_handle_t *object)); +_CK_DECLARE_FUNCTION (C_CopyObject, + (ck_session_handle_t session, ck_object_handle_t object, + struct ck_attribute *templ, unsigned long count, + ck_object_handle_t *new_object)); +_CK_DECLARE_FUNCTION (C_DestroyObject, + (ck_session_handle_t session, + ck_object_handle_t object)); +_CK_DECLARE_FUNCTION (C_GetObjectSize, + (ck_session_handle_t session, + ck_object_handle_t object, + unsigned long *size)); +_CK_DECLARE_FUNCTION (C_GetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_SetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjectsInit, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjects, + (ck_session_handle_t session, + ck_object_handle_t *object, + unsigned long max_object_count, + unsigned long *object_count)); +_CK_DECLARE_FUNCTION (C_FindObjectsFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_EncryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Encrypt, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *encrypted_data, + unsigned long *encrypted_data_len)); +_CK_DECLARE_FUNCTION (C_EncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_EncryptFinal, + (ck_session_handle_t session, + unsigned char *last_encrypted_part, + unsigned long *last_encrypted_part_len)); + +_CK_DECLARE_FUNCTION (C_DecryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Decrypt, + (ck_session_handle_t session, + unsigned char *encrypted_data, + unsigned long encrypted_data_len, + unsigned char *data, unsigned long *data_len)); +_CK_DECLARE_FUNCTION (C_DecryptUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_DecryptFinal, + (ck_session_handle_t session, + unsigned char *last_part, + unsigned long *last_part_len)); + +_CK_DECLARE_FUNCTION (C_DigestInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism)); +_CK_DECLARE_FUNCTION (C_Digest, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *digest, + unsigned long *digest_len)); +_CK_DECLARE_FUNCTION (C_DigestUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_DigestKey, + (ck_session_handle_t session, ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_DigestFinal, + (ck_session_handle_t session, + unsigned char *digest, + unsigned long *digest_len)); + +_CK_DECLARE_FUNCTION (C_SignInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Sign, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_SignFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_SignRecover, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); + +_CK_DECLARE_FUNCTION (C_VerifyInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Verify, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_VerifyFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_VerifyRecover, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len, + unsigned char *data, + unsigned long *data_len)); + +_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_SignEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); + +_CK_DECLARE_FUNCTION (C_GenerateKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *templ, + unsigned long count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_GenerateKeyPair, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *public_key_template, + unsigned long public_key_attribute_count, + struct ck_attribute *private_key_template, + unsigned long private_key_attribute_count, + ck_object_handle_t *public_key, + ck_object_handle_t *private_key)); +_CK_DECLARE_FUNCTION (C_WrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t wrapping_key, + ck_object_handle_t key, + unsigned char *wrapped_key, + unsigned long *wrapped_key_len)); +_CK_DECLARE_FUNCTION (C_UnwrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t unwrapping_key, + unsigned char *wrapped_key, + unsigned long wrapped_key_len, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_DeriveKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t base_key, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); + +_CK_DECLARE_FUNCTION (C_SeedRandom, + (ck_session_handle_t session, unsigned char *seed, + unsigned long seed_len)); +_CK_DECLARE_FUNCTION (C_GenerateRandom, + (ck_session_handle_t session, + unsigned char *random_data, + unsigned long random_len)); + +_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session)); + + +struct ck_function_list +{ + struct ck_version version; + CK_C_Initialize C_Initialize; + CK_C_Finalize C_Finalize; + CK_C_GetInfo C_GetInfo; + CK_C_GetFunctionList C_GetFunctionList; + CK_C_GetSlotList C_GetSlotList; + CK_C_GetSlotInfo C_GetSlotInfo; + CK_C_GetTokenInfo C_GetTokenInfo; + CK_C_GetMechanismList C_GetMechanismList; + CK_C_GetMechanismInfo C_GetMechanismInfo; + CK_C_InitToken C_InitToken; + CK_C_InitPIN C_InitPIN; + CK_C_SetPIN C_SetPIN; + CK_C_OpenSession C_OpenSession; + CK_C_CloseSession C_CloseSession; + CK_C_CloseAllSessions C_CloseAllSessions; + CK_C_GetSessionInfo C_GetSessionInfo; + CK_C_GetOperationState C_GetOperationState; + CK_C_SetOperationState C_SetOperationState; + CK_C_Login C_Login; + CK_C_Logout C_Logout; + CK_C_CreateObject C_CreateObject; + CK_C_CopyObject C_CopyObject; + CK_C_DestroyObject C_DestroyObject; + CK_C_GetObjectSize C_GetObjectSize; + CK_C_GetAttributeValue C_GetAttributeValue; + CK_C_SetAttributeValue C_SetAttributeValue; + CK_C_FindObjectsInit C_FindObjectsInit; + CK_C_FindObjects C_FindObjects; + CK_C_FindObjectsFinal C_FindObjectsFinal; + CK_C_EncryptInit C_EncryptInit; + CK_C_Encrypt C_Encrypt; + CK_C_EncryptUpdate C_EncryptUpdate; + CK_C_EncryptFinal C_EncryptFinal; + CK_C_DecryptInit C_DecryptInit; + CK_C_Decrypt C_Decrypt; + CK_C_DecryptUpdate C_DecryptUpdate; + CK_C_DecryptFinal C_DecryptFinal; + CK_C_DigestInit C_DigestInit; + CK_C_Digest C_Digest; + CK_C_DigestUpdate C_DigestUpdate; + CK_C_DigestKey C_DigestKey; + CK_C_DigestFinal C_DigestFinal; + CK_C_SignInit C_SignInit; + CK_C_Sign C_Sign; + CK_C_SignUpdate C_SignUpdate; + CK_C_SignFinal C_SignFinal; + CK_C_SignRecoverInit C_SignRecoverInit; + CK_C_SignRecover C_SignRecover; + CK_C_VerifyInit C_VerifyInit; + CK_C_Verify C_Verify; + CK_C_VerifyUpdate C_VerifyUpdate; + CK_C_VerifyFinal C_VerifyFinal; + CK_C_VerifyRecoverInit C_VerifyRecoverInit; + CK_C_VerifyRecover C_VerifyRecover; + CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; + CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; + CK_C_SignEncryptUpdate C_SignEncryptUpdate; + CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; + CK_C_GenerateKey C_GenerateKey; + CK_C_GenerateKeyPair C_GenerateKeyPair; + CK_C_WrapKey C_WrapKey; + CK_C_UnwrapKey C_UnwrapKey; + CK_C_DeriveKey C_DeriveKey; + CK_C_SeedRandom C_SeedRandom; + CK_C_GenerateRandom C_GenerateRandom; + CK_C_GetFunctionStatus C_GetFunctionStatus; + CK_C_CancelFunction C_CancelFunction; + CK_C_WaitForSlotEvent C_WaitForSlotEvent; +}; + + +typedef ck_rv_t (*ck_createmutex_t) (void **mutex); +typedef ck_rv_t (*ck_destroymutex_t) (void *mutex); +typedef ck_rv_t (*ck_lockmutex_t) (void *mutex); +typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex); + + +struct ck_c_initialize_args +{ + ck_createmutex_t create_mutex; + ck_destroymutex_t destroy_mutex; + ck_lockmutex_t lock_mutex; + ck_unlockmutex_t unlock_mutex; + ck_flags_t flags; + void *reserved; +}; + + +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1 << 0) +#define CKF_OS_LOCKING_OK (1 << 1) + +#define CKR_OK (0) +#define CKR_CANCEL (1) +#define CKR_HOST_MEMORY (2) +#define CKR_SLOT_ID_INVALID (3) +#define CKR_GENERAL_ERROR (5) +#define CKR_FUNCTION_FAILED (6) +#define CKR_ARGUMENTS_BAD (7) +#define CKR_NO_EVENT (8) +#define CKR_NEED_TO_CREATE_THREADS (9) +#define CKR_CANT_LOCK (0xa) +#define CKR_ATTRIBUTE_READ_ONLY (0x10) +#define CKR_ATTRIBUTE_SENSITIVE (0x11) +#define CKR_ATTRIBUTE_TYPE_INVALID (0x12) +#define CKR_ATTRIBUTE_VALUE_INVALID (0x13) +#define CKR_DATA_INVALID (0x20) +#define CKR_DATA_LEN_RANGE (0x21) +#define CKR_DEVICE_ERROR (0x30) +#define CKR_DEVICE_MEMORY (0x31) +#define CKR_DEVICE_REMOVED (0x32) +#define CKR_ENCRYPTED_DATA_INVALID (0x40) +#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41) +#define CKR_FUNCTION_CANCELED (0x50) +#define CKR_FUNCTION_NOT_PARALLEL (0x51) +#define CKR_FUNCTION_NOT_SUPPORTED (0x54) +#define CKR_KEY_HANDLE_INVALID (0x60) +#define CKR_KEY_SIZE_RANGE (0x62) +#define CKR_KEY_TYPE_INCONSISTENT (0x63) +#define CKR_KEY_NOT_NEEDED (0x64) +#define CKR_KEY_CHANGED (0x65) +#define CKR_KEY_NEEDED (0x66) +#define CKR_KEY_INDIGESTIBLE (0x67) +#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68) +#define CKR_KEY_NOT_WRAPPABLE (0x69) +#define CKR_KEY_UNEXTRACTABLE (0x6a) +#define CKR_MECHANISM_INVALID (0x70) +#define CKR_MECHANISM_PARAM_INVALID (0x71) +#define CKR_OBJECT_HANDLE_INVALID (0x82) +#define CKR_OPERATION_ACTIVE (0x90) +#define CKR_OPERATION_NOT_INITIALIZED (0x91) +#define CKR_PIN_INCORRECT (0xa0) +#define CKR_PIN_INVALID (0xa1) +#define CKR_PIN_LEN_RANGE (0xa2) +#define CKR_PIN_EXPIRED (0xa3) +#define CKR_PIN_LOCKED (0xa4) +#define CKR_SESSION_CLOSED (0xb0) +#define CKR_SESSION_COUNT (0xb1) +#define CKR_SESSION_HANDLE_INVALID (0xb3) +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4) +#define CKR_SESSION_READ_ONLY (0xb5) +#define CKR_SESSION_EXISTS (0xb6) +#define CKR_SESSION_READ_ONLY_EXISTS (0xb7) +#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8) +#define CKR_SIGNATURE_INVALID (0xc0) +#define CKR_SIGNATURE_LEN_RANGE (0xc1) +#define CKR_TEMPLATE_INCOMPLETE (0xd0) +#define CKR_TEMPLATE_INCONSISTENT (0xd1) +#define CKR_TOKEN_NOT_PRESENT (0xe0) +#define CKR_TOKEN_NOT_RECOGNIZED (0xe1) +#define CKR_TOKEN_WRITE_PROTECTED (0xe2) +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0) +#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1) +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2) +#define CKR_USER_ALREADY_LOGGED_IN (0x100) +#define CKR_USER_NOT_LOGGED_IN (0x101) +#define CKR_USER_PIN_NOT_INITIALIZED (0x102) +#define CKR_USER_TYPE_INVALID (0x103) +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104) +#define CKR_USER_TOO_MANY_TYPES (0x105) +#define CKR_WRAPPED_KEY_INVALID (0x110) +#define CKR_WRAPPED_KEY_LEN_RANGE (0x112) +#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113) +#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114) +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115) +#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120) +#define CKR_RANDOM_NO_RNG (0x121) +#define CKR_DOMAIN_PARAMS_INVALID (0x130) +#define CKR_BUFFER_TOO_SMALL (0x150) +#define CKR_SAVED_STATE_INVALID (0x160) +#define CKR_INFORMATION_SENSITIVE (0x170) +#define CKR_STATE_UNSAVEABLE (0x180) +#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190) +#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191) +#define CKR_MUTEX_BAD (0x1a0) +#define CKR_MUTEX_NOT_LOCKED (0x1a1) +#define CKR_FUNCTION_REJECTED (0x200) +#define CKR_VENDOR_DEFINED ((unsigned long) (1 << 31)) + + + +/* Compatibility layer. */ + +#ifdef CRYPTOKI_COMPAT + +#undef CK_DEFINE_FUNCTION +#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name + +/* For NULL. */ +#include + +typedef unsigned char CK_BYTE; +typedef unsigned char CK_CHAR; +typedef unsigned char CK_UTF8CHAR; +typedef unsigned char CK_BBOOL; +typedef unsigned long int CK_ULONG; +typedef long int CK_LONG; +typedef CK_BYTE *CK_BYTE_PTR; +typedef CK_CHAR *CK_CHAR_PTR; +typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR; +typedef CK_ULONG *CK_ULONG_PTR; +typedef void *CK_VOID_PTR; +typedef void **CK_VOID_PTR_PTR; +#define CK_FALSE 0 +#define CK_TRUE 1 +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#endif + +typedef struct ck_version CK_VERSION; +typedef struct ck_version *CK_VERSION_PTR; + +typedef struct ck_info CK_INFO; +typedef struct ck_info *CK_INFO_PTR; + +typedef ck_slot_id_t *CK_SLOT_ID_PTR; + +typedef struct ck_slot_info CK_SLOT_INFO; +typedef struct ck_slot_info *CK_SLOT_INFO_PTR; + +typedef struct ck_token_info CK_TOKEN_INFO; +typedef struct ck_token_info *CK_TOKEN_INFO_PTR; + +typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR; + +typedef struct ck_session_info CK_SESSION_INFO; +typedef struct ck_session_info *CK_SESSION_INFO_PTR; + +typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR; + +typedef ck_object_class_t *CK_OBJECT_CLASS_PTR; + +typedef struct ck_attribute CK_ATTRIBUTE; +typedef struct ck_attribute *CK_ATTRIBUTE_PTR; + +typedef struct ck_date CK_DATE; +typedef struct ck_date *CK_DATE_PTR; + +typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; + +typedef struct ck_mechanism CK_MECHANISM; +typedef struct ck_mechanism *CK_MECHANISM_PTR; + +typedef struct ck_mechanism_info CK_MECHANISM_INFO; +typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; + +typedef struct ck_function_list CK_FUNCTION_LIST; +typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; +typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; + +typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; +typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; + +#define NULL_PTR NULL + +/* Delete the helper macros defined at the top of the file. */ +#undef ck_flags_t +#undef ck_version + +#undef ck_info +#undef cryptoki_version +#undef manufacturer_id +#undef library_description +#undef library_version + +#undef ck_notification_t +#undef ck_slot_id_t + +#undef ck_slot_info +#undef slot_description +#undef hardware_version +#undef firmware_version + +#undef ck_token_info +#undef serial_number +#undef max_session_count +#undef session_count +#undef max_rw_session_count +#undef rw_session_count +#undef max_pin_len +#undef min_pin_len +#undef total_public_memory +#undef free_public_memory +#undef total_private_memory +#undef free_private_memory +#undef utc_time + +#undef ck_session_handle_t +#undef ck_user_type_t +#undef ck_state_t + +#undef ck_session_info +#undef slot_id +#undef device_error + +#undef ck_object_handle_t +#undef ck_object_class_t +#undef ck_hw_feature_type_t +#undef ck_key_type_t +#undef ck_certificate_type_t +#undef ck_attribute_type_t + +#undef ck_attribute +#undef value +#undef value_len + +#undef ck_date + +#undef ck_mechanism_type_t + +#undef ck_mechanism +#undef parameter +#undef parameter_len + +#undef ck_mechanism_info +#undef min_key_size +#undef max_key_size + +#undef ck_rv_t +#undef ck_notify_t + +#undef ck_function_list + +#undef ck_createmutex_t +#undef ck_destroymutex_t +#undef ck_lockmutex_t +#undef ck_unlockmutex_t + +#undef ck_c_initialize_args +#undef create_mutex +#undef destroy_mutex +#undef lock_mutex +#undef unlock_mutex +#undef reserved + +#endif /* CRYPTOKI_COMPAT */ + + +/* System dependencies. */ +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) +#pragma pack(pop, cryptoki) +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* PKCS11_H */ diff --git a/crypto/openssh/platform.c b/crypto/openssh/platform.c index aee4b01e7..e3a428aaa 100644 --- a/crypto/openssh/platform.c +++ b/crypto/openssh/platform.c @@ -1,4 +1,4 @@ -/* $Id: platform.c,v 1.1 2006/08/30 17:24:41 djm Exp $ */ +/* $Id: platform.c,v 1.3 2009/12/20 23:49:22 dtucker Exp $ */ /* * Copyright (c) 2006 Darren Tucker. All rights reserved. @@ -21,6 +21,15 @@ #include "openbsd-compat/openbsd-compat.h" +void +platform_pre_listen(void) +{ +#ifdef LINUX_OOM_ADJUST + /* Adjust out-of-memory killer so listening process is not killed */ + oom_adjust_setup(); +#endif +} + void platform_pre_fork(void) { @@ -43,4 +52,17 @@ platform_post_fork_child(void) #ifdef USE_SOLARIS_PROCESS_CONTRACTS solaris_contract_post_fork_child(); #endif +#ifdef LINUX_OOM_ADJUST + oom_adjust_restore(); +#endif +} + +char * +platform_krb5_get_principal_name(const char *pw_name) +{ +#ifdef USE_AIX_KRB_NAME + return aix_krb5_get_principal_name(pw_name); +#else + return NULL; +#endif } diff --git a/crypto/openssh/platform.h b/crypto/openssh/platform.h index cf93bc57c..30a1d2259 100644 --- a/crypto/openssh/platform.h +++ b/crypto/openssh/platform.h @@ -1,4 +1,4 @@ -/* $Id: platform.h,v 1.1 2006/08/30 17:24:41 djm Exp $ */ +/* $Id: platform.h,v 1.4 2010/01/14 01:44:16 djm Exp $ */ /* * Copyright (c) 2006 Darren Tucker. All rights reserved. @@ -18,6 +18,11 @@ #include +void platform_pre_listen(void); void platform_pre_fork(void); void platform_post_fork_parent(pid_t child_pid); void platform_post_fork_child(void); +char *platform_get_krb5_client(const char *); +char *platform_krb5_get_principal_name(const char *); + + diff --git a/crypto/openssh/readconf.c b/crypto/openssh/readconf.c index 8b810a1fc..6c4bb3453 100644 --- a/crypto/openssh/readconf.c +++ b/crypto/openssh/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.176 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.183 2010/02/08 10:50:20 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -126,14 +126,14 @@ typedef enum { oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, - oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, + oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, - oVisualHostKey, oZeroKnowledgePasswordAuthentication, + oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication, oVersionAddendum, oDeprecated, oUnsupported } OpCodes; @@ -209,10 +209,12 @@ static struct { { "preferredauthentications", oPreferredAuthentications }, { "hostkeyalgorithms", oHostKeyAlgorithms }, { "bindaddress", oBindAddress }, -#ifdef SMARTCARD - { "smartcarddevice", oSmartcardDevice }, +#ifdef ENABLE_PKCS11 + { "smartcarddevice", oPKCS11Provider }, + { "pkcs11provider", oPKCS11Provider }, #else { "smartcarddevice", oUnsupported }, + { "pkcs11provider", oUnsupported }, #endif { "clearallforwardings", oClearAllForwardings }, { "enablesshkeysign", oEnableSSHKeysign }, @@ -232,6 +234,7 @@ static struct { { "localcommand", oLocalCommand }, { "permitlocalcommand", oPermitLocalCommand }, { "visualhostkey", oVisualHostKey }, + { "useroaming", oUseRoaming }, #ifdef JPAKE { "zeroknowledgepasswordauthentication", oZeroKnowledgePasswordAuthentication }, @@ -625,8 +628,8 @@ parse_string: charptr = &options->bind_address; goto parse_string; - case oSmartcardDevice: - charptr = &options->smartcard_device; + case oPKCS11Provider: + charptr = &options->pkcs11_provider; goto parse_string; case oProxyCommand: @@ -931,6 +934,10 @@ parse_int: 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 { @@ -1070,7 +1077,7 @@ initialize_options(Options * options) options->log_level = SYSLOG_LEVEL_NOT_SET; options->preferred_authentications = NULL; options->bind_address = NULL; - options->smartcard_device = NULL; + options->pkcs11_provider = NULL; options->enable_ssh_keysign = - 1; options->no_host_authentication_for_localhost = - 1; options->identities_only = - 1; @@ -1087,6 +1094,7 @@ initialize_options(Options * options) 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; } @@ -1160,7 +1168,7 @@ fill_default_options(Options * options) /* 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; + options->protocol = SSH_PROTO_2; if (options->num_identity_files == 0) { if (options->protocol & SSH_PROTO_1) { len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; @@ -1223,6 +1231,8 @@ fill_default_options(Options * options) options->tun_remote = SSH_TUNID_ANY; if (options->permit_local_command == -1) options->permit_local_command = 0; + if (options->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) diff --git a/crypto/openssh/readconf.h b/crypto/openssh/readconf.h index 8fb3a8528..4264751c5 100644 --- a/crypto/openssh/readconf.h +++ b/crypto/openssh/readconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.h,v 1.78 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: readconf.h,v 1.82 2010/02/08 10:50:20 markus Exp $ */ /* * Author: Tatu Ylonen @@ -84,7 +84,7 @@ typedef struct { char *user_hostfile2; char *preferred_authentications; char *bind_address; /* local socket address for connection to sshd */ - char *smartcard_device; /* Smartcard reader device */ + char *pkcs11_provider; /* PKCS#11 provider */ int verify_host_key_dns; /* Verify host key using DNS */ int num_identity_files; /* Number of files for RSA/DSA identities. */ @@ -123,6 +123,8 @@ typedef struct { int permit_local_command; int visual_host_key; + int use_roaming; + } Options; #define SSHCTL_MASTER_NO 0 diff --git a/crypto/openssh/roaming.h b/crypto/openssh/roaming.h new file mode 100644 index 000000000..6bb94cc39 --- /dev/null +++ b/crypto/openssh/roaming.h @@ -0,0 +1,44 @@ +/* $OpenBSD: roaming.h,v 1.5 2009/10/24 11:11:58 andreas Exp $ */ +/* + * Copyright (c) 2004-2009 AppGate Network Security AB + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ROAMING_H +#define ROAMING_H + +#define DEFAULT_ROAMBUF 65536 +#define ROAMING_REQUEST "roaming@appgate.com" + +extern int roaming_enabled; +extern int resume_in_progress; + +void request_roaming(void); +int get_snd_buf_size(void); +int get_recv_buf_size(void); +void add_recv_bytes(u_int64_t); +int wait_for_roaming_reconnect(void); +void roaming_reply(int, u_int32_t, void *); +void set_out_buffer_size(size_t); +ssize_t roaming_write(int, const void *, size_t, int *); +ssize_t roaming_read(int, void *, size_t, int *); +size_t roaming_atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); +u_int64_t get_recv_bytes(void); +u_int64_t get_sent_bytes(void); +void roam_set_bytes(u_int64_t, u_int64_t); +void resend_bytes(int, u_int64_t *); +void calculate_new_key(u_int64_t *, u_int64_t, u_int64_t); +int resume_kex(void); + +#endif /* ROAMING */ diff --git a/crypto/openssh/roaming_client.c b/crypto/openssh/roaming_client.c new file mode 100644 index 000000000..cea8e7360 --- /dev/null +++ b/crypto/openssh/roaming_client.c @@ -0,0 +1,280 @@ +/* $OpenBSD: roaming_client.c,v 1.3 2010/01/18 01:50:27 dtucker Exp $ */ +/* + * Copyright (c) 2004-2009 AppGate Network Security AB + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include "openbsd-compat/sys-queue.h" +#include +#include + +#ifdef HAVE_INTTYPES_H +#include +#endif +#include +#include +#include + +#include +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "channels.h" +#include "cipher.h" +#include "dispatch.h" +#include "clientloop.h" +#include "log.h" +#include "match.h" +#include "misc.h" +#include "packet.h" +#include "ssh.h" +#include "key.h" +#include "kex.h" +#include "readconf.h" +#include "roaming.h" +#include "ssh2.h" +#include "sshconnect.h" + +/* import */ +extern Options options; +extern char *host; +extern struct sockaddr_storage hostaddr; +extern int session_resumed; + +static u_int32_t roaming_id; +static u_int64_t cookie; +static u_int64_t lastseenchall; +static u_int64_t key1, key2, oldkey1, oldkey2; + +void +roaming_reply(int type, u_int32_t seq, void *ctxt) +{ + if (type == SSH2_MSG_REQUEST_FAILURE) { + logit("Server denied roaming"); + return; + } + verbose("Roaming enabled"); + roaming_id = packet_get_int(); + cookie = packet_get_int64(); + key1 = oldkey1 = packet_get_int64(); + key2 = oldkey2 = packet_get_int64(); + set_out_buffer_size(packet_get_int() + get_snd_buf_size()); + roaming_enabled = 1; +} + +void +request_roaming(void) +{ + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring(ROAMING_REQUEST); + packet_put_char(1); + packet_put_int(get_recv_buf_size()); + packet_send(); + client_register_global_confirm(roaming_reply, NULL); +} + +static void +roaming_auth_required(void) +{ + u_char digest[SHA_DIGEST_LENGTH]; + EVP_MD_CTX md; + Buffer b; + const EVP_MD *evp_md = EVP_sha1(); + u_int64_t chall, oldchall; + + chall = packet_get_int64(); + oldchall = packet_get_int64(); + if (oldchall != lastseenchall) { + key1 = oldkey1; + key2 = oldkey2; + } + lastseenchall = chall; + + buffer_init(&b); + buffer_put_int64(&b, cookie); + buffer_put_int64(&b, chall); + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + buffer_free(&b); + + packet_start(SSH2_MSG_KEX_ROAMING_AUTH); + packet_put_int64(key1 ^ get_recv_bytes()); + packet_put_raw(digest, sizeof(digest)); + packet_send(); + + oldkey1 = key1; + oldkey2 = key2; + calculate_new_key(&key1, cookie, chall); + calculate_new_key(&key2, cookie, chall); + + debug("Received %llu bytes", (unsigned long long)get_recv_bytes()); + debug("Sent roaming_auth packet"); +} + +int +resume_kex(void) +{ + /* + * This should not happen - if the client sends the kex method + * resume@appgate.com then the kex is done in roaming_resume(). + */ + return 1; +} + +static int +roaming_resume(void) +{ + u_int64_t recv_bytes; + char *str = NULL, *kexlist = NULL, *c; + int i, type; + int timeout_ms = options.connection_timeout * 1000; + u_int len; + u_int32_t rnd = 0; + + resume_in_progress = 1; + + /* Exchange banners */ + ssh_exchange_identification(timeout_ms); + packet_set_nonblocking(); + + /* Send a kexinit message with resume@appgate.com as only kex algo */ + packet_start(SSH2_MSG_KEXINIT); + for (i = 0; i < KEX_COOKIE_LEN; i++) { + if (i % 4 == 0) + rnd = arc4random(); + packet_put_char(rnd & 0xff); + rnd >>= 8; + } + packet_put_cstring(KEX_RESUME); + for (i = 1; i < PROPOSAL_MAX; i++) { + /* kex algorithm added so start with i=1 and not 0 */ + packet_put_cstring(""); /* Not used when we resume */ + } + packet_put_char(1); /* first kex_packet follows */ + packet_put_int(0); /* reserved */ + packet_send(); + + /* Assume that resume@appgate.com will be accepted */ + packet_start(SSH2_MSG_KEX_ROAMING_RESUME); + packet_put_int(roaming_id); + packet_send(); + + /* Read the server's kexinit and check for resume@appgate.com */ + if ((type = packet_read()) != SSH2_MSG_KEXINIT) { + debug("expected kexinit on resume, got %d", type); + goto fail; + } + for (i = 0; i < KEX_COOKIE_LEN; i++) + (void)packet_get_char(); + kexlist = packet_get_string(&len); + if (!kexlist + || (str = match_list(KEX_RESUME, kexlist, NULL)) == NULL) { + debug("server doesn't allow resume"); + goto fail; + } + xfree(str); + for (i = 1; i < PROPOSAL_MAX; i++) { + /* kex algorithm taken care of so start with i=1 and not 0 */ + xfree(packet_get_string(&len)); + } + i = packet_get_char(); /* first_kex_packet_follows */ + if (i && (c = strchr(kexlist, ','))) + *c = 0; + if (i && strcmp(kexlist, KEX_RESUME)) { + debug("server's kex guess (%s) was wrong, skipping", kexlist); + (void)packet_read(); /* Wrong guess - discard packet */ + } + + /* + * Read the ROAMING_AUTH_REQUIRED challenge from the server and + * send ROAMING_AUTH + */ + if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED) { + debug("expected roaming_auth_required, got %d", type); + goto fail; + } + roaming_auth_required(); + + /* Read ROAMING_AUTH_OK from the server */ + if ((type = packet_read()) != SSH2_MSG_KEX_ROAMING_AUTH_OK) { + debug("expected roaming_auth_ok, got %d", type); + goto fail; + } + recv_bytes = packet_get_int64() ^ oldkey2; + debug("Peer received %llu bytes", (unsigned long long)recv_bytes); + resend_bytes(packet_get_connection_out(), &recv_bytes); + + resume_in_progress = 0; + + session_resumed = 1; /* Tell clientloop */ + + return 0; + +fail: + if (kexlist) + xfree(kexlist); + if (packet_get_connection_in() == packet_get_connection_out()) + close(packet_get_connection_in()); + else { + close(packet_get_connection_in()); + close(packet_get_connection_out()); + } + return 1; +} + +int +wait_for_roaming_reconnect(void) +{ + static int reenter_guard = 0; + int timeout_ms = options.connection_timeout * 1000; + int c; + + if (reenter_guard != 0) + fatal("Server refused resume, roaming timeout may be exceeded"); + reenter_guard = 1; + + fprintf(stderr, "[connection suspended, press return to resume]"); + fflush(stderr); + packet_backup_state(); + /* TODO Perhaps we should read from tty here */ + while ((c = fgetc(stdin)) != EOF) { + if (c == 'Z' - 64) { + kill(getpid(), SIGTSTP); + continue; + } + if (c != '\n' && c != '\r') + continue; + + if (ssh_connect(host, &hostaddr, options.port, + options.address_family, 1, &timeout_ms, + options.tcp_keep_alive, options.use_privileged_port, + options.proxy_command) == 0 && roaming_resume() == 0) { + packet_restore_state(); + reenter_guard = 0; + fprintf(stderr, "[connection resumed]\n"); + fflush(stderr); + return 0; + } + + fprintf(stderr, "[reconnect failed, press return to retry]"); + fflush(stderr); + } + fprintf(stderr, "[exiting]\n"); + fflush(stderr); + exit(0); +} diff --git a/crypto/openssh/roaming_common.c b/crypto/openssh/roaming_common.c new file mode 100644 index 000000000..9adbe56fc --- /dev/null +++ b/crypto/openssh/roaming_common.c @@ -0,0 +1,244 @@ +/* $OpenBSD: roaming_common.c,v 1.8 2010/01/12 00:59:29 djm Exp $ */ +/* + * Copyright (c) 2004-2009 AppGate Network Security AB + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include +#include +#include + +#include +#ifdef HAVE_INTTYPES_H +#include +#endif +#include +#include +#include + +#include "atomicio.h" +#include "log.h" +#include "packet.h" +#include "xmalloc.h" +#include "cipher.h" +#include "buffer.h" +#include "roaming.h" + +static size_t out_buf_size = 0; +static char *out_buf = NULL; +static size_t out_start; +static size_t out_last; + +static u_int64_t write_bytes = 0; +static u_int64_t read_bytes = 0; + +int roaming_enabled = 0; +int resume_in_progress = 0; + +int +get_snd_buf_size() +{ + int fd = packet_get_connection_out(); + int optval; + socklen_t optvallen = sizeof(optval); + + if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optvallen) != 0) + optval = DEFAULT_ROAMBUF; + return optval; +} + +int +get_recv_buf_size() +{ + int fd = packet_get_connection_in(); + int optval; + socklen_t optvallen = sizeof(optval); + + if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, &optvallen) != 0) + optval = DEFAULT_ROAMBUF; + return optval; +} + +void +set_out_buffer_size(size_t size) +{ + /* + * The buffer size can only be set once and the buffer will live + * as long as the session lives. + */ + if (out_buf == NULL) { + out_buf_size = size; + out_buf = xmalloc(size); + out_start = 0; + out_last = 0; + } +} + +u_int64_t +get_recv_bytes(void) +{ + return read_bytes; +} + +void +add_recv_bytes(u_int64_t num) +{ + read_bytes += num; +} + +u_int64_t +get_sent_bytes(void) +{ + return write_bytes; +} + +void +roam_set_bytes(u_int64_t sent, u_int64_t recvd) +{ + read_bytes = recvd; + write_bytes = sent; +} + +static void +buf_append(const char *buf, size_t count) +{ + if (count > out_buf_size) { + buf += count - out_buf_size; + count = out_buf_size; + } + if (count < out_buf_size - out_last) { + memcpy(out_buf + out_last, buf, count); + if (out_start > out_last) + out_start += count; + out_last += count; + } else { + /* data will wrap */ + size_t chunk = out_buf_size - out_last; + memcpy(out_buf + out_last, buf, chunk); + memcpy(out_buf, buf + chunk, count - chunk); + out_last = count - chunk; + out_start = out_last + 1; + } +} + +ssize_t +roaming_write(int fd, const void *buf, size_t count, int *cont) +{ + ssize_t ret; + + ret = write(fd, buf, count); + if (ret > 0 && !resume_in_progress) { + write_bytes += ret; + if (out_buf_size > 0) + buf_append(buf, ret); + } + if (out_buf_size > 0 && + (ret == 0 || (ret == -1 && errno == EPIPE))) { + if (wait_for_roaming_reconnect() != 0) { + ret = 0; + *cont = 1; + } else { + ret = -1; + errno = EAGAIN; + } + } + return ret; +} + +ssize_t +roaming_read(int fd, void *buf, size_t count, int *cont) +{ + ssize_t ret = read(fd, buf, count); + if (ret > 0) { + if (!resume_in_progress) { + read_bytes += ret; + } + } else if (out_buf_size > 0 && + (ret == 0 || (ret == -1 && (errno == ECONNRESET + || errno == ECONNABORTED || errno == ETIMEDOUT + || errno == EHOSTUNREACH)))) { + debug("roaming_read failed for %d ret=%ld errno=%d", + fd, (long)ret, errno); + ret = 0; + if (wait_for_roaming_reconnect() == 0) + *cont = 1; + } + return ret; +} + +size_t +roaming_atomicio(ssize_t(*f)(int, void*, size_t), int fd, void *buf, + size_t count) +{ + size_t ret = atomicio(f, fd, buf, count); + + if (f == vwrite && ret > 0 && !resume_in_progress) { + write_bytes += ret; + } else if (f == read && ret > 0 && !resume_in_progress) { + read_bytes += ret; + } + return ret; +} + +void +resend_bytes(int fd, u_int64_t *offset) +{ + size_t available, needed; + + if (out_start < out_last) + available = out_last - out_start; + else + available = out_buf_size; + needed = write_bytes - *offset; + debug3("resend_bytes: resend %lu bytes from %llu", + (unsigned long)needed, (unsigned long long)*offset); + if (needed > available) + fatal("Needed to resend more data than in the cache"); + if (out_last < needed) { + int chunkend = needed - out_last; + atomicio(vwrite, fd, out_buf + out_buf_size - chunkend, + chunkend); + atomicio(vwrite, fd, out_buf, out_last); + } else { + atomicio(vwrite, fd, out_buf + (out_last - needed), needed); + } +} + +/* + * Caclulate a new key after a reconnect + */ +void +calculate_new_key(u_int64_t *key, u_int64_t cookie, u_int64_t challenge) +{ + const EVP_MD *md = EVP_sha1(); + EVP_MD_CTX ctx; + char hash[EVP_MAX_MD_SIZE]; + Buffer b; + + buffer_init(&b); + buffer_put_int64(&b, *key); + buffer_put_int64(&b, cookie); + buffer_put_int64(&b, challenge); + + EVP_DigestInit(&ctx, md); + EVP_DigestUpdate(&ctx, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&ctx, hash, NULL); + + buffer_clear(&b); + buffer_append(&b, hash, EVP_MD_size(md)); + *key = buffer_get_int64(&b); + buffer_free(&b); +} diff --git a/crypto/openssh/roaming_dummy.c b/crypto/openssh/roaming_dummy.c new file mode 100644 index 000000000..45c4008e7 --- /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 +#include + +#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/roaming_serv.c b/crypto/openssh/roaming_serv.c new file mode 100644 index 000000000..511ca8461 --- /dev/null +++ b/crypto/openssh/roaming_serv.c @@ -0,0 +1,31 @@ +/* $OpenBSD: roaming_serv.c,v 1.1 2009/10/24 11:18:23 andreas Exp $ */ +/* + * Copyright (c) 2004-2009 AppGate Network Security AB + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include + +#include "roaming.h" + +/* + * Wait for the roaming client to reconnect. Returns 0 if a connect ocurred. + */ +int +wait_for_roaming_reconnect(void) +{ + return 1; +} diff --git a/crypto/openssh/scard-opensc.c b/crypto/openssh/scard-opensc.c deleted file mode 100644 index 36dae05fd..000000000 --- a/crypto/openssh/scard-opensc.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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 - -#include -#include - -#include -#include - -#include -#include - -#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 -#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 deleted file mode 100644 index 9fd3ca1b4..000000000 --- a/crypto/openssh/scard.c +++ /dev/null @@ -1,571 +0,0 @@ -/* $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 - -#include -#include -#include - -#include - -#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 -#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 deleted file mode 100644 index 82efe4839..000000000 --- a/crypto/openssh/scard.h +++ /dev/null @@ -1,39 +0,0 @@ -/* $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 index 61ba68a73..daeec0627 100644 --- a/crypto/openssh/schnorr.c +++ b/crypto/openssh/schnorr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: schnorr.c,v 1.2 2009/02/18 04:31:21 djm Exp $ */ +/* $OpenBSD: schnorr.c,v 1.3 2009/03/05 07:18:19 djm Exp $ */ /* $FreeBSD$ */ /* * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -41,38 +41,36 @@ #include "buffer.h" #include "log.h" -#include "jpake.h" +#include "schnorr.h" #ifdef JPAKE +#include "openbsd-compat/openssl-compat.h" + /* #define SCHNORR_DEBUG */ /* Privacy-violating debugging */ /* #define SCHNORR_MAIN */ /* Include main() selftest */ -/* XXX */ -/* Parametise signature hash? (sha256, sha1, etc.) */ -/* Signature format - include type name, hash type, group params? */ - #ifndef SCHNORR_DEBUG # define SCHNORR_DEBUG_BN(a) # define SCHNORR_DEBUG_BUF(a) #else -# define SCHNORR_DEBUG_BN(a) jpake_debug3_bn a -# define SCHNORR_DEBUG_BUF(a) jpake_debug3_buf a +# 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 SHA1. Returns signature as bignum or NULL on error. + * 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 BIGNUM *g_v, const BIGNUM *g_x, + 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; - EVP_MD_CTX evp_md_ctx; Buffer b; int success = -1; @@ -82,7 +80,6 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, } buffer_init(&b); - EVP_MD_CTX_init(&evp_md_ctx); /* h = H(g || p || q || g^v || g^x || id) */ buffer_put_bignum2(&b, g); @@ -94,7 +91,7 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), "%s: hashblob", __func__)); - if (hash_buffer(buffer_ptr(&b), buffer_len(&b), EVP_sha256(), + if (hash_buffer(buffer_ptr(&b), buffer_len(&b), evp_md, &digest, &digest_len) != 0) { error("%s: hash_buffer", __func__); goto out; @@ -107,7 +104,6 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, SCHNORR_DEBUG_BN((h, "%s: h = ", __func__)); out: buffer_free(&b); - EVP_MD_CTX_cleanup(&evp_md_ctx); bzero(digest, digest_len); xfree(digest); digest_len = 0; @@ -120,18 +116,20 @@ schnorr_hash(const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, /* * 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 and *siglen bytes of signature are returned in - * *sig (caller to free). Returns -1 on failure. + * + * 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 BIGNUM *x, const BIGNUM *g_x, const u_char *id, u_int idlen, - u_char **sig, u_int *siglen) + 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; - Buffer b; BIGNUM *h, *tmp, *v, *g_v, *r; BN_CTX *bn_ctx; @@ -174,7 +172,7 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, 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, g_v, g_x, + 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; @@ -189,12 +187,49 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, 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__)); - /* Signature is (g_v, r) */ + *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, g_v); + buffer_put_bignum2(&b, e); buffer_put_bignum2(&b, r); *siglen = buffer_len(&b); *sig = xmalloc(*siglen); @@ -202,36 +237,28 @@ schnorr_sign(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, SCHNORR_DEBUG_BUF((buffer_ptr(&b), buffer_len(&b), "%s: sigblob", __func__)); buffer_free(&b); - 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(r); - BN_clear_free(g_v); - BN_clear_free(tmp); + BN_clear_free(e); - return success; + return 0; } /* - * 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'. + * 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 BIGNUM *g_x, const u_char *id, u_int idlen, - const u_char *sig, u_int siglen) + 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; - Buffer b; - BIGNUM *g_v, *h, *r, *g_xh, *g_r, *expected; + BIGNUM *h, *g_xh, *g_r, *expected; BN_CTX *bn_ctx; - u_int rlen; SCHNORR_DEBUG_BN((g_x, "%s: g_x = ", __func__)); @@ -241,39 +268,23 @@ schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, return -1; } - g_v = h = r = g_xh = g_r = expected = NULL; + h = g_xh = g_r = expected = 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 || - (g_xh = BN_new()) == NULL || + if ((g_xh = BN_new()) == NULL || (g_r = BN_new()) == NULL || (expected = 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, g_v); - 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; - } - buffer_free(&b); - SCHNORR_DEBUG_BN((g_v, "%s: g_v = ", __func__)); + 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, g_v, g_x, + 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; @@ -300,20 +311,248 @@ schnorr_verify(const BIGNUM *grp_p, const BIGNUM *grp_q, const BIGNUM *grp_g, } SCHNORR_DEBUG_BN((expected, "%s: expected = ", __func__)); - /* Check g_v == expected */ - success = BN_cmp(expected, g_v) == 0; + /* 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_v); - BN_clear_free(r); 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, @@ -331,16 +570,17 @@ schnorr_selftest_one(const BIGNUM *grp_p, const BIGNUM *grp_q, if (BN_mod_exp(g_x, grp_g, x, grp_p, bn_ctx) == -1) fatal("%s: g_x", __func__); - if (schnorr_sign(grp_p, grp_q, grp_g, x, g_x, "junk", 4, &sig, &siglen)) + 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(grp_p, grp_q, grp_g, g_x, "junk", 4, + 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(grp_p, grp_q, grp_g, g_x, "JUNK", 4, + 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(grp_p, grp_q, grp_g, g_x, "junk", 4, + 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); @@ -352,7 +592,7 @@ static void schnorr_selftest(void) { BIGNUM *x; - struct jpake_group *grp; + struct modp_group *grp; u_int i; char *hh; diff --git a/crypto/openssh/schnorr.h b/crypto/openssh/schnorr.h new file mode 100644 index 000000000..9730b47ce --- /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 + +#include + +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 index 611beeaef..615520bb3 100644 --- a/crypto/openssh/scp.1 +++ b/crypto/openssh/scp.1 @@ -9,9 +9,9 @@ .\" .\" Created: Sun May 7 00:14:37 1995 ylo .\" -.\" $OpenBSD: scp.1,v 1.46 2008/07/12 05:33:41 djm Exp $ +.\" $OpenBSD: scp.1,v 1.50 2010/02/08 10:50:20 markus Exp $ .\" -.Dd July 12 2008 +.Dd February 8 2010 .Dt SCP 1 .Os .Sh NAME @@ -153,6 +153,7 @@ For full details of the options listed below, and their possible values, see .It NoHostAuthenticationForLocalhost .It NumberOfPasswordPrompts .It PasswordAuthentication +.It PKCS11Provider .It Port .It PreferredAuthentications .It Protocol @@ -164,7 +165,6 @@ For full details of the options listed below, and their possible values, see .It SendEnv .It ServerAliveInterval .It ServerAliveCountMax -.It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive .It UsePrivilegedPort diff --git a/crypto/openssh/scp.c b/crypto/openssh/scp.c index 323747806..09efb82ac 100644 --- a/crypto/openssh/scp.c +++ b/crypto/openssh/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.164 2008/10/10 04:55:16 stevesk Exp $ */ +/* $OpenBSD: scp.c,v 1.165 2009/12/20 07:28:36 guenther Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -244,8 +244,11 @@ do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) close(pout[1]); replacearg(&args, 0, "%s", ssh_program); - if (remuser != NULL) - addargs(&args, "-l%s", remuser); + if (remuser != NULL) { + addargs(&args, "-l"); + addargs(&args, "%s", remuser); + } + addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", cmd); @@ -337,10 +340,12 @@ main(int argc, char **argv) case 'c': case 'i': case 'F': - addargs(&args, "-%c%s", ch, optarg); + addargs(&args, "-%c", ch); + addargs(&args, "%s", optarg); break; case 'P': - addargs(&args, "-p%s", optarg); + addargs(&args, "-p"); + addargs(&args, "%s", optarg); break; case 'B': addargs(&args, "-oBatchmode yes"); @@ -548,6 +553,7 @@ toremote(char *targ, int argc, char **argv) } else { host = cleanhostname(argv[i]); } + addargs(&alist, "--"); addargs(&alist, "%s", host); addargs(&alist, "%s", cmd); addargs(&alist, "%s", src); @@ -558,7 +564,7 @@ toremote(char *targ, int argc, char **argv) errs = 1; } else { /* local to remote */ if (remin == -1) { - xasprintf(&bp, "%s -t %s", cmd, targ); + xasprintf(&bp, "%s -t -- %s", cmd, targ); host = cleanhostname(thost); if (do_cmd(host, tuser, bp, &remin, &remout) < 0) @@ -591,6 +597,7 @@ tolocal(int argc, char **argv) addargs(&alist, "-r"); if (pflag) addargs(&alist, "-p"); + addargs(&alist, "--"); addargs(&alist, "%s", argv[i]); addargs(&alist, "%s", argv[argc-1]); if (do_local_cmd(&alist)) @@ -610,7 +617,7 @@ tolocal(int argc, char **argv) suser = pwd->pw_name; } host = cleanhostname(host); - xasprintf(&bp, "%s -f %s", cmd, src); + xasprintf(&bp, "%s -f -- %s", cmd, src); if (do_cmd(host, suser, bp, &remin, &remout) < 0) { (void) xfree(bp); ++errs; diff --git a/crypto/openssh/servconf.c b/crypto/openssh/servconf.c index 4744688c4..603c5865f 100644 --- a/crypto/openssh/servconf.c +++ b/crypto/openssh/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.194 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.204 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -42,6 +42,7 @@ __RCSID("$FreeBSD$"); #include "match.h" #include "channels.h" #include "groupaccess.h" +#include "version.h" static void add_listen_addr(ServerOptions *, char *, int); static void add_one_listen_addr(ServerOptions *, char *, int); @@ -66,6 +67,7 @@ initialize_server_options(ServerOptions *options) options->listen_addrs = NULL; options->address_family = -1; options->num_host_key_files = 0; + options->num_host_cert_files = 0; options->pid_file = NULL; options->server_key_bits = -1; options->login_grace_time = -1; @@ -129,6 +131,8 @@ initialize_server_options(ServerOptions *options) options->adm_forced_command = NULL; options->chroot_directory = NULL; options->zero_knowledge_password_authentication = -1; + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; } void @@ -153,6 +157,7 @@ fill_default_server_options(ServerOptions *options) _PATH_HOST_DSA_KEY_FILE; } } + /* No certificates by default */ if (options->num_ports == 0) options->ports[options->num_ports++] = SSH_DEFAULT_PORT; if (options->listen_addrs == NULL) @@ -306,7 +311,8 @@ typedef enum { sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, - sZeroKnowledgePasswordAuthentication, + sZeroKnowledgePasswordAuthentication, sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sVersionAddendum, sDeprecated, sUnsupported } ServerOpCodes; @@ -345,7 +351,7 @@ static struct { { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_GLOBAL }, { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL }, { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, - { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ + { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ #ifdef KRB5 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, { "kerberosorlocalpasswd", sKerberosOrLocalPasswd, SSHCFG_GLOBAL }, @@ -419,13 +425,16 @@ static struct { { "clientalivecountmax", sClientAliveCountMax, SSHCFG_GLOBAL }, { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_GLOBAL }, { "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL }, - { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL }, + { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL}, { "acceptenv", sAcceptEnv, SSHCFG_GLOBAL }, { "permittunnel", sPermitTunnel, SSHCFG_GLOBAL }, - { "match", sMatch, SSHCFG_ALL }, + { "match", sMatch, SSHCFG_ALL }, { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, + { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { NULL, sBadOption, 0 } }; @@ -462,6 +471,22 @@ parse_token(const char *cp, const char *filename, return sBadOption; } +char * +derelativise_path(const char *path) +{ + char *expanded, *ret, *cwd; + + expanded = tilde_expand_filename(path, getuid()); + if (*expanded == '/') + return expanded; + if ((cwd = getcwd(NULL, 0)) == NULL) + fatal("%s: getcwd: %s", __func__, strerror(errno)); + xasprintf(&ret, "%s/%s", cwd, expanded); + xfree(cwd); + xfree(expanded); + return ret; +} + static void add_listen_addr(ServerOptions *options, char *addr, int port) { @@ -796,13 +821,23 @@ process_server_config_line(ServerOptions *options, char *line, fatal("%s line %d: missing file name.", filename, linenum); if (*activep && *charptr == NULL) { - *charptr = tilde_expand_filename(arg, getuid()); + *charptr = derelativise_path(arg); /* increase optional counter */ if (intptr != NULL) *intptr = *intptr + 1; } break; + case sHostCertificate: + intptr = &options->num_host_cert_files; + if (*intptr >= MAX_HOSTKEYS) + fatal("%s line %d: too many host certificates " + "specified (max %d).", filename, linenum, + MAX_HOSTCERTS); + charptr = &options->host_cert_files[*intptr]; + goto parse_filename; + break; + case sPidFile: charptr = &options->pid_file; goto parse_filename; @@ -1297,6 +1332,14 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; + case sTrustedUserCAKeys: + charptr = &options->trusted_user_ca_keys; + goto parse_filename; + + case sRevokedKeys: + charptr = &options->revoked_keys_file; + goto parse_filename; + case sVersionAddendum: ssh_version_set_addendum(strtok(cp, "\n")); do { @@ -1386,7 +1429,7 @@ parse_server_match_config(ServerOptions *options, const char *user, /* * Copy any supported values that are set. * - * If the preauth flag is set, we do not bother copying the the string or + * 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(). */ @@ -1418,6 +1461,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) return; M_CP_STROPT(adm_forced_command); M_CP_STROPT(chroot_directory); + M_CP_STROPT(trusted_user_ca_keys); + M_CP_STROPT(revoked_keys_file); } #undef M_CP_INTOPT @@ -1636,6 +1681,9 @@ dump_config(ServerOptions *o) dump_cfg_string(sAuthorizedKeysFile, o->authorized_keys_file); dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); dump_cfg_string(sForceCommand, o->adm_forced_command); + dump_cfg_string(sChrootDirectory, o->chroot_directory); + dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); + dump_cfg_string(sRevokedKeys, o->revoked_keys_file); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); @@ -1644,6 +1692,8 @@ dump_config(ServerOptions *o) /* string array arguments */ dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, o->host_key_files); + dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files, + o->host_cert_files); dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); dump_cfg_strarray(sAllowGroups, o->num_allow_groups, o->allow_groups); diff --git a/crypto/openssh/servconf.h b/crypto/openssh/servconf.h index b3ac7da4b..860009f9c 100644 --- a/crypto/openssh/servconf.h +++ b/crypto/openssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.87 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen @@ -24,6 +24,7 @@ #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ #define MAX_HOSTKEYS 256 /* Max # hostkeys. */ +#define MAX_HOSTCERTS 256 /* Max # host certificates. */ #define MAX_ACCEPT_ENV 256 /* Max # of env vars. */ #define MAX_MATCH_GROUPS 256 /* Max # of groups for Match. */ @@ -49,6 +50,8 @@ typedef struct { int address_family; /* Address family used by the server. */ char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ int num_host_key_files; /* Number of files for host keys. */ + char *host_cert_files[MAX_HOSTCERTS]; /* Files containing host certs. */ + int num_host_cert_files; /* Number of files for host certs. */ char *pid_file; /* Where to put our pid */ int server_key_bits;/* Size of the server key. */ int login_grace_time; /* Disconnect if no auth in this time @@ -151,6 +154,8 @@ typedef struct { int num_permitted_opens; char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; } ServerOptions; void initialize_server_options(ServerOptions *); @@ -164,5 +169,6 @@ void parse_server_match_config(ServerOptions *, const char *, const char *, const char *); void copy_set_server_options(ServerOptions *, ServerOptions *, int); void dump_config(ServerOptions *); +char *derelativise_path(const char *); #endif /* SERVCONF_H */ diff --git a/crypto/openssh/serverloop.c b/crypto/openssh/serverloop.c index 81cafe6ad..8be01c5c3 100644 --- a/crypto/openssh/serverloop.c +++ b/crypto/openssh/serverloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: serverloop.c,v 1.157 2009/02/12 03:16:01 djm Exp $ */ +/* $OpenBSD: serverloop.c,v 1.159 2009/05/28 16:50:16 andreas Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -78,6 +78,7 @@ #include "auth-options.h" #include "serverloop.h" #include "misc.h" +#include "roaming.h" extern ServerOptions options; @@ -249,7 +250,7 @@ client_alive_check(void) int channel_id; /* timeout, check to see how many we have had */ - if (++keep_alive_timeouts > options.client_alive_count_max) { + if (packet_inc_alive_timeouts() > options.client_alive_count_max) { logit("Timeout, client not responding."); cleanup_exit(255); } @@ -391,8 +392,11 @@ process_input(fd_set *readset) /* Read and buffer any input data from the client. */ if (FD_ISSET(connection_in, readset)) { - len = read(connection_in, buf, sizeof(buf)); + 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; @@ -890,7 +894,7 @@ server_input_keep_alive(int type, u_int32_t seq, void *ctxt) * even if this was generated by something other than * the bogus CHANNEL_REQUEST we send for keepalives. */ - keep_alive_timeouts = 0; + packet_set_alive_timeouts(0); } static void @@ -1120,7 +1124,8 @@ server_input_global_request(int type, u_int32_t seq, void *ctxt) no_port_forwarding_flag || (!want_reply && listen_port == 0) #ifndef NO_IPPORT_RESERVED_CONCEPT - || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) + || (listen_port != 0 && listen_port < IPPORT_RESERVED && + pw->pw_uid != 0) #endif ) { success = 0; diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c index 16cc4aef3..aad0979e7 100644 --- a/crypto/openssh/session.c +++ b/crypto/openssh/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.245 2009/01/22 09:46:01 djm Exp $ */ +/* $OpenBSD: session.c,v 1.252 2010/03/07 11:57:13 dtucker Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -143,9 +143,10 @@ static int sessions_first_unused = -1; static int sessions_nalloc = 0; static Session *sessions = NULL; -#define SUBSYSTEM_NONE 0 -#define SUBSYSTEM_EXT 1 -#define SUBSYSTEM_INT_SFTP 2 +#define SUBSYSTEM_NONE 0 +#define SUBSYSTEM_EXT 1 +#define SUBSYSTEM_INT_SFTP 2 +#define SUBSYSTEM_INT_SFTP_ERROR 3 #ifdef HAVE_LOGIN_CAP login_cap_t *lc; @@ -271,6 +272,8 @@ do_authenticated(Authctxt *authctxt) if (!no_port_forwarding_flag && options.allow_tcp_forwarding) channel_permit_all_opens(); + auth_debug_send(); + if (compat20) do_authenticated2(authctxt); else @@ -572,8 +575,7 @@ do_exec_no_pty(Session *s, const char *command) signal(WJSIGNAL, cray_job_termination_handler); #endif /* _UNICOS */ #ifdef HAVE_CYGWIN - if (is_winnt) - cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); + cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); #endif s->pid = pid; @@ -717,8 +719,8 @@ do_exec_pty(Session *s, const char *command) * Do common processing for the child, such as execing * the command. */ - do_child(s, command); - /* NOTREACHED */ + do_child(s, command); + /* NOTREACHED */ default: break; } @@ -727,8 +729,7 @@ do_exec_pty(Session *s, const char *command) signal(WJSIGNAL, cray_job_termination_handler); #endif /* _UNICOS */ #ifdef HAVE_CYGWIN - if (is_winnt) - cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); + cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); #endif s->pid = pid; @@ -788,17 +789,19 @@ do_exec(Session *s, const char *command) 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) + if (IS_INTERNAL_SFTP(command)) { + s->is_subsystem = s->is_subsystem ? + SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; + } else if (s->is_subsystem) s->is_subsystem = SUBSYSTEM_EXT; debug("Forced command (config) '%.900s'", command); } else if (forced_command) { original_command = command; command = forced_command; - if (IS_INTERNAL_SFTP(command)) - s->is_subsystem = SUBSYSTEM_INT_SFTP; - else if (s->is_subsystem) + if (IS_INTERNAL_SFTP(command)) { + s->is_subsystem = s->is_subsystem ? + SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR; + } else if (s->is_subsystem) s->is_subsystem = SUBSYSTEM_EXT; debug("Forced command (key option) '%.900s'", command); } @@ -848,7 +851,7 @@ do_login(Session *s, const char *command) fromlen = sizeof(from); if (packet_connection_is_on_socket()) { if (getpeername(packet_get_connection_in(), - (struct sockaddr *) & from, &fromlen) < 0) { + (struct sockaddr *)&from, &fromlen) < 0) { debug("getpeername: %.100s", strerror(errno)); cleanup_exit(255); } @@ -1135,7 +1138,7 @@ do_setup_env(Session *s, const char *shell) u_int i, envsize; char **env, *laddr; struct passwd *pw = s->pw; -#ifndef HAVE_LOGIN_CAP +#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) char *path = NULL; #else extern char **environ; @@ -1406,26 +1409,32 @@ static void do_nologin(struct passwd *pw) { FILE *f = NULL; - char buf[1024]; + char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; + struct stat sb; #ifdef HAVE_LOGIN_CAP - if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) - f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, - _PATH_NOLOGIN), "r"); + if (login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) + return; + nl = login_getcapstr(lc, "nologin", def_nl, def_nl); #else - if (pw->pw_uid) - f = fopen(_PATH_NOLOGIN, "r"); + if (pw->pw_uid == 0) + return; + nl = def_nl; #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); + if (stat(nl, &sb) == -1) { + if (nl != def_nl) + xfree(nl); + return; } + + /* /etc/nologin exists. Print its contents if we can and exit. */ + logit("User %.100s not allowed because %s exists", pw->pw_name, nl); + if ((f = fopen(nl, "r")) != NULL) { + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stderr); + fclose(f); + } + exit(254); } /* @@ -1498,11 +1507,6 @@ do_setusercontext(struct passwd *pw) if (getuid() == 0 || geteuid() == 0) #endif /* HAVE_CYGWIN */ { - -#ifdef HAVE_SETPCRED - if (setpcred(pw->pw_name, (char **)NULL) == -1) - fatal("Failed to set process credentials"); -#endif /* HAVE_SETPCRED */ #ifdef HAVE_LOGIN_CAP # ifdef __bsdi__ setpgid(0, 0); @@ -1558,6 +1562,24 @@ do_setusercontext(struct passwd *pw) } # endif /* USE_LIBIAF */ #endif +#ifdef HAVE_SETPCRED + /* + * If we have a chroot directory, we set all creds except real + * uid which we will need for chroot. If we don't have a + * chroot directory, we don't override anything. + */ + { + char **creds = NULL, *chroot_creds[] = + { "REAL_USER=root", NULL }; + + if (options.chroot_directory != NULL && + strcasecmp(options.chroot_directory, "none") != 0) + creds = chroot_creds; + + if (setpcred(pw->pw_name, creds) == -1) + fatal("Failed to set process credentials"); + } +#endif /* HAVE_SETPCRED */ if (options.chroot_directory != NULL && strcasecmp(options.chroot_directory, "none") != 0) { @@ -1581,9 +1603,6 @@ do_setusercontext(struct passwd *pw) #endif } -#ifdef HAVE_CYGWIN - if (is_winnt) -#endif if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); @@ -1819,12 +1838,16 @@ do_child(Session *s, const char *command) /* restore SIGPIPE for child */ signal(SIGPIPE, SIG_DFL); - if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { + if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) { + printf("This service allows sftp connections only.\n"); + fflush(NULL); + exit(1); + } else if (s->is_subsystem == SUBSYSTEM_INT_SFTP) { extern int optind, optreset; int i; char *p, *args; - setproctitle("%s@internal-sftp-server", s->pw->pw_name); + 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) @@ -1832,9 +1855,14 @@ do_child(Session *s, const char *command) argv[i] = NULL; optind = optreset = 1; __progname = argv[0]; +#ifdef WITH_SELINUX + ssh_selinux_change_context("sftpd_t"); +#endif exit(sftp_server_main(i, argv, s->pw)); } + fflush(NULL); + if (options.use_login) { launch_login(pw, hostname); /* NEVERREACHED */ @@ -2145,16 +2173,16 @@ session_subsystem_req(Session *s) if (strcmp(subsys, options.subsystem_name[i]) == 0) { prog = options.subsystem_command[i]; cmd = options.subsystem_args[i]; - if (!strcmp(INTERNAL_SFTP_NAME, prog)) { + if (strcmp(INTERNAL_SFTP_NAME, prog) == 0) { s->is_subsystem = SUBSYSTEM_INT_SFTP; - } else if (stat(prog, &st) < 0) { - error("subsystem: cannot stat %s: %s", prog, - strerror(errno)); - break; + debug("subsystem: %s", prog); } else { + if (stat(prog, &st) < 0) + debug("subsystem: cannot stat %s: %s", + prog, strerror(errno)); s->is_subsystem = SUBSYSTEM_EXT; + debug("subsystem: exec() %s", cmd); } - debug("subsystem: exec() %s", cmd); success = do_exec(s, cmd) == 0; break; } diff --git a/crypto/openssh/sftp-client.c b/crypto/openssh/sftp-client.c index 5e39aa7d2..6124c0f40 100644 --- a/crypto/openssh/sftp-client.c +++ b/crypto/openssh/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.86 2008/06/26 06:10:09 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.90 2009/10/11 10:41:26 dtucker Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -36,6 +36,7 @@ #endif #include +#include #include #include #include @@ -61,6 +62,9 @@ extern int showprogress; /* Minimum amount of data to read at a time */ #define MIN_READ_SIZE 512 +/* Maximum depth to descend in directory trees */ +#define MAX_DIR_DEPTH 64 + struct sftp_conn { int fd_in; int fd_out; @@ -74,6 +78,10 @@ struct sftp_conn { u_int exts; }; +static char * +get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) + __attribute__((format(printf, 4, 5))); + static void send_msg(int fd, Buffer *m) { @@ -179,11 +187,18 @@ get_status(int fd, u_int expected_id) } static char * -get_handle(int fd, u_int expected_id, u_int *len) +get_handle(int fd, u_int expected_id, u_int *len, const char *errfmt, ...) { Buffer msg; u_int type, id; - char *handle; + char *handle, errmsg[256]; + va_list args; + int status; + + va_start(args, errfmt); + if (errfmt != NULL) + vsnprintf(errmsg, sizeof(errmsg), errfmt, args); + va_end(args); buffer_init(&msg); get_msg(fd, &msg); @@ -191,16 +206,17 @@ get_handle(int fd, u_int expected_id, u_int *len) id = buffer_get_int(&msg); if (id != expected_id) - fatal("ID mismatch (%u != %u)", id, expected_id); + fatal("%s: ID mismatch (%u != %u)", + errfmt == NULL ? __func__ : errmsg, id, expected_id); if (type == SSH2_FXP_STATUS) { - int status = buffer_get_int(&msg); - - error("Couldn't get handle: %s", fx2txt(status)); + status = buffer_get_int(&msg); + if (errfmt != NULL) + error("%s: %s", errmsg, fx2txt(status)); buffer_free(&msg); return(NULL); } else if (type != SSH2_FXP_HANDLE) - fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", - SSH2_FXP_HANDLE, type); + fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", + errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); handle = buffer_get_string(&msg, len); buffer_free(&msg); @@ -418,7 +434,8 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, buffer_clear(&msg); - handle = get_handle(conn->fd_in, id, &handle_len); + handle = get_handle(conn->fd_in, id, &handle_len, + "remote readdir(\"%s\")", path); if (handle == NULL) return(-1); @@ -484,6 +501,17 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, if (printflag) printf("%s\n", longname); + /* + * Directory entries should never contain '/' + * These can be used to attack recursive ops + * (e.g. send '../../../../etc/passwd') + */ + if (strchr(filename, '/') != NULL) { + error("Server sent suspect path \"%s\" " + "during readdir of \"%s\"", filename, path); + goto next; + } + if (dir) { *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); (*dir)[ents] = xmalloc(sizeof(***dir)); @@ -492,7 +520,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, memcpy(&(*dir)[ents]->a, a, sizeof(*a)); (*dir)[++ents] = NULL; } - + next: xfree(filename); xfree(longname); } @@ -547,7 +575,7 @@ do_rm(struct sftp_conn *conn, char *path) } int -do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) +do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) { u_int status, id; @@ -556,7 +584,7 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) strlen(path), a); status = get_status(conn->fd_in, id); - if (status != SSH2_FX_OK) + if (status != SSH2_FX_OK && printflag) error("Couldn't create directory: %s", fx2txt(status)); return(status); @@ -895,9 +923,9 @@ send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, int do_download(struct sftp_conn *conn, char *remote_path, char *local_path, - int pflag) + Attrib *a, int pflag) { - Attrib junk, *a; + Attrib junk; Buffer msg; char *handle; int local_fd, status = 0, write_error; @@ -916,9 +944,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, TAILQ_INIT(&requests); - a = do_stat(conn, remote_path, 0); - if (a == NULL) - return(-1); + if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) + return -1; /* Do not preserve set[ug]id here, as we do not preserve ownership */ if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) @@ -951,7 +978,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 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); + handle = get_handle(conn->fd_in, id, &handle_len, + "remote open(\"%s\")", remote_path); if (handle == NULL) { buffer_free(&msg); return(-1); @@ -1132,6 +1160,114 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, return(status); } +static int +download_dir_internal(struct sftp_conn *conn, char *src, char *dst, + Attrib *dirattrib, int pflag, int printflag, int depth) +{ + int i, ret = 0; + SFTP_DIRENT **dir_entries; + char *filename, *new_src, *new_dst; + mode_t mode = 0777; + + if (depth >= MAX_DIR_DEPTH) { + error("Maximum directory depth exceeded: %d levels", depth); + return -1; + } + + if (dirattrib == NULL && + (dirattrib = do_stat(conn, src, 1)) == NULL) { + error("Unable to stat remote directory \"%s\"", src); + return -1; + } + if (!S_ISDIR(dirattrib->perm)) { + error("\"%s\" is not a directory", src); + return -1; + } + if (printflag) + printf("Retrieving %s\n", src); + + if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + mode = dirattrib->perm & 01777; + else { + debug("Server did not send permissions for " + "directory \"%s\"", dst); + } + + if (mkdir(dst, mode) == -1 && errno != EEXIST) { + error("mkdir %s: %s", dst, strerror(errno)); + return -1; + } + + if (do_readdir(conn, src, &dir_entries) == -1) { + error("%s: Failed to get directory contents", src); + return -1; + } + + for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { + filename = dir_entries[i]->filename; + + new_dst = path_append(dst, filename); + new_src = path_append(src, filename); + + if (S_ISDIR(dir_entries[i]->a.perm)) { + if (strcmp(filename, ".") == 0 || + strcmp(filename, "..") == 0) + continue; + if (download_dir_internal(conn, new_src, new_dst, + &(dir_entries[i]->a), pflag, printflag, + depth + 1) == -1) + ret = -1; + } else if (S_ISREG(dir_entries[i]->a.perm) ) { + if (do_download(conn, new_src, new_dst, + &(dir_entries[i]->a), pflag) == -1) { + error("Download of file %s to %s failed", + new_src, new_dst); + ret = -1; + } + } else + logit("%s: not a regular file\n", new_src); + + xfree(new_dst); + xfree(new_src); + } + + if (pflag) { + if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + struct timeval tv[2]; + tv[0].tv_sec = dirattrib->atime; + tv[1].tv_sec = dirattrib->mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(dst, tv) == -1) + error("Can't set times on \"%s\": %s", + dst, strerror(errno)); + } else + debug("Server did not send times for directory " + "\"%s\"", dst); + } + + free_sftp_dirents(dir_entries); + + return ret; +} + +int +download_dir(struct sftp_conn *conn, char *src, char *dst, + Attrib *dirattrib, int pflag, int printflag) +{ + char *src_canon; + int ret; + + if ((src_canon = do_realpath(conn, src)) == NULL) { + error("Unable to canonicalise path \"%s\"", src); + return -1; + } + + ret = download_dir_internal(conn, src_canon, dst, + dirattrib, pflag, printflag, 0); + xfree(src_canon); + return ret; +} + int do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, int pflag) @@ -1195,7 +1331,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, buffer_clear(&msg); - handle = get_handle(conn->fd_in, id, &handle_len); + handle = get_handle(conn->fd_in, id, &handle_len, + "remote open(\"%s\")", remote_path); if (handle == NULL) { close(local_fd); buffer_free(&msg); @@ -1313,3 +1450,127 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, return status; } + +static int +upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, + int pflag, int printflag, int depth) +{ + int ret = 0, status; + DIR *dirp; + struct dirent *dp; + char *filename, *new_src, *new_dst; + struct stat sb; + Attrib a; + + if (depth >= MAX_DIR_DEPTH) { + error("Maximum directory depth exceeded: %d levels", depth); + return -1; + } + + if (stat(src, &sb) == -1) { + error("Couldn't stat directory \"%s\": %s", + src, strerror(errno)); + return -1; + } + if (!S_ISDIR(sb.st_mode)) { + error("\"%s\" is not a directory", src); + return -1; + } + if (printflag) + printf("Entering %s\n", src); + + attrib_clear(&a); + stat_to_attrib(&sb, &a); + a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; + a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; + a.perm &= 01777; + if (!pflag) + a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; + + status = do_mkdir(conn, dst, &a, 0); + /* + * we lack a portable status for errno EEXIST, + * so if we get a SSH2_FX_FAILURE back we must check + * if it was created successfully. + */ + if (status != SSH2_FX_OK) { + if (status != SSH2_FX_FAILURE) + return -1; + if (do_stat(conn, dst, 0) == NULL) + return -1; + } + + if ((dirp = opendir(src)) == NULL) { + error("Failed to open dir \"%s\": %s", src, strerror(errno)); + return -1; + } + + while (((dp = readdir(dirp)) != NULL) && !interrupted) { + if (dp->d_ino == 0) + continue; + filename = dp->d_name; + new_dst = path_append(dst, filename); + new_src = path_append(src, filename); + + if (lstat(new_src, &sb) == -1) { + logit("%s: lstat failed: %s", filename, + strerror(errno)); + ret = -1; + } else if (S_ISDIR(sb.st_mode)) { + if (strcmp(filename, ".") == 0 || + strcmp(filename, "..") == 0) + continue; + + if (upload_dir_internal(conn, new_src, new_dst, + pflag, depth + 1, printflag) == -1) + ret = -1; + } else if (S_ISREG(sb.st_mode)) { + if (do_upload(conn, new_src, new_dst, pflag) == -1) { + error("Uploading of file %s to %s failed!", + new_src, new_dst); + ret = -1; + } + } else + logit("%s: not a regular file\n", filename); + xfree(new_dst); + xfree(new_src); + } + + do_setstat(conn, dst, &a); + + (void) closedir(dirp); + return ret; +} + +int +upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, + int pflag) +{ + char *dst_canon; + int ret; + + if ((dst_canon = do_realpath(conn, dst)) == NULL) { + error("Unable to canonicalise path \"%s\"", dst); + return -1; + } + + ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); + xfree(dst_canon); + return ret; +} + +char * +path_append(char *p1, char *p2) +{ + char *ret; + size_t len = strlen(p1) + strlen(p2) + 2; + + ret = xmalloc(len); + strlcpy(ret, p1, len); + if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') + strlcat(ret, "/", len); + strlcat(ret, p2, len); + + return(ret); +} + diff --git a/crypto/openssh/sftp-client.h b/crypto/openssh/sftp-client.h index edb46790f..1d08c4049 100644 --- a/crypto/openssh/sftp-client.h +++ b/crypto/openssh/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.17 2008/06/08 20:15:29 dtucker Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.18 2009/08/18 18:36:20 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -68,7 +68,7 @@ void free_sftp_dirents(SFTP_DIRENT **); int do_rm(struct sftp_conn *, char *); /* Create directory 'path' */ -int do_mkdir(struct sftp_conn *, char *, Attrib *); +int do_mkdir(struct sftp_conn *, char *, Attrib *, int); /* Remove directory 'path' */ int do_rmdir(struct sftp_conn *, char *); @@ -103,7 +103,13 @@ int do_symlink(struct sftp_conn *, char *, char *); * Download 'remote_path' to 'local_path'. Preserve permissions and times * if 'pflag' is set */ -int do_download(struct sftp_conn *, char *, char *, int); +int do_download(struct sftp_conn *, char *, char *, Attrib *, int); + +/* + * Recursively download 'remote_directory' to 'local_directory'. Preserve + * times if 'pflag' is set + */ +int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times @@ -111,4 +117,13 @@ int do_download(struct sftp_conn *, char *, char *, int); */ int do_upload(struct sftp_conn *, char *, char *, int); +/* + * Recursively upload 'local_directory' to 'remote_directory'. Preserve + * times if 'pflag' is set + */ +int upload_dir(struct sftp_conn *, char *, char *, int, int); + +/* Concatenate paths, taking care of slashes. Caller must free result. */ +char *path_append(char *, char *); + #endif diff --git a/crypto/openssh/sftp-common.c b/crypto/openssh/sftp-common.c index 7ebadcc53..a042875c6 100644 --- a/crypto/openssh/sftp-common.c +++ b/crypto/openssh/sftp-common.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: sftp-common.c,v 1.23 2010/01/15 09:24:23 markus Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Damien Miller. All rights reserved. @@ -36,6 +36,9 @@ #include #include #include +#ifdef HAVE_UTIL_H +#include +#endif #include "xmalloc.h" #include "buffer.h" @@ -184,24 +187,23 @@ fx2txt(int status) * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh */ char * -ls_file(const char *name, const struct stat *st, int remote) +ls_file(const char *name, const struct stat *st, int remote, int si_units) { 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]; + char sbuf[FMT_SCALED_STRSIZE]; strmode(st->st_mode, mode); - if (!remote && (pw = getpwuid(st->st_uid)) != NULL) { - user = pw->pw_name; + if (!remote) { + user = user_from_uid(st->st_uid, 0); } else { snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); user = ubuf; } - if (!remote && (gr = getgrgid(st->st_gid)) != NULL) { - group = gr->gr_name; + if (!remote) { + group = group_from_gid(st->st_gid, 0); } else { snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); group = gbuf; @@ -216,8 +218,15 @@ ls_file(const char *name, const struct stat *st, int remote) 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); + if (si_units) { + fmt_scaled((long long)st->st_size, sbuf); + snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8s %s %s", mode, + (u_int)st->st_nlink, ulen, user, glen, group, + sbuf, tbuf, name); + } else { + snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, + (u_int)st->st_nlink, ulen, user, glen, group, + (unsigned long long)st->st_size, tbuf, name); + } return xstrdup(buf); } diff --git a/crypto/openssh/sftp-common.h b/crypto/openssh/sftp-common.h index 9b5848462..9ed86c070 100644 --- a/crypto/openssh/sftp-common.h +++ b/crypto/openssh/sftp-common.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-common.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: sftp-common.h,v 1.11 2010/01/13 01:40:16 djm Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -46,6 +46,6 @@ 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); +char *ls_file(const char *, const struct stat *, int, int); const char *fx2txt(int); diff --git a/crypto/openssh/sftp-server.8 b/crypto/openssh/sftp-server.8 index 03e58cb89..fb0cc6e07 100644 --- a/crypto/openssh/sftp-server.8 +++ b/crypto/openssh/sftp-server.8 @@ -1,4 +1,5 @@ -.\" $OpenBSD: sftp-server.8,v 1.14 2008/07/18 22:51:01 jmc Exp $ +.\" $OpenBSD: sftp-server.8,v 1.19 2010/01/09 03:36:00 jmc Exp $ +.\" $FreeBSD$ .\" .\" Copyright (c) 2000 Markus Friedl. All rights reserved. .\" @@ -22,7 +23,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd July 18 2008 +.Dd January 9 2010 .Dt SFTP-SERVER 8 .Os .Sh NAME @@ -30,8 +31,10 @@ .Nd SFTP server subsystem .Sh SYNOPSIS .Nm sftp-server +.Op Fl ehR .Op Fl f Ar log_facility .Op Fl l Ar log_level +.Op Fl u Ar umask .Sh DESCRIPTION .Nm is a program that speaks the server side of SFTP protocol @@ -54,12 +57,20 @@ for more information. .Pp Valid options are: .Bl -tag -width Ds +.It Fl e +Causes +.Nm +to print logging information to stderr instead of syslog for debugging. .It Fl f Ar log_facility Specifies the facility code that is used when logging messages from .Nm . The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is AUTH. +.It Fl h +Displays +.Nm +usage information. .It Fl l Ar log_level Specifies which messages will be logged by .Nm . @@ -71,6 +82,17 @@ performs on behalf of the client. DEBUG and DEBUG1 are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. The default is ERROR. +.It Fl R +Places this instance of +.Nm +into a read-only mode. +Attempts to open files for writing, as well as other operations that change +the state of the filesystem, will be denied. +.It Fl u Ar umask +Sets an explicit +.Xr umask 2 +to be applied to newly-created files and directories, instead of the +user's default mask. .El .Pp For logging to work, @@ -79,7 +101,7 @@ must be able to access .Pa /dev/log . Use of .Nm -in a chroot configuation therefore requires that +in a chroot configuration therefore requires that .Xr syslogd 8 establish a logging socket inside the chroot directory. .Sh SEE ALSO diff --git a/crypto/openssh/sftp-server.c b/crypto/openssh/sftp-server.c index 24c4ff717..a98ac2b6d 100644 --- a/crypto/openssh/sftp-server.c +++ b/crypto/openssh/sftp-server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-server.c,v 1.84 2008/06/26 06:10:09 djm Exp $ */ +/* $OpenBSD: sftp-server.c,v 1.91 2010/01/13 01:40:16 djm Exp $ */ /* * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * @@ -70,6 +70,9 @@ Buffer oqueue; /* Version of client */ int version; +/* Disable writes */ +int readonly; + /* portable attributes, etc. */ typedef struct Stat Stat; @@ -553,16 +556,21 @@ process_open(void) 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); + if (readonly && + ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR)) + status = SSH2_FX_PERMISSION_DENIED; + else { + fd = open(name, flags, mode); + if (fd < 0) { + status = errno_to_portable(errno); } else { - send_handle(id, handle); - status = SSH2_FX_OK; + 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) @@ -632,7 +640,7 @@ process_write(void) u_int32_t id; u_int64_t off; u_int len; - int handle, fd, ret, status = SSH2_FX_FAILURE; + int handle, fd, ret, status; char *data; id = get_int(); @@ -643,7 +651,12 @@ process_write(void) 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 (fd < 0) + status = SSH2_FX_FAILURE; + else if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { if (lseek(fd, off, SEEK_SET) < 0) { status = errno_to_portable(errno); error("process_write: seek failed"); @@ -658,6 +671,7 @@ process_write(void) handle_update_write(handle, ret); } else { debug2("nothing at all written"); + status = SSH2_FX_FAILURE; } } } @@ -754,6 +768,10 @@ process_setstat(void) name = get_string(NULL); a = get_attrib(); debug("request %u: setstat name \"%s\"", id, name); + if (readonly) { + status = SSH2_FX_PERMISSION_DENIED; + a->flags = 0; + } if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { logit("set \"%s\" size %llu", name, (unsigned long long)a->size); @@ -802,9 +820,11 @@ process_fsetstat(void) a = get_attrib(); debug("request %u: fsetstat handle %d", id, handle); fd = handle_to_fd(handle); - if (fd < 0) { + if (fd < 0) status = SSH2_FX_FAILURE; - } else { + else if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { char *name = handle_to_name(handle); if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { @@ -920,7 +940,7 @@ process_readdir(void) 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); + stats[count].long_name = ls_file(dp->d_name, &st, 0, 0); count++; /* send up to 100 entries in one message */ /* XXX check packet size instead */ @@ -952,8 +972,12 @@ process_remove(void) 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; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = unlink(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -973,8 +997,12 @@ process_mkdir(void) 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; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = mkdir(name, mode); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -990,8 +1018,12 @@ process_rmdir(void) 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; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = rmdir(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(name); } @@ -1036,12 +1068,14 @@ process_rename(void) debug3("request %u: rename", id); logit("rename old \"%s\" new \"%s\"", oldpath, newpath); status = SSH2_FX_FAILURE; - if (lstat(oldpath, &sb) == -1) + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else if (lstat(oldpath, &sb) == -1) status = errno_to_portable(errno); else if (S_ISREG(sb.st_mode)) { /* Race-free rename of regular files */ if (link(oldpath, newpath) == -1) { - if (errno == EOPNOTSUPP + if (errno == EOPNOTSUPP || errno == ENOSYS #ifdef EXDEV || errno == EXDEV #endif @@ -1120,8 +1154,12 @@ process_symlink(void) 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; + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } send_status(id, status); xfree(oldpath); xfree(newpath); @@ -1131,15 +1169,19 @@ static void process_extended_posix_rename(u_int32_t id) { char *oldpath, *newpath; + int ret, status; oldpath = get_string(NULL); newpath = get_string(NULL); debug3("request %u: posix-rename", id); logit("posix-rename old \"%s\" new \"%s\"", oldpath, newpath); - if (rename(oldpath, newpath) == -1) - send_status(id, errno_to_portable(errno)); - else - send_status(id, SSH2_FX_OK); + if (readonly) + status = SSH2_FX_PERMISSION_DENIED; + else { + ret = rename(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + } + send_status(id, status); xfree(oldpath); xfree(newpath); } @@ -1322,7 +1364,8 @@ sftp_server_usage(void) extern char *__progname; fprintf(stderr, - "usage: %s [-he] [-l log_level] [-f log_facility]\n", __progname); + "usage: %s [-ehR] [-f log_facility] [-l log_level] [-u umask]\n", + __progname); exit(1); } @@ -1334,6 +1377,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) ssize_t len, olen, set_size; SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; char *cp, buf[4*4096]; + const char *errmsg; + mode_t mask; extern char *optarg; extern char *__progname; @@ -1341,8 +1386,11 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) __progname = ssh_get_progname(argv[0]); log_init(__progname, log_level, log_facility, log_stderr); - while (!skipargs && (ch = getopt(argc, argv, "C:f:l:che")) != -1) { + while (!skipargs && (ch = getopt(argc, argv, "f:l:u:cehR")) != -1) { switch (ch) { + case 'R': + readonly = 1; + break; case 'c': /* * Ignore all arguments if we are invoked as a @@ -1363,6 +1411,13 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) if (log_facility == SYSLOG_FACILITY_NOT_SET) error("Invalid log facility \"%s\"", optarg); break; + case 'u': + mask = (mode_t)strtonum(optarg, 0, 0777, &errmsg); + if (errmsg != NULL) + fatal("Invalid umask \"%s\": %s", + optarg, errmsg); + (void)umask(mask); + break; case 'h': default: sftp_server_usage(); @@ -1387,8 +1442,8 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) logit("session opened for local user %s from [%s]", pw->pw_name, client_addr); - in = dup(STDIN_FILENO); - out = dup(STDOUT_FILENO); + in = STDIN_FILENO; + out = STDOUT_FILENO; #ifdef HAVE_CYGWIN setmode(in, O_BINARY); diff --git a/crypto/openssh/sftp.1 b/crypto/openssh/sftp.1 index ea56e5038..9655cb847 100644 --- a/crypto/openssh/sftp.1 +++ b/crypto/openssh/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.69 2008/12/09 15:35:00 sobrado Exp $ +.\" $OpenBSD: sftp.1,v 1.83 2010/02/08 10:50:20 markus Exp $ .\" $FreeBSD$ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. @@ -23,7 +23,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd December 9 2008 +.Dd February 8 2010 .Dt SFTP 1 .Os .Sh NAME @@ -32,12 +32,15 @@ .Sh SYNOPSIS .Nm sftp .Bk -words -.Op Fl 1Cv +.Op Fl 1246Cpqrv .Op Fl B Ar buffer_size .Op Fl b Ar batchfile +.Op Fl c Ar cipher +.Op Fl D Ar sftp_server_path .Op Fl F Ar ssh_config +.Op Fl i Ar identity_file .Op Fl o Ar ssh_option -.Op Fl P Ar sftp_server_path +.Op Fl P Ar port .Op Fl R Ar num_requests .Op Fl S Ar program .Op Fl s Ar subsystem | sftp_server @@ -88,6 +91,16 @@ The options are as follows: .Bl -tag -width Ds .It Fl 1 Specify the use of protocol version 1. +.It Fl 2 +Specify the use of protocol version 2. +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. .It Fl B Ar buffer_size Specify the size of the buffer that .Nm @@ -125,12 +138,26 @@ character (for example, Enables compression (via ssh's .Fl C flag). +.It Fl c Ar cipher +Selects the cipher to use for encrypting the data transfers. +This option is directly passed to +.Xr ssh 1 . +.It Fl D Ar sftp_server_path +Connect directly to a local sftp server +(rather than via +.Xr ssh 1 ) . +This option may be useful in debugging the client and server. .It Fl F Ar ssh_config Specifies an alternative per-user configuration file for .Xr ssh 1 . This option is directly passed to .Xr ssh 1 . +.It Fl i Ar identity_file +Selects the file from which the identity (private key) for public key +authentication is read. +This option is directly passed to +.Xr ssh 1 . .It Fl o Ar ssh_option Can be used to pass options to .Nm ssh @@ -176,6 +203,7 @@ For full details of the options listed below, and their possible values, see .It NoHostAuthenticationForLocalhost .It NumberOfPasswordPrompts .It PasswordAuthentication +.It PKCS11Provider .It Port .It PreferredAuthentications .It Protocol @@ -187,7 +215,6 @@ For full details of the options listed below, and their possible values, see .It SendEnv .It ServerAliveInterval .It ServerAliveCountMax -.It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive .It UsePrivilegedPort @@ -195,16 +222,25 @@ For full details of the options listed below, and their possible values, see .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 P Ar port +Specifies the port to connect to on the remote host. +.It Fl p +Preserves modification times, access times, and modes from the +original files transferred. +.It Fl q +Quiet mode: disables the progress meter as well as warning and +diagnostic messages from +.Xr ssh 1 . .It Fl R Ar num_requests Specify how many requests may be outstanding at any one time. Increasing this may slightly improve file transfer speed but will increase memory usage. The default is 64 outstanding requests. +.It Fl r +Recursively copy entire directories when uploading and downloading. +Note that +.Nm +does not follow symbolic links encountered in the tree traversal. .It Fl S Ar program Name of the .Ar program @@ -295,7 +331,7 @@ extension. Quit .Nm sftp . .It Xo Ic get -.Op Fl P +.Op Fl Ppr .Ar remote-path .Op Ar local-path .Xc @@ -314,10 +350,20 @@ If it does and is specified, then .Ar local-path must specify a directory. -If the +.Pp +If either the .Fl P +or +.Fl p flag is specified, then full file permissions and access times are copied too. +.Pp +If the +.Fl r +flag is specified then directories will be copied recursively. +Note that +.Nm +does not follow symbolic links when performing recursive transfers. .It Ic help Display help text. .It Ic lcd Ar path @@ -348,7 +394,7 @@ to .It Ic lpwd Print local working directory. .It Xo Ic ls -.Op Fl 1aflnrSt +.Op Fl 1afhlnrSt .Op Ar path .Xc Display a remote directory listing of either @@ -373,6 +419,11 @@ List files beginning with a dot .It Fl f Do not sort the listing. The default sort order is lexicographical. +.It Fl h +When used with a long format option, use unit suffixes: Byte, Kilobyte, +Megabyte, Gigabyte, Terabyte, Petabyte, and Exabyte in order to reduce +the number of digits to four or fewer using powers of 2 for sizes (K=1024, +M=1048576, etc.). .It Fl l Display additional details including permissions and ownership information. @@ -395,7 +446,7 @@ Create remote directory specified by .It Ic progress Toggle display of progress meter. .It Xo Ic put -.Op Fl P +.Op Fl Ppr .Ar local-path .Op Ar remote-path .Xc @@ -413,10 +464,20 @@ If it does and is specified, then .Ar remote-path must specify a directory. -If the +.Pp +If ether the .Fl P -flag is specified, then the file's full permission and access time are +or +.Fl p +flag is specified, then full file permissions and access times are copied too. +.Pp +If the +.Fl r +flag is specified then directories will be copied recursively. +Note that +.Nm +does not follow symbolic links when performing recursive transfers. .It Ic pwd Display remote working directory. .It Ic quit diff --git a/crypto/openssh/sftp.c b/crypto/openssh/sftp.c index 66bd111b1..d65d4ec62 100644 --- a/crypto/openssh/sftp.c +++ b/crypto/openssh/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.107 2009/02/02 11:15:14 dtucker Exp $ */ +/* $OpenBSD: sftp.c,v 1.123 2010/01/27 19:21:39 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -35,6 +35,9 @@ #ifdef HAVE_PATHS_H # include #endif +#ifdef HAVE_LIBGEN_H +#include +#endif #ifdef USE_LIBEDIT #include #else @@ -65,30 +68,39 @@ typedef void EditLine; #include "sftp-common.h" #include "sftp-client.h" +#define DEFAULT_COPY_BUFLEN 32768 /* Size of buffer for up/download */ +#define DEFAULT_NUM_REQUESTS 64 /* # concurrent outstanding requests */ + /* File to read commands from */ FILE* infile; /* Are we in batchfile mode? */ int batchmode = 0; -/* 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; +/* When this option is set, we always recursively download/upload directories */ +int global_rflag = 0; + +/* When this option is set, the file transfers will always preserve times */ +int global_pflag = 0; + /* SIGINT received during command processing */ volatile sig_atomic_t interrupted = 0; /* I wish qsort() took a separate ctx for the comparison function...*/ int sort_flag; +/* Context used for commandline completion */ +struct complete_ctx { + struct sftp_conn *conn; + char **remote_pathp; +}; + int remote_glob(struct sftp_conn *, const char *, int, int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ @@ -98,16 +110,17 @@ extern char *__progname; #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 LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ +#define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ +#define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ +#define LS_NAME_SORT 0x0008 /* Sort by name (default) */ +#define LS_TIME_SORT 0x0010 /* Sort by mtime */ +#define LS_SIZE_SORT 0x0020 /* Sort by file size */ +#define LS_REVERSE_SORT 0x0040 /* Reverse sort order */ +#define LS_SHOW_ALL 0x0080 /* Don't skip filenames starting with '.' */ +#define LS_SI_UNITS 0x0100 /* Display sizes as K, M, G, etc. */ + +#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS) #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) /* Commands for interactive mode */ @@ -139,46 +152,50 @@ extern char *__progname; struct CMD { const char *c; const int n; + const int t; }; +/* Type of completion */ +#define NOARGS 0 +#define REMOTE 1 +#define LOCAL 2 + static const struct CMD cmds[] = { - { "bye", I_QUIT }, - { "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} + { "bye", I_QUIT, NOARGS }, + { "cd", I_CHDIR, REMOTE }, + { "chdir", I_CHDIR, REMOTE }, + { "chgrp", I_CHGRP, REMOTE }, + { "chmod", I_CHMOD, REMOTE }, + { "chown", I_CHOWN, REMOTE }, + { "df", I_DF, REMOTE }, + { "dir", I_LS, REMOTE }, + { "exit", I_QUIT, NOARGS }, + { "get", I_GET, REMOTE }, + { "help", I_HELP, NOARGS }, + { "lcd", I_LCHDIR, LOCAL }, + { "lchdir", I_LCHDIR, LOCAL }, + { "lls", I_LLS, LOCAL }, + { "lmkdir", I_LMKDIR, LOCAL }, + { "ln", I_SYMLINK, REMOTE }, + { "lpwd", I_LPWD, LOCAL }, + { "ls", I_LS, REMOTE }, + { "lumask", I_LUMASK, NOARGS }, + { "mkdir", I_MKDIR, REMOTE }, + { "progress", I_PROGRESS, NOARGS }, + { "put", I_PUT, LOCAL }, + { "pwd", I_PWD, REMOTE }, + { "quit", I_QUIT, NOARGS }, + { "rename", I_RENAME, REMOTE }, + { "rm", I_RM, REMOTE }, + { "rmdir", I_RMDIR, REMOTE }, + { "symlink", I_SYMLINK, REMOTE }, + { "version", I_VERSION, NOARGS }, + { "!", I_SHELL, NOARGS }, + { "?", I_HELP, NOARGS }, + { NULL, -1, -1 } }; -int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); +int interactive_loop(struct sftp_conn *, char *file1, char *file2); /* ARGSUSED */ static void @@ -216,18 +233,18 @@ help(void) "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" + "get [-Ppr] remote [local] Download file\n" "help Display this help text\n" "lcd path Change local directory to 'path'\n" "lls [ls-options [path]] Display local directory listing\n" "lmkdir path Create local directory\n" "ln oldpath newpath Symlink remote file\n" "lpwd Print local working directory\n" - "ls [-1aflnrSt] [path] Display remote directory listing\n" + "ls [-1afhlnrSt] [path] Display remote directory listing\n" "lumask umask Set local umask to 'umask'\n" "mkdir path Create remote directory\n" "progress Toggle display of progress meter\n" - "put [-P] local-path [remote-path] Upload file\n" + "put [-Ppr] local [remote] Upload file\n" "pwd Display remote working directory\n" "quit Quit sftp\n" "rename oldpath newpath Rename remote file\n" @@ -313,21 +330,6 @@ path_strip(char *path, char *strip) 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) { @@ -343,27 +345,8 @@ make_absolute(char *p, char *pwd) } 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) +parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, + int *rflag) { extern int opterr, optind, optopt, optreset; int ch; @@ -371,13 +354,17 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag) optind = optreset = 1; opterr = 0; - *pflag = 0; - while ((ch = getopt(argc, argv, "Pp")) != -1) { + *rflag = *pflag = 0; + while ((ch = getopt(argc, argv, "PpRr")) != -1) { switch (ch) { case 'p': case 'P': *pflag = 1; break; + case 'r': + case 'R': + *rflag = 1; + break; default: error("%s: Invalid flag -%c", cmd, optopt); return -1; @@ -397,7 +384,7 @@ parse_ls_flags(char **argv, int argc, int *lflag) opterr = 0; *lflag = LS_NAME_SORT; - while ((ch = getopt(argc, argv, "1Saflnrt")) != -1) { + while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) { switch (ch) { case '1': *lflag &= ~VIEW_FLAGS; @@ -413,12 +400,15 @@ parse_ls_flags(char **argv, int argc, int *lflag) case 'f': *lflag &= ~SORT_FLAGS; break; + case 'h': + *lflag |= LS_SI_UNITS; + break; case 'l': - *lflag &= ~VIEW_FLAGS; + *lflag &= ~LS_SHORT_VIEW; *lflag |= LS_LONG_VIEW; break; case 'n': - *lflag &= ~VIEW_FLAGS; + *lflag &= ~LS_SHORT_VIEW; *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; break; case 'r': @@ -489,62 +479,79 @@ remote_is_dir(struct sftp_conn *conn, char *path) return(S_ISDIR(a->perm)); } +/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ +static int +pathname_is_dir(char *pathname) +{ + size_t l = strlen(pathname); + + return l > 0 && pathname[l - 1] == '/'; +} + static int -process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) +process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, + int pflag, int rflag) { char *abs_src = NULL; char *abs_dst = NULL; - char *tmp; glob_t g; - int err = 0; - int i; + char *filename, *tmp=NULL; + int i, err = 0; abs_src = xstrdup(src); abs_src = make_absolute(abs_src, pwd); - memset(&g, 0, sizeof(g)); + debug3("Looking up %s", abs_src); - if (remote_glob(conn, abs_src, 0, NULL, &g)) { + if (remote_glob(conn, abs_src, GLOB_MARK, 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); + /* + * If multiple matches then dst must be a directory or + * unspecified. + */ + if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) { + error("Multiple source paths, but destination " + "\"%s\" is not a directory", dst); err = -1; goto out; } for (i = 0; g.gl_pathv[i] && !interrupted; i++) { - if (infer_path(g.gl_pathv[i], &tmp)) { + tmp = xstrdup(g.gl_pathv[i]); + if ((filename = basename(tmp)) == NULL) { + error("basename %s: %s", tmp, strerror(errno)); + xfree(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && dst) { - /* If 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 = path_append(dst, filename); + } else { abs_dst = xstrdup(dst); + } } else if (dst) { - abs_dst = path_append(dst, tmp); - xfree(tmp); - } else - abs_dst = tmp; + abs_dst = path_append(dst, filename); + } else { + abs_dst = xstrdup(filename); + } + xfree(tmp); printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); - if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) - err = -1; + if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { + if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, + pflag || global_pflag, 1) == -1) + err = -1; + } else { + if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, + pflag || global_pflag) == -1) + err = -1; + } xfree(abs_dst); abs_dst = NULL; } @@ -556,14 +563,15 @@ out: } static int -process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) +process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, + int pflag, int rflag) { char *tmp_dst = NULL; char *abs_dst = NULL; - char *tmp; + char *tmp = NULL, *filename = NULL; glob_t g; int err = 0; - int i; + int i, dst_is_dir = 1; struct stat sb; if (dst) { @@ -573,16 +581,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); - if (glob(src, GLOB_NOCHECK, NULL, &g)) { + if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; } + /* If we aren't fetching to pwd then stash this status for later */ + if (tmp_dst != NULL) + dst_is_dir = remote_is_dir(conn, tmp_dst); + /* If multiple matches, dst may be directory or unspecified */ - if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) { - error("Multiple files match, but \"%s\" is not a directory", - tmp_dst); + if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { + error("Multiple paths match, but destination " + "\"%s\" is not a directory", tmp_dst); err = -1; goto out; } @@ -593,38 +605,38 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) 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)) { + + tmp = xstrdup(g.gl_pathv[i]); + if ((filename = basename(tmp)) == NULL) { + error("basename %s: %s", tmp, strerror(errno)); + xfree(tmp); err = -1; goto out; } if (g.gl_matchc == 1 && tmp_dst) { /* If directory specified, append filename */ - if (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 + if (dst_is_dir) + abs_dst = path_append(tmp_dst, filename); + else abs_dst = xstrdup(tmp_dst); - } else if (tmp_dst) { - abs_dst = path_append(tmp_dst, tmp); - xfree(tmp); - } else - abs_dst = make_absolute(tmp, pwd); + abs_dst = path_append(tmp_dst, filename); + } else { + abs_dst = make_absolute(xstrdup(filename), pwd); + } + xfree(tmp); printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); - if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) - err = -1; + if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { + if (upload_dir(conn, g.gl_pathv[i], abs_dst, + pflag || global_pflag, 1) == -1) + err = -1; + } else { + if (do_upload(conn, g.gl_pathv[i], abs_dst, + pflag || global_pflag) == -1) + err = -1; + } } out: @@ -708,13 +720,14 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) xfree(tmp); if (lflag & LS_LONG_VIEW) { - if (lflag & LS_NUMERIC_VIEW) { + if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) { char *lname; struct stat sb; memset(&sb, 0, sizeof(sb)); attrib_to_stat(&d[n]->a, &sb); - lname = ls_file(fname, &sb, 1); + lname = ls_file(fname, &sb, 1, + (lflag & LS_SI_UNITS)); printf("%s\n", lname); xfree(lname); } else @@ -816,7 +829,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, a = do_lstat(conn, g.gl_pathv[i], 1); if (a != NULL) attrib_to_stat(a, &sb); - lname = ls_file(fname, &sb, 1); + lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS)); printf("%s\n", lname); xfree(lname); } else { @@ -848,19 +861,19 @@ do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) char s_avail[FMT_SCALED_STRSIZE]; char s_root[FMT_SCALED_STRSIZE]; char s_total[FMT_SCALED_STRSIZE]; + unsigned long long ffree; if (do_statvfs(conn, path, &st, 1) == -1) return -1; if (iflag) { + ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0; printf(" Inodes Used Avail " "(root) %%Capacity\n"); printf("%11llu %11llu %11llu %11llu %3llu%%\n", (unsigned long long)st.f_files, (unsigned long long)(st.f_files - st.f_ffree), (unsigned long long)st.f_favail, - (unsigned long long)st.f_ffree, - (unsigned long long)(100 * (st.f_files - st.f_ffree) / - st.f_files)); + (unsigned long long)st.f_ffree, ffree); } else if (hflag) { strlcpy(s_used, "error", sizeof(s_used)); strlcpy(s_avail, "error", sizeof(s_avail)); @@ -934,12 +947,23 @@ undo_glob_escape(char *s) * Split a string into an argument vector using sh(1)-style quoting, * comment and escaping rules, but with some tweaks to handle glob(3) * wildcards. + * The "sloppy" flag allows for recovery from missing terminating quote, for + * use in parsing incomplete commandlines during tab autocompletion. + * * Returns NULL on error or a NULL-terminated array of arguments. + * + * If "lastquote" is not NULL, the quoting character used for the last + * argument is placed in *lastquote ("\0", "'" or "\""). + * + * If "terminated" is not NULL, *terminated will be set to 1 when the + * last argument's quote has been properly terminated or 0 otherwise. + * This parameter is only of use if "sloppy" is set. */ #define MAXARGS 128 #define MAXARGLEN 8192 static char ** -makeargv(const char *arg, int *argcp) +makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, + u_int *terminated) { int argc, quot; size_t i, j; @@ -953,6 +977,10 @@ makeargv(const char *arg, int *argcp) error("string too long"); return NULL; } + if (terminated != NULL) + *terminated = 1; + if (lastquote != NULL) + *lastquote = '\0'; state = MA_START; i = j = 0; for (;;) { @@ -969,6 +997,8 @@ makeargv(const char *arg, int *argcp) if (state == MA_START) { argv[argc] = argvs + j; state = q; + if (lastquote != NULL) + *lastquote = arg[i]; } else if (state == MA_UNQUOTED) state = q; else if (state == q) @@ -1005,6 +1035,8 @@ makeargv(const char *arg, int *argcp) if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; + if (lastquote != NULL) + *lastquote = '\0'; } if (arg[i + 1] == '?' || arg[i + 1] == '[' || arg[i + 1] == '*' || arg[i + 1] == '\\') { @@ -1030,6 +1062,12 @@ makeargv(const char *arg, int *argcp) goto string_done; } else if (arg[i] == '\0') { if (state == MA_SQUOTE || state == MA_DQUOTE) { + if (sloppy) { + state = MA_UNQUOTED; + if (terminated != NULL) + *terminated = 0; + goto string_done; + } error("Unterminated quoted argument"); return NULL; } @@ -1043,6 +1081,8 @@ makeargv(const char *arg, int *argcp) if (state == MA_START) { argv[argc] = argvs + j; state = MA_UNQUOTED; + if (lastquote != NULL) + *lastquote = '\0'; } if ((state == MA_SQUOTE || state == MA_DQUOTE) && (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) { @@ -1065,8 +1105,8 @@ makeargv(const char *arg, int *argcp) } static int -parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, - unsigned long *n_arg, char **path1, char **path2) +parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, + int *hflag, unsigned long *n_arg, char **path1, char **path2) { const char *cmd, *cp = *cpp; char *cp2, **argv; @@ -1077,18 +1117,19 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, /* 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++; + cp = cp + strspn(cp, WHITESPACE); } - if ((argv = makeargv(cp, &argc)) == NULL) + /* Ignore blank lines and lines which begin with comment '#' char */ + if (*cp == '\0' || *cp == '#') + return (0); + + if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL) return -1; /* Figure out which command we have */ @@ -1109,13 +1150,13 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, } /* Get arguments and parse flags */ - *lflag = *pflag = *hflag = *n_arg = 0; + *lflag = *pflag = *rflag = *hflag = *n_arg = 0; *path1 = *path2 = NULL; optidx = 1; switch (cmdnum) { case I_GET: case I_PUT: - if ((optidx = parse_getput_flags(cmd, argv, argc, pflag)) == -1) + if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1) return -1; /* Get first pathname (mandatory) */ if (argc - optidx < 1) { @@ -1235,7 +1276,7 @@ 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; + int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i; unsigned long n_arg = 0; Attrib a, *aa; char path_buf[MAXPATHLEN]; @@ -1243,7 +1284,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, glob_t g; path1 = path2 = NULL; - cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg, + cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg, &path1, &path2); if (iflag != 0) @@ -1261,10 +1302,10 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, err = -1; break; case I_GET: - err = process_get(conn, path1, path2, *pwd, pflag); + err = process_get(conn, path1, path2, *pwd, pflag, rflag); break; case I_PUT: - err = process_put(conn, path1, path2, *pwd, pflag); + err = process_put(conn, path1, path2, *pwd, pflag, rflag); break; case I_RENAME: path1 = make_absolute(path1, *pwd); @@ -1290,7 +1331,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, attrib_clear(&a); a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.perm = 0777; - err = do_mkdir(conn, path1, &a); + err = do_mkdir(conn, path1, &a, 1); break; case I_RMDIR: path1 = make_absolute(path1, *pwd); @@ -1468,21 +1509,352 @@ prompt(EditLine *el) { return ("sftp> "); } -#endif + +/* Display entries in 'list' after skipping the first 'len' chars */ +static void +complete_display(char **list, u_int len) +{ + u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen; + struct winsize ws; + char *tmp; + + /* Count entries for sort and find longest */ + for (y = 0; list[y]; y++) + m = MAX(m, strlen(list[y])); + + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + + m = m > len ? m - len : 0; + columns = width / (m + 2); + columns = MAX(columns, 1); + colspace = width / columns; + colspace = MIN(colspace, width); + + printf("\n"); + m = 1; + for (y = 0; list[y]; y++) { + llen = strlen(list[y]); + tmp = llen > len ? list[y] + len : ""; + printf("%-*s", colspace, tmp); + if (m >= columns) { + printf("\n"); + m = 1; + } else + m++; + } + printf("\n"); +} + +/* + * Given a "list" of words that begin with a common prefix of "word", + * attempt to find an autocompletion to extends "word" by the next + * characters common to all entries in "list". + */ +static char * +complete_ambiguous(const char *word, char **list, size_t count) +{ + if (word == NULL) + return NULL; + + if (count > 0) { + u_int y, matchlen = strlen(list[0]); + + /* Find length of common stem */ + for (y = 1; list[y]; y++) { + u_int x; + + for (x = 0; x < matchlen; x++) + if (list[0][x] != list[y][x]) + break; + + matchlen = x; + } + + if (matchlen > strlen(word)) { + char *tmp = xstrdup(list[0]); + + tmp[matchlen] = '\0'; + return tmp; + } + } + + return xstrdup(word); +} + +/* Autocomplete a sftp command */ +static int +complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, + int terminated) +{ + u_int y, count = 0, cmdlen, tmplen; + char *tmp, **list, argterm[3]; + const LineInfo *lf; + + list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *)); + + /* No command specified: display all available commands */ + if (cmd == NULL) { + for (y = 0; cmds[y].c; y++) + list[count++] = xstrdup(cmds[y].c); + + list[count] = NULL; + complete_display(list, 0); + + for (y = 0; list[y] != NULL; y++) + xfree(list[y]); + xfree(list); + return count; + } + + /* Prepare subset of commands that start with "cmd" */ + cmdlen = strlen(cmd); + for (y = 0; cmds[y].c; y++) { + if (!strncasecmp(cmd, cmds[y].c, cmdlen)) + list[count++] = xstrdup(cmds[y].c); + } + list[count] = NULL; + + if (count == 0) + return 0; + + /* Complete ambigious command */ + tmp = complete_ambiguous(cmd, list, count); + if (count > 1) + complete_display(list, 0); + + for (y = 0; list[y]; y++) + xfree(list[y]); + xfree(list); + + if (tmp != NULL) { + tmplen = strlen(tmp); + cmdlen = strlen(cmd); + /* If cmd may be extended then do so */ + if (tmplen > cmdlen) + if (el_insertstr(el, tmp + cmdlen) == -1) + fatal("el_insertstr failed."); + lf = el_line(el); + /* Terminate argument cleanly */ + if (count == 1) { + y = 0; + if (!terminated) + argterm[y++] = quote; + if (lastarg || *(lf->cursor) != ' ') + argterm[y++] = ' '; + argterm[y] = '\0'; + if (y > 0 && el_insertstr(el, argterm) == -1) + fatal("el_insertstr failed."); + } + xfree(tmp); + } + + return count; +} + +/* + * Determine whether a particular sftp command's arguments (if any) + * represent local or remote files. + */ +static int +complete_is_remote(char *cmd) { + int i; + + if (cmd == NULL) + return -1; + + for (i = 0; cmds[i].c; i++) { + if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) + return cmds[i].t; + } + + return -1; +} + +/* Autocomplete a filename "file" */ +static int +complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, + char *file, int remote, int lastarg, char quote, int terminated) +{ + glob_t g; + char *tmp, *tmp2, ins[3]; + u_int i, hadglob, pwdlen, len, tmplen, filelen; + const LineInfo *lf; + + /* Glob from "file" location */ + if (file == NULL) + tmp = xstrdup("*"); + else + xasprintf(&tmp, "%s*", file); + + memset(&g, 0, sizeof(g)); + if (remote != LOCAL) { + tmp = make_absolute(tmp, remote_path); + remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); + } else + glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); + + /* Determine length of pwd so we can trim completion display */ + for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { + /* Terminate counting on first unescaped glob metacharacter */ + if (tmp[tmplen] == '*' || tmp[tmplen] == '?') { + if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0') + hadglob = 1; + break; + } + if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0') + tmplen++; + if (tmp[tmplen] == '/') + pwdlen = tmplen + 1; /* track last seen '/' */ + } + xfree(tmp); + + if (g.gl_matchc == 0) + goto out; + + if (g.gl_matchc > 1) + complete_display(g.gl_pathv, pwdlen); + + tmp = NULL; + /* Don't try to extend globs */ + if (file == NULL || hadglob) + goto out; + + tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc); + tmp = path_strip(tmp2, remote_path); + xfree(tmp2); + + if (tmp == NULL) + goto out; + + tmplen = strlen(tmp); + filelen = strlen(file); + + if (tmplen > filelen) { + tmp2 = tmp + filelen; + len = strlen(tmp2); + /* quote argument on way out */ + for (i = 0; i < len; i++) { + ins[0] = '\\'; + ins[1] = tmp2[i]; + ins[2] = '\0'; + switch (tmp2[i]) { + case '\'': + case '"': + case '\\': + case '\t': + case ' ': + if (quote == '\0' || tmp2[i] == quote) { + if (el_insertstr(el, ins) == -1) + fatal("el_insertstr " + "failed."); + break; + } + /* FALLTHROUGH */ + default: + if (el_insertstr(el, ins + 1) == -1) + fatal("el_insertstr failed."); + break; + } + } + } + + lf = el_line(el); + if (g.gl_matchc == 1) { + i = 0; + if (!terminated) + ins[i++] = quote; + if (*(lf->cursor - 1) != '/' && + (lastarg || *(lf->cursor) != ' ')) + ins[i++] = ' '; + ins[i] = '\0'; + if (i > 0 && el_insertstr(el, ins) == -1) + fatal("el_insertstr failed."); + } + xfree(tmp); + + out: + globfree(&g); + return g.gl_matchc; +} + +/* tab-completion hook function, called via libedit */ +static unsigned char +complete(EditLine *el, int ch) +{ + char **argv, *line, quote; + u_int argc, carg, cursor, len, terminated, ret = CC_ERROR; + const LineInfo *lf; + struct complete_ctx *complete_ctx; + + lf = el_line(el); + if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0) + fatal("%s: el_get failed", __func__); + + /* Figure out which argument the cursor points to */ + cursor = lf->cursor - lf->buffer; + line = (char *)xmalloc(cursor + 1); + memcpy(line, lf->buffer, cursor); + line[cursor] = '\0'; + argv = makeargv(line, &carg, 1, "e, &terminated); + xfree(line); + + /* Get all the arguments on the line */ + len = lf->lastchar - lf->buffer; + line = (char *)xmalloc(len + 1); + memcpy(line, lf->buffer, len); + line[len] = '\0'; + argv = makeargv(line, &argc, 1, NULL, NULL); + + /* Ensure cursor is at EOL or a argument boundary */ + if (line[cursor] != ' ' && line[cursor] != '\0' && + line[cursor] != '\n') { + xfree(line); + return ret; + } + + if (carg == 0) { + /* Show all available commands */ + complete_cmd_parse(el, NULL, argc == carg, '\0', 1); + ret = CC_REDISPLAY; + } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { + /* Handle the command parsing */ + if (complete_cmd_parse(el, argv[0], argc == carg, + quote, terminated) != 0) + ret = CC_REDISPLAY; + } else if (carg >= 1) { + /* Handle file parsing */ + int remote = complete_is_remote(argv[0]); + char *filematch = NULL; + + if (carg > 1 && line[cursor-1] != ' ') + filematch = argv[carg - 1]; + + if (remote != 0 && + complete_match(el, complete_ctx->conn, + *complete_ctx->remote_pathp, filematch, + remote, carg == argc, quote, terminated) != 0) + ret = CC_REDISPLAY; + } + + xfree(line); + return ret; +} +#endif /* USE_LIBEDIT */ int -interactive_loop(int fd_in, int fd_out, char *file1, char *file2) +interactive_loop(struct sftp_conn *conn, char *file1, char *file2) { - char *pwd; + char *remote_path; 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; + struct complete_ctx complete_ctx; if (!batchmode && isatty(STDIN_FILENO)) { if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL) @@ -1497,27 +1869,32 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) el_set(el, EL_TERMINAL, NULL); el_set(el, EL_SIGNAL, 1); el_source(el, NULL); + + /* Tab Completion */ + el_set(el, EL_ADDFN, "ftp-complete", + "Context senstive argument completion", complete); + complete_ctx.conn = conn; + complete_ctx.remote_pathp = &remote_path; + el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); + el_set(el, EL_BIND, "^I", "ftp-complete", NULL); } #endif /* USE_LIBEDIT */ - 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) + remote_path = do_realpath(conn, "."); + if (remote_path == NULL) fatal("Need cwd"); if (file1 != NULL) { dir = xstrdup(file1); - dir = make_absolute(dir, pwd); + dir = make_absolute(dir, remote_path); if (remote_is_dir(conn, dir) && file2 == NULL) { printf("Changing to: %s\n", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); - if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) { + if (parse_dispatch_command(conn, cmd, + &remote_path, 1) != 0) { xfree(dir); - xfree(pwd); + xfree(remote_path); xfree(conn); return (-1); } @@ -1528,9 +1905,10 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) snprintf(cmd, sizeof cmd, "get %s %s", dir, file2); - err = parse_dispatch_command(conn, cmd, &pwd, 1); + err = parse_dispatch_command(conn, cmd, + &remote_path, 1); xfree(dir); - xfree(pwd); + xfree(remote_path); xfree(conn); return (err); } @@ -1571,7 +1949,8 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) const char *line; int count = 0; - if ((line = el_gets(el, &count)) == NULL || count <= 0) { + if ((line = el_gets(el, &count)) == NULL || + count <= 0) { printf("\n"); break; } @@ -1591,11 +1970,12 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2) interrupted = 0; signal(SIGINT, cmd_interrupt); - err = parse_dispatch_command(conn, cmd, &pwd, batchmode); + err = parse_dispatch_command(conn, cmd, &remote_path, + batchmode); if (err != 0) break; } - xfree(pwd); + xfree(remote_path); xfree(conn); #ifdef USE_LIBEDIT @@ -1647,9 +2027,11 @@ connect_to_server(char *path, char **args, int *in, int *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 + * kill it too. Contrawise, since sftp sends SIGTERMs to the + * underlying ssh, it must *not* ignore that signal. */ signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_DFL); execvp(path, args); fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); _exit(1); @@ -1668,12 +2050,16 @@ 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" + "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" + " [-D sftp_server_path] [-F ssh_config] " + "[-i identity_file]\n" + " [-o ssh_option] [-P port] [-R num_requests] " + "[-S program]\n" + " [-s subsystem | sftp_server] host\n" " %s [user@]host[:file ...]\n" " %s [user@]host[:dir[/]]\n" - " %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname); + " %s -b batchfile [user@]host\n", + __progname, __progname, __progname, __progname); exit(1); } @@ -1681,7 +2067,7 @@ int main(int argc, char **argv) { int in, out, ch, err; - char *host, *userhost, *cp, *file2 = NULL; + char *host = NULL, *userhost, *cp, *file2 = NULL; int debug_level = 0, sshver = 2; char *file1 = NULL, *sftp_server = NULL; char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; @@ -1689,6 +2075,9 @@ main(int argc, char **argv) arglist args; extern int optind; extern char *optarg; + struct sftp_conn *conn; + size_t copy_buffer_len = DEFAULT_COPY_BUFLEN; + size_t num_requests = DEFAULT_NUM_REQUESTS; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); @@ -1705,10 +2094,29 @@ main(int argc, char **argv) ll = SYSLOG_LEVEL_INFO; infile = stdin; - while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { + while ((ch = getopt(argc, argv, + "1246hpqrvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) { switch (ch) { + /* Passed through to ssh(1) */ + case '4': + case '6': case 'C': - addargs(&args, "-C"); + addargs(&args, "-%c", ch); + break; + /* Passed through to ssh(1) with argument */ + case 'F': + case 'c': + case 'i': + case 'o': + addargs(&args, "-%c", ch); + addargs(&args, "%s", optarg); + break; + case 'q': + showprogress = 0; + addargs(&args, "-%c", ch); + break; + case 'P': + addargs(&args, "-oPort %s", optarg); break; case 'v': if (debug_level < 3) { @@ -1717,21 +2125,18 @@ main(int argc, char **argv) } 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; + case '2': + sshver = 2; break; - case 'S': - ssh_program = optarg; - replacearg(&args, 0, "%s", ssh_program); + case 'B': + copy_buffer_len = strtol(optarg, &cp, 10); + if (copy_buffer_len == 0 || *cp != '\0') + fatal("Invalid buffer size \"%s\"", optarg); break; case 'b': if (batchmode) @@ -1745,13 +2150,14 @@ main(int argc, char **argv) batchmode = 1; addargs(&args, "-obatchmode yes"); break; - case 'P': + case 'p': + global_pflag = 1; + break; + case 'D': 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); + case 'r': + global_rflag = 1; break; case 'R': num_requests = strtol(optarg, &cp, 10); @@ -1759,6 +2165,13 @@ main(int argc, char **argv) fatal("Invalid number of requests \"%s\"", optarg); break; + case 's': + sftp_server = optarg; + break; + case 'S': + ssh_program = optarg; + replacearg(&args, 0, "%s", ssh_program); + break; case 'h': default: usage(); @@ -1785,7 +2198,8 @@ main(int argc, char **argv) fprintf(stderr, "Missing username\n"); usage(); } - addargs(&args, "-l%s", userhost); + addargs(&args, "-l"); + addargs(&args, "%s", userhost); } if ((cp = colon(host)) != NULL) { @@ -1805,24 +2219,32 @@ main(int argc, char **argv) if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) addargs(&args, "-s"); + addargs(&args, "--"); addargs(&args, "%s", host); addargs(&args, "%s", (sftp_server != NULL ? sftp_server : "sftp")); - 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); + conn = do_init(in, out, copy_buffer_len, num_requests); + if (conn == NULL) + fatal("Couldn't initialise connection to server"); + + if (!batchmode) { + if (sftp_direct == NULL) + fprintf(stderr, "Connected to %s.\n", host); + else + fprintf(stderr, "Attached to %s.\n", sftp_direct); + } + + err = interactive_loop(conn, file1, file2); #if !defined(USE_PIPES) shutdown(in, SHUT_RDWR); diff --git a/crypto/openssh/ssh-add.1 b/crypto/openssh/ssh-add.1 index 464070ec5..1eb34f33d 100644 --- a/crypto/openssh/ssh-add.1 +++ b/crypto/openssh/ssh-add.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-add.1,v 1.46 2007/06/12 13:41:03 jmc Exp $ +.\" $OpenBSD: ssh-add.1,v 1.52 2010/03/05 10:28:21 djm Exp $ .\" .\" -*- nroff -*- .\" @@ -37,7 +37,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd June 12 2007 +.Dd March 5 2010 .Dt SSH-ADD 1 .Os .Sh NAME @@ -49,9 +49,9 @@ .Op Fl t Ar life .Op Ar .Nm ssh-add -.Fl s Ar reader +.Fl s Ar pkcs11 .Nm ssh-add -.Fl e Ar reader +.Fl e Ar pkcs11 .Sh DESCRIPTION .Nm adds RSA or DSA identities to the authentication agent, @@ -61,7 +61,14 @@ When run without arguments, it adds the files .Pa ~/.ssh/id_dsa and .Pa ~/.ssh/identity . +After loading a private key, +.Nm +will try to load corresponding certificate information from the +filename obtained by appending +.Pa -cert.pub +to the name of the private key file. Alternative file names can be given on the command line. +.Pp If any file requires a passphrase, .Nm asks for the passphrase from the user. @@ -101,17 +108,17 @@ If no public key is found at a given path, will append .Pa .pub and retry. -.It Fl e Ar reader -Remove key in smartcard -.Ar reader . +.It Fl e Ar pkcs11 +Remove keys provided by the PKCS#11 shared library +.Ar pkcs11 . .It Fl L Lists public key parameters of all identities currently represented by the agent. .It Fl l Lists fingerprints of all identities currently represented by the agent. -.It Fl s Ar reader -Add key in smartcard -.Ar reader . +.It Fl s Ar pkcs11 +Add keys provided by the PKCS#11 shared library +.Ar pkcs11 . .It Fl t Ar life Set a maximum lifetime when adding identities to an agent. The lifetime may be specified in seconds or in a time format @@ -148,8 +155,9 @@ 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. +Identifies the path of a +.Ux Ns -domain +socket used to communicate with the agent. .El .Sh FILES .Bl -tag -width Ds diff --git a/crypto/openssh/ssh-add.c b/crypto/openssh/ssh-add.c index 7a43282f2..ad9f7a83e 100644 --- a/crypto/openssh/ssh-add.c +++ b/crypto/openssh/ssh-add.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-add.c,v 1.90 2007/09/09 11:38:01 sobrado Exp $ */ +/* $OpenBSD: ssh-add.c,v 1.94 2010/03/01 11:07:06 otto Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -138,9 +138,9 @@ delete_all(AuthenticationConnection *ac) static int add_file(AuthenticationConnection *ac, const char *filename) { - Key *private; + Key *private, *cert; char *comment = NULL; - char msg[1024]; + char msg[1024], *certpath; int fd, perms_ok, ret = -1; if ((fd = open(filename, O_RDONLY)) < 0) { @@ -195,13 +195,37 @@ add_file(AuthenticationConnection *ac, const char *filename) 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); } + + /* Now try to add the certificate flavour too */ + xasprintf(&certpath, "%s-cert.pub", filename); + if ((cert = key_load_public(certpath, NULL)) != NULL) { + /* Graft with private bits */ + if (key_to_certified(private) != 0) + fatal("%s: key_to_certified failed", __func__); + key_cert_copy(cert, private); + key_free(cert); + + if (ssh_add_identity_constrained(ac, private, comment, + lifetime, confirm)) { + fprintf(stderr, "Certificate added: %s (%s)\n", + certpath, private->cert->key_id); + if (lifetime != 0) + fprintf(stderr, "Lifetime set to %d seconds\n", + lifetime); + if (confirm != 0) + fprintf(stderr, "The user has to confirm each " + "use of the key\n"); + } else { + error("Certificate %s (%s) add failed", certpath, + private->cert->key_id); + } + } + + xfree(certpath); xfree(comment); key_free(private); @@ -214,7 +238,7 @@ update_card(AuthenticationConnection *ac, int add, const char *id) char *pin; int ret = -1; - pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); + pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN); if (pin == NULL) return -1; @@ -320,10 +344,8 @@ usage(void) 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 + fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n"); + fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n"); } int @@ -332,7 +354,7 @@ main(int argc, char **argv) extern char *optarg; extern int optind; AuthenticationConnection *ac = NULL; - char *sc_reader_id = NULL; + char *pkcs11provider = NULL; int i, ch, deleting = 0, ret = 0; /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ @@ -374,11 +396,11 @@ main(int argc, char **argv) ret = 1; goto done; case 's': - sc_reader_id = optarg; + pkcs11provider = optarg; break; case 'e': deleting = 1; - sc_reader_id = optarg; + pkcs11provider = optarg; break; case 't': if ((lifetime = convtime(optarg)) == -1) { @@ -395,8 +417,8 @@ main(int argc, char **argv) } argc -= optind; argv += optind; - if (sc_reader_id != NULL) { - if (update_card(ac, !deleting, sc_reader_id) == -1) + if (pkcs11provider != NULL) { + if (update_card(ac, !deleting, pkcs11provider) == -1) ret = 1; goto done; } diff --git a/crypto/openssh/ssh-agent.1 b/crypto/openssh/ssh-agent.1 index 7ce9dc2ba..5bcfd8f61 100644 --- a/crypto/openssh/ssh-agent.1 +++ b/crypto/openssh/ssh-agent.1 @@ -1,4 +1,5 @@ -.\" $OpenBSD: ssh-agent.1,v 1.46 2007/09/09 11:38:01 sobrado Exp $ +.\" $OpenBSD: ssh-agent.1,v 1.50 2010/01/17 21:49:09 tedu Exp $ +.\" $FreeBSD$ .\" .\" Author: Tatu Ylonen .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -34,7 +35,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd June 5 2007 +.Dd January 17 2010 .Dt SSH-AGENT 1 .Os .Sh NAME @@ -67,7 +68,9 @@ machines using The options are as follows: .Bl -tag -width Ds .It Fl a Ar bind_address -Bind the agent to the unix-domain socket +Bind the agent to the +.Ux Ns -domain +socket .Ar bind_address . The default is .Pa /tmp/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt . @@ -117,8 +120,9 @@ 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). +asks for the passphrase on the terminal if it has one or from a small X11 +program if running under X11. +If neither of these is the case then the authentication will fail. It then sends the identity to the agent. Several identities can be stored in the agent; the agent can automatically use any of these identities. @@ -141,7 +145,7 @@ 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 evalled in the calling shell, eg +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 @@ -162,8 +166,9 @@ 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 +A +.Ux Ns -domain +socket is created and the name of this socket is stored in the .Ev SSH_AUTH_SOCK environment variable. @@ -186,8 +191,8 @@ 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. +.Ux Ns -domain +sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El diff --git a/crypto/openssh/ssh-agent.c b/crypto/openssh/ssh-agent.c index ef62f196b..320591bf9 100644 --- a/crypto/openssh/ssh-agent.c +++ b/crypto/openssh/ssh-agent.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-agent.c,v 1.159 2008/06/28 14:05:15 djm Exp $ */ +/* $OpenBSD: ssh-agent.c,v 1.165 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -77,8 +77,8 @@ __RCSID("$FreeBSD$"); #include "log.h" #include "misc.h" -#ifdef SMARTCARD -#include "scard.h" +#ifdef ENABLE_PKCS11 +#include "ssh-pkcs11.h" #endif #if defined(HAVE_SYS_PRCTL_H) @@ -106,6 +106,7 @@ typedef struct identity { TAILQ_ENTRY(identity) next; Key *key; char *comment; + char *provider; u_int death; u_int confirm; } Identity; @@ -172,6 +173,8 @@ static void free_identity(Identity *id) { key_free(id->key); + if (id->provider != NULL) + xfree(id->provider); xfree(id->comment); xfree(id); } @@ -466,6 +469,8 @@ process_add_identity(SocketEntry *e, int version) int type, success = 0, death = 0, confirm = 0; char *type_name, *comment; Key *k = NULL; + u_char *cert; + u_int len; switch (version) { case 1: @@ -496,6 +501,14 @@ process_add_identity(SocketEntry *e, int version) buffer_get_bignum2(&e->request, k->dsa->pub_key); buffer_get_bignum2(&e->request, k->dsa->priv_key); break; + case KEY_DSA_CERT: + cert = buffer_get_string(&e->request, &len); + if ((k = key_from_blob(cert, len)) == NULL) + fatal("Certificate parse failed"); + xfree(cert); + key_add_private(k); + buffer_get_bignum2(&e->request, k->dsa->priv_key); + break; case KEY_RSA: k = key_new_private(type); buffer_get_bignum2(&e->request, k->rsa->n); @@ -508,6 +521,17 @@ process_add_identity(SocketEntry *e, int version) /* Generate additional parameters */ rsa_generate_additional_parameters(k->rsa); break; + case KEY_RSA_CERT: + cert = buffer_get_string(&e->request, &len); + if ((k = key_from_blob(cert, len)) == NULL) + fatal("Certificate parse failed"); + xfree(cert); + key_add_private(k); + buffer_get_bignum2(&e->request, k->rsa->d); + buffer_get_bignum2(&e->request, k->rsa->iqmp); + buffer_get_bignum2(&e->request, k->rsa->p); + buffer_get_bignum2(&e->request, k->rsa->q); + break; default: buffer_clear(&e->request); goto send; @@ -517,6 +541,7 @@ process_add_identity(SocketEntry *e, int version) /* enable blinding */ switch (k->type) { case KEY_RSA: + case KEY_RSA_CERT: case KEY_RSA1: if (RSA_blinding_on(k->rsa, NULL) != 1) { error("process_add_identity: RSA_blinding_on failed"); @@ -550,7 +575,7 @@ process_add_identity(SocketEntry *e, int version) if (lifetime && !death) death = time(NULL) + lifetime; if ((id = lookup_identity(k, version)) == NULL) { - id = xmalloc(sizeof(Identity)); + id = xcalloc(1, sizeof(Identity)); id->key = k; TAILQ_INSERT_TAIL(&tab->idlist, id, next); /* Increment the number of identities. */ @@ -610,17 +635,17 @@ no_identities(SocketEntry *e, u_int type) buffer_free(&msg); } -#ifdef SMARTCARD +#ifdef ENABLE_PKCS11 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; + char *provider = NULL, *pin; + int i, type, version, count = 0, success = 0, death = 0, confirm = 0; + Key **keys = NULL, *k; Identity *id; Idtab *tab; - sc_reader_id = buffer_get_string(&e->request, NULL); + provider = buffer_get_string(&e->request, NULL); pin = buffer_get_string(&e->request, NULL); while (buffer_len(&e->request)) { @@ -634,30 +659,22 @@ process_add_smartcard_key(SocketEntry *e) 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++) { + count = pkcs11_add_provider(provider, pin, &keys); + for (i = 0; i < count; i++) { k = keys[i]; version = k->type == KEY_RSA1 ? 1 : 2; tab = idtab_lookup(version); if (lookup_identity(k, version) == NULL) { - id = xmalloc(sizeof(Identity)); + id = xcalloc(1, sizeof(Identity)); id->key = k; - id->comment = sc_get_key_label(k); + id->provider = xstrdup(provider); + id->comment = xstrdup(provider); /* XXX */ id->death = death; id->confirm = confirm; TAILQ_INSERT_TAIL(&tab->idlist, id, next); @@ -668,8 +685,13 @@ process_add_smartcard_key(SocketEntry *e) } keys[i] = NULL; } - xfree(keys); send: + if (pin) + xfree(pin); + if (provider) + xfree(provider); + if (keys) + xfree(keys); buffer_put_int(&e->output, 1); buffer_put_char(&e->output, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); @@ -678,42 +700,37 @@ send: 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; + char *provider = NULL, *pin = NULL; + int version, success = 0; + Identity *id, *nxt; Idtab *tab; - sc_reader_id = buffer_get_string(&e->request, NULL); + provider = 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; + for (version = 1; version < 3; version++) { + tab = idtab_lookup(version); + for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { + nxt = TAILQ_NEXT(id, next); + if (!strcmp(provider, id->provider)) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + tab->nentries--; + } } - key_free(k); - keys[i] = NULL; } - xfree(keys); -send: + if (pkcs11_del_provider(provider) == 0) + success = 1; + else + error("process_remove_smartcard_key:" + " pkcs11_del_provider failed"); + xfree(provider); buffer_put_int(&e->output, 1); buffer_put_char(&e->output, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); } -#endif /* SMARTCARD */ +#endif /* ENABLE_PKCS11 */ /* dispatch incoming messages */ @@ -798,7 +815,7 @@ process_message(SocketEntry *e) case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: process_remove_all_identities(e, 2); break; -#ifdef SMARTCARD +#ifdef ENABLE_PKCS11 case SSH_AGENTC_ADD_SMARTCARD_KEY: case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: process_add_smartcard_key(e); @@ -806,7 +823,7 @@ process_message(SocketEntry *e) case SSH_AGENTC_REMOVE_SMARTCARD_KEY: process_remove_smartcard_key(e); break; -#endif /* SMARTCARD */ +#endif /* ENABLE_PKCS11 */ default: /* Unknown message. Respond with failure. */ error("Unknown message %d", type); @@ -920,11 +937,11 @@ after_select(fd_set *readset, fd_set *writeset) socklen_t slen; char buf[1024]; int len, sock; - u_int i; + u_int i, orig_alloc; uid_t euid; gid_t egid; - for (i = 0; i < sockets_alloc; i++) + for (i = 0, orig_alloc = sockets_alloc; i < orig_alloc; i++) switch (sockets[i].type) { case AUTH_UNUSED: break; @@ -957,16 +974,13 @@ after_select(fd_set *readset, fd_set *writeset) 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); + len = write(sockets[i].fd, + buffer_ptr(&sockets[i].output), + buffer_len(&sockets[i].output)); + if (len == -1 && (errno == EAGAIN || + errno == EWOULDBLOCK || + errno == EINTR)) + continue; if (len <= 0) { close_socket(&sockets[i]); break; @@ -974,14 +988,11 @@ after_select(fd_set *readset, fd_set *writeset) 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); + len = read(sockets[i].fd, buf, sizeof(buf)); + if (len == -1 && (errno == EAGAIN || + errno == EWOULDBLOCK || + errno == EINTR)) + continue; if (len <= 0) { close_socket(&sockets[i]); break; @@ -1016,6 +1027,9 @@ static void cleanup_handler(int sig) { cleanup_socket(); +#ifdef ENABLE_PKCS11 + pkcs11_terminate(); +#endif _exit(2); } @@ -1062,6 +1076,7 @@ main(int ac, char **av) 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(); @@ -1123,8 +1138,8 @@ main(int ac, char **av) if (ac == 0 && !c_flag && !s_flag) { shell = getenv("SHELL"); - if (shell != NULL && - strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) + if (shell != NULL && (len = strlen(shell)) > 2 && + strncmp(shell + len - 3, "csh", 3) == 0) c_flag = 1; } if (k_flag) { @@ -1262,6 +1277,10 @@ main(int ac, char **av) #endif skip: + +#ifdef ENABLE_PKCS11 + pkcs11_init(0); +#endif new_socket(AUTH_SOCKET, sock); if (ac > 0) parent_alive_interval = 10; diff --git a/crypto/openssh/ssh-dss.c b/crypto/openssh/ssh-dss.c index 51a06e98f..449f493b4 100644 --- a/crypto/openssh/ssh-dss.c +++ b/crypto/openssh/ssh-dss.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-dss.c,v 1.24 2006/11/06 21:25:28 markus Exp $ */ +/* $OpenBSD: ssh-dss.c,v 1.25 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -53,7 +53,9 @@ ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, u_int rlen, slen, len, dlen; Buffer b; - if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + if (key == NULL || + (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || + key->dsa == NULL) { error("ssh_dss_sign: no DSA key"); return -1; } @@ -116,7 +118,9 @@ ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, int rlen, ret; Buffer b; - if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + if (key == NULL || + (key->type != KEY_DSA && key->type != KEY_DSA_CERT) || + key->dsa == NULL) { error("ssh_dss_verify: no DSA key"); return -1; } diff --git a/crypto/openssh/ssh-keygen.1 b/crypto/openssh/ssh-keygen.1 index 4247ea13e..0da6354d3 100644 --- a/crypto/openssh/ssh-keygen.1 +++ b/crypto/openssh/ssh-keygen.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keygen.1,v 1.79 2008/07/24 23:55:30 sthen Exp $ +.\" $OpenBSD: ssh-keygen.1,v 1.88 2010/03/08 00:28:55 djm Exp $ .\" $FreeBSD$ .\" .\" -*- nroff -*- @@ -38,7 +38,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd July 24 2008 +.Dd March 8 2010 .Dt SSH-KEYGEN 1 .Os .Sh NAME @@ -53,7 +53,6 @@ .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 @@ -80,7 +79,7 @@ .Fl B .Op Fl f Ar input_keyfile .Nm ssh-keygen -.Fl D Ar reader +.Fl D Ar pkcs11 .Nm ssh-keygen .Fl F Ar hostname .Op Fl f Ar known_hosts_file @@ -92,9 +91,6 @@ .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 @@ -110,6 +106,18 @@ .Op Fl v .Op Fl a Ar num_trials .Op Fl W Ar generator +.Nm ssh-keygen +.Fl s Ar ca_key +.Fl I Ar certificate_identity +.Op Fl h +.Op Fl n Ar principals +.Op Fl O Ar constraint +.Op Fl V Ar validity_interval +.Ar +.Nm ssh-keygen +.Fl L +.Op Fl f Ar input_keyfile +.Ek .Sh DESCRIPTION .Nm generates, manages and converts authentication keys for @@ -202,9 +210,9 @@ 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 D Ar pkcs11 +Download the RSA public keys provided by the PKCS#11 shared library +.Ar pkcs11 . .It Fl e This option will read a private or public OpenSSH key file and print the key in @@ -249,6 +257,17 @@ but they do not reveal identifying information should the file's contents be disclosed. This option will not modify existing hashed hostnames and is therefore safe to use on files that mix hashed and non-hashed names. +.It Fl h +When signing a key, create a host certificate instead of a user +certificate. +Please see the +.Sx CERTIFICATES +section for details. +.It Fl I Ar certificate_identity +Specify the key identity when signing a public key. +Please see the +.Sx CERTIFICATES +section for details. .It Fl i This option will read an unencrypted private (or public) key file in SSH2-compatible format and print an OpenSSH compatible private @@ -258,6 +277,8 @@ also reads the RFC 4716 SSH Public Key File Format. This option allows importing keys from several commercial SSH implementations. +.It Fl L +Prints the contents of a certificate. .It Fl l Show fingerprint of specified public key file. Private RSA1 keys are also supported. @@ -272,6 +293,71 @@ 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 n Ar principals +Specify one or more principals (user or host names) to be included in +a certificate when signing a key. +Multiple principals may be specified, separated by commas. +Please see the +.Sx CERTIFICATES +section for details. +.It Fl O Ar constraint +Specify a certificate constraint when signing a key. +This option may be specified multiple times. +Please see the +.Sx CERTIFICATES +section for details. +The constraints that are valid for user certificates are: +.Bl -tag -width Ds +.It Ic no-x11-forwarding +Disable X11 forwarding (permitted by default). +.It Ic no-agent-forwarding +Disable +.Xr ssh-agent 1 +forwarding (permitted by default). +.It Ic no-port-forwarding +Disable port forwarding (permitted by default). +.It Ic no-pty +Disable PTY allocation (permitted by default). +.It Ic no-user-rc +Disable execution of +.Pa ~/.ssh/rc +by +.Xr sshd 8 +(permitted by default). +.It Ic clear +Clear all enabled permissions. +This is useful for clearing the default set of permissions so permissions may +be added individually. +.It Ic permit-x11-forwarding +Allows X11 forwarding. +.It Ic permit-agent-forwarding +Allows +.Xr ssh-agent 1 +forwarding. +.It Ic permit-port-forwarding +Allows port forwarding. +.It Ic permit-pty +Allows PTY allocation. +.It Ic permit-user-rc +Allows execution of +.Pa ~/.ssh/rc +by +.Xr sshd 8 . +.It Ic force-command=command +Forces the execution of +.Ar command +instead of any shell or command specified by the user when +the certificate is used for authentication. +.It Ic source-address=address_list +Restrict the source addresses from which the certificate is considered valid +from. +The +.Ar address_list +is a comma-separated list of one or more address/netmask pairs in CIDR +format. +.El +.Pp +At present, no constraints are valid for host keys. .It Fl P Ar passphrase Provides the (old) passphrase. .It Fl p @@ -301,6 +387,11 @@ Print the SSHFP fingerprint resource record named for the specified public key file. .It Fl S Ar start Specify start point (in hex) when generating candidate moduli for DH-GEX. +.It Fl s Ar ca_key +Certify (sign) a public key using the specified CA key. +Please see the +.Sx CERTIFICATES +section for details. .It Fl T Ar output_file Test DH group exchange candidate primes (generated using the .Fl G @@ -314,9 +405,29 @@ for protocol version 1 and 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 Ar validity_interval +Specify a validity interval when signing a certificate. +A validity interval may consist of a single time, indicating that the +certificate is valid beginning now and expiring at that time, or may consist +of two times separated by a colon to indicate an explicit time interval. +The start time may be specified as a date in YYYYMMDD format, a time +in YYYYMMDDHHMMSS format or a relative time (to the current time) consisting +of a minus sign followed by a relative time in the format described in the +.Sx TIME FORMATS +section of +.Xr ssh_config 5 . +The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMMSS time or +a relative time starting with a plus character. +.Pp +For example: +.Dq +52w1d +(valid from now to 52 weeks and one day from now), +.Dq -4w:+4w +(valid from four weeks ago to four weeks from now), +.Dq 20100101123000:20110101123000 +(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011), +.Dq -1d:20110101 +(valid from yesterday to midnight, January 1st, 2011). .It Fl v Verbose mode. Causes @@ -387,6 +498,73 @@ Screened DH groups may be installed in .Pa /etc/moduli . It is important that this file contains moduli of a range of bit lengths and that both ends of a connection share common moduli. +.Sh CERTIFICATES +.Nm +supports signing of keys to produce certificates that may be used for +user or host authentication. +Certificates consist of a public key, some identity information, zero or +more principal (user or host) names and an optional set of constraints that +are signed by a Certification Authority (CA) key. +Clients or servers may then trust only the CA key and verify its signature +on a certificate rather than trusting many user/host keys. +Note that OpenSSH certificates are a different, and much simpler, format to +the X.509 certificates used in +.Xr ssl 8 . +.Pp +.Nm +supports two types of certificates: user and host. +User certificates authenticate users to servers, whereas host certificates +authenticate server hosts to users. +To generate a user certificate: +.Pp +.Dl $ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub +.Pp +The resultant certificate will be placed in +.Pa /path/to/user_key_cert.pub . +A host certificate requires the +.Fl h +option: +.Pp +.Dl $ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub +.Pp +The host certificate will be output to +.Pa /path/to/host_key_cert.pub . +In both cases, +.Ar key_id +is a "key identifier" that is logged by the server when the certificate +is used for authentication. +.Pp +Certificates may be limited to be valid for a set of principal (user/host) +names. +By default, generated certificates are valid for all users or hosts. +To generate a certificate for a specified set of principals: +.Pp +.Dl $ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub +.Dl $ ssh-keygen -s ca_key -I key_id -h -n host.domain user_key.pub +.Pp +Additional limitations on the validity and use of user certificates may +be specified through certificate constraints. +A constrained certificate may disable features of the SSH session, may be +valid only when presented from particular source addresses or may +force the use of a specific command. +For a list of valid certificate constraints, see the documentation for the +.Fl O +option above. +.Pp +Finally, certificates may be defined with a validity lifetime. +The +.Fl V +option allows specification of certificate start and end times. +A certificate that is presented at a time outside this range will not be +considered valid. +By default, certificates have a maximum validity interval. +.Pp +For certificates to be used for user or host authentication, the CA +public key must be trusted by +.Xr sshd 8 +or +.Xr ssh 1 . +Please refer to those manual pages for details. .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/identity @@ -394,7 +572,7 @@ 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. +used to encrypt the private part of this file using 128-bit AES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. @@ -412,7 +590,7 @@ 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. +used to encrypt the private part of this file using 128-bit AES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. @@ -430,7 +608,7 @@ 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. +used to encrypt the private part of this file using 128-bit AES. This file is not automatically accessed by .Nm but it is offered as the default file for the private key. diff --git a/crypto/openssh/ssh-keygen.c b/crypto/openssh/ssh-keygen.c index 5765cff08..dd662c907 100644 --- a/crypto/openssh/ssh-keygen.c +++ b/crypto/openssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.173 2009/02/21 19:32:04 tobias Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.184 2010/03/07 22:16:01 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -48,9 +48,10 @@ #include "match.h" #include "hostfile.h" #include "dns.h" +#include "ssh2.h" -#ifdef SMARTCARD -#include "scard.h" +#ifdef ENABLE_PKCS11 +#include "ssh-pkcs11.h" #endif /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ @@ -81,6 +82,9 @@ int find_host = 0; /* Flag indicating that we want to delete a host from a known_hosts file */ int delete_host = 0; +/* Flag indicating that we want to show the contents of a certificate */ +int show_cert = 0; + /* Flag indicating that we just want to see the key fingerprint */ int print_fingerprint = 0; int print_bubblebabble = 0; @@ -98,6 +102,35 @@ char *identity_new_passphrase = NULL; /* This is set to the new comment if given on the command line. */ char *identity_comment = NULL; +/* Path to CA key when certifying keys. */ +char *ca_key_path = NULL; + +/* Key type when certifying */ +u_int cert_key_type = SSH2_CERT_TYPE_USER; + +/* "key ID" of signed key */ +char *cert_key_id = NULL; + +/* Comma-separated list of principal names for certifying keys */ +char *cert_principals = NULL; + +/* Validity period for certificates */ +u_int64_t cert_valid_from = 0; +u_int64_t cert_valid_to = ~0ULL; + +/* Certificate constraints */ +#define CONSTRAINT_X_FWD (1) +#define CONSTRAINT_AGENT_FWD (1<<1) +#define CONSTRAINT_PORT_FWD (1<<2) +#define CONSTRAINT_PTY (1<<3) +#define CONSTRAINT_USER_RC (1<<4) +#define CONSTRAINT_DEFAULT (CONSTRAINT_X_FWD|CONSTRAINT_AGENT_FWD| \ + CONSTRAINT_PORT_FWD|CONSTRAINT_PTY| \ + CONSTRAINT_USER_RC) +u_int32_t constraint_flags = CONSTRAINT_DEFAULT; +char *constraint_command = NULL; +char *constraint_src_addr = 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; @@ -181,6 +214,7 @@ do_convert_to_ssh2(struct passwd *pw) Key *k; u_int len; u_char *blob; + char comment[61]; struct stat st; if (!have_identity) @@ -203,11 +237,14 @@ do_convert_to_ssh2(struct passwd *pw) 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", + /* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ + snprintf(comment, sizeof(comment), + "%u-bit %s, converted by %s@%s from OpenSSH", key_size(k), key_type(k), pw->pw_name, hostname); + + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); + fprintf(stdout, "Comment: \"%s\"\n", comment); dump_base64(stdout, blob, len); fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); key_free(k); @@ -455,51 +492,29 @@ do_print_public(struct passwd *pw) 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) +do_download(struct passwd *pw, char *pkcs11provider) { +#ifdef ENABLE_PKCS11 Key **keys = NULL; - int i; + int i, nkeys; - keys = sc_get_keys(sc_reader_id, NULL); - if (keys == NULL) - fatal("cannot read public key from smartcard"); - for (i = 0; keys[i]; i++) { + pkcs11_init(0); + nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys); + if (nkeys <= 0) + fatal("cannot read public key from pkcs11"); + for (i = 0; i < nkeys; i++) { key_write(keys[i], stdout); key_free(keys[i]); fprintf(stdout, "\n"); } xfree(keys); + pkcs11_terminate(); exit(0); +#else + fatal("no pkcs11 support"); +#endif /* ENABLE_PKCS11 */ } -#endif /* SMARTCARD */ static void do_fingerprint(struct passwd *pw) @@ -524,7 +539,7 @@ do_fingerprint(struct passwd *pw) public = key_load_public(identity_file, &comment); if (public != NULL) { fp = key_fingerprint(public, fptype, rep); - ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); + ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, comment, key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) @@ -589,7 +604,7 @@ do_fingerprint(struct passwd *pw) } comment = *cp ? cp : comment; fp = key_fingerprint(public, fptype, rep); - ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART); + ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, comment ? comment : "no comment", key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) @@ -609,7 +624,7 @@ do_fingerprint(struct passwd *pw) } static void -print_host(FILE *f, const char *name, Key *public, int hash) +printhost(FILE *f, const char *name, Key *public, int ca, int hash) { if (print_fingerprint) { enum fp_rep rep; @@ -619,7 +634,7 @@ print_host(FILE *f, const char *name, Key *public, int hash) 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); + ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, name, key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) @@ -629,7 +644,7 @@ print_host(FILE *f, const char *name, Key *public, int hash) } else { if (hash && (name = host_hash(name, NULL, 0)) == NULL) fatal("hash_host failed"); - fprintf(f, "%s ", name); + fprintf(f, "%s%s%s ", ca ? CA_MARKER : "", ca ? " " : "", name); if (!key_write(public, f)) fatal("key_write failed"); fprintf(f, "\n"); @@ -640,10 +655,11 @@ static void do_known_hosts(struct passwd *pw, const char *name) { FILE *in, *out = stdout; - Key *public; + Key *pub; char *cp, *cp2, *kp, *kp2; char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; + int ca; if (!have_identity) { cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); @@ -699,9 +715,19 @@ do_known_hosts(struct passwd *pw, const char *name) fprintf(out, "%s\n", cp); continue; } + /* Check whether this is a CA key */ + if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && + (cp[sizeof(CA_MARKER) - 1] == ' ' || + cp[sizeof(CA_MARKER) - 1] == '\t')) { + ca = 1; + cp += sizeof(CA_MARKER); + } else + ca = 0; + /* Find the end of the host name portion. */ for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) ; + if (*kp == '\0' || *(kp + 1) == '\0') { error("line %d missing key: %.40s...", num, line); @@ -711,15 +737,15 @@ do_known_hosts(struct passwd *pw, const char *name) *kp++ = '\0'; kp2 = kp; - public = key_new(KEY_RSA1); - if (key_read(public, &kp) != 1) { + pub = key_new(KEY_RSA1); + if (key_read(pub, &kp) != 1) { kp = kp2; - key_free(public); - public = key_new(KEY_UNSPEC); - if (key_read(public, &kp) != 1) { + key_free(pub); + pub = key_new(KEY_UNSPEC); + if (key_read(pub, &kp) != 1) { error("line %d invalid key: %.40s...", num, line); - key_free(public); + key_free(pub); invalid = 1; continue; } @@ -737,43 +763,52 @@ do_known_hosts(struct passwd *pw, const char *name) 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); + "line %d type %s%s\n", name, + num, key_type(pub), + ca ? " (CA key)" : ""); + printhost(out, cp, pub, ca, 0); } - if (delete_host && !c) - print_host(out, cp, public, 0); + if (delete_host && !c && !ca) + printhost(out, cp, pub, ca, 0); } else if (hash_hosts) - print_host(out, cp, public, 0); + printhost(out, cp, pub, ca, 0); } else { if (find_host || delete_host) { c = (match_hostname(name, cp, strlen(cp)) == 1); if (find_host && c) { printf("# Host %s found: " - "line %d type %s\n", name, - num, key_type(public)); - print_host(out, name, public, - hash_hosts); + "line %d type %s%s\n", name, + num, key_type(pub), + ca ? " (CA key)" : ""); + printhost(out, name, pub, + ca, hash_hosts && !ca); } - if (delete_host && !c) - print_host(out, cp, public, 0); + if (delete_host && !c && !ca) + printhost(out, cp, pub, ca, 0); } else if (hash_hosts) { for (cp2 = strsep(&cp, ","); cp2 != NULL && *cp2 != '\0'; cp2 = strsep(&cp, ",")) { - if (strcspn(cp2, "*?!") != strlen(cp2)) + if (ca) { + fprintf(stderr, "Warning: " + "ignoring CA key for host: " + "%.64s\n", cp2); + printhost(out, cp2, pub, ca, 0); + } else if (strcspn(cp2, "*?!") != + strlen(cp2)) { fprintf(stderr, "Warning: " "ignoring host name with " "metacharacters: %.64s\n", cp2); - else - print_host(out, cp2, public, 1); + printhost(out, cp2, pub, ca, 0); + } else + printhost(out, cp2, pub, ca, 1); } has_unhashed = 1; } } - key_free(public); + key_free(pub); } fclose(in); @@ -1030,6 +1065,391 @@ do_change_comment(struct passwd *pw) exit(0); } +static const char * +fmt_validity(u_int64_t valid_from, u_int64_t valid_to) +{ + char from[32], to[32]; + static char ret[64]; + time_t tt; + struct tm *tm; + + *from = *to = '\0'; + if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) + return "forever"; + + if (valid_from != 0) { + /* XXX revisit INT_MAX in 2038 :) */ + tt = valid_from > INT_MAX ? INT_MAX : valid_from; + tm = localtime(&tt); + strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); + } + if (valid_to != 0xffffffffffffffffULL) { + /* XXX revisit INT_MAX in 2038 :) */ + tt = valid_to > INT_MAX ? INT_MAX : valid_to; + tm = localtime(&tt); + strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); + } + + if (valid_from == 0) { + snprintf(ret, sizeof(ret), "before %s", to); + return ret; + } + if (valid_to == 0xffffffffffffffffULL) { + snprintf(ret, sizeof(ret), "after %s", from); + return ret; + } + + snprintf(ret, sizeof(ret), "from %s to %s", from, to); + return ret; +} + +static void +add_flag_constraint(Buffer *c, const char *name) +{ + debug3("%s: %s", __func__, name); + buffer_put_cstring(c, name); + buffer_put_string(c, NULL, 0); +} + +static void +add_string_constraint(Buffer *c, const char *name, const char *value) +{ + Buffer b; + + debug3("%s: %s=%s", __func__, name, value); + buffer_init(&b); + buffer_put_cstring(&b, value); + + buffer_put_cstring(c, name); + buffer_put_string(c, buffer_ptr(&b), buffer_len(&b)); + + buffer_free(&b); +} + +static void +prepare_constraint_buf(Buffer *c) +{ + + buffer_clear(c); + if ((constraint_flags & CONSTRAINT_X_FWD) != 0) + add_flag_constraint(c, "permit-X11-forwarding"); + if ((constraint_flags & CONSTRAINT_AGENT_FWD) != 0) + add_flag_constraint(c, "permit-agent-forwarding"); + if ((constraint_flags & CONSTRAINT_PORT_FWD) != 0) + add_flag_constraint(c, "permit-port-forwarding"); + if ((constraint_flags & CONSTRAINT_PTY) != 0) + add_flag_constraint(c, "permit-pty"); + if ((constraint_flags & CONSTRAINT_USER_RC) != 0) + add_flag_constraint(c, "permit-user-rc"); + if (constraint_command != NULL) + add_string_constraint(c, "force-command", constraint_command); + if (constraint_src_addr != NULL) + add_string_constraint(c, "source-address", constraint_src_addr); +} + +static void +do_ca_sign(struct passwd *pw, int argc, char **argv) +{ + int i, fd; + u_int n; + Key *ca, *public; + char *otmp, *tmp, *cp, *out, *comment, **plist = NULL; + FILE *f; + + tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); + if ((ca = load_identity(tmp)) == NULL) + fatal("Couldn't load CA key \"%s\"", tmp); + xfree(tmp); + + for (i = 0; i < argc; i++) { + /* Split list of principals */ + n = 0; + if (cert_principals != NULL) { + otmp = tmp = xstrdup(cert_principals); + plist = NULL; + for (; (cp = strsep(&tmp, ",")) != NULL; n++) { + plist = xrealloc(plist, n + 1, sizeof(*plist)); + if (*(plist[n] = xstrdup(cp)) == '\0') + fatal("Empty principal name"); + } + xfree(otmp); + } + + tmp = tilde_expand_filename(argv[i], pw->pw_uid); + if ((public = key_load_public(tmp, &comment)) == NULL) + fatal("%s: unable to open \"%s\"", __func__, tmp); + if (public->type != KEY_RSA && public->type != KEY_DSA) + fatal("%s: key \"%s\" type %s cannot be certified", + __func__, tmp, key_type(public)); + + /* Prepare certificate to sign */ + if (key_to_certified(public) != 0) + fatal("Could not upgrade key %s to certificate", tmp); + public->cert->type = cert_key_type; + public->cert->key_id = xstrdup(cert_key_id); + public->cert->nprincipals = n; + public->cert->principals = plist; + public->cert->valid_after = cert_valid_from; + public->cert->valid_before = cert_valid_to; + prepare_constraint_buf(&public->cert->constraints); + public->cert->signature_key = key_from_private(ca); + + if (key_certify(public, ca) != 0) + fatal("Couldn't not certify key %s", tmp); + + if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) + *cp = '\0'; + xasprintf(&out, "%s-cert.pub", tmp); + xfree(tmp); + + if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) + fatal("Could not open \"%s\" for writing: %s", out, + strerror(errno)); + if ((f = fdopen(fd, "w")) == NULL) + fatal("%s: fdopen: %s", __func__, strerror(errno)); + if (!key_write(public, f)) + fatal("Could not write certified key to %s", out); + fprintf(f, " %s\n", comment); + fclose(f); + + if (!quiet) + logit("Signed %s key %s: id \"%s\"%s%s valid %s", + cert_key_type == SSH2_CERT_TYPE_USER?"user":"host", + out, cert_key_id, + cert_principals != NULL ? " for " : "", + cert_principals != NULL ? cert_principals : "", + fmt_validity(cert_valid_from, cert_valid_to)); + + key_free(public); + xfree(out); + } + exit(0); +} + +static u_int64_t +parse_relative_time(const char *s, time_t now) +{ + int64_t mul, secs; + + mul = *s == '-' ? -1 : 1; + + if ((secs = convtime(s + 1)) == -1) + fatal("Invalid relative certificate time %s", s); + if (mul == -1 && secs > now) + fatal("Certificate time %s cannot be represented", s); + return now + (u_int64_t)(secs * mul); +} + +static u_int64_t +parse_absolute_time(const char *s) +{ + struct tm tm; + time_t tt; + char buf[32], *fmt; + + /* + * POSIX strptime says "The application shall ensure that there + * is white-space or other non-alphanumeric characters between + * any two conversion specifications" so arrange things this way. + */ + switch (strlen(s)) { + case 8: + fmt = "%Y-%m-%d"; + snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); + break; + case 14: + fmt = "%Y-%m-%dT%H:%M:%S"; + snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2sT%.2s:%.2s:%.2s", + s, s + 4, s + 6, s + 8, s + 10, s + 12); + break; + default: + fatal("Invalid certificate time format %s", s); + } + + bzero(&tm, sizeof(tm)); + if (strptime(buf, fmt, &tm) == NULL) + fatal("Invalid certificate time %s", s); + if ((tt = mktime(&tm)) < 0) + fatal("Certificate time %s cannot be represented", s); + return (u_int64_t)tt; +} + +static void +parse_cert_times(char *timespec) +{ + char *from, *to; + time_t now = time(NULL); + int64_t secs; + + /* +timespec relative to now */ + if (*timespec == '+' && strchr(timespec, ':') == NULL) { + if ((secs = convtime(timespec + 1)) == -1) + fatal("Invalid relative certificate life %s", timespec); + cert_valid_to = now + secs; + /* + * Backdate certificate one minute to avoid problems on hosts + * with poorly-synchronised clocks. + */ + cert_valid_from = ((now - 59)/ 60) * 60; + return; + } + + /* + * from:to, where + * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS + * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS + */ + from = xstrdup(timespec); + to = strchr(from, ':'); + if (to == NULL || from == to || *(to + 1) == '\0') + fatal("Invalid certificate life specification %s", timespec); + *to++ = '\0'; + + if (*from == '-' || *from == '+') + cert_valid_from = parse_relative_time(from, now); + else + cert_valid_from = parse_absolute_time(from); + + if (*to == '-' || *to == '+') + cert_valid_to = parse_relative_time(to, cert_valid_from); + else + cert_valid_to = parse_absolute_time(to); + + if (cert_valid_to <= cert_valid_from) + fatal("Empty certificate validity interval"); + xfree(from); +} + +static void +add_cert_constraint(char *opt) +{ + char *val; + + if (strcmp(opt, "clear") == 0) + constraint_flags = 0; + else if (strcasecmp(opt, "no-x11-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_X_FWD; + else if (strcasecmp(opt, "permit-x11-forwarding") == 0) + constraint_flags |= CONSTRAINT_X_FWD; + else if (strcasecmp(opt, "no-agent-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_AGENT_FWD; + else if (strcasecmp(opt, "permit-agent-forwarding") == 0) + constraint_flags |= CONSTRAINT_AGENT_FWD; + else if (strcasecmp(opt, "no-port-forwarding") == 0) + constraint_flags &= ~CONSTRAINT_PORT_FWD; + else if (strcasecmp(opt, "permit-port-forwarding") == 0) + constraint_flags |= CONSTRAINT_PORT_FWD; + else if (strcasecmp(opt, "no-pty") == 0) + constraint_flags &= ~CONSTRAINT_PTY; + else if (strcasecmp(opt, "permit-pty") == 0) + constraint_flags |= CONSTRAINT_PTY; + else if (strcasecmp(opt, "no-user-rc") == 0) + constraint_flags &= ~CONSTRAINT_USER_RC; + else if (strcasecmp(opt, "permit-user-rc") == 0) + constraint_flags |= CONSTRAINT_USER_RC; + else if (strncasecmp(opt, "force-command=", 14) == 0) { + val = opt + 14; + if (*val == '\0') + fatal("Empty force-command constraint"); + if (constraint_command != NULL) + fatal("force-command already specified"); + constraint_command = xstrdup(val); + } else if (strncasecmp(opt, "source-address=", 15) == 0) { + val = opt + 15; + if (*val == '\0') + fatal("Empty source-address constraint"); + if (constraint_src_addr != NULL) + fatal("source-address already specified"); + if (addr_match_cidr_list(NULL, val) != 0) + fatal("Invalid source-address list"); + constraint_src_addr = xstrdup(val); + } else + fatal("Unsupported certificate constraint \"%s\"", opt); +} + +static void +do_show_cert(struct passwd *pw) +{ + Key *key; + struct stat st; + char *key_fp, *ca_fp; + Buffer constraints, constraint; + u_char *name, *data; + u_int i, dlen; + + 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 ((key = key_load_public(identity_file, NULL)) == NULL) + fatal("%s is not a public key", identity_file); + if (!key_is_cert(key)) + fatal("%s is not a certificate", identity_file); + + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + ca_fp = key_fingerprint(key->cert->signature_key, + SSH_FP_MD5, SSH_FP_HEX); + + printf("%s:\n", identity_file); + printf(" %s certificate %s\n", key_type(key), key_fp); + printf(" Signed by %s CA %s\n", + key_type(key->cert->signature_key), ca_fp); + printf(" Key ID \"%s\"\n", key->cert->key_id); + printf(" Valid: %s\n", + fmt_validity(key->cert->valid_after, key->cert->valid_before)); + printf(" Principals: "); + if (key->cert->nprincipals == 0) + printf("(none)\n"); + else { + for (i = 0; i < key->cert->nprincipals; i++) + printf("\n %s", + key->cert->principals[i]); + printf("\n"); + } + printf(" Constraints: "); + if (buffer_len(&key->cert->constraints) == 0) + printf("(none)\n"); + else { + printf("\n"); + buffer_init(&constraints); + buffer_append(&constraints, + buffer_ptr(&key->cert->constraints), + buffer_len(&key->cert->constraints)); + buffer_init(&constraint); + while (buffer_len(&constraints) != 0) { + name = buffer_get_string(&constraints, NULL); + data = buffer_get_string_ptr(&constraints, &dlen); + buffer_append(&constraint, data, dlen); + printf(" %s", name); + if (strcmp(name, "permit-X11-forwarding") == 0 || + strcmp(name, "permit-agent-forwarding") == 0 || + strcmp(name, "permit-port-forwarding") == 0 || + strcmp(name, "permit-pty") == 0 || + strcmp(name, "permit-user-rc") == 0) + printf("\n"); + else if (strcmp(name, "force-command") == 0 || + strcmp(name, "source-address") == 0) { + data = buffer_get_string(&constraint, NULL); + printf(" %s\n", data); + xfree(data); + } else { + printf(" UNKNOWN CONSTRAINT (len %u)\n", + buffer_len(&constraint)); + buffer_clear(&constraint); + } + xfree(name); + if (buffer_len(&constraint) != 0) + fatal("Constraint corrupt: extra data at end"); + } + buffer_free(&constraint); + buffer_free(&constraints); + } + + exit(0); +} + static void usage(void) { @@ -1040,30 +1460,34 @@ usage(void) 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 */ +#ifdef ENABLE_PKCS11 + fprintf(stderr, " -D pkcs11 Download public key from pkcs11 token.\n"); +#endif 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, " -h Generate host certificate instead of a user certificate.\n"); + fprintf(stderr, " -I key_id Key identifier to include in certificate.\n"); fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); + fprintf(stderr, " -L Print the contents of a certificate.\n"); fprintf(stderr, " -l Show fingerprint of key file.\n"); fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); + fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); fprintf(stderr, " -N phrase Provide new passphrase.\n"); + fprintf(stderr, " -O cnstr Specify a certificate constraint.\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 ca_key Certify keys with CA key.\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 from:to Specify certificate validity interval.\n"); fprintf(stderr, " -v Verbose.\n"); fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); fprintf(stderr, " -y Read private key file and print public key.\n"); @@ -1078,12 +1502,12 @@ int main(int argc, char **argv) { char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; - char out_file[MAXPATHLEN], *reader_id = NULL; + char out_file[MAXPATHLEN], *pkcs11provider = NULL; char *rr_hostname = NULL; Key *private, *public; struct passwd *pw; struct stat st; - int opt, type, fd, download = 0; + int opt, type, fd; u_int32_t memory = 0, generator_wanted = 0, trials = 100; int do_gen_candidates = 0, do_screen_candidates = 0; BIGNUM *start = NULL; @@ -1115,8 +1539,8 @@ main(int argc, char **argv) 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) { + while ((opt = getopt(argc, argv, "degiqpclBHLhvxXyF:b:f:t:D:I:P:N:n:" + "O:C:r:g:R:T:G:M:S:s:a:V:W:")) != -1) { switch (opt) { case 'b': bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); @@ -1131,16 +1555,25 @@ main(int argc, char **argv) case 'H': hash_hosts = 1; break; + case 'I': + cert_key_id = optarg; + break; case 'R': delete_host = 1; rr_hostname = optarg; break; + case 'L': + show_cert = 1; + break; case 'l': print_fingerprint = 1; break; case 'B': print_bubblebabble = 1; break; + case 'n': + cert_principals = optarg; + break; case 'p': change_passphrase = 1; break; @@ -1162,6 +1595,9 @@ main(int argc, char **argv) case 'N': identity_new_passphrase = optarg; break; + case 'O': + add_cert_constraint(optarg); + break; case 'C': identity_comment = optarg; break; @@ -1173,6 +1609,10 @@ main(int argc, char **argv) /* export key */ convert_to_ssh2 = 1; break; + case 'h': + cert_key_type = SSH2_CERT_TYPE_HOST; + constraint_flags = 0; + break; case 'i': case 'X': /* import key */ @@ -1184,14 +1624,14 @@ main(int argc, char **argv) case 'd': key_type_name = "dsa"; break; + case 's': + ca_key_path = optarg; + break; case 't': key_type_name = optarg; break; case 'D': - download = 1; - /*FALLTHROUGH*/ - case 'U': - reader_id = optarg; + pkcs11provider = optarg; break; case 'v': if (log_level == SYSLOG_LEVEL_INFO) @@ -1241,6 +1681,9 @@ main(int argc, char **argv) if (BN_hex2bn(&start, optarg) == 0) fatal("Invalid start point."); break; + case 'V': + parse_cert_times(optarg); + break; case '?': default: usage(); @@ -1250,7 +1693,15 @@ main(int argc, char **argv) /* reinit */ log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); - if (optind < argc) { + argv += optind; + argc -= optind; + + if (ca_key_path != NULL) { + if (argc < 1) { + printf("Too few arguments.\n"); + usage(); + } + } else if (argc > 0) { printf("Too many arguments.\n"); usage(); } @@ -1262,6 +1713,13 @@ main(int argc, char **argv) printf("Cannot use -l with -D or -R.\n"); usage(); } + if (ca_key_path != NULL) { + if (cert_key_id == NULL) + fatal("Must specify key id (-I) when certifying"); + do_ca_sign(pw, argc, argv); + } + if (show_cert) + do_show_cert(pw); if (delete_host || hash_hosts || find_host) do_known_hosts(pw, rr_hostname); if (print_fingerprint || print_bubblebabble) @@ -1299,16 +1757,8 @@ main(int argc, char **argv) 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 (pkcs11provider != NULL) + do_download(pw, pkcs11provider); if (do_gen_candidates) { FILE *out = fopen(out_file, "w"); diff --git a/crypto/openssh/ssh-keyscan.1 b/crypto/openssh/ssh-keyscan.1 index 2c7ac1084..fd6b94a59 100644 --- a/crypto/openssh/ssh-keyscan.1 +++ b/crypto/openssh/ssh-keyscan.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keyscan.1,v 1.26 2008/12/29 01:12:36 stevesk Exp $ +.\" $OpenBSD: ssh-keyscan.1,v 1.28 2010/01/09 23:04:13 dtucker Exp $ .\" $FreeBSD$ .\" .\" Copyright 1995, 1996 by David Mazieres . @@ -7,7 +7,7 @@ .\" permitted provided that due credit is given to the author and the .\" OpenBSD project by leaving this copyright notice intact. .\" -.Dd December 29 2008 +.Dd January 9 2010 .Dt SSH-KEYSCAN 1 .Os .Sh NAME diff --git a/crypto/openssh/ssh-keyscan.c b/crypto/openssh/ssh-keyscan.c index 9a91be499..7afe446ae 100644 --- a/crypto/openssh/ssh-keyscan.c +++ b/crypto/openssh/ssh-keyscan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keyscan.c,v 1.78 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: ssh-keyscan.c,v 1.81 2010/01/09 23:04:13 dtucker Exp $ */ /* * Copyright 1995, 1996 by David Mazieres . * diff --git a/crypto/openssh/ssh-keysign.c b/crypto/openssh/ssh-keysign.c index c4bc7e56e..0fdcebbd2 100644 --- a/crypto/openssh/ssh-keysign.c +++ b/crypto/openssh/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.30 2010/01/13 01:20:20 dtucker Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -222,7 +222,7 @@ main(int argc, char **argv) if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO)) fatal("bad fd"); if ((host = get_local_name(fd)) == NULL) - fatal("cannot get sockname for fd"); + fatal("cannot get local name for fd"); data = buffer_get_string(&b, &dlen); if (valid_request(pw, host, &key, data, dlen) < 0) diff --git a/crypto/openssh/ssh-pkcs11-client.c b/crypto/openssh/ssh-pkcs11-client.c new file mode 100644 index 000000000..650c37342 --- /dev/null +++ b/crypto/openssh/ssh-pkcs11-client.c @@ -0,0 +1,238 @@ +/* $OpenBSD: ssh-pkcs11-client.c,v 1.2 2010/02/24 06:12:53 djm Exp $ */ +/* + * Copyright (c) 2010 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef ENABLE_PKCS11 + +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include + +#include +#include +#include +#include + +#include "pathnames.h" +#include "xmalloc.h" +#include "buffer.h" +#include "log.h" +#include "misc.h" +#include "key.h" +#include "authfd.h" +#include "atomicio.h" +#include "ssh-pkcs11.h" + +/* borrows code from sftp-server and ssh-agent */ + +int fd = -1; +pid_t pid = -1; + +static void +send_msg(Buffer *m) +{ + u_char buf[4]; + int mlen = buffer_len(m); + + put_u32(buf, mlen); + if (atomicio(vwrite, fd, buf, 4) != 4 || + atomicio(vwrite, fd, buffer_ptr(m), + buffer_len(m)) != buffer_len(m)) + error("write to helper failed"); + buffer_consume(m, mlen); +} + +static int +recv_msg(Buffer *m) +{ + u_int l, len; + u_char buf[1024]; + + if ((len = atomicio(read, fd, buf, 4)) != 4) { + error("read from helper failed: %u", len); + return (0); /* XXX */ + } + len = get_u32(buf); + if (len > 256 * 1024) + fatal("response too long: %u", len); + /* read len bytes into m */ + buffer_clear(m); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + if (atomicio(read, fd, buf, l) != l) { + error("response from helper failed."); + return (0); /* XXX */ + } + buffer_append(m, buf, l); + len -= l; + } + return (buffer_get_char(m)); +} + +int +pkcs11_init(int interactive) +{ + return (0); +} + +void +pkcs11_terminate(void) +{ + close(fd); +} + +static int +pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, + int padding) +{ + Key key; + u_char *blob, *signature = NULL; + u_int blen, slen = 0; + int ret = -1; + Buffer msg; + + if (padding != RSA_PKCS1_PADDING) + return (-1); + key.type = KEY_RSA; + key.rsa = rsa; + if (key_to_blob(&key, &blob, &blen) == 0) + return -1; + buffer_init(&msg); + buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); + buffer_put_string(&msg, blob, blen); + buffer_put_string(&msg, from, flen); + buffer_put_int(&msg, 0); + xfree(blob); + send_msg(&msg); + + if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { + signature = buffer_get_string(&msg, &slen); + if (slen <= (u_int)RSA_size(rsa)) { + memcpy(to, signature, slen); + ret = slen; + } + xfree(signature); + } + return (ret); +} + +/* redirect the private key encrypt operation to the ssh-pkcs11-helper */ +static int +wrap_key(RSA *rsa) +{ + static RSA_METHOD helper_rsa; + + memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); + helper_rsa.name = "ssh-pkcs11-helper"; + helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; + RSA_set_method(rsa, &helper_rsa); + return (0); +} + +static int +pkcs11_start_helper(void) +{ + int pair[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + error("socketpair: %s", strerror(errno)); + return (-1); + } + if ((pid = fork()) == -1) { + error("fork: %s", strerror(errno)); + return (-1); + } else if (pid == 0) { + if ((dup2(pair[1], STDIN_FILENO) == -1) || + (dup2(pair[1], STDOUT_FILENO) == -1)) { + fprintf(stderr, "dup2: %s\n", strerror(errno)); + _exit(1); + } + close(pair[0]); + close(pair[1]); + execlp(_PATH_SSH_PKCS11_HELPER, _PATH_SSH_PKCS11_HELPER, + (char *) 0); + fprintf(stderr, "exec: %s: %s\n", _PATH_SSH_PKCS11_HELPER, + strerror(errno)); + _exit(1); + } + close(pair[1]); + fd = pair[0]; + return (0); +} + +int +pkcs11_add_provider(char *name, char *pin, Key ***keysp) +{ + Key *k; + int i, nkeys; + u_char *blob; + u_int blen; + Buffer msg; + + if (fd < 0 && pkcs11_start_helper() < 0) + return (-1); + + buffer_init(&msg); + buffer_put_char(&msg, SSH_AGENTC_ADD_SMARTCARD_KEY); + buffer_put_cstring(&msg, name); + buffer_put_cstring(&msg, pin); + send_msg(&msg); + buffer_clear(&msg); + + if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) { + nkeys = buffer_get_int(&msg); + *keysp = xcalloc(nkeys, sizeof(Key *)); + for (i = 0; i < nkeys; i++) { + blob = buffer_get_string(&msg, &blen); + xfree(buffer_get_string(&msg, NULL)); + k = key_from_blob(blob, blen); + wrap_key(k->rsa); + (*keysp)[i] = k; + xfree(blob); + } + } else { + nkeys = -1; + } + buffer_free(&msg); + return (nkeys); +} + +int +pkcs11_del_provider(char *name) +{ + int ret = -1; + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, SSH_AGENTC_REMOVE_SMARTCARD_KEY); + buffer_put_cstring(&msg, name); + buffer_put_cstring(&msg, ""); + send_msg(&msg); + buffer_clear(&msg); + + if (recv_msg(&msg) == SSH_AGENT_SUCCESS) + ret = 0; + buffer_free(&msg); + return (ret); +} + +#endif /* ENABLE_PKCS11 */ diff --git a/crypto/openssh/ssh-pkcs11-helper.0 b/crypto/openssh/ssh-pkcs11-helper.0 new file mode 100644 index 000000000..2760cad94 --- /dev/null +++ b/crypto/openssh/ssh-pkcs11-helper.0 @@ -0,0 +1,25 @@ +SSH-PKCS11-HELPER(8) OpenBSD System Manager's Manual SSH-PKCS11-HELPER(8) + +NAME + ssh-pkcs11-helper - ssh-agent helper program for PKCS#11 support + +SYNOPSIS + ssh-pkcs11-helper + +DESCRIPTION + ssh-pkcs11-helper is used by ssh-agent(1) to access keys provided by a + PKCS#11 token. + + ssh-pkcs11-helper is not intended to be invoked by the user, but from + ssh-agent(1). + +SEE ALSO + ssh(1), ssh-add(1), ssh-agent(1) + +HISTORY + ssh-pkcs11-helper first appeared in OpenBSD 4.7. + +AUTHORS + Markus Friedl + +OpenBSD 4.6 February 10, 2010 1 diff --git a/crypto/openssh/ssh-pkcs11-helper.8 b/crypto/openssh/ssh-pkcs11-helper.8 new file mode 100644 index 000000000..9bdaadc01 --- /dev/null +++ b/crypto/openssh/ssh-pkcs11-helper.8 @@ -0,0 +1,43 @@ +.\" $OpenBSD: ssh-pkcs11-helper.8,v 1.3 2010/02/10 23:20:38 markus Exp $ +.\" +.\" Copyright (c) 2010 Markus Friedl. All rights reserved. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: February 10 2010 $ +.Dt SSH-PKCS11-HELPER 8 +.Os +.Sh NAME +.Nm ssh-pkcs11-helper +.Nd ssh-agent helper program for PKCS#11 support +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +is used by +.Xr ssh-agent 1 +to access keys provided by a PKCS#11 token. +.Pp +.Nm +is not intended to be invoked by the user, but from +.Xr ssh-agent 1 . +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-agent 1 +.Sh HISTORY +.Nm +first appeared in +.Ox 4.7 . +.Sh AUTHORS +.An Markus Friedl Aq markus@openbsd.org diff --git a/crypto/openssh/ssh-pkcs11-helper.c b/crypto/openssh/ssh-pkcs11-helper.c new file mode 100644 index 000000000..d3bfb9838 --- /dev/null +++ b/crypto/openssh/ssh-pkcs11-helper.c @@ -0,0 +1,372 @@ +/* $OpenBSD: ssh-pkcs11-helper.c,v 1.3 2010/02/24 06:12:53 djm Exp $ */ +/* + * Copyright (c) 2010 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef ENABLE_PKCS11 + +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif + +#include "openbsd-compat/sys-queue.h" + +#include +#include +#include +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "log.h" +#include "misc.h" +#include "key.h" +#include "authfd.h" +#include "ssh-pkcs11.h" + +/* borrows code from sftp-server and ssh-agent */ + +struct pkcs11_keyinfo { + Key *key; + char *providername; + TAILQ_ENTRY(pkcs11_keyinfo) next; +}; + +TAILQ_HEAD(, pkcs11_keyinfo) pkcs11_keylist; + +#define MAX_MSG_LENGTH 10240 /*XXX*/ + +/* helper */ +#define get_int() buffer_get_int(&iqueue); +#define get_string(lenp) buffer_get_string(&iqueue, lenp); + +/* input and output queue */ +Buffer iqueue; +Buffer oqueue; + +static void +add_key(Key *k, char *name) +{ + struct pkcs11_keyinfo *ki; + + ki = xcalloc(1, sizeof(*ki)); + ki->providername = xstrdup(name); + ki->key = k; + TAILQ_INSERT_TAIL(&pkcs11_keylist, ki, next); +} + +static void +del_keys_by_name(char *name) +{ + struct pkcs11_keyinfo *ki, *nxt; + + for (ki = TAILQ_FIRST(&pkcs11_keylist); ki; ki = nxt) { + nxt = TAILQ_NEXT(ki, next); + if (!strcmp(ki->providername, name)) { + TAILQ_REMOVE(&pkcs11_keylist, ki, next); + xfree(ki->providername); + key_free(ki->key); + free(ki); + } + } +} + +/* lookup matching 'private' key */ +static Key * +lookup_key(Key *k) +{ + struct pkcs11_keyinfo *ki; + + TAILQ_FOREACH(ki, &pkcs11_keylist, next) { + debug("check %p %s", ki, ki->providername); + if (key_equal(k, ki->key)) + return (ki->key); + } + return (NULL); +} + +static void +send_msg(Buffer *m) +{ + int mlen = buffer_len(m); + + buffer_put_int(&oqueue, mlen); + buffer_append(&oqueue, buffer_ptr(m), mlen); + buffer_consume(m, mlen); +} + +static void +process_add(void) +{ + char *name, *pin; + Key **keys; + int i, nkeys; + u_char *blob; + u_int blen; + Buffer msg; + + buffer_init(&msg); + name = get_string(NULL); + pin = get_string(NULL); + if ((nkeys = pkcs11_add_provider(name, pin, &keys)) > 0) { + buffer_put_char(&msg, SSH2_AGENT_IDENTITIES_ANSWER); + buffer_put_int(&msg, nkeys); + for (i = 0; i < nkeys; i++) { + key_to_blob(keys[i], &blob, &blen); + buffer_put_string(&msg, blob, blen); + buffer_put_cstring(&msg, name); + xfree(blob); + add_key(keys[i], name); + } + xfree(keys); + } else { + buffer_put_char(&msg, SSH_AGENT_FAILURE); + } + xfree(pin); + xfree(name); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process_del(void) +{ + char *name, *pin; + Buffer msg; + + buffer_init(&msg); + name = get_string(NULL); + pin = get_string(NULL); + del_keys_by_name(name); + if (pkcs11_del_provider(name) == 0) + buffer_put_char(&msg, SSH_AGENT_SUCCESS); + else + buffer_put_char(&msg, SSH_AGENT_FAILURE); + xfree(pin); + xfree(name); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process_sign(void) +{ + u_char *blob, *data, *signature = NULL; + u_int blen, dlen, slen = 0; + int ok = -1, flags, ret; + Key *key, *found; + Buffer msg; + + blob = get_string(&blen); + data = get_string(&dlen); + flags = get_int(); /* XXX ignore */ + + if ((key = key_from_blob(blob, blen)) != NULL) { + if ((found = lookup_key(key)) != NULL) { + slen = RSA_size(key->rsa); + signature = xmalloc(slen); + if ((ret = RSA_private_encrypt(dlen, data, signature, + found->rsa, RSA_PKCS1_PADDING)) != -1) { + slen = ret; + ok = 0; + } + } + key_free(key); + } + buffer_init(&msg); + if (ok == 0) { + buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); + buffer_put_string(&msg, signature, slen); + } else { + buffer_put_char(&msg, SSH_AGENT_FAILURE); + } + xfree(data); + xfree(blob); + if (signature != NULL) + xfree(signature); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process(void) +{ + u_int msg_len; + u_int buf_len; + u_int consumed; + u_int type; + u_char *cp; + + buf_len = buffer_len(&iqueue); + if (buf_len < 5) + return; /* Incomplete message. */ + cp = buffer_ptr(&iqueue); + msg_len = get_u32(cp); + if (msg_len > MAX_MSG_LENGTH) { + error("bad message len %d", msg_len); + cleanup_exit(11); + } + if (buf_len < msg_len + 4) + return; + buffer_consume(&iqueue, 4); + buf_len -= 4; + type = buffer_get_char(&iqueue); + switch (type) { + case SSH_AGENTC_ADD_SMARTCARD_KEY: + debug("process_add"); + process_add(); + break; + case SSH_AGENTC_REMOVE_SMARTCARD_KEY: + debug("process_del"); + process_del(); + break; + case SSH2_AGENTC_SIGN_REQUEST: + debug("process_sign"); + process_sign(); + break; + default: + error("Unknown message %d", type); + break; + } + /* discard the remaining bytes from the current packet */ + if (buf_len < buffer_len(&iqueue)) { + error("iqueue grew unexpectedly"); + cleanup_exit(255); + } + consumed = buf_len - buffer_len(&iqueue); + if (msg_len < consumed) { + error("msg_len %d < consumed %d", msg_len, consumed); + cleanup_exit(255); + } + if (msg_len > consumed) + buffer_consume(&iqueue, msg_len - consumed); +} + +void +cleanup_exit(int i) +{ + /* XXX */ + _exit(i); +} + +int +main(int argc, char **argv) +{ + fd_set *rset, *wset; + int in, out, max, log_stderr = 0; + ssize_t len, olen, set_size; + SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; + LogLevel log_level = SYSLOG_LEVEL_ERROR; + char buf[4*4096]; + + extern char *optarg; + extern char *__progname; + + TAILQ_INIT(&pkcs11_keylist); + pkcs11_init(0); + + init_rng(); + seed_rng(); + __progname = ssh_get_progname(argv[0]); + + log_init(__progname, log_level, log_facility, log_stderr); + + in = STDIN_FILENO; + out = STDOUT_FILENO; + + max = 0; + if (in > max) + max = in; + if (out > max) + max = out; + + buffer_init(&iqueue); + buffer_init(&oqueue); + + set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); + rset = (fd_set *)xmalloc(set_size); + wset = (fd_set *)xmalloc(set_size); + + for (;;) { + memset(rset, 0, set_size); + memset(wset, 0, set_size); + + /* + * Ensure that we can read a full buffer and handle + * the worst-case length packet it can generate, + * otherwise apply backpressure by stopping reads. + */ + if (buffer_check_alloc(&iqueue, sizeof(buf)) && + buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) + FD_SET(in, rset); + + olen = buffer_len(&oqueue); + if (olen > 0) + FD_SET(out, wset); + + if (select(max+1, rset, wset, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + error("select: %s", strerror(errno)); + cleanup_exit(2); + } + + /* copy stdin to iqueue */ + if (FD_ISSET(in, rset)) { + len = read(in, buf, sizeof buf); + if (len == 0) { + debug("read eof"); + cleanup_exit(0); + } else if (len < 0) { + error("read: %s", strerror(errno)); + cleanup_exit(1); + } else { + buffer_append(&iqueue, buf, len); + } + } + /* send oqueue to stdout */ + if (FD_ISSET(out, wset)) { + len = write(out, buffer_ptr(&oqueue), olen); + if (len < 0) { + error("write: %s", strerror(errno)); + cleanup_exit(1); + } else { + buffer_consume(&oqueue, len); + } + } + + /* + * Process requests from client if we can fit the results + * into the output buffer, otherwise stop processing input + * and let the output queue drain. + */ + if (buffer_check_alloc(&oqueue, MAX_MSG_LENGTH)) + process(); + } +} +#else /* ENABLE_PKCS11 */ +int +main(int argc, char **argv) +{ + extern char *__progname; + + __progname = ssh_get_progname(argv[0]); + log_init(__progname, SYSLOG_LEVEL_ERROR, SYSLOG_FACILITY_AUTH, 0); + fatal("PKCS#11 support disabled at compile time"); +} +#endif /* ENABLE_PKCS11 */ diff --git a/crypto/openssh/ssh-pkcs11.c b/crypto/openssh/ssh-pkcs11.c new file mode 100644 index 000000000..f0192dcf1 --- /dev/null +++ b/crypto/openssh/ssh-pkcs11.c @@ -0,0 +1,564 @@ +/* $OpenBSD: ssh-pkcs11.c,v 1.4 2010/02/24 06:12:53 djm Exp $ */ +/* + * Copyright (c) 2010 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifdef ENABLE_PKCS11 + +#include +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#include + +#include +#include + +#include "openbsd-compat/sys-queue.h" + +#define CRYPTOKI_COMPAT +#include "pkcs11.h" + +#include "log.h" +#include "misc.h" +#include "key.h" +#include "ssh-pkcs11.h" +#include "xmalloc.h" + +struct pkcs11_slotinfo { + CK_TOKEN_INFO token; + CK_SESSION_HANDLE session; + int logged_in; +}; + +struct pkcs11_provider { + char *name; + void *handle; + CK_FUNCTION_LIST *function_list; + CK_INFO info; + CK_ULONG nslots; + CK_SLOT_ID *slotlist; + struct pkcs11_slotinfo *slotinfo; + int valid; + int refcount; + TAILQ_ENTRY(pkcs11_provider) next; +}; + +TAILQ_HEAD(, pkcs11_provider) pkcs11_providers; + +struct pkcs11_key { + struct pkcs11_provider *provider; + CK_ULONG slotidx; + int (*orig_finish)(RSA *rsa); + RSA_METHOD rsa_method; + char *keyid; + int keyid_len; +}; + +int pkcs11_interactive = 0; + +int +pkcs11_init(int interactive) +{ + pkcs11_interactive = interactive; + TAILQ_INIT(&pkcs11_providers); + return (0); +} + +/* + * finalize a provider shared libarary, it's no longer usable. + * however, there might still be keys referencing this provider, + * so the actuall freeing of memory is handled by pkcs11_provider_unref(). + * this is called when a provider gets unregistered. + */ +static void +pkcs11_provider_finalize(struct pkcs11_provider *p) +{ + CK_RV rv; + CK_ULONG i; + + debug("pkcs11_provider_finalize: %p refcount %d valid %d", + p, p->refcount, p->valid); + if (!p->valid) + return; + for (i = 0; i < p->nslots; i++) { + if (p->slotinfo[i].session && + (rv = p->function_list->C_CloseSession( + p->slotinfo[i].session)) != CKR_OK) + error("C_CloseSession failed: %lu", rv); + } + if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize failed: %lu", rv); + p->valid = 0; + p->function_list = NULL; + dlclose(p->handle); +} + +/* + * remove a reference to the provider. + * called when a key gets destroyed or when the provider is unregistered. + */ +static void +pkcs11_provider_unref(struct pkcs11_provider *p) +{ + debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount); + if (--p->refcount <= 0) { + if (p->valid) + error("pkcs11_provider_unref: %p still valid", p); + xfree(p->slotlist); + xfree(p->slotinfo); + xfree(p); + } +} + +/* unregister all providers, keys might still point to the providers */ +void +pkcs11_terminate(void) +{ + struct pkcs11_provider *p; + + while ((p = TAILQ_FIRST(&pkcs11_providers)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); + } +} + +/* lookup provider by name */ +static struct pkcs11_provider * +pkcs11_provider_lookup(char *provider_id) +{ + struct pkcs11_provider *p; + + TAILQ_FOREACH(p, &pkcs11_providers, next) { + debug("check %p %s", p, p->name); + if (!strcmp(provider_id, p->name)) + return (p); + } + return (NULL); +} + +/* unregister provider by name */ +int +pkcs11_del_provider(char *provider_id) +{ + struct pkcs11_provider *p; + + if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); + return (0); + } + return (-1); +} + +/* openssl callback for freeing an RSA key */ +static int +pkcs11_rsa_finish(RSA *rsa) +{ + struct pkcs11_key *k11; + int rv = -1; + + if ((k11 = RSA_get_app_data(rsa)) != NULL) { + if (k11->orig_finish) + rv = k11->orig_finish(rsa); + if (k11->provider) + pkcs11_provider_unref(k11->provider); + if (k11->keyid) + xfree(k11->keyid); + xfree(k11); + } + return (rv); +} + +/* openssl callback doing the actual signing operation */ +static int +pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, + int padding) +{ + struct pkcs11_key *k11; + struct pkcs11_slotinfo *si; + CK_FUNCTION_LIST *f; + CK_OBJECT_HANDLE obj; + CK_ULONG tlen = 0, nfound = 0; + CK_RV rv; + CK_OBJECT_CLASS private_key_class = CKO_PRIVATE_KEY; + CK_BBOOL true_val = CK_TRUE; + CK_MECHANISM mech = { + CKM_RSA_PKCS, NULL_PTR, 0 + }; + CK_ATTRIBUTE key_filter[] = { + {CKA_CLASS, NULL, sizeof(private_key_class) }, + {CKA_ID, NULL, 0}, + {CKA_SIGN, NULL, sizeof(true_val) } + }; + char *pin, prompt[1024]; + int rval = -1; + + /* some compilers complain about non-constant initializer so we + use NULL in CK_ATTRIBUTE above and set the values here */ + key_filter[0].pValue = &private_key_class; + key_filter[2].pValue = &true_val; + + if ((k11 = RSA_get_app_data(rsa)) == NULL) { + error("RSA_get_app_data failed for rsa %p", rsa); + return (-1); + } + if (!k11->provider || !k11->provider->valid) { + error("no pkcs11 (valid) provider for rsa %p", rsa); + return (-1); + } + f = k11->provider->function_list; + si = &k11->provider->slotinfo[k11->slotidx]; + if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { + if (!pkcs11_interactive) { + error("need pin"); + return (-1); + } + snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", + si->token.label); + pin = read_passphrase(prompt, RP_ALLOW_EOF); + if (pin == NULL) + return (-1); /* bail out */ + if ((rv = f->C_Login(si->session, CKU_USER, pin, strlen(pin))) + != CKR_OK) { + xfree(pin); + error("C_Login failed: %lu", rv); + return (-1); + } + xfree(pin); + si->logged_in = 1; + } + key_filter[1].pValue = k11->keyid; + key_filter[1].ulValueLen = k11->keyid_len; + if ((rv = f->C_FindObjectsInit(si->session, key_filter, 3)) != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + return (-1); + } + if ((rv = f->C_FindObjects(si->session, &obj, 1, &nfound)) != CKR_OK || + nfound != 1) { + error("C_FindObjects failed (%lu nfound): %lu", nfound, rv); + } else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) { + error("C_SignInit failed: %lu", rv); + } else { + /* XXX handle CKR_BUFFER_TOO_SMALL */ + tlen = RSA_size(rsa); + rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen); + if (rv == CKR_OK) + rval = tlen; + else + error("C_Sign failed: %lu", rv); + } + if ((rv = f->C_FindObjectsFinal(si->session)) != CKR_OK) + error("C_FindObjectsFinal failed: %lu", rv); + return (rval); +} + +static int +pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, + int padding) +{ + return (-1); +} + +/* redirect private key operations for rsa key to pkcs11 token */ +static int +pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, + CK_ATTRIBUTE *keyid_attrib, RSA *rsa) +{ + struct pkcs11_key *k11; + const RSA_METHOD *def = RSA_get_default_method(); + + k11 = xcalloc(1, sizeof(*k11)); + k11->provider = provider; + provider->refcount++; /* provider referenced by RSA key */ + k11->slotidx = slotidx; + /* identify key object on smartcard */ + k11->keyid_len = keyid_attrib->ulValueLen; + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + k11->orig_finish = def->finish; + memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method)); + k11->rsa_method.name = "pkcs11"; + k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt; + k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt; + k11->rsa_method.finish = pkcs11_rsa_finish; + RSA_set_method(rsa, &k11->rsa_method); + RSA_set_app_data(rsa, k11); + return (0); +} + +/* remove trailing spaces */ +static void +rmspace(char *buf, size_t len) +{ + size_t i; + + if (!len) + return; + for (i = len - 1; i > 0; i--) + if (i == len - 1 || buf[i] == ' ') + buf[i] = '\0'; + else + break; +} + +/* + * open a pkcs11 session and login if required. + * if pin == NULL we delay login until key use + */ +static int +pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) +{ + CK_RV rv; + CK_FUNCTION_LIST *f; + CK_SESSION_HANDLE session; + int login_required; + + f = p->function_list; + login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; + if (pin && login_required && !strlen(pin)) { + error("pin required"); + return (-1); + } + if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| + CKF_SERIAL_SESSION, NULL, NULL, &session)) + != CKR_OK) { + error("C_OpenSession failed: %lu", rv); + return (-1); + } + if (login_required && pin) { + if ((rv = f->C_Login(session, CKU_USER, pin, strlen(pin))) + != CKR_OK) { + error("C_Login failed: %lu", rv); + if ((rv = f->C_CloseSession(session)) != CKR_OK) + error("C_CloseSession failed: %lu", rv); + return (-1); + } + p->slotinfo[slotidx].logged_in = 1; + } + p->slotinfo[slotidx].session = session; + return (0); +} + +/* + * lookup public keys for token in slot identified by slotidx, + * add 'wrapped' public keys to the 'keysp' array and increment nkeys. + * keysp points to an (possibly empty) array with *nkeys keys. + */ +static int +pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, Key ***keysp, + int *nkeys) +{ + Key *key; + RSA *rsa; + int i; + CK_RV rv; + CK_OBJECT_HANDLE obj; + CK_ULONG nfound; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f; + CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; + CK_ATTRIBUTE pubkey_filter[] = { + { CKA_CLASS, NULL, sizeof(pubkey_class) } + }; + CK_ATTRIBUTE attribs[] = { + { CKA_ID, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 } + }; + + /* some compilers complain about non-constant initializer so we + use NULL in CK_ATTRIBUTE above and set the value here */ + pubkey_filter[0].pValue = &pubkey_class; + + f = p->function_list; + session = p->slotinfo[slotidx].session; + /* setup a filter the looks for public keys */ + if ((rv = f->C_FindObjectsInit(session, pubkey_filter, 1)) != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + return (-1); + } + while (1) { + /* XXX 3 attributes in attribs[] */ + for (i = 0; i < 3; i++) { + attribs[i].pValue = NULL; + attribs[i].ulValueLen = 0; + } + if ((rv = f->C_FindObjects(session, &obj, 1, &nfound)) != CKR_OK + || nfound == 0) + break; + /* found a key, so figure out size of the attributes */ + if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) + != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + continue; + } + /* allocate buffers for attributes, XXX check ulValueLen? */ + for (i = 0; i < 3; i++) + attribs[i].pValue = xmalloc(attribs[i].ulValueLen); + /* retrieve ID, modulus and public exponent of RSA key */ + if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) + != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + } else if ((rsa = RSA_new()) == NULL) { + error("RSA_new failed"); + } else { + rsa->n = BN_bin2bn(attribs[1].pValue, + attribs[1].ulValueLen, NULL); + rsa->e = BN_bin2bn(attribs[2].pValue, + attribs[2].ulValueLen, NULL); + if (rsa->n && rsa->e && + pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { + key = key_new(KEY_UNSPEC); + key->rsa = rsa; + key->type = KEY_RSA; + key->flags |= KEY_FLAG_EXT; + /* expand key array and add key */ + *keysp = xrealloc(*keysp, *nkeys + 1, + sizeof(Key *)); + (*keysp)[*nkeys] = key; + *nkeys = *nkeys + 1; + debug("have %d keys", *nkeys); + } else { + RSA_free(rsa); + } + } + for (i = 0; i < 3; i++) + xfree(attribs[i].pValue); + } + if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) + error("C_FindObjectsFinal failed: %lu", rv); + return (0); +} + +/* register a new provider, fails if provider already exists */ +int +pkcs11_add_provider(char *provider_id, char *pin, Key ***keyp) +{ + int nkeys, need_finalize = 0; + struct pkcs11_provider *p = NULL; + void *handle = NULL; + CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); + CK_RV rv; + CK_FUNCTION_LIST *f = NULL; + CK_TOKEN_INFO *token; + CK_ULONG i; + + *keyp = NULL; + if (pkcs11_provider_lookup(provider_id) != NULL) { + error("provider already registered: %s", provider_id); + goto fail; + } + /* open shared pkcs11-libarary */ + if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { + error("dlopen %s failed: %s", provider_id, dlerror()); + goto fail; + } + if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { + error("dlsym(C_GetFunctionList) failed: %s", dlerror()); + goto fail; + } + p = xcalloc(1, sizeof(*p)); + p->name = xstrdup(provider_id); + p->handle = handle; + /* setup the pkcs11 callbacks */ + if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { + error("C_GetFunctionList failed: %lu", rv); + goto fail; + } + p->function_list = f; + if ((rv = f->C_Initialize(NULL)) != CKR_OK) { + error("C_Initialize failed: %lu", rv); + goto fail; + } + need_finalize = 1; + if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { + error("C_GetInfo failed: %lu", rv); + goto fail; + } + rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); + rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); + debug("manufacturerID <%s> cryptokiVersion %d.%d" + " libraryDescription <%s> libraryVersion %d.%d", + p->info.manufacturerID, + p->info.cryptokiVersion.major, + p->info.cryptokiVersion.minor, + p->info.libraryDescription, + p->info.libraryVersion.major, + p->info.libraryVersion.minor); + if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { + error("C_GetSlotList failed: %lu", rv); + goto fail; + } + if (p->nslots == 0) { + error("no slots"); + goto fail; + } + p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); + if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) + != CKR_OK) { + error("C_GetSlotList failed: %lu", rv); + goto fail; + } + p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); + p->valid = 1; + nkeys = 0; + for (i = 0; i < p->nslots; i++) { + token = &p->slotinfo[i].token; + if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) + != CKR_OK) { + error("C_GetTokenInfo failed: %lu", rv); + continue; + } + rmspace(token->label, sizeof(token->label)); + rmspace(token->manufacturerID, sizeof(token->manufacturerID)); + rmspace(token->model, sizeof(token->model)); + rmspace(token->serialNumber, sizeof(token->serialNumber)); + debug("label <%s> manufacturerID <%s> model <%s> serial <%s>" + " flags 0x%lx", + token->label, token->manufacturerID, token->model, + token->serialNumber, token->flags); + /* open session, login with pin and retrieve public keys */ + if (pkcs11_open_session(p, i, pin) == 0) + pkcs11_fetch_keys(p, i, keyp, &nkeys); + } + if (nkeys > 0) { + TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); + p->refcount++; /* add to provider list */ + return (nkeys); + } + error("no keys"); + /* don't add the provider, since it does not have any keys */ +fail: + if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize failed: %lu", rv); + if (p) { + if (p->slotlist) + xfree(p->slotlist); + if (p->slotinfo) + xfree(p->slotinfo); + xfree(p); + } + if (handle) + dlclose(handle); + return (-1); +} + +#endif /* ENABLE_PKCS11 */ diff --git a/crypto/openssh/ssh-pkcs11.h b/crypto/openssh/ssh-pkcs11.h new file mode 100644 index 000000000..59f456adf --- /dev/null +++ b/crypto/openssh/ssh-pkcs11.h @@ -0,0 +1,20 @@ +/* $OpenBSD: ssh-pkcs11.h,v 1.2 2010/02/24 06:12:53 djm Exp $ */ +/* + * Copyright (c) 2010 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +int pkcs11_init(int); +void pkcs11_terminate(void); +int pkcs11_add_provider(char *, char *, Key ***); +int pkcs11_del_provider(char *); diff --git a/crypto/openssh/ssh-rand-helper.c b/crypto/openssh/ssh-rand-helper.c index 8b1c4b4f4..fa5070499 100644 --- a/crypto/openssh/ssh-rand-helper.c +++ b/crypto/openssh/ssh-rand-helper.c @@ -818,6 +818,7 @@ main(int argc, char **argv) unsigned char *buf; int ret, ch, debug_level, output_hex, bytes; extern char *optarg; + extern int optind; LogLevel ll; __progname = ssh_get_progname(argv[0]); @@ -853,11 +854,17 @@ main(int argc, char **argv) default: error("Invalid commandline option"); usage(); + exit(1); } } - log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); + if (argc != optind) { + error("Unexpected commandline arguments."); + usage(); + exit(1); + } + #ifdef USE_SEED_FILES prng_read_seedfile(); #endif diff --git a/crypto/openssh/ssh-rsa.c b/crypto/openssh/ssh-rsa.c index 0e16ff85f..842857fee 100644 --- a/crypto/openssh/ssh-rsa.c +++ b/crypto/openssh/ssh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.39 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.40 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -46,7 +46,9 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, int ok, nid; Buffer b; - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + if (key == NULL || + (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || + key->rsa == NULL) { error("ssh_rsa_sign: no RSA key"); return -1; } @@ -113,7 +115,9 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, u_int len, dlen, modlen; int rlen, ret, nid; - if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + if (key == NULL || + (key->type != KEY_RSA && key->type != KEY_RSA_CERT) || + key->rsa == NULL) { error("ssh_rsa_verify: no RSA key"); return -1; } diff --git a/crypto/openssh/ssh.1 b/crypto/openssh/ssh.1 index 0ea4c490f..e3a826ef4 100644 --- a/crypto/openssh/ssh.1 +++ b/crypto/openssh/ssh.1 @@ -34,9 +34,9 @@ .\" (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.282 2009/02/12 03:44:25 djm Exp $ +.\" $OpenBSD: ssh.1,v 1.302 2010/03/05 10:28:21 djm Exp $ .\" $FreeBSD$ -.Dd February 12 2009 +.Dd March 5 2010 .Dt SSH 1 .Os .Sh NAME @@ -55,6 +55,7 @@ .Oc .Op Fl e Ar escape_char .Op Fl F Ar configfile +.Op Fl I Ar pkcs11 .Bk -words .Op Fl i Ar identity_file .Ek @@ -78,12 +79,11 @@ .Sm on .Oc .Op Fl S Ar ctl_path -.Bk -words +.Op Fl W Ar host : Ns Ar port .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 @@ -133,8 +133,9 @@ 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. +(for the agent's +.Ux Ns -domain +socket) can access the local agent through the forwarded connection. An attacker cannot obtain key material from the agent, however they can perform operations on the keys that enable them to authenticate using the identities loaded into the agent. @@ -192,26 +193,9 @@ For protocol version 2, .Ar cipher_spec is a comma-separated list of ciphers listed in order of preference. -The supported ciphers are: -3des-cbc, -aes128-cbc, -aes192-cbc, -aes256-cbc, -aes128-ctr, -aes192-ctr, -aes256-ctr, -arcfour128, -arcfour256, -arcfour, -blowfish-cbc, -and -cast128-cbc. -The default is: -.Bd -literal -offset indent -aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour128, -arcfour256,arcfour,aes192-cbc,aes256-cbc,aes128-ctr, -aes192-ctr,aes256-ctr -.Ed +See the +.Cm Ciphers +keyword for more information. .It Fl D Xo .Sm off .Oo Ar bind_address : Oc @@ -302,13 +286,11 @@ 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 +.It Fl I Ar pkcs11 +Specify the PKCS#11 shared library .Nm -should use to communicate with a smartcard used for storing the user's +should use to communicate with a PKCS#11 token providing 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. @@ -325,6 +307,11 @@ It is possible to have multiple .Fl i options (and multiple identities specified in configuration files). +.Nm +will also try to load certificate information from the filename obtained +by appending +.Pa -cert.pub +to identity filenames. .It Fl K Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI credentials to the server. @@ -487,6 +474,7 @@ For full details of the options listed below, and their possible values, see .It NumberOfPasswordPrompts .It PasswordAuthentication .It PermitLocalCommand +.It PKCS11Provider .It Port .It PreferredAuthentications .It Protocol @@ -499,7 +487,6 @@ For full details of the options listed below, and their possible values, see .It SendEnv .It ServerAliveInterval .It ServerAliveCountMax -.It SmartcardDevice .It StrictHostKeyChecking .It TCPKeepAlive .It Tunnel @@ -612,6 +599,19 @@ Multiple .Fl v options increase the verbosity. The maximum is 3. +.It Fl W Ar host : Ns Ar port +Requests that standard input and output on the client be forwarded to +.Ar host +on +.Ar port +over the secure channel. +Implies +.Fl N , +.Fl T , +.Cm ExitOnForwardFailure +and +.Cm ClearAllForwardings +and works with Protocol version 2 only. .It Fl w Xo .Ar local_tun Ns Op : Ns Ar remote_tun .Xc @@ -685,20 +685,18 @@ 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 +The default is to use protocol 2 only, +though this can be changed via the .Cm Protocol option in -.Xr ssh_config 5 , -or enforced using the +.Xr ssh_config 5 +or the .Fl 1 and .Fl 2 options (see above). Both protocols support similar authentication methods, -but protocol 2 is preferred since +but protocol 2 is the default since it provides additional mechanisms for confidentiality (the traffic is encrypted using AES, 3DES, Blowfish, CAST128, or Arcfour) and integrity (hmac-md5, hmac-sha1, umac-64, hmac-ripemd160). @@ -807,8 +805,20 @@ 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. +A variation on public key authentication +is available in the form of certificate authentication: +instead of a set of public/private keys, +signed certificates are used. +This has the advantage that a single trusted certification authority +can be used in place of many public/private keys. +See the +.Sx CERTIFICATES +section of +.Xr ssh-keygen 1 +for more information. +.Pp +The most convenient way to use public key or certificate authentication +may be with an authentication agent. See .Xr ssh-agent 1 for more information. diff --git a/crypto/openssh/ssh.c b/crypto/openssh/ssh.c index cd3449a11..884d7e978 100644 --- a/crypto/openssh/ssh.c +++ b/crypto/openssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.324 2009/02/12 03:00:56 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.335 2010/02/26 20:29:54 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -49,6 +49,7 @@ __RCSID("$FreeBSD$"); #endif #include #include +#include #include #include @@ -100,10 +101,11 @@ __RCSID("$FreeBSD$"); #include "match.h" #include "msg.h" #include "uidswap.h" +#include "roaming.h" #include "version.h" -#ifdef SMARTCARD -#include "scard.h" +#ifdef ENABLE_PKCS11 +#include "ssh-pkcs11.h" #endif extern char *__progname; @@ -132,6 +134,10 @@ int stdin_null_flag = 0; */ int fork_after_authentication_flag = 0; +/* forward stdio to remote host and port */ +char *stdio_forward_host = NULL; +int stdio_forward_port = 0; + /* * General data structure for command line options and options configurable * in configuration files. See readconf.h. @@ -182,10 +188,12 @@ 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" +" [-I pkcs11] [-i identity_file]\n" +" [-L [bind_address:]port:host:hostport]\n" " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" -" [-w local_tun[:remote_tun]] [user@]hostname [command]\n" +" [-W host:port] [-w local_tun[:remote_tun]]\n" +" [user@]hostname [command]\n" ); exit(255); } @@ -204,8 +212,8 @@ void muxserver_listen(void); int main(int ac, char **av) { - int i, opt, exit_status, use_syslog; - char *p, *cp, *line, buf[256]; + 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; @@ -271,10 +279,11 @@ main(int ac, char **av) /* 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) { + "ACD:F:I:KL:MNO:PR:S:TVw:W:XYy")) != -1) { switch (opt) { case '1': options.protocol = SSH_PROTO_1; @@ -312,6 +321,11 @@ main(int ac, char **av) options.gateway_ports = 1; break; case 'O': + if (stdio_forward_host != NULL) + fatal("Cannot specify multiplexing " + "command with -W"); + else if (muxclient_command != 0) + fatal("Multiplexing command already specified"); if (strcmp(optarg, "check") == 0) muxclient_command = SSHMUX_COMMAND_ALIVE_CHECK; else if (strcmp(optarg, "exit") == 0) @@ -350,10 +364,10 @@ main(int ac, char **av) xstrdup(optarg); break; case 'I': -#ifdef SMARTCARD - options.smartcard_device = xstrdup(optarg); +#ifdef ENABLE_PKCS11 + options.pkcs11_provider = xstrdup(optarg); #else - fprintf(stderr, "no support for smartcards.\n"); + fprintf(stderr, "no support for PKCS#11.\n"); #endif break; case 't': @@ -387,6 +401,26 @@ main(int ac, char **av) exit(255); } break; + case 'W': + if (stdio_forward_host != NULL) + fatal("stdio forward already specified"); + if (muxclient_command != 0) + fatal("Cannot specify stdio forward with -O"); + if (parse_forward(&fwd, optarg, 1, 0)) { + stdio_forward_host = fwd.listen_host; + stdio_forward_port = fwd.listen_port; + xfree(fwd.connect_host); + } else { + fprintf(stderr, + "Bad stdio forwarding specification '%s'\n", + optarg); + exit(255); + } + no_tty_flag = 1; + no_shell_flag = 1; + options.clear_forwardings = 1; + options.exit_on_forward_failure = 1; + break; case 'q': options.log_level = SYSLOG_LEVEL_QUIET; break; @@ -526,7 +560,7 @@ main(int ac, char **av) ac -= optind; av += optind; - if (ac > 0 && !host && **av != '-') { + if (ac > 0 && !host) { if (strrchr(*av, '@')) { p = xstrdup(*av); cp = strrchr(p, '@'); @@ -601,7 +635,7 @@ main(int ac, char **av) * Initialize "log" output. Since we are the client all output * actually goes to stderr. */ - log_init(av[0], + log_init(argv0, options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, SYSLOG_FACILITY_USER, !use_syslog); @@ -614,9 +648,10 @@ main(int ac, char **av) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { - snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, + r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); - (void)read_config_file(buf, host, &options, 1); + 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, @@ -629,7 +664,7 @@ main(int ac, char **av) channel_set_af(options.address_family); /* reinit */ - log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, !use_syslog); + log_init(argv0, options.log_level, SYSLOG_FACILITY_USER, !use_syslog); seed_rng(); @@ -784,9 +819,9 @@ main(int ac, char **av) * Now that we are back to our own permissions, create ~/.ssh * directory if it doesn't already exist. */ - snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, + r = snprintf(buf, sizeof buf, "%s%s%s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); - if (stat(buf, &st) < 0) + if (r > 0 && (size_t)r < sizeof(buf) && stat(buf, &st) < 0) if (mkdir(buf, 0700) < 0) error("Could not create directory '%.200s'.", buf); @@ -884,12 +919,49 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) } } +static void +client_cleanup_stdio_fwd(int id, void *arg) +{ + debug("stdio forwarding: done"); + cleanup_exit(0); +} + +static int +client_setup_stdio_fwd(const char *host_to_connect, u_short port_to_connect) +{ + Channel *c; + int in, out; + + debug3("client_setup_stdio_fwd %s:%d", host_to_connect, + port_to_connect); + + in = dup(STDIN_FILENO); + out = dup(STDOUT_FILENO); + if (in < 0 || out < 0) + fatal("channel_connect_stdio_fwd: dup() in/out failed"); + + if ((c = channel_connect_stdio_fwd(host_to_connect, port_to_connect, + in, out)) == NULL) + return 0; + channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0); + return 1; +} + static void ssh_init_forwarding(void) { int success = 0; int i; + if (stdio_forward_host != NULL) { + if (!compat20) { + fatal("stdio forwarding require Protocol 2"); + } + if (!client_setup_stdio_fwd(stdio_forward_host, + stdio_forward_port)) + fatal("Failed to connect in stdio forward mode."); + } + /* Initiate local TCP/IP port forwardings. */ for (i = 0; i < options.num_local_forwards; i++) { debug("Local connections to %.200s:%d forwarded to remote " @@ -1237,6 +1309,9 @@ ssh_session2(void) fatal("daemon() failed: %.200s", strerror(errno)); } + if (options.use_roaming) + request_roaming(); + return client_loop(tty_flag, tty_flag ? options.escape_char : SSH_ESCAPECHAR_NONE, id); } @@ -1249,31 +1324,37 @@ load_public_identity_files(void) int i = 0; Key *public; struct passwd *pw; -#ifdef SMARTCARD + u_int n_ids; + char *identity_files[SSH_MAX_IDENTITY_FILES]; + Key *identity_keys[SSH_MAX_IDENTITY_FILES]; +#ifdef ENABLE_PKCS11 Key **keys; + int nkeys; +#endif /* PKCS11 */ - if (options.smartcard_device != NULL && + n_ids = 0; + bzero(identity_files, sizeof(identity_files)); + bzero(identity_keys, sizeof(identity_keys)); + +#ifdef ENABLE_PKCS11 + if (options.pkcs11_provider != NULL && options.num_identity_files < SSH_MAX_IDENTITY_FILES && - (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]); + (pkcs11_init(!options.batch_mode) == 0) && + (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, + &keys)) > 0) { + for (i = 0; i < nkeys; i++) { + if (n_ids >= SSH_MAX_IDENTITY_FILES) { + key_free(keys[i]); + continue; + } + identity_keys[n_ids] = keys[i]; + identity_files[n_ids] = + xstrdup(options.pkcs11_provider); /* XXX */ + n_ids++; } - if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) - options.num_identity_files = SSH_MAX_IDENTITY_FILES; - i = count; xfree(keys); } -#endif /* SMARTCARD */ +#endif /* ENABLE_PKCS11 */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("load_public_identity_files: getpwuid failed"); pwname = xstrdup(pw->pw_name); @@ -1281,7 +1362,11 @@ load_public_identity_files(void) if (gethostname(thishost, sizeof(thishost)) == -1) fatal("load_public_identity_files: gethostname: %s", strerror(errno)); - for (; i < options.num_identity_files; i++) { + for (i = 0; i < options.num_identity_files; i++) { + if (n_ids >= SSH_MAX_IDENTITY_FILES) { + xfree(options.identity_files[i]); + continue; + } cp = tilde_expand_filename(options.identity_files[i], original_real_uid); filename = percent_expand(cp, "d", pwdir, @@ -1292,9 +1377,37 @@ load_public_identity_files(void) 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; + identity_files[n_ids] = filename; + identity_keys[n_ids] = public; + + if (++n_ids >= SSH_MAX_IDENTITY_FILES) + continue; + + /* Try to add the certificate variant too */ + xasprintf(&cp, "%s-cert", filename); + public = key_load_public(cp, NULL); + debug("identity file %s type %d", cp, + public ? public->type : -1); + if (public == NULL) { + xfree(cp); + continue; + } + if (!key_is_cert(public)) { + debug("%s: key %s type %s is not a certificate", + __func__, cp, key_type(public)); + key_free(public); + xfree(cp); + continue; + } + identity_keys[n_ids] = public; + /* point to the original path, most likely the private key */ + identity_files[n_ids] = xstrdup(filename); + n_ids++; } + options.num_identity_files = n_ids; + memcpy(options.identity_files, identity_files, sizeof(identity_files)); + memcpy(options.identity_keys, identity_keys, sizeof(identity_keys)); + bzero(pwname, strlen(pwname)); xfree(pwname); bzero(pwdir, strlen(pwdir)); diff --git a/crypto/openssh/ssh2.h b/crypto/openssh/ssh2.h index 1c33dc268..3ffaf686b 100644 --- a/crypto/openssh/ssh2.h +++ b/crypto/openssh/ssh2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh2.h,v 1.11 2008/11/04 08:22:13 djm Exp $ */ +/* $OpenBSD: ssh2.h,v 1.13 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -166,3 +166,13 @@ #define SSH2_EXTENDED_DATA_STDERR 1 +/* kex messages for resume@appgate.com */ +#define SSH2_MSG_KEX_ROAMING_RESUME 30 +#define SSH2_MSG_KEX_ROAMING_AUTH_REQUIRED 31 +#define SSH2_MSG_KEX_ROAMING_AUTH 32 +#define SSH2_MSG_KEX_ROAMING_AUTH_OK 33 +#define SSH2_MSG_KEX_ROAMING_AUTH_FAIL 34 + +/* Certificate types for OpenSSH certificate keys extension */ +#define SSH2_CERT_TYPE_USER 1 +#define SSH2_CERT_TYPE_HOST 2 diff --git a/crypto/openssh/ssh_config b/crypto/openssh/ssh_config index 1549e06a6..1edf1648c 100644 --- a/crypto/openssh/ssh_config +++ b/crypto/openssh/ssh_config @@ -1,4 +1,4 @@ -# $OpenBSD: ssh_config,v 1.25 2009/02/17 01:28:32 djm Exp $ +# $OpenBSD: ssh_config,v 1.26 2010/01/11 01:39:46 dtucker Exp $ # $FreeBSD$ # This is the ssh client system-wide configuration file. See @@ -45,4 +45,5 @@ # TunnelDevice any:any # PermitLocalCommand no # VisualHostKey no -# VersionAddendum FreeBSD-20090522 +# ProxyCommand ssh -q -W %h:%p gateway.example.com +# VersionAddendum FreeBSD-20100308 diff --git a/crypto/openssh/ssh_config.5 b/crypto/openssh/ssh_config.5 index e5e020e54..0f67fdc6c 100644 --- a/crypto/openssh/ssh_config.5 +++ b/crypto/openssh/ssh_config.5 @@ -34,9 +34,9 @@ .\" (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 $ +.\" $OpenBSD: ssh_config.5,v 1.129 2010/03/05 10:28:21 djm Exp $ .\" $FreeBSD$ -.Dd February 22 2009 +.Dd March 5 2010 .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -560,6 +560,12 @@ and for protocol version 2. Additionally, any identities represented by the authentication agent will be used for authentication. +.Xr ssh 1 +will try to load certificate information from the filename obtained by +appending +.Pa -cert.pub +to the path of a specified +.Cm IdentityFile . .Pp The file name may use the tilde syntax to refer to a user's home directory or one of the following @@ -617,6 +623,13 @@ The following escape character substitutions will be performed: (remote user name) or .Ql %u (local user name). +.Pp +The command is run synchronously and does not have access to the +session of the +.Xr ssh 1 +that spawned it. +It should not be used for interactive commands. +.Pp This directive is ignored unless .Cm PermitLocalCommand has been enabled. @@ -705,6 +718,12 @@ or .Dq no . The default is .Dq no . +.It Cm PKCS11Provider +Specifies which PKCS#11 provider to use. +The argument to this keyword is the PKCS#11 shared libary +.Xr ssh 1 +should use to communicate with a PKCS#11 token providing the user's +private RSA key. .It Cm Port Specifies the port number to connect on the remote host. The default is 22. @@ -731,11 +750,13 @@ The possible values are 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 +When this option is set to +.Dq 2,1 +.Nm ssh +will try version 2 and fall back to version 1 if version 2 is not available. +The default is +.Sq 2 . .It Cm ProxyCommand Specifies the command to use to connect to the server. The command @@ -919,13 +940,6 @@ 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 , @@ -1073,7 +1087,7 @@ in Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20090522 . +.Dq FreeBSD-20100308 . .It Cm VisualHostKey If this flag is set to .Dq yes , diff --git a/crypto/openssh/ssh_namespace.h b/crypto/openssh/ssh_namespace.h index 8fdf708a6..caa14c8ca 100644 --- a/crypto/openssh/ssh_namespace.h +++ b/crypto/openssh/ssh_namespace.h @@ -7,7 +7,7 @@ * * A list of symbols which need munging is obtained as follows: * - * nm libssh.a | awk '$2 == "T" && $3 !~ /^ssh_/ { print "#define", $3, "ssh_" $3 }' + * nm libssh.a | awk '/[0-9a-z] [A-Z] / && $3 !~ /^ssh_/ { print "#define", $3, "ssh_" $3 }' * * $FreeBSD$ */ @@ -18,7 +18,9 @@ #define acss_setkey ssh_acss_setkey #define acss_setsubkey ssh_acss_setsubkey #define add_host_to_hostfile ssh_add_host_to_hostfile +#define add_recv_bytes ssh_add_recv_bytes #define addargs ssh_addargs +#define addr_match_cidr_list ssh_addr_match_cidr_list #define addr_match_list ssh_addr_match_list #define ask_permission ssh_ask_permission #define atomicio ssh_atomicio @@ -54,6 +56,7 @@ #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_ptr_ret ssh_buffer_get_string_ptr_ret #define buffer_get_string_ret ssh_buffer_get_string_ret #define buffer_init ssh_buffer_init #define buffer_len ssh_buffer_len @@ -89,6 +92,7 @@ #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_stdio_fwd ssh_channel_connect_stdio_fwd #define channel_connect_to ssh_channel_connect_to #define channel_find_open ssh_channel_find_open #define channel_free ssh_channel_free @@ -111,10 +115,11 @@ #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_post ssh_channel_post +#define channel_pre ssh_channel_pre #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 @@ -150,19 +155,22 @@ #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 ssh_ciphers #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 compat13 ssh_compat13 +#define compat20 ssh_compat20 #define compat_cipher_proposal ssh_compat_cipher_proposal #define compat_datafellows ssh_compat_datafellows #define convtime ssh_convtime +#define current_keys ssh_current_keys +#define datafellows ssh_datafellows #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 @@ -174,6 +182,7 @@ #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 ssh_dispatch #define dispatch_init ssh_dispatch_init #define dispatch_protocol_error ssh_dispatch_protocol_error #define dispatch_protocol_ignore ssh_dispatch_protocol_ignore @@ -185,7 +194,6 @@ #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 @@ -193,7 +201,6 @@ #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 @@ -204,6 +211,7 @@ #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_recv_bytes ssh_get_recv_bytes #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 @@ -212,9 +220,12 @@ #define get_u32 ssh_get_u32 #define get_u64 ssh_get_u64 #define getrrsetbyname ssh_getrrsetbyname +#define glob ssh_glob +#define globfree ssh_globfree #define host_hash ssh_host_hash #define hostfile_read_key ssh_hostfile_read_key #define hpdelim ssh_hpdelim +#define incoming_stream ssh_incoming_stream #define init_rng ssh_init_rng #define ipv64_normalise_mapped ssh_ipv64_normalise_mapped #define kex_derive_keys ssh_kex_derive_keys @@ -227,14 +238,22 @@ #define kexdh_client ssh_kexdh_client #define kexgex_client ssh_kexgex_client #define kexgex_hash ssh_kexgex_hash +#define key_add_private ssh_key_add_private +#define key_cert_check_authority ssh_key_cert_check_authority +#define key_cert_copy ssh_key_cert_copy +#define key_certify ssh_key_certify #define key_demote ssh_key_demote +#define key_drop_cert ssh_key_drop_cert #define key_equal ssh_key_equal +#define key_equal_public ssh_key_equal_public #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_in_file ssh_key_in_file +#define key_is_cert ssh_key_is_cert #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 @@ -250,8 +269,10 @@ #define key_size ssh_key_size #define key_ssh_name ssh_key_ssh_name #define key_to_blob ssh_key_to_blob +#define key_to_certified ssh_key_to_certified #define key_type ssh_key_type #define key_type_from_name ssh_key_type_from_name +#define key_type_plain ssh_key_type_plain #define key_verify ssh_key_verify #define key_write ssh_key_write #define log_facility_name ssh_log_facility_name @@ -260,13 +281,13 @@ #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 macs ssh_macs #define match_host_and_ip ssh_match_host_and_ip #define match_hostname ssh_match_hostname #define match_list ssh_match_list @@ -278,7 +299,9 @@ #define ms_subtract_diff ssh_ms_subtract_diff #define ms_to_timeval ssh_ms_to_timeval #define mysignal ssh_mysignal +#define outgoing_stream ssh_outgoing_stream #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 @@ -289,10 +312,15 @@ #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 @@ -300,6 +328,7 @@ #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 @@ -309,6 +338,7 @@ #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 @@ -317,9 +347,11 @@ #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 @@ -340,6 +372,12 @@ #define percent_expand ssh_percent_expand #define permanently_drop_suid ssh_permanently_drop_suid #define permanently_set_uid ssh_permanently_set_uid +#define pkcs11_add_provider ssh_pkcs11_add_provider +#define pkcs11_del_provider ssh_pkcs11_del_provider +#define pkcs11_init ssh_pkcs11_init +#define pkcs11_interactive ssh_pkcs11_interactive +#define pkcs11_providers ssh_pkcs11_providers +#define pkcs11_terminate ssh_pkcs11_terminate #define prime_test ssh_prime_test #define proto_spec ssh_proto_spec #define put_host_port ssh_put_host_port @@ -352,9 +390,13 @@ #define refresh_progress_meter ssh_refresh_progress_meter #define replacearg ssh_replacearg #define restore_uid ssh_restore_uid +#define resume_in_progress ssh_resume_in_progress +#define resume_kex ssh_resume_kex #define rijndael_decrypt ssh_rijndael_decrypt #define rijndael_encrypt ssh_rijndael_encrypt #define rijndael_set_key ssh_rijndael_set_key +#define roaming_read ssh_roaming_read +#define roaming_write ssh_roaming_write #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 @@ -368,6 +410,7 @@ #define set_nonblock ssh_set_nonblock #define shadow_pw ssh_shadow_pw #define sigdie ssh_sigdie +#define sock_set_v6only ssh_sock_set_v6only #define ssh1_3des_iv ssh_ssh1_3des_iv #define start_progress_meter ssh_start_progress_meter #define stop_progress_meter ssh_stop_progress_meter @@ -382,6 +425,7 @@ #define tty_make_modes ssh_tty_make_modes #define tty_parse_modes ssh_tty_parse_modes #define tun_open ssh_tun_open +#define umac_ctx ssh_umac_ctx #define umac_delete ssh_umac_delete #define umac_final ssh_umac_final #define umac_new ssh_umac_new @@ -390,7 +434,6 @@ #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 diff --git a/crypto/openssh/sshconnect.c b/crypto/openssh/sshconnect.c index cc214714c..a54d94270 100644 --- a/crypto/openssh/sshconnect.c +++ b/crypto/openssh/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.212 2008/10/14 18:11:33 stevesk Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 djm Exp $ */ /* $FreeBSD$ */ /* * Author: Tatu Ylonen @@ -29,6 +29,7 @@ #include #include +#include #include #ifdef HAVE_PATHS_H #include @@ -57,6 +58,8 @@ #include "atomicio.h" #include "misc.h" #include "dns.h" +#include "roaming.h" +#include "ssh2.h" #include "version.h" char *client_version_string = NULL; @@ -191,8 +194,11 @@ ssh_create_socket(int privileged, struct addrinfo *ai) return sock; } sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) + if (sock < 0) { error("socket: %.100s", strerror(errno)); + return -1; + } + fcntl(sock, F_SETFD, FD_CLOEXEC); /* Bind the socket to an alternative local IP address */ if (options.bind_address == NULL) @@ -414,7 +420,7 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, * Waits for the server identification string, and sends our own * identification string. */ -static void +void ssh_exchange_identification(int timeout_ms) { char buf[256], remote_version[256]; /* must be same size! */ @@ -453,7 +459,7 @@ ssh_exchange_identification(int timeout_ms) } } - len = atomicio(read, connection_in, &buf[i], 1); + len = roaming_atomicio(read, connection_in, &buf[i], 1); if (len != 1 && errno == EPIPE) fatal("ssh_exchange_identification: " @@ -538,7 +544,8 @@ ssh_exchange_identification(int timeout_ms) compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, compat20 ? PROTOCOL_MINOR_2 : minor1, SSH_VERSION, compat20 ? "\r\n" : "\n"); - if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) + 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); @@ -571,6 +578,23 @@ confirm(const char *prompt) } } +static int +check_host_cert(const char *host, const Key *host_key) +{ + const char *reason; + + if (key_cert_check_authority(host_key, 1, 0, host, &reason) != 0) { + error("%s", reason); + return 0; + } + if (buffer_len(&host_key->cert->constraints) != 0) { + error("Certificate for %s contains unsupported constraint(s)", + host); + return 0; + } + return 1; +} + /* * 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. @@ -583,13 +607,13 @@ 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); + Key *file_key, *raw_key = NULL; + const char *type; char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp, *ra; HostStatus host_status; HostStatus ip_status; - int r, local = 0, host_ip_differ = 0; + int r, want_cert, local = 0, host_ip_differ = 0; int salen; char ntop[NI_MAXHOST]; char msg[1024]; @@ -662,11 +686,15 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, host = put_host_port(hostname, port); } + retry: + want_cert = key_is_cert(host_key); + type = key_type(host_key); + /* * 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); + file_key = key_new(key_is_cert(host_key) ? KEY_UNSPEC : host_key->type); /* * Check if the host key is present in the user's list of known @@ -682,9 +710,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, } /* * Also perform check for the ip address, skip the check if we are - * localhost or the hostname was an ip address to begin with + * localhost, looking for a certificate, or the hostname was an ip + * address to begin with. */ - if (options.check_host_ip) { + if (!want_cert && options.check_host_ip) { Key *ip_key = key_new(host_key->type); ip_file = user_hostfile; @@ -708,11 +737,14 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, 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); + debug("Host '%.200s' is known and matches the %s host %s.", + host, type, want_cert ? "certificate" : "key"); + debug("Found %s in %s:%d", + want_cert ? "certificate" : "key", host_file, host_line); + if (want_cert && !check_host_cert(hostname, host_key)) + goto fail; if (options.check_host_ip && ip_status == HOST_NEW) { - if (readonly) + if (readonly || want_cert) logit("%s host key for IP address " "'%.128s' not in list of known hosts.", type, ip); @@ -744,7 +776,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, break; } } - if (readonly) + if (readonly || want_cert) goto fail; /* The host is new. */ if (options.strict_host_key_checking == 1) { @@ -828,7 +860,37 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); break; + case HOST_REVOKED: + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REVOKED HOST KEY DETECTED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("The %s host key for %s is marked as revoked.", type, host); + error("This could mean that a stolen key is being used to"); + error("impersonate this host."); + + /* + * If strict host key checking is in use, the user will have + * to edit the key manually and we can only abort. + */ + if (options.strict_host_key_checking) { + error("%s host key for %.200s was revoked and you have " + "requested strict checking.", type, host); + goto fail; + } + goto continue_unsafe; + case HOST_CHANGED: + if (want_cert) { + /* + * This is only a debug() since it is valid to have + * CAs with wildcard DNS matches that don't match + * all hosts that one might visit. + */ + debug("Host certificate authority does not " + "match %s in %s:%d", CA_MARKER, + host_file, host_line); + goto fail; + } if (readonly == ROQUIET) goto fail; if (options.check_host_ip && host_ip_differ) { @@ -866,6 +928,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, goto fail; } + continue_unsafe: /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or @@ -924,7 +987,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, * 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 + * by that sentence, and ask the user if he/she wishes to * accept the authentication. */ break; @@ -965,6 +1028,20 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, return 0; fail: + if (want_cert && host_status != HOST_REVOKED) { + /* + * No matching certificate. Downgrade cert to raw key and + * search normally. + */ + debug("No matching CA found. Retry with plain key"); + raw_key = key_from_private(host_key); + if (key_drop_cert(raw_key) != 0) + fatal("Couldn't drop certificate"); + host_key = raw_key; + goto retry; + } + if (raw_key != NULL) + key_free(raw_key); xfree(ip); xfree(host); return -1; @@ -977,7 +1054,8 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) struct stat st; int flags = 0; - if (options.verify_host_key_dns && + /* XXX certs are not yet supported for DNS */ + if (!key_is_cert(host_key) && options.verify_host_key_dns && verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { if (flags & DNS_VERIFY_FOUND) { diff --git a/crypto/openssh/sshconnect.h b/crypto/openssh/sshconnect.h index 75bde1a4d..c59a097f4 100644 --- a/crypto/openssh/sshconnect.h +++ b/crypto/openssh/sshconnect.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.h,v 1.24 2007/09/04 11:15:56 djm Exp $ */ +/* $OpenBSD: sshconnect.h,v 1.25 2009/05/27 06:38:16 andreas Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -38,6 +38,8 @@ ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, 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 *); diff --git a/crypto/openssh/sshconnect2.c b/crypto/openssh/sshconnect2.c index a762eec3b..2a5943e7e 100644 --- a/crypto/openssh/sshconnect2.c +++ b/crypto/openssh/sshconnect2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect2.c,v 1.170 2008/11/04 08:22:13 djm Exp $ */ +/* $OpenBSD: sshconnect2.c,v 1.180 2010/02/26 20:29:54 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2008 Damien Miller. All rights reserved. @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include "msg.h" #include "pathnames.h" #include "uidswap.h" +#include "schnorr.h" #include "jpake.h" #ifdef GSSAPI @@ -151,6 +153,11 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) dispatch_run(DISPATCH_BLOCK, &kex->done, kex); + if (options.use_roaming && !kex->roaming) { + debug("Roaming not allowed by server"); + options.use_roaming = 0; + } + session_id2 = kex->session_id; session_id2_len = kex->session_id_len; @@ -209,6 +216,7 @@ struct Authmethod { }; void input_userauth_success(int, u_int32_t, void *); +void input_userauth_success_unexpected(int, u_int32_t, void *); void input_userauth_failure(int, u_int32_t, void *); void input_userauth_banner(int, u_int32_t, void *); void input_userauth_error(int, u_int32_t, void *); @@ -413,7 +421,7 @@ input_userauth_banner(int type, u_int32_t seq, void *ctxt) if (len > 65536) len = 65536; msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ - strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL); + strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH); fprintf(stderr, "%s", msg); xfree(msg); } @@ -426,12 +434,15 @@ void input_userauth_success(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; + if (authctxt == NULL) fatal("input_userauth_success: no authentication context"); if (authctxt->authlist) { xfree(authctxt->authlist); authctxt->authlist = NULL; } + if (authctxt->method != NULL && authctxt->method->cleanup != NULL) + authctxt->method->cleanup(authctxt); if (authctxt->methoddata) { xfree(authctxt->methoddata); authctxt->methoddata = NULL; @@ -439,6 +450,18 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) authctxt->success = 1; /* break out */ } +void +input_userauth_success_unexpected(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + + if (authctxt == NULL) + fatal("%s: no authentication context", __func__); + + fatal("Unexpected authentication success during %s.", + authctxt->method->name); +} + /* ARGSUSED */ void input_userauth_failure(int type, u_int32_t seq, void *ctxt) @@ -781,6 +804,8 @@ userauth_passwd(Authctxt *authctxt) static int attempt = 0; char prompt[150]; char *password; + const char *host = options.host_key_alias ? options.host_key_alias : + authctxt->host; if (attempt++ >= options.number_of_password_prompts) return 0; @@ -789,7 +814,7 @@ userauth_passwd(Authctxt *authctxt) error("Permission denied, please try again."); snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", - authctxt->server_user, authctxt->host); + authctxt->server_user, host); password = read_passphrase(prompt, 0); packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); @@ -818,6 +843,8 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) Authctxt *authctxt = ctxt; char *info, *lang, *password = NULL, *retype = NULL; char prompt[150]; + const char *host = options.host_key_alias ? options.host_key_alias : + authctxt->host; debug2("input_userauth_passwd_changereq"); @@ -838,7 +865,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) packet_put_char(1); /* additional info */ snprintf(prompt, sizeof(prompt), "Enter %.30s@%.128s's old password: ", - authctxt->server_user, authctxt->host); + authctxt->server_user, host); password = read_passphrase(prompt, 0); packet_put_cstring(password); memset(password, 0, strlen(password)); @@ -847,7 +874,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) while (password == NULL) { snprintf(prompt, sizeof(prompt), "Enter %.30s@%.128s's new password: ", - authctxt->server_user, authctxt->host); + authctxt->server_user, host); password = read_passphrase(prompt, RP_ALLOW_EOF); if (password == NULL) { /* bail out */ @@ -855,7 +882,7 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) } snprintf(prompt, sizeof(prompt), "Retype %.30s@%.128s's new password: ", - authctxt->server_user, authctxt->host); + authctxt->server_user, host); retype = read_passphrase(prompt, 0); if (strcmp(password, retype) != 0) { memset(password, 0, strlen(password)); @@ -1223,7 +1250,7 @@ load_identity_file(char *filename) { Key *private; char prompt[300], *passphrase; - int perm_ok, quit, i; + int perm_ok = 0, quit, i; struct stat st; if (stat(filename, &st) < 0) { @@ -1284,6 +1311,8 @@ pubkey_prepare(Authctxt *authctxt) key = options.identity_keys[i]; if (key && key->type == KEY_RSA1) continue; + if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) + continue; options.identity_keys[i] = NULL; id = xcalloc(1, sizeof(*id)); id->key = key; @@ -1487,7 +1516,7 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, debug2("ssh_keysign called"); if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { - error("ssh_keysign: no installed: %s", strerror(errno)); + error("ssh_keysign: not installed: %s", strerror(errno)); return -1; } if (fflush(stdout) != 0) @@ -1505,6 +1534,8 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, return -1; } if (pid == 0) { + /* keep the socket on exec */ + fcntl(packet_get_connection_in(), F_SETFD, 0); permanently_drop_suid(getuid()); close(from[0]); if (dup2(from[1], STDOUT_FILENO) < 0) @@ -1557,10 +1588,10 @@ userauth_hostbased(Authctxt *authctxt) Sensitive *sensitive = authctxt->sensitive; Buffer b; u_char *signature, *blob; - char *chost, *pkalg, *p, myname[NI_MAXHOST]; + char *chost, *pkalg, *p; const char *service; u_int blen, slen; - int ok, i, len, found = 0; + int ok, i, found = 0; /* check for a useful key */ for (i = 0; i < sensitive->nkeys; i++) { @@ -1581,23 +1612,13 @@ userauth_hostbased(Authctxt *authctxt) 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); - } + p = get_local_name(packet_get_connection_in()); if (p == NULL) { error("userauth_hostbased: cannot get local ipaddr/name"); key_free(private); xfree(blob); return 0; } - len = strlen(p) + 2; xasprintf(&chost, "%s.", p); debug2("userauth_hostbased: chost %s", chost); xfree(p); @@ -1708,6 +1729,8 @@ userauth_jpake(Authctxt *authctxt) /* Expect step 1 packet from peer */ dispatch_set(SSH2_MSG_USERAUTH_JPAKE_SERVER_STEP1, input_userauth_jpake_server_step1); + dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, + &input_userauth_success_unexpected); return 1; } @@ -1720,6 +1743,7 @@ userauth_jpake_cleanup(Authctxt *authctxt) jpake_free(authctxt->methoddata); authctxt->methoddata = NULL; } + dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); } #endif /* JPAKE */ diff --git a/crypto/openssh/sshd.8 b/crypto/openssh/sshd.8 index f74decf39..b4a88f823 100644 --- a/crypto/openssh/sshd.8 +++ b/crypto/openssh/sshd.8 @@ -34,9 +34,9 @@ .\" (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.247 2008/10/03 13:08:12 jmc Exp $ +.\" $OpenBSD: sshd.8,v 1.255 2010/03/05 06:50:35 jmc Exp $ .\" $FreeBSD$ -.Dd October 3 2008 +.Dd March 5 2010 .Dt SSHD 8 .Os .Sh NAME @@ -48,6 +48,7 @@ .Op Fl 46DdeiqTt .Op Fl b Ar bits .Op Fl C Ar connection_spec +.Op Fl c Ar host_certificate_file .Op Fl f Ar config_file .Op Fl g Ar login_grace_time .Op Fl h Ar host_key_file @@ -120,6 +121,15 @@ and All are required and may be supplied in any order, either with multiple .Fl C options or as a comma-separated list. +.It Fl c Ar host_certificate_file +Specifies a path to a certificate file to identify +.Nm +during key exchange. +The certificate file must match a host key file specified using the +.Fl h +option or the +.Cm HostKey +configuration directive. .It Fl D When this option is specified, .Nm @@ -128,8 +138,8 @@ 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 sends verbose debug output to standard error, +and does not put itself in the background. The server also will not fork and will only process one connection. This option is only intended for debugging for the server. Multiple @@ -261,7 +271,7 @@ or .El .Sh AUTHENTICATION The OpenSSH SSH daemon supports SSH protocols 1 and 2. -Both protocols are supported by default, +The default is to use protocol 2 only, though this can be changed via the .Cm Protocol option in @@ -501,6 +511,13 @@ No spaces are permitted, except within double quotes. The following option specifications are supported (note that option keywords are case-insensitive): .Bl -tag -width Ds +.It Cm cert-authority +Specifies that the listed key is a certification authority (CA) that is +trusted to validate signed certificates for user authentication. +.Pp +Certificates may encode access restrictions similar to these key options. +If both certificate restrictions and key options are present, the most +restrictive union of the two is applied. .It Cm command="command" Specifies that the command is executed whenever this key is used for authentication. @@ -520,6 +537,10 @@ The command originally supplied by the client is available in the .Ev SSH_ORIGINAL_COMMAND environment variable. Note that this option applies to shell, command or subsystem execution. +Also note that this command may be superseded by either a +.Xr sshd_config 5 +.Cm ForceCommand +directive or a command embedded in a certificate. .It Cm environment="NAME=value" Specifies that the string is to be added to the environment when logging in using this key. @@ -546,7 +567,7 @@ for more information on patterns. In addition to the wildcard matching that may be applied to hostnames or addresses, a .Cm from -stanza may match IP addressess using CIDR address/masklen notation. +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 @@ -616,10 +637,19 @@ 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. +Each line in these files contains the following fields: markers (optional), +hostnames, bits, exponent, modulus, comment. The fields are separated by spaces. .Pp +The marker is optional, but if it is present then it must be one of +.Dq @cert-authority , +to indicate that the line contains a certification authority (CA) key, +or +.Dq @revoked , +to indicate that the key contained on the line is revoked and must not ever +be accepted. +Only one marker should be used on a key line. +.Pp Hostnames is a comma-separated list of patterns .Pf ( Ql * and @@ -659,8 +689,25 @@ Lines starting with 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 +matching line has the proper key; either one that matches exactly or, +if the server has presented a certificate for authentication, the key +of the certification authority that signed the certificate. +For a key to be trusted as a certification authority, it must use the +.Dq @cert-authority +marker described above. +.Pp +The known hosts file also provides a facility to mark keys as revoked, +for example when it is known that the associated private key has been +stolen. +Revoked keys are specified by including the +.Dq @revoked +marker at the beginning of the key line, and are never accepted for +authentication or as certification authorities, but instead will +produce a warning from +.Xr ssh 1 +when they are encountered. +.Pp +It is permissible (but not recommended) to have several lines or different host keys for the same names. This will inevitably happen when short forms of host names @@ -671,10 +718,16 @@ 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 +Rather, generate them by a script, +.Xr ssh-keyscan 1 or by taking .Pa /etc/ssh/ssh_host_key.pub and adding the host names at the front. +.Xr ssh-keygen 1 +also offers some basic automated editing for +.Pa ~/.ssh/known_hosts +including removing hosts matching a host name and converting all host +names to their hashed representations. .Pp An example ssh_known_hosts file: .Bd -literal -offset 3n @@ -684,6 +737,10 @@ cvs.example.net,192.0.2.10 ssh-rsa AAAA1234.....= # A hashed hostname |1|JfKTdBh7rNbXkVAQCRp4OQoPfmI=|USECr3SWf1JUPsms5AqfD5QfxkM= ssh-rsa AAAA1234.....= +# A revoked key +@revoked * ssh-rsa AAAAB5W... +# A CA key, accepted for any host in *.mydomain.com or *.mydomain.org +@cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... .Ed .Sh FILES .Bl -tag -width Ds -compact diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c index 3b955d944..9cc12a3de 100644 --- a/crypto/openssh/sshd.c +++ b/crypto/openssh/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.366 2009/01/22 10:02:34 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.374 2010/03/07 11:57:13 dtucker Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -129,6 +129,7 @@ __RCSID("$FreeBSD$"); #include "ssh-gss.h" #endif #include "monitor_wrap.h" +#include "roaming.h" #include "version.h" #ifdef LIBWRAP @@ -216,6 +217,7 @@ struct { Key *server_key; /* ephemeral server key */ Key *ssh1_host_key; /* ssh1 host key */ Key **host_keys; /* all private host keys */ + Key **host_certificates; /* all public host certificates */ int have_ssh1_key; int have_ssh2_key; u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; @@ -320,6 +322,7 @@ sighup_restart(void) close_listen_socks(); close_startup_pipes(); alarm(0); /* alarm timer persists across exec */ + signal(SIGHUP, SIG_IGN); /* will be restored after exec */ execv(saved_argv[0], saved_argv); logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno)); @@ -431,7 +434,7 @@ sshd_exchange_identification(int sock_in, int sock_out) server_version_string = xstrdup(buf); /* Send our protocol version identification. */ - if (atomicio(vwrite, sock_out, server_version_string, + 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()); @@ -441,7 +444,7 @@ sshd_exchange_identification(int sock_in, int sock_out) /* Read other sides version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { - if (atomicio(read, sock_in, &buf[i], 1) != 1) { + if (roaming_atomicio(read, sock_in, &buf[i], 1) != 1) { logit("Did not receive identification string from %s", get_remote_ipaddr()); cleanup_exit(255); @@ -555,6 +558,10 @@ destroy_sensitive_data(void) key_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; } + if (sensitive_data.host_certificates[i]) { + key_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } } sensitive_data.ssh1_host_key = NULL; memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); @@ -581,6 +588,7 @@ demote_sensitive_data(void) if (tmp->type == KEY_RSA1) sensitive_data.ssh1_host_key = tmp; } + /* Certs do not need demotion */ } /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ @@ -589,7 +597,7 @@ demote_sensitive_data(void) static void privsep_preauth_child(void) { - u_int32_t rnd[256]; + u_int32_t rnd[256]; gid_t gidset[1]; /* Enable challenge-response authentication for privilege separation */ @@ -727,10 +735,11 @@ list_hostkey_types(void) const char *p; char *ret; int i; + Key *key; buffer_init(&b); for (i = 0; i < options.num_host_key_files; i++) { - Key *key = sensitive_data.host_keys[i]; + key = sensitive_data.host_keys[i]; if (key == NULL) continue; switch (key->type) { @@ -742,6 +751,19 @@ list_hostkey_types(void) buffer_append(&b, p, strlen(p)); break; } + /* If the private key has a cert peer, then list that too */ + key = sensitive_data.host_certificates[i]; + if (key == NULL) + continue; + switch (key->type) { + case KEY_RSA_CERT: + case KEY_DSA_CERT: + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + p = key_ssh_name(key); + buffer_append(&b, p, strlen(p)); + break; + } } buffer_append(&b, "\0", 1); ret = xstrdup(buffer_ptr(&b)); @@ -750,19 +772,36 @@ list_hostkey_types(void) return ret; } -Key * -get_hostkey_by_type(int type) +static Key * +get_hostkey_by_type(int type, int need_private) { int i; + Key *key; for (i = 0; i < options.num_host_key_files; i++) { - Key *key = sensitive_data.host_keys[i]; + if (type == KEY_RSA_CERT || type == KEY_DSA_CERT) + key = sensitive_data.host_certificates[i]; + else + key = sensitive_data.host_keys[i]; if (key != NULL && key->type == type) - return key; + return need_private ? + sensitive_data.host_keys[i] : key; } return NULL; } +Key * +get_hostkey_public_by_type(int type) +{ + return get_hostkey_by_type(type, 0); +} + +Key * +get_hostkey_private_by_type(int type) +{ + return get_hostkey_by_type(type, 1); +} + Key * get_hostkey_by_index(int ind) { @@ -777,8 +816,13 @@ 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); + if (key_is_cert(key)) { + if (key == sensitive_data.host_certificates[i]) + return (i); + } else { + if (key == sensitive_data.host_keys[i]) + return (i); + } } return (-1); } @@ -817,9 +861,9 @@ 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" +"usage: sshd [-46DdeiqTt] [-b bits] [-C connection_spec] [-c host_cert_file]\n" +" [-f config_file] [-g login_grace_time] [-h host_key_file]\n" +" [-k key_gen_time] [-o option] [-p port] [-u len]\n" ); exit(1); } @@ -990,15 +1034,9 @@ server_listen(void) &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 + if (ai->ai_family == AF_INET6) + sock_set_v6only(listen_sock); debug("Bind to port %s on %s.", strport, ntop); @@ -1252,7 +1290,7 @@ main(int ac, char **av) { extern char *optarg; extern int optind; - int opt, i, on = 1; + int opt, i, j, on = 1; int sock_in = -1, sock_out = -1, newsock = -1; const char *remote_ip; char *test_user = NULL, *test_host = NULL, *test_addr = NULL; @@ -1305,6 +1343,14 @@ main(int ac, char **av) case 'f': config_file_name = optarg; break; + case 'c': + if (options.num_host_cert_files >= MAX_HOSTCERTS) { + fprintf(stderr, "too many host certificates.\n"); + exit(1); + } + options.host_cert_files[options.num_host_cert_files++] = + derelativise_path(optarg); + break; case 'd': if (debug_flag == 0) { debug_flag = 1; @@ -1367,7 +1413,8 @@ main(int ac, char **av) fprintf(stderr, "too many host keys.\n"); exit(1); } - options.host_key_files[options.num_host_key_files++] = optarg; + options.host_key_files[options.num_host_key_files++] = + derelativise_path(optarg); break; case 't': test_flag = 1; @@ -1551,6 +1598,46 @@ main(int ac, char **av) exit(1); } + /* + * Load certificates. They are stored in an array at identical + * indices to the public keys that they relate to. + */ + sensitive_data.host_certificates = xcalloc(options.num_host_key_files, + sizeof(Key *)); + for (i = 0; i < options.num_host_key_files; i++) + sensitive_data.host_certificates[i] = NULL; + + for (i = 0; i < options.num_host_cert_files; i++) { + key = key_load_public(options.host_cert_files[i], NULL); + if (key == NULL) { + error("Could not load host certificate: %s", + options.host_cert_files[i]); + continue; + } + if (!key_is_cert(key)) { + error("Certificate file is not a certificate: %s", + options.host_cert_files[i]); + key_free(key); + continue; + } + /* Find matching private key */ + for (j = 0; j < options.num_host_key_files; j++) { + if (key_equal_public(key, + sensitive_data.host_keys[j])) { + sensitive_data.host_certificates[j] = key; + break; + } + } + if (j >= options.num_host_key_files) { + error("No matching private key for certificate: %s", + options.host_cert_files[i]); + key_free(key); + continue; + } + sensitive_data.host_certificates[j] = key; + debug("host certificate: #%d type %d %s", j, key->type, + key_type(key)); + } /* Check certain values for sanity. */ if (options.protocol & SSH_PROTO_1) { if (options.server_key_bits < 512 || @@ -1677,6 +1764,7 @@ main(int ac, char **av) if (inetd_flag) { server_accept_inetd(&sock_in, &sock_out); } else { + platform_pre_listen(); server_listen(); if (options.protocol & SSH_PROTO_1) @@ -1766,6 +1854,10 @@ main(int ac, char **av) sock_in, sock_out, newsock, startup_pipe, config_s[0]); } + /* Executed child processes don't need these. */ + fcntl(sock_out, F_SETFD, FD_CLOEXEC); + fcntl(sock_in, F_SETFD, FD_CLOEXEC); + /* * Disable the key regeneration alarm. We will not regenerate the * key since we are no longer in a position to give it to anyone. We @@ -1886,6 +1978,7 @@ main(int ac, char **av) /* prepare buffer to collect messages to display to user after login */ buffer_init(&loginmsg); + auth_debug_reset(); if (use_privsep) if (privsep_preauth(authctxt) == 1) @@ -2242,7 +2335,8 @@ do_ssh2_kex(void) 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->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; kex->host_key_index=&get_hostkey_index; xxx_kex = kex; diff --git a/crypto/openssh/sshd_config b/crypto/openssh/sshd_config index c2c08843d..44b75821e 100644 --- a/crypto/openssh/sshd_config +++ b/crypto/openssh/sshd_config @@ -1,4 +1,4 @@ -# $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $ +# $OpenBSD: sshd_config,v 1.81 2009/10/08 14:03:41 markus Exp $ # $FreeBSD$ # This is the sshd server system-wide configuration file. See @@ -14,18 +14,15 @@ # Note that some of FreeBSD's defaults differ from OpenBSD's, and # FreeBSD has a few additional options. -#VersionAddendum FreeBSD-20090522 +#VersionAddendum FreeBSD-20100308 #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 +# The default requires explicit activation of protocol 1 +#Protocol 2 # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key diff --git a/crypto/openssh/sshd_config.5 b/crypto/openssh/sshd_config.5 index 6779f0a5e..d0d3053b7 100644 --- a/crypto/openssh/sshd_config.5 +++ b/crypto/openssh/sshd_config.5 @@ -34,9 +34,9 @@ .\" (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.102 2009/02/22 23:59:25 djm Exp $ +.\" $OpenBSD: sshd_config.5,v 1.120 2010/03/04 23:17:25 djm Exp $ .\" $FreeBSD$ -.Dd February 22 2009 +.Dd March 4 2010 .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -177,19 +177,22 @@ 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. -See also -.Cm UsePAM . +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 +Specifies the pathname of a directory to .Xr chroot 2 to after authentication. -This path, and all its components, must be root-owned directories that are +All components of the pathname must be root-owned directories that are not writable by any other user or group. +After the chroot, +.Xr sshd 8 +changes the working directory to the user's home directory. .Pp -The path may contain the following tokens that are expanded at runtime once +The pathname may contain the following tokens that are expanded at runtime once the connecting user has been authenticated: %% is replaced by a literal '%', %h is replaced by the home directory of the user being authenticated, and %u is replaced by the username of that user. @@ -197,7 +200,7 @@ the connecting user has been authenticated: %% is replaced by a literal '%', The .Cm ChrootDirectory must contain the necessary files and directories to support the -users' session. +user's session. For an interactive session this requires at least a shell, typically .Xr sh 1 , and basic @@ -215,8 +218,11 @@ devices. For file transfer sessions using .Dq sftp , no additional configuration of the environment is necessary if the -in-process sftp server is used (see -.Cm Subsystem +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 @@ -406,6 +412,14 @@ uses the name supplied by the client rather than attempting to resolve the name from the TCP connection itself. The default is .Dq no . +.It Cm HostCertificate +Specifies a file containing a public host certificate. +The certificate's public key must match a private host key already specified +by +.Cm HostKey . +The default behaviour of +.Xr sshd 8 +is not to load any certificates. .It Cm HostKey Specifies a file containing a private host key used by SSH. @@ -609,6 +623,7 @@ Available keywords are .Cm PermitEmptyPasswords , .Cm PermitOpen , .Cm PermitRootLogin , +.Cm PubkeyAuthentication , .Cm RhostsRSAAuthentication , .Cm RSAAuthentication , .Cm X11DisplayOffset , @@ -796,7 +811,7 @@ and .Sq 2 . Multiple versions must be comma-separated. The default is -.Dq 2 . +.Sq 2 . Note that the order of the protocol list does not indicate preference, because the client selects among multiple protocol versions offered by the server. @@ -809,6 +824,11 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm RevokedKeys +Specifies a list of revoked public keys. +Keys listed in this file will be refused for public key authentication. +Note that if this file is not readable, then public key authentication will +be refused for all users. .It Cm RhostsRSAAuthentication Specifies whether rhosts or .Pa /etc/hosts.equiv @@ -834,6 +854,9 @@ This is normally desirable because novices sometimes accidentally leave their directory or files world-writable. The default is .Dq yes . +Note that this does not apply to +.Cm ChrootDirectory , +whose permissions and ownership are checked unconditionally. .It Cm Subsystem Configures an external subsystem (e.g. file transfer daemon). Arguments should be a subsystem name and a command (with optional arguments) @@ -883,6 +906,22 @@ This avoids infinitely hanging sessions. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm TrustedUserCAKeys +Specifies a file containing public keys of certificate authorities that are +trusted to sign user certificates for authentication. +Keys are listed one per line; empty lines and comments starting with +.Ql # +are allowed. +If a certificate is presented for authentication and has its signing CA key +listed in this file, then it may be used for authentication for any user +listed in the certificate's principals list. +Note that certificates that lack a list of principals will not be permitted +for authentication using +.Cm TrustedUserCAKeys . +For more details on certificates, see the +.Sx CERTIFICATES +section in +.Xr ssh-keygen 1 . .It Cm UseDNS Specifies whether .Xr sshd 8 @@ -949,7 +988,7 @@ The default is Specifies a string to append to the regular version string to identify OS- or site-specific modifications. The default is -.Dq FreeBSD-20090522 . +.Dq FreeBSD-20100308 . .It Cm X11DisplayOffset Specifies the first display number available for .Xr sshd 8 Ns 's diff --git a/crypto/openssh/sshlogin.c b/crypto/openssh/sshlogin.c index cc35d6024..33bd652fb 100644 --- a/crypto/openssh/sshlogin.c +++ b/crypto/openssh/sshlogin.c @@ -86,13 +86,20 @@ get_last_login_time(uid_t uid, const char *logname, 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; -#ifndef NO_SSH_LASTLOG 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)); @@ -107,6 +114,7 @@ store_lastlog_message(const char *user, uid_t uid) time_string, hostname); buffer_append(&loginmsg, buf, strlen(buf)); } +# endif /* CUSTOM_SYS_AUTH_GET_LASTLOGIN_MSG */ #endif /* NO_SSH_LASTLOG */ } diff --git a/crypto/openssh/sshpty.h b/crypto/openssh/sshpty.h index ac9003584..cfa322480 100644 --- a/crypto/openssh/sshpty.h +++ b/crypto/openssh/sshpty.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshpty.h,v 1.11 2008/05/19 15:45:07 djm Exp $ */ +/* $OpenBSD: sshpty.h,v 1.12 2010/01/09 05:04:24 djm Exp $ */ /* * Author: Tatu Ylonen @@ -17,8 +17,8 @@ #include struct termios *get_saved_tio(void); -void leave_raw_mode(void); -void enter_raw_mode(void); +void leave_raw_mode(int); +void enter_raw_mode(int); int pty_allocate(int *, int *, char *, size_t); void pty_release(const char *); diff --git a/crypto/openssh/sshtty.c b/crypto/openssh/sshtty.c index 21ade4e51..d214ce3bb 100644 --- a/crypto/openssh/sshtty.c +++ b/crypto/openssh/sshtty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshtty.c,v 1.13 2008/05/19 15:45:07 djm Exp $ */ +/* $OpenBSD: sshtty.c,v 1.14 2010/01/09 05:04:24 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -54,23 +54,25 @@ get_saved_tio(void) } void -leave_raw_mode(void) +leave_raw_mode(int quiet) { if (!_in_raw_mode) return; - if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) - perror("tcsetattr"); - else + if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) { + if (!quiet) + perror("tcsetattr"); + } else _in_raw_mode = 0; } void -enter_raw_mode(void) +enter_raw_mode(int quiet) { struct termios tio; if (tcgetattr(fileno(stdin), &tio) == -1) { - perror("tcgetattr"); + if (!quiet) + perror("tcgetattr"); return; } _saved_tio = tio; @@ -86,8 +88,9 @@ enter_raw_mode(void) tio.c_oflag &= ~OPOST; tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; - if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) - perror("tcsetattr"); - else + if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) { + if (!quiet) + perror("tcsetattr"); + } else _in_raw_mode = 1; } diff --git a/crypto/openssh/uuencode.c b/crypto/openssh/uuencode.c index a13949585..b9e57e993 100644 --- a/crypto/openssh/uuencode.c +++ b/crypto/openssh/uuencode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uuencode.c,v 1.24 2006/08/03 03:34:42 deraadt Exp $ */ +/* $OpenBSD: uuencode.c,v 1.25 2009/03/05 11:30:50 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -33,6 +33,12 @@ #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) @@ -40,6 +46,11 @@ uuencode(const u_char *src, u_int srclength, 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) { diff --git a/crypto/openssh/version.h b/crypto/openssh/version.h index ff87b920e..d1d1452e9 100644 --- a/crypto/openssh/version.h +++ b/crypto/openssh/version.h @@ -1,12 +1,12 @@ -/* $OpenBSD: version.h,v 1.55 2009/02/23 00:06:15 djm Exp $ */ +/* $OpenBSD: version.h,v 1.57 2010/03/07 22:01:32 djm Exp $ */ /* $FreeBSD$ */ #ifndef SSH_VERSION #define SSH_VERSION (ssh_version_get()) #define SSH_RELEASE (ssh_version_get()) -#define SSH_VERSION_BASE "OpenSSH_5.2p1" -#define SSH_VERSION_ADDENDUM "FreeBSD-20090522" +#define SSH_VERSION_BASE "OpenSSH_5.4p1" +#define SSH_VERSION_ADDENDUM "FreeBSD-20100308" const char *ssh_version_get(void); void ssh_version_set_addendum(const char *); diff --git a/lib/libpam/modules/pam_ssh/Makefile b/lib/libpam/modules/pam_ssh/Makefile index f7dcd0c54..b638d8b05 100644 --- a/lib/libpam/modules/pam_ssh/Makefile +++ b/lib/libpam/modules/pam_ssh/Makefile @@ -7,6 +7,9 @@ LIB= pam_ssh MAN= pam_ssh.8 SRCS= pam_ssh.c +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + WARNS?= 0 CFLAGS+= -I${SSHDIR} -include ssh_namespace.h diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.c b/lib/libpam/modules/pam_ssh/pam_ssh.c index 25c63ca75..9d89045ac 100644 --- a/lib/libpam/modules/pam_ssh/pam_ssh.c +++ b/lib/libpam/modules/pam_ssh/pam_ssh.c @@ -61,6 +61,9 @@ __FBSDID("$FreeBSD$"); #include "authfd.h" #include "authfile.h" +#define ssh_add_identity(auth, key, comment) \ + ssh_add_identity_constrained(auth, key, comment, 0, 0) + extern char **environ; struct pam_ssh_key { diff --git a/secure/lib/libssh/Makefile b/secure/lib/libssh/Makefile index ecc1a9281..d50b8d138 100644 --- a/secure/lib/libssh/Makefile +++ b/secure/lib/libssh/Makefile @@ -12,14 +12,15 @@ SRCS= acss.c authfd.c authfile.c bufaux.c bufbn.c buffer.c \ readpass.c rsa.c ttymodes.c xmalloc.c addrmatch.c \ atomicio.c key.c dispatch.c kex.c mac.c uidswap.c uuencode.c misc.c \ monitor_fdpass.c rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c \ - kexgex.c kexdhc.c kexgexc.c scard.c msg.c progressmeter.c dns.c \ - entropy.c scard-opensc.c umac.c jpake.c schnorr.c + kexgex.c kexdhc.c kexgexc.c msg.c progressmeter.c dns.c \ + entropy.c umac.c jpake.c schnorr.c \ + ssh-pkcs11.c # gss-genr.c should be in $SRCS but causes linking problems, so it is # compiled directly into sshd instead. # Portability layer -SRCS+= bsd-misc.c fmt_scaled.c getrrsetbyname.c \ +SRCS+= bsd-misc.c fmt_scaled.c getrrsetbyname.c glob.c \ openssl-compat.c port-tun.c strtonum.c vis.c xcrypt.c xmmap.c # FreeBSD additions SRCS+= version.c diff --git a/secure/libexec/Makefile b/secure/libexec/Makefile index 1c3ee015a..0c680e4d7 100644 --- a/secure/libexec/Makefile +++ b/secure/libexec/Makefile @@ -4,7 +4,7 @@ SUBDIR= .if ${MK_OPENSSH} != "no" -SUBDIR+=sftp-server ssh-keysign +SUBDIR+=sftp-server ssh-keysign ssh-pkcs11-helper .endif .include diff --git a/secure/libexec/sftp-server/Makefile b/secure/libexec/sftp-server/Makefile index 22ce64945..7069cff90 100644 --- a/secure/libexec/sftp-server/Makefile +++ b/secure/libexec/sftp-server/Makefile @@ -5,8 +5,11 @@ SRCS= sftp-server.c sftp-common.c sftp-server-main.c MAN= sftp-server.8 CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} -LDADD= -lssh -lcrypt -lcrypto -lz +LDADD= -lssh -lcrypt -lcrypto -lz .include diff --git a/secure/libexec/ssh-keysign/Makefile b/secure/libexec/ssh-keysign/Makefile index 6018b9482..75f1b6c4c 100644 --- a/secure/libexec/ssh-keysign/Makefile +++ b/secure/libexec/ssh-keysign/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= ssh-keysign -SRCS= ssh-keysign.c readconf.c +SRCS= ssh-keysign.c readconf.c roaming_dummy.c MAN= ssh-keysign.8 CFLAGS+=-I${SSHDIR} -include ssh_namespace.h .if defined(ENABLE_SUID_SSH) diff --git a/secure/libexec/ssh-pkcs11-helper/Makefile b/secure/libexec/ssh-pkcs11-helper/Makefile new file mode 100644 index 000000000..f575a08af --- /dev/null +++ b/secure/libexec/ssh-pkcs11-helper/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD$ + +PROG= ssh-pkcs11-helper +SRCS= ssh-pkcs11.c ssh-pkcs11-helper.c +SRCS+= roaming_dummy.c +MAN= ssh-pkcs11-helper.8 +CFLAGS+=-I${SSHDIR} -include ssh_namespace.h + +DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} +LDADD= -lssh -lcrypt -lcrypto -lz + +.include + +.PATH: ${SSHDIR} + +${OBJS} ${POBJS} ${SOBJS}: ssh_namespace.h diff --git a/secure/usr.bin/scp/Makefile b/secure/usr.bin/scp/Makefile index ddb2b0930..8a558c77b 100644 --- a/secure/usr.bin/scp/Makefile +++ b/secure/usr.bin/scp/Makefile @@ -1,8 +1,12 @@ # $FreeBSD$ PROG= scp +SRCS= scp.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} LDADD= -lssh -lcrypt -lcrypto -lz diff --git a/secure/usr.bin/sftp/Makefile b/secure/usr.bin/sftp/Makefile index 29c435272..dce010484 100644 --- a/secure/usr.bin/sftp/Makefile +++ b/secure/usr.bin/sftp/Makefile @@ -4,6 +4,9 @@ PROG= sftp SRCS= sftp.c sftp-client.c sftp-common.c sftp-glob.c progressmeter.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} ${LIBEDIT} ${LIBNCURSES} LDADD= -lssh -lcrypt -lcrypto -lz -ledit -lncurses diff --git a/secure/usr.bin/ssh-add/Makefile b/secure/usr.bin/ssh-add/Makefile index 34d66a6a7..0cbcbcb1a 100644 --- a/secure/usr.bin/ssh-add/Makefile +++ b/secure/usr.bin/ssh-add/Makefile @@ -1,8 +1,12 @@ # $FreeBSD$ PROG= ssh-add +SRCS+= ssh-add.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} LDADD= -lssh -lcrypt -lcrypto -lz diff --git a/secure/usr.bin/ssh-agent/Makefile b/secure/usr.bin/ssh-agent/Makefile index ed99a01ce..a93a1c647 100644 --- a/secure/usr.bin/ssh-agent/Makefile +++ b/secure/usr.bin/ssh-agent/Makefile @@ -1,8 +1,12 @@ # $FreeBSD$ PROG= ssh-agent +SRCS= ssh-agent.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} LDADD= -lssh -lcrypt -lcrypto -lz diff --git a/secure/usr.bin/ssh-keygen/Makefile b/secure/usr.bin/ssh-keygen/Makefile index 30adcf214..0c2503310 100644 --- a/secure/usr.bin/ssh-keygen/Makefile +++ b/secure/usr.bin/ssh-keygen/Makefile @@ -1,8 +1,12 @@ # $FreeBSD$ PROG= ssh-keygen +SRCS= ssh-keygen.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h +# required when linking with a dynamic libssh +SRCS+= roaming_dummy.c + DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} LDADD= -lssh -lcrypt -lcrypto -lz diff --git a/secure/usr.bin/ssh-keyscan/Makefile b/secure/usr.bin/ssh-keyscan/Makefile index f59542e55..8d3f6c6b4 100644 --- a/secure/usr.bin/ssh-keyscan/Makefile +++ b/secure/usr.bin/ssh-keyscan/Makefile @@ -1,6 +1,7 @@ # $FreeBSD$ PROG= ssh-keyscan +SRCS= ssh-keyscan.c roaming_dummy.c CFLAGS+=-I${SSHDIR} -include ssh_namespace.h DPADD= ${LIBSSH} ${LIBCRYPT} ${LIBCRYPTO} ${LIBZ} diff --git a/secure/usr.bin/ssh/Makefile b/secure/usr.bin/ssh/Makefile index 11ab8633f..f85784ee0 100644 --- a/secure/usr.bin/ssh/Makefile +++ b/secure/usr.bin/ssh/Makefile @@ -11,7 +11,10 @@ MLINKS= ssh.1 slogin.1 SRCS= ssh.c readconf.c clientloop.c sshtty.c \ sshconnect.c sshconnect1.c sshconnect2.c mux.c \ - gss-genr.c + roaming_common.c roaming_client.c + +# gss-genr.c really belongs in libssh; see src/secure/lib/libssh/Makefile +SRCS+= gss-genr.c DPADD= ${LIBSSH} ${LIBUTIL} ${LIBZ} LDADD= -lssh -lutil -lz diff --git a/secure/usr.sbin/sshd/Makefile b/secure/usr.sbin/sshd/Makefile index 282a40239..b0b8bb778 100644 --- a/secure/usr.sbin/sshd/Makefile +++ b/secure/usr.sbin/sshd/Makefile @@ -15,9 +15,10 @@ SRCS= sshd.c auth-rhosts.c auth-passwd.c auth-rsa.c auth-rh-rsa.c \ auth2-gss.c gss-serv.c gss-serv-krb5.c \ loginrec.c auth-pam.c auth-shadow.c auth-sia.c md5crypt.c \ audit.c audit-bsm.c platform.c sftp-server.c sftp-common.c \ - gss-genr.c + roaming_common.c roaming_serv.c # gss-genr.c really belongs in libssh; see src/secure/lib/libssh/Makefile +SRCS+= gss-genr.c MAN= sshd.8 sshd_config.5 CFLAGS+=-I${SSHDIR} -include ssh_namespace.h @@ -33,8 +34,8 @@ LDADD+= -lbsm .if ${MK_KERBEROS_SUPPORT} != "no" CFLAGS+= -DGSSAPI -DHAVE_GSSAPI_GSSAPI_H=1 -DHAVE_GSSAPI_GSSAPI_KRB5_H=1 -DKRB5 -DHEIMDAL -DPADD+= ${LIBGSSAPI} ${LIBGSSAPI_KRB5} -LDADD+= -lgssapi -lgssapi_krb5 +DPADD+= ${LIBGSSAPI_KRB5} ${LIBGSSAPI} ${LIBKRB5} ${LIBASN1} +LDADD+= -lgssapi_krb5 -lgssapi -lkrb5 -lasn1 .endif .if defined(X11BASE) -- 2.45.0