Import OpenSSH-7.6p1
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Oct 2017 01:32:28 +0000 (18:32 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Oct 2017 01:34:06 +0000 (18:34 -0700)
* Import OpeNSSH-7.6p1.  Couldn't really merge from the vendor branch
  so just brought it in.

* Adjustments for WARNS issues

198 files changed:
crypto/openssh/CREDITS
crypto/openssh/LICENCE
crypto/openssh/PROTOCOL
crypto/openssh/PROTOCOL.agent
crypto/openssh/PROTOCOL.certkeys
crypto/openssh/README
crypto/openssh/addrmatch.c
crypto/openssh/atomicio.c
crypto/openssh/audit-bsm.c
crypto/openssh/audit.c
crypto/openssh/audit.h
crypto/openssh/auth-chall.c
crypto/openssh/auth-options.c
crypto/openssh/auth-options.h
crypto/openssh/auth-pam.c
crypto/openssh/auth-pam.h
crypto/openssh/auth-rh-rsa.c
crypto/openssh/auth-rhosts.c
crypto/openssh/auth-rsa.c
crypto/openssh/auth.c
crypto/openssh/auth.h
crypto/openssh/auth1.c
crypto/openssh/auth2-chall.c
crypto/openssh/auth2-gss.c
crypto/openssh/auth2-hostbased.c
crypto/openssh/auth2-kbdint.c
crypto/openssh/auth2-none.c
crypto/openssh/auth2-passwd.c
crypto/openssh/auth2-pubkey.c
crypto/openssh/auth2.c
crypto/openssh/authfd.c
crypto/openssh/authfd.h
crypto/openssh/authfile.c
crypto/openssh/bitmap.c
crypto/openssh/bufbn.c
crypto/openssh/buffer.h
crypto/openssh/chacha.h
crypto/openssh/channels.c
crypto/openssh/channels.h
crypto/openssh/cipher-3des1.c
crypto/openssh/cipher-bf1.c
crypto/openssh/cipher-chachapoly.c
crypto/openssh/cipher.c
crypto/openssh/cipher.h
crypto/openssh/clientloop.c
crypto/openssh/clientloop.h
crypto/openssh/compat.c
crypto/openssh/compat.h
crypto/openssh/deattack.c
crypto/openssh/deattack.h
crypto/openssh/defines.h
crypto/openssh/dh.c
crypto/openssh/digest-openssl.c
crypto/openssh/digest.h
crypto/openssh/dispatch.c
crypto/openssh/dispatch.h
crypto/openssh/dns.c
crypto/openssh/dns.h
crypto/openssh/entropy.h
crypto/openssh/gss-genr.c
crypto/openssh/gss-serv.c
crypto/openssh/hmac.c
crypto/openssh/hostfile.c
crypto/openssh/includes.h
crypto/openssh/kex.c
crypto/openssh/kex.h
crypto/openssh/kexc25519c.c
crypto/openssh/kexc25519s.c
crypto/openssh/kexdhc.c
crypto/openssh/kexdhs.c
crypto/openssh/kexecdhc.c
crypto/openssh/kexecdhs.c
crypto/openssh/kexgexc.c
crypto/openssh/kexgexs.c
crypto/openssh/key.c
crypto/openssh/key.h
crypto/openssh/krl.c
crypto/openssh/log.c
crypto/openssh/log.h
crypto/openssh/mac.c
crypto/openssh/match.c
crypto/openssh/match.h
crypto/openssh/md-sha256.c
crypto/openssh/md5crypt.h
crypto/openssh/misc.c
crypto/openssh/misc.h
crypto/openssh/moduli
crypto/openssh/moduli.5
crypto/openssh/moduli.c
crypto/openssh/monitor.c
crypto/openssh/monitor.h
crypto/openssh/monitor_mm.c
crypto/openssh/monitor_mm.h
crypto/openssh/monitor_wrap.c
crypto/openssh/monitor_wrap.h
crypto/openssh/mux.c
crypto/openssh/myproposal.h
crypto/openssh/nchan.c
crypto/openssh/opacket.c
crypto/openssh/opacket.h
crypto/openssh/openbsd-compat/base64.h
crypto/openssh/openbsd-compat/bsd-cray.h
crypto/openssh/openbsd-compat/bsd-cygwin_util.h
crypto/openssh/openbsd-compat/bsd-getpagesize.c [new file with mode: 0644]
crypto/openssh/openbsd-compat/bsd-malloc.c [copied from crypto/openssh/openbsd-compat/port-solaris.h with 55% similarity]
crypto/openssh/openbsd-compat/bsd-misc.c
crypto/openssh/openbsd-compat/bsd-misc.h
crypto/openssh/openbsd-compat/bsd-nextstep.h
crypto/openssh/openbsd-compat/bsd-setres_id.h
crypto/openssh/openbsd-compat/bsd-statvfs.h
crypto/openssh/openbsd-compat/bsd-waitpid.h
crypto/openssh/openbsd-compat/explicit_bzero.c
crypto/openssh/openbsd-compat/fake-rfc2553.h
crypto/openssh/openbsd-compat/fmt_scaled.c
crypto/openssh/openbsd-compat/freezero.c [copied from crypto/openssh/openbsd-compat/bsd-setres_id.h with 73% similarity]
crypto/openssh/openbsd-compat/openbsd-compat.h
crypto/openssh/openbsd-compat/openssl-compat.c
crypto/openssh/openbsd-compat/openssl-compat.h
crypto/openssh/openbsd-compat/port-aix.h
crypto/openssh/openbsd-compat/port-irix.h
crypto/openssh/openbsd-compat/port-linux.h
crypto/openssh/openbsd-compat/port-solaris.h
crypto/openssh/openbsd-compat/port-tun.c
crypto/openssh/openbsd-compat/port-tun.h
crypto/openssh/openbsd-compat/recallocarray.c [new file with mode: 0644]
crypto/openssh/openbsd-compat/sha2.h
crypto/openssh/openbsd-compat/strcasestr.c [new file with mode: 0644]
crypto/openssh/openbsd-compat/vis.c
crypto/openssh/packet.c
crypto/openssh/packet.h
crypto/openssh/pathnames.h
crypto/openssh/platform-misc.c [copied from crypto/openssh/openbsd-compat/bsd-setres_id.h with 66% similarity]
crypto/openssh/platform-tracing.c
crypto/openssh/platform.c
crypto/openssh/platform.h
crypto/openssh/readconf.c
crypto/openssh/readconf.h
crypto/openssh/rsa.c
crypto/openssh/rsa.h
crypto/openssh/sandbox-rlimit.c
crypto/openssh/scp.1
crypto/openssh/scp.c
crypto/openssh/servconf.c
crypto/openssh/servconf.h
crypto/openssh/serverloop.c
crypto/openssh/serverloop.h
crypto/openssh/session.c
crypto/openssh/session.h
crypto/openssh/sftp-client.c
crypto/openssh/sftp-common.c
crypto/openssh/sftp-server.c
crypto/openssh/sftp.1
crypto/openssh/sftp.c
crypto/openssh/ssh-add.1
crypto/openssh/ssh-add.c
crypto/openssh/ssh-agent.1
crypto/openssh/ssh-agent.c
crypto/openssh/ssh-gss.h
crypto/openssh/ssh-keygen.1
crypto/openssh/ssh-keygen.c
crypto/openssh/ssh-keyscan.1
crypto/openssh/ssh-keyscan.c
crypto/openssh/ssh-pkcs11-client.c
crypto/openssh/ssh-pkcs11-helper.c
crypto/openssh/ssh-pkcs11.c
crypto/openssh/ssh-rsa.c
crypto/openssh/ssh.1
crypto/openssh/ssh.c
crypto/openssh/ssh.h
crypto/openssh/ssh1.h
crypto/openssh/ssh_api.c
crypto/openssh/ssh_config
crypto/openssh/ssh_config.5
crypto/openssh/sshbuf-getput-basic.c
crypto/openssh/sshbuf.c
crypto/openssh/sshbuf.h
crypto/openssh/sshconnect.c
crypto/openssh/sshconnect.h
crypto/openssh/sshconnect1.c
crypto/openssh/sshconnect2.c
crypto/openssh/sshd.8
crypto/openssh/sshd.c
crypto/openssh/sshd_config
crypto/openssh/sshd_config.5
crypto/openssh/ssherr.c
crypto/openssh/ssherr.h
crypto/openssh/sshkey.c
crypto/openssh/sshkey.h
crypto/openssh/sshpty.c
crypto/openssh/sshpty.h
crypto/openssh/ttymodes.c
crypto/openssh/ttymodes.h
crypto/openssh/umac.c
crypto/openssh/utf8.c
crypto/openssh/utf8.h
crypto/openssh/version.h
crypto/openssh/xmalloc.c
crypto/openssh/xmalloc.h

index eaf105a..43be5e5 100644 (file)
@@ -100,6 +100,3 @@ Zack Weinberg <zack@wolery.cumb.org> - GNOME askpass enhancement
 Apologies to anyone I have missed.
 
 Damien Miller <djm@mindrot.org>
-
-$Id: CREDITS,v 1.81 2006/08/30 17:24:41 djm Exp $
-
index f523871..1524821 100644 (file)
@@ -75,27 +75,6 @@ OpenSSH contains no GPL code.
     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
     POSSIBILITY OF SUCH DAMAGES.
 
-2)
-    The 32-bit CRC compensation attack detector in deattack.c was
-    contributed by CORE SDI S.A. under a BSD-style license.
-
-     * Cryptographic attack detector for ssh - source code
-     *
-     * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
-     *
-     * All rights reserved. Redistribution and use in source and binary
-     * forms, with or without modification, are permitted provided that
-     * this copyright notice is retained.
-     *
-     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-     * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
-     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
-     * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
-     * SOFTWARE.
-     *
-     * Ariel Futoransky <futo@core-sdi.com>
-     * <http://www.core-sdi.com>
-
 3)
     ssh-keyscan was contributed by David Mazieres under a BSD-style
     license.
@@ -337,4 +316,4 @@ OpenSSH contains no GPL code.
 
 
 ------
-$OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $
+$OpenBSD: LICENCE,v 1.20 2017/04/30 23:26:16 djm Exp $
index c6f99a3..4e9e875 100644 (file)
@@ -4,7 +4,7 @@ protocol.
 Note that OpenSSH's sftp and sftp-server implement revision 3 of the SSH
 filexfer protocol described in:
 
-http://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
+https://www.openssh.com/txt/draft-ietf-secsh-filexfer-02.txt
 
 Newer versions of the draft will not be supported, though some features
 are individually implemented as extensions described below.
@@ -20,7 +20,7 @@ This is a new transport-layer MAC method using the UMAC algorithm
 (rfc4418). This method is identical to the "umac-64" method documented
 in:
 
-http://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
+https://www.openssh.com/txt/draft-miller-secsh-umac-01.txt
 
 1.2. transport: Protocol 2 compression algorithm "zlib@openssh.com"
 
@@ -31,10 +31,10 @@ avoids exposing compression code to attacks from unauthenticated users.
 
 The method is documented in:
 
-http://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
+https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
 
-1.3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com",
-     "ssh-dsa-cert-v00@openssh.com",
+1.3. transport: New public key algorithms "ssh-rsa-cert-v01@openssh.com",
+     "ssh-dsa-cert-v01@openssh.com",
      "ecdsa-sha2-nistp256-cert-v01@openssh.com",
      "ecdsa-sha2-nistp384-cert-v01@openssh.com" and
      "ecdsa-sha2-nistp521-cert-v01@openssh.com"
@@ -454,4 +454,4 @@ respond with a SSH_FXP_STATUS message.
 This extension is advertised in the SSH_FXP_VERSION hello with version
 "1".
 
-$OpenBSD: PROTOCOL,v 1.30 2016/04/08 06:35:54 djm Exp $
+$OpenBSD: PROTOCOL,v 1.31 2017/05/26 01:40:07 djm Exp $
index 60d36f9..da33819 100644 (file)
@@ -1,582 +1,5 @@
-This describes the protocol used by OpenSSH's ssh-agent.
+This file used to contain a description of the SSH agent protocol
+implemented by OpenSSH. It has since been superseded by an Internet-
+draft that is available from:
 
-OpenSSH's agent supports managing keys for the standard SSH protocol
-2 as well as the legacy SSH protocol 1. Support for these key types
-is almost completely disjoint - in all but a few cases, operations on
-protocol 2 keys cannot see or affect protocol 1 keys and vice-versa.
-
-Protocol 1 and protocol 2 keys are separated because of the differing
-cryptographic usage: protocol 1 private RSA keys are used to decrypt
-challenges that were encrypted with the corresponding public key,
-whereas protocol 2 RSA private keys are used to sign challenges with
-a private key for verification with the corresponding public key. It
-is considered unsound practice to use the same key for signing and
-encryption.
-
-With a couple of exceptions, the protocol message names used in this
-document indicate which type of key the message relates to. SSH_*
-messages refer to protocol 1 keys only. SSH2_* messages refer to
-protocol 2 keys. Furthermore, the names also indicate whether the
-message is a request to the agent (*_AGENTC_*) or a reply from the
-agent (*_AGENT_*). Section 3 below contains the mapping of the
-protocol message names to their integer values.
-
-1. Data types
-
-Because of support for legacy SSH protocol 1 keys, OpenSSH's agent
-protocol makes use of some data types not defined in RFC 4251.
-
-1.1 uint16
-
-The "uint16" data type is a simple MSB-first 16 bit unsigned integer
-encoded in two bytes.
-
-1.2 mpint1
-
-The "mpint1" type represents an arbitrary precision integer (bignum).
-Its format is as follows:
-
-       uint16                  bits
-       byte[(bits + 7) / 8]    bignum
-
-"bignum" contains an unsigned arbitrary precision integer encoded as
-eight bits per byte in big-endian (MSB first) format.
-
-Note the difference between the "mpint1" encoding and the "mpint"
-encoding defined in RFC 4251. Also note that the length of the encoded
-integer is specified in bits, not bytes and that the byte length of
-the integer must be calculated by rounding up the number of bits to the
-nearest eight.
-
-2. Protocol Messages
-
-All protocol messages are prefixed with their length in bytes, encoded
-as a 32 bit unsigned integer. Specifically:
-
-       uint32                  message_length
-       byte[message_length]    message
-
-The following message descriptions refer only to the content the
-"message" field.
-
-2.1 Generic server responses
-
-The following generic messages may be sent by the server in response to
-requests from the client. On success the agent may reply either with:
-
-       byte                    SSH_AGENT_SUCCESS
-
-or a request-specific success message.
-
-On failure, the agent may reply with:
-
-       byte                    SSH_AGENT_FAILURE
-
-SSH_AGENT_FAILURE messages are also sent in reply to unknown request
-types.
-
-2.2 Adding keys to the agent
-
-Keys are added to the agent using the SSH_AGENTC_ADD_RSA_IDENTITY and
-SSH2_AGENTC_ADD_IDENTITY requests for protocol 1 and protocol 2 keys
-respectively.
-
-Two variants of these requests are SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
-and SSH2_AGENTC_ADD_ID_CONSTRAINED - these add keys with optional
-"constraints" on their usage.
-
-OpenSSH may be built with support for keys hosted on a smartcard
-or other hardware security module. These keys may be added
-to the agent using the SSH_AGENTC_ADD_SMARTCARD_KEY and
-SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED requests.
-
-2.2.1 Key constraints
-
-The OpenSSH agent supports some basic optional constraints on key usage.
-At present there are two constraints defined.
-
-The first constraint limits the validity duration of a key. It is
-encoded as:
-
-       byte                    SSH_AGENT_CONSTRAIN_LIFETIME
-       uint32                  seconds
-
-Where "seconds" contains the number of seconds that the key shall remain
-valid measured from the moment that the agent receives it. After the
-validity period has expired, OpenSSH's agent will erase these keys from
-memory.
-
-The second constraint requires the agent to seek explicit user
-confirmation before performing private key operations with the loaded
-key. This constraint is encoded as:
-
-       byte                    SSH_AGENT_CONSTRAIN_CONFIRM
-
-Zero or more constraints may be specified when adding a key with one
-of the *_CONSTRAINED requests. Multiple constraints are appended
-consecutively to the end of the request:
-
-       byte                    constraint1_type
-       ....                    constraint1_data
-       byte                    constraint2_type
-       ....                    constraint2_data
-       ....
-       byte                    constraintN_type
-       ....                    constraintN_data
-
-Such a sequence of zero or more constraints will be referred to below
-as "constraint[]". Agents may determine whether there are constraints
-by checking whether additional data exists in the "add key" request
-after the key data itself. OpenSSH will refuse to add a key if it
-contains unknown constraints.
-
-2.2.2 Add protocol 1 key
-
-A client may add a protocol 1 key to an agent with the following
-request:
-
-       byte                    SSH_AGENTC_ADD_RSA_IDENTITY or
-                               SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
-       uint32                  ignored
-       mpint1                  rsa_n
-       mpint1                  rsa_e
-       mpint1                  rsa_d
-       mpint1                  rsa_iqmp
-       mpint1                  rsa_q
-       mpint1                  rsa_p
-       string                  key_comment
-       constraint[]            key_constraints
-
-Note that there is some redundancy in the key parameters; a key could be
-fully specified using just rsa_q, rsa_p and rsa_e at the cost of extra
-computation.
-
-"key_constraints" may only be present if the request type is
-SSH_AGENTC_ADD_RSA_ID_CONSTRAINED.
-
-The agent will reply with a SSH_AGENT_SUCCESS if the key has been
-successfully added or a SSH_AGENT_FAILURE if an error occurred.
-
-2.2.3 Add protocol 2 key
-
-The OpenSSH agent supports DSA, ECDSA and RSA keys for protocol 2. DSA
-keys may be added using the following request
-
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-dss"
-       mpint                   dsa_p
-       mpint                   dsa_q
-       mpint                   dsa_g
-       mpint                   dsa_public_key
-       mpint                   dsa_private_key
-       string                  key_comment
-       constraint[]            key_constraints
-
-DSA certificates may be added with:
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-dss-cert-v00@openssh.com"
-       string                  certificate
-       mpint                   dsa_private_key
-       string                  key_comment
-       constraint[]            key_constraints
-
-ECDSA keys may be added using the following request
-
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ecdsa-sha2-nistp256" |
-                               "ecdsa-sha2-nistp384" |
-                               "ecdsa-sha2-nistp521"
-       string                  ecdsa_curve_name
-       string                  ecdsa_public_key
-       mpint                   ecdsa_private
-       string                  key_comment
-       constraint[]            key_constraints
-
-ECDSA certificates may be added with:
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ecdsa-sha2-nistp256-cert-v01@openssh.com" |
-                               "ecdsa-sha2-nistp384-cert-v01@openssh.com" |
-                               "ecdsa-sha2-nistp521-cert-v01@openssh.com"
-       string                  certificate
-       mpint                   ecdsa_private_key
-       string                  key_comment
-       constraint[]            key_constraints
-
-ED25519 keys may be added using the following request
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-ed25519"
-       string                  ed25519_public_key
-       string                  ed25519_private_key || ed25519_public_key
-       string                  key_comment
-       constraint[]            key_constraints
-
-ED25519 certificates may be added with:
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-ed25519-cert-v01@openssh.com"
-       string                  certificate
-       string                  ed25519_public_key
-       string                  ed25519_private_key || ed25519_public_key
-       string                  key_comment
-       constraint[]            key_constraints
-
-For both ssh-ed25519 and ssh-ed25519-cert-v01@openssh.com keys, the private
-key has the public key appended (for historical reasons).
-
-RSA keys may be added with this request:
-
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-rsa"
-       mpint                   rsa_n
-       mpint                   rsa_e
-       mpint                   rsa_d
-       mpint                   rsa_iqmp
-       mpint                   rsa_p
-       mpint                   rsa_q
-       string                  key_comment
-       constraint[]            key_constraints
-
-RSA certificates may be added with this request:
-
-       byte                    SSH2_AGENTC_ADD_IDENTITY or
-                               SSH2_AGENTC_ADD_ID_CONSTRAINED
-       string                  "ssh-rsa-cert-v00@openssh.com"
-       string                  certificate
-       mpint                   rsa_d
-       mpint                   rsa_iqmp
-       mpint                   rsa_p
-       mpint                   rsa_q
-       string                  key_comment
-       constraint[]            key_constraints
-
-Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
-order to the protocol 1 add keys message. As with the corresponding
-protocol 1 "add key" request, the private key is overspecified to avoid
-redundant processing.
-
-For DSA, ECDSA and RSA key add requests, "key_constraints" may only be
-present if the request type is SSH2_AGENTC_ADD_ID_CONSTRAINED.
-
-The agent will reply with a SSH_AGENT_SUCCESS if the key has been
-successfully added or a SSH_AGENT_FAILURE if an error occurred.
-
-2.2.4 Loading keys from a smartcard
-
-The OpenSSH agent may have optional smartcard support built in to it. If
-so, it supports an operation to load keys from a smartcard. Technically,
-only the public components of the keys are loaded into the agent so
-this operation really arranges for future private key operations to be
-delegated to the smartcard.
-
-       byte                    SSH_AGENTC_ADD_SMARTCARD_KEY or
-                               SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
-       string                  reader_id
-       string                  pin
-       constraint[]            key_constraints
-
-"reader_id" is an identifier to a smartcard reader and "pin"
-is a PIN or passphrase used to unlock the private key(s) on the
-device. "key_constraints" may only be present if the request type is
-SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED.
-
-This operation may load all SSH keys that are unlocked using the
-"pin" on the specified reader. The type of key loaded (protocol 1
-or protocol 2) will be specified by the smartcard itself, it is not
-client-specified.
-
-The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
-been successfully loaded or a SSH_AGENT_FAILURE if an error occurred.
-The agent will also return SSH_AGENT_FAILURE if it does not support
-smartcards.
-
-2.3 Removing multiple keys
-
-A client may request that an agent delete all protocol 1 keys using the
-following request:
-
-       byte                    SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES
-
-This message requests the deletion of all protocol 2 keys:
-
-       byte                    SSH2_AGENTC_REMOVE_ALL_IDENTITIES
-
-On success, the agent will delete all keys of the requested type and
-reply with a SSH_AGENT_SUCCESS message. If an error occurred, the agent
-will reply with SSH_AGENT_FAILURE.
-
-Note that, to delete all keys (both protocol 1 and 2), a client
-must send both a SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES and a
-SSH2_AGENTC_REMOVE_ALL_IDENTITIES request.
-
-2.4 Removing specific keys
-
-2.4.1 Removing a protocol 1 key
-
-Removal of a protocol 1 key may be requested with the following message:
-
-       byte                    SSH_AGENTC_REMOVE_RSA_IDENTITY
-       uint32                  key_bits
-       mpint1                  rsa_e
-       mpint1                  rsa_n
-
-Note that key_bits is strictly redundant, as it may be inferred by the
-length of rsa_n.
-
-The agent will delete any private key matching the specified public key
-and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
-return SSH_AGENT_FAILURE.
-
-2.4.2 Removing a protocol 2 key
-
-Protocol 2 keys may be removed with the following request:
-
-       byte                    SSH2_AGENTC_REMOVE_IDENTITY
-       string                  key_blob
-
-Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
-Algorithms" for any of the supported protocol 2 key types.
-
-The agent will delete any private key matching the specified public key
-and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
-return SSH_AGENT_FAILURE.
-
-2.4.3 Removing keys loaded from a smartcard
-
-A client may request that a server remove one or more smartcard-hosted
-keys using this message:
-
-       byte                    SSH_AGENTC_REMOVE_SMARTCARD_KEY
-       string                  reader_id
-       string                  pin
-
-"reader_id" the an identifier to a smartcard reader and "pin" is a PIN
-or passphrase used to unlock the private key(s) on the device.
-
-When this message is received, and if the agent supports
-smartcard-hosted keys, it will delete all keys that are hosted on the
-specified smartcard that may be accessed with the given "pin".
-
-The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
-been successfully removed or a SSH_AGENT_FAILURE if an error occurred.
-The agent will also return SSH_AGENT_FAILURE if it does not support
-smartcards.
-
-2.5 Requesting a list of known keys
-
-An agent may be requested to list which keys it holds. Different
-requests exist for protocol 1 and protocol 2 keys.
-
-2.5.1 Requesting a list of protocol 1 keys
-
-To request a list of protocol 1 keys that are held in the agent, a
-client may send the following message:
-
-       byte                    SSH_AGENTC_REQUEST_RSA_IDENTITIES
-
-The agent will reply with the following message:
-
-       byte                    SSH_AGENT_RSA_IDENTITIES_ANSWER
-       uint32                  num_keys
-
-Followed by zero or more consecutive keys, encoded as:
-
-       uint32                  bits
-       mpint1                  rsa_e
-       mpint1                  rsa_n
-       string                  key_comment
-
-2.5.2 Requesting a list of protocol 2 keys
-
-A client may send the following message to request a list of
-protocol 2 keys that are stored in the agent:
-
-       byte                    SSH2_AGENTC_REQUEST_IDENTITIES
-
-The agent will reply with the following message header:
-
-       byte                    SSH2_AGENT_IDENTITIES_ANSWER
-       uint32                  num_keys
-
-Followed by zero or more consecutive keys, encoded as:
-
-       string                  key_blob
-       string                  key_comment
-
-Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
-Algorithms" for any of the supported protocol 2 key types.
-
-2.6 Private key operations
-
-The purpose of the agent is to perform private key operations, such as
-signing and encryption without requiring a passphrase to unlock the
-key and without allowing the private key itself to be exposed. There
-are separate requests for the protocol 1 and protocol 2 private key
-operations.
-
-2.6.1 Protocol 1 private key challenge
-
-The private key operation used in version 1 of the SSH protocol is
-decrypting a challenge that has been encrypted with a public key.
-It may be requested using this message:
-
-       byte                    SSH_AGENTC_RSA_CHALLENGE
-       uint32                  ignored
-       mpint1                  rsa_e
-       mpint1                  rsa_n
-       mpint1                  encrypted_challenge
-       byte[16]                session_id
-       uint32                  response_type /* must be 1 */
-
-"rsa_e" and "rsa_n" are used to identify which private key to use.
-"encrypted_challenge" is a challenge blob that has (presumably)
-been encrypted with the public key and must be in the range
-1 <= encrypted_challenge < 2^256. "session_id" is the SSH protocol 1
-session ID (computed from the server host key, the server semi-ephemeral
-key and the session cookie).
-
-"ignored" and "response_type" exist for compatibility with legacy
-implementations. "response_type" must be equal to 1; other response
-types are not supported.
-
-On receiving this request, the server decrypts the "encrypted_challenge"
-using the private key matching the supplied (rsa_e, rsa_n) values. For
-the response derivation, the decrypted challenge is represented as an
-unsigned, big-endian integer encoded in a 32 byte buffer (i.e. values
-smaller than 2^248 will have leading 0 bytes).
-
-The response value is then calculated as:
-
-       response = MD5(decrypted_challenge || session_id)
-
-and returned in the following message
-
-       byte                    SSH_AGENT_RSA_RESPONSE
-       byte[16]                response
-
-If the agent cannot find the key specified by the supplied (rsa_e,
-rsa_n) then it will return SSH_AGENT_FAILURE.
-
-2.6.2 Protocol 2 private key signature request
-
-A client may use the following message to request signing of data using
-a protocol 2 key:
-
-       byte                    SSH2_AGENTC_SIGN_REQUEST
-       string                  key_blob
-       string                  data
-       uint32                  flags
-
-Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
-Algorithms" for any of the supported protocol 2 key types. "flags" is
-a bit-mask, but at present only one possible value is defined (see below
-for its meaning):
-
-       SSH_AGENT_OLD_SIGNATURE         1
-
-Upon receiving this request, the agent will look up the private key that
-corresponds to the public key contained in key_blob. It will use this
-private key to sign the "data" and produce a signature blob using the
-key type-specific method described in RFC 4253 section 6.6 "Public Key
-Algorithms".
-
-An exception to this is for "ssh-dss" keys where the "flags" word
-contains the value SSH_AGENT_OLD_SIGNATURE. In this case, a legacy
-signature encoding is used in lieu of the standard one. In this case,
-the DSA signature blob is encoded as:
-
-       byte[40]                signature
-
-The signature will be returned in the response message:
-
-       byte                    SSH2_AGENT_SIGN_RESPONSE
-       string                  signature_blob
-
-If the agent cannot find the key specified by the supplied key_blob then
-it will return SSH_AGENT_FAILURE.
-
-2.7 Locking or unlocking an agent
-
-The agent supports temporary locking with a passphrase to suspend
-processing of sensitive operations until it has been unlocked with the
-same passphrase. To lock an agent, a client send the following request:
-
-       byte                    SSH_AGENTC_LOCK
-       string                  passphrase
-
-Upon receipt of this message and if the agent is not already locked,
-it will suspend processing requests and return a SSH_AGENT_SUCCESS
-reply. If the agent is already locked, it will return SSH_AGENT_FAILURE.
-
-While locked, the agent will refuse all requests except
-SSH_AGENTC_UNLOCK, SSH_AGENTC_REQUEST_RSA_IDENTITIES and
-SSH2_AGENTC_REQUEST_IDENTITIES. The "request identities" requests are
-treated specially by a locked agent: it will always return an empty list
-of keys.
-
-To unlock an agent, a client may request:
-
-       byte                    SSH_AGENTC_UNLOCK
-       string                  passphrase
-
-If the passphrase matches and the agent is locked, then it will resume
-processing all requests and return SSH_AGENT_SUCCESS. If the agent
-is not locked or the passphrase does not match then it will return
-SSH_AGENT_FAILURE.
-
-Locking and unlocking affects both protocol 1 and protocol 2 keys.
-
-3. Protocol message numbers
-
-3.1 Requests from client to agent for protocol 1 key operations
-
-       SSH_AGENTC_REQUEST_RSA_IDENTITIES               1
-       SSH_AGENTC_RSA_CHALLENGE                        3
-       SSH_AGENTC_ADD_RSA_IDENTITY                     7
-       SSH_AGENTC_REMOVE_RSA_IDENTITY                  8
-       SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES            9
-       SSH_AGENTC_ADD_RSA_ID_CONSTRAINED               24
-
-3.2 Requests from client to agent for protocol 2 key operations
-
-       SSH2_AGENTC_REQUEST_IDENTITIES                  11
-       SSH2_AGENTC_SIGN_REQUEST                        13
-       SSH2_AGENTC_ADD_IDENTITY                        17
-       SSH2_AGENTC_REMOVE_IDENTITY                     18
-       SSH2_AGENTC_REMOVE_ALL_IDENTITIES               19
-       SSH2_AGENTC_ADD_ID_CONSTRAINED                  25
-
-3.3 Key-type independent requests from client to agent
-
-       SSH_AGENTC_ADD_SMARTCARD_KEY                    20
-       SSH_AGENTC_REMOVE_SMARTCARD_KEY                 21
-       SSH_AGENTC_LOCK                                 22
-       SSH_AGENTC_UNLOCK                               23
-       SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED        26
-
-3.4 Generic replies from agent to client
-
-       SSH_AGENT_FAILURE                               5
-       SSH_AGENT_SUCCESS                               6
-
-3.5 Replies from agent to client for protocol 1 key operations
-
-       SSH_AGENT_RSA_IDENTITIES_ANSWER                 2
-       SSH_AGENT_RSA_RESPONSE                          4
-
-3.6 Replies from agent to client for protocol 2 key operations
-
-       SSH2_AGENT_IDENTITIES_ANSWER                    12
-       SSH2_AGENT_SIGN_RESPONSE                        14
-
-3.7 Key constraint identifiers
-
-       SSH_AGENT_CONSTRAIN_LIFETIME                    1
-       SSH_AGENT_CONSTRAIN_CONFIRM                     2
-
-$OpenBSD: PROTOCOL.agent,v 1.11 2016/05/19 07:45:32 djm Exp $
+https://tools.ietf.org/html/draft-miller-ssh-agent-02
index aa6f5ae..42aa8c2 100644 (file)
@@ -192,12 +192,13 @@ compatibility.
 The reserved field is currently unused and is ignored in this version of
 the protocol.
 
