Import OpenSSH-8.0p1 vendor/OPENSSH
authorzrj <rimvydas.jasinskas@gmail.com>
Thu, 18 Apr 2019 05:07:17 +0000 (08:07 +0300)
committerzrj <zrj@dragonflybsd.org>
Wed, 24 Apr 2019 16:45:32 +0000 (19:45 +0300)
241 files changed:
crypto/openssh/PROTOCOL
crypto/openssh/PROTOCOL.certkeys
crypto/openssh/PROTOCOL.chacha20poly1305
crypto/openssh/PROTOCOL.krl
crypto/openssh/PROTOCOL.mux
crypto/openssh/README
crypto/openssh/addrmatch.c
crypto/openssh/atomicio.c
crypto/openssh/atomicio.h
crypto/openssh/audit-bsm.c [deleted file]
crypto/openssh/audit.c [deleted file]
crypto/openssh/audit.h
crypto/openssh/auth-bsdauth.c [deleted file]
crypto/openssh/auth-krb5.c [deleted file]
crypto/openssh/auth-options.c
crypto/openssh/auth-options.h
crypto/openssh/auth-pam.c
crypto/openssh/auth-pam.h
crypto/openssh/auth-passwd.c
crypto/openssh/auth-rhosts.c
crypto/openssh/auth-shadow.c [deleted file]
crypto/openssh/auth-sia.c [deleted file]
crypto/openssh/auth-sia.h [deleted file]
crypto/openssh/auth-skey.c [deleted file]
crypto/openssh/auth.c
crypto/openssh/auth.h
crypto/openssh/auth2-chall.c
crypto/openssh/auth2-gss.c [deleted file]
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/bitmap.h
crypto/openssh/blocks.c [deleted file]
crypto/openssh/bufaux.c [deleted file]
crypto/openssh/bufbn.c [deleted file]
crypto/openssh/bufec.c [deleted file]
crypto/openssh/buffer.c [deleted file]
crypto/openssh/buffer.h [deleted file]
crypto/openssh/channels.c
crypto/openssh/channels.h
crypto/openssh/cipher-aes.c [deleted file]
crypto/openssh/cipher-ctr.c [deleted file]
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/crc32.c [deleted file]
crypto/openssh/crypto_api.h
crypto/openssh/defines.h
crypto/openssh/dh.c
crypto/openssh/dh.h
crypto/openssh/digest-openssl.c
crypto/openssh/dispatch.c
crypto/openssh/dispatch.h
crypto/openssh/dns.c
crypto/openssh/dns.h
crypto/openssh/entropy.c
crypto/openssh/entropy.h
crypto/openssh/groupaccess.c
crypto/openssh/gss-genr.c [deleted file]
crypto/openssh/gss-serv-krb5.c [deleted file]
crypto/openssh/gss-serv.c [deleted file]
crypto/openssh/hash.c
crypto/openssh/hostfile.c
crypto/openssh/kex.c
crypto/openssh/kex.h
crypto/openssh/kexc25519.c
crypto/openssh/kexc25519c.c [deleted file]
crypto/openssh/kexc25519s.c [deleted file]
crypto/openssh/kexdh.c
crypto/openssh/kexdhc.c [deleted file]
crypto/openssh/kexdhs.c [deleted file]
crypto/openssh/kexecdh.c
crypto/openssh/kexecdhc.c [deleted file]
crypto/openssh/kexecdhs.c [deleted file]
crypto/openssh/kexgen.c [new file with mode: 0644]
crypto/openssh/kexgex.c
crypto/openssh/kexgexc.c
crypto/openssh/kexgexs.c
crypto/openssh/kexsntrup4591761x25519.c [new file with mode: 0644]
crypto/openssh/key.c [deleted file]
crypto/openssh/key.h [deleted file]
crypto/openssh/krl.c
crypto/openssh/krl.h
crypto/openssh/log.c
crypto/openssh/log.h
crypto/openssh/loginrec.c
crypto/openssh/loginrec.h
crypto/openssh/match.c
crypto/openssh/match.h
crypto/openssh/md5crypt.c [deleted file]
crypto/openssh/md5crypt.h [deleted file]
crypto/openssh/misc.c
crypto/openssh/misc.h
crypto/openssh/moduli
crypto/openssh/moduli.c
crypto/openssh/monitor.c
crypto/openssh/monitor.h
crypto/openssh/monitor_wrap.c
crypto/openssh/monitor_wrap.h
crypto/openssh/msg.c
crypto/openssh/mux.c
crypto/openssh/myproposal.h
crypto/openssh/nchan.c
crypto/openssh/opacket.c [deleted file]
crypto/openssh/opacket.h [deleted file]
crypto/openssh/openbsd-compat/base64.h [deleted file]
crypto/openssh/openbsd-compat/bcrypt_pbkdf.c [deleted file]
crypto/openssh/openbsd-compat/blf.h [deleted file]
crypto/openssh/openbsd-compat/blowfish.c [deleted file]
crypto/openssh/openbsd-compat/bsd-cray.h [deleted file]
crypto/openssh/openbsd-compat/bsd-cygwin_util.h [deleted file]
crypto/openssh/openbsd-compat/bsd-getpagesize.c [deleted file]
crypto/openssh/openbsd-compat/bsd-malloc.c [deleted file]
crypto/openssh/openbsd-compat/bsd-misc.c [deleted file]
crypto/openssh/openbsd-compat/bsd-misc.h [deleted file]
crypto/openssh/openbsd-compat/bsd-nextstep.h [deleted file]
crypto/openssh/openbsd-compat/bsd-poll.h [deleted file]
crypto/openssh/openbsd-compat/bsd-setres_id.h [deleted file]
crypto/openssh/openbsd-compat/bsd-statvfs.h [deleted file]
crypto/openssh/openbsd-compat/bsd-waitpid.h [deleted file]
crypto/openssh/openbsd-compat/charclass.h [deleted file]
crypto/openssh/openbsd-compat/explicit_bzero.c [deleted file]
crypto/openssh/openbsd-compat/fake-rfc2553.h [deleted file]
crypto/openssh/openbsd-compat/fmt_scaled.c [deleted file]
crypto/openssh/openbsd-compat/freezero.c [deleted file]
crypto/openssh/openbsd-compat/getrrsetbyname.c [deleted file]
crypto/openssh/openbsd-compat/getrrsetbyname.h [deleted file]
crypto/openssh/openbsd-compat/glob.c [deleted file]
crypto/openssh/openbsd-compat/glob.h [deleted file]
crypto/openssh/openbsd-compat/md5.c [deleted file]
crypto/openssh/openbsd-compat/md5.h [deleted file]
crypto/openssh/openbsd-compat/openbsd-compat.h [deleted file]
crypto/openssh/openbsd-compat/openssl-compat.c [deleted file]
crypto/openssh/openbsd-compat/openssl-compat.h [deleted file]
crypto/openssh/openbsd-compat/port-aix.h [deleted file]
crypto/openssh/openbsd-compat/port-irix.h [deleted file]
crypto/openssh/openbsd-compat/port-linux.h [deleted file]
crypto/openssh/openbsd-compat/port-solaris.h [deleted file]
crypto/openssh/openbsd-compat/port-tun.c [deleted file]
crypto/openssh/openbsd-compat/port-tun.h [deleted file]
crypto/openssh/openbsd-compat/port-uw.h [deleted file]
crypto/openssh/openbsd-compat/readpassphrase.h [deleted file]
crypto/openssh/openbsd-compat/reallocarray.c [deleted file]
crypto/openssh/openbsd-compat/realpath.c [deleted file]
crypto/openssh/openbsd-compat/recallocarray.c [deleted file]
crypto/openssh/openbsd-compat/rmd160.c [deleted file]
crypto/openssh/openbsd-compat/rmd160.h [deleted file]
crypto/openssh/openbsd-compat/sha1.c [deleted file]
crypto/openssh/openbsd-compat/sha1.h [deleted file]
crypto/openssh/openbsd-compat/sha2.h [deleted file]
crypto/openssh/openbsd-compat/sigact.h [deleted file]
crypto/openssh/openbsd-compat/strcasestr.c [deleted file]
crypto/openssh/openbsd-compat/sys-queue.h [deleted file]
crypto/openssh/openbsd-compat/sys-tree.h [deleted file]
crypto/openssh/openbsd-compat/timingsafe_bcmp.c [deleted file]
crypto/openssh/packet.c
crypto/openssh/packet.h
crypto/openssh/pathnames.h
crypto/openssh/platform-pledge.c [deleted file]
crypto/openssh/platform-tracing.c [deleted file]
crypto/openssh/platform.c
crypto/openssh/progressmeter.c
crypto/openssh/progressmeter.h
crypto/openssh/readconf.c
crypto/openssh/readconf.h
crypto/openssh/readpass.c
crypto/openssh/rijndael.c [deleted file]
crypto/openssh/scp.1
crypto/openssh/scp.c
crypto/openssh/servconf.c
crypto/openssh/servconf.h
crypto/openssh/serverloop.c
crypto/openssh/session.c
crypto/openssh/session.h
crypto/openssh/sftp-client.c
crypto/openssh/sftp-client.h
crypto/openssh/sftp-common.c
crypto/openssh/sftp-server-main.c
crypto/openssh/sftp-server.c
crypto/openssh/sftp.1
crypto/openssh/sftp.c
crypto/openssh/sntrup4591761.c [new file with mode: 0644]
crypto/openssh/ssh-add.1
crypto/openssh/ssh-add.c
crypto/openssh/ssh-agent.c
crypto/openssh/ssh-dss.c
crypto/openssh/ssh-ecdsa.c
crypto/openssh/ssh-gss.h [deleted file]
crypto/openssh/ssh-keygen.1
crypto/openssh/ssh-keygen.c
crypto/openssh/ssh-keyscan.1
crypto/openssh/ssh-keyscan.c
crypto/openssh/ssh-keysign.c
crypto/openssh/ssh-pkcs11-client.c [deleted file]
crypto/openssh/ssh-pkcs11-helper.8
crypto/openssh/ssh-pkcs11-helper.c
crypto/openssh/ssh-pkcs11.c [deleted file]
crypto/openssh/ssh-pkcs11.h
crypto/openssh/ssh-rsa.c
crypto/openssh/ssh.1
crypto/openssh/ssh.c
crypto/openssh/ssh.h
crypto/openssh/ssh_api.c
crypto/openssh/ssh_api.h
crypto/openssh/ssh_config
crypto/openssh/ssh_config.5
crypto/openssh/sshbuf-getput-crypto.c
crypto/openssh/sshbuf.c
crypto/openssh/sshbuf.h
crypto/openssh/sshconnect.c
crypto/openssh/sshconnect.h
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-xmss.h [new file with mode: 0644]
crypto/openssh/sshkey.c
crypto/openssh/sshkey.h
crypto/openssh/sshlogin.c
crypto/openssh/sshpty.c
crypto/openssh/ttymodes.c
crypto/openssh/uidswap.c
crypto/openssh/uidswap.h
crypto/openssh/umac.c
crypto/openssh/umac128.c [new file with mode: 0644]
crypto/openssh/utf8.c
crypto/openssh/version.h
crypto/openssh/xmss_fast.h [new file with mode: 0644]

index 4e9e875..f75c1c0 100644 (file)
@@ -295,10 +295,14 @@ has completed.
        string[]        hostkeys
 
 Upon receiving this message, a client should check which of the
-supplied host keys are present in known_hosts. For keys that are
-not present, it should send a "hostkeys-prove@openssh.com" message
-to request the server prove ownership of the private half of the
-key.
+supplied host keys are present in known_hosts.
+
+Note that the server may send key types that the client does not
+support. The client should disgregard such keys if they are received.
+
+If the client identifies any keys that are not present for the host,
+it should send a "hostkeys-prove@openssh.com" message to request the
+server prove ownership of the private half of the key.
 
        byte            SSH_MSG_GLOBAL_REQUEST
        string          "hostkeys-prove-00@openssh.com"
@@ -330,6 +334,13 @@ a server may offer multiple keys of the same type for a period (to
 give clients an opportunity to learn them using this extension) before
 removing the deprecated key from those offered.
 
+2.6. connection: SIGINFO support for "signal" channel request
+
+The SSH channels protocol (RFC4254 section 6.9) supports sending a
+signal to a session attached to a channel. OpenSSH supports one
+extension signal "INFO@openssh.com" that allows sending SIGINFO on
+BSD-derived systems.
+
 3. SFTP protocol changes
 
 3.1. sftp: Reversal of arguments to SSH_FXP_SYMLINK
@@ -424,7 +435,7 @@ The values of the f_flag bitmask are as follows:
 Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
 advertised in the SSH_FXP_VERSION hello with version "2".
 
-10. sftp: Extension request "hardlink@openssh.com"
+3.5. sftp: Extension request "hardlink@openssh.com"
 
 This request is for creating a hard link to a regular file. This
 request is implemented as a SSH_FXP_EXTENDED request with the
@@ -440,7 +451,7 @@ link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
 This extension is advertised in the SSH_FXP_VERSION hello with version
 "1".
 
-10. sftp: Extension request "fsync@openssh.com"
+3.6. sftp: Extension request "fsync@openssh.com"
 
 This request asks the server to call fsync(2) on an open file handle.
 
@@ -454,4 +465,35 @@ respond with a SSH_FXP_STATUS message.
 This extension is advertised in the SSH_FXP_VERSION hello with version
 "1".
 
-$OpenBSD: PROTOCOL,v 1.31 2017/05/26 01:40:07 djm Exp $
+4. Miscellaneous changes
+
+4.1 Public key format
+
+OpenSSH public keys, as generated by ssh-keygen(1) and appearing in
+authorized_keys files, are formatted as a single line of text consisting
+of the public key algorithm name followed by a base64-encoded key blob.
+The public key blob (before base64 encoding) is the same format used for
+the encoding of public keys sent on the wire: as described in RFC4253
+section 6.6 for RSA and DSA keys, RFC5656 section 3.1 for ECDSA keys
+and the "New public key formats" section of PROTOCOL.certkeys for the
+OpenSSH certificate formats.
+
+4.2 Private key format
+
+OpenSSH private keys, as generated by ssh-keygen(1) use the format
+described in PROTOCOL.key by default. As a legacy option, PEM format
+(RFC7468) private keys are also supported for RSA, DSA and ECDSA keys
+and were the default format before OpenSSH 7.8.
+
+4.3 KRL format
+
+OpenSSH supports a compact format for Key Revocation Lists (KRLs). This
+format is described in the PROTOCOL.krl file.
+
+4.4 Connection multiplexing
+
+OpenSSH's connection multiplexing uses messages as described in
+PROTOCOL.mux over a Unix domain socket for communications between a
+master instance and later clients.
+
+$OpenBSD: PROTOCOL,v 1.36 2018/10/02 12:51:58 djm Exp $
index 42aa8c2..48338e6 100644 (file)
@@ -25,6 +25,10 @@ raw user keys. The ssh client will support automatic verification of
 acceptance of certified host keys, by adding a similar ability to
 specify CA keys in ~/.ssh/known_hosts.
 
+All certificate types include certification information along with the
+public key that is used to sign challenges. In OpenSSH, ssh-keygen
+performs the CA signing operation.
+
 Certified keys are represented using new key types:
 
     ssh-rsa-cert-v01@openssh.com
@@ -32,10 +36,19 @@ Certified keys are represented using new key types:
     ecdsa-sha2-nistp256-cert-v01@openssh.com
     ecdsa-sha2-nistp384-cert-v01@openssh.com
     ecdsa-sha2-nistp521-cert-v01@openssh.com
+    ssh-ed25519-cert-v01@openssh.com
+
+Two additional types exist for RSA certificates to force use of
+SHA-2 signatures (SHA-256 and SHA-512 respectively):
+
+    rsa-sha2-256-cert-v01@openssh.com
+    rsa-sha2-512-cert-v01@openssh.com
 
-These include certification information along with the public key
-that is used to sign challenges. ssh-keygen performs the CA signing
-operation.
+These RSA/SHA-2 types should not appear in keys at rest or transmitted
+on their wire, but do appear in a SSH_MSG_KEXINIT's host-key algorithms
+field or in the "public key algorithm name" field of a "publickey"
+SSH_USERAUTH_REQUEST to indicate that the signature will use the
+specified algorithm.
 
 Protocol extensions
 -------------------
@@ -100,9 +113,9 @@ DSA certificate
 
 ECDSA certificate
 
-    string    "ecdsa-sha2-nistp256-v01@openssh.com" |
-              "ecdsa-sha2-nistp384-v01@openssh.com" |
-              "ecdsa-sha2-nistp521-v01@openssh.com"
+    string    "ecdsa-sha2-nistp256-cert-v01@openssh.com" |
+              "ecdsa-sha2-nistp384-cert-v01@openssh.com" |
+              "ecdsa-sha2-nistp521-cert-v01@openssh.com"
     string    nonce
     string    curve
     string    public_key
@@ -174,7 +187,7 @@ certificate. Each represents a time in seconds since 1970-01-01
 
     valid after <= current time < valid before
 
-criticial options is a set of zero or more key options encoded as
+critical options is a set of zero or more key options encoded as
 below. All such options are "critical" in the sense that an implementation
 must refuse to authorise a key that has an unrecognised option.
 
@@ -291,4 +304,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.12 2017/05/31 04:29:44 djm Exp $
+$OpenBSD: PROTOCOL.certkeys,v 1.16 2018/10/26 01:23:03 djm Exp $
index 4857d38..9ce2a1e 100644 (file)
@@ -16,7 +16,7 @@ that computes a 128 bit integrity tag given a message and a single-use
 The chacha20-poly1305@openssh.com combines these two primitives into an
 authenticated encryption mode. The construction used is based on that
 proposed for TLS by Adam Langley in [3], but differs in the layout of
-data passed to the MAC and in the addition of encyption of the packet
+data passed to the MAC and in the addition of encryption of the packet
 lengths.
 
 Negotiation
@@ -103,5 +103,5 @@ References
 [3] "ChaCha20 and Poly1305 based Cipher Suites for TLS", Adam Langley
     http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-03
 
-$OpenBSD: PROTOCOL.chacha20poly1305,v 1.3 2016/05/03 13:10:24 djm Exp $
+$OpenBSD: PROTOCOL.chacha20poly1305,v 1.4 2018/04/10 00:10:49 djm Exp $
 
index b969510..115f80e 100644 (file)
@@ -36,6 +36,7 @@ The available section types are:
 #define KRL_SECTION_EXPLICIT_KEY               2
 #define KRL_SECTION_FINGERPRINT_SHA1           3
 #define KRL_SECTION_SIGNATURE                  4
+#define KRL_SECTION_FINGERPRINT_SHA256         5
 
 2. Certificate section
 
@@ -127,25 +128,26 @@ must be a raw key (i.e. not a certificate).
 
 This section may appear multiple times.
 
-4. SHA1 fingerprint sections
+4. SHA1/SHA256 fingerprint sections
 
-These sections, identified as KRL_SECTION_FINGERPRINT_SHA1, revoke
-plain keys (i.e. not certificates) by listing their SHA1 hashes:
+These sections, identified as KRL_SECTION_FINGERPRINT_SHA1 and
+KRL_SECTION_FINGERPRINT_SHA256, revoke plain keys (i.e. not
+certificates) by listing their hashes:
 
        string  public_key_hash[0]
        ....
 
 This section must contain at least one "public_key_hash". The hash blob
-is obtained by taking the SHA1 hash of the public key blob. Hashes in
-this section must appear in numeric order, treating each hash as a big-
-endian integer.
+is obtained by taking the SHA1 or SHA256 hash of the public key blob.
+Hashes in this section must appear in numeric order, treating each hash
+as a big-endian integer.
 
 This section may appear multiple times.
 
 5. KRL signature sections
 
 The KRL_SECTION_SIGNATURE section serves a different purpose to the
-preceeding ones: to provide cryptographic authentication of a KRL that
+preceding ones: to provide cryptographic authentication of a KRL that
 is retrieved over a channel that does not provide integrity protection.
 Its format is slightly different to the previously-described sections:
 in order to simplify the signature generation, it includes as a "body"
@@ -166,4 +168,4 @@ Implementations that retrieve KRLs over untrusted channels must verify
 signatures. Signature sections are optional for KRLs distributed by
 trusted means.
 
-$OpenBSD: PROTOCOL.krl,v 1.3 2015/01/30 01:10:33 djm Exp $
+$OpenBSD: PROTOCOL.krl,v 1.5 2018/09/12 01:21:34 djm Exp $
index f042961..77a0780 100644 (file)
@@ -1,15 +1,52 @@
 This document describes the multiplexing protocol used by ssh(1)'s
 ControlMaster connection-sharing.
 
-Most messages from the client to the server contain a "request id" field.
-This field is returned in replies as "client request id" to facilitate
-matching of responses to requests.
+Multiplexing starts with a ssh(1) configured to act as a multiplexing
+master. This will cause ssh(1) to listen on a Unix domain socket for
+requests from clients. Clients communicate over this socket using a
+simple packetised protocol, where each message is proceeded with
+a length and message type in SSH uint32 wire format:
+
+    uint32  packet length
+    uint32  packet type
+    ...     packet body
+
+Most messages from the client to the server contain a "request id"
+field. This field is returned in replies as "client request id" to
+facilitate matching of responses to requests.
+
+Many muliplexing (mux) client requests yield immediate responses from
+the mux process; requesting a forwarding, performing an alive check or
+requesting the master terminate itself fall in to this category.
+
+The most common use of multiplexing however is to maintain multiple
+concurrent sessions. These are supported via two separate modes:
+
+"Passenger" clients start by requesting a new session with a
+MUX_C_NEW_SESSION message and passing stdio file descriptors over the
+Unix domain control socket. The passenger client then waits until it is
+signaled or the mux server closes the session. This mode is so named as
+the client waits around while the mux server does all the driving.
+
+Stdio forwarding (requested using MUX_C_NEW_STDIO_FWD) is another
+example of passenger mode; the client passes the stdio file descriptors
+and passively waits for something to happen.
+
+"Proxy" clients, requested using MUX_C_PROXY, work quite differently. In
+this mode, the mux client/server connection socket will stop speaking
+the multiplexing protocol and start proxying SSH connection protocol
+messages between the client and server. The client therefore must
+speak a significant subset of the SSH protocol, but in return is able
+to access basically the full suite of connection protocol features.
+Moreover, as no file descriptor passing is required, the connection
+supporting a proxy client may iteself be forwarded or relayed to another
+host if necessary.
 
 1. Connection setup
 
 When a multiplexing connection is made to a ssh(1) operating as a
-ControlMaster from a ssh(1) in multiplex slave mode, the first
-action of each is to exchange hello messages:
+ControlMaster from a client ssh(1), the first action of each is send
+a hello messages to its peer:
 
        uint32  MUX_MSG_HELLO
        uint32  protocol version
@@ -17,16 +54,16 @@ action of each is to exchange hello messages:
        string  extension value [optional]
        ...
 
-The current version of the mux protocol is 4. A slave should refuse
+The current version of the mux protocol is 4. A client should refuse
 to connect to a master that speaks an unsupported protocol version.
-Following the version identifier are zero or more extensions
-represented as a name/value pair. No extensions are currently
-defined.
 
-2. Opening sessions
+Following the version identifier are zero or more extensions represented
+as a name/value pair. No extensions are currently defined.
 
-To open a new multiplexed session, a client may send the following
-request:
+2. Opening a passenger mode session
+
+To open a new multiplexed session in passenger mode, a client sends the
+following request:
 
        uint32  MUX_C_NEW_SESSION
        uint32  request id
@@ -80,7 +117,25 @@ return its local tty to "cooked" mode.
        uint32  MUX_S_TTY_ALLOC_FAIL
        uint32  session id
 
-3. Health checks
+3. Requesting passenger-mode stdio forwarding
+
+A client may request the master to establish a stdio forwarding:
+
+       uint32  MUX_C_NEW_STDIO_FWD
+       uint32  request id
+       string  reserved
+       string  connect host
+       string  connect port
+
+The client then sends its standard input and output file descriptors
+(in that order) using Unix domain socket control messages.
+
+The contents of "reserved" are currently ignored.
+
+A server may reply with a MUX_S_SESSION_OPENED, a MUX_S_PERMISSION_DENIED
+or a MUX_S_FAILURE.
+
+4. Health checks
 
 The client may request a health check/PID report from a server:
 
@@ -93,7 +148,7 @@ The server replies with:
        uint32  client request id
        uint32  server pid
 
-4. Remotely terminating a master
+5. Remotely terminating a master
 
 A client may request that a master terminate immediately:
 
@@ -102,7 +157,7 @@ A client may request that a master terminate immediately:
 
 The server will reply with one of MUX_S_OK or MUX_S_PERMISSION_DENIED.
 
-5. Requesting establishment of port forwards
+6. Requesting establishment of port forwards
 
 A client may request the master to establish a port forward:
 
@@ -131,7 +186,7 @@ For dynamically allocated listen port the server replies with
        uint32  client request id
        uint32  allocated remote listen port
 
-6. Requesting closure of port forwards
+7. Requesting closure of port forwards
 
 Note: currently unimplemented (server will always reply with MUX_S_FAILURE).
 
@@ -148,36 +203,45 @@ A client may request the master to close a port forward:
 A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
 MUX_S_FAILURE.
 
-7. Requesting stdio forwarding
+8. Requesting shutdown of mux listener
 
-A client may request the master to establish a stdio forwarding:
+A client may request the master to stop accepting new multiplexing requests
+and remove its listener socket.
 