-signature key contains the CA key used to sign the certificate.
-The valid key types for CA keys are ssh-rsa, ssh-dss and the ECDSA types
-ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained"
-certificates, where the signature key type is a certificate type itself
-are NOT supported. Note that it is possible for a RSA certificate key to
-be signed by a DSS or ECDSA CA key and vice-versa.
+The signature key field contains the CA key used to sign the
+certificate. The valid key types for CA keys are ssh-rsa,
+ssh-dss, ssh-ed25519 and the ECDSA types ecdsa-sha2-nistp256,
+ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained" certificates, where
+the signature key type is a certificate type itself are NOT supported.
+Note that it is possible for a RSA certificate key to be signed by a
+Ed25519 or ECDSA CA key and vice-versa.
 
 signature is computed over all preceding fields from the initial string
 up to, and including the signature key. Signatures are computed and
@@ -223,6 +224,9 @@ option-specific information (see below). All options are
 "critical", if an implementation does not recognise a option
 then the validating party should refuse to accept the certificate.
 
+Custom options should append the originating author or organisation's
+domain name to the option name, e.g. "my-option@example.com".
+
 No critical options are defined for host certificates at present. The
 supported user certificate options and the contents and structure of
 their data fields are:
@@ -254,6 +258,9 @@ as is the requirement that each name appear only once.
 If an implementation does not recognise an extension, then it should
 ignore it.
 
+Custom options should append the originating author or organisation's
+domain name to the option name, e.g. "my-option@example.com".
+
 No extensions are defined for host certificates at present. The
 supported user certificate extensions and the contents and structure of
 their data fields are:
@@ -284,4 +291,4 @@ permit-user-rc          empty         Flag indicating that execution of
                                       of this script will not be permitted if
                                       this option is not present.
 
-$OpenBSD: PROTOCOL.certkeys,v 1.10 2016/05/03 10:27:59 djm Exp $
+$OpenBSD: PROTOCOL.certkeys,v 1.12 2017/05/31 04:29:44 djm Exp $
index 4b6c342..103d43e 100644 (file)
@@ -1,10 +1,10 @@
-See http://www.openssh.com/txt/release-7.3p1 for the release notes.
+See https://www.openssh.com/releasenotes.html#7.6p1 for the release notes.
 
-Please read http://www.openssh.com/report.html for bug reporting
+Please read https://www.openssh.com/report.html for bug reporting
 instructions and note that we do not use Github for bug reporting or
 patch/pull-request management.
 
-- A Japanese translation of this document and of the OpenSSH FAQ is
+- A Japanese translation of this document and of the release notes is
 - available at http://www.unixuser.org/~haruyama/security/openssh/index.html
 - Thanks to HARUYAMA Seigo <haruyama@unixuser.org>
 
@@ -16,7 +16,7 @@ implementation with all patent-encumbered algorithms removed (to
 external libraries), all known security bugs fixed, new features
 reintroduced and many other clean-ups.  OpenSSH has been created by
 Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt,
-and Dug Song. It has a homepage at http://www.openssh.com/
+and Dug Song. It has a homepage at https://www.openssh.com/
 
 This port consists of the re-introduction of autoconf support, PAM
 support, EGD[1]/PRNGD[2] support and replacements for OpenBSD library
@@ -30,20 +30,19 @@ The PAM support is now more functional than the popular packages of
 commercial ssh-1.2.x. It checks "account" and "session" modules for
 all logins, not just when using password authentication.
 
-OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5].
+OpenSSH depends on Zlib[3], OpenSSL[4], and optionally PAM[5] and
+libedit[6]
 
 There is now several mailing lists for this port of OpenSSH. Please
-refer to http://www.openssh.com/list.html for details on how to join.
+refer to https://www.openssh.com/list.html for details on how to join.
 
 Please send bug reports and patches to the mailing list
-openssh-unix-dev@mindrot.org. The list is open to posting by
-unsubscribed users.Code contribution are welcomed, but please follow the 
-OpenBSD style guidelines[6].
+openssh-unix-dev@mindrot.org. The list is open to posting by unsubscribed
+users.  Code contribution are welcomed, but please follow the OpenBSD
+style guidelines[7].
 
 Please refer to the INSTALL document for information on how to install
-OpenSSH on your system. There are a number of differences between this
-port of OpenSSH and F-Secure SSH 1.x, please refer to the OpenSSH FAQ[7]
-for details and general tips.
+OpenSSH on your system.
 
 Damien Miller <djm@mindrot.org>
 
@@ -55,15 +54,13 @@ implementation released by Tatu Ylonen.
 
 References -
 
-[0] http://www.openssh.com/faq.html
+[0] https://www.openssh.com/
 [1] http://www.lothar.com/tech/crypto/
 [2] http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html
 [3] http://www.gzip.org/zlib/
 [4] http://www.openssl.org/
 [5] http://www.openpam.org
-    http://www.kernel.org/pub/linux/libs/pam/ 
+    http://www.kernel.org/pub/linux/libs/pam/
     (PAM also is standard on Solaris and HP-UX 11)
-[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9
-[7] http://www.openssh.com/faq.html
-
-$Id: README,v 1.87 2014/08/10 01:35:06 djm Exp $
+[6] http://thrysoee.dk/editline/ (portable version)
+[7] http://man.openbsd.org/style.9
index 70b050e..8658e10 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: addrmatch.c,v 1.10 2015/07/08 19:04:21 markus Exp $ */
+/*     $OpenBSD: addrmatch.c,v 1.13 2016/09/21 16:55:42 djm Exp $ */
 
 /*
  * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
@@ -398,8 +398,8 @@ addr_match_list(const char *addr, const char *_list)
                /* Prefer CIDR address matching */
                r = addr_pton_cidr(cp, &match_addr, &masklen);
                if (r == -2) {
-                       error("Inconsistent mask length for "
-                           "network \"%.100s\"", cp);
+                       debug2("%s: inconsistent mask length for "
+                           "match network \"%.100s\"", __func__, cp);
                        ret = -2;
                        break;
                } else if (r == 0) {
index b1ec234..f854a06 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: atomicio.c,v 1.27 2015/01/16 06:40:12 deraadt Exp $ */
+/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */
 /*
  * Copyright (c) 2006 Damien Miller. All rights reserved.
  * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@@ -107,12 +107,12 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
        struct iovec iov_array[IOV_MAX], *iov = iov_array;
        struct pollfd pfd;
 
-       if (iovcnt > IOV_MAX) {
+       if (iovcnt < 0 || iovcnt > IOV_MAX) {
                errno = EINVAL;
                return 0;
        }
        /* Make a copy of the iov array because we may modify it below */
-       memcpy(iov, _iov, iovcnt * sizeof(*_iov));
+       memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
 
 #ifndef BROKEN_READV_COMPARISON
        pfd.fd = fd;
index 6135591..f8e0bea 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: audit-bsm.c,v 1.8 2012/02/23 23:40:43 dtucker Exp $ */
-
 /*
  * TODO
  *
index ced57fa..7645c14 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: audit.c,v 1.6 2011/01/17 10:15:30 dtucker Exp $ */
-
 /*
  * Copyright (c) 2004, 2005 Darren Tucker.  All rights reserved.
  *
index 92ede5b..0b59366 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: audit.h,v 1.4 2011/01/17 10:15:30 dtucker Exp $ */
-
 /*
  * Copyright (c) 2004, 2005 Darren Tucker.  All rights reserved.
  *
index 60c9f14..e69de29 100644 (file)
@@ -1,125 +0,0 @@
-/* $OpenBSD: auth-chall.c,v 1.14 2014/06/24 01:13:21 djm Exp $ */
-/*
- * Copyright (c) 2001 Markus Friedl.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include <sys/types.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "xmalloc.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "log.h"
-#include "misc.h"
-#include "servconf.h"
-
-/* limited protocol v1 interface to kbd-interactive authentication */
-
-extern KbdintDevice *devices[];
-static KbdintDevice *device;
-extern ServerOptions options;
-
-char *
-get_challenge(Authctxt *authctxt)
-{
-       char *challenge, *name, *info, **prompts;
-       u_int i, numprompts;
-       u_int *echo_on;
-
-#ifdef USE_PAM
-       if (!options.use_pam)
-               remove_kbdint_device("pam");
-#endif
-
-       device = devices[0]; /* we always use the 1st device for protocol 1 */
-       if (device == NULL)
-               return NULL;
-       if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL)
-               return NULL;
-       if (device->query(authctxt->kbdintctxt, &name, &info,
-           &numprompts, &prompts, &echo_on)) {
-               device->free_ctx(authctxt->kbdintctxt);
-               authctxt->kbdintctxt = NULL;
-               return NULL;
-       }
-       if (numprompts < 1)
-               fatal("get_challenge: numprompts < 1");
-       challenge = xstrdup(prompts[0]);
-       for (i = 0; i < numprompts; i++)
-               free(prompts[i]);
-       free(prompts);
-       free(name);
-       free(echo_on);
-       free(info);
-
-       return (challenge);
-}
-int
-verify_response(Authctxt *authctxt, const char *response)
-{
-       char *resp[1], *name, *info, **prompts;
-       u_int i, numprompts, *echo_on;
-       int authenticated = 0;
-
-       if (device == NULL)
-               return 0;
-       if (authctxt->kbdintctxt == NULL)
-               return 0;
-       resp[0] = (char *)response;
-       switch (device->respond(authctxt->kbdintctxt, 1, resp)) {
-       case 0: /* Success */
-               authenticated = 1;
-               break;
-       case 1: /* Postponed - retry with empty query for PAM */
-               if ((device->query(authctxt->kbdintctxt, &name, &info,
-                   &numprompts, &prompts, &echo_on)) != 0)
-                       break;
-               if (numprompts == 0 &&
-                   device->respond(authctxt->kbdintctxt, 0, resp) == 0)
-                       authenticated = 1;
-
-               for (i = 0; i < numprompts; i++)
-                       free(prompts[i]);
-               free(prompts);
-               free(name);
-               free(echo_on);
-               free(info);
-               break;
-       }
-       device->free_ctx(authctxt->kbdintctxt);
-       authctxt->kbdintctxt = NULL;
-       return authenticated;
-}
-void
-abandon_challenge_response(Authctxt *authctxt)
-{
-       if (authctxt->kbdintctxt != NULL) {
-               device->free_ctx(authctxt->kbdintctxt);
-               authctxt->kbdintctxt = NULL;
-       }
-}
index b399b91..bed00ee 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.71 2016/03/07 19:02:43 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.74 2017/09/12 06:32:07 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,9 +61,13 @@ char *authorized_principals = NULL;
 
 extern ServerOptions options;
 
+/* XXX refactor to be stateless */
+
 void
 auth_clear_options(void)
 {
+       struct ssh *ssh = active_state;         /* XXX */
+
        no_agent_forwarding_flag = 0;
        no_port_forwarding_flag = 0;
        no_pty_flag = 0;
@@ -81,7 +85,7 @@ auth_clear_options(void)
        free(authorized_principals);
        authorized_principals = NULL;
        forced_tun_device = -1;
-       channel_clear_permitted_opens();
+       channel_clear_permitted_opens(ssh);
 }
 
 /*
@@ -117,9 +121,11 @@ match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
 /*
  * return 1 if access is granted, 0 if not.
  * side effect: sets key option flags
+ * XXX remove side effects; fill structure instead.
  */
 int
-auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
+auth_parse_options(struct passwd *pw, char *opts, const char *file,
+    u_long linenum)
 {
        struct ssh *ssh = active_state;         /* XXX */
        const char *cp;
@@ -379,7 +385,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
                                goto bad_option;
                        }
                        if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
-                               channel_add_permitted_opens(host, port);
+                               channel_add_permitted_opens(ssh, host, port);
                        free(patterns);
                        goto next_option;
                }
@@ -601,7 +607,7 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
  * options so this must be called after auth_parse_options().
  */
 int
-auth_cert_options(struct sshkey *k, struct passwd *pw)
+auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
 {
        int cert_no_port_forwarding_flag = 1;
        int cert_no_agent_forwarding_flag = 1;
@@ -611,6 +617,8 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
        char *cert_forced_command = NULL;
        int cert_source_address_done = 0;
 
+       *reason = "invalid certificate options";
+
        /* Separate options and extensions for v01 certs */
        if (parse_option_list(k->cert->critical, pw,
            OPTIONS_CRITICAL, 1, NULL, NULL, NULL, NULL, NULL,
@@ -632,11 +640,24 @@ auth_cert_options(struct sshkey *k, struct passwd *pw)
        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) {
-               free(forced_command);
+       /*
+        * Only permit both CA and key option forced-command if they match.
+        * Otherwise refuse the certificate.
+        */
+       if (cert_forced_command != NULL && forced_command != NULL) {
+               if (strcmp(forced_command, cert_forced_command) == 0) {
+                       free(forced_command);
+                       forced_command = cert_forced_command;
+               } else {
+                       *reason = "certificate and key options forced command "
+                           "do not match";
+                       free(cert_forced_command);
+                       return -1;
+               }
+       } else if (cert_forced_command != NULL)
                forced_command = cert_forced_command;
-       }
+       /* success */
+       *reason = NULL;
        return 0;
 }
 
index 34852e5..547f016 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.h,v 1.21 2015/01/14 10:30:34 markus Exp $ */
+/* $OpenBSD: auth-options.h,v 1.23 2017/05/31 10:54:00 markus Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -33,8 +33,8 @@ extern int forced_tun_device;
 extern int key_is_cert_authority;
 extern char *authorized_principals;
 
-int    auth_parse_options(struct passwd *, char *, char *, u_long);
+int    auth_parse_options(struct passwd *, char *, const char *, u_long);
 void   auth_clear_options(void);
-int    auth_cert_options(struct sshkey *, struct passwd *);
+int    auth_cert_options(struct sshkey *, struct passwd *, const char **);
 
 #endif
index da7aa31..de877ab 100644 (file)
 #include <pam/pam_appl.h>
 #endif
 
+#if !defined(SSHD_PAM_SERVICE)
+extern char *__progname;
+# define SSHD_PAM_SERVICE              __progname
+#endif
+
 /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */
 #ifdef PAM_SUN_CODEBASE
 # define sshpam_const          /* Solaris, HP-UX, SunOS */
 
 extern ServerOptions options;
 extern Buffer loginmsg;
-extern int compat20;
 extern u_int utmp_len;
 
 /* so we don't silently change behaviour */
@@ -463,18 +467,16 @@ sshpam_thread(void *ctxtp)
        if (sshpam_err != PAM_SUCCESS)
                goto auth_fail;
 
-       if (compat20) {
-               if (!do_pam_account()) {
-                       sshpam_err = PAM_ACCT_EXPIRED;
+       if (!do_pam_account()) {
+               sshpam_err = PAM_ACCT_EXPIRED;
+               goto auth_fail;
+       }
+       if (sshpam_authctxt->force_pwchange) {
+               sshpam_err = pam_chauthtok(sshpam_handle,
+                   PAM_CHANGE_EXPIRED_AUTHTOK);
+               if (sshpam_err != PAM_SUCCESS)
                        goto auth_fail;
-               }
-               if (sshpam_authctxt->force_pwchange) {
-                       sshpam_err = pam_chauthtok(sshpam_handle,
-                           PAM_CHANGE_EXPIRED_AUTHTOK);
-                       if (sshpam_err != PAM_SUCCESS)
-                               goto auth_fail;
-                       sshpam_password_change_required(0);
-               }
+               sshpam_password_change_required(0);
        }
 
        buffer_put_cstring(&buffer, "OK");
@@ -615,7 +617,6 @@ sshpam_cleanup(void)
 static int
 sshpam_init(Authctxt *authctxt)
 {
-       extern char *__progname;
        const char *pam_rhost, *pam_user, *user = authctxt->user;
        const char **ptr_pam_user = &pam_user;
        struct ssh *ssh = active_state; /* XXX */
@@ -826,6 +827,8 @@ fake_password(const char *wire_password)
                fatal("%s: password length too long: %zu", __func__, l);
 
        ret = malloc(l + 1);
+       if (ret == NULL)
+               return NULL;
        for (i = 0; i < l; i++)
                ret[i] = junk[i % (sizeof(junk) - 1)];
        ret[i] = '\0';
@@ -923,6 +926,27 @@ finish_pam(void)
        sshpam_cleanup();
 }
 
+static void
+expose_authinfo(const char *caller)
+{
+       char *auth_info;
+
+       /*
+        * Expose authentication information to PAM.
+        * The enviornment variable is versioned. Please increment the
+        * version suffix if the format of session_info changes.
+        */
+       if (sshpam_authctxt->session_info == NULL)
+               auth_info = xstrdup("");
+       else if ((auth_info = sshbuf_dup_string(
+           sshpam_authctxt->session_info)) == NULL)
+               fatal("%s: sshbuf_dup_string failed", __func__);
+
+       debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
+       do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
+       free(auth_info);
+}
+
 u_int
 do_pam_account(void)
 {
@@ -930,6 +954,8 @@ do_pam_account(void)
        if (sshpam_account_status != -1)
                return (sshpam_account_status);
 
+       expose_authinfo(__func__);
+
        sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
        debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
            pam_strerror(sshpam_handle, sshpam_err));
@@ -946,18 +972,6 @@ do_pam_account(void)
        return (sshpam_account_status);
 }
 
-void
-do_pam_set_tty(const char *tty)
-{
-       if (tty != NULL) {
-               debug("PAM: setting PAM_TTY to \"%s\"", tty);
-               sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
-               if (sshpam_err != PAM_SUCCESS)
-                       fatal("PAM: failed to set PAM_TTY: %s",
-                           pam_strerror(sshpam_handle, sshpam_err));
-       }
-}
-
 void
 do_pam_setcred(int init)
 {
@@ -1066,6 +1080,9 @@ void
 do_pam_session(void)
 {
        debug3("PAM: opening session");
+
+       expose_authinfo(__func__);
+
        sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
            (const void *)&store_conv);
        if (sshpam_err != PAM_SUCCESS)
index 2e9a0c0..c47b442 100644 (file)
@@ -1,5 +1,3 @@
-/* $Id: auth-pam.h,v 1.27 2004/09/11 12:17:26 dtucker Exp $ */
-
 /*
  * Copyright (c) 2000 Damien Miller.  All rights reserved.
  *
 #include "includes.h"
 #ifdef USE_PAM
 
-#if !defined(SSHD_PAM_SERVICE)
-# define SSHD_PAM_SERVICE              __progname
-#endif
-
 void start_pam(Authctxt *);
 void finish_pam(void);
 u_int do_pam_account(void);
 void do_pam_session(void);
-void do_pam_set_tty(const char *);
 void do_pam_setcred(int );
 void do_pam_chauthtok(void);
 int do_pam_putenv(char *, char *);
index 057335b..e69de29 100644 (file)
@@ -1,109 +0,0 @@
-/* $OpenBSD: auth-rh-rsa.c,v 1.45 2016/03/07 19:02:43 djm Exp $ */
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
- * Rhosts or /etc/hosts.equiv authentication combined with RSA host
- * authentication.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose.  Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-
-#ifdef WITH_SSH1
-
-#include <sys/types.h>
-
-#include <pwd.h>
-#include <stdarg.h>
-
-#include "packet.h"
-#include "uidswap.h"
-#include "log.h"
-#include "buffer.h"
-#include "misc.h"
-#include "servconf.h"
-#include "key.h"
-#include "hostfile.h"
-#include "pathnames.h"
-#include "auth.h"
-#include "canohost.h"
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-#include "monitor_wrap.h"
-
-/* import */
-extern ServerOptions options;
-
-int
-auth_rhosts_rsa_key_allowed(struct passwd *pw, const char *cuser,
-    const char *chost, Key *client_host_key)
-{
-       HostStatus host_status;
-
-       if (auth_key_is_revoked(client_host_key))
-               return 0;
-
-       /* Check if we would accept it using rhosts authentication. */
-       if (!auth_rhosts(pw, cuser))
-               return 0;
-
-       host_status = check_key_in_hostfiles(pw, client_host_key,
-           chost, _PATH_SSH_SYSTEM_HOSTFILE,
-           options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
-
-       return (host_status == HOST_OK);
-}
-
-/*
- * Tries to authenticate the user using the .rhosts file and the host using
- * its host key.  Returns true if authentication succeeds.
- */
-int
-auth_rhosts_rsa(Authctxt *authctxt, char *cuser, Key *client_host_key)
-{
-       struct ssh *ssh = active_state; /* XXX */
-       const char *chost;
-       struct passwd *pw = authctxt->pw;
-
-       debug("Trying rhosts with RSA host authentication for client user %.100s",
-           cuser);
-
-       if (!authctxt->valid || client_host_key == NULL ||
-           client_host_key->rsa == NULL)
-               return 0;
-
-       chost = auth_get_canonical_hostname(ssh, options.use_dns);
-       debug("Rhosts RSA authentication: canonical host %.900s", chost);
-
-       if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) {
-               debug("Rhosts with RSA host authentication denied: unknown or invalid host key");
-               packet_send_debug("Your host key cannot be verified: unknown or invalid host key.");
-               return 0;
-       }
-       /* A matching host key was found and is known. */
-
-       /* Perform the challenge-response dialog with the client for the host key. */
-       if (!auth_rsa_challenge_dialog(client_host_key)) {
-               logit("Client on %.800s failed to respond correctly to host authentication.",
-                   chost);
-               return 0;
-       }
-       /*
-        * We have authenticated the user using .rhosts or /etc/hosts.equiv,
-        * and the host using RSA. We accept the authentication.
-        */
-
-       verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.",
-           pw->pw_name, cuser, chost);
-       packet_send_debug("Rhosts with RSA host authentication accepted.");
-       return 1;
-}
-
-#endif /* WITH_SSH1 */
index 0ef3447..ecf956f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rhosts.c,v 1.47 2016/03/07 19:02:43 djm Exp $ */
+/* $OpenBSD: auth-rhosts.c,v 1.48 2016/08/13 17:47:41 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -186,20 +186,8 @@ check_rhosts_file(const char *filename, const char *hostname,
  * true if authentication succeeds.  If ignore_rhosts is true, only
  * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored).
  */
-
 int
-auth_rhosts(struct passwd *pw, const char *client_user)
-{
-       struct ssh *ssh = active_state; /* XXX */
-       const char *hostname, *ipaddr;
-
-       hostname = auth_get_canonical_hostname(ssh, options.use_dns);
-       ipaddr = ssh_remote_ipaddr(ssh);
-       return auth_rhosts2(pw, client_user, hostname, ipaddr);
-}
-
-static int
-auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostname,
+auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
     const char *ipaddr)
 {
        char buf[1024];
@@ -334,10 +322,3 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
        restore_uid();
        return 0;
 }