-       uint32  MUX_C_NEW_STDIO_FWD
+       uint32  MUX_C_STOP_LISTENING
        uint32  request id
-       string  reserved
-       string  connect host
-       string  connect port
 
-The client then sends its standard input and output file descriptors
-(in that order) using Unix domain socket control messages.
+A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
+MUX_S_FAILURE.
 
-The contents of "reserved" are currently ignored.
+9. Requesting proxy mode
 
-A server may reply with a MUX_S_SESSION_OPENED, a MUX_S_PERMISSION_DENIED
-or a MUX_S_FAILURE.
+A client may request that the the control connection be placed in proxy
+mode:
 
-8. Requesting shutdown of mux listener
+       uint32  MUX_C_PROXY
+       uint32  request id
 
-A client may request the master to stop accepting new multiplexing requests
-and remove its listener socket.
+When a mux master receives this message, it will reply with a
+confirmation:
 
-       uint32  MUX_C_STOP_LISTENING
+       uint32  MUX_S_PROXY
        uint32  request id
 
-A server may reply with a MUX_S_OK, a MUX_S_PERMISSION_DENIED or a
-MUX_S_FAILURE.
+And go into proxy mode. All subsequent data over the connection will
+be formatted as unencrypted, unpadded, SSH transport messages:
+
+       uint32  packet length
+       byte    0 (padding length)
+       byte    packet type
+       byte[packet length - 2] ...
 
-9. Status messages
+The mux master will accept most connection messages and global requests,
+and will translate channel identifiers to ensure that the proxy client has
+globally unique channel numbers (i.e. a proxy client need not worry about
+collisions with other clients).
+
+10. Status messages
 
 The MUX_S_OK message is empty:
 
@@ -194,7 +258,7 @@ The MUX_S_PERMISSION_DENIED and MUX_S_FAILURE include a reason:
        uint32  client request id
        string  reason
 
-10. Protocol numbers
+11. Protocol numbers
 
 #define MUX_MSG_HELLO          0x00000001
 #define MUX_C_NEW_SESSION      0x10000002
@@ -224,5 +288,11 @@ XXX watch in/out traffic (pre/post crypto)
 XXX inject packet (what about replies)
 XXX server->client error/warning notifications
 XXX send signals via mux
-
-$OpenBSD: PROTOCOL.mux,v 1.10 2015/07/17 03:04:27 djm Exp $
+XXX ^Z support in passengers
+XXX extensions for multi-agent
+XXX extensions for multi-X11
+XXX session inspection via master
+XXX signals via mux request
+XXX list active connections via mux
+
+$OpenBSD: PROTOCOL.mux,v 1.11 2018/09/26 07:30:05 djm Exp $
index 103d43e..77cb0ef 100644 (file)
@@ -1,13 +1,9 @@
-See https://www.openssh.com/releasenotes.html#7.6p1 for the release notes.
+See https://www.openssh.com/releasenotes.html#8.0p1 for the release notes.
 
 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 release notes is
-- available at http://www.unixuser.org/~haruyama/security/openssh/index.html
-- Thanks to HARUYAMA Seigo <haruyama@unixuser.org>
-
 This is the port of OpenBSD's excellent OpenSSH[0] to Linux and other
 Unices.
 
@@ -22,7 +18,7 @@ This port consists of the re-introduction of autoconf support, PAM
 support, EGD[1]/PRNGD[2] support and replacements for OpenBSD library
 functions that are (regrettably) absent from other unices. This port
 has been best tested on AIX, Cygwin, HP-UX, Linux, MacOS/X,
-NetBSD, OpenBSD, OpenServer, Solaris, Unicos, and UnixWare.
+FreeBSD, NetBSD, OpenBSD, OpenServer, Solaris and UnixWare.
 
 This version actively tracks changes in the OpenBSD CVS repository.
 
@@ -56,11 +52,11 @@ References -
 
 [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/
+[2] http://prngd.sourceforge.net/
+[3] https://www.zlib.net/
+[4] https://www.openssl.org/
+[5] https://www.openpam.org
+    https://www.kernel.org/pub/linux/libs/pam/
     (PAM also is standard on Solaris and HP-UX 11)
-[6] http://thrysoee.dk/editline/ (portable version)
-[7] http://man.openbsd.org/style.9
+[6] https://thrysoee.dk/editline/ (portable version)
+[7] https://man.openbsd.org/style.9
index 8658e10..5a402d0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: addrmatch.c,v 1.13 2016/09/21 16:55:42 djm Exp $ */
+/*     $OpenBSD: addrmatch.c,v 1.14 2018/07/31 03:07:24 djm Exp $ */
 
 /*
  * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
@@ -205,25 +205,24 @@ addr_cmp(const struct xaddr *a, const struct xaddr *b)
 static int
 addr_pton(const char *p, struct xaddr *n)
 {
-       struct addrinfo hints, *ai;
+       struct addrinfo hints, *ai = NULL;
+       int ret = -1;
 
        memset(&hints, '\0', sizeof(hints));
        hints.ai_flags = AI_NUMERICHOST;
 
        if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0)
-               return -1;
-
+               goto out;
        if (ai == NULL || ai->ai_addr == NULL)
-               return -1;
-
-       if (n != NULL &&
-           addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1) {
+               goto out;
+       if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, n) == -1)
+               goto out;
+       /* success */
+       ret = 0;
+ out:
+       if (ai != NULL)
                freeaddrinfo(ai);
-               return -1;
-       }
-
-       freeaddrinfo(ai);
-       return 0;
+       return ret;
 }
 
 /*
index f854a06..e00c9f0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */
+/* $OpenBSD: atomicio.c,v 1.30 2019/01/24 02:42:23 dtucker Exp $ */
 /*
  * Copyright (c) 2006 Damien Miller. All rights reserved.
  * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
@@ -57,20 +57,25 @@ atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
        ssize_t res;
        struct pollfd pfd;
 
-#ifndef BROKEN_READ_COMPARISON
        pfd.fd = fd;
+#ifndef BROKEN_READ_COMPARISON
        pfd.events = f == read ? POLLIN : POLLOUT;
+#else
+       pfd.events = POLLIN|POLLOUT;
 #endif
        while (n > pos) {
                res = (f) (fd, s + pos, n - pos);
                switch (res) {
                case -1:
-                       if (errno == EINTR)
+                       if (errno == EINTR) {
+                               /* possible SIGALARM, update callback */
+                               if (cb != NULL && cb(cb_arg, 0) == -1) {
+                                       errno = EINTR;
+                                       return pos;
+                               }
                                continue;
-                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#ifndef BROKEN_READ_COMPARISON
+                       } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                (void)poll(&pfd, 1, -1);
-#endif
                                continue;
                        }
                        return 0;
@@ -114,20 +119,25 @@ atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
        /* Make a copy of the iov array because we may modify it below */
        memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
 
-#ifndef BROKEN_READV_COMPARISON
        pfd.fd = fd;
+#ifndef BROKEN_READV_COMPARISON
        pfd.events = f == readv ? POLLIN : POLLOUT;
+#else
+       pfd.events = POLLIN|POLLOUT;
 #endif
        for (; iovcnt > 0 && iov[0].iov_len > 0;) {
                res = (f) (fd, iov, iovcnt);
                switch (res) {
                case -1:
-                       if (errno == EINTR)
+                       if (errno == EINTR) {
+                               /* possible SIGALARM, update callback */
+                               if (cb != NULL && cb(cb_arg, 0) == -1) {
+                                       errno = EINTR;
+                                       return pos;
+                               }
                                continue;
-                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
-#ifndef BROKEN_READV_COMPARISON
+                       } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                (void)poll(&pfd, 1, -1);
-#endif
                                continue;
                        }
                        return 0;
index 0d728ac..8b3cc6e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */
+/* $OpenBSD: atomicio.h,v 1.12 2018/12/27 03:25:25 djm Exp $ */
 
 /*
  * Copyright (c) 2006 Damien Miller.  All rights reserved.
@@ -29,6 +29,8 @@
 #ifndef _ATOMICIO_H
 #define _ATOMICIO_H
 
+struct iovec;
+
 /*
  * Ensure all of data on socket comes through. f==read || f==vwrite
  */
diff --git a/crypto/openssh/audit-bsm.c b/crypto/openssh/audit-bsm.c
deleted file mode 100644 (file)
index f8e0bea..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * TODO
- *
- * - deal with overlap between this and sys_auth_allowed_user
- *   sys_auth_record_login and record_failed_login.
- */
-
-/*
- * Copyright 1988-2002 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-/* #pragma ident       "@(#)bsmaudit.c 1.1     01/09/17 SMI" */
-
-#include "includes.h"
-#if defined(USE_BSM_AUDIT)
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifdef BROKEN_BSM_API
-#include <libscf.h>
-#endif
-
-#include "ssh.h"
-#include "log.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "xmalloc.h"
-
-#ifndef AUE_openssh
-# define AUE_openssh     32800
-#endif
-#include <bsm/audit.h>
-#include <bsm/libbsm.h>
-#include <bsm/audit_uevents.h>
-#include <bsm/audit_record.h>
-#include <locale.h>
-
-#if defined(HAVE_GETAUDIT_ADDR)
-#define        AuditInfoStruct         auditinfo_addr
-#define AuditInfoTermID                au_tid_addr_t
-#define SetAuditFunc(a,b)      setaudit_addr((a),(b))
-#define SetAuditFuncText       "setaudit_addr"
-#define AUToSubjectFunc                au_to_subject_ex
-#define AUToReturnFunc(a,b)    au_to_return32((a), (int32_t)(b))
-#else
-#define        AuditInfoStruct         auditinfo
-#define AuditInfoTermID                au_tid_t
-#define SetAuditFunc(a,b)      setaudit(a)
-#define SetAuditFuncText       "setaudit"
-#define AUToSubjectFunc                au_to_subject
-#define AUToReturnFunc(a,b)    au_to_return((a), (u_int)(b))
-#endif
-
-#ifndef cannot_audit
-extern int     cannot_audit(int);
-#endif
-extern void    aug_init(void);
-extern void    aug_save_auid(au_id_t);
-extern void    aug_save_uid(uid_t);
-extern void    aug_save_euid(uid_t);
-extern void    aug_save_gid(gid_t);
-extern void    aug_save_egid(gid_t);
-extern void    aug_save_pid(pid_t);
-extern void    aug_save_asid(au_asid_t);
-extern void    aug_save_tid(dev_t, unsigned int);
-extern void    aug_save_tid_ex(dev_t, u_int32_t *, u_int32_t);
-extern int     aug_save_me(void);
-extern int     aug_save_namask(void);
-extern void    aug_save_event(au_event_t);
-extern void    aug_save_sorf(int);
-extern void    aug_save_text(char *);
-extern void    aug_save_text1(char *);
-extern void    aug_save_text2(char *);
-extern void    aug_save_na(int);
-extern void    aug_save_user(char *);
-extern void    aug_save_path(char *);
-extern int     aug_save_policy(void);
-extern void    aug_save_afunc(int (*)(int));
-extern int     aug_audit(void);
-extern int     aug_na_selected(void);
-extern int     aug_selected(void);
-extern int     aug_daemon_session(void);
-
-#ifndef HAVE_GETTEXT
-# define gettext(a)    (a)
-#endif
-
-extern Authctxt *the_authctxt;
-static AuditInfoTermID ssh_bsm_tid;
-
-#ifdef BROKEN_BSM_API
-/* For some reason this constant is no longer defined
-   in Solaris 11. */
-#define BSM_TEXTBUFSZ 256
-#endif
-
-/* Below is the low-level BSM interface code */
-
-/*
- * aug_get_machine is only required on IPv6 capable machines, we use a
- * different mechanism in audit_connection_from() for IPv4-only machines.
- * getaudit_addr() is only present on IPv6 capable machines.
- */
-#if defined(HAVE_AUG_GET_MACHINE) || !defined(HAVE_GETAUDIT_ADDR)
-extern int     aug_get_machine(char *, u_int32_t *, u_int32_t *);
-#else
-static int
-aug_get_machine(char *host, u_int32_t *addr, u_int32_t *type)
-{
-       struct addrinfo *ai; 
-       struct sockaddr_in *in4;
-       struct sockaddr_in6 *in6;
-       int ret = 0, r;
-
-       if ((r = getaddrinfo(host, NULL, NULL, &ai)) != 0) {
-               error("BSM audit: getaddrinfo failed for %.100s: %.100s", host,
-                   r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
-               return -1;
-       }
-       
-       switch (ai->ai_family) {
-       case AF_INET:
-               in4 = (struct sockaddr_in *)ai->ai_addr;
-               *type = AU_IPv4;
-               memcpy(addr, &in4->sin_addr, sizeof(struct in_addr));
-               break;
-#ifdef AU_IPv6
-       case AF_INET6: 
-               in6 = (struct sockaddr_in6 *)ai->ai_addr;
-               *type = AU_IPv6;
-               memcpy(addr, &in6->sin6_addr, sizeof(struct in6_addr));
-               break;
-#endif
-       default:
-               error("BSM audit: unknown address family for %.100s: %d",
-                   host, ai->ai_family);
-               ret = -1;
-       }
-       freeaddrinfo(ai);
-       return ret;
-}
-#endif
-
-#ifdef BROKEN_BSM_API
-/*
-  In Solaris 11 the audit daemon has been moved to SMF. In the process
-  they simply dropped getacna() from the API, since it read from a now
-  non-existent config file. This function re-implements getacna() to
-  read from the SMF repository instead.
- */
-int
-getacna(char *auditstring, int len)
-{
-       scf_handle_t *handle = NULL;
-       scf_property_t *property = NULL;
-       scf_value_t *value = NULL;
-       int ret = 0;
-
-       handle = scf_handle_create(SCF_VERSION);
-       if (handle == NULL) 
-               return -2; /* The man page for getacna on Solaris 10 states
-                             we should return -2 in case of error and set
-                             errno to indicate the error. We don't bother
-                             with errno here, though, since the only use
-                             of this function below doesn't check for errors
-                             anyway. 
-                          */
-
-       ret = scf_handle_bind(handle);
-       if (ret == -1) 
-               return -2;
-
-       property = scf_property_create(handle);
-       if (property == NULL) 
-               return -2;
-
-       ret = scf_handle_decode_fmri(handle, 
-            "svc:/system/auditd:default/:properties/preselection/naflags",
-                                    NULL, NULL, NULL, NULL, property, 0);
-       if (ret == -1) 
-               return -2;
-
-       value = scf_value_create(handle);
-       if (value == NULL) 
-               return -2;
-
-       ret = scf_property_get_value(property, value);
-       if (ret == -1) 
-               return -2;
-
-       ret = scf_value_get_astring(value, auditstring, len);
-       if (ret == -1) 
-               return -2;
-
-       scf_value_destroy(value);
-       scf_property_destroy(property);
-       scf_handle_destroy(handle);
-
-       return 0;
-}
-#endif
-
-/*
- * Check if the specified event is selected (enabled) for auditing.
- * Returns 1 if the event is selected, 0 if not and -1 on failure.
- */
-static int
-selected(char *username, uid_t uid, au_event_t event, int sf)
-{
-       int rc, sorf;
-       char naflags[512];
-       struct au_mask mask;
-
-       mask.am_success = mask.am_failure = 0;
-       if (uid < 0) {
-               /* get flags for non-attributable (to a real user) events */
-               rc = getacna(naflags, sizeof(naflags));
-               if (rc == 0)
-                       (void) getauditflagsbin(naflags, &mask);
-       } else
-               rc = au_user_mask(username, &mask);
-
-       sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE;
-       return(au_preselect(event, &mask, sorf, AU_PRS_REREAD));
-}
-
-static void
-bsm_audit_record(int typ, char *string, au_event_t event_no)
-{
-       int             ad, rc, sel;
-       uid_t           uid = -1;
-       gid_t           gid = -1;
-       pid_t           pid = getpid();
-       AuditInfoTermID tid = ssh_bsm_tid;
-
-       if (the_authctxt != NULL && the_authctxt->valid) {
-               uid = the_authctxt->pw->pw_uid;
-               gid = the_authctxt->pw->pw_gid;
-       }
-
-       rc = (typ == 0) ? 0 : -1;
-       sel = selected(the_authctxt->user, uid, event_no, rc);
-       debug3("BSM audit: typ %d rc %d \"%s\"", typ, rc, string);
-       if (!sel)
-               return; /* audit event does not match mask, do not write */
-
-       debug3("BSM audit: writing audit new record");
-       ad = au_open();
-
-       (void) au_write(ad, AUToSubjectFunc(uid, uid, gid, uid, gid,
-           pid, pid, &tid));
-       (void) au_write(ad, au_to_text(string));
-       (void) au_write(ad, AUToReturnFunc(typ, rc));
-
-#ifdef BROKEN_BSM_API
-       /* The last argument is the event modifier flags. For
-          some seemingly undocumented reason it was added in
-          Solaris 11. */
-       rc = au_close(ad, AU_TO_WRITE, event_no, 0);
-#else
-       rc = au_close(ad, AU_TO_WRITE, event_no);
-#endif
-
-       if (rc < 0)
-               error("BSM audit: %s failed to write \"%s\" record: %s",
-                   __func__, string, strerror(errno));
-}
-
-static void
-bsm_audit_session_setup(void)
-{
-       int rc;
-       struct AuditInfoStruct info;
-       au_mask_t mask;
-
-       if (the_authctxt == NULL) {
-               error("BSM audit: session setup internal error (NULL ctxt)");
-               return;
-       }
-
-       if (the_authctxt->valid)
-               info.ai_auid = the_authctxt->pw->pw_uid;
-       else
-               info.ai_auid = -1;
-       info.ai_asid = getpid();
-       mask.am_success = 0;
-       mask.am_failure = 0;
-
-       (void) au_user_mask(the_authctxt->user, &mask);
-
-       info.ai_mask.am_success  = mask.am_success;
-       info.ai_mask.am_failure  = mask.am_failure;
-
-       info.ai_termid = ssh_bsm_tid;
-
-       rc = SetAuditFunc(&info, sizeof(info));
-       if (rc < 0)
-               error("BSM audit: %s: %s failed: %s", __func__,
-                   SetAuditFuncText, strerror(errno));
-}
-
-static void
-bsm_audit_bad_login(const char *what)
-{
-       char textbuf[BSM_TEXTBUFSZ];
-
-       if (the_authctxt->valid) {
-               (void) snprintf(textbuf, sizeof (textbuf),
-                       gettext("invalid %s for user %s"),
-                           what, the_authctxt->user);
-               bsm_audit_record(4, textbuf, AUE_openssh);
-       } else {
-               (void) snprintf(textbuf, sizeof (textbuf),
-                       gettext("invalid user name \"%s\""),
-                           the_authctxt->user);
-               bsm_audit_record(3, textbuf, AUE_openssh);
-       }
-}
-
-/* Below is the sshd audit API code */
-
-void
-audit_connection_from(const char *host, int port)
-{
-       AuditInfoTermID *tid = &ssh_bsm_tid;
-       char buf[1024];
-
-       if (cannot_audit(0))
-               return;
-       debug3("BSM audit: connection from %.100s port %d", host, port);
-
-       /* populate our terminal id structure */
-#if defined(HAVE_GETAUDIT_ADDR)
-       tid->at_port = (dev_t)port;
-       aug_get_machine((char *)host, &(tid->at_addr[0]), &(tid->at_type));
-       snprintf(buf, sizeof(buf), "%08x %08x %08x %08x", tid->at_addr[0],
-           tid->at_addr[1], tid->at_addr[2], tid->at_addr[3]);
-       debug3("BSM audit: iptype %d machine ID %s", (int)tid->at_type, buf);
-#else
-       /* this is used on IPv4-only machines */
-       tid->port = (dev_t)port;
-       tid->machine = inet_addr(host);
-       snprintf(buf, sizeof(buf), "%08x", tid->machine);
-       debug3("BSM audit: machine ID %s", buf);
-#endif
-}
-
-void
-audit_run_command(const char *command)
-{
-       /* not implemented */
-}
-
-void
-audit_session_open(struct logininfo *li)
-{
-       /* not implemented */
-}
-
-void
-audit_session_close(struct logininfo *li)
-{
-       /* not implemented */
-}
-
-void
-audit_event(ssh_audit_event_t event)
-{
-       char    textbuf[BSM_TEXTBUFSZ];
-       static int logged_in = 0;
-       const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
-
-       if (cannot_audit(0))
-               return;
-
-       switch(event) {
-       case SSH_AUTH_SUCCESS:
-               logged_in = 1;
-               bsm_audit_session_setup();
-               snprintf(textbuf, sizeof(textbuf),
-                   gettext("successful login %s"), user);
-               bsm_audit_record(0, textbuf, AUE_openssh);
-               break;
-
-       case SSH_CONNECTION_CLOSE:
-               /*
-                * We can also get a close event if the user attempted auth
-                * but never succeeded.
-                */
-               if (logged_in) {
-                       snprintf(textbuf, sizeof(textbuf),
-                           gettext("sshd logout %s"), the_authctxt->user);
-                       bsm_audit_record(0, textbuf, AUE_logout);
-               } else {
-                       debug("%s: connection closed without authentication",
-                           __func__);
-               }
-               break;
-
-       case SSH_NOLOGIN:
-               bsm_audit_record(1,
-                   gettext("logins disabled by /etc/nologin"), AUE_openssh);
-               break;
-
-       case SSH_LOGIN_EXCEED_MAXTRIES:
-               snprintf(textbuf, sizeof(textbuf),
-                   gettext("too many tries for user %s"), the_authctxt->user);
-               bsm_audit_record(1, textbuf, AUE_openssh);
-               break;
-
-       case SSH_LOGIN_ROOT_DENIED:
-               bsm_audit_record(2, gettext("not_console"), AUE_openssh);
-               break;
-
-       case SSH_AUTH_FAIL_PASSWD:
-               bsm_audit_bad_login("password");
-               break;
-
-       case SSH_AUTH_FAIL_KBDINT:
-               bsm_audit_bad_login("interactive password entry");
-               break;
-
-       default:
-               debug("%s: unhandled event %d", __func__, event);
-       }
-}
-#endif /* BSM */
diff --git a/crypto/openssh/audit.c b/crypto/openssh/audit.c
deleted file mode 100644 (file)
index 7645c14..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2004, 2005 Darren Tucker.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include <stdarg.h>
-#include <string.h>
-
-#ifdef SSH_AUDIT_EVENTS
-
-#include "audit.h"
-#include "log.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-
-/*
- * Care must be taken when using this since it WILL NOT be initialized when
- * audit_connection_from() is called and MAY NOT be initialized when
- * audit_event(CONNECTION_ABANDON) is called.  Test for NULL before using.
- */
-extern Authctxt *the_authctxt;
-
-/* Maybe add the audit class to struct Authmethod? */
-ssh_audit_event_t
-audit_classify_auth(const char *method)
-{
-       if (strcmp(method, "none") == 0)
-               return SSH_AUTH_FAIL_NONE;
-       else if (strcmp(method, "password") == 0)
-               return SSH_AUTH_FAIL_PASSWD;
-       else if (strcmp(method, "publickey") == 0 ||
-           strcmp(method, "rsa") == 0)
-               return SSH_AUTH_FAIL_PUBKEY;
-       else if (strncmp(method, "keyboard-interactive", 20) == 0 ||
-           strcmp(method, "challenge-response") == 0)
-               return SSH_AUTH_FAIL_KBDINT;
-       else if (strcmp(method, "hostbased") == 0 ||
-           strcmp(method, "rhosts-rsa") == 0)
-               return SSH_AUTH_FAIL_HOSTBASED;
-       else if (strcmp(method, "gssapi-with-mic") == 0)
-               return SSH_AUTH_FAIL_GSSAPI;
-       else
-               return SSH_AUDIT_UNKNOWN;
-}
-
-/* helper to return supplied username */
-const char *
-audit_username(void)
-{
-       static const char unknownuser[] = "(unknown user)";
-       static const char invaliduser[] = "(invalid user)";
-
-       if (the_authctxt == NULL || the_authctxt->user == NULL)
-               return (unknownuser);
-       if (!the_authctxt->valid)
-               return (invaliduser);
-       return (the_authctxt->user);
-}
-
-const char *
-audit_event_lookup(ssh_audit_event_t ev)
-{
-       int i;
-       static struct event_lookup_struct {
-               ssh_audit_event_t event;
-               const char *name;
-       } event_lookup[] = {
-               {SSH_LOGIN_EXCEED_MAXTRIES,     "LOGIN_EXCEED_MAXTRIES"},
-               {SSH_LOGIN_ROOT_DENIED,         "LOGIN_ROOT_DENIED"},
-               {SSH_AUTH_SUCCESS,              "AUTH_SUCCESS"},
-               {SSH_AUTH_FAIL_NONE,            "AUTH_FAIL_NONE"},
-               {SSH_AUTH_FAIL_PASSWD,          "AUTH_FAIL_PASSWD"},
-               {SSH_AUTH_FAIL_KBDINT,          "AUTH_FAIL_KBDINT"},
-               {SSH_AUTH_FAIL_PUBKEY,          "AUTH_FAIL_PUBKEY"},
-               {SSH_AUTH_FAIL_HOSTBASED,       "AUTH_FAIL_HOSTBASED"},
-               {SSH_AUTH_FAIL_GSSAPI,          "AUTH_FAIL_GSSAPI"},
-               {SSH_INVALID_USER,              "INVALID_USER"},
-               {SSH_NOLOGIN,                   "NOLOGIN"},
-               {SSH_CONNECTION_CLOSE,          "CONNECTION_CLOSE"},
-               {SSH_CONNECTION_ABANDON,        "CONNECTION_ABANDON"},
-               {SSH_AUDIT_UNKNOWN,             "AUDIT_UNKNOWN"}
-       };
-
-       for (i = 0; event_lookup[i].event != SSH_AUDIT_UNKNOWN; i++)
-               if (event_lookup[i].event == ev)
-                       break;
-       return(event_lookup[i].name);
-}
-
-# ifndef CUSTOM_SSH_AUDIT_EVENTS
-/*
- * Null implementations of audit functions.
- * These get used if SSH_AUDIT_EVENTS is defined but no audit module is enabled.
- */
-
-/*
- * Called after a connection has been accepted but before any authentication
- * has been attempted.
- */
-void
-audit_connection_from(const char *host, int port)
-{
-       debug("audit connection from %s port %d euid %d", host, port,
-           (int)geteuid());
-}
-
-/*
- * Called when various events occur (see audit.h for a list of possible
- * events and what they mean).
- */
-void
-audit_event(ssh_audit_event_t event)
-{
-       debug("audit event euid %d user %s event %d (%s)", geteuid(),
-           audit_username(), event, audit_event_lookup(event));
-}
-
-/*
- * Called when a user session is started.  Argument is the tty allocated to
- * the session, or NULL if no tty was allocated.
- *
- * Note that this may be called multiple times if multiple sessions are used
- * within a single connection.
- */
-void
-audit_session_open(struct logininfo *li)
-{
-       const char *t = li->line ? li->line : "(no tty)";
-
-       debug("audit session open euid %d user %s tty name %s", geteuid(),
-           audit_username(), t);
-}
-
-/*
- * Called when a user session is closed.  Argument is the tty allocated to
- * the session, or NULL if no tty was allocated.
- *
- * Note that this may be called multiple times if multiple sessions are used
- * within a single connection.
- */
-void
-audit_session_close(struct logininfo *li)
-{
-       const char *t = li->line ? li->line : "(no tty)";
-
-       debug("audit session close euid %d user %s tty name %s", geteuid(),
-           audit_username(), t);
-}
-
-/*
- * This will be called when a user runs a non-interactive command.  Note that
- * it may be called multiple times for a single connection since SSH2 allows
- * multiple sessions within a single connection.
- */
-void
-audit_run_command(const char *command)
-{
-       debug("audit run command euid %d user %s command '%.200s'", geteuid(),
-           audit_username(), command);
-}
-# endif  /* !defined CUSTOM_SSH_AUDIT_EVENTS */
-#endif /* SSH_AUDIT_EVENTS */
index 0b59366..38cb5ad 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "loginrec.h"
 
+struct ssh;
+
 enum ssh_audit_event_type {
        SSH_LOGIN_EXCEED_MAXTRIES,
        SSH_LOGIN_ROOT_DENIED,
@@ -46,7 +48,7 @@ enum ssh_audit_event_type {
 typedef enum ssh_audit_event_type ssh_audit_event_t;
 
 void   audit_connection_from(const char *, int);
-void   audit_event(ssh_audit_event_t);
+void   audit_event(struct ssh *, ssh_audit_event_t);
 void   audit_session_open(struct logininfo *);
 void   audit_session_close(struct logininfo *);
 void   audit_run_command(const char *);
diff --git a/crypto/openssh/auth-bsdauth.c b/crypto/openssh/auth-bsdauth.c
deleted file mode 100644 (file)
index e00718f..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/* $OpenBSD: auth-bsdauth.c,v 1.14 2015/10/20 23:24:25 mmcc Exp $ */
-/*
- * Copyright (c) 2001 Markus Friedl.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include <sys/types.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#include <stdarg.h>
-
-#ifdef BSD_AUTH
-#include "xmalloc.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "log.h"
-#include "buffer.h"
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-#include "monitor_wrap.h"
-
-static void *
-bsdauth_init_ctx(Authctxt *authctxt)
-{
-       return authctxt;
-}
-
-int
-bsdauth_query(void *ctx, char **name, char **infotxt,
-   u_int *numprompts, char ***prompts, u_int **echo_on)
-{
-       Authctxt *authctxt = ctx;
-       char *challenge = NULL;
-
-       *infotxt = NULL;
-       *numprompts = 0;
-       *prompts = NULL;
-       *echo_on = NULL;
-
-       if (authctxt->as != NULL) {
-               debug2("bsdauth_query: try reuse session");
-               challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE);
-               if (challenge == NULL) {
-                       auth_close(authctxt->as);
-                       authctxt->as = NULL;
-               }
-       }
-
-       if (challenge == NULL) {
-               debug2("bsdauth_query: new bsd auth session");
-               debug3("bsdauth_query: style %s",
-                   authctxt->style ? authctxt->style : "<default>");
-               authctxt->as = auth_userchallenge(authctxt->user,
-                   authctxt->style, "auth-ssh", &challenge);
-               if (authctxt->as == NULL)
-                       challenge = NULL;
-               debug2("bsdauth_query: <%s>", challenge ? challenge : "empty");
-       }
-
-       if (challenge == NULL)
-               return -1;
-
-       *name = xstrdup("");
-       *infotxt = xstrdup("");
-       *numprompts = 1;
-       *prompts = xcalloc(*numprompts, sizeof(char *));
-       *echo_on = xcalloc(*numprompts, sizeof(u_int));
-       (*prompts)[0] = xstrdup(challenge);
-
-       return 0;
-}
-
-int
-bsdauth_respond(void *ctx, u_int numresponses, char **responses)
-{
-       Authctxt *authctxt = ctx;
-       int authok;
-
-       if (!authctxt->valid)
-               return -1;
-
-       if (authctxt->as == NULL)
-               error("bsdauth_respond: no bsd auth session");
-
-       if (numresponses != 1)
-               return -1;
-
-       authok = auth_userresponse(authctxt->as, responses[0], 0);
-       authctxt->as = NULL;
-       debug3("bsdauth_respond: <%s> = <%d>", responses[0], authok);
-
-       return (authok == 0) ? -1 : 0;
-}
-
-static void
-bsdauth_free_ctx(void *ctx)
-{
-       Authctxt *authctxt = ctx;
-
-       if (authctxt && authctxt->as) {
-               auth_close(authctxt->as);
-               authctxt->as = NULL;
-       }
-}
-
-KbdintDevice bsdauth_device = {
-       "bsdauth",
-       bsdauth_init_ctx,
-       bsdauth_query,
-       bsdauth_respond,
-       bsdauth_free_ctx
-};
-
-KbdintDevice mm_bsdauth_device = {
-       "bsdauth",
-       bsdauth_init_ctx,
-       mm_bsdauth_query,
-       mm_bsdauth_respond,
-       bsdauth_free_ctx
-};
-#endif
diff --git a/crypto/openssh/auth-krb5.c b/crypto/openssh/auth-krb5.c
deleted file mode 100644 (file)
index a5a81ed..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/* $OpenBSD: auth-krb5.c,v 1.22 2016/05/04 14:22:33 markus Exp $ */
-/*
- *    Kerberos v5 authentication and ticket-passing routines.
- *
- * From: FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar
- */
-/*
- * Copyright (c) 2002 Daniel Kouril.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#include <sys/types.h>
-#include <pwd.h>
-#include <stdarg.h>
-
-#include "xmalloc.h"
-#include "ssh.h"
-#include "packet.h"
-#include "log.h"
-#include "buffer.h"
-#include "misc.h"
-#include "servconf.h"
-#include "uidswap.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-
-#ifdef KRB5
-#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <krb5.h>
-
-extern ServerOptions    options;
-
-static int
-krb5_init(void *context)
-{
-       Authctxt *authctxt = (Authctxt *)context;
-       krb5_error_code problem;
-
-       if (authctxt->krb5_ctx == NULL) {
-               problem = krb5_init_context(&authctxt->krb5_ctx);
-               if (problem)
-                       return (problem);
-       }
-       return (0);
-}
-
-int
-auth_krb5_password(Authctxt *authctxt, const char *password)
-{
-#ifndef HEIMDAL
-       krb5_creds creds;
-       krb5_principal server;
-#endif
-       krb5_error_code problem;
-       krb5_ccache ccache = NULL;
-       int len;
-       char *client, *platform_client;
-       const char *errmsg;
-
-       /* get platform-specific kerberos client principal name (if it exists) */
-       platform_client = platform_krb5_get_principal_name(authctxt->pw->pw_name);
-       client = platform_client ? platform_client : authctxt->pw->pw_name;
-
-       temporarily_use_uid(authctxt->pw);
-
-       problem = krb5_init(authctxt);
-       if (problem)
-               goto out;
-
-       problem = krb5_parse_name(authctxt->krb5_ctx, client,
-                   &authctxt->krb5_user);
-       if (problem)
-               goto out;
-
-#ifdef HEIMDAL
-# ifdef HAVE_KRB5_CC_NEW_UNIQUE
-       problem = krb5_cc_new_unique(authctxt->krb5_ctx,
-            krb5_mcc_ops.prefix, NULL, &ccache);
-# else
-       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache);
-# endif
-       if (problem)
-               goto out;
-
-       problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
-               authctxt->krb5_user);
-       if (problem)
-               goto out;
-
-       restore_uid();
-
-       problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
-           ccache, password, 1, NULL);
-
-       temporarily_use_uid(authctxt->pw);
-
-       if (problem)
-               goto out;
-
-# ifdef HAVE_KRB5_CC_NEW_UNIQUE
-       problem = krb5_cc_new_unique(authctxt->krb5_ctx,
-            krb5_fcc_ops.prefix, NULL, &authctxt->krb5_fwd_ccache);
-# else
-       problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops,
-           &authctxt->krb5_fwd_ccache);
-# endif
-       if (problem)
-               goto out;
-
-       problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache,
-           authctxt->krb5_fwd_ccache);
-       krb5_cc_destroy(authctxt->krb5_ctx, ccache);
-       ccache = NULL;
-       if (problem)
-               goto out;
-
-#else
-       problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
-           authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
-       if (problem)
-               goto out;
-
-       problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
-           KRB5_NT_SRV_HST, &server);
-       if (problem)
-               goto out;
-
-       restore_uid();
-       problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
-           NULL, NULL, NULL);
-       krb5_free_principal(authctxt->krb5_ctx, server);
-       temporarily_use_uid(authctxt->pw);
-       if (problem)
-               goto out;
-
-       if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
-           authctxt->pw->pw_name)) {
-               problem = -1;
-               goto out;
-       }
-
-       problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache);
-       if (problem)
-               goto out;
-
-       problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
-                                    authctxt->krb5_user);
-       if (problem)
-               goto out;
-
-       problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
-                                &creds);
-       if (problem)
-               goto out;
-#endif
-
-       authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
-
-       len = strlen(authctxt->krb5_ticket_file) + 6;
-       authctxt->krb5_ccname = xmalloc(len);
-       snprintf(authctxt->krb5_ccname, len, "FILE:%s",
-           authctxt->krb5_ticket_file);
-
-#ifdef USE_PAM
-       if (options.use_pam)
-               do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname);
-#endif
-
- out:
-       restore_uid();
-       
-       free(platform_client);
-
-       if (problem) {
-               if (ccache)
-                       krb5_cc_destroy(authctxt->krb5_ctx, ccache);
-
-               if (authctxt->krb5_ctx != NULL && problem!=-1) {
-                       errmsg = krb5_get_error_message(authctxt->krb5_ctx,
-                           problem);
-                       debug("Kerberos password authentication failed: %s",
-                           errmsg);
-                       krb5_free_error_message(authctxt->krb5_ctx, errmsg);
-               } else
-                       debug("Kerberos password authentication failed: %d",
-                           problem);
-
-               krb5_cleanup_proc(authctxt);
-
-               if (options.kerberos_or_local_passwd)
-                       return (-1);
-               else
-                       return (0);
-       }
-       return (authctxt->valid ? 1 : 0);
-}
-
-void
-krb5_cleanup_proc(Authctxt *authctxt)
-{
-       debug("krb5_cleanup_proc called");
-       if (authctxt->krb5_fwd_ccache) {
-               krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
-               authctxt->krb5_fwd_ccache = NULL;
-       }
-       if (authctxt->krb5_user) {
-               krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
-               authctxt->krb5_user = NULL;
-       }
-       if (authctxt->krb5_ctx) {
-               krb5_free_context(authctxt->krb5_ctx);
-               authctxt->krb5_ctx = NULL;
-       }
-}
-
-#ifndef HEIMDAL
-krb5_error_code
-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
-       int tmpfd, ret, oerrno;
-       char ccname[40];
-       mode_t old_umask;
-
-       ret = snprintf(ccname, sizeof(ccname),
-           "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
-       if (ret < 0 || (size_t)ret >= sizeof(ccname))
-               return ENOMEM;
-
-       old_umask = umask(0177);
-       tmpfd = mkstemp(ccname + strlen("FILE:"));
-       oerrno = errno;
-       umask(old_umask);
-       if (tmpfd == -1) {
-               logit("mkstemp(): %.100s", strerror(oerrno));
-               return oerrno;
-       }
-
-       if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
-               oerrno = errno;
-               logit("fchmod(): %.100s", strerror(oerrno));
-               close(tmpfd);
-               return oerrno;
-       }
-       close(tmpfd);
-
-       return (krb5_cc_resolve(ctx, ccname, ccache));
-}
-#endif /* !HEIMDAL */
-#endif /* KRB5 */
index bed00ee..b05d6d6 100644 (file)
@@ -1,13 +1,18 @@
-/* $OpenBSD: auth-options.c,v 1.74 2017/09/12 06:32:07 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.84 2018/10/03 06:38:35 djm Exp $ */
 /*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
- * As far as I am concerned, the code I have written for this software
- * can be used freely for any purpose.  Any derived versions of this
- * software must be clearly marked as such, and if the derived work is
- * incompatible with the protocol description in the RFC file, it must be
- * called by a name other than "ssh" or "Secure Shell".
+ * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include "includes.h"
 #include <string.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <ctype.h>
+#include <limits.h>
 
 #include "openbsd-compat/sys-queue.h"
 
-#include "key.h"       /* XXX for typedef */
-#include "buffer.h"    /* XXX for typedef */
 #include "xmalloc.h"