-
-int
-auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
-    const char *ipaddr)
-{
-       return auth_rhosts2_raw(pw, client_user, hostname, ipaddr);
-}
index cbd971b..e69de29 100644 (file)
@@ -1,349 +0,0 @@
-/* $OpenBSD: auth-rsa.c,v 1.90 2015/01/28 22:36:00 djm Exp $ */
-/*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
- * RSA-based authentication.  This code determines whether to admit a login
- * based on RSA authentication.  This file also contains functions to check
- * validity of the host key.
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose.  Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-
-#ifdef WITH_SSH1
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <openssl/rsa.h>
-
-#include <pwd.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "xmalloc.h"
-#include "rsa.h"
-#include "packet.h"
-#include "ssh1.h"
-#include "uidswap.h"
-#include "match.h"
-#include "buffer.h"
-#include "pathnames.h"
-#include "log.h"
-#include "misc.h"
-#include "servconf.h"
-#include "key.h"
-#include "auth-options.h"
-#include "hostfile.h"
-#include "auth.h"
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-#include "monitor_wrap.h"
-#include "ssh.h"
-
-#include "digest.h"
-
-/* import */
-extern ServerOptions options;
-
-/*
- * Session identifier that is used to bind key exchange and authentication
- * responses to a particular session.
- */
-extern u_char session_id[16];
-
-/*
- * The .ssh/authorized_keys file contains public keys, one per line, in the
- * following format:
- *   options bits e n comment
- * where bits, e and n are decimal numbers,
- * and comment is any string of characters up to newline.  The maximum
- * length of a line is SSH_MAX_PUBKEY_BYTES characters.  See sshd(8) for a
- * description of the options.
- */
-
-BIGNUM *
-auth_rsa_generate_challenge(Key *key)
-{
-       BIGNUM *challenge;
-       BN_CTX *ctx;
-
-       if ((challenge = BN_new()) == NULL)
-               fatal("auth_rsa_generate_challenge: BN_new() failed");
-       /* Generate a random challenge. */
-       if (BN_rand(challenge, 256, 0, 0) == 0)
-               fatal("auth_rsa_generate_challenge: BN_rand failed");
-       if ((ctx = BN_CTX_new()) == NULL)
-               fatal("auth_rsa_generate_challenge: BN_CTX_new failed");
-       if (BN_mod(challenge, challenge, key->rsa->n, ctx) == 0)
-               fatal("auth_rsa_generate_challenge: BN_mod failed");
-       BN_CTX_free(ctx);
-
-       return challenge;
-}
-
-int
-auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16])
-{
-       u_char buf[32], mdbuf[16];
-       struct ssh_digest_ctx *md;
-       int len;
-
-       /* don't allow short keys */
-       if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
-               error("%s: RSA modulus too small: %d < minimum %d bits",
-                   __func__,
-                   BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
-               return (0);
-       }
-
-       /* The response is MD5 of decrypted challenge plus session id. */
-       len = BN_num_bytes(challenge);
-       if (len <= 0 || len > 32)
-               fatal("%s: bad challenge length %d", __func__, len);
-       memset(buf, 0, 32);
-       BN_bn2bin(challenge, buf + 32 - len);
-       if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL ||
-           ssh_digest_update(md, buf, 32) < 0 ||
-           ssh_digest_update(md, session_id, 16) < 0 ||
-           ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0)
-               fatal("%s: md5 failed", __func__);
-       ssh_digest_free(md);
-
-       /* Verify that the response is the original challenge. */
-       if (timingsafe_bcmp(response, mdbuf, 16) != 0) {
-               /* Wrong answer. */
-               return (0);
-       }
-       /* Correct answer. */
-       return (1);
-}
-
-/*
- * Performs the RSA authentication challenge-response dialog with the client,
- * and returns true (non-zero) if the client gave the correct answer to
- * our challenge; returns zero if the client gives a wrong answer.
- */
-
-int
-auth_rsa_challenge_dialog(Key *key)
-{
-       BIGNUM *challenge, *encrypted_challenge;
-       u_char response[16];
-       int i, success;
-
-       if ((encrypted_challenge = BN_new()) == NULL)
-               fatal("auth_rsa_challenge_dialog: BN_new() failed");
-
-       challenge = PRIVSEP(auth_rsa_generate_challenge(key));
-
-       /* Encrypt the challenge with the public key. */
-       if (rsa_public_encrypt(encrypted_challenge, challenge, key->rsa) != 0)
-               fatal("%s: rsa_public_encrypt failed", __func__);
-
-       /* Send the encrypted challenge to the client. */
-       packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE);
-       packet_put_bignum(encrypted_challenge);
-       packet_send();
-       BN_clear_free(encrypted_challenge);
-       packet_write_wait();
-
-       /* Wait for a response. */
-       packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE);
-       for (i = 0; i < 16; i++)
-               response[i] = (u_char)packet_get_char();
-       packet_check_eom();
-
-       success = PRIVSEP(auth_rsa_verify_response(key, challenge, response));
-       BN_clear_free(challenge);
-       return (success);
-}
-
-static int
-rsa_key_allowed_in_file(struct passwd *pw, char *file,
-    const BIGNUM *client_n, Key **rkey)
-{
-       char *fp, line[SSH_MAX_PUBKEY_BYTES];
-       int allowed = 0, bits;
-       FILE *f;
-       u_long linenum = 0;
-       Key *key;
-
-       debug("trying public RSA key file %s", file);
-       if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL)
-               return 0;
-
-       /*
-        * Go though the accepted keys, looking for the current key.  If
-        * found, perform a challenge-response dialog to verify that the
-        * user really has the corresponding private key.
-        */
-       key = key_new(KEY_RSA1);
-       while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
-               char *cp;
-               char *key_options;
-               int keybits;
-
-               /* Skip leading whitespace, empty and comment lines. */
-               for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
-                       ;
-               if (!*cp || *cp == '\n' || *cp == '#')
-                       continue;
-
-               /*
-                * Check if there are options for this key, and if so,
-                * save their starting address and skip the option part
-                * for now.  If there are no options, set the starting
-                * address to NULL.
-                */
-               if (*cp < '0' || *cp > '9') {
-                       int quoted = 0;
-                       key_options = cp;
-                       for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
-                               if (*cp == '\\' && cp[1] == '"')
-                                       cp++;   /* Skip both */
-                               else if (*cp == '"')
-                                       quoted = !quoted;
-                       }
-               } else
-                       key_options = NULL;
-
-               /* Parse the key from the line. */
-               if (hostfile_read_key(&cp, &bits, key) == 0) {
-                       debug("%.100s, line %lu: non ssh1 key syntax",
-                           file, linenum);
-                       continue;
-               }
-               /* cp now points to the comment part. */
-
-               /*
-                * Check if the we have found the desired key (identified
-                * by its modulus).
-                */
-               if (BN_cmp(key->rsa->n, client_n) != 0)
-                       continue;
-
-               /* check the real bits  */
-               keybits = BN_num_bits(key->rsa->n);
-               if (keybits < 0 || bits != keybits)
-                       logit("Warning: %s, line %lu: keysize mismatch: "
-                           "actual %d vs. announced %d.",
-                           file, linenum, BN_num_bits(key->rsa->n), bits);
-
-               if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
-                   SSH_FP_DEFAULT)) == NULL)
-                       continue;
-               debug("matching key found: file %s, line %lu %s %s",
-                   file, linenum, key_type(key), fp);
-               free(fp);
-
-               /* Never accept a revoked key */
-               if (auth_key_is_revoked(key))
-                       break;
-
-               /* We have found the desired key. */
-               /*
-                * If our options do not allow this key to be used,
-                * do not send challenge.
-                */
-               if (!auth_parse_options(pw, key_options, file, linenum))
-                       continue;
-               if (key_is_cert_authority)
-                       continue;
-               /* break out, this key is allowed */
-               allowed = 1;
-               break;
-       }
-
-       /* Close the file. */
-       fclose(f);
-
-       /* return key if allowed */
-       if (allowed && rkey != NULL)
-               *rkey = key;
-       else
-               key_free(key);
-
-       return allowed;
-}
-
-/*
- * check if there's user key matching client_n,
- * return key if login is allowed, NULL otherwise
- */
-
-int
-auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
-{
-       char *file;
-       u_int i, allowed = 0;
-
-       temporarily_use_uid(pw);
-
-       for (i = 0; !allowed && i < options.num_authkeys_files; i++) {
-               if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
-                       continue;
-               file = expand_authorized_keys(
-                   options.authorized_keys_files[i], pw);
-               allowed = rsa_key_allowed_in_file(pw, file, client_n, rkey);
-               free(file);
-       }
-
-       restore_uid();
-
-       return allowed;
-}
-
-/*
- * Performs the RSA authentication dialog with the client.  This returns
- * 0 if the client could not be authenticated, and 1 if authentication was
- * successful.  This may exit if there is a serious protocol violation.
- */
-int
-auth_rsa(Authctxt *authctxt, BIGNUM *client_n)
-{
-       Key *key;
-       struct passwd *pw = authctxt->pw;
-
-       /* no user given */
-       if (!authctxt->valid)
-               return 0;
-
-       if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) {
-               auth_clear_options();
-               return (0);
-       }
-
-       /* Perform the challenge-response dialog for this key. */
-       if (!auth_rsa_challenge_dialog(key)) {
-               /* Wrong response. */
-               verbose("Wrong response to RSA authentication challenge.");
-               packet_send_debug("Wrong response to RSA authentication challenge.");
-               /*
-                * Break out of the loop. Otherwise we might send
-                * another challenge and break the protocol.
-                */
-               key_free(key);
-               return (0);
-       }
-       /*
-        * Correct response.  The client has been successfully
-        * authenticated. Note that we have not yet processed the
-        * options; this will be reset if the options cause the
-        * authentication to be rejected.
-        */
-       pubkey_auth_info(authctxt, key, NULL);
-
-       packet_send_debug("RSA authentication accepted.");
-       return (1);
-}
-
-#endif /* WITH_SSH1 */
index 24527dd..a449061 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.115 2016/06/15 00:40:40 dtucker Exp $ */
+/* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -43,9 +43,6 @@
 #ifdef USE_SHADOW
 #include <shadow.h>
 #endif
-#ifdef HAVE_LIBGEN_H
-#include <libgen.h>
-#endif
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -103,6 +100,7 @@ allowed_user(struct passwd * pw)
        struct stat st;
        const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
        u_int i;
+       int r;
 #ifdef USE_SHADOW
        struct spwd *spw = NULL;
 #endif
@@ -191,21 +189,31 @@ allowed_user(struct passwd * pw)
 
        /* Return false if user is listed in DenyUsers */
        if (options.num_deny_users > 0) {
-               for (i = 0; i < options.num_deny_users; i++)
-                       if (match_user(pw->pw_name, hostname, ipaddr,
-                           options.deny_users[i])) {
+               for (i = 0; i < options.num_deny_users; i++) {
+                       r = match_user(pw->pw_name, hostname, ipaddr,
+                           options.deny_users[i]);
+                       if (r < 0) {
+                               fatal("Invalid DenyUsers pattern \"%.100s\"",
+                                   options.deny_users[i]);
+                       } else if (r != 0) {
                                logit("User %.100s from %.100s not allowed "
                                    "because listed in DenyUsers",
                                    pw->pw_name, hostname);
                                return 0;
                        }
+               }
        }
        /* Return false if AllowUsers isn't empty and user isn't listed there */
        if (options.num_allow_users > 0) {
-               for (i = 0; i < options.num_allow_users; i++)
-                       if (match_user(pw->pw_name, hostname, ipaddr,
-                           options.allow_users[i]))
+               for (i = 0; i < options.num_allow_users; i++) {
+                       r = match_user(pw->pw_name, hostname, ipaddr,
+                           options.allow_users[i]);
+                       if (r < 0) {
+                               fatal("Invalid AllowUsers pattern \"%.100s\"",
+                                   options.allow_users[i]);
+                       } else if (r == 1)
                                break;
+               }
                /* i < options.num_allow_users iff we break for loop */
                if (i >= options.num_allow_users) {
                        logit("User %.100s from %.100s not allowed because "
@@ -256,21 +264,41 @@ allowed_user(struct passwd * pw)
        return 1;
 }
 
-void
-auth_info(Authctxt *authctxt, const char *fmt, ...)
+/*
+ * Formats any key left in authctxt->auth_method_key for inclusion in
+ * auth_log()'s message. Also includes authxtct->auth_method_info if present.
+ */
+static char *
+format_method_key(Authctxt *authctxt)
 {
-       va_list ap;
-        int i;
-
-       free(authctxt->info);
-       authctxt->info = NULL;
+       const struct sshkey *key = authctxt->auth_method_key;
+       const char *methinfo = authctxt->auth_method_info;
+       char *fp, *ret = NULL;
 
-       va_start(ap, fmt);
-       i = vasprintf(&authctxt->info, fmt, ap);
-       va_end(ap);
+       if (key == NULL)
+               return NULL;
 
-       if (i < 0 || authctxt->info == NULL)
-               fatal("vasprintf failed");
+       if (key_is_cert(key)) {
+               fp = sshkey_fingerprint(key->cert->signature_key,
+                   options.fingerprint_hash, SSH_FP_DEFAULT);
+               xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
+                   sshkey_type(key), key->cert->key_id,
+                   (unsigned long long)key->cert->serial,
+                   sshkey_type(key->cert->signature_key),
+                   fp == NULL ? "(null)" : fp,
+                   methinfo == NULL ? "" : ", ",
+                   methinfo == NULL ? "" : methinfo);
+               free(fp);
+       } else {
+               fp = sshkey_fingerprint(key, options.fingerprint_hash,
+                   SSH_FP_DEFAULT);
+               xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
+                   fp == NULL ? "(null)" : fp,
+                   methinfo == NULL ? "" : ", ",
+                   methinfo == NULL ? "" : methinfo);
+               free(fp);
+       }
+       return ret;
 }
 
 void
@@ -279,7 +307,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
 {
        struct ssh *ssh = active_state; /* XXX */
        void (*authlog) (const char *fmt,...) = verbose;
-       char *authmsg;
+       const char *authmsg;
+       char *extra = NULL;
 
        if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
                return;
@@ -298,7 +327,12 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
        else
                authmsg = authenticated ? "Accepted" : "Failed";
 
-       authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
+       if ((extra = format_method_key(authctxt)) == NULL) {
+               if (authctxt->auth_method_info != NULL)
+                       extra = xstrdup(authctxt->auth_method_info);
+       }
+
+       authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
            authmsg,
            method,
            submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
@@ -306,11 +340,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
            authctxt->user,
            ssh_remote_ipaddr(ssh),
            ssh_remote_port(ssh),
-           compat20 ? "ssh2" : "ssh1",
-           authctxt->info != NULL ? ": " : "",
-           authctxt->info != NULL ? authctxt->info : "");
-       free(authctxt->info);
-       authctxt->info = NULL;
+           extra != NULL ? ": " : "",
+           extra != NULL ? extra : "");
+
+       free(extra);
 
 #ifdef CUSTOM_FAILED_LOGIN
        if (authenticated == 0 && !authctxt->postponed &&
@@ -339,12 +372,11 @@ auth_maxtries_exceeded(Authctxt *authctxt)
        struct ssh *ssh = active_state; /* XXX */
 
        error("maximum authentication attempts exceeded for "
-           "%s%.100s from %.200s port %d %s",
+           "%s%.100s from %.200s port %d ssh2",
            authctxt->valid ? "" : "invalid user ",
            authctxt->user,
            ssh_remote_ipaddr(ssh),
-           ssh_remote_port(ssh),
-           compat20 ? "ssh2" : "ssh1");
+           ssh_remote_port(ssh));
        packet_disconnect("Too many authentication failures");
        /* NOTREACHED */
 }
@@ -419,7 +451,7 @@ authorized_principals_file(struct passwd *pw)
 
 /* return ok if key exists in sysfile or userfile */
 HostStatus
-check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
+check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
     const char *sysfile, const char *userfile)
 {
        char *user_hostfile;
@@ -463,98 +495,6 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
        return host_status;
 }
 
-/*
- * Check a given path for security. This is defined as all components
- * of the path to the file must be owned by either the owner of
- * of the file or root and no directories must be group or world writable.
- *
- * XXX Should any specific check be done for sym links ?
- *
- * Takes a file name, its stat information (preferably from fstat() to
- * avoid races), the uid of the expected owner, their home directory and an
- * error buffer plus max size as arguments.
- *
- * Returns 0 on success and -1 on failure
- */
-int
-auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
-    uid_t uid, char *err, size_t errlen)
-{
-       char buf[PATH_MAX], homedir[PATH_MAX];
-       char *cp;
-       int comparehome = 0;
-       struct stat st;
-
-       if (realpath(name, buf) == NULL) {
-               snprintf(err, errlen, "realpath %s failed: %s", name,
-                   strerror(errno));
-               return -1;
-       }
-       if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
-               comparehome = 1;
-
-       if (!S_ISREG(stp->st_mode)) {
-               snprintf(err, errlen, "%s is not a regular file", buf);
-               return -1;
-       }
-       if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
-           (stp->st_mode & 022) != 0) {
-               snprintf(err, errlen, "bad ownership or modes for file %s",
-                   buf);
-               return -1;
-       }
-
-       /* for each component of the canonical path, walking upwards */
-       for (;;) {
-               if ((cp = dirname(buf)) == NULL) {
-                       snprintf(err, errlen, "dirname() failed");
-                       return -1;
-               }
-               strlcpy(buf, cp, sizeof(buf));
-
-               if (stat(buf, &st) < 0 ||
-                   (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
-                   (st.st_mode & 022) != 0) {
-                       snprintf(err, errlen,
-                           "bad ownership or modes for directory %s", buf);
-                       return -1;
-               }
-
-               /* If are past the homedir then we can stop */
-               if (comparehome && strcmp(homedir, buf) == 0)
-                       break;
-
-               /*
-                * dirname should always complete with a "/" path,
-                * but we can be paranoid and check for "." too
-                */
-               if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
-                       break;
-       }
-       return 0;
-}
-
-/*
- * Version of secure_path() that accepts an open file descriptor to
- * avoid races.
- *
- * Returns 0 on success and -1 on failure
- */
-static int
-secure_filename(FILE *f, const char *file, struct passwd *pw,
-    char *err, size_t errlen)
-{
-       struct stat st;
-
-       /* check the open file to avoid races */
-       if (fstat(fileno(f), &st) < 0) {
-               snprintf(err, errlen, "cannot stat file %s: %s",
-                   file, strerror(errno));
-               return -1;
-       }
-       return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
-}
-
 static FILE *
 auth_openfile(const char *file, struct passwd *pw, int strict_modes,
     int log_missing, char *file_type)