-#include "match.h"
 #include "ssherr.h"
 #include "log.h"
-#include "canohost.h"
-#include "packet.h"
 #include "sshbuf.h"
 #include "misc.h"
-#include "channels.h"
-#include "servconf.h"
 #include "sshkey.h"
+#include "match.h"
+#include "ssh2.h"
 #include "auth-options.h"
-#include "hostfile.h"
-#include "auth.h"
-
-/* Flags set authorized_keys flags */
-int no_port_forwarding_flag = 0;
-int no_agent_forwarding_flag = 0;
-int no_x11_forwarding_flag = 0;
-int no_pty_flag = 0;
-int no_user_rc = 0;
-int key_is_cert_authority = 0;
-
-/* "command=" option. */
-char *forced_command = NULL;
-
-/* "environment=" options. */
-struct envstring *custom_environment = NULL;
-
-/* "tunnel=" option. */
-int forced_tun_device = -1;
-
-/* "principals=" option. */
-char *authorized_principals = NULL;
-
-extern ServerOptions options;
-
-/* 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;
-       no_x11_forwarding_flag = 0;
-       no_user_rc = 0;
-       key_is_cert_authority = 0;
-       while (custom_environment) {
-               struct envstring *ce = custom_environment;
-               custom_environment = ce->next;
-               free(ce->s);
-               free(ce);
-       }
-       free(forced_command);
-       forced_command = NULL;
-       free(authorized_principals);
-       authorized_principals = NULL;
-       forced_tun_device = -1;
-       channel_clear_permitted_opens(ssh);
-}
 
 /*
  * Match flag 'opt' in *optsp, and if allow_negate is set then also match
  * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
- * if negated option matches. 
+ * if negated option matches.
  * If the option or negated option matches, then *optsp is updated to
- * point to the first character after the option and, if 'msg' is not NULL
- * then a message based on it added via auth_debug_add().
+ * point to the first character after the option.
  */
 static int
-match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
+opt_flag(const char *opt, int allow_negate, const char **optsp)
 {
        size_t opt_len = strlen(opt);
-       char *opts = *optsp;
+       const char *opts = *optsp;
        int negate = 0;
 
        if (allow_negate && strncasecmp(opts, "no-", 3) == 0) {
@@ -109,368 +59,92 @@ match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
        }
        if (strncasecmp(opts, opt, opt_len) == 0) {
                *optsp = opts + opt_len;
-               if (msg != NULL) {
-                       auth_debug_add("%s %s.", msg,
-                           negate ? "disabled" : "enabled");
-               }
                return negate ? 0 : 1;
        }
        return -1;
 }
 
-/*
- * 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, const char *file,
-    u_long linenum)
+static char *
+opt_dequote(const char **sp, const char **errstrp)
 {
-       struct ssh *ssh = active_state;         /* XXX */
-       const char *cp;
-       int i, r;
-
-       /* reset options */
-       auth_clear_options();
+       const char *s = *sp;
+       char *ret;
+       size_t i;
+
+       *errstrp = NULL;
+       if (*s != '"') {
+               *errstrp = "missing start quote";
+               return NULL;
+       }
+       s++;
+       if ((ret = malloc(strlen((s)) + 1)) == NULL) {
+               *errstrp = "memory allocation failed";
+               return NULL;
+       }
+       for (i = 0; *s != '\0' && *s != '"';) {
+               if (s[0] == '\\' && s[1] == '"')
+                       s++;
+               ret[i++] = *s++;
+       }
+       if (*s == '\0') {
+               *errstrp = "missing end quote";
+               free(ret);
+               return NULL;
+       }
+       ret[i] = '\0';
+       s++;
+       *sp = s;
+       return ret;
+}
 
-       if (!opts)
+static int
+opt_match(const char **opts, const char *term)
+{
+       if (strncasecmp((*opts), term, strlen(term)) == 0 &&
+           (*opts)[strlen(term)] == '=') {
+               *opts += strlen(term) + 1;
                return 1;
-
-       while (*opts && *opts != ' ' && *opts != '\t') {
-               if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {
-                       key_is_cert_authority = r;
-                       goto next_option;
-               }
-               if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {
-                       auth_debug_add("Key is restricted.");
-                       no_port_forwarding_flag = 1;
-                       no_agent_forwarding_flag = 1;
-                       no_x11_forwarding_flag = 1;
-                       no_pty_flag = 1;
-                       no_user_rc = 1;
-                       goto next_option;
-               }
-               if ((r = match_flag("port-forwarding", 1, &opts,
-                   "Port forwarding")) != -1) {
-                       no_port_forwarding_flag = r != 1;
-                       goto next_option;
-               }
-               if ((r = match_flag("agent-forwarding", 1, &opts,
-                   "Agent forwarding")) != -1) {
-                       no_agent_forwarding_flag = r != 1;
-                       goto next_option;
-               }
-               if ((r = match_flag("x11-forwarding", 1, &opts,
-                   "X11 forwarding")) != -1) {
-                       no_x11_forwarding_flag = r != 1;
-                       goto next_option;
-               }
-               if ((r = match_flag("pty", 1, &opts,
-                   "PTY allocation")) != -1) {
-                       no_pty_flag = r != 1;
-                       goto next_option;
-               }
-               if ((r = match_flag("user-rc", 1, &opts,
-                   "User rc execution")) != -1) {
-                       no_user_rc = r != 1;
-                       goto next_option;
-               }
-               cp = "command=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       opts += strlen(cp);
-                       free(forced_command);
-                       forced_command = xmalloc(strlen(opts) + 1);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               if (*opts == '\\' && opts[1] == '"') {
-                                       opts += 2;
-                                       forced_command[i++] = '"';
-                                       continue;
-                               }
-                               forced_command[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               free(forced_command);
-                               forced_command = NULL;
-                               goto bad_option;
-                       }
-                       forced_command[i] = '\0';
-                       auth_debug_add("Forced command.");
-                       opts++;
-                       goto next_option;
-               }
-               cp = "principals=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       opts += strlen(cp);
-                       free(authorized_principals);
-                       authorized_principals = xmalloc(strlen(opts) + 1);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               if (*opts == '\\' && opts[1] == '"') {
-                                       opts += 2;
-                                       authorized_principals[i++] = '"';
-                                       continue;
-                               }
-                               authorized_principals[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               free(authorized_principals);
-                               authorized_principals = NULL;
-                               goto bad_option;
-                       }
-                       authorized_principals[i] = '\0';
-                       auth_debug_add("principals: %.900s",
-                           authorized_principals);
-                       opts++;
-                       goto next_option;
-               }
-               cp = "environment=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       char *s;
-                       struct envstring *new_envstring;
-
-                       opts += strlen(cp);
-                       s = xmalloc(strlen(opts) + 1);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               if (*opts == '\\' && opts[1] == '"') {
-                                       opts += 2;
-                                       s[i++] = '"';
-                                       continue;
-                               }
-                               s[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               free(s);
-                               goto bad_option;
-                       }
-                       s[i] = '\0';
-                       opts++;
-                       if (options.permit_user_env) {
-                               auth_debug_add("Adding to environment: "
-                                   "%.900s", s);
-                               debug("Adding to environment: %.900s", s);
-                               new_envstring = xcalloc(1,
-                                   sizeof(*new_envstring));
-                               new_envstring->s = s;
-                               new_envstring->next = custom_environment;
-                               custom_environment = new_envstring;
-                               s = NULL;
-                       }
-                       free(s);
-                       goto next_option;
-               }
-               cp = "from=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       const char *remote_ip = ssh_remote_ipaddr(ssh);
-                       const char *remote_host = auth_get_canonical_hostname(
-                           ssh, options.use_dns);
-                       char *patterns = xmalloc(strlen(opts) + 1);
-
-                       opts += strlen(cp);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               if (*opts == '\\' && opts[1] == '"') {
-                                       opts += 2;
-                                       patterns[i++] = '"';
-                                       continue;
-                               }
-                               patterns[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               free(patterns);
-                               goto bad_option;
-                       }
-                       patterns[i] = '\0';
-                       opts++;
-                       switch (match_host_and_ip(remote_host, remote_ip,
-                           patterns)) {
-                       case 1:
-                               free(patterns);
-                               /* Host name matches. */
-                               goto next_option;
-                       case -1:
-                               debug("%.100s, line %lu: invalid criteria",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: "
-                                   "invalid criteria", file, linenum);
-                               /* FALLTHROUGH */
-                       case 0:
-                               free(patterns);
-                               logit("Authentication tried for %.100s with "
-                                   "correct key but not from a permitted "
-                                   "host (host=%.200s, ip=%.200s).",
-                                   pw->pw_name, remote_host, remote_ip);
-                               auth_debug_add("Your host '%.200s' is not "
-                                   "permitted to use this key for login.",
-                                   remote_host);
-                               break;
-                       }
-                       /* deny access */
-                       return 0;
-               }
-               cp = "permitopen=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       char *host, *p;
-                       int port;
-                       char *patterns = xmalloc(strlen(opts) + 1);
-
-                       opts += strlen(cp);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               if (*opts == '\\' && opts[1] == '"') {
-                                       opts += 2;
-                                       patterns[i++] = '"';
-                                       continue;
-                               }
-                               patterns[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing "
-                                   "end quote", file, linenum);
-                               free(patterns);
-                               goto bad_option;
-                       }
-                       patterns[i] = '\0';
-                       opts++;
-                       p = patterns;
-                       /* XXX - add streamlocal support */
-                       host = hpdelim(&p);
-                       if (host == NULL || strlen(host) >= NI_MAXHOST) {
-                               debug("%.100s, line %lu: Bad permitopen "
-                                   "specification <%.100s>", file, linenum,
-                                   patterns);
-                               auth_debug_add("%.100s, line %lu: "
-                                   "Bad permitopen specification", file,
-                                   linenum);
-                               free(patterns);
-                               goto bad_option;
-                       }
-                       host = cleanhostname(host);
-                       if (p == NULL || (port = permitopen_port(p)) < 0) {
-                               debug("%.100s, line %lu: Bad permitopen port "
-                                   "<%.100s>", file, linenum, p ? p : "");
-                               auth_debug_add("%.100s, line %lu: "
-                                   "Bad permitopen port", file, linenum);
-                               free(patterns);
-                               goto bad_option;
-                       }
-                       if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
-                               channel_add_permitted_opens(ssh, host, port);
-                       free(patterns);
-                       goto next_option;
-               }
-               cp = "tunnel=\"";
-               if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-                       char *tun = NULL;
-                       opts += strlen(cp);
-                       tun = xmalloc(strlen(opts) + 1);
-                       i = 0;
-                       while (*opts) {
-                               if (*opts == '"')
-                                       break;
-                               tun[i++] = *opts++;
-                       }
-                       if (!*opts) {
-                               debug("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: missing end quote",
-                                   file, linenum);
-                               free(tun);
-                               forced_tun_device = -1;
-                               goto bad_option;
-                       }
-                       tun[i] = '\0';
-                       forced_tun_device = a2tun(tun, NULL);
-                       free(tun);
-                       if (forced_tun_device == SSH_TUNID_ERR) {
-                               debug("%.100s, line %lu: invalid tun device",
-                                   file, linenum);
-                               auth_debug_add("%.100s, line %lu: invalid tun device",
-                                   file, linenum);
-                               forced_tun_device = -1;
-                               goto bad_option;
-                       }
-                       auth_debug_add("Forced tun device: %d", forced_tun_device);
-                       opts++;
-                       goto next_option;
-               }
-next_option:
-               /*
-                * Skip the comma, and move to the next option
-                * (or break out if there are no more).
-                */
-               if (!*opts)
-                       fatal("Bugs in auth-options.c option processing.");
-               if (*opts == ' ' || *opts == '\t')
-                       break;          /* End of options. */
-               if (*opts != ',')
-                       goto bad_option;
-               opts++;
-               /* Process the next option. */
        }