@@ -587,7 +527,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes,
                return NULL;
        }
        if (strict_modes &&
-           secure_filename(f, file, pw, line, sizeof(line)) != 0) {
+           safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
                fclose(f);
                logit("Authentication refused: %s", line);
                auth_debug_add("Ignored %s: %s", file_type, line);
@@ -626,6 +566,8 @@ getpwnamallow(const char *user)
 
        ci->user = user;
        parse_server_match_config(&options, ci);
+       log_change_level(options.log_level);
+       process_permitopen(ssh, &options);
 
 #if defined(_AIX) && defined(HAVE_SETAUTHDB)
        aix_setauthdb(user);
@@ -685,7 +627,7 @@ getpwnamallow(const char *user)
 
 /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
 int
-auth_key_is_revoked(Key *key)
+auth_key_is_revoked(struct sshkey *key)
 {
        char *fp = NULL;
        int r;
index 55170af..29835ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.88 2016/05/04 14:04:40 markus Exp $ */
+/* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -44,6 +44,7 @@
 
 struct ssh;
 struct sshkey;
+struct sshbuf;
 
 typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;
@@ -62,13 +63,17 @@ struct Authctxt {
        char            *service;
        struct passwd   *pw;            /* set if 'valid' */
        char            *style;
+
+       /* Method lists for multiple authentication */
+       char            **auth_methods; /* modified from server config */
+       u_int            num_auth_methods;
+
+       /* Authentication method-specific data */
+       void            *methoddata;
        void            *kbdintctxt;
-       char            *info;          /* Extra info for next auth_log */
 #ifdef BSD_AUTH
        auth_session_t  *as;
 #endif
-       char            **auth_methods; /* modified from server config */
-       u_int            num_auth_methods;
 #ifdef KRB5
        krb5_context     krb5_ctx;
        krb5_ccache      krb5_fwd_ccache;
@@ -76,12 +81,20 @@ struct Authctxt {
        char            *krb5_ticket_file;
        char            *krb5_ccname;
 #endif
-       Buffer          *loginmsg;
-       void            *methoddata;
+       struct sshbuf   *loginmsg;
+
+       /* Authentication keys already used; these will be refused henceforth */
+       struct sshkey   **prev_keys;
+       u_int            nprev_keys;
+
+       /* Last used key and ancilliary information from active auth method */
+       struct sshkey   *auth_method_key;
+       char            *auth_method_info;
 
-       struct sshkey   **prev_userkeys;
-       u_int            nprev_userkeys;
+       /* Information exposed to session */
+       struct sshbuf   *session_info;  /* Auth info for environment */
 };
+
 /*
  * Every authentication method has to handle authentication requests for
  * non-existing users, or for users that are not allowed to login. In this
@@ -91,7 +104,7 @@ struct Authctxt {
 
 struct Authmethod {
        char    *name;
-       int     (*userauth)(Authctxt *authctxt);
+       int     (*userauth)(struct ssh *);
        int     *enabled;
 };
 
@@ -112,30 +125,26 @@ struct KbdintDevice
        void    (*free_ctx)(void *ctx);
 };
 
-int      auth_rhosts(struct passwd *, const char *);
 int
 auth_rhosts2(struct passwd *, const char *, const char *, const char *);
 
-int     auth_rhosts_rsa(Authctxt *, char *, Key *);
 int      auth_password(Authctxt *, const char *);
-int      auth_rsa(Authctxt *, BIGNUM *);
-int      auth_rsa_challenge_dialog(Key *);
-BIGNUM *auth_rsa_generate_challenge(Key *);
-int     auth_rsa_verify_response(Key *, BIGNUM *, u_char[]);
-int     auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
-
-int     auth_rhosts_rsa_key_allowed(struct passwd *, const char *,
-    const char *, Key *);
-int     hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
-int     user_key_allowed(struct passwd *, Key *, int);
-void    pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
-           __attribute__((__format__ (printf, 3, 4)));
-void    auth2_record_userkey(Authctxt *, struct sshkey *);
-int     auth2_userkey_already_used(Authctxt *, struct sshkey *);
-
-struct stat;
-int     auth_secure_path(const char *, struct stat *, const char *, uid_t,
-    char *, size_t);
+
+int     hostbased_key_allowed(struct passwd *, const char *, char *,
+           struct sshkey *);
+int     user_key_allowed(struct passwd *, struct sshkey *, int);
+int     auth2_key_already_used(Authctxt *, const struct sshkey *);
+
+/*
+ * Handling auth method-specific information for logging and prevention
+ * of key reuse during multiple authentication.
+ */
+void    auth2_authctxt_reset_info(Authctxt *);
+void    auth2_record_key(Authctxt *, int, const struct sshkey *);
+void    auth2_record_info(Authctxt *authctxt, const char *, ...)
+           __attribute__((__format__ (printf, 2, 3)))
+           __attribute__((__nonnull__ (2)));
+void    auth2_update_session_info(Authctxt *, const char *, const char *);
 
 #ifdef KRB5
 int    auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
@@ -156,15 +165,11 @@ void remove_kbdint_device(const char *);
 
 void disable_forwarding(void);
 
-void   do_authentication(Authctxt *);
 void   do_authentication2(Authctxt *);
 
-void   auth_info(Authctxt *authctxt, const char *, ...)
-           __attribute__((__format__ (printf, 2, 3)))
-           __attribute__((__nonnull__ (2)));
 void   auth_log(Authctxt *, int, int, const char *, const char *);
 void   auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
-void   userauth_finish(Authctxt *, int, const char *, const char *);
+void   userauth_finish(struct ssh *, int, const char *, const char *);
 int    auth_root_allowed(const char *);
 
 void   userauth_send_banner(const char *);
@@ -177,8 +182,8 @@ int  auth2_method_allowed(Authctxt *, const char *, const char *);
 
 void   privsep_challenge_enable(void);
 
-int    auth2_challenge(Authctxt *, char *);
-void   auth2_challenge_stop(Authctxt *);
+int    auth2_challenge(struct ssh *, char *);
+void   auth2_challenge_stop(struct ssh *);
 int    bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
 int    bsdauth_respond(void *, u_int, char **);
 int    skey_query(void *, char **, char **, u_int *, char ***, u_int **);
@@ -187,32 +192,27 @@ int       skey_respond(void *, u_int, char **);
 int    allowed_user(struct passwd *);
 struct passwd * getpwnamallow(const char *user);
 
-char   *get_challenge(Authctxt *);
-int    verify_response(Authctxt *, const char *);
-void   abandon_challenge_response(Authctxt *);
-
 char   *expand_authorized_keys(const char *, struct passwd *pw);
 char   *authorized_principals_file(struct passwd *);
 
 FILE   *auth_openkeyfile(const char *, struct passwd *, int);
 FILE   *auth_openprincipals(const char *, struct passwd *, int);
-int     auth_key_is_revoked(Key *);
+int     auth_key_is_revoked(struct sshkey *);
 
 const char     *auth_get_canonical_hostname(struct ssh *, int);
 
 HostStatus
-check_key_in_hostfiles(struct passwd *, Key *, const char *,
+check_key_in_hostfiles(struct passwd *, struct sshkey *, const char *,
     const char *, const char *);
 
 /* hostkey handling */
-Key    *get_hostkey_by_index(int);
-Key    *get_hostkey_public_by_index(int, struct ssh *);
-Key    *get_hostkey_public_by_type(int, int, struct ssh *);
-Key    *get_hostkey_private_by_type(int, int, struct ssh *);
-int     get_hostkey_index(Key *, int, struct ssh *);
-int     ssh1_session_key(BIGNUM *);
-int     sshd_hostkey_sign(Key *, Key *, u_char **, size_t *,
-            const u_char *, size_t, const char *, u_int);
+struct sshkey  *get_hostkey_by_index(int);
+struct sshkey  *get_hostkey_public_by_index(int, struct ssh *);
+struct sshkey  *get_hostkey_public_by_type(int, int, struct ssh *);
+struct sshkey  *get_hostkey_private_by_type(int, int, struct ssh *);
+int     get_hostkey_index(struct sshkey *, int, struct ssh *);
+int     sshd_hostkey_sign(struct sshkey *, struct sshkey *, u_char **,
+            size_t *, const u_char *, size_t, const char *, u_int);
 
 /* debug messages during authentication */
 void    auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
index 5073c49..e69de29 100644 (file)
@@ -1,444 +0,0 @@
-/* $OpenBSD: auth1.c,v 1.82 2014/07/15 15:54:14 millert Exp $ */
-/*
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
- *
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose.  Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
- */
-
-#include "includes.h"
-
-#ifdef WITH_SSH1
-
-#include <sys/types.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <pwd.h>
-
-#include "openbsd-compat/sys-queue.h"
-#include "xmalloc.h"
-#include "rsa.h"
-#include "ssh1.h"
-#include "packet.h"
-#include "buffer.h"
-#include "log.h"
-#include "misc.h"
-#include "servconf.h"
-#include "compat.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "channels.h"
-#include "session.h"
-#include "uidswap.h"
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-#include "monitor_wrap.h"
-#include "buffer.h"
-
-/* import */
-extern ServerOptions options;
-extern Buffer loginmsg;
-
-static int auth1_process_password(Authctxt *);
-static int auth1_process_rsa(Authctxt *);
-static int auth1_process_rhosts_rsa(Authctxt *);
-static int auth1_process_tis_challenge(Authctxt *);
-static int auth1_process_tis_response(Authctxt *);
-
-static char *client_user = NULL;    /* Used to fill in remote user for PAM */
-
-struct AuthMethod1 {
-       int type;
-       char *name;
-       int *enabled;
-       int (*method)(Authctxt *);
-};
-
-const struct AuthMethod1 auth1_methods[] = {
-       {
-               SSH_CMSG_AUTH_PASSWORD, "password",
-               &options.password_authentication, auth1_process_password
-       },
-       {
-               SSH_CMSG_AUTH_RSA, "rsa",
-               &options.rsa_authentication, auth1_process_rsa
-       },
-       {
-               SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
-               &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
-       },
-       {
-               SSH_CMSG_AUTH_TIS, "challenge-response",
-               &options.challenge_response_authentication,
-               auth1_process_tis_challenge
-       },
-       {
-               SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
-               &options.challenge_response_authentication,
-               auth1_process_tis_response
-       },
-       { -1, NULL, NULL, NULL}
-};
-
-static const struct AuthMethod1
-*lookup_authmethod1(int type)
-{
-       int i;
-
-       for (i = 0; auth1_methods[i].name != NULL; i++)
-               if (auth1_methods[i].type == type)
-                       return (&(auth1_methods[i]));
-
-       return (NULL);
-}
-
-static char *
-get_authname(int type)
-{
-       const struct AuthMethod1 *a;
-       static char buf[64];
-
-       if ((a = lookup_authmethod1(type)) != NULL)
-               return (a->name);
-       snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
-       return (buf);
-}
-
-/*ARGSUSED*/
-static int
-auth1_process_password(Authctxt *authctxt)
-{
-       int authenticated = 0;
-       char *password;
-       u_int dlen;
-
-       /*
-        * Read user password.  It is in plain text, but was
-        * transmitted over the encrypted channel so it is
-        * not visible to an outside observer.
-        */
-       password = packet_get_string(&dlen);
-       packet_check_eom();
-
-       /* Try authentication with the password. */
-       authenticated = PRIVSEP(auth_password(authctxt, password));
-
-       explicit_bzero(password, dlen);
-       free(password);
-
-       return (authenticated);
-}
-
-/*ARGSUSED*/
-static int
-auth1_process_rsa(Authctxt *authctxt)
-{
-       int authenticated = 0;
-       BIGNUM *n;
-
-       /* RSA authentication requested. */
-       if ((n = BN_new()) == NULL)
-               fatal("do_authloop: BN_new failed");
-       packet_get_bignum(n);
-       packet_check_eom();
-       authenticated = auth_rsa(authctxt, n);
-       BN_clear_free(n);
-
-       return (authenticated);
-}
-
-/*ARGSUSED*/
-static int
-auth1_process_rhosts_rsa(Authctxt *authctxt)
-{
-       int keybits, authenticated = 0;
-       u_int bits;
-       Key *client_host_key;
-       u_int ulen;
-
-       /*
-        * Get client user name.  Note that we just have to
-        * trust the client; root on the client machine can
-        * claim to be any user.
-        */
-       client_user = packet_get_cstring(&ulen);
-
-       /* Get the client host key. */
-       client_host_key = key_new(KEY_RSA1);
-       bits = packet_get_int();
-       packet_get_bignum(client_host_key->rsa->e);
-       packet_get_bignum(client_host_key->rsa->n);
-
-       keybits = BN_num_bits(client_host_key->rsa->n);
-       if (keybits < 0 || bits != (u_int)keybits) {
-               verbose("Warning: keysize mismatch for client_host_key: "
-                   "actual %d, announced %d",
-                   BN_num_bits(client_host_key->rsa->n), bits);
-       }
-       packet_check_eom();
-
-       authenticated = auth_rhosts_rsa(authctxt, client_user,
-           client_host_key);
-       key_free(client_host_key);
-
-       auth_info(authctxt, "ruser %.100s", client_user);
-
-       return (authenticated);
-}
-
-/*ARGSUSED*/
-static int
-auth1_process_tis_challenge(Authctxt *authctxt)
-{
-       char *challenge;
-
-       if ((challenge = get_challenge(authctxt)) == NULL)
-               return (0);
-
-       debug("sending challenge '%s'", challenge);
-       packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
-       packet_put_cstring(challenge);
-       free(challenge);
-       packet_send();
-       packet_write_wait();
-
-       return (-1);
-}
-
-/*ARGSUSED*/
-static int
-auth1_process_tis_response(Authctxt *authctxt)
-{
-       int authenticated = 0;
-       char *response;
-       u_int dlen;
-
-       response = packet_get_string(&dlen);
-       packet_check_eom();
-       authenticated = verify_response(authctxt, response);
-       explicit_bzero(response, dlen);
-       free(response);
-
-       return (authenticated);
-}
-
-/*
- * read packets, try to authenticate the user and
- * return only if authentication is successful
- */
-static void
-do_authloop(Authctxt *authctxt)
-{
-       int authenticated = 0;
-       int prev = 0, type = 0;
-       const struct AuthMethod1 *meth;
-
-       debug("Attempting authentication for %s%.100s.",
-           authctxt->valid ? "" : "invalid user ", authctxt->user);
-
-       /* If the user has no password, accept authentication immediately. */
-       if (options.permit_empty_passwd && options.password_authentication &&
-#ifdef KRB5
-           (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
-#endif
-           PRIVSEP(auth_password(authctxt, ""))) {
-#ifdef USE_PAM
-               if (options.use_pam && (PRIVSEP(do_pam_account())))
-#endif
-               {
-                       auth_log(authctxt, 1, 0, "without authentication",
-                           NULL);
-                       return;
-               }
-       }
-
-       /* Indicate that authentication is needed. */
-       packet_start(SSH_SMSG_FAILURE);
-       packet_send();
-       packet_write_wait();
-
-       for (;;) {
-               /* default to fail */
-               authenticated = 0;
-
-
-               /* Get a packet from the client. */
-               prev = type;
-               type = packet_read();
-
-               /*
-                * If we started challenge-response authentication but the
-                * next packet is not a response to our challenge, release
-                * the resources allocated by get_challenge() (which would
-                * normally have been released by verify_response() had we
-                * received such a response)
-                */
-               if (prev == SSH_CMSG_AUTH_TIS &&
-                   type != SSH_CMSG_AUTH_TIS_RESPONSE)
-                       abandon_challenge_response(authctxt);
-
-               if (authctxt->failures >= options.max_authtries)
-                       goto skip;
-               if ((meth = lookup_authmethod1(type)) == NULL) {
-                       logit("Unknown message during authentication: "
-                           "type %d", type);
-                       goto skip;
-               }
-
-               if (!*(meth->enabled)) {
-                       verbose("%s authentication disabled.", meth->name);
-                       goto skip;
-               }
-
-               authenticated = meth->method(authctxt);
-               if (authenticated == -1)
-                       continue; /* "postponed" */
-
-#ifdef BSD_AUTH
-               if (authctxt->as) {
-                       auth_close(authctxt->as);
-                       authctxt->as = NULL;
-               }
-#endif
-               if (!authctxt->valid && authenticated)
-                       fatal("INTERNAL ERROR: authenticated invalid user %s",
-                           authctxt->user);
-
-#ifdef _UNICOS
-               if (authenticated && cray_access_denied(authctxt->user)) {
-                       authenticated = 0;
-                       fatal("Access denied for user %s.",authctxt->user);
-               }
-#endif /* _UNICOS */
-
-#ifndef HAVE_CYGWIN
-               /* Special handling for root */
-               if (authenticated && authctxt->pw->pw_uid == 0 &&
-                   !auth_root_allowed(meth->name)) {
-                       authenticated = 0;
-# ifdef SSH_AUDIT_EVENTS
-                       PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
-# endif
-               }
-#endif
-
-#ifdef USE_PAM
-               if (options.use_pam && authenticated &&
-                   !PRIVSEP(do_pam_account())) {
-                       char *msg;
-                       size_t len;
-
-                       error("Access denied for user %s by PAM account "
-                           "configuration", authctxt->user);
-                       len = buffer_len(&loginmsg);
-                       buffer_append(&loginmsg, "\0", 1);
-                       msg = buffer_ptr(&loginmsg);
-                       /* strip trailing newlines */
-                       if (len > 0)
-                               while (len > 0 && msg[--len] == '\n')
-                                       msg[len] = '\0';
-                       else
-                               msg = "Access denied.";
-                       packet_disconnect("%s", msg);
-               }
-#endif
-
- skip:
-               /* Log before sending the reply */
-               auth_log(authctxt, authenticated, 0, get_authname(type), NULL);
-
-               free(client_user);
-               client_user = NULL;
-
-               if (authenticated)
-                       return;
-
-               if (++authctxt->failures >= options.max_authtries) {
-#ifdef SSH_AUDIT_EVENTS
-                       PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
-#endif
-                       auth_maxtries_exceeded(authctxt);
-               }
-
-               packet_start(SSH_SMSG_FAILURE);
-               packet_send();
-               packet_write_wait();
-       }
-}
-
-/*
- * Performs authentication of an incoming connection.  Session key has already
- * been exchanged and encryption is enabled.
- */
-void
-do_authentication(Authctxt *authctxt)
-{
-       u_int ulen;
-       char *user, *style = NULL;
-
-       /* Get the name of the user that we wish to log in as. */
-       packet_read_expect(SSH_CMSG_USER);
-
-       /* Get the user name. */
-       user = packet_get_cstring(&ulen);
-       packet_check_eom();
-
-       if ((style = strchr(user, ':')) != NULL)
-               *style++ = '\0';
-
-       authctxt->user = user;
-       authctxt->style = style;
-
-       /* Verify that the user is a valid user. */
-       if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
-               authctxt->valid = 1;
-       else {
-               debug("do_authentication: invalid user %s", user);
-               authctxt->pw = fakepw();
-       }
-
-       /* Configuration may have changed as a result of Match */
-       if (options.num_auth_methods != 0)
-               fatal("AuthenticationMethods is not supported with SSH "
-                   "protocol 1");
-
-       setproctitle("%s%s", authctxt->valid ? user : "unknown",
-           use_privsep ? " [net]" : "");
-
-#ifdef USE_PAM
-       if (options.use_pam)
-               PRIVSEP(start_pam(authctxt));
-#endif
-
-       /*
-        * If we are not running as root, the user must have the same uid as
-        * the server.
-        */
-#ifndef HAVE_CYGWIN
-       if (!use_privsep && getuid() != 0 && authctxt->pw &&
-           authctxt->pw->pw_uid != getuid())
-               packet_disconnect("Cannot change user when server not running as root.");
-#endif
-
-       /*
-        * Loop until the user has been authenticated or the connection is
-        * closed, do_authloop() returns only if authentication is successful
-        */
-       do_authloop(authctxt);
-
-       /* The user has been authenticated and accepted. */
-       packet_start(SSH_SMSG_SUCCESS);
-       packet_send();
-       packet_write_wait();
-}
-
-#endif /* WITH_SSH1 */
index ead4803..11c8d31 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-chall.c,v 1.44 2016/05/02 08:49:03 djm Exp $ */
+/* $OpenBSD: auth2-chall.c,v 1.48 2017/05/30 14:29:59 markus Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2001 Per Allansson.  All rights reserved.
@@ -47,9 +47,9 @@
 /* import */
 extern ServerOptions options;
 
-static int auth2_challenge_start(Authctxt *);
+static int auth2_challenge_start(struct ssh *);
 static int send_userauth_info_request(Authctxt *);
-static int input_userauth_info_response(int, u_int32_t, void *);
+static int input_userauth_info_response(int, u_int32_t, struct ssh *);
 
 #ifdef BSD_AUTH
 extern KbdintDevice bsdauth_device;
@@ -195,8 +195,9 @@ kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
  * wait for the response.
  */
 int
-auth2_challenge(Authctxt *authctxt, char *devs)
+auth2_challenge(struct ssh *ssh, char *devs)
 {
+       Authctxt *authctxt = ssh->authctxt;
        debug("auth2_challenge: user=%s devs=%s",
            authctxt->user ? authctxt->user : "<nouser>",
            devs ? devs : "<no devs>");
@@ -205,15 +206,16 @@ auth2_challenge(Authctxt *authctxt, char *devs)
                return 0;
        if (authctxt->kbdintctxt == NULL)
                authctxt->kbdintctxt = kbdint_alloc(devs);
-       return auth2_challenge_start(authctxt);
+       return auth2_challenge_start(ssh);
 }
 
 /* unregister kbd-int callbacks and context */
 void
-auth2_challenge_stop(Authctxt *authctxt)
+auth2_challenge_stop(struct ssh *ssh)
 {
+       Authctxt *authctxt = ssh->authctxt;
        /* unregister callback */
-       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
        if (authctxt->kbdintctxt != NULL) {
                kbdint_free(authctxt->kbdintctxt);
                authctxt->kbdintctxt = NULL;
@@ -222,29 +224,30 @@ auth2_challenge_stop(Authctxt *authctxt)
 
 /* side effect: sets authctxt->postponed if a reply was sent*/
 static int
-auth2_challenge_start(Authctxt *authctxt)
+auth2_challenge_start(struct ssh *ssh)
 {
+       Authctxt *authctxt = ssh->authctxt;
        KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
 
        debug2("auth2_challenge_start: devices %s",
            kbdintctxt->devices ?  kbdintctxt->devices : "<empty>");
 
        if (kbdint_next_device(authctxt, kbdintctxt) == 0) {
-               auth2_challenge_stop(authctxt);
+               auth2_challenge_stop(ssh);
                return 0;
        }
        debug("auth2_challenge_start: trying authentication method '%s'",
            kbdintctxt->device->name);
 
        if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
-               auth2_challenge_stop(authctxt);
+               auth2_challenge_stop(ssh);
                return 0;
        }
        if (send_userauth_info_request(authctxt) == 0) {
-               auth2_challenge_stop(authctxt);
+               auth2_challenge_stop(ssh);
                return 0;
        }
-       dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE,
            &input_userauth_info_response);
 
        authctxt->postponed = 1;
@@ -285,9 +288,9 @@ send_userauth_info_request(Authctxt *authctxt)
 }
 
 static int
-input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
+input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        KbdintAuthctxt *kbdintctxt;
        int authenticated = 0, res;
        u_int i, nresp;
@@ -340,14 +343,14 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
        devicename = kbdintctxt->device->name;
        if (!authctxt->postponed) {
                if (authenticated) {
-                       auth2_challenge_stop(authctxt);
+                       auth2_challenge_stop(ssh);
                } else {
                        /* start next device */
                        /* may set authctxt->postponed */
-                       auth2_challenge_start(authctxt);
+                       auth2_challenge_start(ssh);
                }
        }
-       userauth_finish(authctxt, authenticated, "keyboard-interactive",
+       userauth_finish(ssh, authenticated, "keyboard-interactive",
            devicename);
        return 0;
 }
index 1ca8357..589283b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
+/* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
 
 extern ServerOptions options;
 
-static int input_gssapi_token(int type, u_int32_t plen, void *ctxt);
-static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
-static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
-static int input_gssapi_errtok(int, u_int32_t, void *);
+static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh);
+static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh);
+static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
+static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
 
 /*
  * We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like)
  */
 static int
-userauth_gssapi(Authctxt *authctxt)
+userauth_gssapi(struct ssh *ssh)
 {
+       Authctxt *authctxt = ssh->authctxt;
        gss_OID_desc goid = {0, NULL};
        Gssctxt *ctxt = NULL;
        int mechs;
@@ -119,17 +120,17 @@ userauth_gssapi(Authctxt *authctxt)
        packet_send();
        free(doid);
 
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
        authctxt->postponed = 1;
 
        return (0);
 }
 
 static int
-input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        Gssctxt *gssctxt;
        gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc recv_tok;
@@ -157,8 +158,8 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
                        packet_send();
                }
                authctxt->postponed = 0;
-               dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-               userauth_finish(authctxt, 0, "gssapi-with-mic", NULL);
+               ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+               userauth_finish(ssh, 0, "gssapi-with-mic", NULL);
        } else {
                if (send_tok.length != 0) {
                        packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
@@ -166,12 +167,12 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
                        packet_send();
                }
                if (maj_status == GSS_S_COMPLETE) {
-                       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+                       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
                        if (flags & GSS_C_INTEG_FLAG)
-                               dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
+                               ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC,
                                    &input_gssapi_mic);
                        else
-                               dispatch_set(
+                               ssh_dispatch_set(ssh,
                                    SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
                                    &input_gssapi_exchange_complete);
                }
@@ -182,9 +183,9 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
 }
 
 static int
-input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        Gssctxt *gssctxt;
        gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc recv_tok;
@@ -207,8 +208,8 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
        free(recv_tok.value);
 
        /* We can't return anything to the client, even if we wanted to */
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
 
        /* The client will have already moved on to the next auth */
 
@@ -223,10 +224,11 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
  */
 
 static int
-input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        int authenticated;
+       const char *displayname;
 
        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
                fatal("No authentication or GSSAPI context");
@@ -240,24 +242,29 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
 
        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
 
+       if ((!use_privsep || mm_is_monitor()) &&
+           (displayname = ssh_gssapi_displayname()) != NULL)
+               auth2_record_info(authctxt, "%s", displayname);
+
        authctxt->postponed = 0;
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
-       userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+       userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
        return 0;
 }
 
 static int
-input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
+input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        Gssctxt *gssctxt;
        int authenticated = 0;
        Buffer b;
        gss_buffer_desc mic, gssbuf;
        u_int len;
+       const char *displayname;
 
        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
                fatal("No authentication or GSSAPI context");
@@ -281,12 +288,16 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
        buffer_free(&b);
        free(mic.value);
 
+       if ((!use_privsep || mm_is_monitor()) &&
+           (displayname = ssh_gssapi_displayname()) != NULL)
+               auth2_record_info(authctxt, "%s", displayname);
+
        authctxt->postponed = 0;
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
-       userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+       userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
        return 0;
 }
 
index 1b3c3b2..92758b3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.26 2016/03/07 19:02:43 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -39,7 +39,7 @@
 #include "misc.h"
 #include "servconf.h"
 #include "compat.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "canohost.h"
@@ -48,6 +48,7 @@
 #endif
 #include "monitor_wrap.h"
 #include "pathnames.h"
+#include "ssherr.h"
 #include "match.h"
 
 /* import */
@@ -56,54 +57,56 @@ extern u_char *session_id2;
 extern u_int session_id2_len;
 
 static int
-userauth_hostbased(Authctxt *authctxt)
+userauth_hostbased(struct ssh *ssh)
 {
-       Buffer b;
-       Key *key = NULL;
+       Authctxt *authctxt = ssh->authctxt;
+       struct sshbuf *b;
+       struct sshkey *key = NULL;
        char *pkalg, *cuser, *chost, *service;
        u_char *pkblob, *sig;
-       u_int alen, blen, slen;
-       int pktype;
-       int authenticated = 0;
+       size_t alen, blen, slen;
+       int r, pktype, authenticated = 0;
 
        if (!authctxt->valid) {
-               debug2("userauth_hostbased: disabled because of invalid user");
+               debug2("%s: disabled because of invalid user", __func__);
                return 0;
        }
-       pkalg = packet_get_string(&alen);
-       pkblob = packet_get_string(&blen);
-       chost = packet_get_string(NULL);
-       cuser = packet_get_string(NULL);
-       sig = packet_get_string(&slen);
+       /* XXX use sshkey_froms() */
+       if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
+           (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
+           (r = sshpkt_get_string(ssh, &sig, &slen)) != 0)
+               fatal("%s: packet parsing: %s", __func__, ssh_err(r));
 
-       debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
+       debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__,
            cuser, chost, pkalg, slen);
 #ifdef DEBUG_PK
        debug("signature:");
-       buffer_init(&b);
-       buffer_append(&b, sig, slen);
-       buffer_dump(&b);
-       buffer_free(&b);
+       sshbuf_dump_data(sig, siglen, stderr);
 #endif
-       pktype = key_type_from_name(pkalg);
+       pktype = sshkey_type_from_name(pkalg);
        if (pktype == KEY_UNSPEC) {
                /* this is perfectly legal */
-               logit("userauth_hostbased: unsupported "
-                   "public key algorithm: %s", pkalg);
+               logit("%s: unsupported public key algorithm: %s",
+                   __func__, pkalg);
+               goto done;
+       }
+       if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
+               error("%s: key_from_blob: %s", __func__, ssh_err(r));
                goto done;
        }
-       key = key_from_blob(pkblob, blen);
        if (key == NULL) {
-               error("userauth_hostbased: cannot decode key: %s", pkalg);
+               error("%s: cannot decode key: %s", __func__, pkalg);
                goto done;
        }
        if (key->type != pktype) {
-               error("userauth_hostbased: type mismatch for decoded key "
-                   "(received %d, expected %d)", key->type, pktype);
+               error("%s: type mismatch for decoded key "
+                   "(received %d, expected %d)", __func__, key->type, pktype);
                goto done;
        }
-       if (key_type_plain(key->type) == KEY_RSA &&
-           (datafellows & SSH_BUG_RSASIGMD5) != 0) {
+       if (sshkey_type_plain(key->type) == KEY_RSA &&
+           (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
                error("Refusing RSA key because peer uses unsafe "
                    "signature format");
                goto done;
@@ -115,38 +118,40 @@ userauth_hostbased(Authctxt *authctxt)
                goto done;
        }
 
-       service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
+       service = ssh->compat & SSH_BUG_HBSERVICE ? "ssh-userauth" :
            authctxt->service;
-       buffer_init(&b);
-       buffer_put_string(&b, session_id2, session_id2_len);
+       if ((b = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
        /* reconstruct packet */
-       buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
-       buffer_put_cstring(&b, authctxt->user);
-       buffer_put_cstring(&b, service);
-       buffer_put_cstring(&b, "hostbased");
-       buffer_put_string(&b, pkalg, alen);
-       buffer_put_string(&b, pkblob, blen);
-       buffer_put_cstring(&b, chost);
-       buffer_put_cstring(&b, cuser);
+       if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
+           (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
+           (r = sshbuf_put_cstring(b, authctxt->user)) != 0 ||
+           (r = sshbuf_put_cstring(b, service)) != 0 ||
+           (r = sshbuf_put_cstring(b, "hostbased")) != 0 ||
+           (r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
+           (r = sshbuf_put_string(b, pkblob, blen)) != 0 ||
+           (r = sshbuf_put_cstring(b, chost)) != 0 ||
+           (r = sshbuf_put_cstring(b, cuser)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
 #ifdef DEBUG_PK
-       buffer_dump(&b);
+       sshbuf_dump(b, stderr);
 #endif
 
-       pubkey_auth_info(authctxt, key,
+       auth2_record_info(authctxt,
            "client user \"%.100s\", client host \"%.100s\"", cuser, chost);
 
        /* test for allowed key and correct signature */
        authenticated = 0;
        if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
-           PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
-                       buffer_len(&b))) == 1)
+           PRIVSEP(sshkey_verify(key, sig, slen,
+           sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
                authenticated = 1;
 
-       buffer_free(&b);
+       auth2_record_key(authctxt, authenticated, key);
+       sshbuf_free(b);
 done:
-       debug2("userauth_hostbased: authenticated %d", authenticated);
-       if (key != NULL)
-               key_free(key);
+       debug2("%s: authenticated %d", __func__, authenticated);
+       sshkey_free(key);
        free(pkalg);
        free(pkblob);
        free(cuser);
@@ -158,7 +163,7 @@ done:
 /* return 1 if given hostkey is allowed */
 int
 hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
-    Key *key)
+    struct sshkey *key)
 {
        struct ssh *ssh = active_state; /* XXX */
        const char *resolvedname, *ipaddr, *lookup, *reason;
@@ -203,8 +208,8 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
        }
        debug2("%s: access allowed by auth_rhosts2", __func__);
 
-       if (key_is_cert(key) && 
-           key_cert_check_authority(key, 1, 0, lookup, &reason)) {
+       if (sshkey_is_cert(key) &&
+           sshkey_cert_check_authority(key, 1, 0, lookup, &reason)) {
                error("%s", reason);
                auth_debug_add("%s", reason);
                return 0;
@@ -223,20 +228,20 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
        }
 
        if (host_status == HOST_OK) {
-               if (key_is_cert(key)) {
+               if (sshkey_is_cert(key)) {
                        if ((fp = sshkey_fingerprint(key->cert->signature_key,
                            options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
                                fatal("%s: sshkey_fingerprint fail", __func__);
                        verbose("Accepted certificate ID \"%s\" signed by "
                            "%s CA %s from %s@%s", key->cert->key_id,
-                           key_type(key->cert->signature_key), fp,
+                           sshkey_type(key->cert->signature_key), fp,
                            cuser, lookup);
                } else {
                        if ((fp = sshkey_fingerprint(key,
                            options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
                                fatal("%s: sshkey_fingerprint fail", __func__);
                        verbose("Accepted %s public key %s from %s@%s",
-                           key_type(key), fp, cuser, lookup);
+                           sshkey_type(key), fp, cuser, lookup);
                }
                free(fp);
        }
index bf75c60..86aad8d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-kbdint.c,v 1.7 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: auth2-kbdint.c,v 1.8 2017/05/30 14:29:59 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -43,7 +43,7 @@
 extern ServerOptions options;
 
 static int
-userauth_kbdint(Authctxt *authctxt)
+userauth_kbdint(struct ssh *ssh)
 {
        int authenticated = 0;
        char *lang, *devs;
@@ -55,7 +55,7 @@ userauth_kbdint(Authctxt *authctxt)
        debug("keyboard-interactive devs %s", devs);
 
        if (options.challenge_response_authentication)
-               authenticated = auth2_challenge(authctxt, devs);
+               authenticated = auth2_challenge(ssh, devs);
 
        free(devs);
        free(lang);
index e71e221..35d25fa 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-none.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: auth2-none.c,v 1.20 2017/05/30 14:29:59 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -37,7 +37,7 @@
 
 #include "atomicio.h"
 #include "xmalloc.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "packet.h"
@@ -47,6 +47,7 @@
 #include "servconf.h"
 #include "compat.h"
 #include "ssh2.h"
+#include "ssherr.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
@@ -59,12 +60,15 @@ extern ServerOptions options;
 static int none_enabled = 1;
 
 static int
-userauth_none(Authctxt *authctxt)
+userauth_none(struct ssh *ssh)
 {
+       int r;
+
        none_enabled = 0;
-       packet_check_eom();
+       if ((r = sshpkt_get_end(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
        if (options.permit_empty_passwd && options.password_authentication)
-               return (PRIVSEP(auth_password(authctxt, "")));
+               return (PRIVSEP(auth_password(ssh->authctxt, "")));
        return (0);
 }
 
index b638e87..5f7ba32 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-passwd.c,v 1.12 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: auth2-passwd.c,v 1.14 2017/05/30 14:29:59 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
 #include <string.h>
 #include <stdarg.h>
 
-#include "xmalloc.h"
 #include "packet.h"
+#include "ssherr.h"
 #include "log.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "buffer.h"
 extern ServerOptions options;
 
 static int
-userauth_passwd(Authctxt *authctxt)
+userauth_passwd(struct ssh *ssh)
 {
-       char *password, *newpass;
-       int authenticated = 0;
-       int change;
-       u_int len, newlen;
+       char *password;
+       int authenticated = 0, r;
+       u_char change;
+       size_t len;
 
-       change = packet_get_char();
-       password = packet_get_string(&len);
-       if (change) {
-               /* discard new password from packet */
-               newpass = packet_get_string(&newlen);
-               explicit_bzero(newpass, newlen);
-               free(newpass);
-       }
-       packet_check_eom();
+       if ((r = sshpkt_get_u8(ssh, &change)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &password, &len)) != 0 ||
+           (change && (r = sshpkt_get_cstring(ssh, NULL, NULL)) != 0) ||
+           (r = sshpkt_get_end(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
 
        if (change)
                logit("password change not supported");
-       else if (PRIVSEP(auth_password(authctxt, password)) == 1)
+       else if (PRIVSEP(auth_password(ssh->authctxt, password)) == 1)
                authenticated = 1;
        explicit_bzero(password, len);
        free(password);
index 41b34ae..169839b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.55 2016/01/27 00:53:12 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -27,7 +27,6 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -52,7 +51,7 @@
 #include "misc.h"
 #include "servconf.h"
 #include "compat.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "pathnames.h"
@@ -75,42 +74,52 @@ extern u_char *session_id2;
 extern u_int session_id2_len;
 
 static int
-userauth_pubkey(Authctxt *authctxt)
+userauth_pubkey(struct ssh *ssh)
 {
-       Buffer b;
-       Key *key = NULL;
-       char *pkalg, *userstyle, *fp = NULL;
-       u_char *pkblob, *sig;
-       u_int alen, blen, slen;
-       int have_sig, pktype;
+       Authctxt *authctxt = ssh->authctxt;
+       struct sshbuf *b;
+       struct sshkey *key = NULL;
+       char *pkalg, *userstyle = NULL, *fp = NULL;
+       u_char *pkblob, *sig, have_sig;
+       size_t blen, slen;
+       int r, pktype;
        int authenticated = 0;
 
        if (!authctxt->valid) {
                debug2("%s: disabled because of invalid user", __func__);
                return 0;
        }
-       have_sig = packet_get_char();
-       if (datafellows & SSH_BUG_PKAUTH) {
+       if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0)
+               fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r));
+       if (ssh->compat & SSH_BUG_PKAUTH) {
                debug2("%s: SSH_BUG_PKAUTH", __func__);
+               if ((b = sshbuf_new()) == NULL)
+                       fatal("%s: sshbuf_new failed", __func__);
                /* no explicit pkalg given */
-               pkblob = packet_get_string(&blen);
-               buffer_init(&b);
-               buffer_append(&b, pkblob, blen);
                /* so we have to extract the pkalg from the pkblob */
-               pkalg = buffer_get_string(&b, &alen);
-               buffer_free(&b);
+               /* XXX use sshbuf_from() */
+               if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
+                   (r = sshbuf_put(b, pkblob, blen)) != 0 ||
+                   (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0)
+                       fatal("%s: failed: %s", __func__, ssh_err(r));
+               sshbuf_free(b);
        } else {
-               pkalg = packet_get_string(&alen);
-               pkblob = packet_get_string(&blen);
+               if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
+                   (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
+                       fatal("%s: sshpkt_get_cstring failed: %s",
+                           __func__, ssh_err(r));
        }
-       pktype = key_type_from_name(pkalg);
+       pktype = sshkey_type_from_name(pkalg);
        if (pktype == KEY_UNSPEC) {
                /* this is perfectly legal */
                logit("%s: unsupported public key algorithm: %s",
                    __func__, pkalg);
                goto done;
        }
-       key = key_from_blob(pkblob, blen);
+       if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
+               error("%s: could not parse key: %s", __func__, ssh_err(r));
+               goto done;
+       }
        if (key == NULL) {
                error("%s: cannot decode key: %s", __func__, pkalg);
                goto done;
@@ -120,15 +129,15 @@ userauth_pubkey(Authctxt *authctxt)
                    "(received %d, expected %d)", __func__, key->type, pktype);
                goto done;
        }
-       if (key_type_plain(key->type) == KEY_RSA &&
-           (datafellows & SSH_BUG_RSASIGMD5) != 0) {
+       if (sshkey_type_plain(key->type) == KEY_RSA &&
+           (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
                logit("Refusing RSA key because client uses unsafe "
                    "signature scheme");
                goto done;
        }
        fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
-       if (auth2_userkey_already_used(authctxt, key)) {
-               logit("refusing previously-used %s key", key_type(key));
+       if (auth2_key_already_used(authctxt, key)) {
+               logit("refusing previously-used %s key", sshkey_type(key));
                goto done;
        }
        if (match_pattern_list(sshkey_ssh_name(key),
@@ -141,54 +150,65 @@ userauth_pubkey(Authctxt *authctxt)
        if (have_sig) {
                debug3("%s: have signature for %s %s",
                    __func__, sshkey_type(key), fp);
-               sig = packet_get_string(&slen);
-               packet_check_eom();
-               buffer_init(&b);
-               if (datafellows & SSH_OLD_SESSIONID) {
-                       buffer_append(&b, session_id2, session_id2_len);
+               if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
+                   (r = sshpkt_get_end(ssh)) != 0)
+                       fatal("%s: %s", __func__, ssh_err(r));
+               if ((b = sshbuf_new()) == NULL)
+                       fatal("%s: sshbuf_new failed", __func__);
+               if (ssh->compat & SSH_OLD_SESSIONID) {
+                       if ((r = sshbuf_put(b, session_id2,
+                           session_id2_len)) != 0)
+                               fatal("%s: sshbuf_put session id: %s",
+                                   __func__, ssh_err(r));
                } else {
-                       buffer_put_string(&b, session_id2, session_id2_len);
+                       if ((r = sshbuf_put_string(b, session_id2,
+                           session_id2_len)) != 0)
+                               fatal("%s: sshbuf_put_string session id: %s",
+                                   __func__, ssh_err(r));
                }
                /* reconstruct packet */
-               buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
                xasprintf(&userstyle, "%s%s%s", authctxt->user,
                    authctxt->style ? ":" : "",
                    authctxt->style ? authctxt->style : "");
-               buffer_put_cstring(&b, userstyle);
-               free(userstyle);
-               buffer_put_cstring(&b,
-                   datafellows & SSH_BUG_PKSERVICE ?
-                   "ssh-userauth" :
-                   authctxt->service);
-               if (datafellows & SSH_BUG_PKAUTH) {
-                       buffer_put_char(&b, have_sig);
+               if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
+                   (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
+                   (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ?
+                   "ssh-userauth" : authctxt->service)) != 0)
+                       fatal("%s: build packet failed: %s",
+                           __func__, ssh_err(r));
+               if (ssh->compat & SSH_BUG_PKAUTH) {
+                       if ((r = sshbuf_put_u8(b, have_sig)) != 0)
+                               fatal("%s: build packet failed: %s",
+                                   __func__, ssh_err(r));
                } else {
-                       buffer_put_cstring(&b, "publickey");
-                       buffer_put_char(&b, have_sig);
-                       buffer_put_cstring(&b, pkalg);
+                       if ((r = sshbuf_put_cstring(b, "publickey")) != 0 ||
+                           (r = sshbuf_put_u8(b, have_sig)) != 0 ||
+                           (r = sshbuf_put_cstring(b, pkalg) != 0))
+                               fatal("%s: build packet failed: %s",
+                                   __func__, ssh_err(r));
                }
-               buffer_put_string(&b, pkblob, blen);
+               if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
+                       fatal("%s: build packet failed: %s",
+                           __func__, ssh_err(r));
 #ifdef DEBUG_PK
-               buffer_dump(&b);
+               sshbuf_dump(b, stderr);
 #endif
-               pubkey_auth_info(authctxt, key, NULL);
 
                /* test for correct signature */
                authenticated = 0;
                if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
-                   PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
-                   buffer_len(&b))) == 1) {
+                   PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
+                   sshbuf_len(b), ssh->compat)) == 0) {
                        authenticated = 1;
-                       /* Record the successful key to prevent reuse */
-                       auth2_record_userkey(authctxt, key);
-                       key = NULL; /* Don't free below */
                }
-               buffer_free(&b);
+               sshbuf_free(b);
                free(sig);
+               auth2_record_key(authctxt, authenticated, key);
        } else {
                debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
                    __func__, sshkey_type(key), fp);
-               packet_check_eom();
+               if ((r = sshpkt_get_end(ssh)) != 0)
+                       fatal("%s: %s", __func__, ssh_err(r));
 
                /* XXX fake reply and always send PK_OK ? */
                /*
@@ -199,11 +219,13 @@ userauth_pubkey(Authctxt *authctxt)
                 * issue? -markus
                 */
                if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
-                       packet_start(SSH2_MSG_USERAUTH_PK_OK);
-                       packet_put_string(pkalg, alen);
-                       packet_put_string(pkblob, blen);
-                       packet_send();
-                       packet_write_wait();
+                       if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
+                           != 0 ||
+                           (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
+                           (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
+                           (r = sshpkt_send(ssh)) != 0)
+                               fatal("%s: %s", __func__, ssh_err(r));
+                       ssh_packet_write_wait(ssh);
                        authctxt->postponed = 1;
                }
        }
@@ -211,333 +233,14 @@ userauth_pubkey(Authctxt *authctxt)
                auth_clear_options();
 done:
        debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
-       if (key != NULL)
-               key_free(key);
+       sshkey_free(key);
+       free(userstyle);
        free(pkalg);
        free(pkblob);
        free(fp);
        return authenticated;
 }
 
-void
-pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
-{
-       char *fp, *extra;
-       va_list ap;
-       int i;
-
-       extra = NULL;
-       if (fmt != NULL) {
-               va_start(ap, fmt);
-               i = vasprintf(&extra, fmt, ap);
-               va_end(ap);
-               if (i < 0 || extra == NULL)
-                       fatal("%s: vasprintf failed", __func__);        
-       }
-
-       if (key_is_cert(key)) {
-               fp = sshkey_fingerprint(key->cert->signature_key,
-                   options.fingerprint_hash, SSH_FP_DEFAULT);
-               auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
-                   key_type(key), key->cert->key_id,
-                   (unsigned long long)key->cert->serial,
-                   key_type(key->cert->signature_key),
-                   fp == NULL ? "(null)" : fp,
-                   extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-               free(fp);
-       } else {
-               fp = sshkey_fingerprint(key, options.fingerprint_hash,
-                   SSH_FP_DEFAULT);
-               auth_info(authctxt, "%s %s%s%s", key_type(key),
-                   fp == NULL ? "(null)" : fp,
-                   extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
-               free(fp);
-       }
-       free(extra);
-}
-
-/*
- * Splits 's' into an argument vector. Handles quoted string and basic
- * escape characters (\\, \", \'). Caller must free the argument vector
- * and its members.
- */
-static int
-split_argv(const char *s, int *argcp, char ***argvp)
-{
-       int r = SSH_ERR_INTERNAL_ERROR;
-       int argc = 0, quote, i, j;
-       char *arg, **argv = xcalloc(1, sizeof(*argv));
-
-       *argvp = NULL;
-       *argcp = 0;
-
-       for (i = 0; s[i] != '\0'; i++) {
-               /* Skip leading whitespace */
-               if (s[i] == ' ' || s[i] == '\t')
-                       continue;
-
-               /* Start of a token */
-               quote = 0;
-               if (s[i] == '\\' &&
-                   (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
-                       i++;
-               else if (s[i] == '\'' || s[i] == '"')
-                       quote = s[i++];
-
-               argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
-               arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
-               argv[argc] = NULL;
-
-               /* Copy the token in, removing escapes */
-               for (j = 0; s[i] != '\0'; i++) {
-                       if (s[i] == '\\') {
-                               if (s[i + 1] == '\'' ||
-                                   s[i + 1] == '\"' ||
-                                   s[i + 1] == '\\') {
-                                       i++; /* Skip '\' */
-                                       arg[j++] = s[i];
-                               } else {
-                                       /* Unrecognised escape */
-                                       arg[j++] = s[i];
-                               }
-                       } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
-                               break; /* done */
-                       else if (quote != 0 && s[i] == quote)
-                               break; /* done */
-                       else
-                               arg[j++] = s[i];
-               }
-               if (s[i] == '\0') {
-                       if (quote != 0) {
-                               /* Ran out of string looking for close quote */
-                               r = SSH_ERR_INVALID_FORMAT;
-                               goto out;
-                       }
-                       break;
-               }
-       }
-       /* Success */
-       *argcp = argc;
-       *argvp = argv;
-       argc = 0;
-       argv = NULL;
-       r = 0;
- out:
-       if (argc != 0 && argv != NULL) {
-               for (i = 0; i < argc; i++)
-                       free(argv[i]);
-               free(argv);
-       }
-       return r;
-}
-
-/*
- * Reassemble an argument vector into a string, quoting and escaping as
- * necessary. Caller must free returned string.
- */
-static char *
-assemble_argv(int argc, char **argv)
-{
-       int i, j, ws, r;
-       char c, *ret;
-       struct sshbuf *buf, *arg;
-
-       if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
-               fatal("%s: sshbuf_new failed", __func__);
-
-       for (i = 0; i < argc; i++) {
-               ws = 0;
-               sshbuf_reset(arg);
-               for (j = 0; argv[i][j] != '\0'; j++) {
-                       r = 0;
-                       c = argv[i][j];
-                       switch (c) {
-                       case ' ':
-                       case '\t':
-                               ws = 1;
-                               r = sshbuf_put_u8(arg, c);
-                               break;
-                       case '\\':
-                       case '\'':
-                       case '"':
-                               if ((r = sshbuf_put_u8(arg, '\\')) != 0)
-                                       break;
-                               /* FALLTHROUGH */
-                       default:
-                               r = sshbuf_put_u8(arg, c);
-                               break;
-                       }
-                       if (r != 0)
-                               fatal("%s: sshbuf_put_u8: %s",
-                                   __func__, ssh_err(r));
-               }
-               if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
-                   (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
-                   (r = sshbuf_putb(buf, arg)) != 0 ||
-                   (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
-                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
-       }
-       if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
-               fatal("%s: malloc failed", __func__);
-       memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
-       ret[sshbuf_len(buf)] = '\0';
-       sshbuf_free(buf);
-       sshbuf_free(arg);
-       return ret;
-}
-
-/*
- * Runs command in a subprocess. Returns pid on success and a FILE* to the
- * subprocess' stdout or 0 on failure.
- * NB. "command" is only used for logging.
- */
-static pid_t
-subprocess(const char *tag, struct passwd *pw, const char *command,
-    int ac, char **av, FILE **child)
-{
-       FILE *f;
-       struct stat st;
-       int devnull, p[2], i;
-       pid_t pid;
-       char *cp, errmsg[512];
-       u_int envsize;
-       char **child_env;
-
-       *child = NULL;
-
-       debug3("%s: %s command \"%s\" running as %s", __func__,
-           tag, command, pw->pw_name);
-
-       /* Verify the path exists and is safe-ish to execute */
-       if (*av[0] != '/') {
-               error("%s path is not absolute", tag);
-               return 0;
-       }
-       temporarily_use_uid(pw);
-       if (stat(av[0], &st) < 0) {
-               error("Could not stat %s \"%s\": %s", tag,
-                   av[0], strerror(errno));
-               restore_uid();
-               return 0;
-       }
-       if (auth_secure_path(av[0], &st, NULL, 0,
-           errmsg, sizeof(errmsg)) != 0) {
-               error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
-               restore_uid();
-               return 0;
-       }
-
-       /*
-        * Run the command; stderr is left in place, stdout is the
-        * authorized_keys output.
-        */
-       if (pipe(p) != 0) {
-               error("%s: pipe: %s", tag, strerror(errno));
-               restore_uid();
-               return 0;
-       }
-
-       /*
-        * Don't want to call this in the child, where it can fatal() and
-        * run cleanup_exit() code.
-        */
-       restore_uid();
-
-       switch ((pid = fork())) {
-       case -1: /* error */
-               error("%s: fork: %s", tag, strerror(errno));
-               close(p[0]);
-               close(p[1]);
-               return 0;
-       case 0: /* child */
-               /* Prepare a minimal environment for the child. */
-               envsize = 5;
-               child_env = xcalloc(sizeof(*child_env), envsize);
-               child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
-               child_set_env(&child_env, &envsize, "USER", pw->pw_name);
-               child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
-               child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
-               if ((cp = getenv("LANG")) != NULL)
-                       child_set_env(&child_env, &envsize, "LANG", cp);
-
-               for (i = 0; i < NSIG; i++)
-                       signal(i, SIG_DFL);
-
-               if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
-                       error("%s: open %s: %s", tag, _PATH_DEVNULL,
-                           strerror(errno));
-                       _exit(1);
-               }
-               /* Keep stderr around a while longer to catch errors */
-               if (dup2(devnull, STDIN_FILENO) == -1 ||
-                   dup2(p[1], STDOUT_FILENO) == -1) {
-                       error("%s: dup2: %s", tag, strerror(errno));
-                       _exit(1);
-               }
-               closefrom(STDERR_FILENO + 1);
-
-               /* Don't use permanently_set_uid() here to avoid fatal() */
-               if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
-                       error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
-                           strerror(errno));
-                       _exit(1);
-               }
-               if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
-                       error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
-                           strerror(errno));
-                       _exit(1);
-               }
-               /* stdin is pointed to /dev/null at this point */
-               if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
-                       error("%s: dup2: %s", tag, strerror(errno));
-                       _exit(1);
-               }
-
-               execve(av[0], av, child_env);
-               error("%s exec \"%s\": %s", tag, command, strerror(errno));
-               _exit(127);
-       default: /* parent */
-               break;
-       }
-
-       close(p[1]);
-       if ((f = fdopen(p[0], "r")) == NULL) {
-               error("%s: fdopen: %s", tag, strerror(errno));
-               close(p[0]);
-               /* Don't leave zombie child */
-               kill(pid, SIGTERM);
-               while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
-                       ;
-               return 0;
-       }
-       /* Success */
-       debug3("%s: %s pid %ld", __func__, tag, (long)pid);
-       *child = f;
-       return pid;
-}
-
-/* Returns 0 if pid exited cleanly, non-zero otherwise */
-static int
-exited_cleanly(pid_t pid, const char *tag, const char *cmd)
-{
-       int status;
-
-       while (waitpid(pid, &status, 0) == -1) {
-               if (errno != EINTR) {
-                       error("%s: waitpid: %s", tag, strerror(errno));
-                       return -1;
-               }
-       }
-       if (WIFSIGNALED(status)) {
-               error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
-               return -1;
-       } else if (WEXITSTATUS(status) != 0) {
-               error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
-               return -1;
-       }
-       return 0;
-}
-
 static int
 match_principals_option(const char *principal_list, struct sshkey_cert *cert)
 {
@@ -559,14 +262,17 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
 }
 
 static int
-process_principals(FILE *f, char *file, struct passwd *pw,
-    struct sshkey_cert *cert)
+process_principals(FILE *f, const char *file, struct passwd *pw,
+    const struct sshkey_cert *cert)
 {
        char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
        u_long linenum = 0;
-       u_int i;
+       u_int i, found_principal = 0;
 
        while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+               /* Always consume entire input */
+               if (found_principal)
+                       continue;
                /* Skip leading whitespace. */
                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                        ;
@@ -594,16 +300,16 @@ process_principals(FILE *f, char *file, struct passwd *pw,
                for (i = 0; i < cert->nprincipals; i++) {
                        if (strcmp(cp, cert->principals[i]) == 0) {
                                debug3("%s:%lu: matched principal \"%.100s\"",
-                                   file == NULL ? "(command)" : file,
-                                   linenum, cert->principals[i]);
+                                   file, linenum, cert->principals[i]);
                                if (auth_parse_options(pw, line_opts,
                                    file, linenum) != 1)
                                        continue;
-                               return 1;
+                               found_principal = 1;
+                               continue;
                        }
                }
        }
-       return 0;
+       return found_principal;
 }
 
 static int
@@ -629,14 +335,17 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
  * returns 1 if the principal is allowed or 0 otherwise.
  */
 static int
-match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
+match_principals_command(struct passwd *user_pw, const struct sshkey *key)
 {
+       const struct sshkey_cert *cert = key->cert;
        FILE *f = NULL;
-       int ok, found_principal = 0;
+       int r, ok, found_principal = 0;
        struct passwd *pw;
        int i, ac = 0, uid_swapped = 0;
        pid_t pid;
        char *tmp, *username = NULL, *command = NULL, **av = NULL;
+       char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
+       char serial_s[16];
        void (*osigchld)(int);
 
        if (options.authorized_principals_command == NULL)
@@ -664,7 +373,7 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
        }
 
        /* Turn the command into an argument vector */
-       if (split_argv(options.authorized_principals_command, &ac, &av) != 0) {
+       if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
                error("AuthorizedPrincipalsCommand \"%s\" contains "
                    "invalid quotes", command);
                goto out;
@@ -674,10 +383,38 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
                    command);
                goto out;
        }
+       if ((ca_fp = sshkey_fingerprint(cert->signature_key,
+           options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
+               error("%s: sshkey_fingerprint failed", __func__);
+               goto out;
+       }
+       if ((key_fp = sshkey_fingerprint(key,
+           options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
+               error("%s: sshkey_fingerprint failed", __func__);
+               goto out;
+       }
+       if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
+               error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
+               goto out;
+       }
+       if ((r = sshkey_to_base64(key, &keytext)) != 0) {
+               error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
+               goto out;
+       }
+       snprintf(serial_s, sizeof(serial_s), "%llu",
+           (unsigned long long)cert->serial);
        for (i = 1; i < ac; i++) {
                tmp = percent_expand(av[i],
                    "u", user_pw->pw_name,
                    "h", user_pw->pw_dir,
+                   "t", sshkey_ssh_name(key),
+                   "T", sshkey_ssh_name(cert->signature_key),
+                   "f", key_fp,
+                   "F", ca_fp,
+                   "k", keytext,
+                   "K", catext,
+                   "i", cert->key_id,
+                   "s", serial_s,
                    (char *)NULL);
                if (tmp == NULL)
                        fatal("%s: percent_expand failed", __func__);
@@ -685,18 +422,22 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
                av[i] = tmp;
        }
        /* Prepare a printable command for logs, etc. */
-       command = assemble_argv(ac, av);
+       command = argv_assemble(ac, av);
 
        if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
-           ac, av, &f)) == 0)
+           ac, av, &f,
+           SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
                goto out;
 
        uid_swapped = 1;
        temporarily_use_uid(pw);
 
-       ok = process_principals(f, NULL, pw, cert);
+       ok = process_principals(f, "(command)", pw, cert);
 
-       if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0)
+       fclose(f);
+       f = NULL;
+
+       if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
                goto out;
 
        /* Read completed successfully */
@@ -712,6 +453,10 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
                restore_uid();
        free(command);
        free(username);
+       free(ca_fp);
+       free(key_fp);
+       free(catext);
+       free(keytext);
        return found_principal;
 }
 /*
@@ -719,23 +464,25 @@ match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
  * returns 1 if the key is allowed or 0 otherwise.
  */
 static int
-check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
+check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
 {
        char line[SSH_MAX_PUBKEY_BYTES];
-       const char *reason;
        int found_key = 0;
        u_long linenum = 0;
-       Key *found;
-       char *fp;
-
-       found_key = 0;
+       struct sshkey *found = NULL;
 
-       found = NULL;
        while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
-               char *cp, *key_options = NULL;
+               char *cp, *key_options = NULL, *fp = NULL;
+               const char *reason = NULL;
+
+               /* Always consume entire file */
+               if (found_key)
+                       continue;
                if (found != NULL)
-                       key_free(found);
-               found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
+                       sshkey_free(found);
+               found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
+               if (found == NULL)
+                       goto done;
                auth_clear_options();
 
                /* Skip leading whitespace, empty and comment lines. */
@@ -744,7 +491,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                if (!*cp || *cp == '\n' || *cp == '#')
                        continue;
 
-               if (key_read(found, &cp) != 1) {
+               if (sshkey_read(found, &cp) != 0) {
                        /* no key?  check if there are options for this key */
                        int quoted = 0;
                        debug2("user_key_allowed: check options: '%s'", cp);
@@ -758,14 +505,14 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                        /* Skip remaining whitespace. */
                        for (; *cp == ' ' || *cp == '\t'; cp++)
                                ;
-                       if (key_read(found, &cp) != 1) {
+                       if (sshkey_read(found, &cp) != 0) {
                                debug2("user_key_allowed: advance: '%s'", cp);
                                /* still no key?  advance to next line*/
                                continue;
                        }
                }
-               if (key_is_cert(key)) {
-                       if (!key_equal(found, key->cert->signature_key))
+               if (sshkey_is_cert(key)) {
+                       if (!sshkey_equal(found, key->cert->signature_key))
                                continue;
                        if (auth_parse_options(pw, key_options, file,
                            linenum) != 1)
@@ -776,7 +523,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                            options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
                                continue;
                        debug("matching CA found: file %s, line %lu, %s %s",
-                           file, linenum, key_type(found), fp);
+                           file, linenum, sshkey_type(found), fp);
                        /*
                         * If the user has specified a list of principals as
                         * a key option, then prefer that list to matching
@@ -793,22 +540,20 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                                auth_debug_add("%s", reason);
                                continue;
                        }
-                       if (key_cert_check_authority(key, 0, 0,
+                       if (sshkey_cert_check_authority(key, 0, 0,
                            authorized_principals == NULL ? pw->pw_name : NULL,
                            &reason) != 0)
                                goto fail_reason;
-                       if (auth_cert_options(key, pw) != 0) {
-                               free(fp);
-                               continue;
-                       }
+                       if (auth_cert_options(key, pw, &reason) != 0)
+                               goto fail_reason;
                        verbose("Accepted certificate ID \"%s\" (serial %llu) "
                            "signed by %s CA %s via %s", key->cert->key_id,
                            (unsigned long long)key->cert->serial,
-                           key_type(found), fp, file);
+                           sshkey_type(found), fp, file);
                        free(fp);
                        found_key = 1;
                        break;
-               } else if (key_equal(found, key)) {
+               } else if (sshkey_equal(found, key)) {
                        if (auth_parse_options(pw, key_options, file,
                            linenum) != 1)
                                continue;
@@ -818,14 +563,15 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                            options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
                                continue;
                        debug("matching key found: file %s, line %lu %s %s",
-                           file, linenum, key_type(found), fp);
+                           file, linenum, sshkey_type(found), fp);
                        free(fp);
                        found_key = 1;
-                       break;
+                       continue;
                }
        }
+ done:
        if (found != NULL)
-               key_free(found);
+               sshkey_free(found);
        if (!found_key)
                debug2("key not found");
        return found_key;
@@ -833,24 +579,24 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
 
 /* Authenticate a certificate key against TrustedUserCAKeys */
 static int
-user_cert_trusted_ca(struct passwd *pw, Key *key)
+user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
 {
        char *ca_fp, *principals_file = NULL;
        const char *reason;
-       int ret = 0, found_principal = 0, use_authorized_principals;
+       int r, ret = 0, found_principal = 0, use_authorized_principals;
 
-       if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
+       if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
                return 0;
 
        if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
            options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
                return 0;
 
-       if (sshkey_in_file(key->cert->signature_key,
-           options.trusted_user_ca_keys, 1, 0) != 0) {
-               debug2("%s: CA %s %s is not listed in %s", __func__,
-                   key_type(key->cert->signature_key), ca_fp,
-                   options.trusted_user_ca_keys);
+       if ((r = sshkey_in_file(key->cert->signature_key,
+           options.trusted_user_ca_keys, 1, 0)) != 0) {
+               debug2("%s: CA %s %s is not listed in %s: %s", __func__,
+                   sshkey_type(key->cert->signature_key), ca_fp,
+                   options.trusted_user_ca_keys, ssh_err(r));
                goto out;
        }
        /*
@@ -863,7 +609,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
                        found_principal = 1;
        }
        /* Try querying command if specified */
-       if (!found_principal && match_principals_command(pw, key->cert))
+       if (!found_principal && match_principals_command(pw, key))
                found_principal = 1;
        /* If principals file or command is specified, then require a match */
        use_authorized_principals = principals_file != NULL ||
@@ -875,16 +621,16 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
                auth_debug_add("%s", reason);
                goto out;
        }
-       if (key_cert_check_authority(key, 0, 1,
+       if (sshkey_cert_check_authority(key, 0, 1,
            use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
                goto fail_reason;
-       if (auth_cert_options(key, pw) != 0)
-               goto out;
+       if (auth_cert_options(key, pw, &reason) != 0)
+               goto fail_reason;
 
        verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
            "%s CA %s via %s", key->cert->key_id,
            (unsigned long long)key->cert->serial,
-           key_type(key->cert->signature_key), ca_fp,
+           sshkey_type(key->cert->signature_key), ca_fp,
            options.trusted_user_ca_keys);
        ret = 1;
 
@@ -899,7 +645,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
  * returns 1 if the key is allowed or 0 otherwise.
  */
 static int
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
+user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
 {
        FILE *f;
        int found_key = 0;
@@ -922,7 +668,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
  * returns 1 if the key is allowed or 0 otherwise.
  */
 static int
-user_key_command_allowed2(struct passwd *user_pw, Key *key)
+user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
 {
        FILE *f = NULL;
        int r, ok, found_key = 0;
@@ -968,7 +714,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
        }
 
        /* Turn the command into an argument vector */
-       if (split_argv(options.authorized_keys_command, &ac, &av) != 0) {
+       if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
                error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
                    command);
                goto out;
@@ -992,7 +738,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
                av[i] = tmp;
        }
        /* Prepare a printable command for logs, etc. */
-       command = assemble_argv(ac, av);
+       command = argv_assemble(ac, av);
 
        /*
         * If AuthorizedKeysCommand was run without arguments
@@ -1009,7 +755,8 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
        }
 
        if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
-           ac, av, &f)) == 0)
+           ac, av, &f,
+           SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
                goto out;
 
        uid_swapped = 1;
@@ -1017,7 +764,10 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
 
        ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
 
-       if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0)
+       fclose(f);
+       f = NULL;
+
+       if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
                goto out;
 
        /* Read completed successfully */
@@ -1042,14 +792,15 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
  * Check whether key authenticates and authorises the user.
  */
 int
-user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
+user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
 {
        u_int success, i;
        char *file;
 
        if (auth_key_is_revoked(key))
                return 0;
-       if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
+       if (sshkey_is_cert(key) &&
+           auth_key_is_revoked(key->cert->signature_key))
                return 0;
 
        success = user_cert_trusted_ca(pw, key);
@@ -1074,35 +825,6 @@ user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
        return success;
 }
 
-/* Records a public key in the list of previously-successful keys */
-void
-auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
-{
-       struct sshkey **tmp;
-
-       if (authctxt->nprev_userkeys >= INT_MAX ||
-           (tmp = reallocarray(authctxt->prev_userkeys,
-           authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
-               fatal("%s: reallocarray failed", __func__);
-       authctxt->prev_userkeys = tmp;
-       authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
-       authctxt->nprev_userkeys++;
-}
-
-/* Checks whether a key has already been used successfully for authentication */
-int
-auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
-{
-       u_int i;
-
-       for (i = 0; i < authctxt->nprev_userkeys; i++) {
-               if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-
 Authmethod method_pubkey = {
        "publickey",
        userauth_pubkey,
index 1d8faa7..862e099 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2.c,v 1.136 2016/05/02 08:49:03 djm Exp $ */
+/* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -30,6 +30,7 @@
 #include <sys/uio.h>
 
 #include <fcntl.h>
+#include <limits.h>
 #include <pwd.h>
 #include <stdarg.h>
 #include <string.h>
 #include "dispatch.h"
 #include "pathnames.h"
 #include "buffer.h"
-#include "canohost.h"
 
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "ssherr.h"
 
 /* import */
 extern ServerOptions options;
@@ -88,8 +89,8 @@ Authmethod *authmethods[] = {
 
 /* protocol */
 
-static int input_service_request(int, u_int32_t, void *);
-static int input_userauth_request(int, u_int32_t, void *);
+static int input_service_request(int, u_int32_t, struct ssh *);
+static int input_userauth_request(int, u_int32_t, struct ssh *);
 
 /* helper */
 static Authmethod *authmethod_lookup(Authctxt *, const char *);
@@ -169,16 +170,19 @@ done:
 void
 do_authentication2(Authctxt *authctxt)
 {
-       dispatch_init(&dispatch_protocol_error);
-       dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
-       dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
+       struct ssh *ssh = active_state;         /* XXX */
+       ssh->authctxt = authctxt;               /* XXX move to caller */
+       ssh_dispatch_init(ssh, &dispatch_protocol_error);
+       ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
+       ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
+       ssh->authctxt = NULL;
 }
 
 /*ARGSUSED*/
 static int
-input_service_request(int type, u_int32_t seq, void *ctxt)
+input_service_request(int type, u_int32_t seq, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        u_int len;
        int acceptit = 0;
        char *service = packet_get_cstring(&len);
@@ -191,7 +195,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
                if (!authctxt->success) {
                        acceptit = 1;
                        /* now we can handle user-auth requests */
-                       dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
+                       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
                }
        }
        /* XXX all other service requests are denied */
@@ -211,9 +215,9 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
 
 /*ARGSUSED*/
 static int
-input_userauth_request(int type, u_int32_t seq, void *ctxt)
+input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
 {
-       Authctxt *authctxt = ctxt;
+       Authctxt *authctxt = ssh->authctxt;
        Authmethod *m = NULL;
        char *user, *service, *method, *style = NULL;
        int authenticated = 0;
@@ -236,9 +240,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                authctxt->user = xstrdup(user);
                if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
                        authctxt->valid = 1;
-                       debug2("input_userauth_request: setting up authctxt for %s", user);
+                       debug2("%s: setting up authctxt for %s",
+                           __func__, user);
                } else {
-                       logit("input_userauth_request: invalid user %s", user);
+                       /* Invalid user, fake password information */
                        authctxt->pw = fakepw();
 #ifdef SSH_AUDIT_EVENTS
                        PRIVSEP(audit_event(SSH_INVALID_USER));
@@ -248,6 +253,8 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                if (options.use_pam)
                        PRIVSEP(start_pam(authctxt));
 #endif
+               ssh_packet_set_log_preamble(ssh, "%suser %s",
+                   authctxt->valid ? "authenticating " : "invalid ", user);
                setproctitle("%s%s", authctxt->valid ? user : "unknown",
                    use_privsep ? " [net]" : "");
                authctxt->service = xstrdup(service);
@@ -264,14 +271,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                    authctxt->user, authctxt->service, user, service);
        }
        /* reset state */
-       auth2_challenge_stop(authctxt);
+       auth2_challenge_stop(ssh);
 
 #ifdef GSSAPI
        /* XXX move to auth2_gssapi_stop() */
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
 #endif
 
+       auth2_authctxt_reset_info(authctxt);
        authctxt->postponed = 0;
        authctxt->server_caused_failure = 0;
 
@@ -279,9 +287,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
        m = authmethod_lookup(authctxt, method);
        if (m != NULL && authctxt->failures < options.max_authtries) {
                debug2("input_userauth_request: try method %s", method);
-               authenticated = m->userauth(authctxt);
+               authenticated = m->userauth(ssh);
        }
-       userauth_finish(authctxt, authenticated, method, NULL);
+       userauth_finish(ssh, authenticated, method, NULL);
 
        free(service);
        free(user);
@@ -290,9 +298,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 }
 
 void
-userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
+userauth_finish(struct ssh *ssh, int authenticated, const char *method,
     const char *submethod)
 {
+       Authctxt *authctxt = ssh->authctxt;
        char *methods;
        int partial = 0;
 
@@ -321,6 +330,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
        /* Log before sending the reply */
        auth_log(authctxt, authenticated, partial, method, submethod);
 
+       /* Update information exposed to session */
+       if (authenticated || partial)
+               auth2_update_session_info(authctxt, method, submethod);
+
        if (authctxt->postponed)
                return;
 
@@ -348,12 +361,13 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
 
        if (authenticated == 1) {
                /* turn off userauth */
-               dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
+               ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
                packet_send();
                packet_write_wait();
                /* now we can break out */
                authctxt->success = 1;
+               ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user);
        } else {
 
                /* Allow initial try of "none" auth without failure penalty */
@@ -617,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
        return 0;
 }
 
+/* Reset method-specific information */
+void auth2_authctxt_reset_info(Authctxt *authctxt)
+{
+       sshkey_free(authctxt->auth_method_key);
+       free(authctxt->auth_method_info);
+       authctxt->auth_method_key = NULL;
+       authctxt->auth_method_info = NULL;
+}
+
+/* Record auth method-specific information for logs */
+void
+auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
+{
+       va_list ap;
+        int i;
+
+       free(authctxt->auth_method_info);
+       authctxt->auth_method_info = NULL;
+
+       va_start(ap, fmt);
+       i = vasprintf(&authctxt->auth_method_info, fmt, ap);
+       va_end(ap);
+
+       if (i < 0 || authctxt->auth_method_info == NULL)
+               fatal("%s: vasprintf failed", __func__);
+}
+
+/*
+ * Records a public key used in authentication. This is used for logging
+ * and to ensure that the same key is not subsequently accepted again for
+ * multiple authentication.
+ */
+void
+auth2_record_key(Authctxt *authctxt, int authenticated,
+    const struct sshkey *key)
+{
+       struct sshkey **tmp, *dup;
+       int r;
+
+       if ((r = sshkey_demote(key, &dup)) != 0)
+               fatal("%s: copy key: %s", __func__, ssh_err(r));
+       sshkey_free(authctxt->auth_method_key);
+       authctxt->auth_method_key = dup;
+
+       if (!authenticated)
+               return;
+
+       /* If authenticated, make sure we don't accept this key again */
+       if ((r = sshkey_demote(key, &dup)) != 0)
+               fatal("%s: copy key: %s", __func__, ssh_err(r));
+       if (authctxt->nprev_keys >= INT_MAX ||
+           (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
+           authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
+               fatal("%s: reallocarray failed", __func__);
+       authctxt->prev_keys = tmp;
+       authctxt->prev_keys[authctxt->nprev_keys] = dup;
+       authctxt->nprev_keys++;
+
+}
+
+/* Checks whether a key has already been previously used for authentication */
+int
+auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
+{
+       u_int i;
+       char *fp;
+
+       for (i = 0; i < authctxt->nprev_keys; i++) {
+               if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
+                       fp = sshkey_fingerprint(authctxt->prev_keys[i],
+                           options.fingerprint_hash, SSH_FP_DEFAULT);
+                       debug3("%s: key already used: %s %s", __func__,
+                           sshkey_type(authctxt->prev_keys[i]),
+                           fp == NULL ? "UNKNOWN" : fp);
+                       free(fp);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Updates authctxt->session_info with details of authentication. Should be
+ * whenever an authentication method succeeds.
+ */
+void
+auth2_update_session_info(Authctxt *authctxt, const char *method,
+    const char *submethod)
+{
+       int r;
+
+       if (authctxt->session_info == NULL) {
+               if ((authctxt->session_info = sshbuf_new()) == NULL)
+                       fatal("%s: sshbuf_new", __func__);
+       }
+
+       /* Append method[/submethod] */
+       if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
+           method, submethod == NULL ? "" : "/",
+           submethod == NULL ? "" : submethod)) != 0)
+               fatal("%s: append method: %s", __func__, ssh_err(r));
+
+       /* Append key if present */
+       if (authctxt->auth_method_key != NULL) {
+               if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+                   (r = sshkey_format_text(authctxt->auth_method_key,
+                   authctxt->session_info)) != 0)
+                       fatal("%s: append key: %s", __func__, ssh_err(r));
+       }
+
+       if (authctxt->auth_method_info != NULL) {
+               /* Ensure no ambiguity here */
+               if (strchr(authctxt->auth_method_info, '\n') != NULL)
+                       fatal("%s: auth_method_info contains \\n", __func__);
+               if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
+                   (r = sshbuf_putf(authctxt->session_info, "%s",
+                   authctxt->auth_method_info)) != 0) {
+                       fatal("%s: append method info: %s",
+                           __func__, ssh_err(r));
+               }
+       }
+       if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
+               fatal("%s: append: %s", __func__, ssh_err(r));
+}
 
index a634bcb..a460fa3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfd.c,v 1.100 2015/12/04 16:41:28 markus Exp $ */
+/* $OpenBSD: authfd.c,v 1.105 2017/07/01 13:50:45 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -51,7 +51,6 @@
 
 #include "xmalloc.h"
 #include "ssh.h"
-#include "rsa.h"
 #include "sshbuf.h"
 #include "sshkey.h"
 #include "authfd.h"
@@ -199,43 +198,6 @@ ssh_lock_agent(int sock, int lock, const char *password)
        return r;
 }
 
-#ifdef WITH_SSH1
-static int
-deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
-{
-       struct sshkey *key;
-       int r, keybits;
-       u_int32_t bits;
-       char *comment = NULL;
-
-       if ((key = sshkey_new(KEY_RSA1)) == NULL)
-               return SSH_ERR_ALLOC_FAIL;
-       if ((r = sshbuf_get_u32(ids, &bits)) != 0 ||
-           (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 ||
-           (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 ||
-           (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
-               goto out;
-       keybits = BN_num_bits(key->rsa->n);
-       /* XXX previously we just warned here. I think we should be strict */
-       if (keybits < 0 || bits != (u_int)keybits) {
-               r = SSH_ERR_KEY_BITS_MISMATCH;
-               goto out;
-       }
-       if (keyp != NULL) {
-               *keyp = key;
-               key = NULL;
-       }
-       if (commentp != NULL) {
-               *commentp = comment;
-               comment = NULL;
-       }
-       r = 0;
- out:
-       sshkey_free(key);
-       free(comment);
-       return r;
-}
-#endif
 
 static int
 deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
@@ -264,35 +226,21 @@ deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
  * Fetch list of identities held by the agent.
  */
 int
-ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
+ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp)
 {
-       u_char type, code1 = 0, code2 = 0;
+       u_char type;
        u_int32_t num, i;
        struct sshbuf *msg;
        struct ssh_identitylist *idl = NULL;
        int r;
 
-       /* Determine request and expected response types */
-       switch (version) {
-       case 1:
-               code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
-               code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
-               break;
-       case 2:
-               code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
-               code2 = SSH2_AGENT_IDENTITIES_ANSWER;
-               break;
-       default:
-               return SSH_ERR_INVALID_ARGUMENT;
-       }
-
        /*
         * Send a message to the agent requesting for a list of the
         * identities it can represent.
         */
        if ((msg = sshbuf_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
-       if ((r = sshbuf_put_u8(msg, code1)) != 0)
+       if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REQUEST_IDENTITIES)) != 0)
                goto out;
 
        if ((r = ssh_request_reply(sock, msg, msg)) != 0)
@@ -304,7 +252,7 @@ ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
        if (agent_failed(type)) {
                r = SSH_ERR_AGENT_FAILURE;
                goto out;
-       } else if (type != code2) {
+       } else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
                r = SSH_ERR_INVALID_FORMAT;
                goto out;
        }
@@ -329,25 +277,14 @@ ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
                goto out;
        }
        for (i = 0; i < num;) {
-               switch (version) {
-               case 1:
-#ifdef WITH_SSH1
-                       if ((r = deserialise_identity1(msg,
-                           &(idl->keys[i]), &(idl->comments[i]))) != 0)
+               if ((r = deserialise_identity2(msg, &(idl->keys[i]),
+                   &(idl->comments[i]))) != 0) {
+                       if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
+                               /* Gracefully skip unknown key types */
+                               num--;
+                               continue;
+                       } else
                                goto out;
-#endif
-                       break;
-               case 2:
-                       if ((r = deserialise_identity2(msg,
-                           &(idl->keys[i]), &(idl->comments[i]))) != 0) {
-                               if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
-                                       /* Gracefully skip unknown key types */
-                                       num--;
-                                       continue;
-                               } else
-                                       goto out;
-                       }
-                       break;
                }
                i++;
        }
@@ -385,50 +322,10 @@ ssh_free_identitylist(struct ssh_identitylist *idl)
  * otherwise.
  */
 
-#ifdef WITH_SSH1
-int
-ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
-    u_char session_id[16], u_char response[16])
-{
-       struct sshbuf *msg;
-       int r;
-       u_char type;
-
-       if (key->type != KEY_RSA1)
-               return SSH_ERR_INVALID_ARGUMENT;
-       if ((msg = sshbuf_new()) == NULL)
-               return SSH_ERR_ALLOC_FAIL;
-       if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 ||
-           (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
-           (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
-           (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 ||
-           (r = sshbuf_put_bignum1(msg, challenge)) != 0 ||
-           (r = sshbuf_put(msg, session_id, 16)) != 0 ||
-           (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */
-               goto out;
-       if ((r = ssh_request_reply(sock, msg, msg)) != 0)
-               goto out;
-       if ((r = sshbuf_get_u8(msg, &type)) != 0)
-               goto out;
-       if (agent_failed(type)) {
-               r = SSH_ERR_AGENT_FAILURE;
-               goto out;
-       } else if (type != SSH_AGENT_RSA_RESPONSE) {
-               r = SSH_ERR_INVALID_FORMAT;
-               goto out;
-       }
-       if ((r = sshbuf_get(msg, response, 16)) != 0)
-               goto out;
-       r = 0;
- out:
-       sshbuf_free(msg);
-       return r;
-}
-#endif
 
 /* encode signature algoritm in flag bits, so we can keep the msg format */
 static u_int
-agent_encode_alg(struct sshkey *key, const char *alg)
+agent_encode_alg(const struct sshkey *key, const char *alg)
 {
        if (alg != NULL && key->type == KEY_RSA) {
                if (strcmp(alg, "rsa-sha2-256") == 0)
@@ -441,7 +338,7 @@ agent_encode_alg(struct sshkey *key, const char *alg)
 
 /* ask agent to sign data, returns err.h code on error, 0 on success */
 int
-ssh_agent_sign(int sock, struct sshkey *key,
+ssh_agent_sign(int sock, const struct sshkey *key,
     u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, const char *alg, u_int compat)
 {
@@ -494,25 +391,6 @@ ssh_agent_sign(int sock, struct sshkey *key,
 
 /* Encode key for a message to the agent. */
 
-#ifdef WITH_SSH1
-static int
-ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment)
-{
-       int r;
-
-       /* To keep within the protocol: p < q for ssh. in SSL p > q */
-       if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->n)) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->e)) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->d)) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->q)) != 0 ||
-           (r = sshbuf_put_bignum1(b, key->p)) != 0 ||
-           (r = sshbuf_put_cstring(b, comment)) != 0)
-               return r;
-       return 0;
-}
-#endif
 
 static int
 ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key,
@@ -561,16 +439,6 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment,
                return SSH_ERR_ALLOC_FAIL;
 
        switch (key->type) {
-#ifdef WITH_SSH1
-       case KEY_RSA1:
-               type = constrained ?
-                   SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
-                   SSH_AGENTC_ADD_RSA_IDENTITY;
-               if ((r = sshbuf_put_u8(msg, type)) != 0 ||
-                   (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0)
-                       goto out;
-               break;
-#endif
 #ifdef WITH_OPENSSL
        case KEY_RSA:
        case KEY_RSA_CERT:
@@ -620,16 +488,6 @@ ssh_remove_identity(int sock, struct sshkey *key)
        if ((msg = sshbuf_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
 
-#ifdef WITH_SSH1
-       if (key->type == KEY_RSA1) {
-               if ((r = sshbuf_put_u8(msg,
-                   SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 ||
-                   (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
-                   (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
-                   (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0)
-                       goto out;
-       } else
-#endif
        if (key->type != KEY_UNSPEC) {
                if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
                        goto out;
@@ -696,6 +554,10 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
 /*
  * Removes all identities from the agent.
  * This call is intended only for use by ssh-add(1) and like applications.
+ *
+ * This supports the SSH protocol 1 message to because, when clearing all
+ * keys from an agent, we generally want to clear both protocol v1 and v2
+ * keys.
  */
 int
 ssh_remove_all_identities(int sock, int version)
index 4b417e3..43abf85 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfd.h,v 1.39 2015/12/04 16:41:28 markus Exp $ */
+/* $OpenBSD: authfd.h,v 1.41 2017/06/28 01:09:22 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -27,8 +27,7 @@ int   ssh_get_authentication_socket(int *fdp);
 void   ssh_close_authentication_socket(int sock);
 
 int    ssh_lock_agent(int sock, int lock, const char *password);
-int    ssh_fetch_identitylist(int sock, int version,
-           struct ssh_identitylist **idlp);
+int    ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
 void   ssh_free_identitylist(struct ssh_identitylist *idl);
 int    ssh_add_identity_constrained(int sock, struct sshkey *key,
            const char *comment, u_int life, u_int confirm);
@@ -39,7 +38,7 @@ int   ssh_remove_all_identities(int sock, int version);
 
 int    ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
            u_char session_id[16], u_char response[16]);
-int    ssh_agent_sign(int sock, struct sshkey *key,
+int    ssh_agent_sign(int sock, const struct sshkey *key,
            u_char **sigp, size_t *lenp,
            const u_char *data, size_t datalen, const char *alg, u_int compat);
 
index f46b4e3..d09b700 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfile.c,v 1.121 2016/04/09 12:39:30 djm Exp $ */
+/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
 /*
  * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
  *
@@ -42,7 +42,6 @@
 #include "ssh.h"
 #include "log.h"
 #include "authfile.h"
-#include "rsa.h"
 #include "misc.h"
 #include "atomicio.h"
 #include "sshkey.h"
@@ -135,35 +134,6 @@ sshkey_load_file(int fd, struct sshbuf *blob)
        return r;
 }
 
-#ifdef WITH_SSH1
-/*
- * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
- * encountered (the file does not exist or is not readable), and the key
- * otherwise.
- */
-static int
-sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
-{
-       struct sshbuf *b = NULL;
-       int r;
-
-       if (keyp != NULL)
-               *keyp = NULL;
-       if (commentp != NULL)
-               *commentp = NULL;
-
-       if ((b = sshbuf_new()) == NULL)
-               return SSH_ERR_ALLOC_FAIL;
-       if ((r = sshkey_load_file(fd, b)) != 0)
-               goto out;
-       if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
-               goto out;
-       r = 0;
- out:
-       sshbuf_free(b);
-       return r;
-}
-#endif /* WITH_SSH1 */
 
 /* XXX remove error() calls from here? */
 int
@@ -333,75 +303,48 @@ sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
        return SSH_ERR_INVALID_FORMAT;
 }
 
-/* load public key from ssh v1 private or any pubkey file */
+/* load public key from any pubkey file */
 int
 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
 {
        struct sshkey *pub = NULL;
-       char file[PATH_MAX];
-       int r, fd;
+       char *file = NULL;
+       int r;
 
        if (keyp != NULL)
                *keyp = NULL;
        if (commentp != NULL)
                *commentp = NULL;
 
-       /* XXX should load file once and attempt to parse each format */
-
-       if ((fd = open(filename, O_RDONLY)) < 0)
-               goto skip;
-#ifdef WITH_SSH1
-       /* try rsa1 private key */
-       r = sshkey_load_public_rsa1(fd, keyp, commentp);
-       close(fd);
-       switch (r) {
-       case SSH_ERR_INTERNAL_ERROR:
-       case SSH_ERR_ALLOC_FAIL:
-       case SSH_ERR_INVALID_ARGUMENT:
-       case SSH_ERR_SYSTEM_ERROR:
-       case 0:
-               return r;
-       }
-#else /* WITH_SSH1 */
-       close(fd);
-#endif /* WITH_SSH1 */
-
-       /* try ssh2 public key */
        if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
                return SSH_ERR_ALLOC_FAIL;
        if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
-               if (keyp != NULL)
-                       *keyp = pub;
-               return 0;
-       }
-       sshkey_free(pub);
-
-#ifdef WITH_SSH1
-       /* try rsa1 public key */
-       if ((pub = sshkey_new(KEY_RSA1)) == NULL)
-               return SSH_ERR_ALLOC_FAIL;
-       if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
-               if (keyp != NULL)
+               if (keyp != NULL) {
                        *keyp = pub;
-               return 0;
+                       pub = NULL;
+               }
+               r = 0;
+               goto out;
        }
        sshkey_free(pub);
-#endif /* WITH_SSH1 */
 
- skip:
        /* try .pub suffix */
-       if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
+       if (asprintf(&file, "%s.pub", filename) == -1)
                return SSH_ERR_ALLOC_FAIL;
-       r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
-       if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
-           (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
-           (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
-               if (keyp != NULL)
+       if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
+               if (keyp != NULL) {
                        *keyp = pub;
-               return 0;
+                       pub = NULL;
+               }
+               r = 0;
        }
+ out:
+       free(file);
        sshkey_free(pub);
-
        return r;
 }
 
index f950322..5089b04 100644 (file)
@@ -53,8 +53,9 @@ void
 bitmap_free(struct bitmap *b)
 {
        if (b != NULL && b->d != NULL) {
-               explicit_bzero(b->d, b->len);
+               bitmap_zero(b);
                free(b->d);
+               b->d = NULL;
        }
        free(b);
 }
@@ -86,10 +87,10 @@ reserve(struct bitmap *b, u_int n)
                return -1; /* invalid */
        nlen = (n / BITMAP_BITS) + 1;
        if (b->len < nlen) {
-               if ((tmp = reallocarray(b->d, nlen, BITMAP_BYTES)) == NULL)
+               if ((tmp = recallocarray(b->d, b->len,
+                   nlen, BITMAP_BYTES)) == NULL)
                        return -1;
                b->d = tmp;
-               memset(b->d + b->len, 0, (nlen - b->len) * BITMAP_BYTES);
                b->len = nlen;
        }
        return 0;
@@ -188,7 +189,7 @@ bitmap_from_string(struct bitmap *b, const void *p, size_t l)
 {
        int r;
        size_t i, offset, shift;
-       u_char *s = (u_char *)p;
+       const u_char *s = (const u_char *)p;
 
        if (l > BITMAP_MAX / 8)
                return -1;
index 33ae7f7..98f9466 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */
+/* $OpenBSD: bufbn.c,v 1.13 2017/04/30 23:23:54 djm Exp $ */
 
 /*
  * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
 #include "log.h"
 #include "ssherr.h"
 
-#ifdef WITH_SSH1
-int
-buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
-{
-       int ret;
-
-       if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) {
-               error("%s: %s", __func__, ssh_err(ret));
-               return -1;
-       }
-       return 0;
-}
-
-void
-buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
-{
-       if (buffer_put_bignum_ret(buffer, value) == -1)
-               fatal("%s: buffer error", __func__);
-}
-
-int
-buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
-{
-       int ret;
-
-       if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) {
-               error("%s: %s", __func__, ssh_err(ret));
-               return -1;
-       }
-       return 0;
-}
-
-void
-buffer_get_bignum(Buffer *buffer, BIGNUM *value)
-{
-       if (buffer_get_bignum_ret(buffer, value) == -1)
-               fatal("%s: buffer error", __func__);
-}
-#endif /* WITH_SSH1 */
-
 int
 buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
 {
index df1aebc..5617439 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */
+/* $OpenBSD: buffer.h,v 1.26 2017/04/30 23:23:54 djm Exp $ */
 
 /*
  * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
@@ -49,9 +49,7 @@ int    buffer_consume_end_ret(Buffer *, u_int);
 
 #include <openssl/objects.h>
 #include <openssl/bn.h>
-void    buffer_put_bignum(Buffer *, const BIGNUM *);
 void    buffer_put_bignum2(Buffer *, const BIGNUM *);
-void   buffer_get_bignum(Buffer *, BIGNUM *);
 void   buffer_get_bignum2(Buffer *, BIGNUM *);
 void   buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
 
@@ -75,8 +73,6 @@ void  buffer_put_cstring(Buffer *, const char *);
 
 #define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL);
 
-int    buffer_put_bignum_ret(Buffer *, const BIGNUM *);
-int    buffer_get_bignum_ret(Buffer *, BIGNUM *);
 int    buffer_put_bignum2_ret(Buffer *, const BIGNUM *);
 int    buffer_get_bignum2_ret(Buffer *, BIGNUM *);
 int    buffer_get_short_ret(u_short *, Buffer *);
index 40eaf2d..7620525 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: chacha.h,v 1.3 2014/05/02 03:27:54 djm Exp $ */
+/* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */
 
 /*
 chacha-merged.c version 20080118
@@ -10,6 +10,7 @@ Public domain.
 #define CHACHA_H
 
 #include <sys/types.h>
+#include <stdlib.h>
 
 struct chacha_ctx {
        u_int input[16];
index 9f9e972..83442be 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.351 2016/07/19 11:38:53 dtucker Exp $ */
+/* $OpenBSD: channels.c,v 1.375 2017/09/24 13:45:34 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -42,7 +42,6 @@
 #include "includes.h"
 
 #include <sys/types.h>
-#include <sys/param.h> /* MIN MAX */
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/un.h>
 
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <netdb.h>
+#include <stdarg.h>
 #ifdef HAVE_STDINT_H
-#include <stdint.h>
+ #include <stdint.h>
 #endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <termios.h>
 #include <unistd.h>
-#include <stdarg.h>
 
 #include "openbsd-compat/sys-queue.h"
 #include "xmalloc.h"
 #include "ssh.h"
-#include "ssh1.h"
 #include "ssh2.h"
+#include "ssherr.h"
+#include "sshbuf.h"
 #include "packet.h"
 #include "log.h"
 #include "misc.h"
-#include "buffer.h"
 #include "channels.h"
 #include "compat.h"
 #include "canohost.h"
 #include "authfd.h"
 #include "pathnames.h"
 
-/* -- channel core */
-
-/*
- * Pointer to an array containing all allocated channels.  The array is
- * dynamically extended as needed.
- */
-static Channel **channels = NULL;
-
-/*
- * Size of the channel array.  All slots of the array must always be
- * initialized (at least the type field); unused slots set to NULL
- */
-static u_int channels_alloc = 0;
+/* -- agent forwarding */
+#define        NUM_SOCKS       10
 
-/*
- * Maximum file descriptor value used in any of the channels.  This is
- * updated in channel_new.
- */
-static int channel_max_fd = 0;
+/* -- tcp forwarding */
+/* special-case port number meaning allow any port */
+#define FWD_PERMIT_ANY_PORT    0
 
+/* special-case wildcard meaning allow any host */
+#define FWD_PERMIT_ANY_HOST    "*"
 
-/* -- tcp forwarding */
+/* -- X11 forwarding */
+/* Maximum number of fake X11 displays to try. */
+#define MAX_DISPLAYS  1000
 
 /*
  * Data structure for storing which hosts are permitted for forward requests.
@@ -121,119 +112,188 @@ typedef struct {
        char *listen_host;              /* Remote side should listen address. */
        char *listen_path;              /* Remote side should listen path. */
        int listen_port;                /* Remote side should listen port. */
+       Channel *downstream;            /* Downstream mux*/
 } ForwardPermission;
 
-/* List of all permitted host/port pairs to connect by the user. */
-static ForwardPermission *permitted_opens = NULL;
+typedef void chan_fn(struct ssh *, Channel *c,
+    fd_set *readset, fd_set *writeset);
 
-/* List of all permitted host/port pairs to connect by the admin. */
-static ForwardPermission *permitted_adm_opens = NULL;
-
-/* Number of permitted host/port pairs in the array permitted by the user. */
-static int num_permitted_opens = 0;
+/* Master structure for channels state */
+struct ssh_channels {
+       /*
+        * Pointer to an array containing all allocated channels.  The array
+        * is dynamically extended as needed.
+        */
+       Channel **channels;
 
-/* Number of permitted host/port pair in the array permitted by the admin. */
-static int num_adm_permitted_opens = 0;
+       /*
+        * Size of the channel array.  All slots of the array must always be
+        * initialized (at least the type field); unused slots set to NULL
+        */
+       u_int channels_alloc;
 
-/* special-case port number meaning allow any port */
-#define FWD_PERMIT_ANY_PORT    0
+       /*
+        * Maximum file descriptor value used in any of the channels.  This is
+        * updated in channel_new.
+        */
+       int channel_max_fd;
 
-/* special-case wildcard meaning allow any host */
-#define FWD_PERMIT_ANY_HOST    "*"
+       /*
+        * 'channel_pre*' are called just before select() to add any bits
+        * relevant to channels in the select bitmasks.
+        *
+        * 'channel_post*': perform any appropriate operations for
+        * channels which have events pending.
+        */
+       chan_fn **channel_pre;
+       chan_fn **channel_post;
 
-/*
- * If this is true, all opens are permitted.  This is the case on the server
- * on which we have to trust the client anyway, and the user could do
- * anything after logging in anyway.
- */
-static int all_opens_permitted = 0;
+       /* -- tcp forwarding */
 
+       /* List of all permitted host/port pairs to connect by the user. */
+       ForwardPermission *permitted_opens;
 
-/* -- X11 forwarding */
+       /* List of all permitted host/port pairs to connect by the admin. */
+       ForwardPermission *permitted_adm_opens;
 
-/* Maximum number of fake X11 displays to try. */
-#define MAX_DISPLAYS  1000
+       /*
+        * Number of permitted host/port pairs in the array permitted by
+        * the user.
+        */
+       u_int num_permitted_opens;
 
-/* Saved X11 local (client) display. */
-static char *x11_saved_display = NULL;
+       /*
+        * Number of permitted host/port pair in the array permitted by
+        * the admin.
+        */
+       u_int num_adm_permitted_opens;
 
-/* Saved X11 authentication protocol name. */
-static char *x11_saved_proto = NULL;
+       /*
+        * If this is true, all opens are permitted.  This is the case on
+        * the server on which we have to trust the client anyway, and the
+        * user could do anything after logging in anyway.
+        */
+       int all_opens_permitted;
 
-/* Saved X11 authentication data.  This is the real data. */
-static char *x11_saved_data = NULL;
-static u_int x11_saved_data_len = 0;
+       /* -- X11 forwarding */
 
-/* Deadline after which all X11 connections are refused */
-static u_int x11_refuse_time;
+       /* Saved X11 local (client) display. */
+       char *x11_saved_display;
 
-/*
- * Fake X11 authentication data.  This is what the server will be sending us;
- * we should replace any occurrences of this by the real data.
- */
-static u_char *x11_fake_data = NULL;
-static u_int x11_fake_data_len;
+       /* Saved X11 authentication protocol name. */
+       char *x11_saved_proto;
 
+       /* Saved X11 authentication data.  This is the real data. */
+       char *x11_saved_data;
+       u_int x11_saved_data_len;
 
-/* -- agent forwarding */
+       /* Deadline after which all X11 connections are refused */
+       u_int x11_refuse_time;
 
-#define        NUM_SOCKS       10
+       /*
+        * Fake X11 authentication data.  This is what the server will be
+        * sending us; we should replace any occurrences of this by the
+        * real data.
+        */
+       u_char *x11_fake_data;
+       u_int x11_fake_data_len;
 
-/* AF_UNSPEC or AF_INET or AF_INET6 */
-static int IPv4or6 = AF_UNSPEC;
+       /* AF_UNSPEC or AF_INET or AF_INET6 */
+       int IPv4or6;
+};
 
 /* helper */
-static void port_open_helper(Channel *c, char *rtype);
+static void port_open_helper(struct ssh *ssh, Channel *c, char *rtype);
+static const char *channel_rfwd_bind_host(const char *listen_host);
 
 /* non-blocking connect helpers */
 static int connect_next(struct channel_connect *);
 static void channel_connect_ctx_free(struct channel_connect *);
+static Channel *rdynamic_connect_prepare(struct ssh *, char *, char *);
+static int rdynamic_connect_finish(struct ssh *, Channel *);
+
+/* Setup helper */
+static void channel_handler_init(struct ssh_channels *sc);
 
 /* -- channel core */
 
+void
+channel_init_channels(struct ssh *ssh)
+{
+       struct ssh_channels *sc;
+
+       if ((sc = calloc(1, sizeof(*sc))) == NULL ||
+           (sc->channel_pre = calloc(SSH_CHANNEL_MAX_TYPE,
+           sizeof(*sc->channel_pre))) == NULL ||
+           (sc->channel_post = calloc(SSH_CHANNEL_MAX_TYPE,
+           sizeof(*sc->channel_post))) == NULL)
+               fatal("%s: allocation failed", __func__);
+       sc->channels_alloc = 10;
+       sc->channels = xcalloc(sc->channels_alloc, sizeof(*sc->channels));
+       sc->IPv4or6 = AF_UNSPEC;
+       channel_handler_init(sc);
+
+       ssh->chanctxt = sc;
+}
+
 Channel *
-channel_by_id(int id)
+channel_by_id(struct ssh *ssh, int id)
 {
        Channel *c;
 
-       if (id < 0 || (u_int)id >= channels_alloc) {
-               logit("channel_by_id: %d: bad id", id);
+       if (id < 0 || (u_int)id >= ssh->chanctxt->channels_alloc) {
+               logit("%s: %d: bad id", __func__, id);
                return NULL;
        }
-       c = channels[id];
+       c = ssh->chanctxt->channels[id];
        if (c == NULL) {
-               logit("channel_by_id: %d: bad id: channel free", id);
+               logit("%s: %d: bad id: channel free", __func__, id);
                return NULL;
        }
        return c;
 }
 
+Channel *
+channel_by_remote_id(struct ssh *ssh, u_int remote_id)
+{
+       Channel *c;
+       u_int i;
+
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
+               if (c != NULL && c->have_remote_id && c->remote_id == remote_id)
+                       return c;
+       }
+       return NULL;
+}
+
 /*
  * Returns the channel if it is allowed to receive protocol messages.
  * Private channels, like listening sockets, may not receive messages.
  */
 Channel *
-channel_lookup(int id)
+channel_lookup(struct ssh *ssh, int id)
 {
        Channel *c;
 
-       if ((c = channel_by_id(id)) == NULL)
-               return (NULL);
+       if ((c = channel_by_id(ssh, id)) == NULL)
+               return NULL;
 
        switch (c->type) {
        case SSH_CHANNEL_X11_OPEN:
        case SSH_CHANNEL_LARVAL:
        case SSH_CHANNEL_CONNECTING:
        case SSH_CHANNEL_DYNAMIC:
+       case SSH_CHANNEL_RDYNAMIC_OPEN:
+       case SSH_CHANNEL_RDYNAMIC_FINISH:
        case SSH_CHANNEL_OPENING:
        case SSH_CHANNEL_OPEN:
-       case SSH_CHANNEL_INPUT_DRAINING:
-       case SSH_CHANNEL_OUTPUT_DRAINING:
        case SSH_CHANNEL_ABANDONED:
-               return (c);
+       case SSH_CHANNEL_MUX_PROXY:
+               return c;
        }
        logit("Non-public channel %d, type %d.", id, c->type);
-       return (NULL);
+       return NULL;
 }
 
 /*
@@ -241,13 +301,15 @@ channel_lookup(int id)
  * when the channel consumer/producer is ready, e.g. shell exec'd
  */
 static void
-channel_register_fds(Channel *c, int rfd, int wfd, int efd,
+channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd,
     int extusage, int nonblock, int is_tty)
 {
+       struct ssh_channels *sc = ssh->chanctxt;
+
        /* Update the maximum file descriptor value. */
-       channel_max_fd = MAX(channel_max_fd, rfd);
-       channel_max_fd = MAX(channel_max_fd, wfd);
-       channel_max_fd = MAX(channel_max_fd, efd);
+       sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, rfd);
+       sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, wfd);
+       sc->channel_max_fd = MAXIMUM(sc->channel_max_fd, efd);
 
        if (rfd != -1)
                fcntl(rfd, F_SETFD, FD_CLOEXEC);
@@ -285,150 +347,220 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd,
  * remote_name to be freed.
  */
 Channel *
-channel_new(char *ctype, int type, int rfd, int wfd, int efd,
+channel_new(struct ssh *ssh, char *ctype, int type, int rfd, int wfd, int efd,
     u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock)
 {
-       int found;
-       u_int i;
+       struct ssh_channels *sc = ssh->chanctxt;
+       u_int i, found;
        Channel *c;
 
-       /* Do initial allocation if this is the first call. */
-       if (channels_alloc == 0) {
-               channels_alloc = 10;
-               channels = xcalloc(channels_alloc, sizeof(Channel *));
-               for (i = 0; i < channels_alloc; i++)
-                       channels[i] = NULL;
-       }
        /* Try to find a free slot where to put the new channel. */
-       for (found = -1, i = 0; i < channels_alloc; i++)
-               if (channels[i] == NULL) {
+       for (i = 0; i < sc->channels_alloc; i++) {
+               if (sc->channels[i] == NULL) {
                        /* Found a free slot. */
-                       found = (int)i;
+                       found = i;
                        break;
                }
-       if (found < 0) {
-               /* There are no free slots.  Take last+1 slot and expand the array.  */
-               found = channels_alloc;
-               if (channels_alloc > 10000)
-                       fatal("channel_new: internal error: channels_alloc %d "
-                           "too big.", channels_alloc);
-               channels = xreallocarray(channels, channels_alloc + 10,
-                   sizeof(Channel *));
-               channels_alloc += 10;
-               debug2("channel: expanding %d", channels_alloc);
-               for (i = found; i < channels_alloc; i++)
-                       channels[i] = NULL;
+       }
+       if (i >= sc->channels_alloc) {
+               /*
+                * There are no free slots. Take last+1 slot and expand
+                * the array.
+                */
+               found = sc->channels_alloc;
+               if (sc->channels_alloc > CHANNELS_MAX_CHANNELS)
+                       fatal("%s: internal error: channels_alloc %d too big",
+                           __func__, sc->channels_alloc);
+               sc->channels = xrecallocarray(sc->channels, sc->channels_alloc,
+                   sc->channels_alloc + 10, sizeof(*sc->channels));
+               sc->channels_alloc += 10;
+               debug2("channel: expanding %d", sc->channels_alloc);
        }
        /* Initialize and return new channel. */
-       c = channels[found] = xcalloc(1, sizeof(Channel));
-       buffer_init(&c->input);
-       buffer_init(&c->output);
-       buffer_init(&c->extended);
-       c->path = NULL;
-       c->listening_addr = NULL;
-       c->listening_port = 0;
+       c = sc->channels[found] = xcalloc(1, sizeof(Channel));
+       if ((c->input = sshbuf_new()) == NULL ||
+           (c->output = sshbuf_new()) == NULL ||
+           (c->extended = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
        c->ostate = CHAN_OUTPUT_OPEN;
        c->istate = CHAN_INPUT_OPEN;
-       c->flags = 0;
-       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, 0);
-       c->notbefore = 0;
+       channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, 0);
        c->self = found;
        c->type = type;
        c->ctype = ctype;
        c->local_window = window;
        c->local_window_max = window;
-       c->local_consumed = 0;
        c->local_maxpacket = maxpack;
-       c->remote_id = -1;
        c->remote_name = xstrdup(remote_name);
-       c->remote_window = 0;
-       c->remote_maxpacket = 0;
-       c->force_drain = 0;
-       c->single_connection = 0;
-       c->detach_user = NULL;
-       c->detach_close = 0;
-       c->open_confirm = NULL;
-       c->open_confirm_ctx = NULL;
-       c->input_filter = NULL;
-       c->output_filter = NULL;
-       c->filter_ctx = NULL;
-       c->filter_cleanup = NULL;
        c->ctl_chan = -1;
-       c->mux_rcb = NULL;
-       c->mux_ctx = NULL;
-       c->mux_pause = 0;
        c->delayed = 1;         /* prevent call to channel_post handler */
        TAILQ_INIT(&c->status_confirms);
        debug("channel %d: new [%s]", found, remote_name);
        return c;
 }
 
-static int
-channel_find_maxfd(void)
+static void
+channel_find_maxfd(struct ssh_channels *sc)
 {
        u_int i;
        int max = 0;
        Channel *c;
 
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
+       for (i = 0; i < sc->channels_alloc; i++) {
+               c = sc->channels[i];
                if (c != NULL) {
-                       max = MAX(max, c->rfd);
-                       max = MAX(max, c->wfd);
-                       max = MAX(max, c->efd);
+                       max = MAXIMUM(max, c->rfd);
+                       max = MAXIMUM(max, c->wfd);
+                       max = MAXIMUM(max, c->efd);
                }
        }
-       return max;
+       sc->channel_max_fd = max;
 }
 
 int
-channel_close_fd(int *fdp)
+channel_close_fd(struct ssh *ssh, int *fdp)
 {
+       struct ssh_channels *sc = ssh->chanctxt;
        int ret = 0, fd = *fdp;
 
        if (fd != -1) {
                ret = close(fd);
                *fdp = -1;
-               if (fd == channel_max_fd)
-                       channel_max_fd = channel_find_maxfd();
+               if (fd == sc->channel_max_fd)
+                       channel_find_maxfd(sc);
        }
        return ret;
 }
 
 /* Close all channel fd/socket. */
 static void
-channel_close_fds(Channel *c)
+channel_close_fds(struct ssh *ssh, Channel *c)
+{
+       channel_close_fd(ssh, &c->sock);
+       channel_close_fd(ssh, &c->rfd);
+       channel_close_fd(ssh, &c->wfd);
+       channel_close_fd(ssh, &c->efd);
+}
+
+static void
+fwd_perm_clear(ForwardPermission *fp)
+{
+       free(fp->host_to_connect);
+       free(fp->listen_host);
+       free(fp->listen_path);
+       bzero(fp, sizeof(*fp));
+}
+
+enum { FWDPERM_USER, FWDPERM_ADMIN };
+
+static int
+fwd_perm_list_add(struct ssh *ssh, int which,
+    const char *host_to_connect, int port_to_connect,
+    const char *listen_host, const char *listen_path, int listen_port,
+    Channel *downstream)
+{
+       ForwardPermission **fpl;
+       u_int n, *nfpl;
+
+       switch (which) {
+       case FWDPERM_USER:
+               fpl = &ssh->chanctxt->permitted_opens;
+               nfpl = &ssh->chanctxt->num_permitted_opens;
+               break;
+       case FWDPERM_ADMIN:
+               fpl = &ssh->chanctxt->permitted_adm_opens;
+               nfpl = &ssh->chanctxt->num_adm_permitted_opens;
+               break;
+       default:
+               fatal("%s: invalid list %d", __func__, which);
+       }
+
+       if (*nfpl >= INT_MAX)
+               fatal("%s: overflow", __func__);
+
+       *fpl = xrecallocarray(*fpl, *nfpl, *nfpl + 1, sizeof(**fpl));
+       n = (*nfpl)++;
+#define MAYBE_DUP(s) ((s == NULL) ? NULL : xstrdup(s))
+       (*fpl)[n].host_to_connect = MAYBE_DUP(host_to_connect);
+       (*fpl)[n].port_to_connect = port_to_connect;
+       (*fpl)[n].listen_host = MAYBE_DUP(listen_host);
+       (*fpl)[n].listen_path = MAYBE_DUP(listen_path);
+       (*fpl)[n].listen_port = listen_port;
+       (*fpl)[n].downstream = downstream;
+#undef MAYBE_DUP
+       return (int)n;
+}
+
+static void
+mux_remove_remote_forwardings(struct ssh *ssh, Channel *c)
 {
-       channel_close_fd(&c->sock);
-       channel_close_fd(&c->rfd);
-       channel_close_fd(&c->wfd);
-       channel_close_fd(&c->efd);
+       struct ssh_channels *sc = ssh->chanctxt;
+       ForwardPermission *fp;
+       int r;
+       u_int i;
+
+       for (i = 0; i < sc->num_permitted_opens; i++) {
+               fp = &sc->permitted_opens[i];
+               if (fp->downstream != c)
+                       continue;
+
+               /* cancel on the server, since mux client is gone */
+               debug("channel %d: cleanup remote forward for %s:%u",
+                   c->self, fp->listen_host, fp->listen_port);
+               if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
+                   (r = sshpkt_put_cstring(ssh,
+                   "cancel-tcpip-forward")) != 0 ||
+                   (r = sshpkt_put_u8(ssh, 0)) != 0 ||
+                   (r = sshpkt_put_cstring(ssh,
+                   channel_rfwd_bind_host(fp->listen_host))) != 0 ||
+                   (r = sshpkt_put_u32(ssh, fp->listen_port)) != 0 ||
+                   (r = sshpkt_send(ssh)) != 0) {
+                       fatal("%s: channel %i: %s", __func__,
+                           c->self, ssh_err(r));
+               }
+               fwd_perm_clear(fp); /* unregister */
+       }
 }
 
 /* Free the channel and close its fd/socket. */
 void
-channel_free(Channel *c)
+channel_free(struct ssh *ssh, Channel *c)
 {
+       struct ssh_channels *sc = ssh->chanctxt;
        char *s;
        u_int i, n;
+       Channel *other;
        struct channel_confirm *cc;
 
-       for (n = 0, i = 0; i < channels_alloc; i++)
-               if (channels[i])
-                       n++;
+       for (n = 0, i = 0; i < sc->channels_alloc; i++) {
+               if ((other = sc->channels[i]) == NULL)
+                       continue;
+               n++;
+               /* detach from mux client and prepare for closing */
+               if (c->type == SSH_CHANNEL_MUX_CLIENT &&
+                   other->type == SSH_CHANNEL_MUX_PROXY &&
+                   other->mux_ctx == c) {
+                       other->mux_ctx = NULL;
+                       other->type = SSH_CHANNEL_OPEN;
+                       other->istate = CHAN_INPUT_CLOSED;
+                       other->ostate = CHAN_OUTPUT_CLOSED;
+               }
+       }
        debug("channel %d: free: %s, nchannels %u", c->self,
            c->remote_name ? c->remote_name : "???", n);
 
-       s = channel_open_message();
+       if (c->type == SSH_CHANNEL_MUX_CLIENT)
+               mux_remove_remote_forwardings(ssh, c);
+
+       s = channel_open_message(ssh);
        debug3("channel %d: status: %s", c->self, s);
        free(s);
 
-       if (c->sock != -1)
-               shutdown(c->sock, SHUT_RDWR);
-       channel_close_fds(c);
-       buffer_free(&c->input);
-       buffer_free(&c->output);
-       buffer_free(&c->extended);
+       channel_close_fds(ssh, c);
+       sshbuf_free(c->input);
+       sshbuf_free(c->output);
+       sshbuf_free(c->extended);
+       c->input = c->output = c->extended = NULL;
        free(c->remote_name);
        c->remote_name = NULL;
        free(c->path);
@@ -437,25 +569,26 @@ channel_free(Channel *c)
        c->listening_addr = NULL;
        while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
                if (cc->abandon_cb != NULL)
-                       cc->abandon_cb(c, cc->ctx);
+                       cc->abandon_cb(ssh, c, cc->ctx);
                TAILQ_REMOVE(&c->status_confirms, cc, entry);
                explicit_bzero(cc, sizeof(*cc));
                free(cc);
        }
        if (c->filter_cleanup != NULL && c->filter_ctx != NULL)
-               c->filter_cleanup(c->self, c->filter_ctx);
-       channels[c->self] = NULL;
+               c->filter_cleanup(ssh, c->self, c->filter_ctx);
+       sc->channels[c->self] = NULL;
+       explicit_bzero(c, sizeof(*c));
        free(c);
 }
 
 void
-channel_free_all(void)
+channel_free_all(struct ssh *ssh)
 {
        u_int i;
 
-       for (i = 0; i < channels_alloc; i++)
-               if (channels[i] != NULL)
-                       channel_free(channels[i]);
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++)
+               if (ssh->chanctxt->channels[i] != NULL)
+                       channel_free(ssh, ssh->chanctxt->channels[i]);
 }
 
 /*
@@ -463,26 +596,26 @@ channel_free_all(void)
  * descriptors after a fork.
  */
 void
-channel_close_all(void)
+channel_close_all(struct ssh *ssh)
 {
        u_int i;
 
-       for (i = 0; i < channels_alloc; i++)
-               if (channels[i] != NULL)
-                       channel_close_fds(channels[i]);
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++)
+               if (ssh->chanctxt->channels[i] != NULL)
+                       channel_close_fds(ssh, ssh->chanctxt->channels[i]);
 }
 
 /*
  * Stop listening to channels.
  */
 void
-channel_stop_listening(void)
+channel_stop_listening(struct ssh *ssh)
 {
        u_int i;
        Channel *c;
 
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
                if (c != NULL) {
                        switch (c->type) {
                        case SSH_CHANNEL_AUTH_SOCKET:
@@ -491,8 +624,8 @@ channel_stop_listening(void)
                        case SSH_CHANNEL_X11_LISTENER:
                        case SSH_CHANNEL_UNIX_LISTENER:
                        case SSH_CHANNEL_RUNIX_LISTENER:
-                               channel_close_fd(&c->sock);
-                               channel_free(c);
+                               channel_close_fd(ssh, &c->sock);
+                               channel_free(ssh, c);
                                break;
                        }
                }
@@ -504,28 +637,20 @@ channel_stop_listening(void)
  * more channel is overfull.
  */
 int
-channel_not_very_much_buffered_data(void)
+channel_not_very_much_buffered_data(struct ssh *ssh)
 {
        u_int i;
+       u_int maxsize = ssh_packet_get_maxsize(ssh);
        Channel *c;
 
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
-               if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
-#if 0
-                       if (!compat20 &&
-                           buffer_len(&c->input) > packet_get_maxsize()) {
-                               debug2("channel %d: big input buffer %d",
-                                   c->self, buffer_len(&c->input));
-                               return 0;
-                       }
-#endif
-                       if (buffer_len(&c->output) > packet_get_maxsize()) {
-                               debug2("channel %d: big output buffer %u > %u",
-                                   c->self, buffer_len(&c->output),
-                                   packet_get_maxsize());
-                               return 0;
-                       }
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
+               if (c == NULL || c->type != SSH_CHANNEL_OPEN)
+                       continue;
+               if (sshbuf_len(c->output) > maxsize) {
+                       debug2("channel %d: big output buffer %zu > %u",
+                           c->self, sshbuf_len(c->output), maxsize);
+                       return 0;
                }
        }
        return 1;
@@ -533,13 +658,13 @@ channel_not_very_much_buffered_data(void)
 
 /* Returns true if any channel is still open. */
 int
-channel_still_open(void)
+channel_still_open(struct ssh *ssh)
 {
        u_int i;
        Channel *c;
 
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
                if (c == NULL)
                        continue;
                switch (c->type) {
@@ -550,6 +675,7 @@ channel_still_open(void)
                case SSH_CHANNEL_CLOSED:
                case SSH_CHANNEL_AUTH_SOCKET:
                case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_RDYNAMIC_OPEN:
                case SSH_CHANNEL_CONNECTING:
                case SSH_CHANNEL_ZOMBIE:
                case SSH_CHANNEL_ABANDONED:
@@ -557,21 +683,16 @@ channel_still_open(void)
                case SSH_CHANNEL_RUNIX_LISTENER:
                        continue;
                case SSH_CHANNEL_LARVAL:
-                       if (!compat20)
-                               fatal("cannot happen: SSH_CHANNEL_LARVAL");
                        continue;
                case SSH_CHANNEL_OPENING:
                case SSH_CHANNEL_OPEN:
+               case SSH_CHANNEL_RDYNAMIC_FINISH:
                case SSH_CHANNEL_X11_OPEN:
                case SSH_CHANNEL_MUX_CLIENT:
-                       return 1;
-               case SSH_CHANNEL_INPUT_DRAINING:
-               case SSH_CHANNEL_OUTPUT_DRAINING:
-                       if (!compat13)
-                               fatal("cannot happen: OUT_DRAIN");
+               case SSH_CHANNEL_MUX_PROXY:
                        return 1;
                default:
-                       fatal("channel_still_open: bad channel type %d", c->type);
+                       fatal("%s: bad channel type %d", __func__, c->type);
                        /* NOTREACHED */
                }
        }
@@ -580,23 +701,26 @@ channel_still_open(void)
 
 /* Returns the id of an open channel suitable for keepaliving */
 int
-channel_find_open(void)
+channel_find_open(struct ssh *ssh)
 {
        u_int i;
        Channel *c;
 
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
-               if (c == NULL || c->remote_id < 0)
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
+               if (c == NULL || !c->have_remote_id)
                        continue;
                switch (c->type) {
                case SSH_CHANNEL_CLOSED:
                case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_RDYNAMIC_OPEN:
+               case SSH_CHANNEL_RDYNAMIC_FINISH:
                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_MUX_PROXY:
                case SSH_CHANNEL_OPENING:
                case SSH_CHANNEL_CONNECTING:
                case SSH_CHANNEL_ZOMBIE:
@@ -609,38 +733,35 @@ channel_find_open(void)
                case SSH_CHANNEL_OPEN:
                case SSH_CHANNEL_X11_OPEN:
                        return i;
-               case SSH_CHANNEL_INPUT_DRAINING:
-               case SSH_CHANNEL_OUTPUT_DRAINING:
-                       if (!compat13)
-                               fatal("cannot happen: OUT_DRAIN");
-                       return i;
                default:
-                       fatal("channel_find_open: bad channel type %d", c->type);
+                       fatal("%s: bad channel type %d", __func__, c->type);
                        /* NOTREACHED */
                }
        }
        return -1;
 }
 
-
 /*
  * Returns a message describing the currently open forwarded connections,
  * suitable for sending to the client.  The message contains crlf pairs for
  * newlines.
  */
 char *
-channel_open_message(void)
+channel_open_message(struct ssh *ssh)
 {
-       Buffer buffer;
+       struct sshbuf *buf;
        Channel *c;
-       char buf[1024], *cp;
        u_int i;
-
-       buffer_init(&buffer);
-       snprintf(buf, sizeof buf, "The following connections are open:\r\n");
-       buffer_append(&buffer, buf, strlen(buf));
-       for (i = 0; i < channels_alloc; i++) {
-               c = channels[i];
+       int r;
+       char *ret;
+
+       if ((buf = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new", __func__);
+       if ((r = sshbuf_putf(buf,
+           "The following connections are open:\r\n")) != 0)
+               fatal("%s: sshbuf_putf: %s", __func__, ssh_err(r));
+       for (i = 0; i < ssh->chanctxt->channels_alloc; i++) {
+               c = ssh->chanctxt->channels[i];
                if (c == NULL)
                        continue;
                switch (c->type) {
@@ -651,7 +772,6 @@ channel_open_message(void)
                case SSH_CHANNEL_AUTH_SOCKET:
                case SSH_CHANNEL_ZOMBIE:
                case SSH_CHANNEL_ABANDONED:
-               case SSH_CHANNEL_MUX_CLIENT:
                case SSH_CHANNEL_MUX_LISTENER:
                case SSH_CHANNEL_UNIX_LISTENER:
                case SSH_CHANNEL_RUNIX_LISTENER:
@@ -660,73 +780,95 @@ channel_open_message(void)
                case SSH_CHANNEL_OPENING:
                case SSH_CHANNEL_CONNECTING:
                case SSH_CHANNEL_DYNAMIC:
+               case SSH_CHANNEL_RDYNAMIC_OPEN:
+               case SSH_CHANNEL_RDYNAMIC_FINISH:
                case SSH_CHANNEL_OPEN:
                case SSH_CHANNEL_X11_OPEN:
-               case SSH_CHANNEL_INPUT_DRAINING:
-               case SSH_CHANNEL_OUTPUT_DRAINING:
-                       snprintf(buf, sizeof buf,
-                           "  #%d %.300s (t%d r%d i%u/%d o%u/%d fd %d/%d cc %d)\r\n",
+               case SSH_CHANNEL_MUX_PROXY:
+               case SSH_CHANNEL_MUX_CLIENT:
+                       if ((r = sshbuf_putf(buf, "  #%d %.300s "
+                           "(t%d %s%u i%u/%zu o%u/%zu fd %d/%d cc %d)\r\n",
                            c->self, c->remote_name,
-                           c->type, c->remote_id,
-                           c->istate, buffer_len(&c->input),
-                           c->ostate, buffer_len(&c->output),
-                           c->rfd, c->wfd, c->ctl_chan);
-                       buffer_append(&buffer, buf, strlen(buf));
+                           c->type,
+                           c->have_remote_id ? "r" : "nr", c->remote_id,
+                           c->istate, sshbuf_len(c->input),
+                           c->ostate, sshbuf_len(c->output),
+                           c->rfd, c->wfd, c->ctl_chan)) != 0)
+                               fatal("%s: sshbuf_putf: %s",
+                                   __func__, ssh_err(r));
                        continue;
                default:
-                       fatal("channel_open_message: bad channel type %d", c->type);
+                       fatal("%s: bad channel type %d", __func__, c->type);
                        /* NOTREACHED */
                }
        }
-       buffer_append(&buffer, "\0", 1);
-       cp = xstrdup((char *)buffer_ptr(&buffer));
-       buffer_free(&buffer);
-       return cp;
+       if ((ret = sshbuf_dup_string(buf)) == NULL)
+               fatal("%s: sshbuf_dup_string", __func__);
+       sshbuf_free(buf);
+       return ret;
+}
+
+static void
+open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type)
+{
+       int r;
+
+       if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
+           (r = sshpkt_put_cstring(ssh, type)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->self)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
+               fatal("%s: channel %i: open: %s", where, c->self, ssh_err(r));
+       }
 }
 
 void
-channel_send_open(int id)
+channel_send_open(struct ssh *ssh, int id)
 {
-       Channel *c = channel_lookup(id);
+       Channel *c = channel_lookup(ssh, id);
+       int r;
 
        if (c == NULL) {
                logit("channel_send_open: %d: bad id", id);
                return;
        }
        debug2("channel %d: send open", id);
-       packet_start(SSH2_MSG_CHANNEL_OPEN);
-       packet_put_cstring(c->ctype);
-       packet_put_int(c->self);
-       packet_put_int(c->local_window);
-       packet_put_int(c->local_maxpacket);
-       packet_send();
+       open_preamble(ssh, __func__, c, c->ctype);
+       if ((r = sshpkt_send(ssh)) != 0)
+               fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
 }
 
 void
-channel_request_start(int id, char *service, int wantconfirm)
+channel_request_start(struct ssh *ssh, int id, char *service, int wantconfirm)
 {
-       Channel *c = channel_lookup(id);
+       Channel *c = channel_lookup(ssh, id);
+       int r;
 
        if (c == NULL) {
-               logit("channel_request_start: %d: unknown channel id", id);
+               logit("%s: %d: unknown channel id", __func__, id);
                return;
        }
+       if (!c->have_remote_id)
+               fatal(":%s: channel %d: no remote id", __func__, c->self);
+
        debug2("channel %d: request %s confirm %d", id, service, wantconfirm);
-       packet_start(SSH2_MSG_CHANNEL_REQUEST);
-       packet_put_int(c->remote_id);
-       packet_put_cstring(service);
-       packet_put_char(wantconfirm);
+       if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+           (r = sshpkt_put_cstring(ssh, service)) != 0 ||
+           (r = sshpkt_put_u8(ssh, wantconfirm)) != 0) {
+               fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
+       }
 }
 
 void
-channel_register_status_confirm(int id, channel_confirm_cb *cb,
-    channel_confirm_abandon_cb *abandon_cb, void *ctx)
+channel_register_status_confirm(struct ssh *ssh, int id,
+    channel_confirm_cb *cb, channel_confirm_abandon_cb *abandon_cb, void *ctx)
 {
        struct channel_confirm *cc;
        Channel *c;
 
-       if ((c = channel_lookup(id)) == NULL)
-               fatal("channel_register_expect: %d: bad id", id);
+       if ((c = channel_lookup(ssh, id)) == NULL)
+               fatal("%s: %d: bad id", __func__, id);
 
        cc = xcalloc(1, sizeof(*cc));
        cc->cb = cb;
@@ -736,12 +878,13 @@ channel_register_status_confirm(int id, channel_confirm_cb *cb,
 }
 
 void
-channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
+channel_register_open_confirm(struct ssh *ssh, int id,
+    channel_open_fn *fn, void *ctx)
 {
-       Channel *c = channel_lookup(id);
+       Channel *c = channel_lookup(ssh, id);
 
        if (c == NULL) {
-               logit("channel_register_open_confirm: %d: bad id", id);
+               logit("%s: %d: bad id", __func__, id);
                return;
        }
        c->open_confirm = fn;
@@ -749,12 +892,13 @@ channel_register_open_confirm(int id, channel_open_fn *fn, void *ctx)
 }
 
 void
-channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
+channel_register_cleanup(struct ssh *ssh, int id,
+    channel_callback_fn *fn, int do_close)
 {
-       Channel *c = channel_by_id(id);
+       Channel *c = channel_by_id(ssh, id);
 
        if (c == NULL) {
-               logit("channel_register_cleanup: %d: bad id", id);
+               logit("%s: %d: bad id", __func__, id);
                return;
        }
        c->detach_user = fn;
@@ -762,12 +906,12 @@ channel_register_cleanup(int id, channel_callback_fn *fn, int do_close)
 }
 
 void
-channel_cancel_cleanup(int id)
+channel_cancel_cleanup(struct ssh *ssh, int id)
 {
-       Channel *c = channel_by_id(id);
+       Channel *c = channel_by_id(ssh, id);
 
        if (c == NULL) {
-               logit("channel_cancel_cleanup: %d: bad id", id);
+               logit("%s: %d: bad id", __func__, id);
                return;
        }
        c->detach_user = NULL;
@@ -775,13 +919,13 @@ channel_cancel_cleanup(int id)
 }
 
 void
-channel_register_filter(int id, channel_infilter_fn *ifn,
+channel_register_filter(struct ssh *ssh, int id, channel_infilter_fn *ifn,
     channel_outfilter_fn *ofn, channel_filter_cleanup_fn *cfn, void *ctx)
 {
-       Channel *c = channel_lookup(id);
+       Channel *c = channel_lookup(ssh, id);
 
        if (c == NULL) {
-               logit("channel_register_filter: %d: bad id", id);
+               logit("%s: %d: bad id", __func__, id);
                return;
        }
        c->input_filter = ifn;
@@ -791,118 +935,80 @@ channel_register_filter(int id, channel_infilter_fn *ifn,
 }
 
 void
-channel_set_fds(int id, int rfd, int wfd, int efd,
+channel_set_fds(struct ssh *ssh, int id, int rfd, int wfd, int efd,
     int extusage, int nonblock, int is_tty, u_int window_max)
 {
-       Channel *c = channel_lookup(id);
+       Channel *c = channel_lookup(ssh, id);
+       int r;
 
        if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
                fatal("channel_activate for non-larval channel %d.", id);
-       channel_register_fds(c, rfd, wfd, efd, extusage, nonblock, is_tty);
+       if (!c->have_remote_id)
+               fatal(":%s: channel %d: no remote id", __func__, c->self);
+
+       channel_register_fds(ssh, c, rfd, wfd, efd, extusage, nonblock, is_tty);
        c->type = SSH_CHANNEL_OPEN;
        c->local_window = c->local_window_max = window_max;
-       packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
-       packet_put_int(c->remote_id);
-       packet_put_int(c->local_window);
-       packet_send();
-}
 
-/*
- * 'channel_pre*' are called just before select() to add any bits relevant to
- * channels in the select bitmasks.
- */
-/*
- * 'channel_post*': perform any appropriate operations for channels which
- * have events pending.
- */
-typedef void chan_fn(Channel *c, fd_set *readset, fd_set *writeset);
-chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];
-chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];
+       if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
+           (r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
+           (r = sshpkt_send(ssh)) != 0)
+               fatal("%s: channel %i: %s", __func__, c->self, ssh_err(r));
+}
 
-/* ARGSUSED */
 static void
-channel_pre_listener(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_listener(struct ssh *ssh, Channel *c,
+    fd_set *readset, fd_set *writeset)
 {
        FD_SET(c->sock, readset);
 }
 
-/* ARGSUSED */
 static void
-channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_connecting(struct ssh *ssh, Channel *c,
+    fd_set *readset, fd_set *writeset)
 {
        debug3("channel %d: waiting for connection", c->self);
        FD_SET(c->sock, writeset);
 }
 
 static void
-channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
-{
-       if (buffer_len(&c->input) < packet_get_maxsize())
-               FD_SET(c->sock, readset);
-       if (buffer_len(&c->output) > 0)
-               FD_SET(c->sock, writeset);
-}
-
-static void
-channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_open(struct ssh *ssh, Channel *c,
+    fd_set *readset, fd_set *writeset)
 {
-       u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
-
        if (c->istate == CHAN_INPUT_OPEN &&
-           limit > 0 &&
-           buffer_len(&c->input) < limit &&
-           buffer_check_alloc(&c->input, CHAN_RBUF))
+           c->remote_window > 0 &&
+           sshbuf_len(c->input) < c->remote_window &&
+           sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
                FD_SET(c->rfd, readset);
        if (c->ostate == CHAN_OUTPUT_OPEN ||
            c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
-               if (buffer_len(&c->output) > 0) {
+               if (sshbuf_len(c->output) > 0) {
                        FD_SET(c->wfd, writeset);
                } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
                        if (CHANNEL_EFD_OUTPUT_ACTIVE(c))
-                               debug2("channel %d: obuf_empty delayed efd %d/(%d)",
-                                   c->self, c->efd, buffer_len(&c->extended));
+                               debug2("channel %d: "
+                                   "obuf_empty delayed efd %d/(%zu)", c->self,
+                                   c->efd, sshbuf_len(c->extended));
                        else
-                               chan_obuf_empty(c);
+                               chan_obuf_empty(ssh, c);
                }
        }
        /** XXX check close conditions, too */
-       if (compat20 && c->efd != -1 && 
-           !(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
+       if (c->efd != -1 && !(c->istate == CHAN_INPUT_CLOSED &&
+           c->ostate == CHAN_OUTPUT_CLOSED)) {
                if (c->extended_usage == CHAN_EXTENDED_WRITE &&
-                   buffer_len(&c->extended) > 0)
+                   sshbuf_len(c->extended) > 0)
                        FD_SET(c->efd, writeset);
                else if (c->efd != -1 && !(c->flags & CHAN_EOF_SENT) &&
                    (c->extended_usage == CHAN_EXTENDED_READ ||
                    c->extended_usage == CHAN_EXTENDED_IGNORE) &&
-                   buffer_len(&c->extended) < c->remote_window)
+                   sshbuf_len(c->extended) < c->remote_window)
                        FD_SET(c->efd, readset);
        }
        /* XXX: What about efd? races? */
 }
 
-/* ARGSUSED */
-static void
-channel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
-{
-       if (buffer_len(&c->input) == 0) {
-               packet_start(SSH_MSG_CHANNEL_CLOSE);
-               packet_put_int(c->remote_id);
-               packet_send();
-               c->type = SSH_CHANNEL_CLOSED;
-               debug2("channel %d: closing after input drain.", c->self);
-       }
-}
-
-/* ARGSUSED */
-static void
-channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
-{
-       if (buffer_len(&c->output) == 0)
-               chan_mark_dead(c);
-       else
-               FD_SET(c->sock, writeset);
-}
-
 /*
  * This is a special state for X11 authentication spoofing.  An opened X11
  * connection (when authentication spoofing is being done) remains in this
@@ -913,24 +1019,26 @@ channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
  * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
  */
 static int
-x11_open_helper(Buffer *b)
+x11_open_helper(struct ssh *ssh, struct sshbuf *b)
 {
+       struct ssh_channels *sc = ssh->chanctxt;
        u_char *ucp;
        u_int proto_len, data_len;
 
        /* Is this being called after the refusal deadline? */
-       if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) {
+       if (sc->x11_refuse_time != 0 &&
+           (u_int)monotime() >= sc->x11_refuse_time) {
                verbose("Rejected X11 connection after ForwardX11Timeout "
                    "expired");
                return -1;
        }
 
        /* Check if the fixed size part of the packet is in buffer. */
-       if (buffer_len(b) < 12)
+       if (sshbuf_len(b) < 12)
                return 0;
 
        /* Parse the lengths of variable-length fields. */
-       ucp = buffer_ptr(b);
+       ucp = sshbuf_mutable_ptr(b);
        if (ucp[0] == 0x42) {   /* Byte order MSB first. */
                proto_len = 256 * ucp[6] + ucp[7];
                data_len = 256 * ucp[8] + ucp[9];
@@ -944,27 +1052,27 @@ x11_open_helper(Buffer *b)
        }
 
        /* Check if the whole packet is in buffer. */
-       if (buffer_len(b) <
+       if (sshbuf_len(b) <
            12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3))
                return 0;
 
        /* Check if authentication protocol matches. */
-       if (proto_len != strlen(x11_saved_proto) ||
-           memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) {
+       if (proto_len != strlen(sc->x11_saved_proto) ||
+           memcmp(ucp + 12, sc->x11_saved_proto, proto_len) != 0) {
                debug2("X11 connection uses different authentication protocol.");
                return -1;
        }
        /* Check if authentication data matches our fake data. */
-       if (data_len != x11_fake_data_len ||
+       if (data_len != sc->x11_fake_data_len ||
            timingsafe_bcmp(ucp + 12 + ((proto_len + 3) & ~3),
-               x11_fake_data, x11_fake_data_len) != 0) {
+               sc->x11_fake_data, sc->x11_fake_data_len) != 0) {
                debug2("X11 auth data does not match fake data.");
                return -1;
        }
        /* Check fake data length */
-       if (x11_fake_data_len != x11_saved_data_len) {
+       if (sc->x11_fake_data_len != sc->x11_saved_data_len) {
                error("X11 fake_data_len %d != saved_data_len %d",
-                   x11_fake_data_len, x11_saved_data_len);
+                   sc->x11_fake_data_len, sc->x11_saved_data_len);
                return -1;
        }
        /*
@@ -973,90 +1081,63 @@ x11_open_helper(Buffer *b)
         * data.
         */
        memcpy(ucp + 12 + ((proto_len + 3) & ~3),
-           x11_saved_data, x11_saved_data_len);
+           sc->x11_saved_data, sc->x11_saved_data_len);
        return 1;
 }
 
 static void
-channel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
-{
-       int ret = x11_open_helper(&c->output);
-
-       if (ret == 1) {
-               /* Start normal processing for the channel. */
-               c->type = SSH_CHANNEL_OPEN;
-               channel_pre_open_13(c, readset, writeset);
-       } else if (ret == -1) {
-               /*
-                * We have received an X11 connection that has bad
-                * authentication information.
-                */
-               logit("X11 connection rejected because of wrong authentication.");
-               buffer_clear(&c->input);
-               buffer_clear(&c->output);
-               channel_close_fd(&c->sock);
-               c->sock = -1;
-               c->type = SSH_CHANNEL_CLOSED;
-               packet_start(SSH_MSG_CHANNEL_CLOSE);
-               packet_put_int(c->remote_id);
-               packet_send();
-       }
-}
-
-static void
-channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_x11_open(struct ssh *ssh, Channel *c,
+    fd_set *readset, fd_set *writeset)
 {
-       int ret = x11_open_helper(&c->output);
+       int ret = x11_open_helper(ssh, c->output);
 
        /* c->force_drain = 1; */
 
        if (ret == 1) {
                c->type = SSH_CHANNEL_OPEN;
-               channel_pre_open(c, readset, writeset);
+               channel_pre_open(ssh, c, readset, writeset);
        } else if (ret == -1) {
                logit("X11 connection rejected because of wrong authentication.");
-               debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate);
-               chan_read_failed(c);
-               buffer_clear(&c->input);
-               chan_ibuf_empty(c);
-               buffer_clear(&c->output);
-               /* for proto v1, the peer will send an IEOF */
-               if (compat20)
-                       chan_write_failed(c);
-               else
-                       c->type = SSH_CHANNEL_OPEN;
+               debug2("X11 rejected %d i%d/o%d",
+                   c->self, c->istate, c->ostate);
+               chan_read_failed(ssh, c);
+               sshbuf_reset(c->input);
+               chan_ibuf_empty(ssh, c);
+               sshbuf_reset(c->output);
+               chan_write_failed(ssh, c);
                debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
        }
 }
 
 static void
-channel_pre_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
+channel_pre_mux_client(struct ssh *ssh,
+    Channel *c, fd_set *readset, fd_set *writeset)
 {
        if (c->istate == CHAN_INPUT_OPEN && !c->mux_pause &&
-           buffer_check_alloc(&c->input, CHAN_RBUF))
+           sshbuf_check_reserve(c->input, CHAN_RBUF) == 0)
                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);
+               sshbuf_reset(c->input);
+               chan_ibuf_empty(ssh, c);
                /* Start output drain. XXX just kill chan? */
-               chan_rcvd_oclose(c);
+               chan_rcvd_oclose(ssh, c);
        }
        if (c->ostate == CHAN_OUTPUT_OPEN ||
            c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
-               if (buffer_len(&c->output) > 0)
+               if (sshbuf_len(c->output) > 0)
                        FD_SET(c->wfd, writeset);
                else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN)
-                       chan_obuf_empty(c);
+                       chan_obuf_empty(ssh, c);
        }
 }
 
 /* try to decode a socks4 header */
-/* ARGSUSED */
 static int
-channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
+channel_decode_socks4(Channel *c, struct sshbuf *input, struct sshbuf *output)
 {
-       char *p, *host;
+       const u_char *p;
+       char *host;
        u_int len, have, i, found, need;
        char username[256];
        struct {
@@ -1065,14 +1146,15 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
                u_int16_t dest_port;
                struct in_addr dest_addr;
        } s4_req, s4_rsp;
+       int r;
 
        debug2("channel %d: decode socks4", c->self);
 
-       have = buffer_len(&c->input);
+       have = sshbuf_len(input);
        len = sizeof(s4_req);
        if (have < len)
                return 0;
-       p = (char *)buffer_ptr(&c->input);
+       p = sshbuf_ptr(input);
 
        need = 1;
        /* SOCKS4A uses an invalid IP address 0.0.0.x */
@@ -1097,46 +1179,55 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset)
        }
        if (found < need)
                return 0;
-       buffer_get(&c->input, (char *)&s4_req.version, 1);
-       buffer_get(&c->input, (char *)&s4_req.command, 1);
-       buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
-       buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
-       have = buffer_len(&c->input);
-       p = (char *)buffer_ptr(&c->input);
-       if (memchr(p, '\0', have) == NULL)