+       return 0;
+}
 
-       /* grant access */
-       return 1;
+static int
+dup_strings(char ***dstp, size_t *ndstp, char **src, size_t nsrc)
+{
+       char **dst;
+       size_t i, j;
 
-bad_option:
-       logit("Bad options in %.100s file, line %lu: %.50s",
-           file, linenum, opts);
-       auth_debug_add("Bad options in %.100s file, line %lu: %.50s",
-           file, linenum, opts);
+       *dstp = NULL;
+       *ndstp = 0;
+       if (nsrc == 0)
+               return 0;
 
-       /* deny access */
+       if ((dst = calloc(nsrc, sizeof(*src))) == NULL)
+               return -1;
+       for (i = 0; i < nsrc; i++) {
+               if ((dst[i] = strdup(src[i])) == NULL) {
+                       for (j = 0; j < i; j++)
+                               free(dst[j]);
+                       free(dst);
+                       return -1;
+               }
+       }
+       /* success */
+       *dstp = dst;
+       *ndstp = nsrc;
        return 0;
 }
 
 #define OPTIONS_CRITICAL       1
 #define OPTIONS_EXTENSIONS     2
 static int
-parse_option_list(struct sshbuf *oblob, struct passwd *pw,
-    u_int which, int crit,
-    int *cert_no_port_forwarding_flag,
-    int *cert_no_agent_forwarding_flag,
-    int *cert_no_x11_forwarding_flag,
-    int *cert_no_pty_flag,
-    int *cert_no_user_rc,
-    char **cert_forced_command,
-    int *cert_source_address_done)
+cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
+    u_int which, int crit)
 {
-       struct ssh *ssh = active_state;         /* XXX */
        char *command, *allowed;
-       const char *remote_ip;
        char *name = NULL;
        struct sshbuf *c = NULL, *data = NULL;
-       int r, ret = -1, result, found;
+       int r, ret = -1, found;
 
        if ((c = sshbuf_fromb(oblob)) == NULL) {
                error("%s: sshbuf_fromb failed", __func__);
@@ -491,21 +165,21 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
                found = 0;
                if ((which & OPTIONS_EXTENSIONS) != 0) {
                        if (strcmp(name, "permit-X11-forwarding") == 0) {
-                               *cert_no_x11_forwarding_flag = 0;
+                               opts->permit_x11_forwarding_flag = 1;
                                found = 1;
                        } else if (strcmp(name,
                            "permit-agent-forwarding") == 0) {
-                               *cert_no_agent_forwarding_flag = 0;
+                               opts->permit_agent_forwarding_flag = 1;
                                found = 1;
                        } else if (strcmp(name,
                            "permit-port-forwarding") == 0) {
-                               *cert_no_port_forwarding_flag = 0;
+                               opts->permit_port_forwarding_flag = 1;
                                found = 1;
                        } else if (strcmp(name, "permit-pty") == 0) {
-                               *cert_no_pty_flag = 0;
+                               opts->permit_pty_flag = 1;
                                found = 1;
                        } else if (strcmp(name, "permit-user-rc") == 0) {
-                               *cert_no_user_rc = 0;
+                               opts->permit_user_rc = 1;
                                found = 1;
                        }
                }
@@ -517,13 +191,13 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
                                            "section: %s", name, ssh_err(r));
                                        goto out;
                                }
-                               if (*cert_forced_command != NULL) {
+                               if (opts->force_command != NULL) {
                                        error("Certificate has multiple "
                                            "force-command options");
                                        free(command);
                                        goto out;
                                }
-                               *cert_forced_command = command;
+                               opts->force_command = command;
                                found = 1;
                        }
                        if (strcmp(name, "source-address") == 0) {
@@ -533,38 +207,19 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
                                            "section: %s", name, ssh_err(r));
                                        goto out;
                                }
-                               if ((*cert_source_address_done)++) {
+                               if (opts->required_from_host_cert != NULL) {
                                        error("Certificate has multiple "
                                            "source-address options");
                                        free(allowed);
                                        goto out;
                                }
-                               remote_ip = ssh_remote_ipaddr(ssh);
-                               result = addr_match_cidr_list(remote_ip,
-                                   allowed);
-                               free(allowed);
-                               switch (result) {
-                               case 1:
-                                       /* accepted */
-                                       break;
-                               case 0:
-                                       /* no match */
-                                       logit("Authentication tried for %.100s "
-                                           "with valid certificate but not "
-                                           "from a permitted host "
-                                           "(ip=%.200s).", pw->pw_name,
-                                           remote_ip);
-                                       auth_debug_add("Your address '%.200s' "
-                                           "is not permitted to use this "
-                                           "certificate for login.",
-                                           remote_ip);
-                                       goto out;
-                               case -1:
-                               default:
+                               /* Check syntax */
+                               if (addr_match_cidr_list(NULL, allowed) == -1) {
                                        error("Certificate source-address "
                                            "contents invalid");
                                        goto out;
                                }
+                               opts->required_from_host_cert = allowed;
                                found = 1;
                        }
                }
@@ -590,74 +245,691 @@ parse_option_list(struct sshbuf *oblob, struct passwd *pw,
        ret = 0;
 
  out:
-       if (ret != 0 &&
-           cert_forced_command != NULL &&
-           *cert_forced_command != NULL) {
-               free(*cert_forced_command);
-               *cert_forced_command = NULL;
-       }
        free(name);
        sshbuf_free(data);
        sshbuf_free(c);
        return ret;
 }
 
+struct sshauthopt *
+sshauthopt_new(void)
+{
+       struct sshauthopt *ret;
+
+       if ((ret = calloc(1, sizeof(*ret))) == NULL)
+               return NULL;
+       ret->force_tun_device = -1;
+       return ret;
+}
+
+void
+sshauthopt_free(struct sshauthopt *opts)
+{
+       size_t i;
+
+       if (opts == NULL)
+               return;
+
+       free(opts->cert_principals);
+       free(opts->force_command);
+       free(opts->required_from_host_cert);
+       free(opts->required_from_host_keys);
+
+       for (i = 0; i < opts->nenv; i++)
+               free(opts->env[i]);
+       free(opts->env);
+
+       for (i = 0; i < opts->npermitopen; i++)
+               free(opts->permitopen[i]);
+       free(opts->permitopen);
+
+       for (i = 0; i < opts->npermitlisten; i++)
+               free(opts->permitlisten[i]);
+       free(opts->permitlisten);
+
+       explicit_bzero(opts, sizeof(*opts));
+       free(opts);
+}
+
+struct sshauthopt *
+sshauthopt_new_with_keys_defaults(void)
+{
+       struct sshauthopt *ret = NULL;
+
+       if ((ret = sshauthopt_new()) == NULL)
+               return NULL;
+
+       /* Defaults for authorized_keys flags */
+       ret->permit_port_forwarding_flag = 1;
+       ret->permit_agent_forwarding_flag = 1;
+       ret->permit_x11_forwarding_flag = 1;
+       ret->permit_pty_flag = 1;
+       ret->permit_user_rc = 1;
+       return ret;
+}
+
 /*
- * Set options from critical certificate options. These supersede user key
- * options so this must be called after auth_parse_options().
+ * Parse and record a permitopen/permitlisten directive.
+ * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
  */
-int
-auth_cert_options(struct sshkey *k, struct passwd *pw, const char **reason)
+static int
+handle_permit(const char **optsp, int allow_bare_port,
+    char ***permitsp, size_t *npermitsp, const char **errstrp)
 {
-       int cert_no_port_forwarding_flag = 1;
-       int cert_no_agent_forwarding_flag = 1;
-       int cert_no_x11_forwarding_flag = 1;
-       int cert_no_pty_flag = 1;
-       int cert_no_user_rc = 1;
-       char *cert_forced_command = NULL;
-       int cert_source_address_done = 0;
-
-       *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,
-           &cert_forced_command,
-           &cert_source_address_done) == -1)
+       char *opt, *tmp, *cp, *host, **permits = *permitsp;
+       size_t npermits = *npermitsp;
+       const char *errstr = "unknown error";
+
+       if (npermits > INT_MAX) {
+               *errstrp = "too many permission directives";
+               return -1;
+       }
+       if ((opt = opt_dequote(optsp, &errstr)) == NULL) {
+               return -1;
+       }
+       if (allow_bare_port && strchr(opt, ':') == NULL) {
+               /*
+                * Allow a bare port number in permitlisten to indicate a
+                * listen_host wildcard.
+                */
+               if (asprintf(&tmp, "*:%s", opt) < 0) {
+                       *errstrp = "memory allocation failed";
+                       return -1;
+               }
+               free(opt);
+               opt = tmp;
+       }
+       if ((tmp = strdup(opt)) == NULL) {
+               free(opt);
+               *errstrp = "memory allocation failed";
                return -1;
-       if (parse_option_list(k->cert->extensions, pw,
-           OPTIONS_EXTENSIONS, 0,
-           &cert_no_port_forwarding_flag,
-           &cert_no_agent_forwarding_flag,
-           &cert_no_x11_forwarding_flag,
-           &cert_no_pty_flag,
-           &cert_no_user_rc,
-           NULL, NULL) == -1)
+       }
+       cp = tmp;
+       /* validate syntax before recording it. */
+       host = hpdelim(&cp);
+       if (host == NULL || strlen(host) >= NI_MAXHOST) {
+               free(tmp);
+               free(opt);
+               *errstrp = "invalid permission hostname";
+               return -1;
+       }
+       /*
+        * don't want to use permitopen_port to avoid
+        * dependency on channels.[ch] here.
+        */
+       if (cp == NULL ||
+           (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
+               free(tmp);
+               free(opt);
+               *errstrp = "invalid permission port";
+               return -1;
+       }
+       /* XXX - add streamlocal support */
+       free(tmp);
+       /* Record it */
+       if ((permits = recallocarray(permits, npermits, npermits + 1,
+           sizeof(*permits))) == NULL) {
+               free(opt);
+               /* NB. don't update *permitsp if alloc fails */
+               *errstrp = "memory allocation failed";
                return -1;
+       }
+       permits[npermits++] = opt;
+       *permitsp = permits;
+       *npermitsp = npermits;
+       return 0;
+}
+
+struct sshauthopt *
+sshauthopt_parse(const char *opts, const char **errstrp)
+{
+       char **oarray, *opt, *cp, *tmp;
+       int r;
+       struct sshauthopt *ret = NULL;
+       const char *errstr = "unknown error";
+       uint64_t valid_before;
+
+       if (errstrp != NULL)
+               *errstrp = NULL;
+       if ((ret = sshauthopt_new_with_keys_defaults()) == NULL)
+               goto alloc_fail;
+
+       if (opts == NULL)
+               return ret;
+
+       while (*opts && *opts != ' ' && *opts != '\t') {
+               /* flag options */
+               if ((r = opt_flag("restrict", 0, &opts)) != -1) {
+                       ret->restricted = 1;
+                       ret->permit_port_forwarding_flag = 0;
+                       ret->permit_agent_forwarding_flag = 0;
+                       ret->permit_x11_forwarding_flag = 0;
+                       ret->permit_pty_flag = 0;
+                       ret->permit_user_rc = 0;
+               } else if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
+                       ret->cert_authority = r;
+               } else if ((r = opt_flag("port-forwarding", 1, &opts)) != -1) {
+                       ret->permit_port_forwarding_flag = r == 1;
+               } else if ((r = opt_flag("agent-forwarding", 1, &opts)) != -1) {
+                       ret->permit_agent_forwarding_flag = r == 1;
+               } else if ((r = opt_flag("x11-forwarding", 1, &opts)) != -1) {
+                       ret->permit_x11_forwarding_flag = r == 1;
+               } else if ((r = opt_flag("pty", 1, &opts)) != -1) {
+                       ret->permit_pty_flag = r == 1;
+               } else if ((r = opt_flag("user-rc", 1, &opts)) != -1) {
+                       ret->permit_user_rc = r == 1;
+               } else if (opt_match(&opts, "command")) {
+                       if (ret->force_command != NULL) {
+                               errstr = "multiple \"command\" clauses";
+                               goto fail;
+                       }
+                       ret->force_command = opt_dequote(&opts, &errstr);
+                       if (ret->force_command == NULL)
+                               goto fail;
+               } else if (opt_match(&opts, "principals")) {
+                       if (ret->cert_principals != NULL) {
+                               errstr = "multiple \"principals\" clauses";
+                               goto fail;
+                       }
+                       ret->cert_principals = opt_dequote(&opts, &errstr);
+                       if (ret->cert_principals == NULL)
+                               goto fail;
+               } else if (opt_match(&opts, "from")) {
+                       if (ret->required_from_host_keys != NULL) {
+                               errstr = "multiple \"from\" clauses";
+                               goto fail;
+                       }
+                       ret->required_from_host_keys = opt_dequote(&opts,
+                           &errstr);
+                       if (ret->required_from_host_keys == NULL)
+                               goto fail;
+               } else if (opt_match(&opts, "expiry-time")) {
+                       if ((opt = opt_dequote(&opts, &errstr)) == NULL)
+                               goto fail;
+                       if (parse_absolute_time(opt, &valid_before) != 0 ||
+                           valid_before == 0) {
+                               free(opt);
+                               errstr = "invalid expires time";
+                               goto fail;
+                       }
+                       free(opt);
+                       if (ret->valid_before == 0 ||
+                           valid_before < ret->valid_before)
+                               ret->valid_before = valid_before;
+               } else if (opt_match(&opts, "environment")) {
+                       if (ret->nenv > INT_MAX) {
+                               errstr = "too many environment strings";
+                               goto fail;
+                       }
+                       if ((opt = opt_dequote(&opts, &errstr)) == NULL)
+                               goto fail;
+                       /* env name must be alphanumeric and followed by '=' */
+                       if ((tmp = strchr(opt, '=')) == NULL) {
+                               free(opt);
+                               errstr = "invalid environment string";
+                               goto fail;
+                       }
+                       if ((cp = strdup(opt)) == NULL)
+                               goto alloc_fail;
+                       cp[tmp - opt] = '\0'; /* truncate at '=' */
+                       if (!valid_env_name(cp)) {
+                               free(cp);
+                               free(opt);
+                               errstr = "invalid environment string";
+                               goto fail;
+                       }
+                       free(cp);
+                       /* Append it. */
+                       oarray = ret->env;
+                       if ((ret->env = recallocarray(ret->env, ret->nenv,
+                           ret->nenv + 1, sizeof(*ret->env))) == NULL) {
+                               free(opt);
+                               ret->env = oarray; /* put it back for cleanup */
+                               goto alloc_fail;
+                       }
+                       ret->env[ret->nenv++] = opt;
+               } else if (opt_match(&opts, "permitopen")) {
+                       if (handle_permit(&opts, 0, &ret->permitopen,
+                           &ret->npermitopen, &errstr) != 0)
+                               goto fail;
+               } else if (opt_match(&opts, "permitlisten")) {
+                       if (handle_permit(&opts, 1, &ret->permitlisten,
+                           &ret->npermitlisten, &errstr) != 0)
+                               goto fail;
+               } else if (opt_match(&opts, "tunnel")) {
+                       if ((opt = opt_dequote(&opts, &errstr)) == NULL)
+                               goto fail;
+                       ret->force_tun_device = a2tun(opt, NULL);
+                       free(opt);
+                       if (ret->force_tun_device == SSH_TUNID_ERR) {
+                               errstr = "invalid tun device";
+                               goto fail;
+                       }
+               }
+               /*
+                * Skip the comma, and move to the next option
+                * (or break out if there are no more).
+                */
+               if (*opts == '\0' || *opts == ' ' || *opts == '\t')
+                       break;          /* End of options. */
+               /* Anything other than a comma is an unknown option */
+               if (*opts != ',') {
+                       errstr = "unknown key option";
+                       goto fail;
+               }
+               opts++;
+               if (*opts == '\0') {
+                       errstr = "unexpected end-of-options";
+                       goto fail;
+               }
+       }
+
+       /* success */
+       if (errstrp != NULL)
+               *errstrp = NULL;
+       return ret;
+
+alloc_fail:
+       errstr = "memory allocation failed";
+fail:
+       sshauthopt_free(ret);
+       if (errstrp != NULL)
+               *errstrp = errstr;
+       return NULL;
+}
+
+struct sshauthopt *
+sshauthopt_from_cert(struct sshkey *k)
+{
+       struct sshauthopt *ret;
+
+       if (k == NULL || !sshkey_type_is_cert(k->type) || k->cert == NULL ||
+           k->cert->type != SSH2_CERT_TYPE_USER)
+               return NULL;
+
+       if ((ret = sshauthopt_new()) == NULL)
+               return NULL;
+
+       /* Handle options and critical extensions separately */
+       if (cert_option_list(ret, k->cert->critical,
+           OPTIONS_CRITICAL, 1) == -1) {
+               sshauthopt_free(ret);
+               return NULL;
+       }
+       if (cert_option_list(ret, k->cert->extensions,
+           OPTIONS_EXTENSIONS, 0) == -1) {
+               sshauthopt_free(ret);
+               return NULL;
+       }
+       /* success */
+       return ret;
+}
+
+/*
+ * Merges "additional" options to "primary" and returns the result.
+ * NB. Some options from primary have primacy.
+ */
+struct sshauthopt *
+sshauthopt_merge(const struct sshauthopt *primary,
+    const struct sshauthopt *additional, const char **errstrp)
+{
+       struct sshauthopt *ret;
+       const char *errstr = "internal error";
+       const char *tmp;
+
+       if (errstrp != NULL)
+               *errstrp = NULL;
+
+       if ((ret = sshauthopt_new()) == NULL)
+               goto alloc_fail;
+
+       /* cert_authority and cert_principals are cleared in result */
+
+       /* Prefer access lists from primary. */
+       /* XXX err is both set and mismatch? */
+       tmp = primary->required_from_host_cert;
+       if (tmp == NULL)
+               tmp = additional->required_from_host_cert;
+       if (tmp != NULL && (ret->required_from_host_cert = strdup(tmp)) == NULL)
+               goto alloc_fail;
+       tmp = primary->required_from_host_keys;
+       if (tmp == NULL)
+               tmp = additional->required_from_host_keys;
+       if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
+               goto alloc_fail;
 
-       no_port_forwarding_flag |= cert_no_port_forwarding_flag;
-       no_agent_forwarding_flag |= cert_no_agent_forwarding_flag;
-       no_x11_forwarding_flag |= cert_no_x11_forwarding_flag;
-       no_pty_flag |= cert_no_pty_flag;
-       no_user_rc |= cert_no_user_rc;
        /*
-        * Only permit both CA and key option forced-command if they match.
-        * Otherwise refuse the certificate.
+        * force_tun_device, permitopen/permitlisten and environment all
+        * prefer the primary.
         */
-       if (cert_forced_command != NULL && forced_command != NULL) {
-               if (strcmp(forced_command, cert_forced_command) == 0) {
-                       free(forced_command);
-                       forced_command = cert_forced_command;
+       ret->force_tun_device = primary->force_tun_device;
+       if (ret->force_tun_device == -1)
+               ret->force_tun_device = additional->force_tun_device;
+       if (primary->nenv > 0) {
+               if (dup_strings(&ret->env, &ret->nenv,
+                   primary->env, primary->nenv) != 0)
+                       goto alloc_fail;
+       } else if (additional->nenv) {
+               if (dup_strings(&ret->env, &ret->nenv,
+                   additional->env, additional->nenv) != 0)
+                       goto alloc_fail;
+       }
+       if (primary->npermitopen > 0) {
+               if (dup_strings(&ret->permitopen, &ret->npermitopen,
+                   primary->permitopen, primary->npermitopen) != 0)
+                       goto alloc_fail;
+       } else if (additional->npermitopen > 0) {
+               if (dup_strings(&ret->permitopen, &ret->npermitopen,
+                   additional->permitopen, additional->npermitopen) != 0)
+                       goto alloc_fail;
+       }
+
+       if (primary->npermitlisten > 0) {
+               if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
+                   primary->permitlisten, primary->npermitlisten) != 0)
+                       goto alloc_fail;
+       } else if (additional->npermitlisten > 0) {
+               if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
+                   additional->permitlisten, additional->npermitlisten) != 0)
+                       goto alloc_fail;
+       }
+
+       /* Flags are logical-AND (i.e. must be set in both for permission) */
+#define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1)
+       OPTFLAG(permit_port_forwarding_flag);
+       OPTFLAG(permit_agent_forwarding_flag);
+       OPTFLAG(permit_x11_forwarding_flag);
+       OPTFLAG(permit_pty_flag);
+       OPTFLAG(permit_user_rc);
+#undef OPTFLAG
+
+       /* Earliest expiry time should win */
+       if (primary->valid_before != 0)
+               ret->valid_before = primary->valid_before;
+       if (additional->valid_before != 0 &&
+           additional->valid_before < ret->valid_before)
+               ret->valid_before = additional->valid_before;
+
+       /*
+        * When both multiple forced-command are specified, only
+        * proceed if they are identical, otherwise fail.
+        */
+       if (primary->force_command != NULL &&
+           additional->force_command != NULL) {
+               if (strcmp(primary->force_command,
+                   additional->force_command) == 0) {
+                       /* ok */
+                       ret->force_command = strdup(primary->force_command);
+                       if (ret->force_command == NULL)
+                               goto alloc_fail;
                } else {
-                       *reason = "certificate and key options forced command "
-                           "do not match";
-                       free(cert_forced_command);
-                       return -1;
+                       errstr = "forced command options do not match";
+                       goto fail;
                }
-       } else if (cert_forced_command != NULL)
-               forced_command = cert_forced_command;
+       } else if (primary->force_command != NULL) {
+               if ((ret->force_command = strdup(
+                   primary->force_command)) == NULL)
+                       goto alloc_fail;
+       } else if (additional->force_command != NULL) {
+               if ((ret->force_command = strdup(
+                   additional->force_command)) == NULL)
+                       goto alloc_fail;
+       }
+       /* success */
+       if (errstrp != NULL)
+               *errstrp = NULL;
+       return ret;
+
+ alloc_fail:
+       errstr = "memory allocation failed";
+ fail:
+       if (errstrp != NULL)
+               *errstrp = errstr;
+       sshauthopt_free(ret);
+       return NULL;
+}
+
+/*
+ * Copy options
+ */
+struct sshauthopt *
+sshauthopt_copy(const struct sshauthopt *orig)
+{
+       struct sshauthopt *ret;
+
+       if ((ret = sshauthopt_new()) == NULL)
+               return NULL;
+
+#define OPTSCALAR(x) ret->x = orig->x
+       OPTSCALAR(permit_port_forwarding_flag);
+       OPTSCALAR(permit_agent_forwarding_flag);
+       OPTSCALAR(permit_x11_forwarding_flag);
+       OPTSCALAR(permit_pty_flag);
+       OPTSCALAR(permit_user_rc);
+       OPTSCALAR(restricted);
+       OPTSCALAR(cert_authority);
+       OPTSCALAR(force_tun_device);
+       OPTSCALAR(valid_before);
+#undef OPTSCALAR
+#define OPTSTRING(x) \
+       do { \
+               if (orig->x != NULL && (ret->x = strdup(orig->x)) == NULL) { \
+                       sshauthopt_free(ret); \
+                       return NULL; \
+               } \
+       } while (0)
+       OPTSTRING(cert_principals);
+       OPTSTRING(force_command);
+       OPTSTRING(required_from_host_cert);
+       OPTSTRING(required_from_host_keys);
+#undef OPTSTRING
+
+       if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
+           dup_strings(&ret->permitopen, &ret->npermitopen,
+           orig->permitopen, orig->npermitopen) != 0 ||
+           dup_strings(&ret->permitlisten, &ret->npermitlisten,
+           orig->permitlisten, orig->npermitlisten) != 0) {
+               sshauthopt_free(ret);
+               return NULL;
+       }
+       return ret;
+}
+
+static int
+serialise_array(struct sshbuf *m, char **a, size_t n)
+{
+       struct sshbuf *b;
+       size_t i;
+       int r;
+
+       if (n > INT_MAX)
+               return SSH_ERR_INTERNAL_ERROR;
+
+       if ((b = sshbuf_new()) == NULL) {
+               return SSH_ERR_ALLOC_FAIL;
+       }
+       for (i = 0; i < n; i++) {
+               if ((r = sshbuf_put_cstring(b, a[i])) != 0) {
+                       sshbuf_free(b);
+                       return r;
+               }
+       }
+       if ((r = sshbuf_put_u32(m, n)) != 0 ||
+           (r = sshbuf_put_stringb(m, b)) != 0) {
+               sshbuf_free(b);
+               return r;
+       }
+       /* success */
+       return 0;
+}
+
+static int
+deserialise_array(struct sshbuf *m, char ***ap, size_t *np)
+{
+       char **a = NULL;
+       size_t i, n = 0;
+       struct sshbuf *b = NULL;
+       u_int tmp;
+       int r = SSH_ERR_INTERNAL_ERROR;
+
+       if ((r = sshbuf_get_u32(m, &tmp)) != 0 ||
+           (r = sshbuf_froms(m, &b)) != 0)
+               goto out;
+       if (tmp > INT_MAX) {
+               r = SSH_ERR_INVALID_FORMAT;
+               goto out;
+       }
+       n = tmp;
+       if (n > 0 && (a = calloc(n, sizeof(*a))) == NULL) {
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       for (i = 0; i < n; i++) {
+               if ((r = sshbuf_get_cstring(b, &a[i], NULL)) != 0)
+                       goto out;
+       }
+       /* success */
+       r = 0;
+       *ap = a;
+       a = NULL;
+       *np = n;
+       n = 0;
+ out:
+       for (i = 0; i < n; i++)
+               free(a[i]);
+       free(a);
+       sshbuf_free(b);
+       return r;
+}
+
+static int
+serialise_nullable_string(struct sshbuf *m, const char *s)
+{
+       int r;
+
+       if ((r = sshbuf_put_u8(m, s == NULL)) != 0 ||
+           (r = sshbuf_put_cstring(m, s)) != 0)
+               return r;
+       return 0;
+}
+
+static int
+deserialise_nullable_string(struct sshbuf *m, char **sp)
+{
+       int r;
+       u_char flag;
+
+       *sp = NULL;
+       if ((r = sshbuf_get_u8(m, &flag)) != 0 ||
+           (r = sshbuf_get_cstring(m, flag ? NULL : sp, NULL)) != 0)
+               return r;
+       return 0;
+}
+
+int
+sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
+    int untrusted)
+{
+       int r = SSH_ERR_INTERNAL_ERROR;
+
+       /* Flag and simple integer options */
+       if ((r = sshbuf_put_u8(m, opts->permit_port_forwarding_flag)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->permit_agent_forwarding_flag)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->permit_x11_forwarding_flag)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->permit_pty_flag)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
+           (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
+           (r = sshbuf_put_u64(m, opts->valid_before)) != 0)
+               return r;
+
+       /* tunnel number can be negative to indicate "unset" */
+       if ((r = sshbuf_put_u8(m, opts->force_tun_device == -1)) != 0 ||
+           (r = sshbuf_put_u32(m, (opts->force_tun_device < 0) ?
+           0 : (u_int)opts->force_tun_device)) != 0)
+               return r;
+
+       /* String options; these may be NULL */
+       if ((r = serialise_nullable_string(m,
+           untrusted ? "yes" : opts->cert_principals)) != 0 ||
+           (r = serialise_nullable_string(m,
+           untrusted ? "true" : opts->force_command)) != 0 ||
+           (r = serialise_nullable_string(m,
+           untrusted ? NULL : opts->required_from_host_cert)) != 0 ||
+           (r = serialise_nullable_string(m,
+            untrusted ? NULL : opts->required_from_host_keys)) != 0)
+               return r;
+
+       /* Array options */
+       if ((r = serialise_array(m, opts->env,
+           untrusted ? 0 : opts->nenv)) != 0 ||
+           (r = serialise_array(m, opts->permitopen,
+           untrusted ? 0 : opts->npermitopen)) != 0 ||
+           (r = serialise_array(m, opts->permitlisten,
+           untrusted ? 0 : opts->npermitlisten)) != 0)
+               return r;
+
        /* success */
-       *reason = NULL;
        return 0;
 }
 
+int
+sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
+{
+       struct sshauthopt *opts = NULL;
+       int r = SSH_ERR_INTERNAL_ERROR;
+       u_char f;
+       u_int tmp;
+
+       if ((opts = calloc(1, sizeof(*opts))) == NULL)
+               return SSH_ERR_ALLOC_FAIL;
+
+#define OPT_FLAG(x) \
+       do { \
+               if ((r = sshbuf_get_u8(m, &f)) != 0) \
+                       goto out; \
+               opts->x = f; \
+       } while (0)
+       OPT_FLAG(permit_port_forwarding_flag);
+       OPT_FLAG(permit_agent_forwarding_flag);
+       OPT_FLAG(permit_x11_forwarding_flag);
+       OPT_FLAG(permit_pty_flag);
+       OPT_FLAG(permit_user_rc);
+       OPT_FLAG(restricted);
+       OPT_FLAG(cert_authority);
+#undef OPT_FLAG
+
+       if ((r = sshbuf_get_u64(m, &opts->valid_before)) != 0)
+               goto out;
+
+       /* tunnel number can be negative to indicate "unset" */
+       if ((r = sshbuf_get_u8(m, &f)) != 0 ||
+           (r = sshbuf_get_u32(m, &tmp)) != 0)
+               goto out;
+       opts->force_tun_device = f ? -1 : (int)tmp;
+
+       /* String options may be NULL */
+       if ((r = deserialise_nullable_string(m, &opts->cert_principals)) != 0 ||
+           (r = deserialise_nullable_string(m, &opts->force_command)) != 0 ||
+           (r = deserialise_nullable_string(m,
+           &opts->required_from_host_cert)) != 0 ||
+           (r = deserialise_nullable_string(m,
+           &opts->required_from_host_keys)) != 0)
+               goto out;
+
+       /* Array options */
+       if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
+           (r = deserialise_array(m,
+           &opts->permitopen, &opts->npermitopen)) != 0 ||
+           (r = deserialise_array(m,
+           &opts->permitlisten, &opts->npermitlisten)) != 0)
+               goto out;
+
+       /* success */
+       r = 0;
+       *optsp = opts;
+       opts = NULL;
+ out:
+       sshauthopt_free(opts);
+       return r;
+}
index 547f016..0462983 100644 (file)
@@ -1,40 +1,95 @@
-/* $OpenBSD: auth-options.h,v 1.23 2017/05/31 10:54:00 markus Exp $ */
+/* $OpenBSD: auth-options.h,v 1.27 2018/06/06 18:23:32 djm Exp $ */
 
 /*
- * Author: Tatu Ylonen <ylo@cs.hut.fi>
- * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
- *                    All rights reserved
+ * Copyright (c) 2018 Damien Miller <djm@mindrot.org>
  *
- * 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".
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #ifndef AUTH_OPTIONS_H
 #define AUTH_OPTIONS_H
 
-/* Linked list of custom environment strings */
-struct envstring {
-       struct envstring *next;
-       char   *s;
+struct passwd;
+struct sshkey;
+
+/*
+ * sshauthopt represents key options parsed from authorized_keys or
+ * from certificate extensions/options.
+ */
+struct sshauthopt {
+       /* Feature flags */
+       int permit_port_forwarding_flag;
+       int permit_agent_forwarding_flag;
+       int permit_x11_forwarding_flag;
+       int permit_pty_flag;
+       int permit_user_rc;
+
+       /* "restrict" keyword was invoked */
+       int restricted;
+
+       /* key/principal expiry date */
+       uint64_t valid_before;
+
+       /* Certificate-related options */
+       int cert_authority;
+       char *cert_principals;
+
+       int force_tun_device;
+       char *force_command;
+
+       /* Custom environment */
+       size_t nenv;
+       char **env;
+
+       /* Permitted port forwardings */
+       size_t npermitopen;
+       char **permitopen;
+
+       /* Permitted listens (remote forwarding) */
+       size_t npermitlisten;
+       char **permitlisten;
+
+       /*
+        * Permitted host/addresses (comma-separated)
+        * Caller must check source address matches both lists (if present).
+        */
+       char *required_from_host_cert;
+       char *required_from_host_keys;
 };
 
-/* Flags that may be set in authorized_keys options. */
-extern int no_port_forwarding_flag;
-extern int no_agent_forwarding_flag;
-extern int no_x11_forwarding_flag;
-extern int no_pty_flag;
-extern int no_user_rc;
-extern char *forced_command;
-extern struct envstring *custom_environment;
-extern int forced_tun_device;
-extern int key_is_cert_authority;
-extern char *authorized_principals;
-
-int    auth_parse_options(struct passwd *, char *, const char *, u_long);
-void   auth_clear_options(void);
-int    auth_cert_options(struct sshkey *, struct passwd *, const char **);
+struct sshauthopt *sshauthopt_new(void);
+struct sshauthopt *sshauthopt_new_with_keys_defaults(void);
+void sshauthopt_free(struct sshauthopt *opts);
+struct sshauthopt *sshauthopt_copy(const struct sshauthopt *orig);
+int sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m, int);
+int sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **opts);
+
+/*
+ * Parse authorized_keys options. Returns an options structure on success
+ * or NULL on failure. Will set errstr on failure.
+ */
+struct sshauthopt *sshauthopt_parse(const char *s, const char **errstr);
+
+/*
+ * Parse certification options to a struct sshauthopt.
+ * Returns options on success or NULL on failure.
+ */
+struct sshauthopt *sshauthopt_from_cert(struct sshkey *k);
+
+/*
+ * Merge key options.
+ */
+struct sshauthopt *sshauthopt_merge(const struct sshauthopt *primary,
+    const struct sshauthopt *additional, const char **errstrp);
 
 #endif
index de29c04..bde0a8f 100644 (file)
@@ -86,8 +86,8 @@ extern char *__progname;
 #endif
 
 #include "xmalloc.h"
-#include "buffer.h"
-#include "key.h"
+#include "sshbuf.h"
+#include "ssherr.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "auth-pam.h"
@@ -105,7 +105,7 @@ extern char *__progname;
 #include "monitor_wrap.h"
 
 extern ServerOptions options;
-extern Buffer loginmsg;
+extern struct sshbuf *loginmsg;
 extern u_int utmp_len;
 
 /* so we don't silently change behaviour */
@@ -128,6 +128,10 @@ extern u_int utmp_len;
 typedef pthread_t sp_pthread_t;
 #else
 typedef pid_t sp_pthread_t;
+#define pthread_exit   fake_pthread_exit
+#define pthread_create fake_pthread_create
+#define pthread_cancel fake_pthread_cancel
+#define pthread_join   fake_pthread_join
 #endif
 
 struct pam_ctxt {
@@ -244,6 +248,9 @@ static int sshpam_maxtries_reached = 0;
 static char **sshpam_env = NULL;
 static Authctxt *sshpam_authctxt = NULL;
 static const char *sshpam_password = NULL;
+static char *sshpam_rhost = NULL;
+static char *sshpam_laddr = NULL;
+static char *sshpam_conninfo = NULL;
 
 /* Some PAM implementations don't implement this */
 #ifndef HAVE_PAM_GETENVLIST
@@ -287,61 +294,80 @@ sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
 void
 sshpam_password_change_required(int reqd)
 {
+       extern struct sshauthopt *auth_opts;
+       static int saved_port, saved_agent, saved_x11;
+
        debug3("%s %d", __func__, reqd);
        if (sshpam_authctxt == NULL)
                fatal("%s: PAM authctxt not initialized", __func__);
        sshpam_authctxt->force_pwchange = reqd;
        if (reqd) {
-               no_port_forwarding_flag |= 2;
-               no_agent_forwarding_flag |= 2;
-               no_x11_forwarding_flag |= 2;
+               saved_port = auth_opts->permit_port_forwarding_flag;
+               saved_agent = auth_opts->permit_agent_forwarding_flag;
+               saved_x11 = auth_opts->permit_x11_forwarding_flag;
+               auth_opts->permit_port_forwarding_flag = 0;
+               auth_opts->permit_agent_forwarding_flag = 0;
+               auth_opts->permit_x11_forwarding_flag = 0;
        } else {
-               no_port_forwarding_flag &= ~2;
-               no_agent_forwarding_flag &= ~2;
-               no_x11_forwarding_flag &= ~2;
+               if (saved_port)
+                       auth_opts->permit_port_forwarding_flag = saved_port;
+               if (saved_agent)
+                       auth_opts->permit_agent_forwarding_flag = saved_agent;
+               if (saved_x11)
+                       auth_opts->permit_x11_forwarding_flag = saved_x11;
        }
 }
 
 /* Import regular and PAM environment from subprocess */
 static void
-import_environments(Buffer *b)
+import_environments(struct sshbuf *b)
 {
        char *env;
-       u_int i, num_env;
-       int err;
+       u_int n, i, num_env;
+       int r;
 
        debug3("PAM: %s entering", __func__);
 
 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
        /* Import variables set by do_pam_account */
-       sshpam_account_status = buffer_get_int(b);
-       sshpam_password_change_required(buffer_get_int(b));
+       if ((r = sshbuf_get_u32(b, &n)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       if (n > INT_MAX)
+               fatal("%s: invalid PAM account status %u", __func__, n);
+       sshpam_account_status = (int)n;
+       if ((r = sshbuf_get_u32(b, &n)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       sshpam_password_change_required(n != 0);
 
        /* Import environment from subprocess */
-       num_env = buffer_get_int(b);
+       if ((r = sshbuf_get_u32(b, &num_env)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
        if (num_env > 1024)
                fatal("%s: received %u environment variables, expected <= 1024",
                    __func__, num_env);
        sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
        debug3("PAM: num env strings %d", num_env);
-       for(i = 0; i < num_env; i++)
-               sshpam_env[i] = buffer_get_string(b, NULL);
-
+       for(i = 0; i < num_env; i++) {
+               if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       }
        sshpam_env[num_env] = NULL;
 
        /* Import PAM environment from subprocess */
-       num_env = buffer_get_int(b);
+       if ((r = sshbuf_get_u32(b, &num_env)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
        debug("PAM: num PAM env strings %d", num_env);
-       for(i = 0; i < num_env; i++) {
-               env = buffer_get_string(b, NULL);
-
+       for (i = 0; i < num_env; i++) {
+               if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
 #ifdef HAVE_PAM_PUTENV
                /* Errors are not fatal here */
-               if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
+               if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
                        error("PAM: pam_putenv: %s",
-                           pam_strerror(sshpam_handle, sshpam_err));
+                           pam_strerror(sshpam_handle, r));
                }
 #endif
+               /* XXX leak env? */
        }
 #endif
 }
@@ -353,10 +379,11 @@ static int
 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
     struct pam_response **resp, void *data)
 {
-       Buffer buffer;
+       struct sshbuf *buffer;
        struct pam_ctxt *ctxt;
        struct pam_response *reply;
-       int i;
+       int r, i;
+       u_char status;
 
        debug3("PAM: %s entering, %d messages", __func__, n);
        *resp = NULL;
@@ -370,38 +397,52 @@ sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
                return (PAM_CONV_ERR);
 
        if ((reply = calloc(n, sizeof(*reply))) == NULL)
-               return (PAM_CONV_ERR);
+               return PAM_CONV_ERR;
+       if ((buffer = sshbuf_new()) == NULL) {
+               free(reply);
+               return PAM_CONV_ERR;
+       }
 
-       buffer_init(&buffer);
        for (i = 0; i < n; ++i) {
                switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
                case PAM_PROMPT_ECHO_OFF:
                case PAM_PROMPT_ECHO_ON:
-                       buffer_put_cstring(&buffer,
-                           PAM_MSG_MEMBER(msg, i, msg));
+                       if ((r = sshbuf_put_cstring(buffer,
+                           PAM_MSG_MEMBER(msg, i, msg))) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
                        if (ssh_msg_send(ctxt->pam_csock,
-                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                           PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
                                goto fail;
-                       if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
+
+                       if (ssh_msg_recv(ctxt->pam_csock, buffer) == -1)
                                goto fail;
-                       if (buffer_get_char(&buffer) != PAM_AUTHTOK)
+                       if ((r = sshbuf_get_u8(buffer, &status)) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
+                       if (status != PAM_AUTHTOK)
                                goto fail;
-                       reply[i].resp = buffer_get_string(&buffer, NULL);
+                       if ((r = sshbuf_get_cstring(buffer,
+                           &reply[i].resp, NULL)) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
                        break;
                case PAM_ERROR_MSG:
                case PAM_TEXT_INFO:
-                       buffer_put_cstring(&buffer,
-                           PAM_MSG_MEMBER(msg, i, msg));
+                       if ((r = sshbuf_put_cstring(buffer,
+                           PAM_MSG_MEMBER(msg, i, msg))) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
                        if (ssh_msg_send(ctxt->pam_csock,
-                           PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
+                           PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1)
                                goto fail;
                        break;
                default:
                        goto fail;
                }
-               buffer_clear(&buffer);
+               sshbuf_reset(buffer);
        }
-       buffer_free(&buffer);
+       sshbuf_free(buffer);
        *resp = reply;
        return (PAM_SUCCESS);
 
@@ -410,7 +451,7 @@ sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
                free(reply[i].resp);
        }
        free(reply);
-       buffer_free(&buffer);
+       sshbuf_free(buffer);
        return (PAM_CONV_ERR);
 }
 
@@ -421,9 +462,9 @@ static void *
 sshpam_thread(void *ctxtp)
 {
        struct pam_ctxt *ctxt = ctxtp;
-       Buffer buffer;
+       struct sshbuf *buffer = NULL;
        struct pam_conv sshpam_conv;
-       int flags = (options.permit_empty_passwd == 0 ?
+       int r, flags = (options.permit_empty_passwd == 0 ?
            PAM_DISALLOW_NULL_AUTHTOK : 0);
 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
        extern char **environ;
@@ -456,7 +497,9 @@ sshpam_thread(void *ctxtp)
        if (sshpam_authctxt == NULL)
                fatal("%s: PAM authctxt not initialized", __func__);
 
-       buffer_init(&buffer);
+       if ((buffer = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
+
        sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
            (const void *)&sshpam_conv);
        if (sshpam_err != PAM_SUCCESS)
@@ -479,45 +522,59 @@ sshpam_thread(void *ctxtp)
                sshpam_password_change_required(0);
        }
 
-       buffer_put_cstring(&buffer, "OK");
+       if ((r = sshbuf_put_cstring(buffer, "OK")) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
 
 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
        /* Export variables set by do_pam_account */
-       buffer_put_int(&buffer, sshpam_account_status);
-       buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
+       if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 ||
+           (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
 
        /* Export any environment strings set in child */
-       for(i = 0; environ[i] != NULL; i++)
-               ; /* Count */
-       buffer_put_int(&buffer, i);
-       for(i = 0; environ[i] != NULL; i++)
-               buffer_put_cstring(&buffer, environ[i]);
-
+       for (i = 0; environ[i] != NULL; i++) {
+               /* Count */
+               if (i > INT_MAX)
+                       fatal("%s: too many enviornment strings", __func__);
+       }
+       if ((r = sshbuf_put_u32(buffer, i)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       for (i = 0; environ[i] != NULL; i++) {
+               if ((r = sshbuf_put_cstring(buffer, environ[i])) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       }
        /* Export any environment strings set by PAM in child */
        env_from_pam = pam_getenvlist(sshpam_handle);
-       for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
-               ; /* Count */
-       buffer_put_int(&buffer, i);
-       for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
-               buffer_put_cstring(&buffer, env_from_pam[i]);
+       for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
+               /* Count */
+               if (i > INT_MAX)
+                       fatal("%s: too many PAM enviornment strings", __func__);
+       }
+       if ((r = sshbuf_put_u32(buffer, i)) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       for (i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) {
+               if ((r = sshbuf_put_cstring(buffer, env_from_pam[i])) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       }
 #endif /* UNSUPPORTED_POSIX_THREADS_HACK */
 
        /* XXX - can't do much about an error here */
-       ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
-       buffer_free(&buffer);
+       ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer);
+       sshbuf_free(buffer);
        pthread_exit(NULL);
 
  auth_fail:
-       buffer_put_cstring(&buffer,
-           pam_strerror(sshpam_handle, sshpam_err));
+       if ((r = sshbuf_put_cstring(buffer,
+           pam_strerror(sshpam_handle, sshpam_err))) != 0)
+               fatal("%s: buffer error: %s", __func__, ssh_err(r));
        /* XXX - can't do much about an error here */
        if (sshpam_err == PAM_ACCT_EXPIRED)
-               ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer);
+               ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer);
        else if (sshpam_maxtries_reached)
-               ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer);
+               ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer);
        else
-               ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
-       buffer_free(&buffer);
+               ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, buffer);
+       sshbuf_free(buffer);
        pthread_exit(NULL);
 
        return (NULL); /* Avoid warning for non-pthread case */
@@ -554,8 +611,7 @@ sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
     struct pam_response **resp, void *data)
 {
        struct pam_response *reply;
-       int i;
-       size_t len;
+       int r, i;
 
        debug3("PAM: %s called with %d messages", __func__, n);
        *resp = NULL;
@@ -570,9 +626,10 @@ sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
                switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
                case PAM_ERROR_MSG:
                case PAM_TEXT_INFO:
-                       len = strlen(PAM_MSG_MEMBER(msg, i, msg));
-                       buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
-                       buffer_append(&loginmsg, "\n", 1 );
+                       if ((r = sshbuf_putf(loginmsg, "%s\n",
+                           PAM_MSG_MEMBER(msg, i, msg))) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
                        reply[i].resp_retcode = PAM_SUCCESS;
                        break;
                default:
@@ -615,13 +672,17 @@ sshpam_cleanup(void)
 }
 
 static int
-sshpam_init(Authctxt *authctxt)
+sshpam_init(struct ssh *ssh, Authctxt *authctxt)
 {
-       const char *pam_rhost, *pam_user, *user = authctxt->user;
+       const char *pam_user, *user = authctxt->user;
        const char **ptr_pam_user = &pam_user;
-       struct ssh *ssh = active_state; /* XXX */
 
-       if (sshpam_handle != NULL) {
+       if (sshpam_handle == NULL) {
+               if (ssh == NULL) {
+                       fatal("%s: called initially with no "
+                           "packet context", __func__);
+               }
+       } if (sshpam_handle != NULL) {
                /* We already have a PAM context; check if the user matches */
                sshpam_err = pam_get_item(sshpam_handle,
                    PAM_USER, (sshpam_const void **)ptr_pam_user);
@@ -640,14 +701,33 @@ sshpam_init(Authctxt *authctxt)
                sshpam_handle = NULL;
                return (-1);
        }
-       pam_rhost = auth_get_canonical_hostname(ssh, options.use_dns);
-       debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
-       sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
-       if (sshpam_err != PAM_SUCCESS) {
-               pam_end(sshpam_handle, sshpam_err);
-               sshpam_handle = NULL;
-               return (-1);
+
+       if (ssh != NULL && sshpam_rhost == NULL) {
+               /*
+                * We need to cache these as we don't have packet context
+                * during the kbdint flow.
+                */
+               sshpam_rhost = xstrdup(auth_get_canonical_hostname(ssh,
+                   options.use_dns));
+               sshpam_laddr = get_local_ipaddr(
+                   ssh_packet_get_connection_in(ssh));
+               xasprintf(&sshpam_conninfo, "SSH_CONNECTION=%.50s %d %.50s %d",
+                   ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
+                   sshpam_laddr, ssh_local_port(ssh));
        }
+       if (sshpam_rhost != NULL) {
+               debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost);
+               sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST,
+                   sshpam_rhost);
+               if (sshpam_err != PAM_SUCCESS) {
+                       pam_end(sshpam_handle, sshpam_err);
+                       sshpam_handle = NULL;
+                       return (-1);
+               }
+               /* Put SSH_CONNECTION in the PAM environment too */
+               pam_putenv(sshpam_handle, sshpam_conninfo);
+       }
+
 #ifdef PAM_TTY_KLUDGE
        /*
         * Some silly PAM modules (e.g. pam_time) require a TTY to operate.
@@ -665,6 +745,27 @@ sshpam_init(Authctxt *authctxt)
        return (0);
 }
 
+static void
+expose_authinfo(const char *caller)
+{
+       char *auth_info;
+
+       /*
+        * Expose authentication information to PAM.
+        * The environment 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);
+}
+
 static void *
 sshpam_init_ctx(Authctxt *authctxt)
 {
@@ -680,11 +781,12 @@ sshpam_init_ctx(Authctxt *authctxt)
                return NULL;
 
        /* Initialize PAM */
-       if (sshpam_init(authctxt) == -1) {
+       if (sshpam_init(NULL, authctxt) == -1) {
                error("PAM: initialization failed");
                return (NULL);
        }
 
+       expose_authinfo(__func__);
        ctxt = xcalloc(1, sizeof *ctxt);
 
        /* Start the authentication thread */
@@ -711,26 +813,27 @@ static int
 sshpam_query(void *ctx, char **name, char **info,
     u_int *num, char ***prompts, u_int **echo_on)
 {
-       struct ssh *ssh = active_state; /* XXX */
-       Buffer buffer;
+       struct sshbuf *buffer;
        struct pam_ctxt *ctxt = ctx;
        size_t plen;
        u_char type;
        char *msg;
        size_t len, mlen;
+       int r;
 
        debug3("PAM: %s entering", __func__);
-       buffer_init(&buffer);
+       if ((buffer = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
        *name = xstrdup("");
        *info = xstrdup("");
        *prompts = xmalloc(sizeof(char *));
        **prompts = NULL;
        plen = 0;
        *echo_on = xmalloc(sizeof(u_int));
-       while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
-               type = buffer_get_char(&buffer);
-               msg = buffer_get_string(&buffer, NULL);
-               mlen = strlen(msg);
+       while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) {
+               if ((r = sshbuf_get_u8(buffer, &type)) != 0 ||
+                   (r = sshbuf_get_cstring(buffer, &msg, &mlen)) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
                switch (type) {
                case PAM_PROMPT_ECHO_ON:
                case PAM_PROMPT_ECHO_OFF:
@@ -776,8 +879,10 @@ sshpam_query(void *ctx, char **name, char **info,
                        if (**prompts != NULL) {
                                /* drain any accumulated messages */
                                debug("PAM: %s", **prompts);
-                               buffer_append(&loginmsg, **prompts,
-                                   strlen(**prompts));
+                               if ((r = sshbuf_put(loginmsg, **prompts,
+                                   strlen(**prompts))) != 0)
+                                       fatal("%s: buffer error: %s",
+                                           __func__, ssh_err(r));
                                free(**prompts);
                                **prompts = NULL;
                        }
@@ -788,7 +893,7 @@ sshpam_query(void *ctx, char **name, char **info,
                                        fatal("Internal error: PAM auth "
                                            "succeeded when it should have "
                                            "failed");
-                               import_environments(&buffer);
+                               import_environments(buffer);
                                *num = 0;
                                **echo_on = 0;
                                ctxt->pam_done = 1;
@@ -797,8 +902,7 @@ sshpam_query(void *ctx, char **name, char **info,
                        }
                        error("PAM: %s for %s%.100s from %.100s", msg,
                            sshpam_authctxt->valid ? "" : "illegal user ",
-                           sshpam_authctxt->user,
-                           auth_get_canonical_hostname(ssh, options.use_dns));
+                           sshpam_authctxt->user, sshpam_rhost);
                        /* FALLTHROUGH */
                default:
                        *num = 0;
@@ -839,9 +943,10 @@ fake_password(const char *wire_password)
 static int
 sshpam_respond(void *ctx, u_int num, char **resp)
 {
-       Buffer buffer;
+       struct sshbuf *buffer;
        struct pam_ctxt *ctxt = ctx;
        char *fake;
+       int r;
 
        debug2("PAM: %s entering, %u responses", __func__, num);
        switch (ctxt->pam_done) {
@@ -857,21 +962,24 @@ sshpam_respond(void *ctx, u_int num, char **resp)
                error("PAM: expected one response, got %u", num);
                return (-1);
        }
-       buffer_init(&buffer);
+       if ((buffer = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
        if (sshpam_authctxt->valid &&
            (sshpam_authctxt->pw->pw_uid != 0 ||
-           options.permit_root_login == PERMIT_YES))
-               buffer_put_cstring(&buffer, *resp);
-       else {
+           options.permit_root_login == PERMIT_YES)) {
+               if ((r = sshbuf_put_cstring(buffer, *resp)) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
+       } else {
                fake = fake_password(*resp);
-               buffer_put_cstring(&buffer, fake);
+               if ((r = sshbuf_put_cstring(buffer, fake)) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
                free(fake);
        }
-       if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
-               buffer_free(&buffer);
+       if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, buffer) == -1) {
+               sshbuf_free(buffer);
                return (-1);
        }
-       buffer_free(&buffer);
+       sshbuf_free(buffer);
        return (1);
 }
 
@@ -911,12 +1019,14 @@ KbdintDevice mm_sshpam_device = {
  * This replaces auth-pam.c
  */
 void
-start_pam(Authctxt *authctxt)
+start_pam(struct ssh *ssh)
 {
+       Authctxt *authctxt = (Authctxt *)ssh->authctxt;
+
        if (!options.use_pam)
                fatal("PAM: initialisation requested when UsePAM=no");
 
-       if (sshpam_init(authctxt) == -1)
+       if (sshpam_init(ssh, authctxt) == -1)
                fatal("PAM: initialisation failed");
 }
 
@@ -926,26 +1036,6 @@ 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)
@@ -1077,7 +1167,7 @@ do_pam_chauthtok(void)
 }
 
 void
-do_pam_session(void)
+do_pam_session(struct ssh *ssh)
 {
        debug3("PAM: opening session");
 
@@ -1093,7 +1183,7 @@ do_pam_session(void)
                sshpam_session_open = 1;
        else {
                sshpam_session_open = 0;
-               disable_forwarding();
+               auth_restrict_session(ssh);
                error("PAM: pam_open_session(): %s",
                    pam_strerror(sshpam_handle, sshpam_err));
        }
@@ -1165,7 +1255,7 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
     struct pam_response **resp, void *data)
 {
        struct pam_response *reply;
-       int i;
+       int r, i;
        size_t len;
 
        debug3("PAM: %s called with %d messages", __func__, n);
@@ -1191,9 +1281,10 @@ sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
                case PAM_TEXT_INFO:
                        len = strlen(PAM_MSG_MEMBER(msg, i, msg));
                        if (len > 0) {
-                               buffer_append(&loginmsg,
-                                   PAM_MSG_MEMBER(msg, i, msg), len);
-                               buffer_append(&loginmsg, "\n", 1);
+                               if ((r = sshbuf_putf(loginmsg, "%s\n",
+                                   PAM_MSG_MEMBER(msg, i, msg))) != 0)
+                                       fatal("%s: buffer error: %s",
+                                           __func__, ssh_err(r));
                        }
                        if ((reply[i].resp = strdup("")) == NULL)
                                goto fail;
index c47b442..9fcea27 100644 (file)
 #include "includes.h"
 #ifdef USE_PAM
 
-void start_pam(Authctxt *);
+struct ssh;
+
+void start_pam(struct ssh *);
 void finish_pam(void);
 u_int do_pam_account(void);
-void do_pam_session(void);
+void do_pam_session(struct ssh *);
 void do_pam_setcred(int );
 void do_pam_chauthtok(void);
 int do_pam_putenv(char *, char *);
index 996c2cf..24fcb67 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-passwd.c,v 1.45 2016/07/21 01:39:35 dtucker Exp $ */
+/* $OpenBSD: auth-passwd.c,v 1.47 2018/07/09 21:26:02 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include <stdarg.h>
 
 #include "packet.h"
-#include "buffer.h"
+#include "sshbuf.h"
+#include "ssherr.h"
 #include "log.h"
 #include "misc.h"
 #include "servconf.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "auth-options.h"
 
-extern Buffer loginmsg;
+extern struct sshbuf *loginmsg;
 extern ServerOptions options;
 
 #ifdef HAVE_LOGIN_CAP
@@ -68,22 +69,15 @@ extern login_cap_t *lc;
 
 #define MAX_PASSWORD_LEN       1024
 
-void
-disable_forwarding(void)
-{
-       no_port_forwarding_flag = 1;
-       no_agent_forwarding_flag = 1;
-       no_x11_forwarding_flag = 1;
-}
-
 /*
  * Tries to authenticate the user using password.  Returns true if
  * authentication succeeds.
  */
 int
-auth_password(Authctxt *authctxt, const char *password)
+auth_password(struct ssh *ssh, const char *password)
 {
-       struct passwd * pw = authctxt->pw;
+       Authctxt *authctxt = ssh->authctxt;
+       struct passwd *pw = authctxt->pw;
        int result, ok = authctxt->valid;
 #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
        static int expire_checked = 0;
@@ -128,9 +122,9 @@ auth_password(Authctxt *authctxt, const char *password)
                        authctxt->force_pwchange = 1;
        }
 #endif
-       result = sys_auth_passwd(authctxt, password);
+       result = sys_auth_passwd(ssh, password);
        if (authctxt->force_pwchange)
-               disable_forwarding();
+               auth_restrict_session(ssh);
        return (result && ok);
 }
 
@@ -138,7 +132,7 @@ auth_password(Authctxt *authctxt, const char *password)
 static void
 warn_expiry(Authctxt *authctxt, auth_session_t *as)
 {
-       char buf[256];
+       int r;
        quad_t pwtimeleft, actimeleft, daysleft, pwwarntime, acwarntime;
 
        pwwarntime = acwarntime = TWO_WEEKS;
@@ -155,34 +149,34 @@ warn_expiry(Authctxt *authctxt, auth_session_t *as)
 #endif
        if (pwtimeleft != 0 && pwtimeleft < pwwarntime) {
                daysleft = pwtimeleft / DAY + 1;
-               snprintf(buf, sizeof(buf),
+               if ((r = sshbuf_putf(loginmsg,
                    "Your password will expire in %lld day%s.\n",
-                   daysleft, daysleft == 1 ? "" : "s");
-               buffer_append(&loginmsg, buf, strlen(buf));
+                   daysleft, daysleft == 1 ? "" : "s")) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
        }
        if (actimeleft != 0 && actimeleft < acwarntime) {
                daysleft = actimeleft / DAY + 1;
-               snprintf(buf, sizeof(buf),
+               if ((r = sshbuf_putf(loginmsg,
                    "Your account will expire in %lld day%s.\n",
-                   daysleft, daysleft == 1 ? "" : "s");
-               buffer_append(&loginmsg, buf, strlen(buf));
+                   daysleft, daysleft == 1 ? "" : "s")) != 0)
+                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
        }
 }
 
 int
-sys_auth_passwd(Authctxt *authctxt, const char *password)
+sys_auth_passwd(struct ssh *ssh, const char *password)
 {
-       struct passwd *pw = authctxt->pw;
+       Authctxt *authctxt = ssh->authctxt;
        auth_session_t *as;
        static int expire_checked = 0;
 
-       as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh",
+       as = auth_usercheck(authctxt->pw->pw_name, authctxt->style, "auth-ssh",
            (char *)password);
        if (as == NULL)
                return (0);
        if (auth_getstate(as) & AUTH_PWEXPIRED) {
                auth_close(as);
-               disable_forwarding();
+               auth_restrict_session(ssh);
                authctxt->force_pwchange = 1;
                return (1);
        } else {
@@ -195,14 +189,18 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
 }
 #elif !defined(CUSTOM_SYS_AUTH_PASSWD)
 int
-sys_auth_passwd(Authctxt *authctxt, const char *password)
+sys_auth_passwd(struct ssh *ssh, const char *password)
 {
+       Authctxt *authctxt = ssh->authctxt;
        struct passwd *pw = authctxt->pw;
        char *encrypted_password, *salt = NULL;
 
        /* Just use the supplied fake password if authctxt is invalid */
        char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd;
 
+       if (pw_password == NULL)
+               return 0;
+
        /* Check for users with no password. */
        if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0)
                return (1);
index ecf956f..57296e1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rhosts.c,v 1.48 2016/08/13 17:47:41 markus Exp $ */
+/* $OpenBSD: auth-rhosts.c,v 1.49 2018/07/09 21:35:50 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -34,8 +34,8 @@
 #include "pathnames.h"
 #include "log.h"
 #include "misc.h"
-#include "buffer.h" /* XXX */
-#include "key.h" /* XXX */
+#include "sshbuf.h"
+#include "sshkey.h"
 #include "servconf.h"
 #include "canohost.h"
 #include "sshkey.h"
diff --git a/crypto/openssh/auth-shadow.c b/crypto/openssh/auth-shadow.c
deleted file mode 100644 (file)
index 2190916..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2004 Darren Tucker.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
-#include <shadow.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "buffer.h"
-#include "log.h"
-
-#ifdef DAY
-# undef DAY
-#endif
-#define DAY    (24L * 60 * 60) /* 1 day in seconds */
-
-extern Buffer loginmsg;
-
-/*
- * For the account and password expiration functions, we assume the expiry
- * occurs the day after the day specified.
- */
-
-/*
- * Check if specified account is expired.  Returns 1 if account is expired,
- * 0 otherwise.
- */
-int
-auth_shadow_acctexpired(struct spwd *spw)
-{
-       time_t today;
-       int daysleft;
-       char buf[256];
-
-       today = time(NULL) / DAY;
-       daysleft = spw->sp_expire - today;
-       debug3("%s: today %d sp_expire %d days left %d", __func__, (int)today,
-           (int)spw->sp_expire, daysleft);
-
-       if (spw->sp_expire == -1) {
-               debug3("account expiration disabled");
-       } else if (daysleft < 0) {
-               logit("Account %.100s has expired", spw->sp_namp);
-               return 1;
-       } else if (daysleft <= spw->sp_warn) {
-               debug3("account will expire in %d days", daysleft);
-               snprintf(buf, sizeof(buf),
-                   "Your account will expire in %d day%s.\n", daysleft,
-                   daysleft == 1 ? "" : "s");
-               buffer_append(&loginmsg, buf, strlen(buf));
-       }
-
-       return 0;
-}
-
-/*
- * Checks password expiry for platforms that use shadow passwd files.
- * Returns: 1 = password expired, 0 = password not expired
- */
-int
-auth_shadow_pwexpired(Authctxt *ctxt)
-{
-       struct spwd *spw = NULL;
-       const char *user = ctxt->pw->pw_name;
-       char buf[256];
-       time_t today;
-       int daysleft, disabled = 0;
-
-       if ((spw = getspnam((char *)user)) == NULL) {
-               error("Could not get shadow information for %.100s", user);
-               return 0;
-       }
-
-       today = time(NULL) / DAY;
-       debug3("%s: today %d sp_lstchg %d sp_max %d", __func__, (int)today,
-           (int)spw->sp_lstchg, (int)spw->sp_max);
-
-#if defined(__hpux) && !defined(HAVE_SECUREWARE)
-       if (iscomsec()) {
-               struct pr_passwd *pr;
-
-               pr = getprpwnam((char *)user);
-
-               /* Test for Trusted Mode expiry disabled */
-               if (pr != NULL && pr->ufld.fd_min == 0 &&
-                   pr->ufld.fd_lifetime == 0 && pr->ufld.fd_expire == 0 &&
-                   pr->ufld.fd_pw_expire_warning == 0 &&
-                   pr->ufld.fd_schange != 0)
-                       disabled = 1;
-       }
-#endif
-
-       /* TODO: check sp_inact */
-       daysleft = spw->sp_lstchg + spw->sp_max - today;
-       if (disabled) {
-               debug3("password expiration disabled");
-       } else if (spw->sp_lstchg == 0) {
-               logit("User %.100s password has expired (root forced)", user);
-               return 1;
-       } else if (spw->sp_max == -1) {
-               debug3("password expiration disabled");
-       } else if (daysleft < 0) {
-               logit("User %.100s password has expired (password aged)", user);
-               return 1;
-       } else if (daysleft <= spw->sp_warn) {
-               debug3("password will expire in %d days", daysleft);
-               snprintf(buf, sizeof(buf),
-                   "Your password will expire in %d day%s.\n", daysleft,
-                   daysleft == 1 ? "" : "s");
-               buffer_append(&loginmsg, buf, strlen(buf));
-       }
-
-       return 0;
-}
-#endif /* USE_SHADOW && HAS_SHADOW_EXPIRE */
diff --git a/crypto/openssh/auth-sia.c b/crypto/openssh/auth-sia.c
deleted file mode 100644 (file)
index a9e1c25..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2002 Chris Adams.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef HAVE_OSF_SIA
-#include <sia.h>
-#include <siad.h>
-#include <pwd.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sys/resource.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "ssh.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "auth-sia.h"
-#include "log.h"
-#include "servconf.h"
-#include "canohost.h"
-#include "uidswap.h"
-
-extern ServerOptions options;
-extern int saved_argc;
-extern char **saved_argv;
-
-int
-sys_auth_passwd(Authctxt *authctxt, const char *pass)
-{
-       int ret;
-       SIAENTITY *ent = NULL;
-       const char *host;
-
-       host = get_canonical_hostname(options.use_dns);
-
-       if (!authctxt->user || pass == NULL || pass[0] == '\0')
-               return (0);
-
-       if (sia_ses_init(&ent, saved_argc, saved_argv, host, authctxt->user,
-           NULL, 0, NULL) != SIASUCCESS)
-               return (0);
-
-       if ((ret = sia_ses_authent(NULL, pass, ent)) != SIASUCCESS) {
-               error("Couldn't authenticate %s from %s",
-                   authctxt->user, host);
-               if (ret & SIASTOP)
-                       sia_ses_release(&ent);
-
-               return (0);
-       }
-
-       sia_ses_release(&ent);
-
-       return (1);
-}
-
-void
-session_setup_sia(struct passwd *pw, char *tty)
-{
-       SIAENTITY *ent = NULL;
-       const char *host;
-
-       host = get_canonical_hostname(options.use_dns);
-
-       if (sia_ses_init(&ent, saved_argc, saved_argv, host, pw->pw_name,
-           tty, 0, NULL) != SIASUCCESS)
-               fatal("sia_ses_init failed");
-
-       if (sia_make_entity_pwd(pw, ent) != SIASUCCESS) {
-               sia_ses_release(&ent);
-               fatal("sia_make_entity_pwd failed");
-       }
-
-       ent->authtype = SIA_A_NONE;
-       if (sia_ses_estab(sia_collect_trm, ent) != SIASUCCESS)
-               fatal("Couldn't establish session for %s from %s",
-                   pw->pw_name, host);
-
-       if (sia_ses_launch(sia_collect_trm, ent) != SIASUCCESS)
-               fatal("Couldn't launch session for %s from %s",
-                   pw->pw_name, host);
-
-       sia_ses_release(&ent);
-
-       setuid(0);
-       permanently_set_uid(pw);
-}
-
-#endif /* HAVE_OSF_SIA */
diff --git a/crypto/openssh/auth-sia.h b/crypto/openssh/auth-sia.h
deleted file mode 100644 (file)
index 27cbb93..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2002 Chris Adams.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef HAVE_OSF_SIA
-
-void   session_setup_sia(struct passwd *, char *);
-
-#endif /* HAVE_OSF_SIA */
diff --git a/crypto/openssh/auth-skey.c b/crypto/openssh/auth-skey.c
deleted file mode 100644 (file)
index 3536ec8..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/* $OpenBSD: auth-skey.c,v 1.27 2007/01/21 01:41:54 stevesk Exp $ */
-/*
- * Copyright (c) 2001 Markus Friedl.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef SKEY
-
-#include <sys/types.h>
-
-#include <pwd.h>
-#include <stdio.h>
-
-#include <skey.h>
-
-#include "xmalloc.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "ssh-gss.h"
-#include "log.h"
-#include "monitor_wrap.h"
-
-static void *
-skey_init_ctx(Authctxt *authctxt)
-{
-       return authctxt;
-}
-
-int
-skey_query(void *ctx, char **name, char **infotxt,
-    u_int* numprompts, char ***prompts, u_int **echo_on)
-{
-       Authctxt *authctxt = ctx;
-       char challenge[1024];
-       struct skey skey;
-
-       if (_compat_skeychallenge(&skey, authctxt->user, challenge,
-           sizeof(challenge)) == -1)
-               return -1;
-
-       *name = xstrdup("");
-       *infotxt = xstrdup("");
-       *numprompts = 1;
-       *prompts = xcalloc(*numprompts, sizeof(char *));
-       *echo_on = xcalloc(*numprompts, sizeof(u_int));
-
-       xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
-
-       return 0;
-}
-
-int
-skey_respond(void *ctx, u_int numresponses, char **responses)
-{
-       Authctxt *authctxt = ctx;
-
-       if (authctxt->valid &&
-           numresponses == 1 &&
-           skey_haskey(authctxt->pw->pw_name) == 0 &&
-           skey_passcheck(authctxt->pw->pw_name, responses[0]) != -1)
-           return 0;
-       return -1;
-}
-
-static void
-skey_free_ctx(void *ctx)
-{
-       /* we don't have a special context */
-}
-
-KbdintDevice skey_device = {
-       "skey",
-       skey_init_ctx,
-       skey_query,
-       skey_respond,
-       skey_free_ctx
-};
-
-KbdintDevice mm_skey_device = {
-       "skey",
-       skey_init_ctx,
-       mm_skey_query,
-       mm_skey_respond,
-       skey_free_ctx
-};
-#endif /* SKEY */
index a449061..8696f25 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.138 2019/01/19 21:41:18 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
+#include <sys/wait.h>
 
 #include <netinet/in.h>
 
 #include <unistd.h>
 #include <limits.h>
 #include <netdb.h>
+#include <time.h>
 
 #include "xmalloc.h"
 #include "match.h"
 #include "groupaccess.h"
 #include "log.h"
-#include "buffer.h"
+#include "sshbuf.h"
 #include "misc.h"
 #include "servconf.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "auth-options.h"
 #include "authfile.h"
 #include "ssherr.h"
 #include "compat.h"
+#include "channels.h"
 
 /* import */
 extern ServerOptions options;
 extern int use_privsep;
-extern Buffer loginmsg;
+extern struct sshbuf *loginmsg;
 extern struct passwd *privsep_pw;
+extern struct sshauthopt *auth_opts;
 
 /* Debugging messages */
-Buffer auth_debug;
-int auth_debug_init;
+static struct sshbuf *auth_debug;
 
 /*
  * Check if the user is allowed to log in via ssh. If user is listed
@@ -94,9 +97,8 @@ int auth_debug_init;
  * Otherwise true is returned.
  */
 int
-allowed_user(struct passwd * pw)
+allowed_user(struct ssh *ssh, struct passwd * pw)
 {
-       struct ssh *ssh = active_state; /* XXX */
        struct stat st;
        const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL;
        u_int i;
@@ -256,7 +258,7 @@ allowed_user(struct passwd * pw)
        }
 
 #ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
-       if (!sys_auth_allowed_user(pw, &loginmsg))
+       if (!sys_auth_allowed_user(pw, loginmsg))
                return 0;
 #endif
 
@@ -273,22 +275,26 @@ format_method_key(Authctxt *authctxt)
 {
        const struct sshkey *key = authctxt->auth_method_key;
        const char *methinfo = authctxt->auth_method_info;
-       char *fp, *ret = NULL;
+       char *fp, *cafp, *ret = NULL;
 
        if (key == NULL)
                return NULL;
 
-       if (key_is_cert(key)) {
-               fp = sshkey_fingerprint(key->cert->signature_key,
+       if (sshkey_is_cert(key)) {
+               fp = sshkey_fingerprint(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,
+               cafp = sshkey_fingerprint(key->cert->signature_key,
+                   options.fingerprint_hash, SSH_FP_DEFAULT);
+               xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
+                   sshkey_type(key), fp == NULL ? "(null)" : fp,
+                   key->cert->key_id,
                    (unsigned long long)key->cert->serial,
                    sshkey_type(key->cert->signature_key),
-                   fp == NULL ? "(null)" : fp,
+                   cafp == NULL ? "(null)" : cafp,
                    methinfo == NULL ? "" : ", ",
                    methinfo == NULL ? "" : methinfo);
                free(fp);
+               free(cafp);
        } else {
                fp = sshkey_fingerprint(key, options.fingerprint_hash,
                    SSH_FP_DEFAULT);
@@ -302,11 +308,11 @@ format_method_key(Authctxt *authctxt)
 }
 
 void
-auth_log(Authctxt *authctxt, int authenticated, int partial,
+auth_log(struct ssh *ssh, int authenticated, int partial,
     const char *method, const char *submethod)
 {
-       struct ssh *ssh = active_state; /* XXX */
-       void (*authlog) (const char *fmt,...) = verbose;
+       Authctxt *authctxt = (Authctxt *)ssh->authctxt;
+       int level = SYSLOG_LEVEL_VERBOSE;
        const char *authmsg;
        char *extra = NULL;
 
@@ -318,7 +324,7 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
            !authctxt->valid ||
            authctxt->failures >= options.max_authtries / 2 ||
            strcmp(method, "password") == 0)
-               authlog = logit;
+               level = SYSLOG_LEVEL_INFO;
 
        if (authctxt->postponed)
                authmsg = "Postponed";
@@ -332,7 +338,7 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
                        extra = xstrdup(authctxt->auth_method_info);
        }
 
-       authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
+       do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
            authmsg,
            method,
            submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
@@ -350,26 +356,26 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
            (strcmp(method, "password") == 0 ||
            strncmp(method, "keyboard-interactive", 20) == 0 ||
            strcmp(method, "challenge-response") == 0))
-               record_failed_login(authctxt->user,
+               record_failed_login(ssh, authctxt->user,
                    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
 # ifdef WITH_AIXAUTHENTICATE
        if (authenticated)
                sys_auth_record_login(authctxt->user,
                    auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
-                   &loginmsg);
+                   loginmsg);
 # endif
 #endif
 #ifdef SSH_AUDIT_EVENTS
        if (authenticated == 0 && !authctxt->postponed)
-               audit_event(audit_classify_auth(method));
+               audit_event(ssh, audit_classify_auth(method));
 #endif
 }
 
 
 void
-auth_maxtries_exceeded(Authctxt *authctxt)
+auth_maxtries_exceeded(struct ssh *ssh)
 {
-       struct ssh *ssh = active_state; /* XXX */
+       Authctxt *authctxt = (Authctxt *)ssh->authctxt;
 
        error("maximum authentication attempts exceeded for "
            "%s%.100s from %.200s port %d ssh2",
@@ -377,7 +383,7 @@ auth_maxtries_exceeded(Authctxt *authctxt)
            authctxt->user,
            ssh_remote_ipaddr(ssh),
            ssh_remote_port(ssh));
-       packet_disconnect("Too many authentication failures");
+       ssh_packet_disconnect(ssh, "Too many authentication failures");
        /* NOTREACHED */
 }
 
@@ -385,10 +391,8 @@ auth_maxtries_exceeded(Authctxt *authctxt)
  * Check whether root logins are disallowed.
  */
 int
-auth_root_allowed(const char *method)
+auth_root_allowed(struct ssh *ssh, const char *method)
 {
-       struct ssh *ssh = active_state; /* XXX */
-
        switch (options.permit_root_login) {
        case PERMIT_YES:
                return 1;
@@ -399,7 +403,7 @@ auth_root_allowed(const char *method)
                        return 1;
                break;
        case PERMIT_FORCED_ONLY:
-               if (forced_command) {
+               if (auth_opts->force_command != NULL) {
                        logit("Root login accepted for forced command.");
                        return 1;
                }
@@ -421,17 +425,19 @@ auth_root_allowed(const char *method)
 char *
 expand_authorized_keys(const char *filename, struct passwd *pw)
 {
-       char *file, ret[PATH_MAX];
+       char *file, uidstr[32], ret[PATH_MAX];
        int i;
 
+       snprintf(uidstr, sizeof(uidstr), "%llu",
+           (unsigned long long)pw->pw_uid);
        file = percent_expand(filename, "h", pw->pw_dir,
-           "u", pw->pw_name, (char *)NULL);
+           "u", pw->pw_name, "U", uidstr, (char *)NULL);
 
        /*
         * Ensure that filename starts anchored. If not, be backward
         * compatible and prepend the '%h/'
         */
-       if (*file == '/')
+       if (path_absolute(file))
                return (file);
 
        i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
@@ -552,9 +558,8 @@ auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
 }
 
 struct passwd *
-getpwnamallow(const char *user)
+getpwnamallow(struct ssh *ssh, const char *user)
 {
-       struct ssh *ssh = active_state; /* XXX */
 #ifdef HAVE_LOGIN_CAP
        extern login_cap_t *lc;
 #ifdef BSD_AUTH
@@ -562,8 +567,9 @@ getpwnamallow(const char *user)
 #endif
 #endif
        struct passwd *pw;
-       struct connection_info *ci = get_connection_info(1, options.use_dns);
+       struct connection_info *ci;
 
+       ci = get_connection_info(ssh, 1, options.use_dns);
        ci->user = user;
        parse_server_match_config(&options, ci);
        log_change_level(options.log_level);
@@ -577,33 +583,20 @@ getpwnamallow(const char *user)
 
 #if defined(_AIX) && defined(HAVE_SETAUTHDB)
        aix_restoreauthdb();
-#endif
-#ifdef HAVE_CYGWIN
-       /*
-        * Windows usernames are case-insensitive.  To avoid later problems
-        * when trying to match the username, the user is only allowed to
-        * login if the username is given in the same case as stored in the
-        * user database.
-        */
-       if (pw != NULL && strcmp(user, pw->pw_name) != 0) {
-               logit("Login name %.100s does not match stored username %.100s",
-                   user, pw->pw_name);
-               pw = NULL;
-       }
 #endif
        if (pw == NULL) {
                logit("Invalid user %.100s from %.100s port %d",
                    user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
 #ifdef CUSTOM_FAILED_LOGIN
-               record_failed_login(user,
+               record_failed_login(ssh, user,
                    auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
 #endif
 #ifdef SSH_AUDIT_EVENTS
-               audit_event(SSH_INVALID_USER);
+               audit_event(ssh, SSH_INVALID_USER);
 #endif /* SSH_AUDIT_EVENTS */
                return (NULL);
        }
-       if (!allowed_user(pw))
+       if (!allowed_user(ssh, pw))
                return (NULL);
 #ifdef HAVE_LOGIN_CAP
        if ((lc = login_getclass(pw->pw_class)) == NULL) {
@@ -669,26 +662,31 @@ auth_debug_add(const char *fmt,...)
 {
        char buf[1024];
        va_list args;
+       int r;
 
-       if (!auth_debug_init)
+       if (auth_debug == NULL)
                return;
 
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
-       buffer_put_cstring(&auth_debug, buf);
+       if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0)
+               fatal("%s: sshbuf_put_cstring: %s", __func__, ssh_err(r));
 }
 
 void
-auth_debug_send(void)
+auth_debug_send(struct ssh *ssh)
 {
        char *msg;
+       int r;
 
-       if (!auth_debug_init)
+       if (auth_debug == NULL)
                return;
-       while (buffer_len(&auth_debug)) {
-               msg = buffer_get_string(&auth_debug, NULL);
-               packet_send_debug("%s", msg);
+       while (sshbuf_len(auth_debug) != 0) {
+               if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0)
+                       fatal("%s: sshbuf_get_cstring: %s",
+                           __func__, ssh_err(r));
+               ssh_packet_send_debug(ssh, "%s", msg);
                free(msg);
        }
 }
@@ -696,12 +694,10 @@ auth_debug_send(void)
 void
 auth_debug_reset(void)
 {
-       if (auth_debug_init)
-               buffer_clear(&auth_debug);
-       else {
-               buffer_init(&auth_debug);
-               auth_debug_init = 1;
-       }
+       if (auth_debug != NULL)
+               sshbuf_reset(auth_debug);
+       else if ((auth_debug = sshbuf_new()) == NULL)
+               fatal("%s: sshbuf_new failed", __func__);
 }
 
 struct passwd *
@@ -840,3 +836,353 @@ auth_get_canonical_hostname(struct ssh *ssh, int use_dns)
                return dnsname;
        }
 }
+
+/*
+ * Runs command in a subprocess with a minimal environment.
+ * Returns pid on success, 0 on failure.
+ * The child stdout and stderr maybe captured, left attached or sent to
+ * /dev/null depending on the contents of flags.
+ * "tag" is prepended to log messages.
+ * NB. "command" is only used for logging; the actual command executed is
+ * av[0].
+ */
+pid_t
+subprocess(const char *tag, struct passwd *pw, const char *command,
+    int ac, char **av, FILE **child, u_int flags)
+{
+       FILE *f = NULL;
+       struct stat st;
+       int fd, devnull, p[2], i;
+       pid_t pid;
+       char *cp, errmsg[512];
+       u_int envsize;
+       char **child_env;
+
+       if (child != NULL)
+               *child = NULL;
+
+       debug3("%s: %s command \"%s\" running as %s (flags 0x%x)", __func__,
+           tag, command, pw->pw_name, flags);
+
+       /* Check consistency */
+       if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
+           (flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0) {
+               error("%s: inconsistent flags", __func__);
+               return 0;
+       }
+       if (((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0) != (child == NULL)) {
+               error("%s: inconsistent flags/output", __func__);
+               return 0;
+       }
+
+       /*
+        * If executing an explicit binary, then verify the it exists
+        * and appears safe-ish to execute
+        */
+       if (!path_absolute(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 (safe_path(av[0], &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) {
+               error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
+               restore_uid();
+               return 0;
+       }
+       /* Prepare to keep the child's stdout if requested */
+       if (pipe(p) != 0) {
+               error("%s: pipe: %s", tag, strerror(errno));
+               restore_uid();
+               return 0;
+       }
+       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);
+               }
+               if (dup2(devnull, STDIN_FILENO) == -1) {
+                       error("%s: dup2: %s", tag, strerror(errno));
+                       _exit(1);
+               }
+
+               /* Set up stdout as requested; leave stderr in place for now. */
+               fd = -1;
+               if ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) != 0)
+                       fd = p[1];
+               else if ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0)
+                       fd = devnull;
+               if (fd != -1 && dup2(fd, 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 ((flags & SSH_SUBPROCESS_STDOUT_DISCARD) != 0 &&
+                   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 ((flags & SSH_SUBPROCESS_STDOUT_CAPTURE) == 0)
+               close(p[0]);
+       else 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);
+       if (child != NULL)
+               *child = f;
+       return pid;
+}
+
+/* These functions link key/cert options to the auth framework */
+
+/* Log sshauthopt options locally and (optionally) for remote transmission */
+void
+auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
+{
+       int do_env = options.permit_user_env && opts->nenv > 0;
+       int do_permitopen = opts->npermitopen > 0 &&
+           (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
+       int do_permitlisten = opts->npermitlisten > 0 &&
+           (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
+       size_t i;
+       char msg[1024], buf[64];
+
+       snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
+       /* Try to keep this alphabetically sorted */
+       snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s",
+           opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
+           opts->force_command == NULL ? "" : " command",
+           do_env ?  " environment" : "",
+           opts->valid_before == 0 ? "" : "expires",
+           do_permitopen ?  " permitopen" : "",
+           do_permitlisten ?  " permitlisten" : "",
+           opts->permit_port_forwarding_flag ? " port-forwarding" : "",
+           opts->cert_principals == NULL ? "" : " principals",
+           opts->permit_pty_flag ? " pty" : "",
+           opts->force_tun_device == -1 ? "" : " tun=",
+           opts->force_tun_device == -1 ? "" : buf,
+           opts->permit_user_rc ? " user-rc" : "",
+           opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
+
+       debug("%s: %s", loc, msg);
+       if (do_remote)
+               auth_debug_add("%s: %s", loc, msg);
+
+       if (options.permit_user_env) {
+               for (i = 0; i < opts->nenv; i++) {
+                       debug("%s: environment: %s", loc, opts->env[i]);
+                       if (do_remote) {
+                               auth_debug_add("%s: environment: %s",
+                                   loc, opts->env[i]);
+                       }
+               }
+       }
+
+       /* Go into a little more details for the local logs. */
+       if (opts->valid_before != 0) {
+               format_absolute_time(opts->valid_before, buf, sizeof(buf));
+               debug("%s: expires at %s", loc, buf);
+       }
+       if (opts->cert_principals != NULL) {
+               debug("%s: authorized principals: \"%s\"",
+                   loc, opts->cert_principals);
+       }
+       if (opts->force_command != NULL)
+               debug("%s: forced command: \"%s\"", loc, opts->force_command);
+       if (do_permitopen) {
+               for (i = 0; i < opts->npermitopen; i++) {
+                       debug("%s: permitted open: %s",
+                           loc, opts->permitopen[i]);
+               }
+       }
+       if (do_permitlisten) {
+               for (i = 0; i < opts->npermitlisten; i++) {
+                       debug("%s: permitted listen: %s",
+                           loc, opts->permitlisten[i]);
+               }
+       }
+}
+
+/* Activate a new set of key/cert options; merging with what is there. */
+int
+auth_activate_options(struct ssh *ssh, struct sshauthopt *opts)
+{
+       struct sshauthopt *old = auth_opts;
+       const char *emsg = NULL;
+
+       debug("%s: setting new authentication options", __func__);
+       if ((auth_opts = sshauthopt_merge(old, opts, &emsg)) == NULL) {
+               error("Inconsistent authentication options: %s", emsg);
+               return -1;
+       }
+       return 0;
+}
+
+/* Disable forwarding, etc for the session */
+void
+auth_restrict_session(struct ssh *ssh)
+{
+       struct sshauthopt *restricted;
+
+       debug("%s: restricting session", __func__);
+
+       /* A blank sshauthopt defaults to permitting nothing */
+       restricted = sshauthopt_new();
+       restricted->permit_pty_flag = 1;
+       restricted->restricted = 1;
+
+       if (auth_activate_options(ssh, restricted) != 0)
+               fatal("%s: failed to restrict session", __func__);
+       sshauthopt_free(restricted);
+}
+
+int
+auth_authorise_keyopts(struct ssh *ssh, struct passwd *pw,
+    struct sshauthopt *opts, int allow_cert_authority, const char *loc)
+{
+       const char *remote_ip = ssh_remote_ipaddr(ssh);
+       const char *remote_host = auth_get_canonical_hostname(ssh,
+           options.use_dns);
+       time_t now = time(NULL);
+       char buf[64];
+
+       /*
+        * Check keys/principals file expiry time.
+        * NB. validity interval in certificate is handled elsewhere.
+        */
+       if (opts->valid_before && now > 0 &&
+           opts->valid_before < (uint64_t)now) {
+               format_absolute_time(opts->valid_before, buf, sizeof(buf));
+               debug("%s: entry expired at %s", loc, buf);
+               auth_debug_add("%s: entry expired at %s", loc, buf);
+               return -1;
+       }
+       /* Consistency checks */
+       if (opts->cert_principals != NULL && !opts->cert_authority) {
+               debug("%s: principals on non-CA key", loc);
+               auth_debug_add("%s: principals on non-CA key", loc);
+               /* deny access */
+               return -1;
+       }
+       /* cert-authority flag isn't valid in authorized_principals files */
+       if (!allow_cert_authority && opts->cert_authority) {
+               debug("%s: cert-authority flag invalid here", loc);
+               auth_debug_add("%s: cert-authority flag invalid here", loc);
+               /* deny access */
+               return -1;
+       }
+
+       /* Perform from= checks */
+       if (opts->required_from_host_keys != NULL) {
+               switch (match_host_and_ip(remote_host, remote_ip,
+                   opts->required_from_host_keys )) {
+               case 1:
+                       /* Host name matches. */
+                       break;
+               case -1:
+               default:
+                       debug("%s: invalid from criteria", loc);
+                       auth_debug_add("%s: invalid from criteria", loc);
+                       /* FALLTHROUGH */
+               case 0:
+                       logit("%s: Authentication tried for %.100s with "
+                           "correct key but not from a permitted "
+                           "host (host=%.200s, ip=%.200s, required=%.200s).",
+                           loc, pw->pw_name, remote_host, remote_ip,
+                           opts->required_from_host_keys);
+                       auth_debug_add("%s: Your host '%.200s' is not "
+                           "permitted to use this key for login.",
+                           loc, remote_host);
+                       /* deny access */
+                       return -1;
+               }
+       }
+       /* Check source-address restriction from certificate */
+       if (opts->required_from_host_cert != NULL) {
+               switch (addr_match_cidr_list(remote_ip,
+                   opts->required_from_host_cert)) {
+               case 1:
+                       /* accepted */
+                       break;
+               case -1:
+               default:
+                       /* invalid */
+                       error("%s: Certificate source-address invalid",
+                           loc);
+                       /* FALLTHROUGH */
+               case 0:
+                       logit("%s: Authentication tried for %.100s with valid "
+                           "certificate but not from a permitted source "
+                           "address (%.200s).", loc, pw->pw_name, remote_ip);
+                       auth_debug_add("%s: Your address '%.200s' is not "
+                           "permitted to use this certificate for login.",
+                           loc, remote_ip);
+                       return -1;
+               }
+       }
+       /*
+        *
+        * XXX this is spammy. We should report remotely only for keys
+        *     that are successful in actual auth attempts, and not PK_OK
+        *     tests.
+        */
+       auth_log_authopts(loc, opts, 1);
+
+       return 0;
+}
index 29835ae..bf393e7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */
+/* $OpenBSD: auth.h,v 1.99 2019/01/19 21:43:56 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
 #include <krb5.h>
 #endif
 
+struct passwd;
 struct ssh;
-struct sshkey;
 struct sshbuf;
+struct sshkey;
+struct sshauthopt;
 
 typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;
@@ -87,7 +89,7 @@ struct Authctxt {
        struct sshkey   **prev_keys;
        u_int            nprev_keys;
 
-       /* Last used key and ancilliary information from active auth method */
+       /* Last used key and ancillary information from active auth method */
        struct sshkey   *auth_method_key;
        char            *auth_method_info;
 
@@ -128,11 +130,12 @@ struct KbdintDevice
 int
 auth_rhosts2(struct passwd *, const char *, const char *, const char *);
 
-int      auth_password(Authctxt *, const char *);
+int      auth_password(struct ssh *, const char *);
 
-int     hostbased_key_allowed(struct passwd *, const char *, char *,
-           struct sshkey *);
-int     user_key_allowed(struct passwd *, struct sshkey *, int);
+int     hostbased_key_allowed(struct ssh *, struct passwd *,
+           const char *, char *, struct sshkey *);
+int     user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int,
+    struct sshauthopt **);
 int     auth2_key_already_used(Authctxt *, const struct sshkey *);
 
 /*
@@ -163,16 +166,12 @@ int auth_shadow_pwexpired(Authctxt *);
 #include "audit.h"
 void remove_kbdint_device(const char *);
 
-void disable_forwarding(void);
-
-void   do_authentication2(Authctxt *);
+void   do_authentication2(struct ssh *);
 
-void   auth_log(Authctxt *, int, int, const char *, const char *);
-void   auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
+void   auth_log(struct ssh *, int, int, const char *, const char *);
+void   auth_maxtries_exceeded(struct ssh *) __attribute__((noreturn));
 void   userauth_finish(struct ssh *, int, const char *, const char *);
-int    auth_root_allowed(const char *);
-
-void   userauth_send_banner(const char *);
+int    auth_root_allowed(struct ssh *, const char *);
 
 char   *auth2_read_banner(void);
 int     auth2_methods_valid(const char *, int);
@@ -186,11 +185,9 @@ 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 **);
-int    skey_respond(void *, u_int, char **);
 
-int    allowed_user(struct passwd *);
-struct passwd * getpwnamallow(const char *user);
+int    allowed_user(struct ssh *, struct passwd *);
+struct passwd * getpwnamallow(struct ssh *, const char *user);
 
 char   *expand_authorized_keys(const char *, struct passwd *pw);
 char   *authorized_principals_file(struct passwd *);
@@ -211,19 +208,32 @@ 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);
+int     sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *,
+    u_char **, size_t *, const u_char *, size_t, const char *);
+
+/* Key / cert options linkage to auth layer */
+const struct sshauthopt *auth_options(struct ssh *);
+int     auth_activate_options(struct ssh *, struct sshauthopt *);
+void    auth_restrict_session(struct ssh *);
+int     auth_authorise_keyopts(struct ssh *, struct passwd *pw,
+    struct sshauthopt *, int, const char *);
+void    auth_log_authopts(const char *, const struct sshauthopt *, int);
 
 /* debug messages during authentication */
-void    auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
-void    auth_debug_send(void);
+void    auth_debug_add(const char *fmt,...)
+    __attribute__((format(printf, 1, 2)));
+void    auth_debug_send(struct ssh *);
 void    auth_debug_reset(void);
 
 struct passwd *fakepw(void);
 
-int     sys_auth_passwd(Authctxt *, const char *);
+#define        SSH_SUBPROCESS_STDOUT_DISCARD  (1)     /* Discard stdout */
+#define        SSH_SUBPROCESS_STDOUT_CAPTURE  (1<<1)  /* Redirect stdout */
+#define        SSH_SUBPROCESS_STDERR_DISCARD  (1<<2)  /* Discard stderr */
+pid_t  subprocess(const char *, struct passwd *,
+    const char *, int, char **, FILE **, u_int flags);
 
-#define SKEY_PROMPT "\nS/Key Password: "
+int     sys_auth_passwd(struct ssh *, const char *);
 
 #if defined(KRB5) && !defined(HEIMDAL)
 #include <krb5.h>
index 11c8d31..2d5cff4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-chall.c,v 1.48 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-chall.c,v 1.50 2018/07/11 18:55:11 markus Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2001 Per Allansson.  All rights reserved.
 
 #include "xmalloc.h"
 #include "ssh2.h"
-#include "key.h"
+#include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
-#include "buffer.h"
+#include "sshbuf.h"
 #include "packet.h"
 #include "dispatch.h"
+#include "ssherr.h"
 #include "log.h"
 #include "misc.h"
 #include "servconf.h"
@@ -48,7 +49,7 @@
 extern ServerOptions options;
 
 static int auth2_challenge_start(struct ssh *);
-static int send_userauth_info_request(Authctxt *);
+static int send_userauth_info_request(struct ssh *);
 static int input_userauth_info_response(int, u_int32_t, struct ssh *);
 
 #ifdef BSD_AUTH
@@ -57,9 +58,6 @@ extern KbdintDevice bsdauth_device;
 #ifdef USE_PAM
 extern KbdintDevice sshpam_device;
 #endif
-#ifdef SKEY
-extern KbdintDevice skey_device;
-#endif
 #endif
 
 KbdintDevice *devices[] = {
@@ -69,9 +67,6 @@ KbdintDevice *devices[] = {
 #ifdef USE_PAM
        &sshpam_device,
 #endif
-#ifdef SKEY
-       &skey_device,
-#endif
 #endif
        NULL
 };
@@ -105,8 +100,8 @@ static KbdintAuthctxt *
 kbdint_alloc(const char *devs)
 {
        KbdintAuthctxt *kbdintctxt;
-       Buffer b;
-       int i;
+       struct sshbuf *b;
+       int i, r;
 
 #ifdef USE_PAM
        if (!options.use_pam)
@@ -115,16 +110,17 @@ kbdint_alloc(const char *devs)
 
        kbdintctxt = xcalloc(1, sizeof(KbdintAuthctxt));
        if (strcmp(devs, "") == 0) {
-               buffer_init(&b);
+               if ((b = sshbuf_new()) == NULL)
+                       fatal("%s: sshbuf_new failed", __func__);
                for (i = 0; devices[i]; i++) {
-                       if (buffer_len(&b) > 0)
-                               buffer_append(&b, ",", 1);
-                       buffer_append(&b, devices[i]->name,
-                           strlen(devices[i]->name));
+                       if ((r = sshbuf_putf(b, "%s%s",
+                           sshbuf_len(b) ? "," : "", devices[i]->name)) != 0)
+                               fatal("%s: buffer error: %s",
+                                   __func__, ssh_err(r));
                }
-               if ((kbdintctxt->devices = sshbuf_dup_string(&b)) == NULL)
+               if ((kbdintctxt->devices = sshbuf_dup_string(b)) == NULL)
                        fatal("%s: sshbuf_dup_string failed", __func__);
-               buffer_free(&b);
+               sshbuf_free(b);
        } else {
                kbdintctxt->devices = xstrdup(devs);
        }
@@ -243,7 +239,7 @@ auth2_challenge_start(struct ssh *ssh)
                auth2_challenge_stop(ssh);
                return 0;
        }
-       if (send_userauth_info_request(authctxt) == 0) {
+       if (send_userauth_info_request(ssh) == 0) {
                auth2_challenge_stop(ssh);
                return 0;
        }
@@ -255,28 +251,32 @@ auth2_challenge_start(struct ssh *ssh)
 }
 
 static int
-send_userauth_info_request(Authctxt *authctxt)
+send_userauth_info_request(struct ssh *ssh)
 {
+       Authctxt *authctxt = ssh->authctxt;
        KbdintAuthctxt *kbdintctxt;
        char *name, *instr, **prompts;
-       u_int i, *echo_on;
+       u_int r, i, *echo_on;
 
        kbdintctxt = authctxt->kbdintctxt;
        if (kbdintctxt->device->query(kbdintctxt->ctxt,
            &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on))
                return 0;
 
-       packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
-       packet_put_cstring(name);
-       packet_put_cstring(instr);
-       packet_put_cstring("");         /* language not used */
-       packet_put_int(kbdintctxt->nreq);
+       if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_INFO_REQUEST)) != 0 ||
+           (r = sshpkt_put_cstring(ssh, name)) != 0 ||
+           (r = sshpkt_put_cstring(ssh, instr)) != 0 ||
+           (r = sshpkt_put_cstring(ssh, "")) != 0 ||   /* language not used */
+           (r = sshpkt_put_u32(ssh, kbdintctxt->nreq)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
        for (i = 0; i < kbdintctxt->nreq; i++) {
-               packet_put_cstring(prompts[i]);
-               packet_put_char(echo_on[i]);
+               if ((r = sshpkt_put_cstring(ssh, prompts[i])) != 0 ||
+                   (r = sshpkt_put_u8(ssh, echo_on[i])) != 0)
+                       fatal("%s: %s", __func__, ssh_err(r));
        }
-       packet_send();
-       packet_write_wait();
+       if ((r = sshpkt_send(ssh)) != 0 ||
+           (r = ssh_packet_write_wait(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
 
        for (i = 0; i < kbdintctxt->nreq; i++)
                free(prompts[i]);
@@ -293,6 +293,7 @@ input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
        Authctxt *authctxt = ssh->authctxt;
        KbdintAuthctxt *kbdintctxt;
        int authenticated = 0, res;
+       int r;
        u_int i, nresp;
        const char *devicename = NULL;
        char **response = NULL;
@@ -306,7 +307,8 @@ input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
                fatal("input_userauth_info_response: no device");
 
        authctxt->postponed = 0;        /* reset */
-       nresp = packet_get_int();
+       if ((r = sshpkt_get_u32(ssh, &nresp)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
        if (nresp != kbdintctxt->nreq)
                fatal("input_userauth_info_response: wrong number of replies");
        if (nresp > 100)
@@ -314,9 +316,12 @@ input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
        if (nresp > 0) {
                response = xcalloc(nresp, sizeof(char *));
                for (i = 0; i < nresp; i++)
-                       response[i] = packet_get_string(NULL);
+                       if ((r = sshpkt_get_cstring(ssh, &response[i],
+                           NULL)) != 0)
+                               fatal("%s: %s", __func__, ssh_err(r));
        }
-       packet_check_eom();
+       if ((r = sshpkt_get_end(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
 
        res = kbdintctxt->device->respond(kbdintctxt->ctxt, nresp, response);
 
@@ -333,7 +338,7 @@ input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
                break;
        case 1:
                /* Authentication needs further interaction */
-               if (send_userauth_info_request(authctxt) == 1)
+               if (send_userauth_info_request(ssh) == 1)
                        authctxt->postponed = 1;
                break;
        default:
@@ -358,7 +363,7 @@ input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
 void
 privsep_challenge_enable(void)
 {
-#if defined(BSD_AUTH) || defined(USE_PAM) || defined(SKEY)
+#if defined(BSD_AUTH) || defined(USE_PAM)
        int n = 0;
 #endif
 #ifdef BSD_AUTH
@@ -367,9 +372,6 @@ privsep_challenge_enable(void)
 #ifdef USE_PAM
        extern KbdintDevice mm_sshpam_device;
 #endif
-#ifdef SKEY
-       extern KbdintDevice mm_skey_device;
-#endif
 
 #ifdef BSD_AUTH
        devices[n++] = &mm_bsdauth_device;
@@ -377,8 +379,5 @@ privsep_challenge_enable(void)
 #ifdef USE_PAM
        devices[n++] = &mm_sshpam_device;
 #endif
-#ifdef SKEY
-       devices[n++] = &mm_skey_device;
-#endif
 #endif
 }
diff --git a/crypto/openssh/auth2-gss.c b/crypto/openssh/auth2-gss.c
deleted file mode 100644 (file)
index 589283b..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
-
-/*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef GSSAPI
-
-#include <sys/types.h>
-
-#include <stdarg.h>
-
-#include "xmalloc.h"
-#include "key.h"
-#include "hostfile.h"
-#include "auth.h"
-#include "ssh2.h"
-#include "log.h"
-#include "dispatch.h"
-#include "buffer.h"
-#include "misc.h"
-#include "servconf.h"
-#include "packet.h"
-#include "ssh-gss.h"
-#include "monitor_wrap.h"
-
-extern ServerOptions options;
-
-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(struct ssh *ssh)
-{
-       Authctxt *authctxt = ssh->authctxt;
-       gss_OID_desc goid = {0, NULL};
-       Gssctxt *ctxt = NULL;
-       int mechs;
-       int present;
-       OM_uint32 ms;
-       u_int len;
-       u_char *doid = NULL;
-
-       if (!authctxt->valid || authctxt->user == NULL)
-               return (0);
-
-       mechs = packet_get_int();
-       if (mechs == 0) {
-               debug("Mechanism negotiation is not supported");
-               return (0);
-       }
-
-       do {
-               mechs--;
-
-               free(doid);
-
-               present = 0;
-               doid = packet_get_string(&len);
-
-               if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
-                   doid[1] == len - 2) {
-                       goid.elements = doid + 2;
-                       goid.length   = len - 2;
-                       ssh_gssapi_test_oid_supported(&ms, &goid, &present);
-               } else {
-                       logit("Badly formed OID received");
-               }
-       } while (mechs > 0 && !present);
-
-       if (!present) {
-               free(doid);
-               authctxt->server_caused_failure = 1;
-               return (0);
-       }
-
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
-               if (ctxt != NULL)
-                       ssh_gssapi_delete_ctx(&ctxt);
-               free(doid);
-               authctxt->server_caused_failure = 1;
-               return (0);
-       }
-
-       authctxt->methoddata = (void *)ctxt;
-
-       packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
-
-       /* Return the OID that we received */
-       packet_put_string(doid, len);
-
-       packet_send();
-       free(doid);
-
-       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, struct ssh *ssh)
-{
-       Authctxt *authctxt = ssh->authctxt;
-       Gssctxt *gssctxt;
-       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
-       gss_buffer_desc recv_tok;
-       OM_uint32 maj_status, min_status, flags;
-       u_int len;
-
-       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
-               fatal("No authentication or GSSAPI context");
-
-       gssctxt = authctxt->methoddata;
-       recv_tok.value = packet_get_string(&len);
-       recv_tok.length = len; /* u_int vs. size_t */
-
-       packet_check_eom();
-
-       maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
-           &send_tok, &flags));
-
-       free(recv_tok.value);
-
-       if (GSS_ERROR(maj_status)) {
-               if (send_tok.length != 0) {
-                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
-                       packet_put_string(send_tok.value, send_tok.length);
-                       packet_send();
-               }
-               authctxt->postponed = 0;
-               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);
-                       packet_put_string(send_tok.value, send_tok.length);
-                       packet_send();
-               }
-               if (maj_status == GSS_S_COMPLETE) {
-                       ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-                       if (flags & GSS_C_INTEG_FLAG)
-                               ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC,
-                                   &input_gssapi_mic);
-                       else
-                               ssh_dispatch_set(ssh,
-                                   SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
-                                   &input_gssapi_exchange_complete);
-               }
-       }
-
-       gss_release_buffer(&min_status, &send_tok);
-       return 0;
-}
-
-static int
-input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
-{
-       Authctxt *authctxt = ssh->authctxt;
-       Gssctxt *gssctxt;
-       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
-       gss_buffer_desc recv_tok;
-       OM_uint32 maj_status;
-       u_int len;
-
-       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
-               fatal("No authentication or GSSAPI context");
-
-       gssctxt = authctxt->methoddata;
-       recv_tok.value = packet_get_string(&len);
-       recv_tok.length = len;
-
-       packet_check_eom();
-
-       /* Push the error token into GSSAPI to see what it says */
-       maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
-           &send_tok, NULL));
-
-       free(recv_tok.value);
-
-       /* We can't return anything to the client, even if we wanted to */
-       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 */
-
-       gss_release_buffer(&maj_status, &send_tok);
-       return 0;
-}
-
-/*
- * This is called when the client thinks we've completed authentication.
- * It should only be enabled in the dispatch handler by the function above,
- * which only enables it once the GSSAPI exchange is complete.
- */
-
-static int
-input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
-{
-       Authctxt *authctxt = ssh->authctxt;
-       int authenticated;
-       const char *displayname;
-
-       if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
-               fatal("No authentication or GSSAPI context");
-
-       /*
-        * We don't need to check the status, because we're only enabled in
-        * the dispatcher once the exchange is complete
-        */
-
-       packet_check_eom();
-
-       authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
-
-       if ((!use_privsep || mm_is_monitor()) &&
-           (displayname = ssh_gssapi_displayname()) != NULL)
-               auth2_record_info(authctxt, "%s", displayname);
-
-       authctxt->postponed = 0;
-       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, struct ssh *ssh)
-{
-       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");
-
-       gssctxt = authctxt->methoddata;
-
-       mic.value = packet_get_string(&len);
-       mic.length = len;
-
-       ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
-           "gssapi-with-mic");
-
-       gssbuf.value = buffer_ptr(&b);
-       gssbuf.length = buffer_len(&b);
-
-       if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
-               authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
-       else
-               logit("GSSAPI MIC check failed");
-
-       buffer_free(&b);
-       free(mic.value);
-
-       if ((!use_privsep || mm_is_monitor()) &&
-           (displayname = ssh_gssapi_displayname()) != NULL)
-               auth2_record_info(authctxt, "%s", displayname);
-
-       authctxt->postponed = 0;
-       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;
-}
-
-Authmethod method_gssapi = {
-       "gssapi-with-mic",
-       userauth_gssapi,
-       &options.gss_authentication
-};
-
-#endif /* GSSAPI */
index 92758b3..0c40fad 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.40 2019/01/19 21:43:56 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -34,7 +34,7 @@
 #include "xmalloc.h"
 #include "ssh2.h"
 #include "packet.h"
-#include "buffer.h"
+#include "sshbuf.h"
 #include "log.h"
 #include "misc.h"
 #include "servconf.h"
@@ -62,15 +62,11 @@ userauth_hostbased(struct ssh *ssh)
        Authctxt *authctxt = ssh->authctxt;
        struct sshbuf *b;
        struct sshkey *key = NULL;
-       char *pkalg, *cuser, *chost, *service;
+       char *pkalg, *cuser, *chost;
        u_char *pkblob, *sig;
        size_t alen, blen, slen;
        int r, pktype, authenticated = 0;
 
-       if (!authctxt->valid) {
-               debug2("%s: disabled because of invalid user", __func__);
-               return 0;
-       }
        /* XXX use sshkey_froms() */
        if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
            (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
@@ -83,7 +79,7 @@ userauth_hostbased(struct ssh *ssh)
            cuser, chost, pkalg, slen);
 #ifdef DEBUG_PK
        debug("signature:");
-       sshbuf_dump_data(sig, siglen, stderr);
+       sshbuf_dump_data(sig, slen, stderr);
 #endif
        pktype = sshkey_type_from_name(pkalg);
        if (pktype == KEY_UNSPEC) {
@@ -111,22 +107,31 @@ userauth_hostbased(struct ssh *ssh)
                    "signature format");
                goto done;
        }
-       if (match_pattern_list(sshkey_ssh_name(key),
-           options.hostbased_key_types, 0) != 1) {
+       if (match_pattern_list(pkalg, options.hostbased_key_types, 0) != 1) {
                logit("%s: key type %s not in HostbasedAcceptedKeyTypes",
                    __func__, sshkey_type(key));
                goto done;
        }
+       if ((r = sshkey_check_cert_sigtype(key,
+           options.ca_sign_algorithms)) != 0) {
+               logit("%s: certificate signature algorithm %s: %s", __func__,
+                   (key->cert == NULL || key->cert->signature_type == NULL) ?
+                   "(null)" : key->cert->signature_type, ssh_err(r));
+               goto done;
+       }
+
+       if (!authctxt->valid || authctxt->user == NULL) {
+               debug2("%s: disabled because of invalid user", __func__);
+               goto done;
+       }
 
-       service = ssh->compat & SSH_BUG_HBSERVICE ? "ssh-userauth" :
-           authctxt->service;
        if ((b = sshbuf_new()) == NULL)
                fatal("%s: sshbuf_new failed", __func__);
        /* reconstruct packet */
        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, authctxt->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 ||
@@ -142,9 +147,10 @@ userauth_hostbased(struct ssh *ssh)
 
        /* test for allowed key and correct signature */
        authenticated = 0;
-       if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
+       if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser,
+           chost, key)) &&
            PRIVSEP(sshkey_verify(key, sig, slen,
-           sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
+           sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0)
                authenticated = 1;
 
        auth2_record_key(authctxt, authenticated, key);
@@ -162,10 +168,9 @@ done:
 
 /* return 1 if given hostkey is allowed */
 int
-hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
-    struct sshkey *key)
+hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
+    const char *cuser, char *chost, struct sshkey *key)
 {
-       struct ssh *ssh = active_state; /* XXX */
        const char *resolvedname, *ipaddr, *lookup, *reason;
        HostStatus host_status;
        int len;
index 86aad8d..a813b8f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-kbdint.c,v 1.8 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-kbdint.c,v 1.9 2018/07/09 21:35:50 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
 
 #include "xmalloc.h"
 #include "packet.h"
-#include "key.h"
 #include "hostfile.h"
 #include "auth.h"
 #include "log.h"
-#include "buffer.h"
 #include "misc.h"
 #include "servconf.h"
+#include "ssherr.h"
 
 /* import */
 extern ServerOptions options;
@@ -45,12 +44,13 @@ extern ServerOptions options;
 static int
 userauth_kbdint(struct ssh *ssh)
 {
-       int authenticated = 0;
+       int r, authenticated = 0;
        char *lang, *devs;
 
-       lang = packet_get_string(NULL);
-       devs = packet_get_string(NULL);
-       packet_check_eom();
+       if ((r = sshpkt_get_cstring(ssh, &lang, NULL)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &devs, NULL)) != 0 ||
+           (r = sshpkt_get_end(ssh)) != 0)
+               fatal("%s: %s", __func__, ssh_err(r));
 
        debug("keyboard-interactive devs %s", devs);
 
index 35d25fa..dacb5fb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-none.c,v 1.20 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-none.c,v 1.22 2018/07/09 21:35:50 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -42,7 +42,6 @@
 #include "auth.h"
 #include "packet.h"
 #include "log.h"
-#include "buffer.h"
 #include "misc.h"
 #include "servconf.h"
 #include "compat.h"
@@ -68,7 +67,7 @@ userauth_none(struct ssh *ssh)
        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(ssh->authctxt, "")));
+               return (PRIVSEP(auth_password(ssh, "")));
        return (0);
 }
 
index 5f7ba32..0395a69 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-passwd.c,v 1.14 2017/05/30 14:29:59 markus Exp $ */
+/* $OpenBSD: auth2-passwd.c,v 1.16 2018/07/09 21:35:50 markus Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -36,7 +36,6 @@
 #include "sshkey.h"
 #include "hostfile.h"
 #include "auth.h"
-#include "buffer.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
@@ -63,7 +62,7 @@ userauth_passwd(struct ssh *ssh)
 
        if (change)
                logit("password change not supported");
-       else if (PRIVSEP(auth_password(ssh->authctxt, password)) == 1)
+       else if (PRIVSEP(auth_password(ssh, password)) == 1)
                authenticated = 1;
        explicit_bzero(password, len);
        free(password);
index 169839b..0b3975a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.87 2019/01/22 11:26:16 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -46,7 +46,7 @@
 #include "ssh.h"
 #include "ssh2.h"
 #include "packet.h"
-#include "buffer.h"
+#include "sshbuf.h"
 #include "log.h"
 #include "misc.h"
 #include "servconf.h"
@@ -73,46 +73,55 @@ extern ServerOptions options;
 extern u_char *session_id2;
 extern u_int session_id2_len;
 
+static char *
+format_key(const struct sshkey *key)
+{
+       char *ret, *fp = sshkey_fingerprint(key,
+           options.fingerprint_hash, SSH_FP_DEFAULT);
+
+       xasprintf(&ret, "%s %s", sshkey_type(key), fp);
+       free(fp);
+       return ret;
+}
+
 static int
 userauth_pubkey(struct ssh *ssh)
 {
        Authctxt *authctxt = ssh->authctxt;
-       struct sshbuf *b;
+       struct passwd *pw = authctxt->pw;
+       struct sshbuf *b = NULL;
        struct sshkey *key = NULL;
-       char *pkalg, *userstyle = NULL, *fp = NULL;
-       u_char *pkblob, *sig, have_sig;
+       char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
+       u_char *pkblob = NULL, *sig = NULL, 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;
-       }
-       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 */
-               /* so we have to extract the pkalg from the pkblob */
-               /* 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 {
-               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));
+       struct sshauthopt *authopts = NULL;
+
+       if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
+           (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
+           (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
+               fatal("%s: parse request failed: %s", __func__, ssh_err(r));
+
+       if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) {
+               char *keystring;
+               struct sshbuf *pkbuf;
+
+               if ((pkbuf = sshbuf_from(pkblob, blen)) == NULL)
+                       fatal("%s: sshbuf_from failed", __func__);
+               if ((keystring = sshbuf_dtob64(pkbuf)) == NULL)
+                       fatal("%s: sshbuf_dtob64 failed", __func__);
+               debug2("%s: %s user %s %s public key %s %s", __func__,
+                   authctxt->valid ? "valid" : "invalid", authctxt->user,
+                   have_sig ? "attempting" : "querying", pkalg, keystring);
+               sshbuf_free(pkbuf);
+               free(keystring);
        }
+
        pktype = sshkey_type_from_name(pkalg);
        if (pktype == KEY_UNSPEC) {
                /* this is perfectly legal */
-               logit("%s: unsupported public key algorithm: %s",
+               verbose("%s: unsupported public key algorithm: %s",
                    __func__, pkalg);
                goto done;
        }
@@ -135,21 +144,31 @@ userauth_pubkey(struct ssh *ssh)
                    "signature scheme");
                goto done;
        }
-       fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
        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),
-           options.pubkey_key_types, 0) != 1) {
+       if (match_pattern_list(pkalg, options.pubkey_key_types, 0) != 1) {
                logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
                    __func__, sshkey_ssh_name(key));
                goto done;
        }
+       if ((r = sshkey_check_cert_sigtype(key,
+           options.ca_sign_algorithms)) != 0) {
+               logit("%s: certificate signature algorithm %s: %s", __func__,
+                   (key->cert == NULL || key->cert->signature_type == NULL) ?
+                   "(null)" : key->cert->signature_type, ssh_err(r));
+               goto done;
+       }
+       key_s = format_key(key);
+       if (sshkey_is_cert(key))
+               ca_s = format_key(key->cert->signature_key);
 
        if (have_sig) {
-               debug3("%s: have signature for %s %s",
-                   __func__, sshkey_type(key), fp);
+               debug3("%s: have %s signature for %s%s%s",
+                   __func__, pkalg, key_s,
+                   ca_s == NULL ? "" : " CA ",
+                   ca_s == NULL ? "" : ca_s);
                if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
                    (r = sshpkt_get_end(ssh)) != 0)
                        fatal("%s: %s", __func__, ssh_err(r));
@@ -166,50 +185,51 @@ userauth_pubkey(struct ssh *ssh)
                                fatal("%s: sshbuf_put_string session id: %s",
                                    __func__, ssh_err(r));
                }
+               if (!authctxt->valid || authctxt->user == NULL) {
+                       debug2("%s: disabled because of invalid user",
+                           __func__);
+                       goto done;
+               }
                /* reconstruct packet */
                xasprintf(&userstyle, "%s%s%s", authctxt->user,
                    authctxt->style ? ":" : "",
                    authctxt->style ? authctxt->style : "");
                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 {
-                       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));
-               }
-               if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
+                   (r = sshbuf_put_cstring(b, authctxt->service)) != 0 ||
+                   (r = sshbuf_put_cstring(b, "publickey")) != 0 ||
+                   (r = sshbuf_put_u8(b, have_sig)) != 0 ||
+                   (r = sshbuf_put_cstring(b, pkalg)) != 0 ||
+                   (r = sshbuf_put_string(b, pkblob, blen)) != 0)
                        fatal("%s: build packet failed: %s",
                            __func__, ssh_err(r));
 #ifdef DEBUG_PK
                sshbuf_dump(b, stderr);
 #endif
-
                /* test for correct signature */
                authenticated = 0;
-               if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
-                   PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
-                   sshbuf_len(b), ssh->compat)) == 0) {
+               if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
+                   PRIVSEP(sshkey_verify(key, sig, slen,
+                   sshbuf_ptr(b), sshbuf_len(b),
+                   (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL,
+                   ssh->compat)) == 0) {
                        authenticated = 1;
                }
-               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);
+               debug("%s: test pkalg %s pkblob %s%s%s",
+                   __func__, pkalg, key_s,
+                   ca_s == NULL ? "" : " CA ",
+                   ca_s == NULL ? "" : ca_s);
+
                if ((r = sshpkt_get_end(ssh)) != 0)
                        fatal("%s: %s", __func__, ssh_err(r));
 
+               if (!authctxt->valid || authctxt->user == NULL) {
+                       debug2("%s: disabled because of invalid user",
+                           __func__);
+                       goto done;
+               }
                /* XXX fake reply and always send PK_OK ? */
                /*
                 * XXX this allows testing whether a user is allowed
@@ -218,26 +238,33 @@ userauth_pubkey(struct ssh *ssh)
                 * if a user is not allowed to login. is this an
                 * issue? -markus
                 */
-               if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
+               if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) {
                        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)
+                           (r = sshpkt_send(ssh)) != 0 ||
+                           (r = ssh_packet_write_wait(ssh)) != 0)
                                fatal("%s: %s", __func__, ssh_err(r));
-                       ssh_packet_write_wait(ssh);
                        authctxt->postponed = 1;
                }
        }
-       if (authenticated != 1)
-               auth_clear_options();
 done:
+       if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
+               debug("%s: key options inconsistent with existing", __func__);
+               authenticated = 0;
+       }
        debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
+
+       sshbuf_free(b);
+       sshauthopt_free(authopts);
        sshkey_free(key);
        free(userstyle);
        free(pkalg);
        free(pkblob);
-       free(fp);
+       free(key_s);
+       free(ca_s);
+       free(sig);
        return authenticated;
 }
 
@@ -261,18 +288,79 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
        return 0;
 }
 
+/*
+ * Process a single authorized_principals format line. Returns 0 and sets
+ * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a
+ * log preamble for file/line information.
+ */
+static int
+check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
+    const char *loc, struct sshauthopt **authoptsp)
+{
+       u_int i, found = 0;
+       char *ep, *line_opts;
+       const char *reason = NULL;
+       struct sshauthopt *opts = NULL;
+
+       if (authoptsp != NULL)
+               *authoptsp = NULL;
+
+       /* Trim trailing whitespace. */
+       ep = cp + strlen(cp) - 1;
+       while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
+               *ep-- = '\0';
+
+       /*
+        * If the line has internal whitespace then assume it has
+        * key options.
+        */
+       line_opts = NULL;
+       if ((ep = strrchr(cp, ' ')) != NULL ||
+           (ep = strrchr(cp, '\t')) != NULL) {
+               for (; *ep == ' ' || *ep == '\t'; ep++)
+                       ;
+               line_opts = cp;
+               cp = ep;
+       }
+       if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) {
+               debug("%s: bad principals options: %s", loc, reason);
+               auth_debug_add("%s: bad principals options: %s", loc, reason);
+               return -1;
+       }
+       /* Check principals in cert against those on line */
+       for (i = 0; i < cert->nprincipals; i++) {
+               if (strcmp(cp, cert->principals[i]) != 0)
+                       continue;
+               debug3("%s: matched principal \"%.100s\"",
+                   loc, cert->principals[i]);
+               found = 1;
+       }
+       if (found && authoptsp != NULL) {
+               *authoptsp = opts;
+               opts = NULL;
+       }
+       sshauthopt_free(opts);
+       return found ? 0 : -1;
+}
+
 static int
-process_principals(FILE *f, const char *file, struct passwd *pw,
-    const struct sshkey_cert *cert)
+process_principals(struct ssh *ssh, FILE *f, const char *file,
+    const struct sshkey_cert *cert, struct sshauthopt **authoptsp)
 {
-       char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
+       char loc[256], *line = NULL, *cp, *ep;
+       size_t linesize = 0;
        u_long linenum = 0;
-       u_int i, found_principal = 0;
+       u_int found_principal = 0;
 
-       while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+       if (authoptsp != NULL)
+               *authoptsp = NULL;
+
+       while (getline(&line, &linesize, f) != -1) {
+               linenum++;
                /* Always consume entire input */
                if (found_principal)
                        continue;
+
                /* Skip leading whitespace. */
                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                        ;
@@ -281,50 +369,34 @@ process_principals(FILE *f, const char *file, struct passwd *pw,
                        *ep = '\0';
                if (!*cp || *cp == '\n')
                        continue;
-               /* Trim trailing whitespace. */
-               ep = cp + strlen(cp) - 1;
-               while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
-                       *ep-- = '\0';
-               /*
-                * If the line has internal whitespace then assume it has
-                * key options.
-                */
-               line_opts = NULL;
-               if ((ep = strrchr(cp, ' ')) != NULL ||
-                   (ep = strrchr(cp, '\t')) != NULL) {
-                       for (; *ep == ' ' || *ep == '\t'; ep++)
-                               ;
-                       line_opts = cp;
-                       cp = ep;
-               }
-               for (i = 0; i < cert->nprincipals; i++) {
-                       if (strcmp(cp, cert->principals[i]) == 0) {
-                               debug3("%s:%lu: matched principal \"%.100s\"",
-                                   file, linenum, cert->principals[i]);
-                               if (auth_parse_options(pw, line_opts,
-                                   file, linenum) != 1)
-                                       continue;
-                               found_principal = 1;
-                               continue;
-                       }
-               }
+
+               snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
+               if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
+                       found_principal = 1;
        }
+       free(line);
        return found_principal;
 }
 
+/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
+
 static int
-match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
+match_principals_file(struct ssh *ssh, struct passwd *pw, char *file,
+    struct sshkey_cert *cert, struct sshauthopt **authoptsp)
 {
        FILE *f;
        int success;
 
+       if (authoptsp != NULL)
+               *authoptsp = NULL;
+
        temporarily_use_uid(pw);
        debug("trying authorized principals file %s", file);
        if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
                restore_uid();
                return 0;
        }
-       success = process_principals(f, file, pw, cert);
+       success = process_principals(ssh, f, file, cert, authoptsp);
        fclose(f);
        restore_uid();
        return success;
@@ -335,19 +407,22 @@ 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, const struct sshkey *key)
+match_principals_command(struct ssh *ssh, struct passwd *user_pw,
+    const struct sshkey *key, struct sshauthopt **authoptsp)
 {
+       struct passwd *runas_pw = NULL;
        const struct sshkey_cert *cert = key->cert;
        FILE *f = NULL;
        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];
+       char serial_s[16], uidstr[32];
        void (*osigchld)(int);
 
+       if (authoptsp != NULL)
+               *authoptsp = NULL;
        if (options.authorized_principals_command == NULL)
                return 0;
        if (options.authorized_principals_command_user == NULL) {
@@ -365,8 +440,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
        /* Prepare and verify the user for the command */
        username = percent_expand(options.authorized_principals_command_user,
            "u", user_pw->pw_name, (char *)NULL);
-       pw = getpwnam(username);
-       if (pw == NULL) {
+       runas_pw = getpwnam(username);
+       if (runas_pw == NULL) {
                error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
                    username, strerror(errno));
                goto out;
@@ -403,8 +478,11 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
        }
        snprintf(serial_s, sizeof(serial_s), "%llu",
            (unsigned long long)cert->serial);
+       snprintf(uidstr, sizeof(uidstr), "%llu",
+           (unsigned long long)user_pw->pw_uid);
        for (i = 1; i < ac; i++) {
                tmp = percent_expand(av[i],
+                   "U", uidstr,
                    "u", user_pw->pw_name,
                    "h", user_pw->pw_dir,
                    "t", sshkey_ssh_name(key),
@@ -424,15 +502,15 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
        /* Prepare a printable command for logs, etc. */
        command = argv_assemble(ac, av);
 
-       if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
+       if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command,
            ac, av, &f,
            SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
                goto out;
 
        uid_swapped = 1;
-       temporarily_use_uid(pw);
+       temporarily_use_uid(runas_pw);
 
-       ok = process_principals(f, "(command)", pw, cert);
+       ok = process_principals(ssh, f, "(command)", cert, authoptsp);
 
        fclose(f);
        f = NULL;