Vendor import of OpenSSH 7.6p1.
This commit is contained in:
parent
03c436e653
commit
b976cff2b1
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
Makefile
|
||||
buildpkg.sh
|
||||
config.h
|
||||
config.h.in
|
||||
config.status
|
||||
configure
|
||||
openbsd-compat/Makefile
|
||||
openbsd-compat/regress/Makefile
|
||||
openssh.xml
|
||||
opensshd.init
|
||||
survey.sh
|
||||
**/*.0
|
||||
**/*.o
|
||||
**/*.out
|
||||
**/*.a
|
||||
autom4te.cache/
|
||||
scp
|
||||
sftp
|
||||
sftp-server
|
||||
ssh
|
||||
ssh-add
|
||||
ssh-agent
|
||||
ssh-keygen
|
||||
ssh-keyscan
|
||||
ssh-keysign
|
||||
ssh-pkcs11-helper
|
||||
sshd
|
||||
!regress/misc/fuzz-harness/Makefile
|
@ -11,3 +11,13 @@ f6ae971186ba68d066cd102e57d5b0b2c211a5ee systrace is dead.
|
||||
96c5054e3e1f170c6276902d5bc65bb3b87a2603 remove DEBUGLIBS from Makefile
|
||||
6da9a37f74aef9f9cc639004345ad893cad582d8 Update moduli file
|
||||
77bcb50e47b68c7209c7f0a5a020d73761e5143b unset REGRESS_FAIL_EARLY
|
||||
38c2133817cbcae75c88c63599ac54228f0fa384 Change COMPILER_VERSION tests
|
||||
30c20180c87cbc99fa1020489fe7fd8245b6420c resync integrity.sh shell
|
||||
1e6b51ddf767cbad0a4e63eb08026c127e654308 integrity.sh reliability
|
||||
fe5b31f69a60d47171836911f144acff77810217 Makefile.inc bits
|
||||
5781670c0578fe89663c9085ed3ba477cf7e7913 Delete sshconnect1.c
|
||||
ea80f445e819719ccdcb237022cacfac990fdc5c Makefile.inc warning flags
|
||||
b92c93266d8234d493857bb822260dacf4366157 moduli-gen.sh tweak
|
||||
b25bf747544265b39af74fe0716dc8d9f5b63b95 Updated moduli
|
||||
1bd41cba06a7752de4df304305a8153ebfb6b0ac rsa.[ch] already removed
|
||||
e39b3902fe1d6c4a7ba6a3c58e072219f3c1e604 Makefile changes
|
||||
|
2
INSTALL
2
INSTALL
@ -99,7 +99,7 @@ http://www.gnu.org/software/autoconf/
|
||||
|
||||
Basic Security Module (BSM):
|
||||
|
||||
Native BSM support is know to exist in Solaris from at least 2.5.1,
|
||||
Native BSM support is known to exist in Solaris from at least 2.5.1,
|
||||
FreeBSD 6.1 and OS X. Alternatively, you may use the OpenBSM
|
||||
implementation (http://www.openbsm.org).
|
||||
|
||||
|
23
LICENCE
23
LICENCE
@ -75,27 +75,6 @@ OpenSSH contains no GPL code.
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
2)
|
||||
The 32-bit CRC compensation attack detector in deattack.c was
|
||||
contributed by CORE SDI S.A. under a BSD-style license.
|
||||
|
||||
* Cryptographic attack detector for ssh - source code
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
|
||||
3)
|
||||
ssh-keyscan was contributed by David Mazieres under a BSD-style
|
||||
license.
|
||||
@ -337,4 +316,4 @@ OpenSSH contains no GPL code.
|
||||
|
||||
|
||||
------
|
||||
$OpenBSD: LICENCE,v 1.19 2004/08/30 09:18:08 markus Exp $
|
||||
$OpenBSD: LICENCE,v 1.20 2017/04/30 23:26:16 djm Exp $
|
||||
|
31
Makefile.in
31
Makefile.in
@ -78,10 +78,10 @@ LIBOPENSSH_OBJS=\
|
||||
LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
authfd.o authfile.o bufaux.o bufbn.o bufec.o buffer.o \
|
||||
canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \
|
||||
cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
|
||||
compat.o crc32.o deattack.o fatal.o hostfile.o \
|
||||
log.o match.o md-sha256.o moduli.o nchan.o packet.o opacket.o \
|
||||
readpass.o rsa.o ttymodes.o xmalloc.o addrmatch.o \
|
||||
cipher-ctr.o cleanup.o \
|
||||
compat.o crc32.o fatal.o hostfile.o \
|
||||
log.o match.o moduli.o nchan.o packet.o opacket.o \
|
||||
readpass.o ttymodes.o xmalloc.o addrmatch.o \
|
||||
atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \
|
||||
monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
|
||||
msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
|
||||
@ -92,10 +92,10 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
||||
kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
|
||||
kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
|
||||
kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
|
||||
platform-pledge.o platform-tracing.o
|
||||
platform-pledge.o platform-tracing.o platform-misc.o
|
||||
|
||||
SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
|
||||
sshconnect.o sshconnect1.o sshconnect2.o mux.o
|
||||
sshconnect.o sshconnect2.o mux.o
|
||||
|
||||
SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \
|
||||
audit.o audit-bsm.o audit-linux.o platform.o \
|
||||
@ -228,26 +228,27 @@ umac128.o: umac.c
|
||||
clean: regressclean
|
||||
rm -f *.o *.a $(TARGETS) logintest config.cache config.log
|
||||
rm -f *.out core survey
|
||||
rm -f regress/check-perm$(EXEEXT)
|
||||
rm -f regress/unittests/test_helper/*.a
|
||||
rm -f regress/unittests/test_helper/*.o
|
||||
rm -f regress/unittests/sshbuf/*.o
|
||||
rm -f regress/unittests/sshbuf/test_sshbuf
|
||||
rm -f regress/unittests/sshbuf/test_sshbuf$(EXEEXT)
|
||||
rm -f regress/unittests/sshkey/*.o
|
||||
rm -f regress/unittests/sshkey/test_sshkey
|
||||
rm -f regress/unittests/sshkey/test_sshkey$(EXEEXT)
|
||||
rm -f regress/unittests/bitmap/*.o
|
||||
rm -f regress/unittests/bitmap/test_bitmap
|
||||
rm -f regress/unittests/bitmap/test_bitmap$(EXEEXT)
|
||||
rm -f regress/unittests/conversion/*.o
|
||||
rm -f regress/unittests/conversion/test_conversion
|
||||
rm -f regress/unittests/conversion/test_conversion$(EXEEXT)
|
||||
rm -f regress/unittests/hostkeys/*.o
|
||||
rm -f regress/unittests/hostkeys/test_hostkeys
|
||||
rm -f regress/unittests/hostkeys/test_hostkeys$(EXEEXT)
|
||||
rm -f regress/unittests/kex/*.o
|
||||
rm -f regress/unittests/kex/test_kex
|
||||
rm -f regress/unittests/kex/test_kex$(EXEEXT)
|
||||
rm -f regress/unittests/match/*.o
|
||||
rm -f regress/unittests/match/test_match
|
||||
rm -f regress/unittests/match/test_match$(EXEEXT)
|
||||
rm -f regress/unittests/utf8/*.o
|
||||
rm -f regress/unittests/utf8/test_utf8
|
||||
rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
|
||||
rm -f regress/misc/kexfuzz/*.o
|
||||
rm -f regress/misc/kexfuzz/kexfuzz
|
||||
rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT)
|
||||
(cd openbsd-compat && $(MAKE) clean)
|
||||
|
||||
distclean: regressclean
|
||||
|
6
PROTOCOL
6
PROTOCOL
@ -33,8 +33,8 @@ The method is documented in:
|
||||
|
||||
https://www.openssh.com/txt/draft-miller-secsh-compression-delayed-00.txt
|
||||
|
||||
1.3. transport: New public key algorithms "ssh-rsa-cert-v00@openssh.com",
|
||||
"ssh-dsa-cert-v00@openssh.com",
|
||||
1.3. transport: New public key algorithms "ssh-rsa-cert-v01@openssh.com",
|
||||
"ssh-dsa-cert-v01@openssh.com",
|
||||
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com" and
|
||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
@ -454,4 +454,4 @@ respond with a SSH_FXP_STATUS message.
|
||||
This extension is advertised in the SSH_FXP_VERSION hello with version
|
||||
"1".
|
||||
|
||||
$OpenBSD: PROTOCOL,v 1.30 2016/04/08 06:35:54 djm Exp $
|
||||
$OpenBSD: PROTOCOL,v 1.31 2017/05/26 01:40:07 djm Exp $
|
||||
|
585
PROTOCOL.agent
585
PROTOCOL.agent
@ -1,582 +1,5 @@
|
||||
This describes the protocol used by OpenSSH's ssh-agent.
|
||||
This file used to contain a description of the SSH agent protocol
|
||||
implemented by OpenSSH. It has since been superseded by an Internet-
|
||||
draft that is available from:
|
||||
|
||||
OpenSSH's agent supports managing keys for the standard SSH protocol
|
||||
2 as well as the legacy SSH protocol 1. Support for these key types
|
||||
is almost completely disjoint - in all but a few cases, operations on
|
||||
protocol 2 keys cannot see or affect protocol 1 keys and vice-versa.
|
||||
|
||||
Protocol 1 and protocol 2 keys are separated because of the differing
|
||||
cryptographic usage: protocol 1 private RSA keys are used to decrypt
|
||||
challenges that were encrypted with the corresponding public key,
|
||||
whereas protocol 2 RSA private keys are used to sign challenges with
|
||||
a private key for verification with the corresponding public key. It
|
||||
is considered unsound practice to use the same key for signing and
|
||||
encryption.
|
||||
|
||||
With a couple of exceptions, the protocol message names used in this
|
||||
document indicate which type of key the message relates to. SSH_*
|
||||
messages refer to protocol 1 keys only. SSH2_* messages refer to
|
||||
protocol 2 keys. Furthermore, the names also indicate whether the
|
||||
message is a request to the agent (*_AGENTC_*) or a reply from the
|
||||
agent (*_AGENT_*). Section 3 below contains the mapping of the
|
||||
protocol message names to their integer values.
|
||||
|
||||
1. Data types
|
||||
|
||||
Because of support for legacy SSH protocol 1 keys, OpenSSH's agent
|
||||
protocol makes use of some data types not defined in RFC 4251.
|
||||
|
||||
1.1 uint16
|
||||
|
||||
The "uint16" data type is a simple MSB-first 16 bit unsigned integer
|
||||
encoded in two bytes.
|
||||
|
||||
1.2 mpint1
|
||||
|
||||
The "mpint1" type represents an arbitrary precision integer (bignum).
|
||||
Its format is as follows:
|
||||
|
||||
uint16 bits
|
||||
byte[(bits + 7) / 8] bignum
|
||||
|
||||
"bignum" contains an unsigned arbitrary precision integer encoded as
|
||||
eight bits per byte in big-endian (MSB first) format.
|
||||
|
||||
Note the difference between the "mpint1" encoding and the "mpint"
|
||||
encoding defined in RFC 4251. Also note that the length of the encoded
|
||||
integer is specified in bits, not bytes and that the byte length of
|
||||
the integer must be calculated by rounding up the number of bits to the
|
||||
nearest eight.
|
||||
|
||||
2. Protocol Messages
|
||||
|
||||
All protocol messages are prefixed with their length in bytes, encoded
|
||||
as a 32 bit unsigned integer. Specifically:
|
||||
|
||||
uint32 message_length
|
||||
byte[message_length] message
|
||||
|
||||
The following message descriptions refer only to the content the
|
||||
"message" field.
|
||||
|
||||
2.1 Generic server responses
|
||||
|
||||
The following generic messages may be sent by the server in response to
|
||||
requests from the client. On success the agent may reply either with:
|
||||
|
||||
byte SSH_AGENT_SUCCESS
|
||||
|
||||
or a request-specific success message.
|
||||
|
||||
On failure, the agent may reply with:
|
||||
|
||||
byte SSH_AGENT_FAILURE
|
||||
|
||||
SSH_AGENT_FAILURE messages are also sent in reply to unknown request
|
||||
types.
|
||||
|
||||
2.2 Adding keys to the agent
|
||||
|
||||
Keys are added to the agent using the SSH_AGENTC_ADD_RSA_IDENTITY and
|
||||
SSH2_AGENTC_ADD_IDENTITY requests for protocol 1 and protocol 2 keys
|
||||
respectively.
|
||||
|
||||
Two variants of these requests are SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
|
||||
and SSH2_AGENTC_ADD_ID_CONSTRAINED - these add keys with optional
|
||||
"constraints" on their usage.
|
||||
|
||||
OpenSSH may be built with support for keys hosted on a smartcard
|
||||
or other hardware security module. These keys may be added
|
||||
to the agent using the SSH_AGENTC_ADD_SMARTCARD_KEY and
|
||||
SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED requests.
|
||||
|
||||
2.2.1 Key constraints
|
||||
|
||||
The OpenSSH agent supports some basic optional constraints on key usage.
|
||||
At present there are two constraints defined.
|
||||
|
||||
The first constraint limits the validity duration of a key. It is
|
||||
encoded as:
|
||||
|
||||
byte SSH_AGENT_CONSTRAIN_LIFETIME
|
||||
uint32 seconds
|
||||
|
||||
Where "seconds" contains the number of seconds that the key shall remain
|
||||
valid measured from the moment that the agent receives it. After the
|
||||
validity period has expired, OpenSSH's agent will erase these keys from
|
||||
memory.
|
||||
|
||||
The second constraint requires the agent to seek explicit user
|
||||
confirmation before performing private key operations with the loaded
|
||||
key. This constraint is encoded as:
|
||||
|
||||
byte SSH_AGENT_CONSTRAIN_CONFIRM
|
||||
|
||||
Zero or more constraints may be specified when adding a key with one
|
||||
of the *_CONSTRAINED requests. Multiple constraints are appended
|
||||
consecutively to the end of the request:
|
||||
|
||||
byte constraint1_type
|
||||
.... constraint1_data
|
||||
byte constraint2_type
|
||||
.... constraint2_data
|
||||
....
|
||||
byte constraintN_type
|
||||
.... constraintN_data
|
||||
|
||||
Such a sequence of zero or more constraints will be referred to below
|
||||
as "constraint[]". Agents may determine whether there are constraints
|
||||
by checking whether additional data exists in the "add key" request
|
||||
after the key data itself. OpenSSH will refuse to add a key if it
|
||||
contains unknown constraints.
|
||||
|
||||
2.2.2 Add protocol 1 key
|
||||
|
||||
A client may add a protocol 1 key to an agent with the following
|
||||
request:
|
||||
|
||||
byte SSH_AGENTC_ADD_RSA_IDENTITY or
|
||||
SSH_AGENTC_ADD_RSA_ID_CONSTRAINED
|
||||
uint32 ignored
|
||||
mpint1 rsa_n
|
||||
mpint1 rsa_e
|
||||
mpint1 rsa_d
|
||||
mpint1 rsa_iqmp
|
||||
mpint1 rsa_q
|
||||
mpint1 rsa_p
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
Note that there is some redundancy in the key parameters; a key could be
|
||||
fully specified using just rsa_q, rsa_p and rsa_e at the cost of extra
|
||||
computation.
|
||||
|
||||
"key_constraints" may only be present if the request type is
|
||||
SSH_AGENTC_ADD_RSA_ID_CONSTRAINED.
|
||||
|
||||
The agent will reply with a SSH_AGENT_SUCCESS if the key has been
|
||||
successfully added or a SSH_AGENT_FAILURE if an error occurred.
|
||||
|
||||
2.2.3 Add protocol 2 key
|
||||
|
||||
The OpenSSH agent supports DSA, ECDSA and RSA keys for protocol 2. DSA
|
||||
keys may be added using the following request
|
||||
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-dss"
|
||||
mpint dsa_p
|
||||
mpint dsa_q
|
||||
mpint dsa_g
|
||||
mpint dsa_public_key
|
||||
mpint dsa_private_key
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
DSA certificates may be added with:
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-dss-cert-v00@openssh.com"
|
||||
string certificate
|
||||
mpint dsa_private_key
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
ECDSA keys may be added using the following request
|
||||
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ecdsa-sha2-nistp256" |
|
||||
"ecdsa-sha2-nistp384" |
|
||||
"ecdsa-sha2-nistp521"
|
||||
string ecdsa_curve_name
|
||||
string ecdsa_public_key
|
||||
mpint ecdsa_private
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
ECDSA certificates may be added with:
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ecdsa-sha2-nistp256-cert-v01@openssh.com" |
|
||||
"ecdsa-sha2-nistp384-cert-v01@openssh.com" |
|
||||
"ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
string certificate
|
||||
mpint ecdsa_private_key
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
ED25519 keys may be added using the following request
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-ed25519"
|
||||
string ed25519_public_key
|
||||
string ed25519_private_key || ed25519_public_key
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
ED25519 certificates may be added with:
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-ed25519-cert-v01@openssh.com"
|
||||
string certificate
|
||||
string ed25519_public_key
|
||||
string ed25519_private_key || ed25519_public_key
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
For both ssh-ed25519 and ssh-ed25519-cert-v01@openssh.com keys, the private
|
||||
key has the public key appended (for historical reasons).
|
||||
|
||||
RSA keys may be added with this request:
|
||||
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-rsa"
|
||||
mpint rsa_n
|
||||
mpint rsa_e
|
||||
mpint rsa_d
|
||||
mpint rsa_iqmp
|
||||
mpint rsa_p
|
||||
mpint rsa_q
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
RSA certificates may be added with this request:
|
||||
|
||||
byte SSH2_AGENTC_ADD_IDENTITY or
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED
|
||||
string "ssh-rsa-cert-v00@openssh.com"
|
||||
string certificate
|
||||
mpint rsa_d
|
||||
mpint rsa_iqmp
|
||||
mpint rsa_p
|
||||
mpint rsa_q
|
||||
string key_comment
|
||||
constraint[] key_constraints
|
||||
|
||||
Note that the 'rsa_p' and 'rsa_q' parameters are sent in the reverse
|
||||
order to the protocol 1 add keys message. As with the corresponding
|
||||
protocol 1 "add key" request, the private key is overspecified to avoid
|
||||
redundant processing.
|
||||
|
||||
For DSA, ECDSA and RSA key add requests, "key_constraints" may only be
|
||||
present if the request type is SSH2_AGENTC_ADD_ID_CONSTRAINED.
|
||||
|
||||
The agent will reply with a SSH_AGENT_SUCCESS if the key has been
|
||||
successfully added or a SSH_AGENT_FAILURE if an error occurred.
|
||||
|
||||
2.2.4 Loading keys from a smartcard
|
||||
|
||||
The OpenSSH agent may have optional smartcard support built in to it. If
|
||||
so, it supports an operation to load keys from a smartcard. Technically,
|
||||
only the public components of the keys are loaded into the agent so
|
||||
this operation really arranges for future private key operations to be
|
||||
delegated to the smartcard.
|
||||
|
||||
byte SSH_AGENTC_ADD_SMARTCARD_KEY or
|
||||
SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED
|
||||
string reader_id
|
||||
string pin
|
||||
constraint[] key_constraints
|
||||
|
||||
"reader_id" is an identifier to a smartcard reader and "pin"
|
||||
is a PIN or passphrase used to unlock the private key(s) on the
|
||||
device. "key_constraints" may only be present if the request type is
|
||||
SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED.
|
||||
|
||||
This operation may load all SSH keys that are unlocked using the
|
||||
"pin" on the specified reader. The type of key loaded (protocol 1
|
||||
or protocol 2) will be specified by the smartcard itself, it is not
|
||||
client-specified.
|
||||
|
||||
The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
|
||||
been successfully loaded or a SSH_AGENT_FAILURE if an error occurred.
|
||||
The agent will also return SSH_AGENT_FAILURE if it does not support
|
||||
smartcards.
|
||||
|
||||
2.3 Removing multiple keys
|
||||
|
||||
A client may request that an agent delete all protocol 1 keys using the
|
||||
following request:
|
||||
|
||||
byte SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES
|
||||
|
||||
This message requests the deletion of all protocol 2 keys:
|
||||
|
||||
byte SSH2_AGENTC_REMOVE_ALL_IDENTITIES
|
||||
|
||||
On success, the agent will delete all keys of the requested type and
|
||||
reply with a SSH_AGENT_SUCCESS message. If an error occurred, the agent
|
||||
will reply with SSH_AGENT_FAILURE.
|
||||
|
||||
Note that, to delete all keys (both protocol 1 and 2), a client
|
||||
must send both a SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES and a
|
||||
SSH2_AGENTC_REMOVE_ALL_IDENTITIES request.
|
||||
|
||||
2.4 Removing specific keys
|
||||
|
||||
2.4.1 Removing a protocol 1 key
|
||||
|
||||
Removal of a protocol 1 key may be requested with the following message:
|
||||
|
||||
byte SSH_AGENTC_REMOVE_RSA_IDENTITY
|
||||
uint32 key_bits
|
||||
mpint1 rsa_e
|
||||
mpint1 rsa_n
|
||||
|
||||
Note that key_bits is strictly redundant, as it may be inferred by the
|
||||
length of rsa_n.
|
||||
|
||||
The agent will delete any private key matching the specified public key
|
||||
and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
|
||||
return SSH_AGENT_FAILURE.
|
||||
|
||||
2.4.2 Removing a protocol 2 key
|
||||
|
||||
Protocol 2 keys may be removed with the following request:
|
||||
|
||||
byte SSH2_AGENTC_REMOVE_IDENTITY
|
||||
string key_blob
|
||||
|
||||
Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
|
||||
Algorithms" for any of the supported protocol 2 key types.
|
||||
|
||||
The agent will delete any private key matching the specified public key
|
||||
and return SSH_AGENT_SUCCESS. If no such key was found, the agent will
|
||||
return SSH_AGENT_FAILURE.
|
||||
|
||||
2.4.3 Removing keys loaded from a smartcard
|
||||
|
||||
A client may request that a server remove one or more smartcard-hosted
|
||||
keys using this message:
|
||||
|
||||
byte SSH_AGENTC_REMOVE_SMARTCARD_KEY
|
||||
string reader_id
|
||||
string pin
|
||||
|
||||
"reader_id" the an identifier to a smartcard reader and "pin" is a PIN
|
||||
or passphrase used to unlock the private key(s) on the device.
|
||||
|
||||
When this message is received, and if the agent supports
|
||||
smartcard-hosted keys, it will delete all keys that are hosted on the
|
||||
specified smartcard that may be accessed with the given "pin".
|
||||
|
||||
The agent will reply with a SSH_AGENT_SUCCESS if one or more keys have
|
||||
been successfully removed or a SSH_AGENT_FAILURE if an error occurred.
|
||||
The agent will also return SSH_AGENT_FAILURE if it does not support
|
||||
smartcards.
|
||||
|
||||
2.5 Requesting a list of known keys
|
||||
|
||||
An agent may be requested to list which keys it holds. Different
|
||||
requests exist for protocol 1 and protocol 2 keys.
|
||||
|
||||
2.5.1 Requesting a list of protocol 1 keys
|
||||
|
||||
To request a list of protocol 1 keys that are held in the agent, a
|
||||
client may send the following message:
|
||||
|
||||
byte SSH_AGENTC_REQUEST_RSA_IDENTITIES
|
||||
|
||||
The agent will reply with the following message:
|
||||
|
||||
byte SSH_AGENT_RSA_IDENTITIES_ANSWER
|
||||
uint32 num_keys
|
||||
|
||||
Followed by zero or more consecutive keys, encoded as:
|
||||
|
||||
uint32 bits
|
||||
mpint1 rsa_e
|
||||
mpint1 rsa_n
|
||||
string key_comment
|
||||
|
||||
2.5.2 Requesting a list of protocol 2 keys
|
||||
|
||||
A client may send the following message to request a list of
|
||||
protocol 2 keys that are stored in the agent:
|
||||
|
||||
byte SSH2_AGENTC_REQUEST_IDENTITIES
|
||||
|
||||
The agent will reply with the following message header:
|
||||
|
||||
byte SSH2_AGENT_IDENTITIES_ANSWER
|
||||
uint32 num_keys
|
||||
|
||||
Followed by zero or more consecutive keys, encoded as:
|
||||
|
||||
string key_blob
|
||||
string key_comment
|
||||
|
||||
Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
|
||||
Algorithms" for any of the supported protocol 2 key types.
|
||||
|
||||
2.6 Private key operations
|
||||
|
||||
The purpose of the agent is to perform private key operations, such as
|
||||
signing and encryption without requiring a passphrase to unlock the
|
||||
key and without allowing the private key itself to be exposed. There
|
||||
are separate requests for the protocol 1 and protocol 2 private key
|
||||
operations.
|
||||
|
||||
2.6.1 Protocol 1 private key challenge
|
||||
|
||||
The private key operation used in version 1 of the SSH protocol is
|
||||
decrypting a challenge that has been encrypted with a public key.
|
||||
It may be requested using this message:
|
||||
|
||||
byte SSH_AGENTC_RSA_CHALLENGE
|
||||
uint32 ignored
|
||||
mpint1 rsa_e
|
||||
mpint1 rsa_n
|
||||
mpint1 encrypted_challenge
|
||||
byte[16] session_id
|
||||
uint32 response_type /* must be 1 */
|
||||
|
||||
"rsa_e" and "rsa_n" are used to identify which private key to use.
|
||||
"encrypted_challenge" is a challenge blob that has (presumably)
|
||||
been encrypted with the public key and must be in the range
|
||||
1 <= encrypted_challenge < 2^256. "session_id" is the SSH protocol 1
|
||||
session ID (computed from the server host key, the server semi-ephemeral
|
||||
key and the session cookie).
|
||||
|
||||
"ignored" and "response_type" exist for compatibility with legacy
|
||||
implementations. "response_type" must be equal to 1; other response
|
||||
types are not supported.
|
||||
|
||||
On receiving this request, the server decrypts the "encrypted_challenge"
|
||||
using the private key matching the supplied (rsa_e, rsa_n) values. For
|
||||
the response derivation, the decrypted challenge is represented as an
|
||||
unsigned, big-endian integer encoded in a 32 byte buffer (i.e. values
|
||||
smaller than 2^248 will have leading 0 bytes).
|
||||
|
||||
The response value is then calculated as:
|
||||
|
||||
response = MD5(decrypted_challenge || session_id)
|
||||
|
||||
and returned in the following message
|
||||
|
||||
byte SSH_AGENT_RSA_RESPONSE
|
||||
byte[16] response
|
||||
|
||||
If the agent cannot find the key specified by the supplied (rsa_e,
|
||||
rsa_n) then it will return SSH_AGENT_FAILURE.
|
||||
|
||||
2.6.2 Protocol 2 private key signature request
|
||||
|
||||
A client may use the following message to request signing of data using
|
||||
a protocol 2 key:
|
||||
|
||||
byte SSH2_AGENTC_SIGN_REQUEST
|
||||
string key_blob
|
||||
string data
|
||||
uint32 flags
|
||||
|
||||
Where "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
|
||||
Algorithms" for any of the supported protocol 2 key types. "flags" is
|
||||
a bit-mask, but at present only one possible value is defined (see below
|
||||
for its meaning):
|
||||
|
||||
SSH_AGENT_OLD_SIGNATURE 1
|
||||
|
||||
Upon receiving this request, the agent will look up the private key that
|
||||
corresponds to the public key contained in key_blob. It will use this
|
||||
private key to sign the "data" and produce a signature blob using the
|
||||
key type-specific method described in RFC 4253 section 6.6 "Public Key
|
||||
Algorithms".
|
||||
|
||||
An exception to this is for "ssh-dss" keys where the "flags" word
|
||||
contains the value SSH_AGENT_OLD_SIGNATURE. In this case, a legacy
|
||||
signature encoding is used in lieu of the standard one. In this case,
|
||||
the DSA signature blob is encoded as:
|
||||
|
||||
byte[40] signature
|
||||
|
||||
The signature will be returned in the response message:
|
||||
|
||||
byte SSH2_AGENT_SIGN_RESPONSE
|
||||
string signature_blob
|
||||
|
||||
If the agent cannot find the key specified by the supplied key_blob then
|
||||
it will return SSH_AGENT_FAILURE.
|
||||
|
||||
2.7 Locking or unlocking an agent
|
||||
|
||||
The agent supports temporary locking with a passphrase to suspend
|
||||
processing of sensitive operations until it has been unlocked with the
|
||||
same passphrase. To lock an agent, a client send the following request:
|
||||
|
||||
byte SSH_AGENTC_LOCK
|
||||
string passphrase
|
||||
|
||||
Upon receipt of this message and if the agent is not already locked,
|
||||
it will suspend processing requests and return a SSH_AGENT_SUCCESS
|
||||
reply. If the agent is already locked, it will return SSH_AGENT_FAILURE.
|
||||
|
||||
While locked, the agent will refuse all requests except
|
||||
SSH_AGENTC_UNLOCK, SSH_AGENTC_REQUEST_RSA_IDENTITIES and
|
||||
SSH2_AGENTC_REQUEST_IDENTITIES. The "request identities" requests are
|
||||
treated specially by a locked agent: it will always return an empty list
|
||||
of keys.
|
||||
|
||||
To unlock an agent, a client may request:
|
||||
|
||||
byte SSH_AGENTC_UNLOCK
|
||||
string passphrase
|
||||
|
||||
If the passphrase matches and the agent is locked, then it will resume
|
||||
processing all requests and return SSH_AGENT_SUCCESS. If the agent
|
||||
is not locked or the passphrase does not match then it will return
|
||||
SSH_AGENT_FAILURE.
|
||||
|
||||
Locking and unlocking affects both protocol 1 and protocol 2 keys.
|
||||
|
||||
3. Protocol message numbers
|
||||
|
||||
3.1 Requests from client to agent for protocol 1 key operations
|
||||
|
||||
SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||
SSH_AGENTC_RSA_CHALLENGE 3
|
||||
SSH_AGENTC_ADD_RSA_IDENTITY 7
|
||||
SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||
SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
|
||||
SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24
|
||||
|
||||
3.2 Requests from client to agent for protocol 2 key operations
|
||||
|
||||
SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||
SSH2_AGENTC_SIGN_REQUEST 13
|
||||
SSH2_AGENTC_ADD_IDENTITY 17
|
||||
SSH2_AGENTC_REMOVE_IDENTITY 18
|
||||
SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
|
||||
SSH2_AGENTC_ADD_ID_CONSTRAINED 25
|
||||
|
||||
3.3 Key-type independent requests from client to agent
|
||||
|
||||
SSH_AGENTC_ADD_SMARTCARD_KEY 20
|
||||
SSH_AGENTC_REMOVE_SMARTCARD_KEY 21
|
||||
SSH_AGENTC_LOCK 22
|
||||
SSH_AGENTC_UNLOCK 23
|
||||
SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
|
||||
|
||||
3.4 Generic replies from agent to client
|
||||
|
||||
SSH_AGENT_FAILURE 5
|
||||
SSH_AGENT_SUCCESS 6
|
||||
|
||||
3.5 Replies from agent to client for protocol 1 key operations
|
||||
|
||||
SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||
SSH_AGENT_RSA_RESPONSE 4
|
||||
|
||||
3.6 Replies from agent to client for protocol 2 key operations
|
||||
|
||||
SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||
SSH2_AGENT_SIGN_RESPONSE 14
|
||||
|
||||
3.7 Key constraint identifiers
|
||||
|
||||
SSH_AGENT_CONSTRAIN_LIFETIME 1
|
||||
SSH_AGENT_CONSTRAIN_CONFIRM 2
|
||||
|
||||
$OpenBSD: PROTOCOL.agent,v 1.11 2016/05/19 07:45:32 djm Exp $
|
||||
https://tools.ietf.org/html/draft-miller-ssh-agent-02
|
||||
|
@ -192,12 +192,13 @@ compatibility.
|
||||
The reserved field is currently unused and is ignored in this version of
|
||||
the protocol.
|
||||
|
||||
signature key contains the CA key used to sign the certificate.
|
||||
The valid key types for CA keys are ssh-rsa, ssh-dss and the ECDSA types
|
||||
ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained"
|
||||
certificates, where the signature key type is a certificate type itself
|
||||
are NOT supported. Note that it is possible for a RSA certificate key to
|
||||
be signed by a DSS or ECDSA CA key and vice-versa.
|
||||
The signature key field contains the CA key used to sign the
|
||||
certificate. The valid key types for CA keys are ssh-rsa,
|
||||
ssh-dss, ssh-ed25519 and the ECDSA types ecdsa-sha2-nistp256,
|
||||
ecdsa-sha2-nistp384, ecdsa-sha2-nistp521. "Chained" certificates, where
|
||||
the signature key type is a certificate type itself are NOT supported.
|
||||
Note that it is possible for a RSA certificate key to be signed by a
|
||||
Ed25519 or ECDSA CA key and vice-versa.
|
||||
|
||||
signature is computed over all preceding fields from the initial string
|
||||
up to, and including the signature key. Signatures are computed and
|
||||
@ -223,6 +224,9 @@ option-specific information (see below). All options are
|
||||
"critical", if an implementation does not recognise a option
|
||||
then the validating party should refuse to accept the certificate.
|
||||
|
||||
Custom options should append the originating author or organisation's
|
||||
domain name to the option name, e.g. "my-option@example.com".
|
||||
|
||||
No critical options are defined for host certificates at present. The
|
||||
supported user certificate options and the contents and structure of
|
||||
their data fields are:
|
||||
@ -254,6 +258,9 @@ as is the requirement that each name appear only once.
|
||||
If an implementation does not recognise an extension, then it should
|
||||
ignore it.
|
||||
|
||||
Custom options should append the originating author or organisation's
|
||||
domain name to the option name, e.g. "my-option@example.com".
|
||||
|
||||
No extensions are defined for host certificates at present. The
|
||||
supported user certificate extensions and the contents and structure of
|
||||
their data fields are:
|
||||
@ -284,4 +291,4 @@ permit-user-rc empty Flag indicating that execution of
|
||||
of this script will not be permitted if
|
||||
this option is not present.
|
||||
|
||||
$OpenBSD: PROTOCOL.certkeys,v 1.10 2016/05/03 10:27:59 djm Exp $
|
||||
$OpenBSD: PROTOCOL.certkeys,v 1.12 2017/05/31 04:29:44 djm Exp $
|
||||
|
10
README
10
README
@ -1,4 +1,4 @@
|
||||
See https://www.openssh.com/releasenotes.html#7.5p1 for the release notes.
|
||||
See https://www.openssh.com/releasenotes.html#7.6p1 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
|
||||
@ -30,7 +30,8 @@ The PAM support is now more functional than the popular packages of
|
||||
commercial ssh-1.2.x. It checks "account" and "session" modules for
|
||||
all logins, not just when using password authentication.
|
||||
|
||||
OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5].
|
||||
OpenSSH depends on Zlib[3], OpenSSL[4], and optionally PAM[5] and
|
||||
libedit[6]
|
||||
|
||||
There is now several mailing lists for this port of OpenSSH. Please
|
||||
refer to https://www.openssh.com/list.html for details on how to join.
|
||||
@ -38,7 +39,7 @@ refer to https://www.openssh.com/list.html for details on how to join.
|
||||
Please send bug reports and patches to the mailing list
|
||||
openssh-unix-dev@mindrot.org. The list is open to posting by unsubscribed
|
||||
users. Code contribution are welcomed, but please follow the OpenBSD
|
||||
style guidelines[6].
|
||||
style guidelines[7].
|
||||
|
||||
Please refer to the INSTALL document for information on how to install
|
||||
OpenSSH on your system.
|
||||
@ -61,4 +62,5 @@ References -
|
||||
[5] http://www.openpam.org
|
||||
http://www.kernel.org/pub/linux/libs/pam/
|
||||
(PAM also is standard on Solaris and HP-UX 11)
|
||||
[6] http://man.openbsd.org/style.9
|
||||
[6] http://thrysoee.dk/editline/ (portable version)
|
||||
[7] http://man.openbsd.org/style.9
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth-options.c,v 1.72 2016/11/30 02:57:40 djm Exp $ */
|
||||
/* $OpenBSD: auth-options.c,v 1.74 2017/09/12 06:32:07 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -61,9 +61,13 @@ char *authorized_principals = NULL;
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
/* XXX refactor to be stateless */
|
||||
|
||||
void
|
||||
auth_clear_options(void)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
|
||||
no_agent_forwarding_flag = 0;
|
||||
no_port_forwarding_flag = 0;
|
||||
no_pty_flag = 0;
|
||||
@ -81,7 +85,7 @@ auth_clear_options(void)
|
||||
free(authorized_principals);
|
||||
authorized_principals = NULL;
|
||||
forced_tun_device = -1;
|
||||
channel_clear_permitted_opens();
|
||||
channel_clear_permitted_opens(ssh);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -117,9 +121,11 @@ match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
|
||||
/*
|
||||
* return 1 if access is granted, 0 if not.
|
||||
* side effect: sets key option flags
|
||||
* XXX remove side effects; fill structure instead.
|
||||
*/
|
||||
int
|
||||
auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
|
||||
auth_parse_options(struct passwd *pw, char *opts, const char *file,
|
||||
u_long linenum)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
const char *cp;
|
||||
@ -379,7 +385,7 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
|
||||
goto bad_option;
|
||||
}
|
||||
if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
|
||||
channel_add_permitted_opens(host, port);
|
||||
channel_add_permitted_opens(ssh, host, port);
|
||||
free(patterns);
|
||||
goto next_option;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth-options.h,v 1.22 2016/11/30 02:57:40 djm Exp $ */
|
||||
/* $OpenBSD: auth-options.h,v 1.23 2017/05/31 10:54:00 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -33,7 +33,7 @@ extern int forced_tun_device;
|
||||
extern int key_is_cert_authority;
|
||||
extern char *authorized_principals;
|
||||
|
||||
int auth_parse_options(struct passwd *, char *, char *, u_long);
|
||||
int auth_parse_options(struct passwd *, char *, const char *, u_long);
|
||||
void auth_clear_options(void);
|
||||
int auth_cert_options(struct sshkey *, struct passwd *, const char **);
|
||||
|
||||
|
47
auth-pam.c
47
auth-pam.c
@ -106,7 +106,6 @@ extern char *__progname;
|
||||
|
||||
extern ServerOptions options;
|
||||
extern Buffer loginmsg;
|
||||
extern int compat20;
|
||||
extern u_int utmp_len;
|
||||
|
||||
/* so we don't silently change behaviour */
|
||||
@ -468,18 +467,16 @@ sshpam_thread(void *ctxtp)
|
||||
if (sshpam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
|
||||
if (compat20) {
|
||||
if (!do_pam_account()) {
|
||||
sshpam_err = PAM_ACCT_EXPIRED;
|
||||
if (!do_pam_account()) {
|
||||
sshpam_err = PAM_ACCT_EXPIRED;
|
||||
goto auth_fail;
|
||||
}
|
||||
if (sshpam_authctxt->force_pwchange) {
|
||||
sshpam_err = pam_chauthtok(sshpam_handle,
|
||||
PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (sshpam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
}
|
||||
if (sshpam_authctxt->force_pwchange) {
|
||||
sshpam_err = pam_chauthtok(sshpam_handle,
|
||||
PAM_CHANGE_EXPIRED_AUTHTOK);
|
||||
if (sshpam_err != PAM_SUCCESS)
|
||||
goto auth_fail;
|
||||
sshpam_password_change_required(0);
|
||||
}
|
||||
sshpam_password_change_required(0);
|
||||
}
|
||||
|
||||
buffer_put_cstring(&buffer, "OK");
|
||||
@ -929,6 +926,27 @@ finish_pam(void)
|
||||
sshpam_cleanup();
|
||||
}
|
||||
|
||||
static void
|
||||
expose_authinfo(const char *caller)
|
||||
{
|
||||
char *auth_info;
|
||||
|
||||
/*
|
||||
* Expose authentication information to PAM.
|
||||
* The enviornment variable is versioned. Please increment the
|
||||
* version suffix if the format of session_info changes.
|
||||
*/
|
||||
if (sshpam_authctxt->session_info == NULL)
|
||||
auth_info = xstrdup("");
|
||||
else if ((auth_info = sshbuf_dup_string(
|
||||
sshpam_authctxt->session_info)) == NULL)
|
||||
fatal("%s: sshbuf_dup_string failed", __func__);
|
||||
|
||||
debug2("%s: auth information in SSH_AUTH_INFO_0", caller);
|
||||
do_pam_putenv("SSH_AUTH_INFO_0", auth_info);
|
||||
free(auth_info);
|
||||
}
|
||||
|
||||
u_int
|
||||
do_pam_account(void)
|
||||
{
|
||||
@ -936,6 +954,8 @@ do_pam_account(void)
|
||||
if (sshpam_account_status != -1)
|
||||
return (sshpam_account_status);
|
||||
|
||||
expose_authinfo(__func__);
|
||||
|
||||
sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
|
||||
debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
|
||||
pam_strerror(sshpam_handle, sshpam_err));
|
||||
@ -1060,6 +1080,9 @@ void
|
||||
do_pam_session(void)
|
||||
{
|
||||
debug3("PAM: opening session");
|
||||
|
||||
expose_authinfo(__func__);
|
||||
|
||||
sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
|
||||
(const void *)&store_conv);
|
||||
if (sshpam_err != PAM_SUCCESS)
|
||||
|
165
auth.c
165
auth.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth.c,v 1.119 2016/12/15 21:29:05 dtucker Exp $ */
|
||||
/* $OpenBSD: auth.c,v 1.124 2017/09/12 06:32:07 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -43,9 +43,6 @@
|
||||
#ifdef USE_SHADOW
|
||||
#include <shadow.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -267,21 +264,41 @@ allowed_user(struct passwd * pw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
auth_info(Authctxt *authctxt, const char *fmt, ...)
|
||||
/*
|
||||
* Formats any key left in authctxt->auth_method_key for inclusion in
|
||||
* auth_log()'s message. Also includes authxtct->auth_method_info if present.
|
||||
*/
|
||||
static char *
|
||||
format_method_key(Authctxt *authctxt)
|
||||
{
|
||||
va_list ap;
|
||||
int i;
|
||||
const struct sshkey *key = authctxt->auth_method_key;
|
||||
const char *methinfo = authctxt->auth_method_info;
|
||||
char *fp, *ret = NULL;
|
||||
|
||||
free(authctxt->info);
|
||||
authctxt->info = NULL;
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
i = vasprintf(&authctxt->info, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (i < 0 || authctxt->info == NULL)
|
||||
fatal("vasprintf failed");
|
||||
if (key_is_cert(key)) {
|
||||
fp = sshkey_fingerprint(key->cert->signature_key,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT);
|
||||
xasprintf(&ret, "%s ID %s (serial %llu) CA %s %s%s%s",
|
||||
sshkey_type(key), key->cert->key_id,
|
||||
(unsigned long long)key->cert->serial,
|
||||
sshkey_type(key->cert->signature_key),
|
||||
fp == NULL ? "(null)" : fp,
|
||||
methinfo == NULL ? "" : ", ",
|
||||
methinfo == NULL ? "" : methinfo);
|
||||
free(fp);
|
||||
} else {
|
||||
fp = sshkey_fingerprint(key, options.fingerprint_hash,
|
||||
SSH_FP_DEFAULT);
|
||||
xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
|
||||
fp == NULL ? "(null)" : fp,
|
||||
methinfo == NULL ? "" : ", ",
|
||||
methinfo == NULL ? "" : methinfo);
|
||||
free(fp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
@ -290,7 +307,8 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
void (*authlog) (const char *fmt,...) = verbose;
|
||||
char *authmsg;
|
||||
const char *authmsg;
|
||||
char *extra = NULL;
|
||||
|
||||
if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
|
||||
return;
|
||||
@ -309,6 +327,11 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
|
||||
else
|
||||
authmsg = authenticated ? "Accepted" : "Failed";
|
||||
|
||||
if ((extra = format_method_key(authctxt)) == NULL) {
|
||||
if (authctxt->auth_method_info != NULL)
|
||||
extra = xstrdup(authctxt->auth_method_info);
|
||||
}
|
||||
|
||||
authlog("%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
|
||||
authmsg,
|
||||
method,
|
||||
@ -317,10 +340,10 @@ auth_log(Authctxt *authctxt, int authenticated, int partial,
|
||||
authctxt->user,
|
||||
ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh),
|
||||
authctxt->info != NULL ? ": " : "",
|
||||
authctxt->info != NULL ? authctxt->info : "");
|
||||
free(authctxt->info);
|
||||
authctxt->info = NULL;
|
||||
extra != NULL ? ": " : "",
|
||||
extra != NULL ? extra : "");
|
||||
|
||||
free(extra);
|
||||
|
||||
#ifdef CUSTOM_FAILED_LOGIN
|
||||
if (authenticated == 0 && !authctxt->postponed &&
|
||||
@ -428,7 +451,7 @@ authorized_principals_file(struct passwd *pw)
|
||||
|
||||
/* return ok if key exists in sysfile or userfile */
|
||||
HostStatus
|
||||
check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
|
||||
check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
|
||||
const char *sysfile, const char *userfile)
|
||||
{
|
||||
char *user_hostfile;
|
||||
@ -472,98 +495,6 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
|
||||
return host_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a given path for security. This is defined as all components
|
||||
* of the path to the file must be owned by either the owner of
|
||||
* of the file or root and no directories must be group or world writable.
|
||||
*
|
||||
* XXX Should any specific check be done for sym links ?
|
||||
*
|
||||
* Takes a file name, its stat information (preferably from fstat() to
|
||||
* avoid races), the uid of the expected owner, their home directory and an
|
||||
* error buffer plus max size as arguments.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
int
|
||||
auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
|
||||
uid_t uid, char *err, size_t errlen)
|
||||
{
|
||||
char buf[PATH_MAX], homedir[PATH_MAX];
|
||||
char *cp;
|
||||
int comparehome = 0;
|
||||
struct stat st;
|
||||
|
||||
if (realpath(name, buf) == NULL) {
|
||||
snprintf(err, errlen, "realpath %s failed: %s", name,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
|
||||
comparehome = 1;
|
||||
|
||||
if (!S_ISREG(stp->st_mode)) {
|
||||
snprintf(err, errlen, "%s is not a regular file", buf);
|
||||
return -1;
|
||||
}
|
||||
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
|
||||
(stp->st_mode & 022) != 0) {
|
||||
snprintf(err, errlen, "bad ownership or modes for file %s",
|
||||
buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for each component of the canonical path, walking upwards */
|
||||
for (;;) {
|
||||
if ((cp = dirname(buf)) == NULL) {
|
||||
snprintf(err, errlen, "dirname() failed");
|
||||
return -1;
|
||||
}
|
||||
strlcpy(buf, cp, sizeof(buf));
|
||||
|
||||
if (stat(buf, &st) < 0 ||
|
||||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(err, errlen,
|
||||
"bad ownership or modes for directory %s", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If are past the homedir then we can stop */
|
||||
if (comparehome && strcmp(homedir, buf) == 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* dirname should always complete with a "/" path,
|
||||
* but we can be paranoid and check for "." too
|
||||
*/
|
||||
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of secure_path() that accepts an open file descriptor to
|
||||
* avoid races.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
static int
|
||||
secure_filename(FILE *f, const char *file, struct passwd *pw,
|
||||
char *err, size_t errlen)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
/* check the open file to avoid races */
|
||||
if (fstat(fileno(f), &st) < 0) {
|
||||
snprintf(err, errlen, "cannot stat file %s: %s",
|
||||
file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
|
||||
}
|
||||
|
||||
static FILE *
|
||||
auth_openfile(const char *file, struct passwd *pw, int strict_modes,
|
||||
int log_missing, char *file_type)
|
||||
@ -596,7 +527,7 @@ auth_openfile(const char *file, struct passwd *pw, int strict_modes,
|
||||
return NULL;
|
||||
}
|
||||
if (strict_modes &&
|
||||
secure_filename(f, file, pw, line, sizeof(line)) != 0) {
|
||||
safe_path_fd(fileno(f), file, pw, line, sizeof(line)) != 0) {
|
||||
fclose(f);
|
||||
logit("Authentication refused: %s", line);
|
||||
auth_debug_add("Ignored %s: %s", file_type, line);
|
||||
@ -635,6 +566,8 @@ getpwnamallow(const char *user)
|
||||
|
||||
ci->user = user;
|
||||
parse_server_match_config(&options, ci);
|
||||
log_change_level(options.log_level);
|
||||
process_permitopen(ssh, &options);
|
||||
|
||||
#if defined(_AIX) && defined(HAVE_SETAUTHDB)
|
||||
aix_setauthdb(user);
|
||||
@ -694,7 +627,7 @@ getpwnamallow(const char *user)
|
||||
|
||||
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
|
||||
int
|
||||
auth_key_is_revoked(Key *key)
|
||||
auth_key_is_revoked(struct sshkey *key)
|
||||
{
|
||||
char *fp = NULL;
|
||||
int r;
|
||||
|
81
auth.h
81
auth.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth.h,v 1.89 2016/08/13 17:47:41 markus Exp $ */
|
||||
/* $OpenBSD: auth.h,v 1.93 2017/08/18 05:36:45 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
@ -44,6 +44,7 @@
|
||||
|
||||
struct ssh;
|
||||
struct sshkey;
|
||||
struct sshbuf;
|
||||
|
||||
typedef struct Authctxt Authctxt;
|
||||
typedef struct Authmethod Authmethod;
|
||||
@ -62,13 +63,17 @@ struct Authctxt {
|
||||
char *service;
|
||||
struct passwd *pw; /* set if 'valid' */
|
||||
char *style;
|
||||
|
||||
/* Method lists for multiple authentication */
|
||||
char **auth_methods; /* modified from server config */
|
||||
u_int num_auth_methods;
|
||||
|
||||
/* Authentication method-specific data */
|
||||
void *methoddata;
|
||||
void *kbdintctxt;
|
||||
char *info; /* Extra info for next auth_log */
|
||||
#ifdef BSD_AUTH
|
||||
auth_session_t *as;
|
||||
#endif
|
||||
char **auth_methods; /* modified from server config */
|
||||
u_int num_auth_methods;
|
||||
#ifdef KRB5
|
||||
krb5_context krb5_ctx;
|
||||
krb5_ccache krb5_fwd_ccache;
|
||||
@ -76,12 +81,20 @@ struct Authctxt {
|
||||
char *krb5_ticket_file;
|
||||
char *krb5_ccname;
|
||||
#endif
|
||||
Buffer *loginmsg;
|
||||
void *methoddata;
|
||||
struct sshbuf *loginmsg;
|
||||
|
||||
struct sshkey **prev_userkeys;
|
||||
u_int nprev_userkeys;
|
||||
/* Authentication keys already used; these will be refused henceforth */
|
||||
struct sshkey **prev_keys;
|
||||
u_int nprev_keys;
|
||||
|
||||
/* Last used key and ancilliary information from active auth method */
|
||||
struct sshkey *auth_method_key;
|
||||
char *auth_method_info;
|
||||
|
||||
/* Information exposed to session */
|
||||
struct sshbuf *session_info; /* Auth info for environment */
|
||||
};
|
||||
|
||||
/*
|
||||
* Every authentication method has to handle authentication requests for
|
||||
* non-existing users, or for users that are not allowed to login. In this
|
||||
@ -91,7 +104,7 @@ struct Authctxt {
|
||||
|
||||
struct Authmethod {
|
||||
char *name;
|
||||
int (*userauth)(Authctxt *authctxt);
|
||||
int (*userauth)(struct ssh *);
|
||||
int *enabled;
|
||||
};
|
||||
|
||||
@ -117,16 +130,21 @@ auth_rhosts2(struct passwd *, const char *, const char *, const char *);
|
||||
|
||||
int auth_password(Authctxt *, const char *);
|
||||
|
||||
int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
|
||||
int user_key_allowed(struct passwd *, Key *, int);
|
||||
void pubkey_auth_info(Authctxt *, const Key *, const char *, ...)
|
||||
__attribute__((__format__ (printf, 3, 4)));
|
||||
void auth2_record_userkey(Authctxt *, struct sshkey *);
|
||||
int auth2_userkey_already_used(Authctxt *, struct sshkey *);
|
||||
int hostbased_key_allowed(struct passwd *, const char *, char *,
|
||||
struct sshkey *);
|
||||
int user_key_allowed(struct passwd *, struct sshkey *, int);
|
||||
int auth2_key_already_used(Authctxt *, const struct sshkey *);
|
||||
|
||||
struct stat;
|
||||
int auth_secure_path(const char *, struct stat *, const char *, uid_t,
|
||||
char *, size_t);
|
||||
/*
|
||||
* Handling auth method-specific information for logging and prevention
|
||||
* of key reuse during multiple authentication.
|
||||
*/
|
||||
void auth2_authctxt_reset_info(Authctxt *);
|
||||
void auth2_record_key(Authctxt *, int, const struct sshkey *);
|
||||
void auth2_record_info(Authctxt *authctxt, const char *, ...)
|
||||
__attribute__((__format__ (printf, 2, 3)))
|
||||
__attribute__((__nonnull__ (2)));
|
||||
void auth2_update_session_info(Authctxt *, const char *, const char *);
|
||||
|
||||
#ifdef KRB5
|
||||
int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
|
||||
@ -149,12 +167,9 @@ void disable_forwarding(void);
|
||||
|
||||
void do_authentication2(Authctxt *);
|
||||
|
||||
void auth_info(Authctxt *authctxt, const char *, ...)
|
||||
__attribute__((__format__ (printf, 2, 3)))
|
||||
__attribute__((__nonnull__ (2)));
|
||||
void auth_log(Authctxt *, int, int, const char *, const char *);
|
||||
void auth_maxtries_exceeded(Authctxt *) __attribute__((noreturn));
|
||||
void userauth_finish(Authctxt *, int, const char *, const char *);
|
||||
void userauth_finish(struct ssh *, int, const char *, const char *);
|
||||
int auth_root_allowed(const char *);
|
||||
|
||||
void userauth_send_banner(const char *);
|
||||
@ -167,8 +182,8 @@ int auth2_method_allowed(Authctxt *, const char *, const char *);
|
||||
|
||||
void privsep_challenge_enable(void);
|
||||
|
||||
int auth2_challenge(Authctxt *, char *);
|
||||
void auth2_challenge_stop(Authctxt *);
|
||||
int auth2_challenge(struct ssh *, char *);
|
||||
void auth2_challenge_stop(struct ssh *);
|
||||
int bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **);
|
||||
int bsdauth_respond(void *, u_int, char **);
|
||||
int skey_query(void *, char **, char **, u_int *, char ***, u_int **);
|
||||
@ -182,22 +197,22 @@ char *authorized_principals_file(struct passwd *);
|
||||
|
||||
FILE *auth_openkeyfile(const char *, struct passwd *, int);
|
||||
FILE *auth_openprincipals(const char *, struct passwd *, int);
|
||||
int auth_key_is_revoked(Key *);
|
||||
int auth_key_is_revoked(struct sshkey *);
|
||||
|
||||
const char *auth_get_canonical_hostname(struct ssh *, int);
|
||||
|
||||
HostStatus
|
||||
check_key_in_hostfiles(struct passwd *, Key *, const char *,
|
||||
check_key_in_hostfiles(struct passwd *, struct sshkey *, const char *,
|
||||
const char *, const char *);
|
||||
|
||||
/* hostkey handling */
|
||||
Key *get_hostkey_by_index(int);
|
||||
Key *get_hostkey_public_by_index(int, struct ssh *);
|
||||
Key *get_hostkey_public_by_type(int, int, struct ssh *);
|
||||
Key *get_hostkey_private_by_type(int, int, struct ssh *);
|
||||
int get_hostkey_index(Key *, int, struct ssh *);
|
||||
int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *,
|
||||
const u_char *, size_t, const char *, u_int);
|
||||
struct sshkey *get_hostkey_by_index(int);
|
||||
struct sshkey *get_hostkey_public_by_index(int, struct ssh *);
|
||||
struct sshkey *get_hostkey_public_by_type(int, int, struct ssh *);
|
||||
struct sshkey *get_hostkey_private_by_type(int, int, struct ssh *);
|
||||
int get_hostkey_index(struct sshkey *, int, struct ssh *);
|
||||
int sshd_hostkey_sign(struct sshkey *, struct sshkey *, u_char **,
|
||||
size_t *, const u_char *, size_t, const char *, u_int);
|
||||
|
||||
/* debug messages during authentication */
|
||||
void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2)));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-chall.c,v 1.44 2016/05/02 08:49:03 djm Exp $ */
|
||||
/* $OpenBSD: auth2-chall.c,v 1.48 2017/05/30 14:29:59 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2001 Per Allansson. All rights reserved.
|
||||
@ -47,9 +47,9 @@
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
|
||||
static int auth2_challenge_start(Authctxt *);
|
||||
static int auth2_challenge_start(struct ssh *);
|
||||
static int send_userauth_info_request(Authctxt *);
|
||||
static int input_userauth_info_response(int, u_int32_t, void *);
|
||||
static int input_userauth_info_response(int, u_int32_t, struct ssh *);
|
||||
|
||||
#ifdef BSD_AUTH
|
||||
extern KbdintDevice bsdauth_device;
|
||||
@ -195,8 +195,9 @@ kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
|
||||
* wait for the response.
|
||||
*/
|
||||
int
|
||||
auth2_challenge(Authctxt *authctxt, char *devs)
|
||||
auth2_challenge(struct ssh *ssh, char *devs)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
debug("auth2_challenge: user=%s devs=%s",
|
||||
authctxt->user ? authctxt->user : "<nouser>",
|
||||
devs ? devs : "<no devs>");
|
||||
@ -205,15 +206,16 @@ auth2_challenge(Authctxt *authctxt, char *devs)
|
||||
return 0;
|
||||
if (authctxt->kbdintctxt == NULL)
|
||||
authctxt->kbdintctxt = kbdint_alloc(devs);
|
||||
return auth2_challenge_start(authctxt);
|
||||
return auth2_challenge_start(ssh);
|
||||
}
|
||||
|
||||
/* unregister kbd-int callbacks and context */
|
||||
void
|
||||
auth2_challenge_stop(Authctxt *authctxt)
|
||||
auth2_challenge_stop(struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
/* unregister callback */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
|
||||
if (authctxt->kbdintctxt != NULL) {
|
||||
kbdint_free(authctxt->kbdintctxt);
|
||||
authctxt->kbdintctxt = NULL;
|
||||
@ -222,29 +224,30 @@ auth2_challenge_stop(Authctxt *authctxt)
|
||||
|
||||
/* side effect: sets authctxt->postponed if a reply was sent*/
|
||||
static int
|
||||
auth2_challenge_start(Authctxt *authctxt)
|
||||
auth2_challenge_start(struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
|
||||
|
||||
debug2("auth2_challenge_start: devices %s",
|
||||
kbdintctxt->devices ? kbdintctxt->devices : "<empty>");
|
||||
|
||||
if (kbdint_next_device(authctxt, kbdintctxt) == 0) {
|
||||
auth2_challenge_stop(authctxt);
|
||||
auth2_challenge_stop(ssh);
|
||||
return 0;
|
||||
}
|
||||
debug("auth2_challenge_start: trying authentication method '%s'",
|
||||
kbdintctxt->device->name);
|
||||
|
||||
if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
|
||||
auth2_challenge_stop(authctxt);
|
||||
auth2_challenge_stop(ssh);
|
||||
return 0;
|
||||
}
|
||||
if (send_userauth_info_request(authctxt) == 0) {
|
||||
auth2_challenge_stop(authctxt);
|
||||
auth2_challenge_stop(ssh);
|
||||
return 0;
|
||||
}
|
||||
dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_INFO_RESPONSE,
|
||||
&input_userauth_info_response);
|
||||
|
||||
authctxt->postponed = 1;
|
||||
@ -285,9 +288,9 @@ send_userauth_info_request(Authctxt *authctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
|
||||
input_userauth_info_response(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
KbdintAuthctxt *kbdintctxt;
|
||||
int authenticated = 0, res;
|
||||
u_int i, nresp;
|
||||
@ -340,14 +343,14 @@ input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
|
||||
devicename = kbdintctxt->device->name;
|
||||
if (!authctxt->postponed) {
|
||||
if (authenticated) {
|
||||
auth2_challenge_stop(authctxt);
|
||||
auth2_challenge_stop(ssh);
|
||||
} else {
|
||||
/* start next device */
|
||||
/* may set authctxt->postponed */
|
||||
auth2_challenge_start(authctxt);
|
||||
auth2_challenge_start(ssh);
|
||||
}
|
||||
}
|
||||
userauth_finish(authctxt, authenticated, "keyboard-interactive",
|
||||
userauth_finish(ssh, authenticated, "keyboard-interactive",
|
||||
devicename);
|
||||
return 0;
|
||||
}
|
||||
|
77
auth2-gss.c
77
auth2-gss.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */
|
||||
/* $OpenBSD: auth2-gss.c,v 1.26 2017/06/24 06:34:38 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
|
||||
@ -48,18 +48,19 @@
|
||||
|
||||
extern ServerOptions options;
|
||||
|
||||
static int input_gssapi_token(int type, u_int32_t plen, void *ctxt);
|
||||
static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
|
||||
static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
|
||||
static int input_gssapi_errtok(int, u_int32_t, void *);
|
||||
static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh);
|
||||
static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh);
|
||||
static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
|
||||
static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
|
||||
|
||||
/*
|
||||
* We only support those mechanisms that we know about (ie ones that we know
|
||||
* how to check local user kuserok and the like)
|
||||
*/
|
||||
static int
|
||||
userauth_gssapi(Authctxt *authctxt)
|
||||
userauth_gssapi(struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
gss_OID_desc goid = {0, NULL};
|
||||
Gssctxt *ctxt = NULL;
|
||||
int mechs;
|
||||
@ -119,17 +120,17 @@ userauth_gssapi(Authctxt *authctxt)
|
||||
packet_send();
|
||||
free(doid);
|
||||
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
|
||||
authctxt->postponed = 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
input_gssapi_token(int type, u_int32_t plen, void *ctxt)
|
||||
input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
Gssctxt *gssctxt;
|
||||
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc recv_tok;
|
||||
@ -157,8 +158,8 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
|
||||
packet_send();
|
||||
}
|
||||
authctxt->postponed = 0;
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
userauth_finish(authctxt, 0, "gssapi-with-mic", NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
userauth_finish(ssh, 0, "gssapi-with-mic", NULL);
|
||||
} else {
|
||||
if (send_tok.length != 0) {
|
||||
packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
|
||||
@ -166,12 +167,12 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
|
||||
packet_send();
|
||||
}
|
||||
if (maj_status == GSS_S_COMPLETE) {
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
if (flags & GSS_C_INTEG_FLAG)
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC,
|
||||
&input_gssapi_mic);
|
||||
else
|
||||
dispatch_set(
|
||||
ssh_dispatch_set(ssh,
|
||||
SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
|
||||
&input_gssapi_exchange_complete);
|
||||
}
|
||||
@ -182,9 +183,9 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
|
||||
input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
Gssctxt *gssctxt;
|
||||
gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc recv_tok;
|
||||
@ -207,8 +208,8 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
|
||||
free(recv_tok.value);
|
||||
|
||||
/* We can't return anything to the client, even if we wanted to */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
|
||||
/* The client will have already moved on to the next auth */
|
||||
|
||||
@ -223,10 +224,11 @@ input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
|
||||
*/
|
||||
|
||||
static int
|
||||
input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
|
||||
input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
int authenticated;
|
||||
const char *displayname;
|
||||
|
||||
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
|
||||
fatal("No authentication or GSSAPI context");
|
||||
@ -240,24 +242,29 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
|
||||
|
||||
authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
|
||||
|
||||
if ((!use_privsep || mm_is_monitor()) &&
|
||||
(displayname = ssh_gssapi_displayname()) != NULL)
|
||||
auth2_record_info(authctxt, "%s", displayname);
|
||||
|
||||
authctxt->postponed = 0;
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
|
||||
input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
Gssctxt *gssctxt;
|
||||
int authenticated = 0;
|
||||
Buffer b;
|
||||
gss_buffer_desc mic, gssbuf;
|
||||
u_int len;
|
||||
const char *displayname;
|
||||
|
||||
if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
|
||||
fatal("No authentication or GSSAPI context");
|
||||
@ -281,12 +288,16 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
|
||||
buffer_free(&b);
|
||||
free(mic.value);
|
||||
|
||||
if ((!use_privsep || mm_is_monitor()) &&
|
||||
(displayname = ssh_gssapi_displayname()) != NULL)
|
||||
auth2_record_info(authctxt, "%s", displayname);
|
||||
|
||||
authctxt->postponed = 0;
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-hostbased.c,v 1.26 2016/03/07 19:02:43 djm Exp $ */
|
||||
/* $OpenBSD: auth2-hostbased.c,v 1.31 2017/06/24 06:34:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -39,7 +39,7 @@
|
||||
#include "misc.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "key.h"
|
||||
#include "sshkey.h"
|
||||
#include "hostfile.h"
|
||||
#include "auth.h"
|
||||
#include "canohost.h"
|
||||
@ -48,6 +48,7 @@
|
||||
#endif
|
||||
#include "monitor_wrap.h"
|
||||
#include "pathnames.h"
|
||||
#include "ssherr.h"
|
||||
#include "match.h"
|
||||
|
||||
/* import */
|
||||
@ -56,54 +57,56 @@ extern u_char *session_id2;
|
||||
extern u_int session_id2_len;
|
||||
|
||||
static int
|
||||
userauth_hostbased(Authctxt *authctxt)
|
||||
userauth_hostbased(struct ssh *ssh)
|
||||
{
|
||||
Buffer b;
|
||||
Key *key = NULL;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
struct sshbuf *b;
|
||||
struct sshkey *key = NULL;
|
||||
char *pkalg, *cuser, *chost, *service;
|
||||
u_char *pkblob, *sig;
|
||||
u_int alen, blen, slen;
|
||||
int pktype;
|
||||
int authenticated = 0;
|
||||
size_t alen, blen, slen;
|
||||
int r, pktype, authenticated = 0;
|
||||
|
||||
if (!authctxt->valid) {
|
||||
debug2("userauth_hostbased: disabled because of invalid user");
|
||||
debug2("%s: disabled because of invalid user", __func__);
|
||||
return 0;
|
||||
}
|
||||
pkalg = packet_get_string(&alen);
|
||||
pkblob = packet_get_string(&blen);
|
||||
chost = packet_get_string(NULL);
|
||||
cuser = packet_get_string(NULL);
|
||||
sig = packet_get_string(&slen);
|
||||
/* XXX use sshkey_froms() */
|
||||
if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
|
||||
(r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
|
||||
(r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &sig, &slen)) != 0)
|
||||
fatal("%s: packet parsing: %s", __func__, ssh_err(r));
|
||||
|
||||
debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
|
||||
debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__,
|
||||
cuser, chost, pkalg, slen);
|
||||
#ifdef DEBUG_PK
|
||||
debug("signature:");
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, sig, slen);
|
||||
buffer_dump(&b);
|
||||
buffer_free(&b);
|
||||
sshbuf_dump_data(sig, siglen, stderr);
|
||||
#endif
|
||||
pktype = key_type_from_name(pkalg);
|
||||
pktype = sshkey_type_from_name(pkalg);
|
||||
if (pktype == KEY_UNSPEC) {
|
||||
/* this is perfectly legal */
|
||||
logit("userauth_hostbased: unsupported "
|
||||
"public key algorithm: %s", pkalg);
|
||||
logit("%s: unsupported public key algorithm: %s",
|
||||
__func__, pkalg);
|
||||
goto done;
|
||||
}
|
||||
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
|
||||
error("%s: key_from_blob: %s", __func__, ssh_err(r));
|
||||
goto done;
|
||||
}
|
||||
key = key_from_blob(pkblob, blen);
|
||||
if (key == NULL) {
|
||||
error("userauth_hostbased: cannot decode key: %s", pkalg);
|
||||
error("%s: cannot decode key: %s", __func__, pkalg);
|
||||
goto done;
|
||||
}
|
||||
if (key->type != pktype) {
|
||||
error("userauth_hostbased: type mismatch for decoded key "
|
||||
"(received %d, expected %d)", key->type, pktype);
|
||||
error("%s: type mismatch for decoded key "
|
||||
"(received %d, expected %d)", __func__, key->type, pktype);
|
||||
goto done;
|
||||
}
|
||||
if (key_type_plain(key->type) == KEY_RSA &&
|
||||
(datafellows & SSH_BUG_RSASIGMD5) != 0) {
|
||||
if (sshkey_type_plain(key->type) == KEY_RSA &&
|
||||
(ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
|
||||
error("Refusing RSA key because peer uses unsafe "
|
||||
"signature format");
|
||||
goto done;
|
||||
@ -115,38 +118,40 @@ userauth_hostbased(Authctxt *authctxt)
|
||||
goto done;
|
||||
}
|
||||
|
||||
service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
|
||||
service = ssh->compat & SSH_BUG_HBSERVICE ? "ssh-userauth" :
|
||||
authctxt->service;
|
||||
buffer_init(&b);
|
||||
buffer_put_string(&b, session_id2, session_id2_len);
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
/* reconstruct packet */
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
buffer_put_cstring(&b, authctxt->user);
|
||||
buffer_put_cstring(&b, service);
|
||||
buffer_put_cstring(&b, "hostbased");
|
||||
buffer_put_string(&b, pkalg, alen);
|
||||
buffer_put_string(&b, pkblob, blen);
|
||||
buffer_put_cstring(&b, chost);
|
||||
buffer_put_cstring(&b, cuser);
|
||||
if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
|
||||
(r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, authctxt->user)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, service)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, "hostbased")) != 0 ||
|
||||
(r = sshbuf_put_string(b, pkalg, alen)) != 0 ||
|
||||
(r = sshbuf_put_string(b, pkblob, blen)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, chost)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, cuser)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
#ifdef DEBUG_PK
|
||||
buffer_dump(&b);
|
||||
sshbuf_dump(b, stderr);
|
||||
#endif
|
||||
|
||||
pubkey_auth_info(authctxt, key,
|
||||
auth2_record_info(authctxt,
|
||||
"client user \"%.100s\", client host \"%.100s\"", cuser, chost);
|
||||
|
||||
/* test for allowed key and correct signature */
|
||||
authenticated = 0;
|
||||
if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
|
||||
PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
|
||||
buffer_len(&b))) == 1)
|
||||
PRIVSEP(sshkey_verify(key, sig, slen,
|
||||
sshbuf_ptr(b), sshbuf_len(b), ssh->compat)) == 0)
|
||||
authenticated = 1;
|
||||
|
||||
buffer_free(&b);
|
||||
auth2_record_key(authctxt, authenticated, key);
|
||||
sshbuf_free(b);
|
||||
done:
|
||||
debug2("userauth_hostbased: authenticated %d", authenticated);
|
||||
if (key != NULL)
|
||||
key_free(key);
|
||||
debug2("%s: authenticated %d", __func__, authenticated);
|
||||
sshkey_free(key);
|
||||
free(pkalg);
|
||||
free(pkblob);
|
||||
free(cuser);
|
||||
@ -158,7 +163,7 @@ userauth_hostbased(Authctxt *authctxt)
|
||||
/* return 1 if given hostkey is allowed */
|
||||
int
|
||||
hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
|
||||
Key *key)
|
||||
struct sshkey *key)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
const char *resolvedname, *ipaddr, *lookup, *reason;
|
||||
@ -203,8 +208,8 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
|
||||
}
|
||||
debug2("%s: access allowed by auth_rhosts2", __func__);
|
||||
|
||||
if (key_is_cert(key) &&
|
||||
key_cert_check_authority(key, 1, 0, lookup, &reason)) {
|
||||
if (sshkey_is_cert(key) &&
|
||||
sshkey_cert_check_authority(key, 1, 0, lookup, &reason)) {
|
||||
error("%s", reason);
|
||||
auth_debug_add("%s", reason);
|
||||
return 0;
|
||||
@ -223,20 +228,20 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
|
||||
}
|
||||
|
||||
if (host_status == HOST_OK) {
|
||||
if (key_is_cert(key)) {
|
||||
if (sshkey_is_cert(key)) {
|
||||
if ((fp = sshkey_fingerprint(key->cert->signature_key,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
fatal("%s: sshkey_fingerprint fail", __func__);
|
||||
verbose("Accepted certificate ID \"%s\" signed by "
|
||||
"%s CA %s from %s@%s", key->cert->key_id,
|
||||
key_type(key->cert->signature_key), fp,
|
||||
sshkey_type(key->cert->signature_key), fp,
|
||||
cuser, lookup);
|
||||
} else {
|
||||
if ((fp = sshkey_fingerprint(key,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
fatal("%s: sshkey_fingerprint fail", __func__);
|
||||
verbose("Accepted %s public key %s from %s@%s",
|
||||
key_type(key), fp, cuser, lookup);
|
||||
sshkey_type(key), fp, cuser, lookup);
|
||||
}
|
||||
free(fp);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-kbdint.c,v 1.7 2014/07/15 15:54:14 millert Exp $ */
|
||||
/* $OpenBSD: auth2-kbdint.c,v 1.8 2017/05/30 14:29:59 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -43,7 +43,7 @@
|
||||
extern ServerOptions options;
|
||||
|
||||
static int
|
||||
userauth_kbdint(Authctxt *authctxt)
|
||||
userauth_kbdint(struct ssh *ssh)
|
||||
{
|
||||
int authenticated = 0;
|
||||
char *lang, *devs;
|
||||
@ -55,7 +55,7 @@ userauth_kbdint(Authctxt *authctxt)
|
||||
debug("keyboard-interactive devs %s", devs);
|
||||
|
||||
if (options.challenge_response_authentication)
|
||||
authenticated = auth2_challenge(authctxt, devs);
|
||||
authenticated = auth2_challenge(ssh, devs);
|
||||
|
||||
free(devs);
|
||||
free(lang);
|
||||
|
14
auth2-none.c
14
auth2-none.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-none.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
|
||||
/* $OpenBSD: auth2-none.c,v 1.20 2017/05/30 14:29:59 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -37,7 +37,7 @@
|
||||
|
||||
#include "atomicio.h"
|
||||
#include "xmalloc.h"
|
||||
#include "key.h"
|
||||
#include "sshkey.h"
|
||||
#include "hostfile.h"
|
||||
#include "auth.h"
|
||||
#include "packet.h"
|
||||
@ -47,6 +47,7 @@
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "ssh2.h"
|
||||
#include "ssherr.h"
|
||||
#ifdef GSSAPI
|
||||
#include "ssh-gss.h"
|
||||
#endif
|
||||
@ -59,12 +60,15 @@ extern ServerOptions options;
|
||||
static int none_enabled = 1;
|
||||
|
||||
static int
|
||||
userauth_none(Authctxt *authctxt)
|
||||
userauth_none(struct ssh *ssh)
|
||||
{
|
||||
int r;
|
||||
|
||||
none_enabled = 0;
|
||||
packet_check_eom();
|
||||
if ((r = sshpkt_get_end(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
if (options.permit_empty_passwd && options.password_authentication)
|
||||
return (PRIVSEP(auth_password(authctxt, "")));
|
||||
return (PRIVSEP(auth_password(ssh->authctxt, "")));
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-passwd.c,v 1.12 2014/07/15 15:54:14 millert Exp $ */
|
||||
/* $OpenBSD: auth2-passwd.c,v 1.14 2017/05/30 14:29:59 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -30,10 +30,10 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "packet.h"
|
||||
#include "ssherr.h"
|
||||
#include "log.h"
|
||||
#include "key.h"
|
||||
#include "sshkey.h"
|
||||
#include "hostfile.h"
|
||||
#include "auth.h"
|
||||
#include "buffer.h"
|
||||
@ -48,26 +48,22 @@
|
||||
extern ServerOptions options;
|
||||
|
||||
static int
|
||||
userauth_passwd(Authctxt *authctxt)
|
||||
userauth_passwd(struct ssh *ssh)
|
||||
{
|
||||
char *password, *newpass;
|
||||
int authenticated = 0;
|
||||
int change;
|
||||
u_int len, newlen;
|
||||
char *password;
|
||||
int authenticated = 0, r;
|
||||
u_char change;
|
||||
size_t len;
|
||||
|
||||
change = packet_get_char();
|
||||
password = packet_get_string(&len);
|
||||
if (change) {
|
||||
/* discard new password from packet */
|
||||
newpass = packet_get_string(&newlen);
|
||||
explicit_bzero(newpass, newlen);
|
||||
free(newpass);
|
||||
}
|
||||
packet_check_eom();
|
||||
if ((r = sshpkt_get_u8(ssh, &change)) != 0 ||
|
||||
(r = sshpkt_get_cstring(ssh, &password, &len)) != 0 ||
|
||||
(change && (r = sshpkt_get_cstring(ssh, NULL, NULL)) != 0) ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
|
||||
if (change)
|
||||
logit("password change not supported");
|
||||
else if (PRIVSEP(auth_password(authctxt, password)) == 1)
|
||||
else if (PRIVSEP(auth_password(ssh->authctxt, password)) == 1)
|
||||
authenticated = 1;
|
||||
explicit_bzero(password, len);
|
||||
free(password);
|
||||
|
580
auth2-pubkey.c
580
auth2-pubkey.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2-pubkey.c,v 1.62 2017/01/30 01:03:00 djm Exp $ */
|
||||
/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -27,7 +27,6 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -52,7 +51,7 @@
|
||||
#include "misc.h"
|
||||
#include "servconf.h"
|
||||
#include "compat.h"
|
||||
#include "key.h"
|
||||
#include "sshkey.h"
|
||||
#include "hostfile.h"
|
||||
#include "auth.h"
|
||||
#include "pathnames.h"
|
||||
@ -75,42 +74,52 @@ extern u_char *session_id2;
|
||||
extern u_int session_id2_len;
|
||||
|
||||
static int
|
||||
userauth_pubkey(Authctxt *authctxt)
|
||||
userauth_pubkey(struct ssh *ssh)
|
||||
{
|
||||
Buffer b;
|
||||
Key *key = NULL;
|
||||
char *pkalg, *userstyle, *fp = NULL;
|
||||
u_char *pkblob, *sig;
|
||||
u_int alen, blen, slen;
|
||||
int have_sig, pktype;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
struct sshbuf *b;
|
||||
struct sshkey *key = NULL;
|
||||
char *pkalg, *userstyle = NULL, *fp = NULL;
|
||||
u_char *pkblob, *sig, have_sig;
|
||||
size_t blen, slen;
|
||||
int r, pktype;
|
||||
int authenticated = 0;
|
||||
|
||||
if (!authctxt->valid) {
|
||||
debug2("%s: disabled because of invalid user", __func__);
|
||||
return 0;
|
||||
}
|
||||
have_sig = packet_get_char();
|
||||
if (datafellows & SSH_BUG_PKAUTH) {
|
||||
if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0)
|
||||
fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r));
|
||||
if (ssh->compat & SSH_BUG_PKAUTH) {
|
||||
debug2("%s: SSH_BUG_PKAUTH", __func__);
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
/* no explicit pkalg given */
|
||||
pkblob = packet_get_string(&blen);
|
||||
buffer_init(&b);
|
||||
buffer_append(&b, pkblob, blen);
|
||||
/* so we have to extract the pkalg from the pkblob */
|
||||
pkalg = buffer_get_string(&b, &alen);
|
||||
buffer_free(&b);
|
||||
/* XXX use sshbuf_from() */
|
||||
if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
|
||||
(r = sshbuf_put(b, pkblob, blen)) != 0 ||
|
||||
(r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0)
|
||||
fatal("%s: failed: %s", __func__, ssh_err(r));
|
||||
sshbuf_free(b);
|
||||
} else {
|
||||
pkalg = packet_get_string(&alen);
|
||||
pkblob = packet_get_string(&blen);
|
||||
if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
|
||||
fatal("%s: sshpkt_get_cstring failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
pktype = key_type_from_name(pkalg);
|
||||
pktype = sshkey_type_from_name(pkalg);
|
||||
if (pktype == KEY_UNSPEC) {
|
||||
/* this is perfectly legal */
|
||||
logit("%s: unsupported public key algorithm: %s",
|
||||
__func__, pkalg);
|
||||
goto done;
|
||||
}
|
||||
key = key_from_blob(pkblob, blen);
|
||||
if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
|
||||
error("%s: could not parse key: %s", __func__, ssh_err(r));
|
||||
goto done;
|
||||
}
|
||||
if (key == NULL) {
|
||||
error("%s: cannot decode key: %s", __func__, pkalg);
|
||||
goto done;
|
||||
@ -120,15 +129,15 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
"(received %d, expected %d)", __func__, key->type, pktype);
|
||||
goto done;
|
||||
}
|
||||
if (key_type_plain(key->type) == KEY_RSA &&
|
||||
(datafellows & SSH_BUG_RSASIGMD5) != 0) {
|
||||
if (sshkey_type_plain(key->type) == KEY_RSA &&
|
||||
(ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
|
||||
logit("Refusing RSA key because client uses unsafe "
|
||||
"signature scheme");
|
||||
goto done;
|
||||
}
|
||||
fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
|
||||
if (auth2_userkey_already_used(authctxt, key)) {
|
||||
logit("refusing previously-used %s key", key_type(key));
|
||||
if (auth2_key_already_used(authctxt, key)) {
|
||||
logit("refusing previously-used %s key", sshkey_type(key));
|
||||
goto done;
|
||||
}
|
||||
if (match_pattern_list(sshkey_ssh_name(key),
|
||||
@ -141,54 +150,65 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
if (have_sig) {
|
||||
debug3("%s: have signature for %s %s",
|
||||
__func__, sshkey_type(key), fp);
|
||||
sig = packet_get_string(&slen);
|
||||
packet_check_eom();
|
||||
buffer_init(&b);
|
||||
if (datafellows & SSH_OLD_SESSIONID) {
|
||||
buffer_append(&b, session_id2, session_id2_len);
|
||||
if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if (ssh->compat & SSH_OLD_SESSIONID) {
|
||||
if ((r = sshbuf_put(b, session_id2,
|
||||
session_id2_len)) != 0)
|
||||
fatal("%s: sshbuf_put session id: %s",
|
||||
__func__, ssh_err(r));
|
||||
} else {
|
||||
buffer_put_string(&b, session_id2, session_id2_len);
|
||||
if ((r = sshbuf_put_string(b, session_id2,
|
||||
session_id2_len)) != 0)
|
||||
fatal("%s: sshbuf_put_string session id: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
/* reconstruct packet */
|
||||
buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
|
||||
xasprintf(&userstyle, "%s%s%s", authctxt->user,
|
||||
authctxt->style ? ":" : "",
|
||||
authctxt->style ? authctxt->style : "");
|
||||
buffer_put_cstring(&b, userstyle);
|
||||
free(userstyle);
|
||||
buffer_put_cstring(&b,
|
||||
datafellows & SSH_BUG_PKSERVICE ?
|
||||
"ssh-userauth" :
|
||||
authctxt->service);
|
||||
if (datafellows & SSH_BUG_PKAUTH) {
|
||||
buffer_put_char(&b, have_sig);
|
||||
if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, userstyle)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ?
|
||||
"ssh-userauth" : authctxt->service)) != 0)
|
||||
fatal("%s: build packet failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
if (ssh->compat & SSH_BUG_PKAUTH) {
|
||||
if ((r = sshbuf_put_u8(b, have_sig)) != 0)
|
||||
fatal("%s: build packet failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
} else {
|
||||
buffer_put_cstring(&b, "publickey");
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, pkalg);
|
||||
if ((r = sshbuf_put_cstring(b, "publickey")) != 0 ||
|
||||
(r = sshbuf_put_u8(b, have_sig)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, pkalg) != 0))
|
||||
fatal("%s: build packet failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
buffer_put_string(&b, pkblob, blen);
|
||||
if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
|
||||
fatal("%s: build packet failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
#ifdef DEBUG_PK
|
||||
buffer_dump(&b);
|
||||
sshbuf_dump(b, stderr);
|
||||
#endif
|
||||
pubkey_auth_info(authctxt, key, NULL);
|
||||
|
||||
/* test for correct signature */
|
||||
authenticated = 0;
|
||||
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
|
||||
PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
|
||||
buffer_len(&b))) == 1) {
|
||||
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
|
||||
sshbuf_len(b), ssh->compat)) == 0) {
|
||||
authenticated = 1;
|
||||
/* Record the successful key to prevent reuse */
|
||||
auth2_record_userkey(authctxt, key);
|
||||
key = NULL; /* Don't free below */
|
||||
}
|
||||
buffer_free(&b);
|
||||
sshbuf_free(b);
|
||||
free(sig);
|
||||
auth2_record_key(authctxt, authenticated, key);
|
||||
} else {
|
||||
debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
|
||||
__func__, sshkey_type(key), fp);
|
||||
packet_check_eom();
|
||||
if ((r = sshpkt_get_end(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
|
||||
/* XXX fake reply and always send PK_OK ? */
|
||||
/*
|
||||
@ -199,11 +219,13 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
* issue? -markus
|
||||
*/
|
||||
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
|
||||
packet_start(SSH2_MSG_USERAUTH_PK_OK);
|
||||
packet_put_string(pkalg, alen);
|
||||
packet_put_string(pkblob, blen);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
|
||||
!= 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
|
||||
(r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
ssh_packet_write_wait(ssh);
|
||||
authctxt->postponed = 1;
|
||||
}
|
||||
}
|
||||
@ -211,333 +233,14 @@ userauth_pubkey(Authctxt *authctxt)
|
||||
auth_clear_options();
|
||||
done:
|
||||
debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
|
||||
if (key != NULL)
|
||||
key_free(key);
|
||||
sshkey_free(key);
|
||||
free(userstyle);
|
||||
free(pkalg);
|
||||
free(pkblob);
|
||||
free(fp);
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
void
|
||||
pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
|
||||
{
|
||||
char *fp, *extra;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
extra = NULL;
|
||||
if (fmt != NULL) {
|
||||
va_start(ap, fmt);
|
||||
i = vasprintf(&extra, fmt, ap);
|
||||
va_end(ap);
|
||||
if (i < 0 || extra == NULL)
|
||||
fatal("%s: vasprintf failed", __func__);
|
||||
}
|
||||
|
||||
if (key_is_cert(key)) {
|
||||
fp = sshkey_fingerprint(key->cert->signature_key,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT);
|
||||
auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
|
||||
key_type(key), key->cert->key_id,
|
||||
(unsigned long long)key->cert->serial,
|
||||
key_type(key->cert->signature_key),
|
||||
fp == NULL ? "(null)" : fp,
|
||||
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
|
||||
free(fp);
|
||||
} else {
|
||||
fp = sshkey_fingerprint(key, options.fingerprint_hash,
|
||||
SSH_FP_DEFAULT);
|
||||
auth_info(authctxt, "%s %s%s%s", key_type(key),
|
||||
fp == NULL ? "(null)" : fp,
|
||||
extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
|
||||
free(fp);
|
||||
}
|
||||
free(extra);
|
||||
}
|
||||
|
||||
/*
|
||||
* Splits 's' into an argument vector. Handles quoted string and basic
|
||||
* escape characters (\\, \", \'). Caller must free the argument vector
|
||||
* and its members.
|
||||
*/
|
||||
static int
|
||||
split_argv(const char *s, int *argcp, char ***argvp)
|
||||
{
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
int argc = 0, quote, i, j;
|
||||
char *arg, **argv = xcalloc(1, sizeof(*argv));
|
||||
|
||||
*argvp = NULL;
|
||||
*argcp = 0;
|
||||
|
||||
for (i = 0; s[i] != '\0'; i++) {
|
||||
/* Skip leading whitespace */
|
||||
if (s[i] == ' ' || s[i] == '\t')
|
||||
continue;
|
||||
|
||||
/* Start of a token */
|
||||
quote = 0;
|
||||
if (s[i] == '\\' &&
|
||||
(s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
|
||||
i++;
|
||||
else if (s[i] == '\'' || s[i] == '"')
|
||||
quote = s[i++];
|
||||
|
||||
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
|
||||
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Copy the token in, removing escapes */
|
||||
for (j = 0; s[i] != '\0'; i++) {
|
||||
if (s[i] == '\\') {
|
||||
if (s[i + 1] == '\'' ||
|
||||
s[i + 1] == '\"' ||
|
||||
s[i + 1] == '\\') {
|
||||
i++; /* Skip '\' */
|
||||
arg[j++] = s[i];
|
||||
} else {
|
||||
/* Unrecognised escape */
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
|
||||
break; /* done */
|
||||
else if (quote != 0 && s[i] == quote)
|
||||
break; /* done */
|
||||
else
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
if (s[i] == '\0') {
|
||||
if (quote != 0) {
|
||||
/* Ran out of string looking for close quote */
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Success */
|
||||
*argcp = argc;
|
||||
*argvp = argv;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
r = 0;
|
||||
out:
|
||||
if (argc != 0 && argv != NULL) {
|
||||
for (i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reassemble an argument vector into a string, quoting and escaping as
|
||||
* necessary. Caller must free returned string.
|
||||
*/
|
||||
static char *
|
||||
assemble_argv(int argc, char **argv)
|
||||
{
|
||||
int i, j, ws, r;
|
||||
char c, *ret;
|
||||
struct sshbuf *buf, *arg;
|
||||
|
||||
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ws = 0;
|
||||
sshbuf_reset(arg);
|
||||
for (j = 0; argv[i][j] != '\0'; j++) {
|
||||
r = 0;
|
||||
c = argv[i][j];
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
ws = 1;
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
}
|
||||
if (r != 0)
|
||||
fatal("%s: sshbuf_put_u8: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
|
||||
(r = sshbuf_putb(buf, arg)) != 0 ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
}
|
||||
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
|
||||
fatal("%s: malloc failed", __func__);
|
||||
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
ret[sshbuf_len(buf)] = '\0';
|
||||
sshbuf_free(buf);
|
||||
sshbuf_free(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs command in a subprocess. Returns pid on success and a FILE* to the
|
||||
* subprocess' stdout or 0 on failure.
|
||||
* NB. "command" is only used for logging.
|
||||
*/
|
||||
static pid_t
|
||||
subprocess(const char *tag, struct passwd *pw, const char *command,
|
||||
int ac, char **av, FILE **child)
|
||||
{
|
||||
FILE *f;
|
||||
struct stat st;
|
||||
int devnull, p[2], i;
|
||||
pid_t pid;
|
||||
char *cp, errmsg[512];
|
||||
u_int envsize;
|
||||
char **child_env;
|
||||
|
||||
*child = NULL;
|
||||
|
||||
debug3("%s: %s command \"%s\" running as %s", __func__,
|
||||
tag, command, pw->pw_name);
|
||||
|
||||
/* Verify the path exists and is safe-ish to execute */
|
||||
if (*av[0] != '/') {
|
||||
error("%s path is not absolute", tag);
|
||||
return 0;
|
||||
}
|
||||
temporarily_use_uid(pw);
|
||||
if (stat(av[0], &st) < 0) {
|
||||
error("Could not stat %s \"%s\": %s", tag,
|
||||
av[0], strerror(errno));
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
if (auth_secure_path(av[0], &st, NULL, 0,
|
||||
errmsg, sizeof(errmsg)) != 0) {
|
||||
error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the command; stderr is left in place, stdout is the
|
||||
* authorized_keys output.
|
||||
*/
|
||||
if (pipe(p) != 0) {
|
||||
error("%s: pipe: %s", tag, strerror(errno));
|
||||
restore_uid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't want to call this in the child, where it can fatal() and
|
||||
* run cleanup_exit() code.
|
||||
*/
|
||||
restore_uid();
|
||||
|
||||
switch ((pid = fork())) {
|
||||
case -1: /* error */
|
||||
error("%s: fork: %s", tag, strerror(errno));
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
return 0;
|
||||
case 0: /* child */
|
||||
/* Prepare a minimal environment for the child. */
|
||||
envsize = 5;
|
||||
child_env = xcalloc(sizeof(*child_env), envsize);
|
||||
child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
|
||||
child_set_env(&child_env, &envsize, "USER", pw->pw_name);
|
||||
child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
|
||||
child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
|
||||
if ((cp = getenv("LANG")) != NULL)
|
||||
child_set_env(&child_env, &envsize, "LANG", cp);
|
||||
|
||||
for (i = 0; i < NSIG; i++)
|
||||
signal(i, SIG_DFL);
|
||||
|
||||
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
|
||||
error("%s: open %s: %s", tag, _PATH_DEVNULL,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
/* Keep stderr around a while longer to catch errors */
|
||||
if (dup2(devnull, STDIN_FILENO) == -1 ||
|
||||
dup2(p[1], STDOUT_FILENO) == -1) {
|
||||
error("%s: dup2: %s", tag, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
/* Don't use permanently_set_uid() here to avoid fatal() */
|
||||
if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
|
||||
error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
|
||||
error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
|
||||
strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
/* stdin is pointed to /dev/null at this point */
|
||||
if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
|
||||
error("%s: dup2: %s", tag, strerror(errno));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
execve(av[0], av, child_env);
|
||||
error("%s exec \"%s\": %s", tag, command, strerror(errno));
|
||||
_exit(127);
|
||||
default: /* parent */
|
||||
break;
|
||||
}
|
||||
|
||||
close(p[1]);
|
||||
if ((f = fdopen(p[0], "r")) == NULL) {
|
||||
error("%s: fdopen: %s", tag, strerror(errno));
|
||||
close(p[0]);
|
||||
/* Don't leave zombie child */
|
||||
kill(pid, SIGTERM);
|
||||
while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
/* Success */
|
||||
debug3("%s: %s pid %ld", __func__, tag, (long)pid);
|
||||
*child = f;
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Returns 0 if pid exited cleanly, non-zero otherwise */
|
||||
static int
|
||||
exited_cleanly(pid_t pid, const char *tag, const char *cmd)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
error("%s: waitpid: %s", tag, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
|
||||
return -1;
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
|
||||
{
|
||||
@ -559,7 +262,7 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
|
||||
}
|
||||
|
||||
static int
|
||||
process_principals(FILE *f, char *file, struct passwd *pw,
|
||||
process_principals(FILE *f, const char *file, struct passwd *pw,
|
||||
const struct sshkey_cert *cert)
|
||||
{
|
||||
char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
|
||||
@ -597,8 +300,7 @@ process_principals(FILE *f, char *file, struct passwd *pw,
|
||||
for (i = 0; i < cert->nprincipals; i++) {
|
||||
if (strcmp(cp, cert->principals[i]) == 0) {
|
||||
debug3("%s:%lu: matched principal \"%.100s\"",
|
||||
file == NULL ? "(command)" : file,
|
||||
linenum, cert->principals[i]);
|
||||
file, linenum, cert->principals[i]);
|
||||
if (auth_parse_options(pw, line_opts,
|
||||
file, linenum) != 1)
|
||||
continue;
|
||||
@ -671,7 +373,7 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
}
|
||||
|
||||
/* Turn the command into an argument vector */
|
||||
if (split_argv(options.authorized_principals_command, &ac, &av) != 0) {
|
||||
if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
|
||||
error("AuthorizedPrincipalsCommand \"%s\" contains "
|
||||
"invalid quotes", command);
|
||||
goto out;
|
||||
@ -720,21 +422,22 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
av[i] = tmp;
|
||||
}
|
||||
/* Prepare a printable command for logs, etc. */
|
||||
command = assemble_argv(ac, av);
|
||||
command = argv_assemble(ac, av);
|
||||
|
||||
if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
|
||||
ac, av, &f)) == 0)
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
temporarily_use_uid(pw);
|
||||
|
||||
ok = process_principals(f, NULL, pw, cert);
|
||||
ok = process_principals(f, "(command)", pw, cert);
|
||||
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0)
|
||||
if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
|
||||
goto out;
|
||||
|
||||
/* Read completed successfully */
|
||||
@ -761,26 +464,25 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
|
||||
* returns 1 if the key is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
|
||||
{
|
||||
char line[SSH_MAX_PUBKEY_BYTES];
|
||||
int found_key = 0;
|
||||
u_long linenum = 0;
|
||||
Key *found;
|
||||
struct sshkey *found = NULL;
|
||||
|
||||
found_key = 0;
|
||||
|
||||
found = NULL;
|
||||
while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
|
||||
char *cp, *key_options = NULL, *fp = NULL;
|
||||
const char *reason = NULL;
|
||||
|
||||
/* Always consume entrire file */
|
||||
/* Always consume entire file */
|
||||
if (found_key)
|
||||
continue;
|
||||
if (found != NULL)
|
||||
key_free(found);
|
||||
found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
|
||||
sshkey_free(found);
|
||||
found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
|
||||
if (found == NULL)
|
||||
goto done;
|
||||
auth_clear_options();
|
||||
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
@ -789,7 +491,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
if (!*cp || *cp == '\n' || *cp == '#')
|
||||
continue;
|
||||
|
||||
if (key_read(found, &cp) != 1) {
|
||||
if (sshkey_read(found, &cp) != 0) {
|
||||
/* no key? check if there are options for this key */
|
||||
int quoted = 0;
|
||||
debug2("user_key_allowed: check options: '%s'", cp);
|
||||
@ -803,14 +505,14 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
/* Skip remaining whitespace. */
|
||||
for (; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (key_read(found, &cp) != 1) {
|
||||
if (sshkey_read(found, &cp) != 0) {
|
||||
debug2("user_key_allowed: advance: '%s'", cp);
|
||||
/* still no key? advance to next line*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (key_is_cert(key)) {
|
||||
if (!key_equal(found, key->cert->signature_key))
|
||||
if (sshkey_is_cert(key)) {
|
||||
if (!sshkey_equal(found, key->cert->signature_key))
|
||||
continue;
|
||||
if (auth_parse_options(pw, key_options, file,
|
||||
linenum) != 1)
|
||||
@ -821,7 +523,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
continue;
|
||||
debug("matching CA found: file %s, line %lu, %s %s",
|
||||
file, linenum, key_type(found), fp);
|
||||
file, linenum, sshkey_type(found), fp);
|
||||
/*
|
||||
* If the user has specified a list of principals as
|
||||
* a key option, then prefer that list to matching
|
||||
@ -838,7 +540,7 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
auth_debug_add("%s", reason);
|
||||
continue;
|
||||
}
|
||||
if (key_cert_check_authority(key, 0, 0,
|
||||
if (sshkey_cert_check_authority(key, 0, 0,
|
||||
authorized_principals == NULL ? pw->pw_name : NULL,
|
||||
&reason) != 0)
|
||||
goto fail_reason;
|
||||
@ -847,11 +549,11 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
verbose("Accepted certificate ID \"%s\" (serial %llu) "
|
||||
"signed by %s CA %s via %s", key->cert->key_id,
|
||||
(unsigned long long)key->cert->serial,
|
||||
key_type(found), fp, file);
|
||||
sshkey_type(found), fp, file);
|
||||
free(fp);
|
||||
found_key = 1;
|
||||
break;
|
||||
} else if (key_equal(found, key)) {
|
||||
} else if (sshkey_equal(found, key)) {
|
||||
if (auth_parse_options(pw, key_options, file,
|
||||
linenum) != 1)
|
||||
continue;
|
||||
@ -861,14 +563,15 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
continue;
|
||||
debug("matching key found: file %s, line %lu %s %s",
|
||||
file, linenum, key_type(found), fp);
|
||||
file, linenum, sshkey_type(found), fp);
|
||||
free(fp);
|
||||
found_key = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (found != NULL)
|
||||
key_free(found);
|
||||
sshkey_free(found);
|
||||
if (!found_key)
|
||||
debug2("key not found");
|
||||
return found_key;
|
||||
@ -876,24 +579,24 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
|
||||
|
||||
/* Authenticate a certificate key against TrustedUserCAKeys */
|
||||
static int
|
||||
user_cert_trusted_ca(struct passwd *pw, Key *key)
|
||||
user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
|
||||
{
|
||||
char *ca_fp, *principals_file = NULL;
|
||||
const char *reason;
|
||||
int ret = 0, found_principal = 0, use_authorized_principals;
|
||||
int r, ret = 0, found_principal = 0, use_authorized_principals;
|
||||
|
||||
if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
|
||||
if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
|
||||
return 0;
|
||||
|
||||
if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
|
||||
return 0;
|
||||
|
||||
if (sshkey_in_file(key->cert->signature_key,
|
||||
options.trusted_user_ca_keys, 1, 0) != 0) {
|
||||
debug2("%s: CA %s %s is not listed in %s", __func__,
|
||||
key_type(key->cert->signature_key), ca_fp,
|
||||
options.trusted_user_ca_keys);
|
||||
if ((r = sshkey_in_file(key->cert->signature_key,
|
||||
options.trusted_user_ca_keys, 1, 0)) != 0) {
|
||||
debug2("%s: CA %s %s is not listed in %s: %s", __func__,
|
||||
sshkey_type(key->cert->signature_key), ca_fp,
|
||||
options.trusted_user_ca_keys, ssh_err(r));
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
@ -918,7 +621,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
|
||||
auth_debug_add("%s", reason);
|
||||
goto out;
|
||||
}
|
||||
if (key_cert_check_authority(key, 0, 1,
|
||||
if (sshkey_cert_check_authority(key, 0, 1,
|
||||
use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
|
||||
goto fail_reason;
|
||||
if (auth_cert_options(key, pw, &reason) != 0)
|
||||
@ -927,7 +630,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
|
||||
verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
|
||||
"%s CA %s via %s", key->cert->key_id,
|
||||
(unsigned long long)key->cert->serial,
|
||||
key_type(key->cert->signature_key), ca_fp,
|
||||
sshkey_type(key->cert->signature_key), ca_fp,
|
||||
options.trusted_user_ca_keys);
|
||||
ret = 1;
|
||||
|
||||
@ -942,7 +645,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
|
||||
* returns 1 if the key is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
user_key_allowed2(struct passwd *pw, Key *key, char *file)
|
||||
user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
|
||||
{
|
||||
FILE *f;
|
||||
int found_key = 0;
|
||||
@ -965,7 +668,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
|
||||
* returns 1 if the key is allowed or 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
int r, ok, found_key = 0;
|
||||
@ -1011,7 +714,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
}
|
||||
|
||||
/* Turn the command into an argument vector */
|
||||
if (split_argv(options.authorized_keys_command, &ac, &av) != 0) {
|
||||
if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
|
||||
error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
|
||||
command);
|
||||
goto out;
|
||||
@ -1035,7 +738,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
av[i] = tmp;
|
||||
}
|
||||
/* Prepare a printable command for logs, etc. */
|
||||
command = assemble_argv(ac, av);
|
||||
command = argv_assemble(ac, av);
|
||||
|
||||
/*
|
||||
* If AuthorizedKeysCommand was run without arguments
|
||||
@ -1052,7 +755,8 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
}
|
||||
|
||||
if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
|
||||
ac, av, &f)) == 0)
|
||||
ac, av, &f,
|
||||
SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
|
||||
goto out;
|
||||
|
||||
uid_swapped = 1;
|
||||
@ -1063,7 +767,7 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0)
|
||||
if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
|
||||
goto out;
|
||||
|
||||
/* Read completed successfully */
|
||||
@ -1088,14 +792,15 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key)
|
||||
* Check whether key authenticates and authorises the user.
|
||||
*/
|
||||
int
|
||||
user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
|
||||
user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
|
||||
{
|
||||
u_int success, i;
|
||||
char *file;
|
||||
|
||||
if (auth_key_is_revoked(key))
|
||||
return 0;
|
||||
if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
|
||||
if (sshkey_is_cert(key) &&
|
||||
auth_key_is_revoked(key->cert->signature_key))
|
||||
return 0;
|
||||
|
||||
success = user_cert_trusted_ca(pw, key);
|
||||
@ -1120,35 +825,6 @@ user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Records a public key in the list of previously-successful keys */
|
||||
void
|
||||
auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
|
||||
{
|
||||
struct sshkey **tmp;
|
||||
|
||||
if (authctxt->nprev_userkeys >= INT_MAX ||
|
||||
(tmp = reallocarray(authctxt->prev_userkeys,
|
||||
authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
|
||||
fatal("%s: reallocarray failed", __func__);
|
||||
authctxt->prev_userkeys = tmp;
|
||||
authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
|
||||
authctxt->nprev_userkeys++;
|
||||
}
|
||||
|
||||
/* Checks whether a key has already been used successfully for authentication */
|
||||
int
|
||||
auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
|
||||
{
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < authctxt->nprev_userkeys; i++) {
|
||||
if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Authmethod method_pubkey = {
|
||||
"publickey",
|
||||
userauth_pubkey,
|
||||
|
173
auth2.c
173
auth2.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: auth2.c,v 1.137 2017/02/03 23:05:57 djm Exp $ */
|
||||
/* $OpenBSD: auth2.c,v 1.143 2017/06/24 06:34:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -30,6 +30,7 @@
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
@ -55,6 +56,7 @@
|
||||
#include "ssh-gss.h"
|
||||
#endif
|
||||
#include "monitor_wrap.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
@ -87,8 +89,8 @@ Authmethod *authmethods[] = {
|
||||
|
||||
/* protocol */
|
||||
|
||||
static int input_service_request(int, u_int32_t, void *);
|
||||
static int input_userauth_request(int, u_int32_t, void *);
|
||||
static int input_service_request(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_request(int, u_int32_t, struct ssh *);
|
||||
|
||||
/* helper */
|
||||
static Authmethod *authmethod_lookup(Authctxt *, const char *);
|
||||
@ -168,16 +170,19 @@ userauth_banner(void)
|
||||
void
|
||||
do_authentication2(Authctxt *authctxt)
|
||||
{
|
||||
dispatch_init(&dispatch_protocol_error);
|
||||
dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
ssh->authctxt = authctxt; /* XXX move to caller */
|
||||
ssh_dispatch_init(ssh, &dispatch_protocol_error);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request);
|
||||
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success);
|
||||
ssh->authctxt = NULL;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
input_service_request(int type, u_int32_t seq, void *ctxt)
|
||||
input_service_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
u_int len;
|
||||
int acceptit = 0;
|
||||
char *service = packet_get_cstring(&len);
|
||||
@ -190,7 +195,7 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
|
||||
if (!authctxt->success) {
|
||||
acceptit = 1;
|
||||
/* now we can handle user-auth requests */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
|
||||
}
|
||||
}
|
||||
/* XXX all other service requests are denied */
|
||||
@ -210,10 +215,9 @@ input_service_request(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
Authctxt *authctxt = ctxt;
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
Authmethod *m = NULL;
|
||||
char *user, *service, *method, *style = NULL;
|
||||
int authenticated = 0;
|
||||
@ -267,14 +271,15 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
authctxt->user, authctxt->service, user, service);
|
||||
}
|
||||
/* reset state */
|
||||
auth2_challenge_stop(authctxt);
|
||||
auth2_challenge_stop(ssh);
|
||||
|
||||
#ifdef GSSAPI
|
||||
/* XXX move to auth2_gssapi_stop() */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
|
||||
#endif
|
||||
|
||||
auth2_authctxt_reset_info(authctxt);
|
||||
authctxt->postponed = 0;
|
||||
authctxt->server_caused_failure = 0;
|
||||
|
||||
@ -282,9 +287,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
m = authmethod_lookup(authctxt, method);
|
||||
if (m != NULL && authctxt->failures < options.max_authtries) {
|
||||
debug2("input_userauth_request: try method %s", method);
|
||||
authenticated = m->userauth(authctxt);
|
||||
authenticated = m->userauth(ssh);
|
||||
}
|
||||
userauth_finish(authctxt, authenticated, method, NULL);
|
||||
userauth_finish(ssh, authenticated, method, NULL);
|
||||
|
||||
free(service);
|
||||
free(user);
|
||||
@ -293,10 +298,10 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
void
|
||||
userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
|
||||
userauth_finish(struct ssh *ssh, int authenticated, const char *method,
|
||||
const char *submethod)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
Authctxt *authctxt = ssh->authctxt;
|
||||
char *methods;
|
||||
int partial = 0;
|
||||
|
||||
@ -325,6 +330,10 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
|
||||
/* Log before sending the reply */
|
||||
auth_log(authctxt, authenticated, partial, method, submethod);
|
||||
|
||||
/* Update information exposed to session */
|
||||
if (authenticated || partial)
|
||||
auth2_update_session_info(authctxt, method, submethod);
|
||||
|
||||
if (authctxt->postponed)
|
||||
return;
|
||||
|
||||
@ -352,7 +361,7 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
|
||||
|
||||
if (authenticated == 1) {
|
||||
/* turn off userauth */
|
||||
dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
|
||||
packet_start(SSH2_MSG_USERAUTH_SUCCESS);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
@ -622,4 +631,128 @@ auth2_update_methods_lists(Authctxt *authctxt, const char *method,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset method-specific information */
|
||||
void auth2_authctxt_reset_info(Authctxt *authctxt)
|
||||
{
|
||||
sshkey_free(authctxt->auth_method_key);
|
||||
free(authctxt->auth_method_info);
|
||||
authctxt->auth_method_key = NULL;
|
||||
authctxt->auth_method_info = NULL;
|
||||
}
|
||||
|
||||
/* Record auth method-specific information for logs */
|
||||
void
|
||||
auth2_record_info(Authctxt *authctxt, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
free(authctxt->auth_method_info);
|
||||
authctxt->auth_method_info = NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
i = vasprintf(&authctxt->auth_method_info, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (i < 0 || authctxt->auth_method_info == NULL)
|
||||
fatal("%s: vasprintf failed", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Records a public key used in authentication. This is used for logging
|
||||
* and to ensure that the same key is not subsequently accepted again for
|
||||
* multiple authentication.
|
||||
*/
|
||||
void
|
||||
auth2_record_key(Authctxt *authctxt, int authenticated,
|
||||
const struct sshkey *key)
|
||||
{
|
||||
struct sshkey **tmp, *dup;
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_demote(key, &dup)) != 0)
|
||||
fatal("%s: copy key: %s", __func__, ssh_err(r));
|
||||
sshkey_free(authctxt->auth_method_key);
|
||||
authctxt->auth_method_key = dup;
|
||||
|
||||
if (!authenticated)
|
||||
return;
|
||||
|
||||
/* If authenticated, make sure we don't accept this key again */
|
||||
if ((r = sshkey_demote(key, &dup)) != 0)
|
||||
fatal("%s: copy key: %s", __func__, ssh_err(r));
|
||||
if (authctxt->nprev_keys >= INT_MAX ||
|
||||
(tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys,
|
||||
authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL)
|
||||
fatal("%s: reallocarray failed", __func__);
|
||||
authctxt->prev_keys = tmp;
|
||||
authctxt->prev_keys[authctxt->nprev_keys] = dup;
|
||||
authctxt->nprev_keys++;
|
||||
|
||||
}
|
||||
|
||||
/* Checks whether a key has already been previously used for authentication */
|
||||
int
|
||||
auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key)
|
||||
{
|
||||
u_int i;
|
||||
char *fp;
|
||||
|
||||
for (i = 0; i < authctxt->nprev_keys; i++) {
|
||||
if (sshkey_equal_public(key, authctxt->prev_keys[i])) {
|
||||
fp = sshkey_fingerprint(authctxt->prev_keys[i],
|
||||
options.fingerprint_hash, SSH_FP_DEFAULT);
|
||||
debug3("%s: key already used: %s %s", __func__,
|
||||
sshkey_type(authctxt->prev_keys[i]),
|
||||
fp == NULL ? "UNKNOWN" : fp);
|
||||
free(fp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates authctxt->session_info with details of authentication. Should be
|
||||
* whenever an authentication method succeeds.
|
||||
*/
|
||||
void
|
||||
auth2_update_session_info(Authctxt *authctxt, const char *method,
|
||||
const char *submethod)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (authctxt->session_info == NULL) {
|
||||
if ((authctxt->session_info = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new", __func__);
|
||||
}
|
||||
|
||||
/* Append method[/submethod] */
|
||||
if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s",
|
||||
method, submethod == NULL ? "" : "/",
|
||||
submethod == NULL ? "" : submethod)) != 0)
|
||||
fatal("%s: append method: %s", __func__, ssh_err(r));
|
||||
|
||||
/* Append key if present */
|
||||
if (authctxt->auth_method_key != NULL) {
|
||||
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
|
||||
(r = sshkey_format_text(authctxt->auth_method_key,
|
||||
authctxt->session_info)) != 0)
|
||||
fatal("%s: append key: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
if (authctxt->auth_method_info != NULL) {
|
||||
/* Ensure no ambiguity here */
|
||||
if (strchr(authctxt->auth_method_info, '\n') != NULL)
|
||||
fatal("%s: auth_method_info contains \\n", __func__);
|
||||
if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 ||
|
||||
(r = sshbuf_putf(authctxt->session_info, "%s",
|
||||
authctxt->auth_method_info)) != 0) {
|
||||
fatal("%s: append method info: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
}
|
||||
if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0)
|
||||
fatal("%s: append: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
|
174
authfd.c
174
authfd.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfd.c,v 1.100 2015/12/04 16:41:28 markus Exp $ */
|
||||
/* $OpenBSD: authfd.c,v 1.105 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -51,7 +51,6 @@
|
||||
|
||||
#include "xmalloc.h"
|
||||
#include "ssh.h"
|
||||
#include "rsa.h"
|
||||
#include "sshbuf.h"
|
||||
#include "sshkey.h"
|
||||
#include "authfd.h"
|
||||
@ -199,43 +198,6 @@ ssh_lock_agent(int sock, int lock, const char *password)
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
static int
|
||||
deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
|
||||
{
|
||||
struct sshkey *key;
|
||||
int r, keybits;
|
||||
u_int32_t bits;
|
||||
char *comment = NULL;
|
||||
|
||||
if ((key = sshkey_new(KEY_RSA1)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_get_u32(ids, &bits)) != 0 ||
|
||||
(r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 ||
|
||||
(r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 ||
|
||||
(r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
|
||||
goto out;
|
||||
keybits = BN_num_bits(key->rsa->n);
|
||||
/* XXX previously we just warned here. I think we should be strict */
|
||||
if (keybits < 0 || bits != (u_int)keybits) {
|
||||
r = SSH_ERR_KEY_BITS_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
if (keyp != NULL) {
|
||||
*keyp = key;
|
||||
key = NULL;
|
||||
}
|
||||
if (commentp != NULL) {
|
||||
*commentp = comment;
|
||||
comment = NULL;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
sshkey_free(key);
|
||||
free(comment);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
|
||||
@ -264,35 +226,21 @@ deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
|
||||
* Fetch list of identities held by the agent.
|
||||
*/
|
||||
int
|
||||
ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
|
||||
ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp)
|
||||
{
|
||||
u_char type, code1 = 0, code2 = 0;
|
||||
u_char type;
|
||||
u_int32_t num, i;
|
||||
struct sshbuf *msg;
|
||||
struct ssh_identitylist *idl = NULL;
|
||||
int r;
|
||||
|
||||
/* Determine request and expected response types */
|
||||
switch (version) {
|
||||
case 1:
|
||||
code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
|
||||
code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER;
|
||||
break;
|
||||
case 2:
|
||||
code1 = SSH2_AGENTC_REQUEST_IDENTITIES;
|
||||
code2 = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||
break;
|
||||
default:
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to the agent requesting for a list of the
|
||||
* identities it can represent.
|
||||
*/
|
||||
if ((msg = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_put_u8(msg, code1)) != 0)
|
||||
if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REQUEST_IDENTITIES)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
|
||||
@ -304,7 +252,7 @@ ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
|
||||
if (agent_failed(type)) {
|
||||
r = SSH_ERR_AGENT_FAILURE;
|
||||
goto out;
|
||||
} else if (type != code2) {
|
||||
} else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
@ -329,25 +277,14 @@ ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp)
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < num;) {
|
||||
switch (version) {
|
||||
case 1:
|
||||
#ifdef WITH_SSH1
|
||||
if ((r = deserialise_identity1(msg,
|
||||
&(idl->keys[i]), &(idl->comments[i]))) != 0)
|
||||
if ((r = deserialise_identity2(msg, &(idl->keys[i]),
|
||||
&(idl->comments[i]))) != 0) {
|
||||
if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
|
||||
/* Gracefully skip unknown key types */
|
||||
num--;
|
||||
continue;
|
||||
} else
|
||||
goto out;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
if ((r = deserialise_identity2(msg,
|
||||
&(idl->keys[i]), &(idl->comments[i]))) != 0) {
|
||||
if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
|
||||
/* Gracefully skip unknown key types */
|
||||
num--;
|
||||
continue;
|
||||
} else
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@ -385,50 +322,10 @@ ssh_free_identitylist(struct ssh_identitylist *idl)
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
int
|
||||
ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
|
||||
u_char session_id[16], u_char response[16])
|
||||
{
|
||||
struct sshbuf *msg;
|
||||
int r;
|
||||
u_char type;
|
||||
|
||||
if (key->type != KEY_RSA1)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((msg = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 ||
|
||||
(r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
|
||||
(r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(msg, challenge)) != 0 ||
|
||||
(r = sshbuf_put(msg, session_id, 16)) != 0 ||
|
||||
(r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */
|
||||
goto out;
|
||||
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
|
||||
goto out;
|
||||
if ((r = sshbuf_get_u8(msg, &type)) != 0)
|
||||
goto out;
|
||||
if (agent_failed(type)) {
|
||||
r = SSH_ERR_AGENT_FAILURE;
|
||||
goto out;
|
||||
} else if (type != SSH_AGENT_RSA_RESPONSE) {
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get(msg, response, 16)) != 0)
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
sshbuf_free(msg);
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* encode signature algoritm in flag bits, so we can keep the msg format */
|
||||
static u_int
|
||||
agent_encode_alg(struct sshkey *key, const char *alg)
|
||||
agent_encode_alg(const struct sshkey *key, const char *alg)
|
||||
{
|
||||
if (alg != NULL && key->type == KEY_RSA) {
|
||||
if (strcmp(alg, "rsa-sha2-256") == 0)
|
||||
@ -441,7 +338,7 @@ agent_encode_alg(struct sshkey *key, const char *alg)
|
||||
|
||||
/* ask agent to sign data, returns err.h code on error, 0 on success */
|
||||
int
|
||||
ssh_agent_sign(int sock, struct sshkey *key,
|
||||
ssh_agent_sign(int sock, const struct sshkey *key,
|
||||
u_char **sigp, size_t *lenp,
|
||||
const u_char *data, size_t datalen, const char *alg, u_int compat)
|
||||
{
|
||||
@ -494,25 +391,6 @@ ssh_agent_sign(int sock, struct sshkey *key,
|
||||
|
||||
/* Encode key for a message to the agent. */
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
static int
|
||||
ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment)
|
||||
{
|
||||
int r;
|
||||
|
||||
/* To keep within the protocol: p < q for ssh. in SSL p > q */
|
||||
if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->n)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->e)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->d)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->iqmp)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->q)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(b, key->p)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, comment)) != 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key,
|
||||
@ -561,16 +439,6 @@ ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment,
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
|
||||
switch (key->type) {
|
||||
#ifdef WITH_SSH1
|
||||
case KEY_RSA1:
|
||||
type = constrained ?
|
||||
SSH_AGENTC_ADD_RSA_ID_CONSTRAINED :
|
||||
SSH_AGENTC_ADD_RSA_IDENTITY;
|
||||
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
|
||||
(r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_OPENSSL
|
||||
case KEY_RSA:
|
||||
case KEY_RSA_CERT:
|
||||
@ -620,16 +488,6 @@ ssh_remove_identity(int sock, struct sshkey *key)
|
||||
if ((msg = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
if (key->type == KEY_RSA1) {
|
||||
if ((r = sshbuf_put_u8(msg,
|
||||
SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 ||
|
||||
(r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
|
||||
(r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
|
||||
(r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0)
|
||||
goto out;
|
||||
} else
|
||||
#endif
|
||||
if (key->type != KEY_UNSPEC) {
|
||||
if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
|
||||
goto out;
|
||||
@ -696,6 +554,10 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
|
||||
/*
|
||||
* Removes all identities from the agent.
|
||||
* This call is intended only for use by ssh-add(1) and like applications.
|
||||
*
|
||||
* This supports the SSH protocol 1 message to because, when clearing all
|
||||
* keys from an agent, we generally want to clear both protocol v1 and v2
|
||||
* keys.
|
||||
*/
|
||||
int
|
||||
ssh_remove_all_identities(int sock, int version)
|
||||
|
7
authfd.h
7
authfd.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfd.h,v 1.39 2015/12/04 16:41:28 markus Exp $ */
|
||||
/* $OpenBSD: authfd.h,v 1.41 2017/06/28 01:09:22 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -27,8 +27,7 @@ int ssh_get_authentication_socket(int *fdp);
|
||||
void ssh_close_authentication_socket(int sock);
|
||||
|
||||
int ssh_lock_agent(int sock, int lock, const char *password);
|
||||
int ssh_fetch_identitylist(int sock, int version,
|
||||
struct ssh_identitylist **idlp);
|
||||
int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
|
||||
void ssh_free_identitylist(struct ssh_identitylist *idl);
|
||||
int ssh_add_identity_constrained(int sock, struct sshkey *key,
|
||||
const char *comment, u_int life, u_int confirm);
|
||||
@ -39,7 +38,7 @@ int ssh_remove_all_identities(int sock, int version);
|
||||
|
||||
int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
|
||||
u_char session_id[16], u_char response[16]);
|
||||
int ssh_agent_sign(int sock, struct sshkey *key,
|
||||
int ssh_agent_sign(int sock, const struct sshkey *key,
|
||||
u_char **sigp, size_t *lenp,
|
||||
const u_char *data, size_t datalen, const char *alg, u_int compat);
|
||||
|
||||
|
115
authfile.c
115
authfile.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: authfile.c,v 1.122 2016/11/25 23:24:45 djm Exp $ */
|
||||
/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -42,7 +42,6 @@
|
||||
#include "ssh.h"
|
||||
#include "log.h"
|
||||
#include "authfile.h"
|
||||
#include "rsa.h"
|
||||
#include "misc.h"
|
||||
#include "atomicio.h"
|
||||
#include "sshkey.h"
|
||||
@ -100,25 +99,13 @@ sshkey_load_file(int fd, struct sshbuf *blob)
|
||||
u_char buf[1024];
|
||||
size_t len;
|
||||
struct stat st;
|
||||
int r, dontmax = 0;
|
||||
int r;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return SSH_ERR_SYSTEM_ERROR;
|
||||
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
|
||||
st.st_size > MAX_KEY_FILE_SIZE)
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
/*
|
||||
* Pre-allocate the buffer used for the key contents and clamp its
|
||||
* maximum size. This ensures that key contents are never leaked via
|
||||
* implicit realloc() in the sshbuf code.
|
||||
*/
|
||||
if ((st.st_mode & S_IFREG) == 0 || st.st_size <= 0) {
|
||||
st.st_size = 64*1024; /* 64k should be enough for anyone :) */
|
||||
dontmax = 1;
|
||||
}
|
||||
if ((r = sshbuf_allocate(blob, st.st_size)) != 0 ||
|
||||
(dontmax && (r = sshbuf_set_max_size(blob, st.st_size)) != 0))
|
||||
return r;
|
||||
for (;;) {
|
||||
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
|
||||
if (errno == EPIPE)
|
||||
@ -147,35 +134,6 @@ sshkey_load_file(int fd, struct sshbuf *blob)
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
/*
|
||||
* Loads the public part of the ssh v1 key file. Returns NULL if an error was
|
||||
* encountered (the file does not exist or is not readable), and the key
|
||||
* otherwise.
|
||||
*/
|
||||
static int
|
||||
sshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
|
||||
{
|
||||
struct sshbuf *b = NULL;
|
||||
int r;
|
||||
|
||||
if (keyp != NULL)
|
||||
*keyp = NULL;
|
||||
if (commentp != NULL)
|
||||
*commentp = NULL;
|
||||
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshkey_load_file(fd, b)) != 0)
|
||||
goto out;
|
||||
if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
sshbuf_free(b);
|
||||
return r;
|
||||
}
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
/* XXX remove error() calls from here? */
|
||||
int
|
||||
@ -345,75 +303,48 @@ sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
/* load public key from ssh v1 private or any pubkey file */
|
||||
/* load public key from any pubkey file */
|
||||
int
|
||||
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
|
||||
{
|
||||
struct sshkey *pub = NULL;
|
||||
char file[PATH_MAX];
|
||||
int r, fd;
|
||||
char *file = NULL;
|
||||
int r;
|
||||
|
||||
if (keyp != NULL)
|
||||
*keyp = NULL;
|
||||
if (commentp != NULL)
|
||||
*commentp = NULL;
|
||||
|
||||
/* XXX should load file once and attempt to parse each format */
|
||||
|
||||
if ((fd = open(filename, O_RDONLY)) < 0)
|
||||
goto skip;
|
||||
#ifdef WITH_SSH1
|
||||
/* try rsa1 private key */
|
||||
r = sshkey_load_public_rsa1(fd, keyp, commentp);
|
||||
close(fd);
|
||||
switch (r) {
|
||||
case SSH_ERR_INTERNAL_ERROR:
|
||||
case SSH_ERR_ALLOC_FAIL:
|
||||
case SSH_ERR_INVALID_ARGUMENT:
|
||||
case SSH_ERR_SYSTEM_ERROR:
|
||||
case 0:
|
||||
return r;
|
||||
}
|
||||
#else /* WITH_SSH1 */
|
||||
close(fd);
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
/* try ssh2 public key */
|
||||
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
|
||||
if (keyp != NULL)
|
||||
if (keyp != NULL) {
|
||||
*keyp = pub;
|
||||
return 0;
|
||||
pub = NULL;
|
||||
}
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
sshkey_free(pub);
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
/* try rsa1 public key */
|
||||
if ((pub = sshkey_new(KEY_RSA1)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
|
||||
if (keyp != NULL)
|
||||
*keyp = pub;
|
||||
return 0;
|
||||
}
|
||||
sshkey_free(pub);
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
skip:
|
||||
/* try .pub suffix */
|
||||
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
|
||||
if (asprintf(&file, "%s.pub", filename) == -1)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
|
||||
if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
|
||||
(strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
|
||||
(r = sshkey_try_load_public(pub, file, commentp)) == 0) {
|
||||
if (keyp != NULL)
|
||||
*keyp = pub;
|
||||
return 0;
|
||||
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
|
||||
if (keyp != NULL) {
|
||||
*keyp = pub;
|
||||
pub = NULL;
|
||||
}
|
||||
r = 0;
|
||||
}
|
||||
out:
|
||||
free(file);
|
||||
sshkey_free(pub);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
9
bitmap.c
9
bitmap.c
@ -53,8 +53,9 @@ void
|
||||
bitmap_free(struct bitmap *b)
|
||||
{
|
||||
if (b != NULL && b->d != NULL) {
|
||||
explicit_bzero(b->d, b->len);
|
||||
bitmap_zero(b);
|
||||
free(b->d);
|
||||
b->d = NULL;
|
||||
}
|
||||
free(b);
|
||||
}
|
||||
@ -86,10 +87,10 @@ reserve(struct bitmap *b, u_int n)
|
||||
return -1; /* invalid */
|
||||
nlen = (n / BITMAP_BITS) + 1;
|
||||
if (b->len < nlen) {
|
||||
if ((tmp = reallocarray(b->d, nlen, BITMAP_BYTES)) == NULL)
|
||||
if ((tmp = recallocarray(b->d, b->len,
|
||||
nlen, BITMAP_BYTES)) == NULL)
|
||||
return -1;
|
||||
b->d = tmp;
|
||||
memset(b->d + b->len, 0, (nlen - b->len) * BITMAP_BYTES);
|
||||
b->len = nlen;
|
||||
}
|
||||
return 0;
|
||||
@ -188,7 +189,7 @@ bitmap_from_string(struct bitmap *b, const void *p, size_t l)
|
||||
{
|
||||
int r;
|
||||
size_t i, offset, shift;
|
||||
u_char *s = (u_char *)p;
|
||||
const u_char *s = (const u_char *)p;
|
||||
|
||||
if (l > BITMAP_MAX / 8)
|
||||
return -1;
|
||||
|
42
bufbn.c
42
bufbn.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: bufbn.c,v 1.12 2014/04/30 05:29:56 djm Exp $ */
|
||||
/* $OpenBSD: bufbn.c,v 1.13 2017/04/30 23:23:54 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
@ -28,46 +28,6 @@
|
||||
#include "log.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
int
|
||||
buffer_put_bignum_ret(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_put_bignum1(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_put_bignum(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
if (buffer_put_bignum_ret(buffer, value) == -1)
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
|
||||
int
|
||||
buffer_get_bignum_ret(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = sshbuf_get_bignum1(buffer, value)) != 0) {
|
||||
error("%s: %s", __func__, ssh_err(ret));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
buffer_get_bignum(Buffer *buffer, BIGNUM *value)
|
||||
{
|
||||
if (buffer_get_bignum_ret(buffer, value) == -1)
|
||||
fatal("%s: buffer error", __func__);
|
||||
}
|
||||
#endif /* WITH_SSH1 */
|
||||
|
||||
int
|
||||
buffer_put_bignum2_ret(Buffer *buffer, const BIGNUM *value)
|
||||
{
|
||||
|
6
buffer.h
6
buffer.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: buffer.h,v 1.25 2014/04/30 05:29:56 djm Exp $ */
|
||||
/* $OpenBSD: buffer.h,v 1.26 2017/04/30 23:23:54 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Damien Miller <djm@mindrot.org>
|
||||
@ -49,9 +49,7 @@ int buffer_consume_end_ret(Buffer *, u_int);
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/bn.h>
|
||||
void buffer_put_bignum(Buffer *, const BIGNUM *);
|
||||
void buffer_put_bignum2(Buffer *, const BIGNUM *);
|
||||
void buffer_get_bignum(Buffer *, BIGNUM *);
|
||||
void buffer_get_bignum2(Buffer *, BIGNUM *);
|
||||
void buffer_put_bignum2_from_string(Buffer *, const u_char *, u_int);
|
||||
|
||||
@ -75,8 +73,6 @@ void buffer_put_cstring(Buffer *, const char *);
|
||||
|
||||
#define buffer_skip_string(b) (void)buffer_get_string_ptr(b, NULL);
|
||||
|
||||
int buffer_put_bignum_ret(Buffer *, const BIGNUM *);
|
||||
int buffer_get_bignum_ret(Buffer *, BIGNUM *);
|
||||
int buffer_put_bignum2_ret(Buffer *, const BIGNUM *);
|
||||
int buffer_get_bignum2_ret(Buffer *, BIGNUM *);
|
||||
int buffer_get_short_ret(u_short *, Buffer *);
|
||||
|
3891
channels.c
3891
channels.c
File diff suppressed because it is too large
Load Diff
226
channels.h
226
channels.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.h,v 1.121 2017/02/01 02:59:09 dtucker Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.130 2017/09/21 19:16:53 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -46,8 +46,6 @@
|
||||
#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */
|
||||
#define SSH_CHANNEL_AUTH_SOCKET 6 /* authentication socket */
|
||||
#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */
|
||||
#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */
|
||||
#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */
|
||||
#define SSH_CHANNEL_LARVAL 10 /* larval session */
|
||||
#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */
|
||||
#define SSH_CHANNEL_CONNECTING 12
|
||||
@ -59,22 +57,27 @@
|
||||
#define SSH_CHANNEL_UNIX_LISTENER 18 /* Listening on a domain socket. */
|
||||
#define SSH_CHANNEL_RUNIX_LISTENER 19 /* Listening to a R-style domain socket. */
|
||||
#define SSH_CHANNEL_MUX_PROXY 20 /* proxy channel for mux-slave */
|
||||
#define SSH_CHANNEL_MAX_TYPE 21
|
||||
#define SSH_CHANNEL_RDYNAMIC_OPEN 21 /* reverse SOCKS, parsing request */
|
||||
#define SSH_CHANNEL_RDYNAMIC_FINISH 22 /* reverse SOCKS, finishing connect */
|
||||
#define SSH_CHANNEL_MAX_TYPE 23
|
||||
|
||||
#define CHANNEL_CANCEL_PORT_STATIC -1
|
||||
|
||||
struct ssh;
|
||||
struct Channel;
|
||||
typedef struct Channel Channel;
|
||||
struct fwd_perm_list;
|
||||
|
||||
typedef void channel_open_fn(int, int, void *);
|
||||
typedef void channel_callback_fn(int, void *);
|
||||
typedef int channel_infilter_fn(struct Channel *, char *, int);
|
||||
typedef void channel_filter_cleanup_fn(int, void *);
|
||||
typedef u_char *channel_outfilter_fn(struct Channel *, u_char **, u_int *);
|
||||
typedef void channel_open_fn(struct ssh *, int, int, void *);
|
||||
typedef void channel_callback_fn(struct ssh *, int, void *);
|
||||
typedef int channel_infilter_fn(struct ssh *, struct Channel *, char *, int);
|
||||
typedef void channel_filter_cleanup_fn(struct ssh *, int, void *);
|
||||
typedef u_char *channel_outfilter_fn(struct ssh *, struct Channel *,
|
||||
u_char **, size_t *);
|
||||
|
||||
/* Channel success/failure callbacks */
|
||||
typedef void channel_confirm_cb(int, struct Channel *, void *);
|
||||
typedef void channel_confirm_abandon_cb(struct Channel *, void *);
|
||||
typedef void channel_confirm_cb(struct ssh *, int, struct Channel *, void *);
|
||||
typedef void channel_confirm_abandon_cb(struct ssh *, struct Channel *, void *);
|
||||
struct channel_confirm {
|
||||
TAILQ_ENTRY(channel_confirm) entry;
|
||||
channel_confirm_cb *cb;
|
||||
@ -91,12 +94,14 @@ struct channel_connect {
|
||||
};
|
||||
|
||||
/* Callbacks for mux channels back into client-specific code */
|
||||
typedef int mux_callback_fn(struct Channel *);
|
||||
typedef int mux_callback_fn(struct ssh *, struct Channel *);
|
||||
|
||||
struct Channel {
|
||||
int type; /* channel type/state */
|
||||
int self; /* my own channel identifier */
|
||||
int remote_id; /* channel identifier for remote peer */
|
||||
uint32_t remote_id; /* channel identifier for remote peer */
|
||||
int have_remote_id; /* non-zero if remote_id is valid */
|
||||
|
||||
u_int istate; /* input from channel (state of receive half) */
|
||||
u_int ostate; /* output to channel (state of transmit half) */
|
||||
int flags; /* close sent/rcvd */
|
||||
@ -117,11 +122,12 @@ struct Channel {
|
||||
* to a matching pre-select handler.
|
||||
* this way post-select handlers are not
|
||||
* accidentally called if a FD gets reused */
|
||||
Buffer input; /* data read from socket, to be sent over
|
||||
struct sshbuf *input; /* data read from socket, to be sent over
|
||||
* encrypted connection */
|
||||
Buffer output; /* data received over encrypted connection for
|
||||
struct sshbuf *output; /* data received over encrypted connection for
|
||||
* send on socket */
|
||||
Buffer extended;
|
||||
struct sshbuf *extended;
|
||||
|
||||
char *path;
|
||||
/* path for unix domain sockets, or host name for forwards */
|
||||
int listening_port; /* port being listened for forwards */
|
||||
@ -157,6 +163,7 @@ struct Channel {
|
||||
int datagram;
|
||||
|
||||
/* non-blocking connect */
|
||||
/* XXX make this a pointer so the structure can be opaque */
|
||||
struct channel_connect connect_ctx;
|
||||
|
||||
/* multiplexing protocol hook, called for each packet received */
|
||||
@ -196,128 +203,137 @@ struct Channel {
|
||||
#define CHAN_EOF_RCVD 0x08
|
||||
#define CHAN_LOCAL 0x10
|
||||
|
||||
#define CHAN_RBUF 16*1024
|
||||
/* Read buffer size */
|
||||
#define CHAN_RBUF (16*1024)
|
||||
|
||||
/* Hard limit on number of channels */
|
||||
#define CHANNELS_MAX_CHANNELS (16*1024)
|
||||
|
||||
/* check whether 'efd' is still in use */
|
||||
#define CHANNEL_EFD_INPUT_ACTIVE(c) \
|
||||
(compat20 && c->extended_usage == CHAN_EXTENDED_READ && \
|
||||
(c->extended_usage == CHAN_EXTENDED_READ && \
|
||||
(c->efd != -1 || \
|
||||
buffer_len(&c->extended) > 0))
|
||||
sshbuf_len(c->extended) > 0))
|
||||
#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
|
||||
(compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \
|
||||
(c->extended_usage == CHAN_EXTENDED_WRITE && \
|
||||
c->efd != -1 && (!(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD)) || \
|
||||
buffer_len(&c->extended) > 0))
|
||||
sshbuf_len(c->extended) > 0))
|
||||
|
||||
/* Add channel management structures to SSH transport instance */
|
||||
void channel_init_channels(struct ssh *ssh);
|
||||
|
||||
/* channel management */
|
||||
|
||||
Channel *channel_by_id(int);
|
||||
Channel *channel_by_remote_id(int);
|
||||
Channel *channel_lookup(int);
|
||||
Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int);
|
||||
void channel_set_fds(int, int, int, int, int, int, int, u_int);
|
||||
void channel_free(Channel *);
|
||||
void channel_free_all(void);
|
||||
void channel_stop_listening(void);
|
||||
Channel *channel_by_id(struct ssh *, int);
|
||||
Channel *channel_by_remote_id(struct ssh *, u_int);
|
||||
Channel *channel_lookup(struct ssh *, int);
|
||||
Channel *channel_new(struct ssh *, char *, int, int, int, int,
|
||||
u_int, u_int, int, char *, int);
|
||||
void channel_set_fds(struct ssh *, int, int, int, int, int,
|
||||
int, int, u_int);
|
||||
void channel_free(struct ssh *, Channel *);
|
||||
void channel_free_all(struct ssh *);
|
||||
void channel_stop_listening(struct ssh *);
|
||||
|
||||
void channel_send_open(int);
|
||||
void channel_request_start(int, char *, int);
|
||||
void channel_register_cleanup(int, channel_callback_fn *, int);
|
||||
void channel_register_open_confirm(int, channel_open_fn *, void *);
|
||||
void channel_register_filter(int, channel_infilter_fn *,
|
||||
channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
|
||||
void channel_register_status_confirm(int, channel_confirm_cb *,
|
||||
channel_confirm_abandon_cb *, void *);
|
||||
void channel_cancel_cleanup(int);
|
||||
int channel_close_fd(int *);
|
||||
void channel_send_window_changes(void);
|
||||
void channel_send_open(struct ssh *, int);
|
||||
void channel_request_start(struct ssh *, int, char *, int);
|
||||
void channel_register_cleanup(struct ssh *, int,
|
||||
channel_callback_fn *, int);
|
||||
void channel_register_open_confirm(struct ssh *, int,
|
||||
channel_open_fn *, void *);
|
||||
void channel_register_filter(struct ssh *, int, channel_infilter_fn *,
|
||||
channel_outfilter_fn *, channel_filter_cleanup_fn *, void *);
|
||||
void channel_register_status_confirm(struct ssh *, int,
|
||||
channel_confirm_cb *, channel_confirm_abandon_cb *, void *);
|
||||
void channel_cancel_cleanup(struct ssh *, int);
|
||||
int channel_close_fd(struct ssh *, int *);
|
||||
void channel_send_window_changes(struct ssh *);
|
||||
|
||||
/* mux proxy support */
|
||||
|
||||
int channel_proxy_downstream(Channel *mc);
|
||||
int channel_proxy_upstream(Channel *, int, u_int32_t, void *);
|
||||
int channel_proxy_downstream(struct ssh *, Channel *mc);
|
||||
int channel_proxy_upstream(Channel *, int, u_int32_t, struct ssh *);
|
||||
|
||||
/* protocol handler */
|
||||
|
||||
int channel_input_close(int, u_int32_t, void *);
|
||||
int channel_input_close_confirmation(int, u_int32_t, void *);
|
||||
int channel_input_data(int, u_int32_t, void *);
|
||||
int channel_input_extended_data(int, u_int32_t, void *);
|
||||
int channel_input_ieof(int, u_int32_t, void *);
|
||||
int channel_input_oclose(int, u_int32_t, void *);
|
||||
int channel_input_open_confirmation(int, u_int32_t, void *);
|
||||
int channel_input_open_failure(int, u_int32_t, void *);
|
||||
int channel_input_port_open(int, u_int32_t, void *);
|
||||
int channel_input_window_adjust(int, u_int32_t, void *);
|
||||
int channel_input_status_confirm(int, u_int32_t, void *);
|
||||
int channel_input_data(int, u_int32_t, struct ssh *);
|
||||
int channel_input_extended_data(int, u_int32_t, struct ssh *);
|
||||
int channel_input_ieof(int, u_int32_t, struct ssh *);
|
||||
int channel_input_oclose(int, u_int32_t, struct ssh *);
|
||||
int channel_input_open_confirmation(int, u_int32_t, struct ssh *);
|
||||
int channel_input_open_failure(int, u_int32_t, struct ssh *);
|
||||
int channel_input_port_open(int, u_int32_t, struct ssh *);
|
||||
int channel_input_window_adjust(int, u_int32_t, struct ssh *);
|
||||
int channel_input_status_confirm(int, u_int32_t, struct ssh *);
|
||||
|
||||
/* file descriptor handling (read/write) */
|
||||
|
||||
void channel_prepare_select(fd_set **, fd_set **, int *, u_int*,
|
||||
time_t*, int);
|
||||
void channel_after_select(fd_set *, fd_set *);
|
||||
void channel_output_poll(void);
|
||||
void channel_prepare_select(struct ssh *, fd_set **, fd_set **, int *,
|
||||
u_int*, time_t*);
|
||||
void channel_after_select(struct ssh *, fd_set *, fd_set *);
|
||||
void channel_output_poll(struct ssh *);
|
||||
|
||||
int channel_not_very_much_buffered_data(void);
|
||||
void channel_close_all(void);
|
||||
int channel_still_open(void);
|
||||
char *channel_open_message(void);
|
||||
int channel_find_open(void);
|
||||
int channel_not_very_much_buffered_data(struct ssh *);
|
||||
void channel_close_all(struct ssh *);
|
||||
int channel_still_open(struct ssh *);
|
||||
char *channel_open_message(struct ssh *);
|
||||
int channel_find_open(struct ssh *);
|
||||
|
||||
/* tcp forwarding */
|
||||
struct Forward;
|
||||
struct ForwardOptions;
|
||||
void channel_set_af(int af);
|
||||
void channel_permit_all_opens(void);
|
||||
void channel_add_permitted_opens(char *, int);
|
||||
int channel_add_adm_permitted_opens(char *, int);
|
||||
void channel_disable_adm_local_opens(void);
|
||||
void channel_update_permitted_opens(int, int);
|
||||
void channel_clear_permitted_opens(void);
|
||||
void channel_clear_adm_permitted_opens(void);
|
||||
void channel_print_adm_permitted_opens(void);
|
||||
Channel *channel_connect_to_port(const char *, u_short, char *, char *, int *,
|
||||
const char **);
|
||||
Channel *channel_connect_to_path(const char *, char *, char *);
|
||||
Channel *channel_connect_stdio_fwd(const char*, u_short, int, int);
|
||||
Channel *channel_connect_by_listen_address(const char *, u_short,
|
||||
char *, char *);
|
||||
Channel *channel_connect_by_listen_path(const char *, char *, char *);
|
||||
int channel_request_remote_forwarding(struct Forward *);
|
||||
int channel_setup_local_fwd_listener(struct Forward *, struct ForwardOptions *);
|
||||
int channel_request_rforward_cancel(struct Forward *);
|
||||
int channel_setup_remote_fwd_listener(struct Forward *, int *, struct ForwardOptions *);
|
||||
int channel_cancel_rport_listener(struct Forward *);
|
||||
int channel_cancel_lport_listener(struct Forward *, int, struct ForwardOptions *);
|
||||
void channel_set_af(struct ssh *, int af);
|
||||
void channel_permit_all_opens(struct ssh *);
|
||||
void channel_add_permitted_opens(struct ssh *, char *, int);
|
||||
int channel_add_adm_permitted_opens(struct ssh *, char *, int);
|
||||
void channel_copy_adm_permitted_opens(struct ssh *,
|
||||
const struct fwd_perm_list *);
|
||||
void channel_disable_adm_local_opens(struct ssh *);
|
||||
void channel_update_permitted_opens(struct ssh *, int, int);
|
||||
void channel_clear_permitted_opens(struct ssh *);
|
||||
void channel_clear_adm_permitted_opens(struct ssh *);
|
||||
void channel_print_adm_permitted_opens(struct ssh *);
|
||||
Channel *channel_connect_to_port(struct ssh *, const char *, u_short,
|
||||
char *, char *, int *, const char **);
|
||||
Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *);
|
||||
Channel *channel_connect_stdio_fwd(struct ssh *, const char*,
|
||||
u_short, int, int);
|
||||
Channel *channel_connect_by_listen_address(struct ssh *, const char *,
|
||||
u_short, char *, char *);
|
||||
Channel *channel_connect_by_listen_path(struct ssh *, const char *,
|
||||
char *, char *);
|
||||
int channel_request_remote_forwarding(struct ssh *, struct Forward *);
|
||||
int channel_setup_local_fwd_listener(struct ssh *, struct Forward *,
|
||||
struct ForwardOptions *);
|
||||
int channel_request_rforward_cancel(struct ssh *, struct Forward *);
|
||||
int channel_setup_remote_fwd_listener(struct ssh *, struct Forward *,
|
||||
int *, struct ForwardOptions *);
|
||||
int channel_cancel_rport_listener(struct ssh *, struct Forward *);
|
||||
int channel_cancel_lport_listener(struct ssh *, struct Forward *,
|
||||
int, struct ForwardOptions *);
|
||||
int permitopen_port(const char *);
|
||||
|
||||
/* x11 forwarding */
|
||||
|
||||
void channel_set_x11_refuse_time(u_int);
|
||||
int x11_connect_display(void);
|
||||
int x11_create_display_inet(int, int, int, u_int *, int **);
|
||||
int x11_input_open(int, u_int32_t, void *);
|
||||
void x11_request_forwarding_with_spoofing(int, const char *, const char *,
|
||||
const char *, int);
|
||||
int deny_input_open(int, u_int32_t, void *);
|
||||
|
||||
/* agent forwarding */
|
||||
|
||||
void auth_request_forwarding(void);
|
||||
void channel_set_x11_refuse_time(struct ssh *, u_int);
|
||||
int x11_connect_display(struct ssh *);
|
||||
int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **);
|
||||
void x11_request_forwarding_with_spoofing(struct ssh *, int,
|
||||
const char *, const char *, const char *, int);
|
||||
|
||||
/* channel close */
|
||||
|
||||
int chan_is_dead(Channel *, int);
|
||||
void chan_mark_dead(Channel *);
|
||||
int chan_is_dead(struct ssh *, Channel *, int);
|
||||
void chan_mark_dead(struct ssh *, Channel *);
|
||||
|
||||
/* channel events */
|
||||
|
||||
void chan_rcvd_oclose(Channel *);
|
||||
void chan_rcvd_eow(Channel *); /* SSH2-only */
|
||||
void chan_read_failed(Channel *);
|
||||
void chan_ibuf_empty(Channel *);
|
||||
|
||||
void chan_rcvd_ieof(Channel *);
|
||||
void chan_write_failed(Channel *);
|
||||
void chan_obuf_empty(Channel *);
|
||||
void chan_rcvd_oclose(struct ssh *, Channel *);
|
||||
void chan_rcvd_eow(struct ssh *, Channel *);
|
||||
void chan_read_failed(struct ssh *, Channel *);
|
||||
void chan_ibuf_empty(struct ssh *, Channel *);
|
||||
void chan_rcvd_ieof(struct ssh *, Channel *);
|
||||
void chan_write_failed(struct ssh *, Channel *);
|
||||
void chan_obuf_empty(struct ssh *, Channel *);
|
||||
|
||||
#endif
|
||||
|
158
cipher-3des1.c
158
cipher-3des1.c
@ -1,158 +0,0 @@
|
||||
/* $OpenBSD: cipher-3des1.c,v 1.12 2015/01/14 10:24:42 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2003 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (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 WITH_SSH1
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "ssherr.h"
|
||||
|
||||
/*
|
||||
* This is used by SSH1:
|
||||
*
|
||||
* What kind of triple DES are these 2 routines?
|
||||
*
|
||||
* Why is there a redundant initialization vector?
|
||||
*
|
||||
* If only iv3 was used, then, this would till effect have been
|
||||
* outer-cbc. However, there is also a private iv1 == iv2 which
|
||||
* perhaps makes differential analysis easier. On the other hand, the
|
||||
* private iv1 probably makes the CRC-32 attack ineffective. This is a
|
||||
* result of that there is no longer any known iv1 to use when
|
||||
* choosing the X block.
|
||||
*/
|
||||
struct ssh1_3des_ctx
|
||||
{
|
||||
EVP_CIPHER_CTX k1, k2, k3;
|
||||
};
|
||||
|
||||
const EVP_CIPHER * evp_ssh1_3des(void);
|
||||
int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
|
||||
|
||||
static int
|
||||
ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
|
||||
int enc)
|
||||
{
|
||||
struct ssh1_3des_ctx *c;
|
||||
u_char *k1, *k2, *k3;
|
||||
|
||||
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
|
||||
if ((c = calloc(1, sizeof(*c))) == NULL)
|
||||
return 0;
|
||||
EVP_CIPHER_CTX_set_app_data(ctx, c);
|
||||
}
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
if (enc == -1)
|
||||
enc = ctx->encrypt;
|
||||
k1 = k2 = k3 = (u_char *) key;
|
||||
k2 += 8;
|
||||
if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
|
||||
if (enc)
|
||||
k3 += 16;
|
||||
else
|
||||
k1 += 16;
|
||||
}
|
||||
EVP_CIPHER_CTX_init(&c->k1);
|
||||
EVP_CIPHER_CTX_init(&c->k2);
|
||||
EVP_CIPHER_CTX_init(&c->k3);
|
||||
if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
|
||||
EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
|
||||
EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
|
||||
explicit_bzero(c, sizeof(*c));
|
||||
free(c);
|
||||
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
|
||||
{
|
||||
struct ssh1_3des_ctx *c;
|
||||
|
||||
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
|
||||
return 0;
|
||||
if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
|
||||
EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
|
||||
EVP_Cipher(&c->k3, dest, dest, len) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
|
||||
{
|
||||
struct ssh1_3des_ctx *c;
|
||||
|
||||
if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
|
||||
EVP_CIPHER_CTX_cleanup(&c->k1);
|
||||
EVP_CIPHER_CTX_cleanup(&c->k2);
|
||||
EVP_CIPHER_CTX_cleanup(&c->k3);
|
||||
explicit_bzero(c, sizeof(*c));
|
||||
free(c);
|
||||
EVP_CIPHER_CTX_set_app_data(ctx, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
|
||||
{
|
||||
struct ssh1_3des_ctx *c;
|
||||
|
||||
if (len != 24)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
if (doset) {
|
||||
memcpy(c->k1.iv, iv, 8);
|
||||
memcpy(c->k2.iv, iv + 8, 8);
|
||||
memcpy(c->k3.iv, iv + 16, 8);
|
||||
} else {
|
||||
memcpy(iv, c->k1.iv, 8);
|
||||
memcpy(iv + 8, c->k2.iv, 8);
|
||||
memcpy(iv + 16, c->k3.iv, 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
evp_ssh1_3des(void)
|
||||
{
|
||||
static EVP_CIPHER ssh1_3des;
|
||||
|
||||
memset(&ssh1_3des, 0, sizeof(ssh1_3des));
|
||||
ssh1_3des.nid = NID_undef;
|
||||
ssh1_3des.block_size = 8;
|
||||
ssh1_3des.iv_len = 0;
|
||||
ssh1_3des.key_len = 16;
|
||||
ssh1_3des.init = ssh1_3des_init;
|
||||
ssh1_3des.cleanup = ssh1_3des_cleanup;
|
||||
ssh1_3des.do_cipher = ssh1_3des_cbc;
|
||||
ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
|
||||
return &ssh1_3des;
|
||||
}
|
||||
#endif /* WITH_SSH1 */
|
106
cipher-bf1.c
106
cipher-bf1.c
@ -1,106 +0,0 @@
|
||||
/* $OpenBSD: cipher-bf1.c,v 1.7 2015/01/14 10:24:42 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2003 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (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 WITH_SSH1
|
||||
#if defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "openbsd-compat/openssl-compat.h"
|
||||
|
||||
/*
|
||||
* SSH1 uses a variation on Blowfish, all bytes must be swapped before
|
||||
* and after encryption/decryption. Thus the swap_bytes stuff (yuk).
|
||||
*/
|
||||
|
||||
const EVP_CIPHER * evp_ssh1_bf(void);
|
||||
|
||||
static void
|
||||
swap_bytes(const u_char *src, u_char *dst, int n)
|
||||
{
|
||||
u_char c[4];
|
||||
|
||||
/* Process 4 bytes every lap. */
|
||||
for (n = n / 4; n > 0; n--) {
|
||||
c[3] = *src++;
|
||||
c[2] = *src++;
|
||||
c[1] = *src++;
|
||||
c[0] = *src++;
|
||||
|
||||
*dst++ = c[0];
|
||||
*dst++ = c[1];
|
||||
*dst++ = c[2];
|
||||
*dst++ = c[3];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SSH_OLD_EVP
|
||||
static void bf_ssh1_init (EVP_CIPHER_CTX * ctx, const unsigned char *key,
|
||||
const unsigned char *iv, int enc)
|
||||
{
|
||||
if (iv != NULL)
|
||||
memcpy (&(ctx->oiv[0]), iv, 8);
|
||||
memcpy (&(ctx->iv[0]), &(ctx->oiv[0]), 8);
|
||||
if (key != NULL)
|
||||
BF_set_key (&(ctx->c.bf_ks), EVP_CIPHER_CTX_key_length (ctx),
|
||||
key);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *,
|
||||
const u_char *, LIBCRYPTO_EVP_INL_TYPE) = NULL;
|
||||
|
||||
static int
|
||||
bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in,
|
||||
LIBCRYPTO_EVP_INL_TYPE len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
swap_bytes(in, out, len);
|
||||
ret = (*orig_bf)(ctx, out, out, len);
|
||||
swap_bytes(out, out, len);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
const EVP_CIPHER *
|
||||
evp_ssh1_bf(void)
|
||||
{
|
||||
static EVP_CIPHER ssh1_bf;
|
||||
|
||||
memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
|
||||
orig_bf = ssh1_bf.do_cipher;
|
||||
ssh1_bf.nid = NID_undef;
|
||||
#ifdef SSH_OLD_EVP
|
||||
ssh1_bf.init = bf_ssh1_init;
|
||||
#endif
|
||||
ssh1_bf.do_cipher = bf_ssh1_cipher;
|
||||
ssh1_bf.key_len = 32;
|
||||
return (&ssh1_bf);
|
||||
}
|
||||
#endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF) */
|
||||
|
||||
#endif /* WITH_SSH1 */
|
303
cipher.c
303
cipher.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cipher.c,v 1.102 2016/08/03 05:41:57 djm Exp $ */
|
||||
/* $OpenBSD: cipher.c,v 1.107 2017/05/07 23:12:57 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -51,11 +51,6 @@
|
||||
|
||||
#include "openbsd-compat/openssl-compat.h"
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
extern const EVP_CIPHER *evp_ssh1_bf(void);
|
||||
extern const EVP_CIPHER *evp_ssh1_3des(void);
|
||||
extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int);
|
||||
#endif
|
||||
|
||||
struct sshcipher_ctx {
|
||||
int plaintext;
|
||||
@ -68,17 +63,16 @@ struct sshcipher_ctx {
|
||||
|
||||
struct sshcipher {
|
||||
char *name;
|
||||
int number; /* for ssh1 only */
|
||||
u_int block_size;
|
||||
u_int key_len;
|
||||
u_int iv_len; /* defaults to block_size */
|
||||
u_int auth_len;
|
||||
u_int discard_len;
|
||||
u_int flags;
|
||||
#define CFLAG_CBC (1<<0)
|
||||
#define CFLAG_CHACHAPOLY (1<<1)
|
||||
#define CFLAG_AESCTR (1<<2)
|
||||
#define CFLAG_NONE (1<<3)
|
||||
#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */
|
||||
#ifdef WITH_OPENSSL
|
||||
const EVP_CIPHER *(*evptype)(void);
|
||||
#else
|
||||
@ -87,53 +81,32 @@ struct sshcipher {
|
||||
};
|
||||
|
||||
static const struct sshcipher ciphers[] = {
|
||||
#ifdef WITH_SSH1
|
||||
{ "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc },
|
||||
{ "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des },
|
||||
# ifndef OPENSSL_NO_BF
|
||||
{ "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf },
|
||||
# endif /* OPENSSL_NO_BF */
|
||||
#endif /* WITH_SSH1 */
|
||||
#ifdef WITH_OPENSSL
|
||||
{ "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null },
|
||||
{ "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc },
|
||||
# ifndef OPENSSL_NO_BF
|
||||
{ "blowfish-cbc",
|
||||
SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc },
|
||||
# endif /* OPENSSL_NO_BF */
|
||||
# ifndef OPENSSL_NO_CAST
|
||||
{ "cast128-cbc",
|
||||
SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_cast5_cbc },
|
||||
# endif /* OPENSSL_NO_CAST */
|
||||
# ifndef OPENSSL_NO_RC4
|
||||
{ "arcfour", SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 0, EVP_rc4 },
|
||||
{ "arcfour128", SSH_CIPHER_SSH2, 8, 16, 0, 0, 1536, 0, EVP_rc4 },
|
||||
{ "arcfour256", SSH_CIPHER_SSH2, 8, 32, 0, 0, 1536, 0, EVP_rc4 },
|
||||
# endif /* OPENSSL_NO_RC4 */
|
||||
{ "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc },
|
||||
{ "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc },
|
||||
{ "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
|
||||
{ "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc },
|
||||
{ "aes128-cbc", 16, 16, 0, 0, CFLAG_CBC, EVP_aes_128_cbc },
|
||||
{ "aes192-cbc", 16, 24, 0, 0, CFLAG_CBC, EVP_aes_192_cbc },
|
||||
{ "aes256-cbc", 16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
|
||||
{ "rijndael-cbc@lysator.liu.se",
|
||||
SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc },
|
||||
{ "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr },
|
||||
{ "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr },
|
||||
{ "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr },
|
||||
16, 32, 0, 0, CFLAG_CBC, EVP_aes_256_cbc },
|
||||
{ "aes128-ctr", 16, 16, 0, 0, 0, EVP_aes_128_ctr },
|
||||
{ "aes192-ctr", 16, 24, 0, 0, 0, EVP_aes_192_ctr },
|
||||
{ "aes256-ctr", 16, 32, 0, 0, 0, EVP_aes_256_ctr },
|
||||
# ifdef OPENSSL_HAVE_EVPGCM
|
||||
{ "aes128-gcm@openssh.com",
|
||||
SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm },
|
||||
16, 16, 12, 16, 0, EVP_aes_128_gcm },
|
||||
{ "aes256-gcm@openssh.com",
|
||||
SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm },
|
||||
16, 32, 12, 16, 0, EVP_aes_256_gcm },
|
||||
# endif /* OPENSSL_HAVE_EVPGCM */
|
||||
#else /* WITH_OPENSSL */
|
||||
{ "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL },
|
||||
{ "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL },
|
||||
{ "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL },
|
||||
{ "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL },
|
||||
#endif /* WITH_OPENSSL */
|
||||
#else
|
||||
{ "aes128-ctr", 16, 16, 0, 0, CFLAG_AESCTR, NULL },
|
||||
{ "aes192-ctr", 16, 24, 0, 0, CFLAG_AESCTR, NULL },
|
||||
{ "aes256-ctr", 16, 32, 0, 0, CFLAG_AESCTR, NULL },
|
||||
#endif
|
||||
{ "chacha20-poly1305@openssh.com",
|
||||
SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL },
|
||||
8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL },
|
||||
{ "none", 8, 0, 0, 0, CFLAG_NONE, NULL },
|
||||
|
||||
{ NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
|
||||
{ NULL, 0, 0, 0, 0, 0, NULL }
|
||||
};
|
||||
|
||||
/*--*/
|
||||
@ -147,7 +120,7 @@ cipher_alg_list(char sep, int auth_only)
|
||||
const struct sshcipher *c;
|
||||
|
||||
for (c = ciphers; c->name != NULL; c++) {
|
||||
if (c->number != SSH_CIPHER_SSH2)
|
||||
if ((c->flags & CFLAG_INTERNAL) != 0)
|
||||
continue;
|
||||
if (auth_only && c->auth_len == 0)
|
||||
continue;
|
||||
@ -202,12 +175,6 @@ cipher_ivlen(const struct sshcipher *c)
|
||||
c->iv_len : c->block_size;
|
||||
}
|
||||
|
||||
u_int
|
||||
cipher_get_number(const struct sshcipher *c)
|
||||
{
|
||||
return (c->number);
|
||||
}
|
||||
|
||||
u_int
|
||||
cipher_is_cbc(const struct sshcipher *c)
|
||||
{
|
||||
@ -220,24 +187,6 @@ cipher_ctx_is_plaintext(struct sshcipher_ctx *cc)
|
||||
return cc->plaintext;
|
||||
}
|
||||
|
||||
u_int
|
||||
cipher_ctx_get_number(struct sshcipher_ctx *cc)
|
||||
{
|
||||
return cc->cipher->number;
|
||||
}
|
||||
|
||||
u_int
|
||||
cipher_mask_ssh1(int client)
|
||||
{
|
||||
u_int mask = 0;
|
||||
mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */
|
||||
mask |= 1 << SSH_CIPHER_BLOWFISH;
|
||||
if (client) {
|
||||
mask |= 1 << SSH_CIPHER_DES;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
const struct sshcipher *
|
||||
cipher_by_name(const char *name)
|
||||
{
|
||||
@ -248,16 +197,6 @@ cipher_by_name(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct sshcipher *
|
||||
cipher_by_number(int id)
|
||||
{
|
||||
const struct sshcipher *c;
|
||||
for (c = ciphers; c->name != NULL; c++)
|
||||
if (c->number == id)
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define CIPHER_SEP ","
|
||||
int
|
||||
ciphers_valid(const char *names)
|
||||
@ -273,7 +212,7 @@ ciphers_valid(const char *names)
|
||||
for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0';
|
||||
(p = strsep(&cp, CIPHER_SEP))) {
|
||||
c = cipher_by_name(p);
|
||||
if (c == NULL || c->number != SSH_CIPHER_SSH2) {
|
||||
if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) {
|
||||
free(cipher_list);
|
||||
return 0;
|
||||
}
|
||||
@ -282,38 +221,12 @@ ciphers_valid(const char *names)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the name of the cipher. Returns the number of the corresponding
|
||||
* cipher, or -1 on error.
|
||||
*/
|
||||
|
||||
int
|
||||
cipher_number(const char *name)
|
||||
{
|
||||
const struct sshcipher *c;
|
||||
if (name == NULL)
|
||||
return -1;
|
||||
for (c = ciphers; c->name != NULL; c++)
|
||||
if (strcasecmp(c->name, name) == 0)
|
||||
return c->number;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *
|
||||
cipher_name(int id)
|
||||
{
|
||||
const struct sshcipher *c = cipher_by_number(id);
|
||||
return (c==NULL) ? "<unknown>" : c->name;
|
||||
}
|
||||
|
||||
const char *
|
||||
cipher_warning_message(const struct sshcipher_ctx *cc)
|
||||
{
|
||||
if (cc == NULL || cc->cipher == NULL)
|
||||
return NULL;
|
||||
if (cc->cipher->number == SSH_CIPHER_DES)
|
||||
return "use of DES is strongly discouraged due to "
|
||||
"cryptographic weaknesses";
|
||||
/* XXX repurpose for CBC warning */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -327,19 +240,13 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
|
||||
#ifdef WITH_OPENSSL
|
||||
const EVP_CIPHER *type;
|
||||
int klen;
|
||||
u_char *junk, *discard;
|
||||
#endif
|
||||
|
||||
*ccp = NULL;
|
||||
if ((cc = calloc(sizeof(*cc), 1)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
|
||||
if (cipher->number == SSH_CIPHER_DES) {
|
||||
if (keylen > 8)
|
||||
keylen = 8;
|
||||
}
|
||||
|
||||
cc->plaintext = (cipher->number == SSH_CIPHER_NONE);
|
||||
cc->plaintext = (cipher->flags & CFLAG_NONE) != 0;
|
||||
cc->encrypt = do_encrypt;
|
||||
|
||||
if (keylen < cipher->key_len ||
|
||||
@ -353,6 +260,10 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
|
||||
ret = chachapoly_init(&cc->cp_ctx, key, keylen);
|
||||
goto out;
|
||||
}
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#ifndef WITH_OPENSSL
|
||||
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
|
||||
aesctr_keysetup(&cc->ac_ctx, key, 8 * keylen, 8 * ivlen);
|
||||
@ -360,10 +271,6 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ret = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
#else /* WITH_OPENSSL */
|
||||
@ -394,23 +301,6 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cipher->discard_len > 0) {
|
||||
if ((junk = malloc(cipher->discard_len)) == NULL ||
|
||||
(discard = malloc(cipher->discard_len)) == NULL) {
|
||||
free(junk);
|
||||
ret = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
ret = EVP_Cipher(cc->evp, discard, junk, cipher->discard_len);
|
||||
explicit_bzero(discard, cipher->discard_len);
|
||||
free(junk);
|
||||
free(discard);
|
||||
if (ret != 1) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
#endif /* WITH_OPENSSL */
|
||||
out:
|
||||
@ -448,6 +338,10 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
|
||||
return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src,
|
||||
len, aadlen, authlen, cc->encrypt);
|
||||
}
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
|
||||
memcpy(dest, src, aadlen + len);
|
||||
return 0;
|
||||
}
|
||||
#ifndef WITH_OPENSSL
|
||||
if ((cc->cipher->flags & CFLAG_AESCTR) != 0) {
|
||||
if (aadlen)
|
||||
@ -456,10 +350,6 @@ cipher_crypt(struct sshcipher_ctx *cc, u_int seqnr, u_char *dest,
|
||||
dest + aadlen, len);
|
||||
return 0;
|
||||
}
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0) {
|
||||
memcpy(dest, src, aadlen + len);
|
||||
return 0;
|
||||
}
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
#else
|
||||
if (authlen) {
|
||||
@ -535,28 +425,6 @@ cipher_free(struct sshcipher_ctx *cc)
|
||||
free(cc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Selects the cipher, and keys if by computing the MD5 checksum of the
|
||||
* passphrase and using the resulting 16 bytes as the key.
|
||||
*/
|
||||
int
|
||||
cipher_set_key_string(struct sshcipher_ctx **ccp,
|
||||
const struct sshcipher *cipher, const char *passphrase, int do_encrypt)
|
||||
{
|
||||
u_char digest[16];
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
|
||||
if ((r = ssh_digest_memory(SSH_DIGEST_MD5,
|
||||
passphrase, strlen(passphrase),
|
||||
digest, sizeof(digest))) != 0)
|
||||
goto out;
|
||||
|
||||
r = cipher_init(ccp, cipher, digest, 16, NULL, 0, do_encrypt);
|
||||
out:
|
||||
explicit_bzero(digest, sizeof(digest));
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exports an IV from the sshcipher_ctx required to export the key
|
||||
* state back from the unprivileged child to the privileged parent
|
||||
@ -566,19 +434,16 @@ int
|
||||
cipher_get_keyiv_len(const struct sshcipher_ctx *cc)
|
||||
{
|
||||
const struct sshcipher *c = cc->cipher;
|
||||
int ivlen = 0;
|
||||
|
||||
if (c->number == SSH_CIPHER_3DES)
|
||||
ivlen = 24;
|
||||
else if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0)
|
||||
ivlen = 0;
|
||||
else if ((cc->cipher->flags & CFLAG_AESCTR) != 0)
|
||||
ivlen = sizeof(cc->ac_ctx.ctr);
|
||||
if ((c->flags & CFLAG_CHACHAPOLY) != 0)
|
||||
return 0;
|
||||
else if ((c->flags & CFLAG_AESCTR) != 0)
|
||||
return sizeof(cc->ac_ctx.ctr);
|
||||
#ifdef WITH_OPENSSL
|
||||
else
|
||||
ivlen = EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
#endif /* WITH_OPENSSL */
|
||||
return (ivlen);
|
||||
return EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@ -603,38 +468,26 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0)
|
||||
return 0;
|
||||
|
||||
switch (c->number) {
|
||||
#ifdef WITH_OPENSSL
|
||||
case SSH_CIPHER_SSH2:
|
||||
case SSH_CIPHER_DES:
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
if (evplen == 0)
|
||||
return 0;
|
||||
else if (evplen < 0)
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((u_int)evplen != len)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
#ifndef OPENSSL_HAVE_EVPCTR
|
||||
if (c->evptype == evp_aes_128_ctr)
|
||||
ssh_aes_ctr_iv(cc->evp, 0, iv, len);
|
||||
else
|
||||
#endif
|
||||
if (cipher_authlen(c)) {
|
||||
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
|
||||
len, iv))
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
} else
|
||||
memcpy(iv, cc->evp->iv, len);
|
||||
break;
|
||||
#endif
|
||||
#ifdef WITH_SSH1
|
||||
case SSH_CIPHER_3DES:
|
||||
return ssh1_3des_iv(cc->evp, 0, iv, 24);
|
||||
#endif
|
||||
default:
|
||||
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
if (evplen == 0)
|
||||
return 0;
|
||||
else if (evplen < 0)
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((u_int)evplen != len)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
#ifndef OPENSSL_HAVE_EVPCTR
|
||||
if (c->evptype == evp_aes_128_ctr)
|
||||
ssh_aes_ctr_iv(cc->evp, 0, iv, len);
|
||||
else
|
||||
#endif
|
||||
if (cipher_authlen(c)) {
|
||||
if (!EVP_CIPHER_CTX_ctrl(cc->evp, EVP_CTRL_GCM_IV_GEN,
|
||||
len, iv))
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
} else
|
||||
memcpy(iv, cc->evp->iv, len);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -651,36 +504,24 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
|
||||
if ((cc->cipher->flags & CFLAG_NONE) != 0)
|
||||
return 0;
|
||||
|
||||
switch (c->number) {
|
||||
#ifdef WITH_OPENSSL
|
||||
case SSH_CIPHER_SSH2:
|
||||
case SSH_CIPHER_DES:
|
||||
case SSH_CIPHER_BLOWFISH:
|
||||
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
if (evplen <= 0)
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
evplen = EVP_CIPHER_CTX_iv_length(cc->evp);
|
||||
if (evplen <= 0)
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
#ifndef OPENSSL_HAVE_EVPCTR
|
||||
/* XXX iv arg is const, but ssh_aes_ctr_iv isn't */
|
||||
if (c->evptype == evp_aes_128_ctr)
|
||||
ssh_aes_ctr_iv(cc->evp, 1, (u_char *)iv, evplen);
|
||||
else
|
||||
/* XXX iv arg is const, but ssh_aes_ctr_iv isn't */
|
||||
if (c->evptype == evp_aes_128_ctr)
|
||||
ssh_aes_ctr_iv(cc->evp, 1, (u_char *)iv, evplen);
|
||||
else
|
||||
#endif
|
||||
if (cipher_authlen(c)) {
|
||||
/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
|
||||
if (!EVP_CIPHER_CTX_ctrl(cc->evp,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
} else
|
||||
memcpy(cc->evp->iv, iv, evplen);
|
||||
break;
|
||||
if (cipher_authlen(c)) {
|
||||
/* XXX iv arg is const, but EVP_CIPHER_CTX_ctrl isn't */
|
||||
if (!EVP_CIPHER_CTX_ctrl(cc->evp,
|
||||
EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
|
||||
return SSH_ERR_LIBCRYPTO_ERROR;
|
||||
} else
|
||||
memcpy(cc->evp->iv, iv, evplen);
|
||||
#endif
|
||||
#ifdef WITH_SSH1
|
||||
case SSH_CIPHER_3DES:
|
||||
return ssh1_3des_iv(cc->evp, 1, (u_char *)iv, 24);
|
||||
#endif
|
||||
default:
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
29
cipher.h
29
cipher.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cipher.h,v 1.49 2016/08/03 05:41:57 djm Exp $ */
|
||||
/* $OpenBSD: cipher.h,v 1.52 2017/05/07 23:12:57 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -42,34 +42,13 @@
|
||||
#include "cipher-chachapoly.h"
|
||||
#include "cipher-aesctr.h"
|
||||
|
||||
/*
|
||||
* Cipher types for SSH-1. New types can be added, but old types should not
|
||||
* be removed for compatibility. The maximum allowed value is 31.
|
||||
*/
|
||||
#define SSH_CIPHER_SSH2 -3
|
||||
#define SSH_CIPHER_INVALID -2 /* No valid cipher selected. */
|
||||
#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */
|
||||
#define SSH_CIPHER_NONE 0 /* no encryption */
|
||||
#define SSH_CIPHER_IDEA 1 /* IDEA CFB */
|
||||
#define SSH_CIPHER_DES 2 /* DES CBC */
|
||||
#define SSH_CIPHER_3DES 3 /* 3DES CBC */
|
||||
#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */
|
||||
#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */
|
||||
#define SSH_CIPHER_BLOWFISH 6
|
||||
#define SSH_CIPHER_RESERVED 7
|
||||
#define SSH_CIPHER_MAX 31
|
||||
|
||||
#define CIPHER_ENCRYPT 1
|
||||
#define CIPHER_DECRYPT 0
|
||||
|
||||
struct sshcipher;
|
||||
struct sshcipher_ctx;
|
||||
|
||||
u_int cipher_mask_ssh1(int);
|
||||
const struct sshcipher *cipher_by_name(const char *);
|
||||
const struct sshcipher *cipher_by_number(int);
|
||||
int cipher_number(const char *);
|
||||
char *cipher_name(int);
|
||||
const char *cipher_warning_message(const struct sshcipher_ctx *);
|
||||
int ciphers_valid(const char *);
|
||||
char *cipher_alg_list(char, int);
|
||||
@ -80,8 +59,6 @@ int cipher_crypt(struct sshcipher_ctx *, u_int, u_char *, const u_char *,
|
||||
int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int,
|
||||
const u_char *, u_int);
|
||||
void cipher_free(struct sshcipher_ctx *);
|
||||
int cipher_set_key_string(struct sshcipher_ctx **,
|
||||
const struct sshcipher *, const char *, int);
|
||||
u_int cipher_blocksize(const struct sshcipher *);
|
||||
u_int cipher_keylen(const struct sshcipher *);
|
||||
u_int cipher_seclen(const struct sshcipher *);
|
||||
@ -90,13 +67,9 @@ u_int cipher_ivlen(const struct sshcipher *);
|
||||
u_int cipher_is_cbc(const struct sshcipher *);
|
||||
|
||||
u_int cipher_ctx_is_plaintext(struct sshcipher_ctx *);
|
||||
u_int cipher_ctx_get_number(struct sshcipher_ctx *);
|
||||
|
||||
u_int cipher_get_number(const struct sshcipher *);
|
||||
int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, u_int);
|
||||
int cipher_set_keyiv(struct sshcipher_ctx *, const u_char *);
|
||||
int cipher_get_keyiv_len(const struct sshcipher_ctx *);
|
||||
int cipher_get_keycontext(const struct sshcipher_ctx *, u_char *);
|
||||
void cipher_set_keycontext(struct sshcipher_ctx *, const u_char *);
|
||||
|
||||
#endif /* CIPHER_H */
|
||||
|
853
clientloop.c
853
clientloop.c
File diff suppressed because it is too large
Load Diff
31
clientloop.h
31
clientloop.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: clientloop.h,v 1.33 2016/09/30 09:19:13 markus Exp $ */
|
||||
/* $OpenBSD: clientloop.h,v 1.34 2017/09/12 06:32:07 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -37,28 +37,31 @@
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
struct ssh;
|
||||
|
||||
/* Client side main loop for the interactive session. */
|
||||
int client_loop(int, int, int);
|
||||
int client_x11_get_proto(const char *, const char *, u_int, u_int,
|
||||
char **, char **);
|
||||
int client_loop(struct ssh *, int, int, int);
|
||||
int client_x11_get_proto(struct ssh *, const char *, const char *,
|
||||
u_int, u_int, char **, char **);
|
||||
void client_global_request_reply_fwd(int, u_int32_t, void *);
|
||||
void client_session2_setup(int, int, int, const char *, struct termios *,
|
||||
int, Buffer *, char **);
|
||||
int client_request_tun_fwd(int, int, int);
|
||||
void client_session2_setup(struct ssh *, int, int, int,
|
||||
const char *, struct termios *, int, Buffer *, char **);
|
||||
int client_request_tun_fwd(struct ssh *, int, int, int);
|
||||
void client_stop_mux(void);
|
||||
|
||||
/* Escape filter for protocol 2 sessions */
|
||||
void *client_new_escape_filter_ctx(int);
|
||||
void client_filter_cleanup(int, void *);
|
||||
int client_simple_escape_filter(Channel *, char *, int);
|
||||
void client_filter_cleanup(struct ssh *, int, void *);
|
||||
int client_simple_escape_filter(struct ssh *, Channel *, char *, int);
|
||||
|
||||
/* Global request confirmation callbacks */
|
||||
typedef void global_confirm_cb(int, u_int32_t seq, void *);
|
||||
typedef void global_confirm_cb(struct ssh *, int, u_int32_t, void *);
|
||||
void client_register_global_confirm(global_confirm_cb *, void *);
|
||||
|
||||
/* Channel request confirmation callbacks */
|
||||
enum confirm_action { CONFIRM_WARN = 0, CONFIRM_CLOSE, CONFIRM_TTY };
|
||||
void client_expect_confirm(int, const char *, enum confirm_action);
|
||||
void client_expect_confirm(struct ssh *, int, const char *,
|
||||
enum confirm_action);
|
||||
|
||||
/* Multiplexing protocol version */
|
||||
#define SSHMUX_VER 4
|
||||
@ -73,8 +76,8 @@ void client_expect_confirm(int, const char *, enum confirm_action);
|
||||
#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */
|
||||
#define SSHMUX_COMMAND_PROXY 8 /* Open new connection */
|
||||
|
||||
void muxserver_listen(void);
|
||||
void muxserver_listen(struct ssh *);
|
||||
int muxclient(const char *);
|
||||
void mux_exit_message(Channel *, int);
|
||||
void mux_tty_alloc_failed(Channel *);
|
||||
void mux_exit_message(struct ssh *, Channel *, int);
|
||||
void mux_tty_alloc_failed(struct ssh *ssh, Channel *);
|
||||
|
||||
|
34
compat.c
34
compat.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: compat.c,v 1.100 2017/02/03 23:01:19 djm Exp $ */
|
||||
/* $OpenBSD: compat.c,v 1.104 2017/07/25 09:22:25 dtucker Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -39,24 +39,8 @@
|
||||
#include "match.h"
|
||||
#include "kex.h"
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
int datafellows = 0;
|
||||
|
||||
void
|
||||
enable_compat20(void)
|
||||
{
|
||||
if (compat20)
|
||||
return;
|
||||
debug("Enabling compatibility mode for protocol 2.0");
|
||||
compat20 = 1;
|
||||
}
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
debug("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
||||
/* datafellows bug compatibility */
|
||||
u_int
|
||||
compat_datafellows(const char *version)
|
||||
@ -193,9 +177,12 @@ compat_datafellows(const char *version)
|
||||
"TTSSH/2.72*", SSH_BUG_HOSTKEYS },
|
||||
{ "WinSCP_release_4*,"
|
||||
"WinSCP_release_5.0*,"
|
||||
"WinSCP_release_5.1*,"
|
||||
"WinSCP_release_5.5*,"
|
||||
"WinSCP_release_5.6*,"
|
||||
"WinSCP_release_5.1,"
|
||||
"WinSCP_release_5.1.*,"
|
||||
"WinSCP_release_5.5,"
|
||||
"WinSCP_release_5.5.*,"
|
||||
"WinSCP_release_5.6,"
|
||||
"WinSCP_release_5.6.*,"
|
||||
"WinSCP_release_5.7,"
|
||||
"WinSCP_release_5.7.1,"
|
||||
"WinSCP_release_5.7.2,"
|
||||
@ -232,13 +219,6 @@ proto_spec(const char *spec)
|
||||
return ret;
|
||||
for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) {
|
||||
switch (atoi(p)) {
|
||||
case 1:
|
||||
#ifdef WITH_SSH1
|
||||
if (ret == SSH_PROTO_UNKNOWN)
|
||||
ret |= SSH_PROTO_1_PREFERRED;
|
||||
ret |= SSH_PROTO_1;
|
||||
#endif
|
||||
break;
|
||||
case 2:
|
||||
ret |= SSH_PROTO_2;
|
||||
break;
|
||||
|
6
compat.h
6
compat.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: compat.h,v 1.48 2015/05/26 23:23:40 dtucker Exp $ */
|
||||
/* $OpenBSD: compat.h,v 1.49 2017/04/30 23:13:25 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -63,15 +63,11 @@
|
||||
#define SSH_BUG_HOSTKEYS 0x20000000
|
||||
#define SSH_BUG_DHGEX_LARGE 0x40000000
|
||||
|
||||
void enable_compat13(void);
|
||||
void enable_compat20(void);
|
||||
u_int compat_datafellows(const char *);
|
||||
int proto_spec(const char *);
|
||||
char *compat_cipher_proposal(char *);
|
||||
char *compat_pkalg_proposal(char *);
|
||||
char *compat_kex_proposal(char *);
|
||||
|
||||
extern int compat13;
|
||||
extern int compat20;
|
||||
extern int datafellows;
|
||||
#endif
|
||||
|
42
config.h.in
42
config.h.in
@ -252,6 +252,9 @@
|
||||
/* Define to 1 if you have the <bstring.h> header file. */
|
||||
#undef HAVE_BSTRING_H
|
||||
|
||||
/* calloc(x, 0) returns NULL */
|
||||
#undef HAVE_CALLOC
|
||||
|
||||
/* Define to 1 if you have the `cap_rights_limit' function. */
|
||||
#undef HAVE_CAP_RIGHTS_LIMIT
|
||||
|
||||
@ -469,6 +472,9 @@
|
||||
/* Define to 1 if you have the `freeaddrinfo' function. */
|
||||
#undef HAVE_FREEADDRINFO
|
||||
|
||||
/* Define to 1 if you have the `freezero' function. */
|
||||
#undef HAVE_FREEZERO
|
||||
|
||||
/* Define to 1 if the system has the type `fsblkcnt_t'. */
|
||||
#undef HAVE_FSBLKCNT_T
|
||||
|
||||
@ -769,6 +775,10 @@
|
||||
/* Define to 1 if you have the <maillock.h> header file. */
|
||||
#undef HAVE_MAILLOCK_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the `mblen' function. */
|
||||
#undef HAVE_MBLEN
|
||||
|
||||
@ -899,12 +909,19 @@
|
||||
/* Define to 1 if you have the <readpassphrase.h> header file. */
|
||||
#undef HAVE_READPASSPHRASE_H
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `reallocarray' function. */
|
||||
#undef HAVE_REALLOCARRAY
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
/* Define to 1 if you have the `recallocarray' function. */
|
||||
#undef HAVE_RECALLOCARRAY
|
||||
|
||||
/* Define to 1 if you have the `recvmsg' function. */
|
||||
#undef HAVE_RECVMSG
|
||||
|
||||
@ -1115,6 +1132,9 @@
|
||||
/* Define to 1 if you have the `strsep' function. */
|
||||
#undef HAVE_STRSEP
|
||||
|
||||
/* Define to 1 if you have the `strsignal' function. */
|
||||
#undef HAVE_STRSIGNAL
|
||||
|
||||
/* Define to 1 if you have the `strtoll' function. */
|
||||
#undef HAVE_STRTOLL
|
||||
|
||||
@ -1157,6 +1177,12 @@
|
||||
/* Define to 1 if `st_blksize' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
|
||||
/* Define to 1 if `st_mtim' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIM
|
||||
|
||||
/* Define to 1 if `st_mtime' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIME
|
||||
|
||||
/* Define to 1 if the system has the type `struct timespec'. */
|
||||
#undef HAVE_STRUCT_TIMESPEC
|
||||
|
||||
@ -1181,8 +1207,8 @@
|
||||
/* Define to 1 if you have the <sys/bsdtty.h> header file. */
|
||||
#undef HAVE_SYS_BSDTTY_H
|
||||
|
||||
/* Define to 1 if you have the <sys/capability.h> header file. */
|
||||
#undef HAVE_SYS_CAPABILITY_H
|
||||
/* Define to 1 if you have the <sys/capsicum.h> header file. */
|
||||
#undef HAVE_SYS_CAPSICUM_H
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
#undef HAVE_SYS_CDEFS_H
|
||||
@ -1719,9 +1745,6 @@
|
||||
/* Define if you want SELinux support. */
|
||||
#undef WITH_SELINUX
|
||||
|
||||
/* include SSH protocol version 1 support */
|
||||
#undef WITH_SSH1
|
||||
|
||||
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
|
||||
significant byte first (like Motorola and SPARC, unlike Intel). */
|
||||
#if defined AC_APPLE_UNIVERSAL_BUILD
|
||||
@ -1760,11 +1783,20 @@
|
||||
/* Define if we don't have struct __res_state in resolv.h */
|
||||
#undef __res_state
|
||||
|
||||
/* Define to rpl_calloc if the replacement function should be used. */
|
||||
#undef calloc
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
#undef malloc
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
#undef realloc
|
||||
|
||||
/* type to use in place of socklen_t if not defined */
|
||||
#undef socklen_t
|
||||
|
335
configure
vendored
335
configure
vendored
@ -624,7 +624,6 @@ ac_includes_default="\
|
||||
#endif"
|
||||
|
||||
ac_subst_vars='LTLIBOBJS
|
||||
LIBOBJS
|
||||
UNSUPPORTED_ALGORITHMS
|
||||
TEST_MALLOC_OPTIONS
|
||||
TEST_SSH_UTF8
|
||||
@ -648,7 +647,7 @@ TEST_SSH_ECC
|
||||
LIBEDIT
|
||||
PKGCONFIG
|
||||
LDNSCONFIG
|
||||
COMMENT_OUT_RSA1
|
||||
LIBOBJS
|
||||
LD
|
||||
PATH_PASSWD_PROG
|
||||
STARTUP_SCRIPT_SHELL
|
||||
@ -735,13 +734,14 @@ ac_user_opts='
|
||||
enable_option_checking
|
||||
enable_largefile
|
||||
with_openssl
|
||||
with_ssh1
|
||||
with_stackprotect
|
||||
with_hardening
|
||||
with_rpath
|
||||
with_cflags
|
||||
with_cflags_after
|
||||
with_cppflags
|
||||
with_ldflags
|
||||
with_ldflags_after
|
||||
with_libs
|
||||
with_Werror
|
||||
with_solaris_contracts
|
||||
@ -1430,13 +1430,14 @@ Optional Packages:
|
||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
|
||||
--without-openssl Disable use of OpenSSL; use only limited internal crypto **EXPERIMENTAL**
|
||||
--with-ssh1 Enable support for SSH protocol 1
|
||||
--without-stackprotect Don't use compiler's stack protection
|
||||
--without-hardening Don't use toolchain hardening flags
|
||||
--without-rpath Disable auto-added -R linker paths
|
||||
--with-cflags Specify additional flags to pass to compiler
|
||||
--with-cflags-after Specify additional flags to pass to compiler after configure
|
||||
--with-cppflags Specify additional flags to pass to preprocessor
|
||||
--with-ldflags Specify additional flags to pass to linker
|
||||
--with-ldflags-after Specify additional flags to pass to linker after configure
|
||||
--with-libs Specify additional libraries to link with
|
||||
--with-Werror Build main code with -Werror
|
||||
--with-solaris-contracts Enable Solaris process contracts (experimental)
|
||||
@ -5634,14 +5635,11 @@ fi
|
||||
|
||||
|
||||
openssl=yes
|
||||
ssh1=no
|
||||
COMMENT_OUT_RSA1="#no ssh1#"
|
||||
|
||||
# Check whether --with-openssl was given.
|
||||
if test "${with_openssl+set}" = set; then :
|
||||
withval=$with_openssl; if test "x$withval" = "xno" ; then
|
||||
openssl=no
|
||||
ssh1=no
|
||||
fi
|
||||
|
||||
|
||||
@ -5657,41 +5655,6 @@ cat >>confdefs.h <<_ACEOF
|
||||
#define WITH_OPENSSL 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-ssh1 was given.
|
||||
if test "${with_ssh1+set}" = set; then :
|
||||
withval=$with_ssh1;
|
||||
if test "x$withval" = "xyes" ; then
|
||||
if test "x$openssl" = "xno" ; then
|
||||
as_fn_error $? "Cannot enable SSH protocol 1 with OpenSSL disabled" "$LINENO" 5
|
||||
fi
|
||||
ssh1=yes
|
||||
COMMENT_OUT_RSA1=""
|
||||
elif test "x$withval" = "xno" ; then
|
||||
ssh1=no
|
||||
else
|
||||
as_fn_error $? "unknown --with-ssh1 argument" "$LINENO" 5
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether SSH protocol 1 support is enabled" >&5
|
||||
$as_echo_n "checking whether SSH protocol 1 support is enabled... " >&6; }
|
||||
if test "x$ssh1" = "xyes" ; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define WITH_SSH1 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
@ -5742,6 +5705,49 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
|
||||
if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
|
||||
{
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -pipe" >&5
|
||||
$as_echo_n "checking if $CC supports compile flag -pipe... " >&6; }
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $WERROR -pipe"
|
||||
_define_flag=""
|
||||
test "x$_define_flag" = "x" && _define_flag="-pipe"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
int main(int argc, char **argv) {
|
||||
/* Some math to catch -ftrapv problems in the toolchain */
|
||||
int i = 123 * argc, j = 456 + argc, k = 789 - argc;
|
||||
float l = i * 2.1;
|
||||
double m = l / 0.5;
|
||||
long long int n = argc * 12345LL, o = 12345LL * (long long int)argc;
|
||||
printf("%d %d %d %f %f %lld %lld\n", i, j, k, l, m, n, o);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
|
||||
if `grep -i "unrecognized option" conftest.err >/dev/null`
|
||||
then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
CFLAGS="$saved_CFLAGS $_define_flag"
|
||||
fi
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
}
|
||||
{
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -Qunused-arguments" >&5
|
||||
$as_echo_n "checking if $CC supports compile flag -Qunused-arguments... " >&6; }
|
||||
@ -6215,6 +6221,7 @@ $as_echo "no" >&6; }
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
}
|
||||
if test "x$use_toolchain_hardening" = "x1"; then
|
||||
{
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -D_FORTIFY_SOURCE=2" >&5
|
||||
$as_echo_n "checking if $CC supports compile flag -D_FORTIFY_SOURCE=2... " >&6; }
|
||||
@ -6258,7 +6265,6 @@ $as_echo "no" >&6; }
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
}
|
||||
if test "x$use_toolchain_hardening" = "x1"; then
|
||||
{
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $LD supports link flag -Wl,-z,relro" >&5
|
||||
$as_echo_n "checking if $LD supports link flag -Wl,-z,relro... " >&6; }
|
||||
@ -6620,6 +6626,19 @@ if test "${with_cflags+set}" = set; then :
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Check whether --with-cflags-after was given.
|
||||
if test "${with_cflags_after+set}" = set; then :
|
||||
withval=$with_cflags_after;
|
||||
if test -n "$withval" && test "x$withval" != "xno" && \
|
||||
test "x${withval}" != "xyes"; then
|
||||
CFLAGS_AFTER="$withval"
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-cppflags was given.
|
||||
if test "${with_cppflags+set}" = set; then :
|
||||
withval=$with_cppflags;
|
||||
@ -6644,6 +6663,18 @@ if test "${with_ldflags+set}" = set; then :
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-ldflags-after was given.
|
||||
if test "${with_ldflags_after+set}" = set; then :
|
||||
withval=$with_ldflags_after;
|
||||
if test -n "$withval" && test "x$withval" != "xno" && \
|
||||
test "x${withval}" != "xyes"; then
|
||||
LDFLAGS_AFTER="$withval"
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# Check whether --with-libs was given.
|
||||
if test "${with_libs+set}" = set; then :
|
||||
withval=$with_libs;
|
||||
@ -6712,7 +6743,6 @@ for ac_header in \
|
||||
sys/audit.h \
|
||||
sys/bitypes.h \
|
||||
sys/bsdtty.h \
|
||||
sys/capability.h \
|
||||
sys/cdefs.h \
|
||||
sys/dir.h \
|
||||
sys/mman.h \
|
||||
@ -6756,6 +6786,25 @@ fi
|
||||
done
|
||||
|
||||
|
||||
# sys/capsicum.h requires sys/types.h
|
||||
for ac_header in sys/capsicum.h
|
||||
do :
|
||||
ac_fn_c_check_header_compile "$LINENO" "sys/capsicum.h" "ac_cv_header_sys_capsicum_h" "
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
"
|
||||
if test "x$ac_cv_header_sys_capsicum_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_SYS_CAPSICUM_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
|
||||
# lastlog.h requires sys/time.h to be included first on Solaris
|
||||
for ac_header in lastlog.h
|
||||
do :
|
||||
@ -8208,6 +8257,8 @@ $as_echo "#define UNIXWARE_LONG_PASSWORDS 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define PASSWD_NEEDS_USERNAME 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define BROKEN_TCGETATTR_ICANON 1" >>confdefs.h
|
||||
|
||||
TEST_SHELL=$SHELL # let configure find us a capable shell
|
||||
case "$host" in
|
||||
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
||||
@ -9631,6 +9682,8 @@ if test "$ac_res" != no; then :
|
||||
fi
|
||||
|
||||
|
||||
# "Particular Function Checks"
|
||||
# see https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Functions.html
|
||||
for ac_func in strftime
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "strftime" "ac_cv_func_strftime"
|
||||
@ -9686,6 +9739,149 @@ fi
|
||||
fi
|
||||
done
|
||||
|
||||
for ac_header in stdlib.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_stdlib_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_STDLIB_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
|
||||
$as_echo_n "checking for GNU libc compatible malloc... " >&6; }
|
||||
if ${ac_cv_func_malloc_0_nonnull+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test "$cross_compiling" = yes; then :
|
||||
ac_cv_func_malloc_0_nonnull=no
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#if defined STDC_HEADERS || defined HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
char *malloc ();
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return ! malloc (0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_run "$LINENO"; then :
|
||||
ac_cv_func_malloc_0_nonnull=yes
|
||||
else
|
||||
ac_cv_func_malloc_0_nonnull=no
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
|
||||
$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; }
|
||||
if test $ac_cv_func_malloc_0_nonnull = yes; then :
|
||||
|
||||
$as_echo "#define HAVE_MALLOC 1" >>confdefs.h
|
||||
|
||||
else
|
||||
$as_echo "#define HAVE_MALLOC 0" >>confdefs.h
|
||||
|
||||
case " $LIBOBJS " in
|
||||
*" malloc.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS malloc.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
$as_echo "#define malloc rpl_malloc" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
for ac_header in stdlib.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_stdlib_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_STDLIB_H 1
|
||||
_ACEOF
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5
|
||||
$as_echo_n "checking for GNU libc compatible realloc... " >&6; }
|
||||
if ${ac_cv_func_realloc_0_nonnull+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
if test "$cross_compiling" = yes; then :
|
||||
ac_cv_func_realloc_0_nonnull=no
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#if defined STDC_HEADERS || defined HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
char *realloc ();
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return ! realloc (0, 0);
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_run "$LINENO"; then :
|
||||
ac_cv_func_realloc_0_nonnull=yes
|
||||
else
|
||||
ac_cv_func_realloc_0_nonnull=no
|
||||
fi
|
||||
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
|
||||
conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
fi
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5
|
||||
$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; }
|
||||
if test $ac_cv_func_realloc_0_nonnull = yes; then :
|
||||
|
||||
$as_echo "#define HAVE_REALLOC 1" >>confdefs.h
|
||||
|
||||
else
|
||||
$as_echo "#define HAVE_REALLOC 0" >>confdefs.h
|
||||
|
||||
case " $LIBOBJS " in
|
||||
*" realloc.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS realloc.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
$as_echo "#define realloc rpl_realloc" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
|
||||
# autoconf doesn't have AC_FUNC_CALLOC so fake it if malloc returns NULL;
|
||||
if test "x$ac_cv_func_malloc_0_nonnull" != "xyes"; then
|
||||
|
||||
$as_echo "#define HAVE_CALLOC 0" >>confdefs.h
|
||||
|
||||
|
||||
$as_echo "#define calloc rpl_calloc" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
# Check for ALTDIRFUNC glob() extension
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_ALTDIRFUNC support" >&5
|
||||
@ -10068,6 +10264,7 @@ fi
|
||||
else
|
||||
LIBS="$LIBS `$LDNSCONFIG --libs`"
|
||||
CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`"
|
||||
ldns=yes
|
||||
fi
|
||||
elif test "x$withval" != "xno" ; then
|
||||
CPPFLAGS="$CPPFLAGS -I${withval}/include"
|
||||
@ -10647,6 +10844,7 @@ for ac_func in \
|
||||
fchmod \
|
||||
fchown \
|
||||
freeaddrinfo \
|
||||
freezero \
|
||||
fstatfs \
|
||||
fstatvfs \
|
||||
futimes \
|
||||
@ -10655,6 +10853,7 @@ for ac_func in \
|
||||
getgrouplist \
|
||||
getnameinfo \
|
||||
getopt \
|
||||
getpagesize \
|
||||
getpeereid \
|
||||
getpeerucred \
|
||||
getpgid \
|
||||
@ -10685,6 +10884,7 @@ for ac_func in \
|
||||
readpassphrase \
|
||||
reallocarray \
|
||||
recvmsg \
|
||||
recallocarray \
|
||||
rresvport_af \
|
||||
sendmsg \
|
||||
setdtablesize \
|
||||
@ -10718,6 +10918,7 @@ for ac_func in \
|
||||
strnlen \
|
||||
strnvis \
|
||||
strptime \
|
||||
strsignal \
|
||||
strtonum \
|
||||
strtoll \
|
||||
strtoul \
|
||||
@ -12484,7 +12685,11 @@ if ac_fn_c_try_run "$LINENO"; then :
|
||||
10000*|0*)
|
||||
as_fn_error $? "OpenSSL >= 1.0.1 required (have \"$ssl_library_ver\")" "$LINENO" 5
|
||||
;;
|
||||
*) ;;
|
||||
100*) ;; # 1.0.x
|
||||
200*) ;; # LibreSSL
|
||||
*)
|
||||
as_fn_error $? "OpenSSL >= 1.1.0 is not yet supported (have \"$ssl_library_ver\")" "$LINENO" 5
|
||||
;;
|
||||
esac
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ssl_library_ver" >&5
|
||||
$as_echo "$ssl_library_ver" >&6; }
|
||||
@ -13053,9 +13258,6 @@ $as_echo_n "checking whether OpenSSL has NID_X9_62_prime256v1... " >&6; }
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
@ -13091,9 +13293,6 @@ $as_echo_n "checking whether OpenSSL has NID_secp384r1... " >&6; }
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
@ -13129,9 +13328,6 @@ $as_echo_n "checking whether OpenSSL has NID_secp521r1... " >&6; }
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
|
||||
int
|
||||
main ()
|
||||
@ -13858,6 +14054,7 @@ $as_echo_n "checking if select works with descriptor rlimit... " >&6; }
|
||||
if test "$cross_compiling" = yes; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
|
||||
$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
|
||||
select_works_with_rlimit=yes
|
||||
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@ -13918,6 +14115,7 @@ $as_echo_n "checking if setrlimit(RLIMIT_NOFILE,{0,0}) works... " >&6; }
|
||||
if test "$cross_compiling" = yes; then :
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cross compiling: assuming yes" >&5
|
||||
$as_echo "$as_me: WARNING: cross compiling: assuming yes" >&2;}
|
||||
rlimit_nofile_zero_works=yes
|
||||
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
@ -14052,10 +14250,10 @@ $as_echo "#define SANDBOX_SECCOMP_FILTER 1" >>confdefs.h
|
||||
|
||||
elif test "x$sandbox_arg" = "xcapsicum" || \
|
||||
( test -z "$sandbox_arg" && \
|
||||
test "x$ac_cv_header_sys_capability_h" = "xyes" && \
|
||||
test "x$ac_cv_header_sys_capsicum_h" = "xyes" && \
|
||||
test "x$ac_cv_func_cap_rights_limit" = "xyes") ; then
|
||||
test "x$ac_cv_header_sys_capability_h" != "xyes" && \
|
||||
as_fn_error $? "capsicum sandbox requires sys/capability.h header" "$LINENO" 5
|
||||
test "x$ac_cv_header_sys_capsicum_h" != "xyes" && \
|
||||
as_fn_error $? "capsicum sandbox requires sys/capsicum.h header" "$LINENO" 5
|
||||
test "x$ac_cv_func_cap_rights_limit" != "xyes" && \
|
||||
as_fn_error $? "capsicum sandbox requires cap_rights_limit function" "$LINENO" 5
|
||||
SANDBOX_STYLE="capsicum"
|
||||
@ -16185,6 +16383,26 @@ cat >>confdefs.h <<_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default"
|
||||
if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then :
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_STRUCT_STAT_ST_MTIM 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtime" "ac_cv_member_struct_stat_st_mtime" "$ac_includes_default"
|
||||
if test "x$ac_cv_member_struct_stat_st_mtime" = xyes; then :
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_STRUCT_STAT_ST_MTIME 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct passwd" "pw_gecos" "ac_cv_member_struct_passwd_pw_gecos" "
|
||||
@ -19055,6 +19273,9 @@ TEST_MALLOC_OPTIONS=$TEST_MALLOC_OPTIONS
|
||||
UNSUPPORTED_ALGORITHMS=$unsupported_algorithms
|
||||
|
||||
|
||||
CFLAGS="${CFLAGS} ${CFLAGS_AFTER}"
|
||||
LDFLAGS="${LDFLAGS} ${LDFLAGS_AFTER}"
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile buildpkg.sh opensshd.init openssh.xml openbsd-compat/Makefile openbsd-compat/regress/Makefile survey.sh"
|
||||
|
||||
|
106
configure.ac
106
configure.ac
@ -109,13 +109,10 @@ AC_CHECK_DECL([PR_SET_NO_NEW_PRIVS], [have_linux_no_new_privs=1], , [
|
||||
])
|
||||
|
||||
openssl=yes
|
||||
ssh1=no
|
||||
COMMENT_OUT_RSA1="#no ssh1#"
|
||||
AC_ARG_WITH([openssl],
|
||||
[ --without-openssl Disable use of OpenSSL; use only limited internal crypto **EXPERIMENTAL** ],
|
||||
[ if test "x$withval" = "xno" ; then
|
||||
openssl=no
|
||||
ssh1=no
|
||||
fi
|
||||
]
|
||||
)
|
||||
@ -127,31 +124,6 @@ else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([ssh1],
|
||||
[ --with-ssh1 Enable support for SSH protocol 1],
|
||||
[
|
||||
if test "x$withval" = "xyes" ; then
|
||||
if test "x$openssl" = "xno" ; then
|
||||
AC_MSG_ERROR([Cannot enable SSH protocol 1 with OpenSSL disabled])
|
||||
fi
|
||||
ssh1=yes
|
||||
COMMENT_OUT_RSA1=""
|
||||
elif test "x$withval" = "xno" ; then
|
||||
ssh1=no
|
||||
else
|
||||
AC_MSG_ERROR([unknown --with-ssh1 argument])
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_MSG_CHECKING([whether SSH protocol 1 support is enabled])
|
||||
if test "x$ssh1" = "xyes" ; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE_UNQUOTED([WITH_SSH1], [1], [include SSH protocol version 1 support])
|
||||
AC_SUBST([COMMENT_OUT_RSA1])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
use_stack_protector=1
|
||||
use_toolchain_hardening=1
|
||||
AC_ARG_WITH([stackprotect],
|
||||
@ -179,6 +151,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int main(void) { return 0; }]])],
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
|
||||
if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
|
||||
OSSH_CHECK_CFLAG_COMPILE([-pipe])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-Qunused-arguments])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-Wunknown-warning-option])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-Wall])
|
||||
@ -190,8 +163,8 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
|
||||
OSSH_CHECK_CFLAG_COMPILE([-Wpointer-sign], [-Wno-pointer-sign])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-Wunused-result], [-Wno-unused-result])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-fno-strict-aliasing])
|
||||
OSSH_CHECK_CFLAG_COMPILE([-D_FORTIFY_SOURCE=2])
|
||||
if test "x$use_toolchain_hardening" = "x1"; then
|
||||
OSSH_CHECK_CFLAG_COMPILE([-D_FORTIFY_SOURCE=2])
|
||||
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,relro])
|
||||
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,now])
|
||||
OSSH_CHECK_LDFLAG_LINK([-Wl,-z,noexecstack])
|
||||
@ -316,6 +289,16 @@ AC_ARG_WITH([cflags],
|
||||
fi
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_WITH([cflags-after],
|
||||
[ --with-cflags-after Specify additional flags to pass to compiler after configure],
|
||||
[
|
||||
if test -n "$withval" && test "x$withval" != "xno" && \
|
||||
test "x${withval}" != "xyes"; then
|
||||
CFLAGS_AFTER="$withval"
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_WITH([cppflags],
|
||||
[ --with-cppflags Specify additional flags to pass to preprocessor] ,
|
||||
[
|
||||
@ -334,6 +317,15 @@ AC_ARG_WITH([ldflags],
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_WITH([ldflags-after],
|
||||
[ --with-ldflags-after Specify additional flags to pass to linker after configure],
|
||||
[
|
||||
if test -n "$withval" && test "x$withval" != "xno" && \
|
||||
test "x${withval}" != "xyes"; then
|
||||
LDFLAGS_AFTER="$withval"
|
||||
fi
|
||||
]
|
||||
)
|
||||
AC_ARG_WITH([libs],
|
||||
[ --with-libs Specify additional libraries to link with],
|
||||
[
|
||||
@ -397,7 +389,6 @@ AC_CHECK_HEADERS([ \
|
||||
sys/audit.h \
|
||||
sys/bitypes.h \
|
||||
sys/bsdtty.h \
|
||||
sys/capability.h \
|
||||
sys/cdefs.h \
|
||||
sys/dir.h \
|
||||
sys/mman.h \
|
||||
@ -429,6 +420,13 @@ AC_CHECK_HEADERS([ \
|
||||
wchar.h \
|
||||
])
|
||||
|
||||
# sys/capsicum.h requires sys/types.h
|
||||
AC_CHECK_HEADERS([sys/capsicum.h], [], [], [
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
# lastlog.h requires sys/time.h to be included first on Solaris
|
||||
AC_CHECK_HEADERS([lastlog.h], [], [], [
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
@ -1007,6 +1005,7 @@ mips-sony-bsd|mips-sony-newsos4)
|
||||
AC_DEFINE([BROKEN_SETREUID])
|
||||
AC_DEFINE([BROKEN_SETREGID])
|
||||
AC_DEFINE([PASSWD_NEEDS_USERNAME])
|
||||
AC_DEFINE([BROKEN_TCGETATTR_ICANON])
|
||||
TEST_SHELL=$SHELL # let configure find us a capable shell
|
||||
case "$host" in
|
||||
*-*-sysv5SCO_SV*) # SCO OpenServer 6.x
|
||||
@ -1332,7 +1331,17 @@ AC_CHECK_FUNCS([fmt_scaled scan_scaled login logout openpty updwtmp logwtmp])
|
||||
AC_SEARCH_LIBS([inet_ntop], [resolv nsl])
|
||||
AC_SEARCH_LIBS([gethostbyname], [resolv nsl])
|
||||
|
||||
# "Particular Function Checks"
|
||||
# see https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Particular-Functions.html
|
||||
AC_FUNC_STRFTIME
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_REALLOC
|
||||
# autoconf doesn't have AC_FUNC_CALLOC so fake it if malloc returns NULL;
|
||||
if test "x$ac_cv_func_malloc_0_nonnull" != "xyes"; then
|
||||
AC_DEFINE(HAVE_CALLOC, 0, [calloc(x, 0) returns NULL])
|
||||
AC_DEFINE(calloc, rpl_calloc,
|
||||
[Define to rpl_calloc if the replacement function should be used.])
|
||||
fi
|
||||
|
||||
# Check for ALTDIRFUNC glob() extension
|
||||
AC_MSG_CHECKING([for GLOB_ALTDIRFUNC support])
|
||||
@ -1486,6 +1495,7 @@ AC_ARG_WITH(ldns,
|
||||
else
|
||||
LIBS="$LIBS `$LDNSCONFIG --libs`"
|
||||
CPPFLAGS="$CPPFLAGS `$LDNSCONFIG --cflags`"
|
||||
ldns=yes
|
||||
fi
|
||||
elif test "x$withval" != "xno" ; then
|
||||
CPPFLAGS="$CPPFLAGS -I${withval}/include"
|
||||
@ -1696,6 +1706,7 @@ AC_CHECK_FUNCS([ \
|
||||
fchmod \
|
||||
fchown \
|
||||
freeaddrinfo \
|
||||
freezero \
|
||||
fstatfs \
|
||||
fstatvfs \
|
||||
futimes \
|
||||
@ -1704,6 +1715,7 @@ AC_CHECK_FUNCS([ \
|
||||
getgrouplist \
|
||||
getnameinfo \
|
||||
getopt \
|
||||
getpagesize \
|
||||
getpeereid \
|
||||
getpeerucred \
|
||||
getpgid \
|
||||
@ -1734,6 +1746,7 @@ AC_CHECK_FUNCS([ \
|
||||
readpassphrase \
|
||||
reallocarray \
|
||||
recvmsg \
|
||||
recallocarray \
|
||||
rresvport_af \
|
||||
sendmsg \
|
||||
setdtablesize \
|
||||
@ -1767,6 +1780,7 @@ AC_CHECK_FUNCS([ \
|
||||
strnlen \
|
||||
strnvis \
|
||||
strptime \
|
||||
strsignal \
|
||||
strtonum \
|
||||
strtoll \
|
||||
strtoul \
|
||||
@ -2535,7 +2549,11 @@ if test "x$openssl" = "xyes" ; then
|
||||
10000*|0*)
|
||||
AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")])
|
||||
;;
|
||||
*) ;;
|
||||
100*) ;; # 1.0.x
|
||||
200*) ;; # LibreSSL
|
||||
*)
|
||||
AC_MSG_ERROR([OpenSSL >= 1.1.0 is not yet supported (have "$ssl_library_ver")])
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$ssl_library_ver])
|
||||
],
|
||||
@ -2768,9 +2786,6 @@ if test "x$openssl" = "xyes" ; then
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
]], [[
|
||||
EC_KEY *e = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
const EVP_MD *m = EVP_sha256(); /* We need this too */
|
||||
@ -2789,9 +2804,6 @@ if test "x$openssl" = "xyes" ; then
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
]], [[
|
||||
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp384r1);
|
||||
const EVP_MD *m = EVP_sha384(); /* We need this too */
|
||||
@ -2810,9 +2822,6 @@ if test "x$openssl" = "xyes" ; then
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#if OPENSSL_VERSION_NUMBER < 0x0090807f /* 0.9.8g */
|
||||
# error "OpenSSL < 0.9.8g has unreliable ECC code"
|
||||
#endif
|
||||
]], [[
|
||||
EC_KEY *e = EC_KEY_new_by_curve_name(NID_secp521r1);
|
||||
const EVP_MD *m = EVP_sha512(); /* We need this too */
|
||||
@ -3197,7 +3206,8 @@ AC_RUN_IFELSE(
|
||||
select_works_with_rlimit=yes],
|
||||
[AC_MSG_RESULT([no])
|
||||
select_works_with_rlimit=no],
|
||||
[AC_MSG_WARN([cross compiling: assuming yes])]
|
||||
[AC_MSG_WARN([cross compiling: assuming yes])
|
||||
select_works_with_rlimit=yes]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([if setrlimit(RLIMIT_NOFILE,{0,0}) works])
|
||||
@ -3223,7 +3233,8 @@ AC_RUN_IFELSE(
|
||||
rlimit_nofile_zero_works=yes],
|
||||
[AC_MSG_RESULT([no])
|
||||
rlimit_nofile_zero_works=no],
|
||||
[AC_MSG_WARN([cross compiling: assuming yes])]
|
||||
[AC_MSG_WARN([cross compiling: assuming yes])
|
||||
rlimit_nofile_zero_works=yes]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([if setrlimit RLIMIT_FSIZE works])
|
||||
@ -3286,10 +3297,10 @@ elif test "x$sandbox_arg" = "xseccomp_filter" || \
|
||||
AC_DEFINE([SANDBOX_SECCOMP_FILTER], [1], [Sandbox using seccomp filter])
|
||||
elif test "x$sandbox_arg" = "xcapsicum" || \
|
||||
( test -z "$sandbox_arg" && \
|
||||
test "x$ac_cv_header_sys_capability_h" = "xyes" && \
|
||||
test "x$ac_cv_header_sys_capsicum_h" = "xyes" && \
|
||||
test "x$ac_cv_func_cap_rights_limit" = "xyes") ; then
|
||||
test "x$ac_cv_header_sys_capability_h" != "xyes" && \
|
||||
AC_MSG_ERROR([capsicum sandbox requires sys/capability.h header])
|
||||
test "x$ac_cv_header_sys_capsicum_h" != "xyes" && \
|
||||
AC_MSG_ERROR([capsicum sandbox requires sys/capsicum.h header])
|
||||
test "x$ac_cv_func_cap_rights_limit" != "xyes" && \
|
||||
AC_MSG_ERROR([capsicum sandbox requires cap_rights_limit function])
|
||||
SANDBOX_STYLE="capsicum"
|
||||
@ -3845,6 +3856,8 @@ OSSH_CHECK_HEADER_FOR_FIELD([ut_time], [utmpx.h], [HAVE_TIME_IN_UTMPX])
|
||||
OSSH_CHECK_HEADER_FOR_FIELD([ut_tv], [utmpx.h], [HAVE_TV_IN_UTMPX])
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_blksize])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtim])
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtime])
|
||||
AC_CHECK_MEMBERS([struct passwd.pw_gecos, struct passwd.pw_class,
|
||||
struct passwd.pw_change, struct passwd.pw_expire],
|
||||
[], [], [[
|
||||
@ -5044,6 +5057,9 @@ AC_SUBST([TEST_SSH_UTF8], [$TEST_SSH_UTF8])
|
||||
AC_SUBST([TEST_MALLOC_OPTIONS], [$TEST_MALLOC_OPTIONS])
|
||||
AC_SUBST([UNSUPPORTED_ALGORITHMS], [$unsupported_algorithms])
|
||||
|
||||
CFLAGS="${CFLAGS} ${CFLAGS_AFTER}"
|
||||
LDFLAGS="${LDFLAGS} ${LDFLAGS_AFTER}"
|
||||
|
||||
AC_EXEEXT
|
||||
AC_CONFIG_FILES([Makefile buildpkg.sh opensshd.init openssh.xml \
|
||||
openbsd-compat/Makefile openbsd-compat/regress/Makefile \
|
||||
|
@ -35,7 +35,7 @@ The script treats all packages as USR packages (not ROOT+USR when
|
||||
appropriate). It seems to work, though......
|
||||
|
||||
If there are any patches to this that have not yet been integrated they
|
||||
may be found at http://www.zip.com.au/~dtucker/openssh/.
|
||||
may be found at http://www.dtucker.net/openssh/.
|
||||
|
||||
|
||||
Disclaimer:
|
||||
|
@ -1,4 +1,4 @@
|
||||
%define ver 7.5p1
|
||||
%define ver 7.6p1
|
||||
%define rel 1
|
||||
|
||||
# OpenSSH privilege separation requires a user & group ID
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 1999-2013 Philip Hands <phil@hands.com>
|
||||
# Copyright (c) 1999-2016 Philip Hands <phil@hands.com>
|
||||
# 2013 Martin Kletzander <mkletzan@redhat.com>
|
||||
# 2010 Adeodato =?iso-8859-1?Q?Sim=F3?= <asp16@alu.ua.es>
|
||||
# 2010 Eric Moret <eric.moret@gmail.com>
|
||||
@ -56,7 +56,8 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
DEFAULT_PUB_ID_FILE="$HOME/$(cd "$HOME" ; ls -t .ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1)"
|
||||
most_recent_id="$(cd "$HOME" ; ls -t .ssh/id*.pub 2>/dev/null | grep -v -- '-cert.pub$' | head -n 1)"
|
||||
DEFAULT_PUB_ID_FILE="${most_recent_id:+$HOME/}$most_recent_id"
|
||||
|
||||
usage () {
|
||||
printf 'Usage: %s [-h|-?|-f|-n] [-i [identity_file]] [-p port] [[-o <ssh -o options>] ...] [user@]hostname\n' "$0" >&2
|
||||
@ -74,6 +75,11 @@ quote() {
|
||||
use_id_file() {
|
||||
local L_ID_FILE="$1"
|
||||
|
||||
if [ -z "$L_ID_FILE" ] ; then
|
||||
printf "%s: ERROR: no ID file found\n" "$0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if expr "$L_ID_FILE" : ".*\.pub$" >/dev/null ; then
|
||||
PUB_ID_FILE="$L_ID_FILE"
|
||||
else
|
||||
@ -287,9 +293,10 @@ case "$REMOTE_VERSION" in
|
||||
*)
|
||||
# Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect
|
||||
populate_new_ids 0
|
||||
# in ssh below - to defend against quirky remote shells: use 'exec sh -c' to get POSIX; 'cd' to be at $HOME; and all on one line, because tcsh.
|
||||
# in ssh below - to defend against quirky remote shells: use 'exec sh -c' to get POSIX;
|
||||
# 'cd' to be at $HOME; add a newline if it's missing; and all on one line, because tcsh.
|
||||
[ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | \
|
||||
ssh "$@" "exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi'" \
|
||||
ssh "$@" "exec sh -c 'cd ; umask 077 ; mkdir -p .ssh && { [ -z "'`tail -1c .ssh/authorized_keys 2>/dev/null`'" ] || echo >> .ssh/authorized_keys ; } && cat >> .ssh/authorized_keys || exit 1 ; if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi'" \
|
||||
|| exit 1
|
||||
ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l)
|
||||
;;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
|
||||
Name: openssh
|
||||
Version: 7.5p1
|
||||
Version: 7.6p1
|
||||
URL: https://www.openssh.com/
|
||||
Release: 1
|
||||
Source0: openssh-%{version}.tar.gz
|
||||
|
165
deattack.c
165
deattack.c
@ -1,165 +0,0 @@
|
||||
/* $OpenBSD: deattack.c,v 1.32 2015/01/20 23:14:00 deraadt Exp $ */
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - source code
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "deattack.h"
|
||||
#include "crc32.h"
|
||||
#include "sshbuf.h"
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
* CRC attack detection has a worst-case behaviour that is O(N^3) over
|
||||
* the number of identical blocks in a packet. This behaviour can be
|
||||
* exploited to create a limited denial of service attack.
|
||||
*
|
||||
* However, because we are dealing with encrypted data, identical
|
||||
* blocks should only occur every 2^35 maximally-sized packets or so.
|
||||
* Consequently, we can detect this DoS by looking for identical blocks
|
||||
* in a packet.
|
||||
*
|
||||
* The parameter below determines how many identical blocks we will
|
||||
* accept in a single packet, trading off between attack detection and
|
||||
* likelihood of terminating a legitimate connection. A value of 32
|
||||
* corresponds to an average of 2^40 messages before an attack is
|
||||
* misdetected
|
||||
*/
|
||||
#define MAX_IDENTICAL 32
|
||||
|
||||
/* SSH Constants */
|
||||
#define SSH_MAXBLOCKS (32 * 1024)
|
||||
#define SSH_BLOCKSIZE (8)
|
||||
|
||||
/* Hashing constants */
|
||||
#define HASH_MINSIZE (8 * 1024)
|
||||
#define HASH_ENTRYSIZE (2)
|
||||
#define HASH_FACTOR(x) ((x)*3/2)
|
||||
#define HASH_UNUSEDCHAR (0xff)
|
||||
#define HASH_UNUSED (0xffff)
|
||||
#define HASH_IV (0xfffe)
|
||||
|
||||
#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE)
|
||||
|
||||
|
||||
/* Hash function (Input keys are cipher results) */
|
||||
#define HASH(x) PEEK_U32(x)
|
||||
|
||||
#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE))
|
||||
|
||||
static void
|
||||
crc_update(u_int32_t *a, u_int32_t b)
|
||||
{
|
||||
b ^= *a;
|
||||
*a = ssh_crc32((u_char *)&b, sizeof(b));
|
||||
}
|
||||
|
||||
/* detect if a block is used in a particular pattern */
|
||||
static int
|
||||
check_crc(const u_char *S, const u_char *buf, u_int32_t len)
|
||||
{
|
||||
u_int32_t crc;
|
||||
const u_char *c;
|
||||
|
||||
crc = 0;
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
if (!CMP(S, c)) {
|
||||
crc_update(&crc, 1);
|
||||
crc_update(&crc, 0);
|
||||
} else {
|
||||
crc_update(&crc, 0);
|
||||
crc_update(&crc, 0);
|
||||
}
|
||||
}
|
||||
return crc == 0;
|
||||
}
|
||||
|
||||
void
|
||||
deattack_init(struct deattack_ctx *dctx)
|
||||
{
|
||||
bzero(dctx, sizeof(*dctx));
|
||||
dctx->n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
}
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
int
|
||||
detect_attack(struct deattack_ctx *dctx, const u_char *buf, u_int32_t len)
|
||||
{
|
||||
u_int32_t i, j, l, same;
|
||||
u_int16_t *tmp;
|
||||
const u_char *c, *d;
|
||||
|
||||
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0)
|
||||
return DEATTACK_ERROR;
|
||||
for (l = dctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (dctx->h == NULL) {
|
||||
if ((dctx->h = calloc(l, HASH_ENTRYSIZE)) == NULL)
|
||||
return DEATTACK_ERROR;
|
||||
dctx->n = l;
|
||||
} else {
|
||||
if (l > dctx->n) {
|
||||
if ((tmp = reallocarray(dctx->h, l, HASH_ENTRYSIZE))
|
||||
== NULL) {
|
||||
free(dctx->h);
|
||||
dctx->h = NULL;
|
||||
return DEATTACK_ERROR;
|
||||
}
|
||||
dctx->h = tmp;
|
||||
dctx->n = l;
|
||||
}
|
||||
}
|
||||
|
||||
if (len <= HASH_MINBLOCKS) {
|
||||
for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) {
|
||||
for (d = buf; d < c; d += SSH_BLOCKSIZE) {
|
||||
if (!CMP(c, d)) {
|
||||
if ((check_crc(c, buf, len)))
|
||||
return DEATTACK_DETECTED;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DEATTACK_OK;
|
||||
}
|
||||
memset(dctx->h, HASH_UNUSEDCHAR, dctx->n * HASH_ENTRYSIZE);
|
||||
|
||||
for (c = buf, same = j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) {
|
||||
for (i = HASH(c) & (dctx->n - 1); dctx->h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (dctx->n - 1)) {
|
||||
if (!CMP(c, buf + dctx->h[i] * SSH_BLOCKSIZE)) {
|
||||
if (++same > MAX_IDENTICAL)
|
||||
return DEATTACK_DOS_DETECTED;
|
||||
if (check_crc(c, buf, len))
|
||||
return DEATTACK_DETECTED;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
dctx->h[i] = j;
|
||||
}
|
||||
return DEATTACK_OK;
|
||||
}
|
38
deattack.h
38
deattack.h
@ -1,38 +0,0 @@
|
||||
/* $OpenBSD: deattack.h,v 1.11 2015/01/19 19:52:16 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Cryptographic attack detector for ssh - Header file
|
||||
*
|
||||
* Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina.
|
||||
*
|
||||
* All rights reserved. Redistribution and use in source and binary
|
||||
* forms, with or without modification, are permitted provided that
|
||||
* this copyright notice is retained.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR
|
||||
* CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Ariel Futoransky <futo@core-sdi.com>
|
||||
* <http://www.core-sdi.com>
|
||||
*/
|
||||
|
||||
#ifndef _DEATTACK_H
|
||||
#define _DEATTACK_H
|
||||
|
||||
/* Return codes */
|
||||
#define DEATTACK_OK 0
|
||||
#define DEATTACK_DETECTED 1
|
||||
#define DEATTACK_DOS_DETECTED 2
|
||||
#define DEATTACK_ERROR 3
|
||||
|
||||
struct deattack_ctx {
|
||||
u_int16_t *h;
|
||||
u_int32_t n;
|
||||
};
|
||||
|
||||
void deattack_init(struct deattack_ctx *);
|
||||
int detect_attack(struct deattack_ctx *, const u_char *, u_int32_t);
|
||||
#endif
|
29
defines.h
29
defines.h
@ -328,6 +328,28 @@ typedef unsigned int size_t;
|
||||
#define SIZE_MAX SIZE_T_MAX
|
||||
#endif
|
||||
|
||||
#ifndef INT32_MAX
|
||||
# if (SIZEOF_INT == 4)
|
||||
# define INT32_MAX INT_MAX
|
||||
# elif (SIZEOF_LONG == 4)
|
||||
# define INT32_MAX LONG_MAX
|
||||
# else
|
||||
# error "need INT32_MAX"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef INT64_MAX
|
||||
# if (SIZEOF_INT == 8)
|
||||
# define INT64_MAX INT_MAX
|
||||
# elif (SIZEOF_LONG == 8)
|
||||
# define INT64_MAX LONG_MAX
|
||||
# elif (SIZEOF_LONG_LONG_INT == 8)
|
||||
# define INT64_MAX LLONG_MAX
|
||||
# else
|
||||
# error "need INT64_MAX"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SSIZE_T
|
||||
typedef int ssize_t;
|
||||
# define HAVE_SSIZE_T
|
||||
@ -497,6 +519,13 @@ struct winsize {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef timespeccmp
|
||||
#define timespeccmp(tsp, usp, cmp) \
|
||||
(((tsp)->tv_sec == (usp)->tv_sec) ? \
|
||||
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
|
||||
((tsp)->tv_sec cmp (usp)->tv_sec))
|
||||
#endif
|
||||
|
||||
#ifndef __P
|
||||
# define __P(x) x
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: digest-libc.c,v 1.5 2015/05/05 02:48:17 jsg Exp $ */
|
||||
/* $OpenBSD: digest-libc.c,v 1.6 2017/05/08 22:57:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
|
||||
* Copyright (c) 2014 Markus Friedl. All rights reserved.
|
||||
@ -68,16 +68,6 @@ const struct ssh_digest digests[SSH_DIGEST_MAX] = {
|
||||
(md_update_fn *) MD5Update,
|
||||
(md_final_fn *) MD5Final
|
||||
},
|
||||
{
|
||||
SSH_DIGEST_RIPEMD160,
|
||||
"RIPEMD160",
|
||||
RMD160_BLOCK_LENGTH,
|
||||
RMD160_DIGEST_LENGTH,
|
||||
sizeof(RMD160_CTX),
|
||||
(md_init_fn *) RMD160Init,
|
||||
(md_update_fn *) RMD160Update,
|
||||
(md_final_fn *) RMD160Final
|
||||
},
|
||||
{
|
||||
SSH_DIGEST_SHA1,
|
||||
"SHA1",
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: digest-openssl.c,v 1.6 2017/03/10 02:59:51 dtucker Exp $ */
|
||||
/* $OpenBSD: digest-openssl.c,v 1.7 2017/05/08 22:57:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
@ -56,7 +56,6 @@ struct ssh_digest {
|
||||
/* NB. Indexed directly by algorithm number */
|
||||
const struct ssh_digest digests[] = {
|
||||
{ SSH_DIGEST_MD5, "MD5", 16, EVP_md5 },
|
||||
{ SSH_DIGEST_RIPEMD160, "RIPEMD160", 20, EVP_ripemd160 },
|
||||
{ SSH_DIGEST_SHA1, "SHA1", 20, EVP_sha1 },
|
||||
{ SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 },
|
||||
{ SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 },
|
||||
|
13
digest.h
13
digest.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: digest.h,v 1.7 2014/12/21 22:27:56 djm Exp $ */
|
||||
/* $OpenBSD: digest.h,v 1.8 2017/05/08 22:57:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2013 Damien Miller <djm@mindrot.org>
|
||||
*
|
||||
@ -23,12 +23,11 @@
|
||||
|
||||
/* Digest algorithms */
|
||||
#define SSH_DIGEST_MD5 0
|
||||
#define SSH_DIGEST_RIPEMD160 1
|
||||
#define SSH_DIGEST_SHA1 2
|
||||
#define SSH_DIGEST_SHA256 3
|
||||
#define SSH_DIGEST_SHA384 4
|
||||
#define SSH_DIGEST_SHA512 5
|
||||
#define SSH_DIGEST_MAX 6
|
||||
#define SSH_DIGEST_SHA1 1
|
||||
#define SSH_DIGEST_SHA256 2
|
||||
#define SSH_DIGEST_SHA384 3
|
||||
#define SSH_DIGEST_SHA512 4
|
||||
#define SSH_DIGEST_MAX 5
|
||||
|
||||
struct sshbuf;
|
||||
struct ssh_digest_ctx;
|
||||
|
21
dispatch.c
21
dispatch.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dispatch.c,v 1.27 2015/05/01 07:10:01 djm Exp $ */
|
||||
/* $OpenBSD: dispatch.c,v 1.31 2017/05/31 07:00:13 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -30,7 +30,6 @@
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "ssh1.h"
|
||||
#include "ssh2.h"
|
||||
#include "log.h"
|
||||
#include "dispatch.h"
|
||||
@ -39,14 +38,11 @@
|
||||
#include "ssherr.h"
|
||||
|
||||
int
|
||||
dispatch_protocol_error(int type, u_int32_t seq, void *ctx)
|
||||
dispatch_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
int r;
|
||||
|
||||
logit("dispatch_protocol_error: type %d seq %u", type, seq);
|
||||
if (!compat20)
|
||||
fatal("protocol error");
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0 ||
|
||||
@ -56,7 +52,7 @@ dispatch_protocol_error(int type, u_int32_t seq, void *ctx)
|
||||
}
|
||||
|
||||
int
|
||||
dispatch_protocol_ignore(int type, u_int32_t seq, void *ssh)
|
||||
dispatch_protocol_ignore(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
logit("dispatch_protocol_ignore: type %d seq %u", type, seq);
|
||||
return 0;
|
||||
@ -89,8 +85,7 @@ ssh_dispatch_set(struct ssh *ssh, int type, dispatch_fn *fn)
|
||||
}
|
||||
|
||||
int
|
||||
ssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
|
||||
void *ctxt)
|
||||
ssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done)
|
||||
{
|
||||
int r;
|
||||
u_char type;
|
||||
@ -115,8 +110,7 @@ ssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
|
||||
ssh->dispatch_skip_packets--;
|
||||
continue;
|
||||
}
|
||||
/* XXX 'ssh' will replace 'ctxt' later */
|
||||
r = (*ssh->dispatch[type])(type, seqnr, ctxt);
|
||||
r = (*ssh->dispatch[type])(type, seqnr, ssh);
|
||||
if (r != 0)
|
||||
return r;
|
||||
} else {
|
||||
@ -132,11 +126,10 @@ ssh_dispatch_run(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
|
||||
}
|
||||
|
||||
void
|
||||
ssh_dispatch_run_fatal(struct ssh *ssh, int mode, volatile sig_atomic_t *done,
|
||||
void *ctxt)
|
||||
ssh_dispatch_run_fatal(struct ssh *ssh, int mode, volatile sig_atomic_t *done)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = ssh_dispatch_run(ssh, mode, done, ctxt)) != 0)
|
||||
if ((r = ssh_dispatch_run(ssh, mode, done)) != 0)
|
||||
sshpkt_fatal(ssh, __func__, r);
|
||||
}
|
||||
|
14
dispatch.h
14
dispatch.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dispatch.h,v 1.12 2015/01/19 20:07:45 markus Exp $ */
|
||||
/* $OpenBSD: dispatch.h,v 1.14 2017/05/31 07:00:13 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
@ -36,15 +36,15 @@ enum {
|
||||
|
||||
struct ssh;
|
||||
|
||||
typedef int dispatch_fn(int, u_int32_t, void *);
|
||||
typedef int dispatch_fn(int, u_int32_t, struct ssh *);
|
||||
|
||||
int dispatch_protocol_error(int, u_int32_t, void *);
|
||||
int dispatch_protocol_ignore(int, u_int32_t, void *);
|
||||
int dispatch_protocol_error(int, u_int32_t, struct ssh *);
|
||||
int dispatch_protocol_ignore(int, u_int32_t, struct ssh *);
|
||||
void ssh_dispatch_init(struct ssh *, dispatch_fn *);
|
||||
void ssh_dispatch_set(struct ssh *, int, dispatch_fn *);
|
||||
void ssh_dispatch_range(struct ssh *, u_int, u_int, dispatch_fn *);
|
||||
int ssh_dispatch_run(struct ssh *, int, volatile sig_atomic_t *, void *);
|
||||
void ssh_dispatch_run_fatal(struct ssh *, int, volatile sig_atomic_t *, void *);
|
||||
int ssh_dispatch_run(struct ssh *, int, volatile sig_atomic_t *);
|
||||
void ssh_dispatch_run_fatal(struct ssh *, int, volatile sig_atomic_t *);
|
||||
|
||||
#define dispatch_init(dflt) \
|
||||
ssh_dispatch_init(active_state, (dflt))
|
||||
@ -52,7 +52,5 @@ void ssh_dispatch_run_fatal(struct ssh *, int, volatile sig_atomic_t *, void *);
|
||||
ssh_dispatch_range(active_state, (from), (to), (fn))
|
||||
#define dispatch_set(type, fn) \
|
||||
ssh_dispatch_set(active_state, (type), (fn))
|
||||
#define dispatch_run(mode, done, ctxt) \
|
||||
ssh_dispatch_run_fatal(active_state, (mode), (done), (ctxt))
|
||||
|
||||
#endif
|
||||
|
2
dns.c
2
dns.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dns.c,v 1.35 2015/08/20 22:32:42 deraadt Exp $ */
|
||||
/* $OpenBSD: dns.c,v 1.37 2017/09/14 04:32:21 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
||||
|
2
dns.h
2
dns.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dns.h,v 1.15 2015/05/08 06:45:13 djm Exp $ */
|
||||
/* $OpenBSD: dns.h,v 1.17 2017/09/14 04:32:21 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
|
||||
|
11
gss-serv.c
11
gss-serv.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 djm Exp $ */
|
||||
/* $OpenBSD: gss-serv.c,v 1.30 2017/06/24 06:34:38 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
|
||||
@ -393,4 +393,13 @@ ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
|
||||
return (ctx->major);
|
||||
}
|
||||
|
||||
/* Privileged */
|
||||
const char *ssh_gssapi_displayname(void)
|
||||
{
|
||||
if (gssapi_client.displayname.length == 0 ||
|
||||
gssapi_client.displayname.value == NULL)
|
||||
return NULL;
|
||||
return (char *)gssapi_client.displayname.value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
33
hostfile.c
33
hostfile.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: hostfile.c,v 1.68 2017/03/10 04:26:06 djm Exp $ */
|
||||
/* $OpenBSD: hostfile.c,v 1.71 2017/05/31 09:15:42 deraadt Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -251,7 +251,7 @@ record_hostkey(struct hostkey_foreach_line *l, void *_ctx)
|
||||
l->marker == MRK_NONE ? "" :
|
||||
(l->marker == MRK_CA ? "ca " : "revoked "),
|
||||
sshkey_type(l->key), l->path, l->linenum);
|
||||
if ((tmp = reallocarray(hostkeys->entries,
|
||||
if ((tmp = recallocarray(hostkeys->entries, hostkeys->num_entries,
|
||||
hostkeys->num_entries + 1, sizeof(*hostkeys->entries))) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
hostkeys->entries = tmp;
|
||||
@ -346,16 +346,11 @@ check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
|
||||
HostStatus end_return = HOST_NEW;
|
||||
int want_cert = sshkey_is_cert(k);
|
||||
HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
|
||||
int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2;
|
||||
|
||||
if (found != NULL)
|
||||
*found = NULL;
|
||||
|
||||
for (i = 0; i < hostkeys->num_entries; i++) {
|
||||
if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1)
|
||||
continue;
|
||||
if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1)
|
||||
continue;
|
||||
if (hostkeys->entries[i].marker != want_marker)
|
||||
continue;
|
||||
if (k == NULL) {
|
||||
@ -490,13 +485,6 @@ host_delete(struct hostkey_foreach_line *l, void *_ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX might need a knob for this later */
|
||||
/* Don't remove RSA1 keys */
|
||||
if (l->key->type == KEY_RSA1) {
|
||||
fprintf(ctx->out, "%s\n", l->line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this line contains one of the keys that we will be
|
||||
* adding later, then don't change it and mark the key for
|
||||
@ -789,20 +777,7 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
|
||||
break;
|
||||
}
|
||||
if (!hostfile_read_key(&cp, &kbits, lineinfo.key)) {
|
||||
#ifdef WITH_SSH1
|
||||
sshkey_free(lineinfo.key);
|
||||
lineinfo.key = sshkey_new(KEY_RSA1);
|
||||
if (lineinfo.key == NULL) {
|
||||
error("%s: sshkey_new fail", __func__);
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
break;
|
||||
}
|
||||
if (!hostfile_read_key(&cp, &kbits,
|
||||
lineinfo.key))
|
||||
goto bad;
|
||||
#else
|
||||
goto bad;
|
||||
#endif
|
||||
}
|
||||
lineinfo.keytype = lineinfo.key->type;
|
||||
lineinfo.comment = cp;
|
||||
@ -817,12 +792,12 @@ hostkeys_foreach(const char *path, hostkeys_foreach_fn *callback, void *ctx,
|
||||
lineinfo.keytype = sshkey_type_from_name(ktype);
|
||||
|
||||
/*
|
||||
* Assume RSA1 if the first component is a short
|
||||
* Assume legacy RSA1 if the first component is a short
|
||||
* decimal number.
|
||||
*/
|
||||
if (lineinfo.keytype == KEY_UNSPEC && l < 8 &&
|
||||
strspn(ktype, "0123456789") == l)
|
||||
lineinfo.keytype = KEY_RSA1;
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Check that something other than whitespace follows
|
||||
|
@ -93,6 +93,9 @@
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h> /* For MIN, MAX, etc */
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h> /* for timespeccmp if present */
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h> /* for MAP_ANONYMOUS */
|
||||
#endif
|
||||
|
81
kex.c
81
kex.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kex.c,v 1.131 2017/03/15 07:07:39 markus Exp $ */
|
||||
/* $OpenBSD: kex.c,v 1.134 2017/06/13 12:13:59 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -54,17 +54,9 @@
|
||||
#include "sshbuf.h"
|
||||
#include "digest.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||
# if defined(HAVE_EVP_SHA256)
|
||||
# define evp_ssh_sha256 EVP_sha256
|
||||
# else
|
||||
extern const EVP_MD *evp_ssh_sha256(void);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* prototype */
|
||||
static int kex_choose_conf(struct ssh *);
|
||||
static int kex_input_newkeys(int, u_int32_t, void *);
|
||||
static int kex_input_newkeys(int, u_int32_t, struct ssh *);
|
||||
|
||||
static const char *proposal_names[PROPOSAL_MAX] = {
|
||||
"KEX algorithms",
|
||||
@ -323,9 +315,8 @@ kex_prop_free(char **proposal)
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
kex_protocol_error(int type, u_int32_t seq, void *ctxt)
|
||||
kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
int r;
|
||||
|
||||
error("kex protocol error: type %d seq %u", type, seq);
|
||||
@ -383,12 +374,13 @@ kex_send_newkeys(struct ssh *ssh)
|
||||
}
|
||||
|
||||
int
|
||||
kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
|
||||
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
u_int32_t i, ninfo;
|
||||
char *name, *val, *found;
|
||||
char *name, *found;
|
||||
u_char *val;
|
||||
size_t vlen;
|
||||
int r;
|
||||
|
||||
debug("SSH2_MSG_EXT_INFO received");
|
||||
@ -398,12 +390,17 @@ kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
|
||||
return r;
|
||||
if ((r = sshpkt_get_cstring(ssh, &val, NULL)) != 0) {
|
||||
if ((r = sshpkt_get_string(ssh, &val, &vlen)) != 0) {
|
||||
free(name);
|
||||
return r;
|
||||
}
|
||||
debug("%s: %s=<%s>", __func__, name, val);
|
||||
if (strcmp(name, "server-sig-algs") == 0) {
|
||||
/* Ensure no \0 lurking in value */
|
||||
if (memchr(val, '\0', vlen) != NULL) {
|
||||
error("%s: nul byte in %s", __func__, name);
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
}
|
||||
debug("%s: %s=<%s>", __func__, name, val);
|
||||
found = match_list("rsa-sha2-256", val, NULL);
|
||||
if (found) {
|
||||
kex->rsa_sha2 = 256;
|
||||
@ -414,7 +411,8 @@ kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
|
||||
kex->rsa_sha2 = 512;
|
||||
free(found);
|
||||
}
|
||||
}
|
||||
} else
|
||||
debug("%s: %s (unrecognised)", __func__, name);
|
||||
free(name);
|
||||
free(val);
|
||||
}
|
||||
@ -422,9 +420,8 @@ kex_input_ext_info(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
kex_input_newkeys(int type, u_int32_t seq, void *ctxt)
|
||||
kex_input_newkeys(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
int r;
|
||||
|
||||
@ -475,9 +472,8 @@ kex_send_kexinit(struct ssh *ssh)
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
|
||||
kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
const u_char *ptr;
|
||||
u_int i;
|
||||
@ -988,47 +984,6 @@ kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
int
|
||||
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
|
||||
u_int8_t cookie[8], u_int8_t id[16])
|
||||
{
|
||||
u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
|
||||
struct ssh_digest_ctx *hashctx = NULL;
|
||||
size_t hlen, slen;
|
||||
int r;
|
||||
|
||||
hlen = BN_num_bytes(host_modulus);
|
||||
slen = BN_num_bytes(server_modulus);
|
||||
if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
|
||||
slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
|
||||
return SSH_ERR_KEY_BITS_MISMATCH;
|
||||
if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
|
||||
BN_bn2bin(server_modulus, sbuf) <= 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
|
||||
ssh_digest_update(hashctx, sbuf, slen) != 0 ||
|
||||
ssh_digest_update(hashctx, cookie, 8) != 0 ||
|
||||
ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
|
||||
r = 0;
|
||||
out:
|
||||
ssh_digest_free(hashctx);
|
||||
explicit_bzero(hbuf, sizeof(hbuf));
|
||||
explicit_bzero(sbuf, sizeof(sbuf));
|
||||
explicit_bzero(obuf, sizeof(obuf));
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
|
||||
void
|
||||
|
9
kex.h
9
kex.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kex.h,v 1.81 2016/09/28 21:44:52 djm Exp $ */
|
||||
/* $OpenBSD: kex.h,v 1.83 2017/05/30 14:23:52 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -181,8 +181,8 @@ int kex_prop2buf(struct sshbuf *, char *proposal[PROPOSAL_MAX]);
|
||||
void kex_prop_free(char **);
|
||||
|
||||
int kex_send_kexinit(struct ssh *);
|
||||
int kex_input_kexinit(int, u_int32_t, void *);
|
||||
int kex_input_ext_info(int, u_int32_t, void *);
|
||||
int kex_input_kexinit(int, u_int32_t, struct ssh *);
|
||||
int kex_input_ext_info(int, u_int32_t, struct ssh *);
|
||||
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
|
||||
int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *);
|
||||
int kex_send_newkeys(struct ssh *);
|
||||
@ -225,9 +225,6 @@ int kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
|
||||
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
|
||||
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
|
||||
|
||||
int
|
||||
derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
|
||||
|
||||
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)
|
||||
void dump_digest(char *, u_char *, int);
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexc25519c.c,v 1.7 2015/01/26 06:10:03 djm Exp $ */
|
||||
/* $OpenBSD: kexc25519c.c,v 1.8 2017/05/31 04:17:12 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2010 Damien Miller. All rights reserved.
|
||||
@ -44,7 +44,7 @@
|
||||
#include "ssherr.h"
|
||||
|
||||
static int
|
||||
input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt);
|
||||
input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh);
|
||||
|
||||
int
|
||||
kexc25519_client(struct ssh *ssh)
|
||||
@ -69,9 +69,8 @@ kexc25519_client(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
struct sshkey *server_host_key = NULL;
|
||||
struct sshbuf *shared_secret = NULL;
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include "sshbuf.h"
|
||||
#include "ssherr.h"
|
||||
|
||||
static int input_kex_c25519_init(int, u_int32_t, void *);
|
||||
static int input_kex_c25519_init(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexc25519_server(struct ssh *ssh)
|
||||
@ -52,9 +52,8 @@ kexc25519_server(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_c25519_init(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
struct sshkey *server_host_private, *server_host_public;
|
||||
struct sshbuf *shared_secret = NULL;
|
||||
|
7
kexdhc.c
7
kexdhc.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexdhc.c,v 1.19 2016/05/02 10:26:04 djm Exp $ */
|
||||
/* $OpenBSD: kexdhc.c,v 1.20 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -49,7 +49,7 @@
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
static int input_kex_dh(int, u_int32_t, void *);
|
||||
static int input_kex_dh(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexdh_client(struct ssh *ssh)
|
||||
@ -100,9 +100,8 @@ kexdh_client(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
|
||||
struct sshkey *server_host_key = NULL;
|
||||
|
7
kexdhs.c
7
kexdhs.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexdhs.c,v 1.24 2016/05/02 10:26:04 djm Exp $ */
|
||||
/* $OpenBSD: kexdhs.c,v 1.25 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -49,7 +49,7 @@
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
static int input_kex_dh_init(int, u_int32_t, void *);
|
||||
static int input_kex_dh_init(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexdh_server(struct ssh *ssh)
|
||||
@ -91,9 +91,8 @@ kexdh_server(struct ssh *ssh)
|
||||
}
|
||||
|
||||
int
|
||||
input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
|
||||
struct sshkey *server_host_public, *server_host_private;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexecdhc.c,v 1.10 2015/01/26 06:10:03 djm Exp $ */
|
||||
/* $OpenBSD: kexecdhc.c,v 1.11 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2010 Damien Miller. All rights reserved.
|
||||
@ -49,7 +49,7 @@
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
static int input_kex_ecdh_reply(int, u_int32_t, void *);
|
||||
static int input_kex_ecdh_reply(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexecdh_client(struct ssh *ssh)
|
||||
@ -95,9 +95,8 @@ kexecdh_client(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_ecdh_reply(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
const EC_GROUP *group;
|
||||
EC_POINT *server_public = NULL;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexecdhs.c,v 1.15 2015/12/04 16:41:28 markus Exp $ */
|
||||
/* $OpenBSD: kexecdhs.c,v 1.16 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2010 Damien Miller. All rights reserved.
|
||||
@ -47,7 +47,7 @@
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
|
||||
static int input_kex_ecdh_init(int, u_int32_t, void *);
|
||||
static int input_kex_ecdh_init(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexecdh_server(struct ssh *ssh)
|
||||
@ -58,9 +58,8 @@ kexecdh_server(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_ecdh_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
EC_POINT *client_public;
|
||||
EC_KEY *server_key = NULL;
|
||||
|
16
kexgexc.c
16
kexgexc.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexgexc.c,v 1.23 2016/09/12 01:22:38 deraadt Exp $ */
|
||||
/* $OpenBSD: kexgexc.c,v 1.25 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Niels Provos. All rights reserved.
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
@ -51,8 +51,8 @@
|
||||
#include "sshbuf.h"
|
||||
#include "misc.h"
|
||||
|
||||
static int input_kex_dh_gex_group(int, u_int32_t, void *);
|
||||
static int input_kex_dh_gex_reply(int, u_int32_t, void *);
|
||||
static int input_kex_dh_gex_group(int, u_int32_t, struct ssh *);
|
||||
static int input_kex_dh_gex_reply(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexgex_client(struct ssh *ssh)
|
||||
@ -89,9 +89,8 @@ kexgex_client(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *p = NULL, *g = NULL;
|
||||
int r, bits;
|
||||
@ -143,9 +142,8 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
|
||||
struct sshkey *server_host_key = NULL;
|
||||
@ -165,10 +163,6 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
goto out;
|
||||
if (server_host_key->type != kex->hostkey_type) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
if (server_host_key->type != kex->hostkey_type ||
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
|
12
kexgexs.c
12
kexgexs.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: kexgexs.c,v 1.30 2016/09/12 01:22:38 deraadt Exp $ */
|
||||
/* $OpenBSD: kexgexs.c,v 1.31 2017/05/30 14:23:52 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Niels Provos. All rights reserved.
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
@ -54,8 +54,8 @@
|
||||
#include "sshbuf.h"
|
||||
#include "misc.h"
|
||||
|
||||
static int input_kex_dh_gex_request(int, u_int32_t, void *);
|
||||
static int input_kex_dh_gex_init(int, u_int32_t, void *);
|
||||
static int input_kex_dh_gex_request(int, u_int32_t, struct ssh *);
|
||||
static int input_kex_dh_gex_init(int, u_int32_t, struct ssh *);
|
||||
|
||||
int
|
||||
kexgex_server(struct ssh *ssh)
|
||||
@ -67,9 +67,8 @@ kexgex_server(struct ssh *ssh)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
int r;
|
||||
u_int min = 0, max = 0, nbits = 0;
|
||||
@ -120,9 +119,8 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
|
||||
input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
|
||||
struct sshkey *server_host_public, *server_host_private;
|
||||
|
177
key.c
177
key.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: key.c,v 1.130 2016/05/02 09:36:42 djm Exp $ */
|
||||
/* $OpenBSD: key.c,v 1.131 2017/05/30 14:16:41 markus Exp $ */
|
||||
/*
|
||||
* placed in the public domain
|
||||
*/
|
||||
@ -20,68 +20,6 @@
|
||||
#include "log.h"
|
||||
#include "authfile.h"
|
||||
|
||||
void
|
||||
key_add_private(Key *k)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_add_private(k)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
Key *
|
||||
key_new_private(int type)
|
||||
{
|
||||
Key *ret = NULL;
|
||||
|
||||
if ((ret = sshkey_new_private(type)) == NULL)
|
||||
fatal("%s: failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
key_read(Key *ret, char **cpp)
|
||||
{
|
||||
return sshkey_read(ret, cpp) == 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
key_write(const Key *key, FILE *f)
|
||||
{
|
||||
return sshkey_write(key, f) == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
Key *
|
||||
key_generate(int type, u_int bits)
|
||||
{
|
||||
int r;
|
||||
Key *ret = NULL;
|
||||
|
||||
if ((r = sshkey_generate(type, bits, &ret)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
key_cert_copy(const Key *from_key, Key *to_key)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_cert_copy(from_key, to_key)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
Key *
|
||||
key_from_private(const Key *k)
|
||||
{
|
||||
int r;
|
||||
Key *ret = NULL;
|
||||
|
||||
if ((r = sshkey_from_private(k, &ret)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
fatal_on_fatal_errors(int r, const char *func, int extra_fatal)
|
||||
{
|
||||
@ -183,19 +121,6 @@ key_demote(const Key *k)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
key_to_certified(Key *k)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_to_certified(k)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, 0);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
key_drop_cert(Key *k)
|
||||
{
|
||||
@ -209,19 +134,6 @@ key_drop_cert(Key *k)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
key_certify(Key *k, Key *ca)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_certify(k, ca, NULL)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, 0);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
key_cert_check_authority(const Key *k, int want_host, int require_principal,
|
||||
const char *name, const char **reason)
|
||||
@ -237,88 +149,8 @@ key_cert_check_authority(const Key *k, int want_host, int require_principal,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
|
||||
int
|
||||
key_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_ec_validate_public(group, public)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
key_ec_validate_private(const EC_KEY *key)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_ec_validate_private(key)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
||||
void
|
||||
key_private_serialize(const Key *key, struct sshbuf *b)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_private_serialize(key, b)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
Key *
|
||||
key_private_deserialize(struct sshbuf *blob)
|
||||
{
|
||||
int r;
|
||||
Key *ret = NULL;
|
||||
|
||||
if ((r = sshkey_private_deserialize(blob, &ret)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* authfile.c */
|
||||
|
||||
int
|
||||
key_save_private(Key *key, const char *filename, const char *passphrase,
|
||||
const char *comment, int force_new_format, const char *new_format_cipher,
|
||||
int new_format_rounds)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_save_private(key, filename, passphrase, comment,
|
||||
force_new_format, new_format_cipher, new_format_rounds)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
key_load_file(int fd, const char *filename, struct sshbuf *blob)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshkey_load_file(fd, blob)) != 0) {
|
||||
fatal_on_fatal_errors(r, __func__, SSH_ERR_LIBCRYPTO_ERROR);
|
||||
error("%s: %s", __func__, ssh_err(r));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
Key *
|
||||
key_load_cert(const char *filename)
|
||||
{
|
||||
@ -417,10 +249,3 @@ key_load_private_type(int type, const char *filename, const char *passphrase,
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
key_perm_ok(int fd, const char *filename)
|
||||
{
|
||||
return sshkey_perm_ok(fd, filename) == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
|
36
key.h
36
key.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: key.h,v 1.50 2016/09/12 23:31:27 djm Exp $ */
|
||||
/* $OpenBSD: key.h,v 1.51 2017/05/30 14:16:41 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -35,51 +35,24 @@ typedef struct sshkey Key;
|
||||
#define fp_rep sshkey_fp_rep
|
||||
|
||||
#ifndef SSH_KEY_NO_DEFINE
|
||||
#define key_new sshkey_new
|
||||
#define key_free sshkey_free
|
||||
#define key_equal_public sshkey_equal_public
|
||||
#define key_equal sshkey_equal
|
||||
#define key_type sshkey_type
|
||||
#define key_cert_type sshkey_cert_type
|
||||
#define key_ssh_name sshkey_ssh_name
|
||||
#define key_ssh_name_plain sshkey_ssh_name_plain
|
||||
#define key_type_from_name sshkey_type_from_name
|
||||
#define key_ecdsa_nid_from_name sshkey_ecdsa_nid_from_name
|
||||
#define key_type_is_cert sshkey_type_is_cert
|
||||
#define key_size sshkey_size
|
||||
#define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid
|
||||
#define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid
|
||||
#define key_is_cert sshkey_is_cert
|
||||
#define key_type_plain sshkey_type_plain
|
||||
#define key_curve_name_to_nid sshkey_curve_name_to_nid
|
||||
#define key_curve_nid_to_bits sshkey_curve_nid_to_bits
|
||||
#define key_curve_nid_to_name sshkey_curve_nid_to_name
|
||||
#define key_ec_nid_to_hash_alg sshkey_ec_nid_to_hash_alg
|
||||
#define key_dump_ec_point sshkey_dump_ec_point
|
||||
#define key_dump_ec_key sshkey_dump_ec_key
|
||||
#endif
|
||||
|
||||
void key_add_private(Key *);
|
||||
Key *key_new_private(int);
|
||||
void key_free(Key *);
|
||||
Key *key_demote(const Key *);
|
||||
int key_write(const Key *, FILE *);
|
||||
int key_read(Key *, char **);
|
||||
|
||||
Key *key_generate(int, u_int);
|
||||
Key *key_from_private(const Key *);
|
||||
int key_to_certified(Key *);
|
||||
int key_drop_cert(Key *);
|
||||
int key_certify(Key *, Key *);
|
||||
void key_cert_copy(const Key *, Key *);
|
||||
int key_cert_check_authority(const Key *, int, int, const char *,
|
||||
const char **);
|
||||
|
||||
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
|
||||
int key_ec_validate_public(const EC_GROUP *, const EC_POINT *);
|
||||
int key_ec_validate_private(const EC_KEY *);
|
||||
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
|
||||
|
||||
Key *key_from_blob(const u_char *, u_int);
|
||||
int key_to_blob(const Key *, u_char **, u_int *);
|
||||
|
||||
@ -87,18 +60,11 @@ int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int,
|
||||
const char *);
|
||||
int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int);
|
||||
|
||||
void key_private_serialize(const Key *, struct sshbuf *);
|
||||
Key *key_private_deserialize(struct sshbuf *);
|
||||
|
||||
/* authfile.c */
|
||||
int key_save_private(Key *, const char *, const char *, const char *,
|
||||
int, const char *, int);
|
||||
int key_load_file(int, const char *, struct sshbuf *);
|
||||
Key *key_load_cert(const char *);
|
||||
Key *key_load_public(const char *, char **);
|
||||
Key *key_load_private(const char *, const char *, char **);
|
||||
Key *key_load_private_cert(int, const char *, const char *, int *);
|
||||
Key *key_load_private_type(int, const char *, const char *, char **, int *);
|
||||
int key_perm_ok(int, const char *);
|
||||
|
||||
#endif
|
||||
|
4
krl.c
4
krl.c
@ -14,7 +14,7 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $OpenBSD: krl.c,v 1.39 2017/03/10 07:18:32 dtucker Exp $ */
|
||||
/* $OpenBSD: krl.c,v 1.40 2017/05/31 09:15:42 deraadt Exp $ */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
@ -1026,7 +1026,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
|
||||
}
|
||||
}
|
||||
/* Record keys used to sign the KRL */
|
||||
tmp_ca_used = reallocarray(ca_used, nca_used + 1,
|
||||
tmp_ca_used = recallocarray(ca_used, nca_used, nca_used + 1,
|
||||
sizeof(*ca_used));
|
||||
if (tmp_ca_used == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
|
35
log.c
35
log.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: log.c,v 1.49 2017/03/10 03:15:58 djm Exp $ */
|
||||
/* $OpenBSD: log.c,v 1.50 2017/05/17 01:24:17 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -256,18 +256,7 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
|
||||
argv0 = av0;
|
||||
|
||||
switch (level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG1:
|
||||
case SYSLOG_LEVEL_DEBUG2:
|
||||
case SYSLOG_LEVEL_DEBUG3:
|
||||
log_level = level;
|
||||
break;
|
||||
default:
|
||||
if (log_change_level(level) != 0) {
|
||||
fprintf(stderr, "Unrecognized internal syslog level code %d\n",
|
||||
(int) level);
|
||||
exit(1);
|
||||
@ -340,13 +329,27 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
log_change_level(LogLevel new_log_level)
|
||||
{
|
||||
/* no-op if log_init has not been called */
|
||||
if (argv0 == NULL)
|
||||
return;
|
||||
log_init(argv0, new_log_level, log_facility, log_on_stderr);
|
||||
return 0;
|
||||
|
||||
switch (new_log_level) {
|
||||
case SYSLOG_LEVEL_QUIET:
|
||||
case SYSLOG_LEVEL_FATAL:
|
||||
case SYSLOG_LEVEL_ERROR:
|
||||
case SYSLOG_LEVEL_INFO:
|
||||
case SYSLOG_LEVEL_VERBOSE:
|
||||
case SYSLOG_LEVEL_DEBUG1:
|
||||
case SYSLOG_LEVEL_DEBUG2:
|
||||
case SYSLOG_LEVEL_DEBUG3:
|
||||
log_level = new_log_level;
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
4
log.h
4
log.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: log.h,v 1.21 2016/07/15 05:01:58 dtucker Exp $ */
|
||||
/* $OpenBSD: log.h,v 1.22 2017/05/17 01:24:17 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -49,7 +49,7 @@ typedef enum {
|
||||
typedef void (log_handler_fn)(LogLevel, const char *, void *);
|
||||
|
||||
void log_init(char *, LogLevel, SyslogFacility, int);
|
||||
void log_change_level(LogLevel);
|
||||
int log_change_level(LogLevel);
|
||||
int log_is_on_stderr(void);
|
||||
void log_redirect_stderr_to(const char *);
|
||||
|
||||
|
9
mac.c
9
mac.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: mac.c,v 1.33 2016/07/08 03:44:42 djm Exp $ */
|
||||
/* $OpenBSD: mac.c,v 1.34 2017/05/08 22:57:38 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -64,10 +64,6 @@ static const struct macalg macs[] = {
|
||||
#endif
|
||||
{ "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 },
|
||||
{ "hmac-md5-96", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 0 },
|
||||
#ifdef HAVE_EVP_RIPEMD160
|
||||
{ "hmac-ripemd160", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 0 },
|
||||
{ "hmac-ripemd160@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 0 },
|
||||
#endif
|
||||
{ "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 },
|
||||
{ "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 },
|
||||
|
||||
@ -80,9 +76,6 @@ static const struct macalg macs[] = {
|
||||
#endif
|
||||
{ "hmac-md5-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 1 },
|
||||
{ "hmac-md5-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 1 },
|
||||
#ifdef HAVE_EVP_RIPEMD160
|
||||
{ "hmac-ripemd160-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 1 },
|
||||
#endif
|
||||
{ "umac-64-etm@openssh.com", SSH_UMAC, 0, 0, 128, 64, 1 },
|
||||
{ "umac-128-etm@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 1 },
|
||||
|
||||
|
86
md-sha256.c
86
md-sha256.c
@ -1,86 +0,0 @@
|
||||
/* $OpenBSD: md-sha256.c,v 1.5 2006/08/03 03:34:42 deraadt Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2005 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* EVP wrapper for SHA256 */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if !defined(HAVE_EVP_SHA256) && (OPENSSL_VERSION_NUMBER >= 0x00907000L)
|
||||
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#ifdef HAVE_SHA256_UPDATE
|
||||
# ifdef HAVE_SHA2_H
|
||||
# include <sha2.h>
|
||||
# elif defined(HAVE_CRYPTO_SHA2_H)
|
||||
# include <crypto/sha2.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
const EVP_MD *evp_ssh_sha256(void);
|
||||
|
||||
static int
|
||||
ssh_sha256_init(EVP_MD_CTX *ctxt)
|
||||
{
|
||||
SHA256_Init(ctxt->md_data);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_sha256_update(EVP_MD_CTX *ctxt, const void *data, unsigned long len)
|
||||
{
|
||||
SHA256_Update(ctxt->md_data, data, len);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_sha256_final(EVP_MD_CTX *ctxt, unsigned char *digest)
|
||||
{
|
||||
SHA256_Final(digest, ctxt->md_data);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_sha256_cleanup(EVP_MD_CTX *ctxt)
|
||||
{
|
||||
memset(ctxt->md_data, 0, sizeof(SHA256_CTX));
|
||||
return (1);
|
||||
}
|
||||
|
||||
const EVP_MD *
|
||||
evp_ssh_sha256(void)
|
||||
{
|
||||
static EVP_MD ssh_sha256;
|
||||
|
||||
memset(&ssh_sha256, 0, sizeof(ssh_sha256));
|
||||
ssh_sha256.type = NID_undef;
|
||||
ssh_sha256.md_size = SHA256_DIGEST_LENGTH;
|
||||
ssh_sha256.init = ssh_sha256_init;
|
||||
ssh_sha256.update = ssh_sha256_update;
|
||||
ssh_sha256.final = ssh_sha256_final;
|
||||
ssh_sha256.cleanup = ssh_sha256_cleanup;
|
||||
ssh_sha256.block_size = SHA256_BLOCK_LENGTH;
|
||||
ssh_sha256.ctx_size = sizeof(SHA256_CTX);
|
||||
|
||||
return (&ssh_sha256);
|
||||
}
|
||||
|
||||
#endif /* !defined(HAVE_EVP_SHA256) && (OPENSSL_VERSION_NUMBER >= 0x00907000L) */
|
||||
|
473
misc.c
473
misc.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.c,v 1.109 2017/03/14 00:55:37 dtucker Exp $ */
|
||||
/* $OpenBSD: misc.c,v 1.113 2017/08/18 05:48:04 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
|
||||
@ -29,10 +29,16 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -61,6 +67,10 @@
|
||||
#include "misc.h"
|
||||
#include "log.h"
|
||||
#include "ssh.h"
|
||||
#include "sshbuf.h"
|
||||
#include "ssherr.h"
|
||||
#include "uidswap.h"
|
||||
#include "platform.h"
|
||||
|
||||
/* remove newline at end of string */
|
||||
char *
|
||||
@ -539,7 +549,7 @@ addargs(arglist *args, char *fmt, ...)
|
||||
} else if (args->num+2 >= nalloc)
|
||||
nalloc *= 2;
|
||||
|
||||
args->list = xreallocarray(args->list, nalloc, sizeof(char *));
|
||||
args->list = xrecallocarray(args->list, args->nalloc, nalloc, sizeof(char *));
|
||||
args->nalloc = nalloc;
|
||||
args->list[args->num++] = cp;
|
||||
args->list[args->num] = NULL;
|
||||
@ -1085,6 +1095,7 @@ static const struct {
|
||||
const char *name;
|
||||
int value;
|
||||
} ipqos[] = {
|
||||
{ "none", INT_MAX }, /* can't use 0 here; that's CS0 */
|
||||
{ "af11", IPTOS_DSCP_AF11 },
|
||||
{ "af12", IPTOS_DSCP_AF12 },
|
||||
{ "af13", IPTOS_DSCP_AF13 },
|
||||
@ -1274,3 +1285,461 @@ daemonized(void)
|
||||
debug3("already daemonized");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Splits 's' into an argument vector. Handles quoted string and basic
|
||||
* escape characters (\\, \", \'). Caller must free the argument vector
|
||||
* and its members.
|
||||
*/
|
||||
int
|
||||
argv_split(const char *s, int *argcp, char ***argvp)
|
||||
{
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
int argc = 0, quote, i, j;
|
||||
char *arg, **argv = xcalloc(1, sizeof(*argv));
|
||||
|
||||
*argvp = NULL;
|
||||
*argcp = 0;
|
||||
|
||||
for (i = 0; s[i] != '\0'; i++) {
|
||||
/* Skip leading whitespace */
|
||||
if (s[i] == ' ' || s[i] == '\t')
|
||||
continue;
|
||||
|
||||
/* Start of a token */
|
||||
quote = 0;
|
||||
if (s[i] == '\\' &&
|
||||
(s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
|
||||
i++;
|
||||
else if (s[i] == '\'' || s[i] == '"')
|
||||
quote = s[i++];
|
||||
|
||||
argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
|
||||
arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Copy the token in, removing escapes */
|
||||
for (j = 0; s[i] != '\0'; i++) {
|
||||
if (s[i] == '\\') {
|
||||
if (s[i + 1] == '\'' ||
|
||||
s[i + 1] == '\"' ||
|
||||
s[i + 1] == '\\') {
|
||||
i++; /* Skip '\' */
|
||||
arg[j++] = s[i];
|
||||
} else {
|
||||
/* Unrecognised escape */
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
|
||||
break; /* done */
|
||||
else if (quote != 0 && s[i] == quote)
|
||||
break; /* done */
|
||||
else
|
||||
arg[j++] = s[i];
|
||||
}
|
||||
if (s[i] == '\0') {
|
||||
if (quote != 0) {
|
||||
/* Ran out of string looking for close quote */
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Success */
|
||||
*argcp = argc;
|
||||
*argvp = argv;
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
r = 0;
|
||||
out:
|
||||
if (argc != 0 && argv != NULL) {
|
||||
for (i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reassemble an argument vector into a string, quoting and escaping as
|
||||
* necessary. Caller must free returned string.
|
||||
*/
|
||||
char *
|
||||
argv_assemble(int argc, char **argv)
|
||||
{
|
||||
int i, j, ws, r;
|
||||
char c, *ret;
|
||||
struct sshbuf *buf, *arg;
|
||||
|
||||
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ws = 0;
|
||||
sshbuf_reset(arg);
|
||||
for (j = 0; argv[i][j] != '\0'; j++) {
|
||||
r = 0;
|
||||
c = argv[i][j];
|
||||
switch (c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
ws = 1;
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
if ((r = sshbuf_put_u8(arg, '\\')) != 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
r = sshbuf_put_u8(arg, c);
|
||||
break;
|
||||
}
|
||||
if (r != 0)
|
||||
fatal("%s: sshbuf_put_u8: %s",
|
||||
__func__, ssh_err(r));
|
||||
}
|
||||
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
|
||||
(r = sshbuf_putb(buf, arg)) != 0 ||
|
||||
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
}
|
||||
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
|
||||
fatal("%s: malloc failed", __func__);
|
||||
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
|
||||
ret[sshbuf_len(buf)] = '\0';
|
||||
sshbuf_free(buf);
|
||||
sshbuf_free(arg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Runs command in a subprocess wuth 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 (*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;
|
||||
}
|
||||
|
||||
/* Returns 0 if pid exited cleanly, non-zero otherwise */
|
||||
int
|
||||
exited_cleanly(pid_t pid, const char *tag, const char *cmd, int quiet)
|
||||
{
|
||||
int status;
|
||||
|
||||
while (waitpid(pid, &status, 0) == -1) {
|
||||
if (errno != EINTR) {
|
||||
error("%s: waitpid: %s", tag, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
|
||||
return -1;
|
||||
} else if (WEXITSTATUS(status) != 0) {
|
||||
do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
|
||||
"%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a given path for security. This is defined as all components
|
||||
* of the path to the file must be owned by either the owner of
|
||||
* of the file or root and no directories must be group or world writable.
|
||||
*
|
||||
* XXX Should any specific check be done for sym links ?
|
||||
*
|
||||
* Takes a file name, its stat information (preferably from fstat() to
|
||||
* avoid races), the uid of the expected owner, their home directory and an
|
||||
* error buffer plus max size as arguments.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
int
|
||||
safe_path(const char *name, struct stat *stp, const char *pw_dir,
|
||||
uid_t uid, char *err, size_t errlen)
|
||||
{
|
||||
char buf[PATH_MAX], homedir[PATH_MAX];
|
||||
char *cp;
|
||||
int comparehome = 0;
|
||||
struct stat st;
|
||||
|
||||
if (realpath(name, buf) == NULL) {
|
||||
snprintf(err, errlen, "realpath %s failed: %s", name,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
|
||||
comparehome = 1;
|
||||
|
||||
if (!S_ISREG(stp->st_mode)) {
|
||||
snprintf(err, errlen, "%s is not a regular file", buf);
|
||||
return -1;
|
||||
}
|
||||
if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
|
||||
(stp->st_mode & 022) != 0) {
|
||||
snprintf(err, errlen, "bad ownership or modes for file %s",
|
||||
buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for each component of the canonical path, walking upwards */
|
||||
for (;;) {
|
||||
if ((cp = dirname(buf)) == NULL) {
|
||||
snprintf(err, errlen, "dirname() failed");
|
||||
return -1;
|
||||
}
|
||||
strlcpy(buf, cp, sizeof(buf));
|
||||
|
||||
if (stat(buf, &st) < 0 ||
|
||||
(!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) ||
|
||||
(st.st_mode & 022) != 0) {
|
||||
snprintf(err, errlen,
|
||||
"bad ownership or modes for directory %s", buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If are past the homedir then we can stop */
|
||||
if (comparehome && strcmp(homedir, buf) == 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* dirname should always complete with a "/" path,
|
||||
* but we can be paranoid and check for "." too
|
||||
*/
|
||||
if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Version of safe_path() that accepts an open file descriptor to
|
||||
* avoid races.
|
||||
*
|
||||
* Returns 0 on success and -1 on failure
|
||||
*/
|
||||
int
|
||||
safe_path_fd(int fd, const char *file, struct passwd *pw,
|
||||
char *err, size_t errlen)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
/* check the open file to avoid races */
|
||||
if (fstat(fd, &st) < 0) {
|
||||
snprintf(err, errlen, "cannot stat file %s: %s",
|
||||
file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return safe_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the value of the given variable in the environment. If the variable
|
||||
* already exists, its value is overridden.
|
||||
*/
|
||||
void
|
||||
child_set_env(char ***envp, u_int *envsizep, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
char **env;
|
||||
u_int envsize;
|
||||
u_int i, namelen;
|
||||
|
||||
if (strchr(name, '=') != NULL) {
|
||||
error("Invalid environment variable \"%.100s\"", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're passed an uninitialized list, allocate a single null
|
||||
* entry before continuing.
|
||||
*/
|
||||
if (*envp == NULL && *envsizep == 0) {
|
||||
*envp = xmalloc(sizeof(char *));
|
||||
*envp[0] = NULL;
|
||||
*envsizep = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the slot where the value should be stored. If the variable
|
||||
* already exists, we reuse the slot; otherwise we append a new slot
|
||||
* at the end of the array, expanding if necessary.
|
||||
*/
|
||||
env = *envp;
|
||||
namelen = strlen(name);
|
||||
for (i = 0; env[i]; i++)
|
||||
if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
|
||||
break;
|
||||
if (env[i]) {
|
||||
/* Reuse the slot. */
|
||||
free(env[i]);
|
||||
} else {
|
||||
/* New variable. Expand if necessary. */
|
||||
envsize = *envsizep;
|
||||
if (i >= envsize - 1) {
|
||||
if (envsize >= 1000)
|
||||
fatal("child_set_env: too many env vars");
|
||||
envsize += 50;
|
||||
env = (*envp) = xreallocarray(env, envsize, sizeof(char *));
|
||||
*envsizep = envsize;
|
||||
}
|
||||
/* Need to set the NULL pointer at end of array beyond the new slot. */
|
||||
env[i + 1] = NULL;
|
||||
}
|
||||
|
||||
/* Allocate space and format the variable in the appropriate slot. */
|
||||
env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
|
||||
snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
|
||||
}
|
||||
|
||||
|
22
misc.h
22
misc.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.h,v 1.61 2016/11/30 00:28:31 dtucker Exp $ */
|
||||
/* $OpenBSD: misc.h,v 1.63 2017/08/18 05:48:04 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -16,6 +16,7 @@
|
||||
#define _MISC_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Data structure for representing a forwarding request. */
|
||||
struct Forward {
|
||||
@ -132,6 +133,25 @@ int parse_ipqos(const char *);
|
||||
const char *iptos2str(int);
|
||||
void mktemp_proto(char *, size_t);
|
||||
|
||||
void child_set_env(char ***envp, u_int *envsizep, const char *name,
|
||||
const char *value);
|
||||
|
||||
int argv_split(const char *, int *, char ***);
|
||||
char *argv_assemble(int, char **argv);
|
||||
int exited_cleanly(pid_t, const char *, const char *, int);
|
||||
|
||||
#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);
|
||||
|
||||
struct stat;
|
||||
int safe_path(const char *, struct stat *, const char *, uid_t,
|
||||
char *, size_t);
|
||||
int safe_path_fd(int, const char *, struct passwd *,
|
||||
char *err, size_t errlen);
|
||||
|
||||
/* readpass.c */
|
||||
|
||||
#define RP_ECHO 0x0001
|
||||
|
2
moduli.0
2
moduli.0
@ -71,4 +71,4 @@ STANDARDS
|
||||
the Secure Shell (SSH) Transport Layer Protocol, RFC 4419, March 2006,
|
||||
2006.
|
||||
|
||||
OpenBSD 6.0 September 26, 2012 OpenBSD 6.0
|
||||
OpenBSD 6.2 September 26, 2012 OpenBSD 6.2
|
||||
|
103
monitor.c
103
monitor.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: monitor.c,v 1.167 2017/02/03 23:05:57 djm Exp $ */
|
||||
/* $OpenBSD: monitor.c,v 1.174 2017/10/02 19:33:20 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
@ -308,6 +308,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
|
||||
partial = 0;
|
||||
auth_method = "unknown";
|
||||
auth_submethod = NULL;
|
||||
auth2_authctxt_reset_info(authctxt);
|
||||
|
||||
authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
|
||||
|
||||
/* Special handling for multiple required authentications */
|
||||
@ -347,6 +349,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor)
|
||||
auth_method, auth_submethod);
|
||||
if (!partial && !authenticated)
|
||||
authctxt->failures++;
|
||||
if (authenticated || partial) {
|
||||
auth2_update_session_info(authctxt,
|
||||
auth_method, auth_submethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,10 +760,12 @@ mm_answer_pwnamallow(int sock, Buffer *m)
|
||||
for (i = 0; i < options.nx; i++) \
|
||||
buffer_put_cstring(m, options.x[i]); \
|
||||
} while (0)
|
||||
#define M_CP_STRARRAYOPT_ALLOC(x, nx) M_CP_STRARRAYOPT(x, nx)
|
||||
/* See comment in servconf.h */
|
||||
COPY_MATCH_STRING_OPTS();
|
||||
#undef M_CP_STROPT
|
||||
#undef M_CP_STRARRAYOPT
|
||||
#undef M_CP_STRARRAYOPT_ALLOC
|
||||
|
||||
/* Create valid auth method lists */
|
||||
if (auth2_setup_methods_lists(authctxt) != 0) {
|
||||
@ -1119,7 +1127,7 @@ mm_answer_pam_free_ctx(int sock, Buffer *m)
|
||||
int
|
||||
mm_answer_keyallowed(int sock, Buffer *m)
|
||||
{
|
||||
Key *key;
|
||||
struct sshkey *key;
|
||||
char *cuser, *chost;
|
||||
u_char *blob;
|
||||
u_int bloblen, pubkey_auth_attempt;
|
||||
@ -1147,12 +1155,11 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
||||
switch (type) {
|
||||
case MM_USERKEY:
|
||||
allowed = options.pubkey_authentication &&
|
||||
!auth2_userkey_already_used(authctxt, key) &&
|
||||
!auth2_key_already_used(authctxt, key) &&
|
||||
match_pattern_list(sshkey_ssh_name(key),
|
||||
options.pubkey_key_types, 0) == 1 &&
|
||||
user_key_allowed(authctxt->pw, key,
|
||||
pubkey_auth_attempt);
|
||||
pubkey_auth_info(authctxt, key, NULL);
|
||||
auth_method = "publickey";
|
||||
if (options.pubkey_authentication &&
|
||||
(!pubkey_auth_attempt || allowed != 1))
|
||||
@ -1160,11 +1167,12 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
||||
break;
|
||||
case MM_HOSTKEY:
|
||||
allowed = options.hostbased_authentication &&
|
||||
!auth2_key_already_used(authctxt, key) &&
|
||||
match_pattern_list(sshkey_ssh_name(key),
|
||||
options.hostbased_key_types, 0) == 1 &&
|
||||
hostbased_key_allowed(authctxt->pw,
|
||||
cuser, chost, key);
|
||||
pubkey_auth_info(authctxt, key,
|
||||
auth2_record_info(authctxt,
|
||||
"client user \"%.100s\", client host \"%.100s\"",
|
||||
cuser, chost);
|
||||
auth_method = "hostbased";
|
||||
@ -1175,11 +1183,10 @@ mm_answer_keyallowed(int sock, Buffer *m)
|
||||
}
|
||||
}
|
||||
|
||||
debug3("%s: key %p is %s",
|
||||
__func__, key, allowed ? "allowed" : "not allowed");
|
||||
debug3("%s: key is %s", __func__, allowed ? "allowed" : "not allowed");
|
||||
|
||||
if (key != NULL)
|
||||
key_free(key);
|
||||
auth2_record_key(authctxt, 0, key);
|
||||
sshkey_free(key);
|
||||
|
||||
/* clear temporarily storage (used by verify) */
|
||||
monitor_reset_key_state();
|
||||
@ -1330,33 +1337,35 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser,
|
||||
}
|
||||
|
||||
int
|
||||
mm_answer_keyverify(int sock, Buffer *m)
|
||||
mm_answer_keyverify(int sock, struct sshbuf *m)
|
||||
{
|
||||
Key *key;
|
||||
struct sshkey *key;
|
||||
u_char *signature, *data, *blob;
|
||||
u_int signaturelen, datalen, bloblen;
|
||||
int verified = 0;
|
||||
int valid_data = 0;
|
||||
size_t signaturelen, datalen, bloblen;
|
||||
int r, ret, valid_data = 0, encoded_ret;
|
||||
|
||||
blob = buffer_get_string(m, &bloblen);
|
||||
signature = buffer_get_string(m, &signaturelen);
|
||||
data = buffer_get_string(m, &datalen);
|
||||
if ((r = sshbuf_get_string(m, &blob, &bloblen)) != 0 ||
|
||||
(r = sshbuf_get_string(m, &signature, &signaturelen)) != 0 ||
|
||||
(r = sshbuf_get_string(m, &data, &datalen)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
|
||||
if (hostbased_cuser == NULL || hostbased_chost == NULL ||
|
||||
!monitor_allowed_key(blob, bloblen))
|
||||
fatal("%s: bad key, not previously allowed", __func__);
|
||||
|
||||
key = key_from_blob(blob, bloblen);
|
||||
if (key == NULL)
|
||||
fatal("%s: bad public key blob", __func__);
|
||||
/* XXX use sshkey_froms here; need to change key_blob, etc. */
|
||||
if ((r = sshkey_from_blob(blob, bloblen, &key)) != 0)
|
||||
fatal("%s: bad public key blob: %s", __func__, ssh_err(r));
|
||||
|
||||
switch (key_blobtype) {
|
||||
case MM_USERKEY:
|
||||
valid_data = monitor_valid_userblob(data, datalen);
|
||||
auth_method = "publickey";
|
||||
break;
|
||||
case MM_HOSTKEY:
|
||||
valid_data = monitor_valid_hostbasedblob(data, datalen,
|
||||
hostbased_cuser, hostbased_chost);
|
||||
auth_method = "hostbased";
|
||||
break;
|
||||
default:
|
||||
valid_data = 0;
|
||||
@ -1365,29 +1374,28 @@ mm_answer_keyverify(int sock, Buffer *m)
|
||||
if (!valid_data)
|
||||
fatal("%s: bad signature data blob", __func__);
|
||||
|
||||
verified = key_verify(key, signature, signaturelen, data, datalen);
|
||||
debug3("%s: key %p signature %s",
|
||||
__func__, key, (verified == 1) ? "verified" : "unverified");
|
||||
|
||||
/* If auth was successful then record key to ensure it isn't reused */
|
||||
if (verified == 1 && key_blobtype == MM_USERKEY)
|
||||
auth2_record_userkey(authctxt, key);
|
||||
else
|
||||
key_free(key);
|
||||
ret = sshkey_verify(key, signature, signaturelen, data, datalen,
|
||||
active_state->compat);
|
||||
debug3("%s: %s %p signature %s", __func__, auth_method, key,
|
||||
(ret == 0) ? "verified" : "unverified");
|
||||
auth2_record_key(authctxt, ret == 0, key);
|
||||
|
||||
free(blob);
|
||||
free(signature);
|
||||
free(data);
|
||||
|
||||
auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
|
||||
|
||||
monitor_reset_key_state();
|
||||
|
||||
buffer_clear(m);
|
||||
buffer_put_int(m, verified);
|
||||
sshkey_free(key);
|
||||
sshbuf_reset(m);
|
||||
|
||||
/* encode ret != 0 as positive integer, since we're sending u32 */
|
||||
encoded_ret = (ret != 0);
|
||||
if ((r = sshbuf_put_u32(m, encoded_ret)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m);
|
||||
|
||||
return (verified == 1);
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1513,13 +1521,14 @@ mm_answer_pty_cleanup(int sock, Buffer *m)
|
||||
int
|
||||
mm_answer_term(int sock, Buffer *req)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
extern struct monitor *pmonitor;
|
||||
int res, status;
|
||||
|
||||
debug3("%s: tearing down sessions", __func__);
|
||||
|
||||
/* The child is terminating */
|
||||
session_destroy_all(&mm_session_close);
|
||||
session_destroy_all(ssh, &mm_session_close);
|
||||
|
||||
#ifdef USE_PAM
|
||||
if (options.use_pam)
|
||||
@ -1578,6 +1587,17 @@ mm_answer_audit_command(int socket, Buffer *m)
|
||||
}
|
||||
#endif /* SSH_AUDIT_EVENTS */
|
||||
|
||||
void
|
||||
monitor_clear_keystate(struct monitor *pmonitor)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
|
||||
ssh_clear_newkeys(ssh, MODE_IN);
|
||||
ssh_clear_newkeys(ssh, MODE_OUT);
|
||||
sshbuf_free(child_state);
|
||||
child_state = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
monitor_apply_keystate(struct monitor *pmonitor)
|
||||
{
|
||||
@ -1639,9 +1659,18 @@ static void
|
||||
monitor_openfds(struct monitor *mon, int do_logfds)
|
||||
{
|
||||
int pair[2];
|
||||
#ifdef SO_ZEROIZE
|
||||
int on = 1;
|
||||
#endif
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)
|
||||
fatal("%s: socketpair: %s", __func__, strerror(errno));
|
||||
#ifdef SO_ZEROIZE
|
||||
if (setsockopt(pair[0], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) < 0)
|
||||
error("setsockopt SO_ZEROIZE(0): %.100s", strerror(errno));
|
||||
if (setsockopt(pair[1], SOL_SOCKET, SO_ZEROIZE, &on, sizeof(on)) < 0)
|
||||
error("setsockopt SO_ZEROIZE(1): %.100s", strerror(errno));
|
||||
#endif
|
||||
FD_CLOSEONEXEC(pair[0]);
|
||||
FD_CLOSEONEXEC(pair[1]);
|
||||
mon->m_recvfd = pair[0];
|
||||
@ -1774,6 +1803,7 @@ int
|
||||
mm_answer_gss_userok(int sock, Buffer *m)
|
||||
{
|
||||
int authenticated;
|
||||
const char *displayname;
|
||||
|
||||
if (!options.gss_authentication)
|
||||
fatal("%s: GSSAPI authentication not enabled", __func__);
|
||||
@ -1788,6 +1818,9 @@ mm_answer_gss_userok(int sock, Buffer *m)
|
||||
|
||||
auth_method = "gssapi-with-mic";
|
||||
|
||||
if ((displayname = ssh_gssapi_displayname()) != NULL)
|
||||
auth2_record_info(authctxt, "%s", displayname);
|
||||
|
||||
/* Monitor loop will terminate if authenticated */
|
||||
return (authenticated);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.89 2016/08/13 17:47:41 markus Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.c,v 1.94 2017/10/02 19:33:20 djm Exp $ */
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||
@ -216,7 +216,7 @@ mm_choose_dh(int min, int nbits, int max)
|
||||
#endif
|
||||
|
||||
int
|
||||
mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
|
||||
mm_key_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
|
||||
const u_char *data, u_int datalen, const char *hostkey_alg)
|
||||
{
|
||||
struct kex *kex = *pmonitor->m_pkex;
|
||||
@ -242,6 +242,7 @@ mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
|
||||
struct passwd *
|
||||
mm_getpwnamallow(const char *username)
|
||||
{
|
||||
struct ssh *ssh = active_state; /* XXX */
|
||||
Buffer m;
|
||||
struct passwd *pw;
|
||||
u_int len, i;
|
||||
@ -289,12 +290,20 @@ mm_getpwnamallow(const char *username)
|
||||
for (i = 0; i < newopts->nx; i++) \
|
||||
newopts->x[i] = buffer_get_string(&m, NULL); \
|
||||
} while (0)
|
||||
#define M_CP_STRARRAYOPT_ALLOC(x, nx) do { \
|
||||
newopts->x = newopts->nx == 0 ? \
|
||||
NULL : xcalloc(newopts->nx, sizeof(*newopts->x)); \
|
||||
M_CP_STRARRAYOPT(x, nx); \
|
||||
} while (0)
|
||||
/* See comment in servconf.h */
|
||||
COPY_MATCH_STRING_OPTS();
|
||||
#undef M_CP_STROPT
|
||||
#undef M_CP_STRARRAYOPT
|
||||
#undef M_CP_STRARRAYOPT_ALLOC
|
||||
|
||||
copy_set_server_options(&options, newopts, 1);
|
||||
log_change_level(options.log_level);
|
||||
process_permitopen(ssh, &options);
|
||||
free(newopts);
|
||||
|
||||
buffer_free(&m);
|
||||
@ -374,7 +383,8 @@ mm_auth_password(Authctxt *authctxt, char *password)
|
||||
}
|
||||
|
||||
int
|
||||
mm_user_key_allowed(struct passwd *pw, Key *key, int pubkey_auth_attempt)
|
||||
mm_user_key_allowed(struct passwd *pw, struct sshkey *key,
|
||||
int pubkey_auth_attempt)
|
||||
{
|
||||
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
|
||||
pubkey_auth_attempt));
|
||||
@ -382,14 +392,14 @@ mm_user_key_allowed(struct passwd *pw, Key *key, int pubkey_auth_attempt)
|
||||
|
||||
int
|
||||
mm_hostbased_key_allowed(struct passwd *pw, const char *user, const char *host,
|
||||
Key *key)
|
||||
struct sshkey *key)
|
||||
{
|
||||
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0));
|
||||
}
|
||||
|
||||
int
|
||||
mm_key_allowed(enum mm_keytype type, const char *user, const char *host,
|
||||
Key *key, int pubkey_auth_attempt)
|
||||
struct sshkey *key, int pubkey_auth_attempt)
|
||||
{
|
||||
Buffer m;
|
||||
u_char *blob;
|
||||
@ -434,12 +444,13 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host,
|
||||
*/
|
||||
|
||||
int
|
||||
mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
|
||||
mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen,
|
||||
const u_char *data, size_t datalen, u_int compat)
|
||||
{
|
||||
Buffer m;
|
||||
u_char *blob;
|
||||
u_int len;
|
||||
int verified = 0;
|
||||
u_int encoded_ret = 0;
|
||||
|
||||
debug3("%s entering", __func__);
|
||||
|
||||
@ -458,11 +469,13 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
|
||||
debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m);
|
||||
|
||||
verified = buffer_get_int(&m);
|
||||
encoded_ret = buffer_get_int(&m);
|
||||
|
||||
buffer_free(&m);
|
||||
|
||||
return (verified);
|
||||
if (encoded_ret != 0)
|
||||
return SSH_ERR_SIGNATURE_INVALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: monitor_wrap.h,v 1.32 2016/09/28 16:33:07 djm Exp $ */
|
||||
/* $OpenBSD: monitor_wrap.h,v 1.35 2017/05/31 08:09:45 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||
@ -34,22 +34,24 @@ extern int use_privsep;
|
||||
enum mm_keytype { MM_NOKEY, MM_HOSTKEY, MM_USERKEY };
|
||||
|
||||
struct monitor;
|
||||
struct mm_master;
|
||||
struct Authctxt;
|
||||
|
||||
void mm_log_handler(LogLevel, const char *, void *);
|
||||
int mm_is_monitor(void);
|
||||
DH *mm_choose_dh(int, int, int);
|
||||
int mm_key_sign(Key *, u_char **, u_int *, const u_char *, u_int, const char *);
|
||||
int mm_key_sign(struct sshkey *, u_char **, u_int *, const u_char *, u_int,
|
||||
const char *);
|
||||
void mm_inform_authserv(char *, char *);
|
||||
struct passwd *mm_getpwnamallow(const char *);
|
||||
char *mm_auth2_read_banner(void);
|
||||
int mm_auth_password(struct Authctxt *, char *);
|
||||
int mm_key_allowed(enum mm_keytype, const char *, const char *, Key *, int);
|
||||
int mm_user_key_allowed(struct passwd *, Key *, int);
|
||||
int mm_key_allowed(enum mm_keytype, const char *, const char *, struct sshkey *,
|
||||
int);
|
||||
int mm_user_key_allowed(struct passwd *, struct sshkey *, int);
|
||||
int mm_hostbased_key_allowed(struct passwd *, const char *,
|
||||
const char *, Key *);
|
||||
int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int);
|
||||
const char *, struct sshkey *);
|
||||
int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
|
||||
const u_char *, size_t, u_int);
|
||||
|
||||
#ifdef GSSAPI
|
||||
OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
|
||||
@ -83,6 +85,7 @@ void mm_session_pty_cleanup2(struct Session *);
|
||||
struct newkeys *mm_newkeys_from_blob(u_char *, int);
|
||||
int mm_newkeys_to_blob(int, u_char **, u_int *);
|
||||
|
||||
void monitor_clear_keystate(struct monitor *);
|
||||
void monitor_apply_keystate(struct monitor *);
|
||||
void mm_get_keystate(struct monitor *);
|
||||
void mm_send_keystate(struct monitor*);
|
||||
|
237
mux.c
237
mux.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: mux.c,v 1.64 2017/01/21 11:32:04 guenther Exp $ */
|
||||
/* $OpenBSD: mux.c,v 1.69 2017/09/20 05:19:00 dtucker Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
@ -161,22 +161,32 @@ struct mux_master_state {
|
||||
#define MUX_FWD_REMOTE 2
|
||||
#define MUX_FWD_DYNAMIC 3
|
||||
|
||||
static void mux_session_confirm(int, int, void *);
|
||||
static void mux_stdio_confirm(int, int, void *);
|
||||
static void mux_session_confirm(struct ssh *, int, int, void *);
|
||||
static void mux_stdio_confirm(struct ssh *, int, int, void *);
|
||||
|
||||
static int process_mux_master_hello(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_new_session(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_alive_check(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_terminate(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_open_fwd(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_close_fwd(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_stdio_fwd(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_stop_listening(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_proxy(u_int, Channel *, Buffer *, Buffer *);
|
||||
static int process_mux_master_hello(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_new_session(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_alive_check(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_terminate(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_open_fwd(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_close_fwd(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_stdio_fwd(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_stop_listening(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
static int process_mux_proxy(struct ssh *, u_int,
|
||||
Channel *, struct sshbuf *, struct sshbuf *);
|
||||
|
||||
static const struct {
|
||||
u_int type;
|
||||
int (*handler)(u_int, Channel *, Buffer *, Buffer *);
|
||||
int (*handler)(struct ssh *, u_int, Channel *,
|
||||
struct sshbuf *, struct sshbuf *);
|
||||
} mux_master_handlers[] = {
|
||||
{ MUX_MSG_HELLO, process_mux_master_hello },
|
||||
{ MUX_C_NEW_SESSION, process_mux_new_session },
|
||||
@ -193,52 +203,54 @@ static const struct {
|
||||
/* Cleanup callback fired on closure of mux slave _session_ channel */
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
mux_master_session_cleanup_cb(int cid, void *unused)
|
||||
mux_master_session_cleanup_cb(struct ssh *ssh, int cid, void *unused)
|
||||
{
|
||||
Channel *cc, *c = channel_by_id(cid);
|
||||
Channel *cc, *c = channel_by_id(ssh, cid);
|
||||
|
||||
debug3("%s: entering for channel %d", __func__, cid);
|
||||
if (c == NULL)
|
||||
fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
|
||||
if (c->ctl_chan != -1) {
|
||||
if ((cc = channel_by_id(c->ctl_chan)) == NULL)
|
||||
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
|
||||
fatal("%s: channel %d missing control channel %d",
|
||||
__func__, c->self, c->ctl_chan);
|
||||
c->ctl_chan = -1;
|
||||
cc->remote_id = -1;
|
||||
chan_rcvd_oclose(cc);
|
||||
cc->remote_id = 0;
|
||||
cc->have_remote_id = 0;
|
||||
chan_rcvd_oclose(ssh, cc);
|
||||
}
|
||||
channel_cancel_cleanup(c->self);
|
||||
channel_cancel_cleanup(ssh, c->self);
|
||||
}
|
||||
|
||||
/* Cleanup callback fired on closure of mux slave _control_ channel */
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
mux_master_control_cleanup_cb(int cid, void *unused)
|
||||
mux_master_control_cleanup_cb(struct ssh *ssh, int cid, void *unused)
|
||||
{
|
||||
Channel *sc, *c = channel_by_id(cid);
|
||||
Channel *sc, *c = channel_by_id(ssh, cid);
|
||||
|
||||
debug3("%s: entering for channel %d", __func__, cid);
|
||||
if (c == NULL)
|
||||
fatal("%s: channel_by_id(%i) == NULL", __func__, cid);
|
||||
if (c->remote_id != -1) {
|
||||
if ((sc = channel_by_id(c->remote_id)) == NULL)
|
||||
fatal("%s: channel %d missing session channel %d",
|
||||
if (c->have_remote_id) {
|
||||
if ((sc = channel_by_id(ssh, c->remote_id)) == NULL)
|
||||
fatal("%s: channel %d missing session channel %u",
|
||||
__func__, c->self, c->remote_id);
|
||||
c->remote_id = -1;
|
||||
c->remote_id = 0;
|
||||
c->have_remote_id = 0;
|
||||
sc->ctl_chan = -1;
|
||||
if (sc->type != SSH_CHANNEL_OPEN &&
|
||||
sc->type != SSH_CHANNEL_OPENING) {
|
||||
debug2("%s: channel %d: not open", __func__, sc->self);
|
||||
chan_mark_dead(sc);
|
||||
chan_mark_dead(ssh, sc);
|
||||
} else {
|
||||
if (sc->istate == CHAN_INPUT_OPEN)
|
||||
chan_read_failed(sc);
|
||||
chan_read_failed(ssh, sc);
|
||||
if (sc->ostate == CHAN_OUTPUT_OPEN)
|
||||
chan_write_failed(sc);
|
||||
chan_write_failed(ssh, sc);
|
||||
}
|
||||
}
|
||||
channel_cancel_cleanup(c->self);
|
||||
channel_cancel_cleanup(ssh, c->self);
|
||||
}
|
||||
|
||||
/* Check mux client environment variables before passing them to mux master. */
|
||||
@ -266,7 +278,8 @@ env_permitted(char *env)
|
||||
/* Mux master protocol message handlers */
|
||||
|
||||
static int
|
||||
process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_master_hello(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
u_int ver;
|
||||
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
|
||||
@ -308,7 +321,8 @@ process_mux_master_hello(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_new_session(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
Channel *nc;
|
||||
struct mux_session_confirm_ctx *cctx;
|
||||
@ -401,7 +415,7 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
new_fd[0], new_fd[1], new_fd[2]);
|
||||
|
||||
/* XXX support multiple child sessions in future */
|
||||
if (c->remote_id != -1) {
|
||||
if (c->have_remote_id) {
|
||||
debug2("%s: session already open", __func__);
|
||||
/* prepare reply */
|
||||
buffer_put_int(r, MUX_S_FAILURE);
|
||||
@ -453,15 +467,16 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
packetmax >>= 1;
|
||||
}
|
||||
|
||||
nc = channel_new("session", SSH_CHANNEL_OPENING,
|
||||
nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING,
|
||||
new_fd[0], new_fd[1], new_fd[2], window, packetmax,
|
||||
CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0);
|
||||
|
||||
nc->ctl_chan = c->self; /* link session -> control channel */
|
||||
c->remote_id = nc->self; /* link control -> session channel */
|
||||
c->have_remote_id = 1;
|
||||
|
||||
if (cctx->want_tty && escape_char != 0xffffffff) {
|
||||
channel_register_filter(nc->self,
|
||||
channel_register_filter(ssh, nc->self,
|
||||
client_simple_escape_filter, NULL,
|
||||
client_filter_cleanup,
|
||||
client_new_escape_filter_ctx((int)escape_char));
|
||||
@ -470,17 +485,19 @@ process_mux_new_session(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
debug2("%s: channel_new: %d linked to control channel %d",
|
||||
__func__, nc->self, nc->ctl_chan);
|
||||
|
||||
channel_send_open(nc->self);
|
||||
channel_register_open_confirm(nc->self, mux_session_confirm, cctx);
|
||||
channel_send_open(ssh, nc->self);
|
||||
channel_register_open_confirm(ssh, nc->self, mux_session_confirm, cctx);
|
||||
c->mux_pause = 1; /* stop handling messages until open_confirm done */
|
||||
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
|
||||
channel_register_cleanup(ssh, nc->self,
|
||||
mux_master_session_cleanup_cb, 1);
|
||||
|
||||
/* reply is deferred, sent by mux_session_confirm */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_alive_check(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
debug2("%s: channel %d: alive check", __func__, c->self);
|
||||
|
||||
@ -493,7 +510,8 @@ process_mux_alive_check(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_terminate(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_terminate(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
debug2("%s: channel %d: terminate request", __func__, c->self);
|
||||
|
||||
@ -582,7 +600,7 @@ compare_forward(struct Forward *a, struct Forward *b)
|
||||
}
|
||||
|
||||
static void
|
||||
mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
mux_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct mux_channel_confirm_ctx *fctx = ctxt;
|
||||
char *failmsg = NULL;
|
||||
@ -590,7 +608,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
Channel *c;
|
||||
Buffer out;
|
||||
|
||||
if ((c = channel_by_id(fctx->cid)) == NULL) {
|
||||
if ((c = channel_by_id(ssh, fctx->cid)) == NULL) {
|
||||
/* no channel for reply */
|
||||
error("%s: unknown channel", __func__);
|
||||
return;
|
||||
@ -616,7 +634,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
buffer_put_int(&out, MUX_S_REMOTE_PORT);
|
||||
buffer_put_int(&out, fctx->rid);
|
||||
buffer_put_int(&out, rfwd->allocated_port);
|
||||
channel_update_permitted_opens(rfwd->handle,
|
||||
channel_update_permitted_opens(ssh, rfwd->handle,
|
||||
rfwd->allocated_port);
|
||||
} else {
|
||||
buffer_put_int(&out, MUX_S_OK);
|
||||
@ -625,7 +643,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
goto out;
|
||||
} else {
|
||||
if (rfwd->listen_port == 0)
|
||||
channel_update_permitted_opens(rfwd->handle, -1);
|
||||
channel_update_permitted_opens(ssh, rfwd->handle, -1);
|
||||
if (rfwd->listen_path != NULL)
|
||||
xasprintf(&failmsg, "remote port forwarding failed for "
|
||||
"listen path %s", rfwd->listen_path);
|
||||
@ -651,7 +669,7 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
buffer_put_cstring(&out, failmsg);
|
||||
free(failmsg);
|
||||
out:
|
||||
buffer_put_string(&c->output, buffer_ptr(&out), buffer_len(&out));
|
||||
buffer_put_string(c->output, buffer_ptr(&out), buffer_len(&out));
|
||||
buffer_free(&out);
|
||||
if (c->mux_pause <= 0)
|
||||
fatal("%s: mux_pause %d", __func__, c->mux_pause);
|
||||
@ -659,7 +677,8 @@ mux_confirm_remote_forward(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_open_fwd(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
struct Forward fwd;
|
||||
char *fwd_desc = NULL;
|
||||
@ -727,13 +746,16 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
fwd.listen_port);
|
||||
goto invalid;
|
||||
}
|
||||
if ((fwd.connect_port != PORT_STREAMLOCAL && fwd.connect_port >= 65536)
|
||||
|| (ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE && fwd.connect_port == 0)) {
|
||||
if ((fwd.connect_port != PORT_STREAMLOCAL &&
|
||||
fwd.connect_port >= 65536) ||
|
||||
(ftype != MUX_FWD_DYNAMIC && ftype != MUX_FWD_REMOTE &&
|
||||
fwd.connect_port == 0)) {
|
||||
logit("%s: invalid connect port %u", __func__,
|
||||
fwd.connect_port);
|
||||
goto invalid;
|
||||
}
|
||||
if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL && fwd.connect_path == NULL) {
|
||||
if (ftype != MUX_FWD_DYNAMIC && fwd.connect_host == NULL &&
|
||||
fwd.connect_path == NULL) {
|
||||
logit("%s: missing connect host", __func__);
|
||||
goto invalid;
|
||||
}
|
||||
@ -784,7 +806,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
if (ftype == MUX_FWD_LOCAL || ftype == MUX_FWD_DYNAMIC) {
|
||||
if (!channel_setup_local_fwd_listener(&fwd,
|
||||
if (!channel_setup_local_fwd_listener(ssh, &fwd,
|
||||
&options.fwd_opts)) {
|
||||
fail:
|
||||
logit("slave-requested %s failed", fwd_desc);
|
||||
@ -798,7 +820,7 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
} else {
|
||||
struct mux_channel_confirm_ctx *fctx;
|
||||
|
||||
fwd.handle = channel_request_remote_forwarding(&fwd);
|
||||
fwd.handle = channel_request_remote_forwarding(ssh, &fwd);
|
||||
if (fwd.handle < 0)
|
||||
goto fail;
|
||||
add_remote_forward(&options, &fwd);
|
||||
@ -827,7 +849,8 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_close_fwd(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
struct Forward fwd, *found_fwd;
|
||||
char *fwd_desc = NULL;
|
||||
@ -908,11 +931,11 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
* However, for dynamic allocated listen ports we need
|
||||
* to use the actual listen port.
|
||||
*/
|
||||
if (channel_request_rforward_cancel(found_fwd) == -1)
|
||||
if (channel_request_rforward_cancel(ssh, found_fwd) == -1)
|
||||
error_reason = "port not in permitted opens";
|
||||
} else { /* local and dynamic forwards */
|
||||
/* Ditto */
|
||||
if (channel_cancel_lport_listener(&fwd, fwd.connect_port,
|
||||
if (channel_cancel_lport_listener(ssh, &fwd, fwd.connect_port,
|
||||
&options.fwd_opts) == -1)
|
||||
error_reason = "port not found";
|
||||
}
|
||||
@ -942,7 +965,8 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_stdio_fwd(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
Channel *nc;
|
||||
char *reserved, *chost;
|
||||
@ -986,7 +1010,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
new_fd[0], new_fd[1]);
|
||||
|
||||
/* XXX support multiple child sessions in future */
|
||||
if (c->remote_id != -1) {
|
||||
if (c->have_remote_id) {
|
||||
debug2("%s: session already open", __func__);
|
||||
/* prepare reply */
|
||||
buffer_put_int(r, MUX_S_FAILURE);
|
||||
@ -1018,19 +1042,21 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
if (!isatty(new_fd[1]))
|
||||
set_nonblock(new_fd[1]);
|
||||
|
||||
nc = channel_connect_stdio_fwd(chost, cport, new_fd[0], new_fd[1]);
|
||||
nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]);
|
||||
|
||||
nc->ctl_chan = c->self; /* link session -> control channel */
|
||||
c->remote_id = nc->self; /* link control -> session channel */
|
||||
c->have_remote_id = 1;
|
||||
|
||||
debug2("%s: channel_new: %d linked to control channel %d",
|
||||
__func__, nc->self, nc->ctl_chan);
|
||||
|
||||
channel_register_cleanup(nc->self, mux_master_session_cleanup_cb, 1);
|
||||
channel_register_cleanup(ssh, nc->self,
|
||||
mux_master_session_cleanup_cb, 1);
|
||||
|
||||
cctx = xcalloc(1, sizeof(*cctx));
|
||||
cctx->rid = rid;
|
||||
channel_register_open_confirm(nc->self, mux_stdio_confirm, cctx);
|
||||
channel_register_open_confirm(ssh, nc->self, mux_stdio_confirm, cctx);
|
||||
c->mux_pause = 1; /* stop handling messages until open_confirm done */
|
||||
|
||||
/* reply is deferred, sent by mux_session_confirm */
|
||||
@ -1039,7 +1065,7 @@ process_mux_stdio_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
|
||||
/* Callback on open confirmation in mux master for a mux stdio fwd session. */
|
||||
static void
|
||||
mux_stdio_confirm(int id, int success, void *arg)
|
||||
mux_stdio_confirm(struct ssh *ssh, int id, int success, void *arg)
|
||||
{
|
||||
struct mux_stdio_confirm_ctx *cctx = arg;
|
||||
Channel *c, *cc;
|
||||
@ -1047,9 +1073,9 @@ mux_stdio_confirm(int id, int success, void *arg)
|
||||
|
||||
if (cctx == NULL)
|
||||
fatal("%s: cctx == NULL", __func__);
|
||||
if ((c = channel_by_id(id)) == NULL)
|
||||
if ((c = channel_by_id(ssh, id)) == NULL)
|
||||
fatal("%s: no channel for id %d", __func__, id);
|
||||
if ((cc = channel_by_id(c->ctl_chan)) == NULL)
|
||||
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
|
||||
fatal("%s: channel %d lacks control channel %d", __func__,
|
||||
id, c->ctl_chan);
|
||||
|
||||
@ -1072,7 +1098,7 @@ mux_stdio_confirm(int id, int success, void *arg)
|
||||
|
||||
done:
|
||||
/* Send reply */
|
||||
buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
|
||||
buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply));
|
||||
buffer_free(&reply);
|
||||
|
||||
if (cc->mux_pause <= 0)
|
||||
@ -1083,7 +1109,8 @@ mux_stdio_confirm(int id, int success, void *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_stop_listening(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
debug("%s: channel %d: stop listening", __func__, c->self);
|
||||
|
||||
@ -1100,7 +1127,7 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
if (mux_listener_channel != NULL) {
|
||||
channel_free(mux_listener_channel);
|
||||
channel_free(ssh, mux_listener_channel);
|
||||
client_stop_mux();
|
||||
free(options.control_path);
|
||||
options.control_path = NULL;
|
||||
@ -1116,7 +1143,8 @@ process_mux_stop_listening(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
}
|
||||
|
||||
static int
|
||||
process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
process_mux_proxy(struct ssh *ssh, u_int rid,
|
||||
Channel *c, Buffer *m, Buffer *r)
|
||||
{
|
||||
debug("%s: channel %d: proxy request", __func__, c->self);
|
||||
|
||||
@ -1129,7 +1157,7 @@ process_mux_proxy(u_int rid, Channel *c, Buffer *m, Buffer *r)
|
||||
|
||||
/* Channel callbacks fired on read/write from mux slave fd */
|
||||
static int
|
||||
mux_master_read_cb(Channel *c)
|
||||
mux_master_read_cb(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
struct mux_master_state *state = (struct mux_master_state *)c->mux_ctx;
|
||||
Buffer in, out;
|
||||
@ -1141,7 +1169,7 @@ mux_master_read_cb(Channel *c)
|
||||
if (c->mux_ctx == NULL) {
|
||||
state = xcalloc(1, sizeof(*state));
|
||||
c->mux_ctx = state;
|
||||
channel_register_cleanup(c->self,
|
||||
channel_register_cleanup(ssh, c->self,
|
||||
mux_master_control_cleanup_cb, 0);
|
||||
|
||||
/* Send hello */
|
||||
@ -1149,7 +1177,7 @@ mux_master_read_cb(Channel *c)
|
||||
buffer_put_int(&out, MUX_MSG_HELLO);
|
||||
buffer_put_int(&out, SSHMUX_VER);
|
||||
/* no extensions */
|
||||
buffer_put_string(&c->output, buffer_ptr(&out),
|
||||
buffer_put_string(c->output, buffer_ptr(&out),
|
||||
buffer_len(&out));
|
||||
buffer_free(&out);
|
||||
debug3("%s: channel %d: hello sent", __func__, c->self);
|
||||
@ -1160,7 +1188,7 @@ mux_master_read_cb(Channel *c)
|
||||
buffer_init(&out);
|
||||
|
||||
/* Channel code ensures that we receive whole packets */
|
||||
if ((ptr = buffer_get_string_ptr_ret(&c->input, &have)) == NULL) {
|
||||
if ((ptr = buffer_get_string_ptr_ret(c->input, &have)) == NULL) {
|
||||
malf:
|
||||
error("%s: malformed message", __func__);
|
||||
goto out;
|
||||
@ -1186,7 +1214,8 @@ mux_master_read_cb(Channel *c)
|
||||
|
||||
for (i = 0; mux_master_handlers[i].handler != NULL; i++) {
|
||||
if (type == mux_master_handlers[i].type) {
|
||||
ret = mux_master_handlers[i].handler(rid, c, &in, &out);
|
||||
ret = mux_master_handlers[i].handler(ssh, rid,
|
||||
c, &in, &out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1199,7 +1228,7 @@ mux_master_read_cb(Channel *c)
|
||||
}
|
||||
/* Enqueue reply packet */
|
||||
if (buffer_len(&out) != 0) {
|
||||
buffer_put_string(&c->output, buffer_ptr(&out),
|
||||
buffer_put_string(c->output, buffer_ptr(&out),
|
||||
buffer_len(&out));
|
||||
}
|
||||
out:
|
||||
@ -1209,7 +1238,7 @@ mux_master_read_cb(Channel *c)
|
||||
}
|
||||
|
||||
void
|
||||
mux_exit_message(Channel *c, int exitval)
|
||||
mux_exit_message(struct ssh *ssh, Channel *c, int exitval)
|
||||
{
|
||||
Buffer m;
|
||||
Channel *mux_chan;
|
||||
@ -1217,7 +1246,7 @@ mux_exit_message(Channel *c, int exitval)
|
||||
debug3("%s: channel %d: exit message, exitval %d", __func__, c->self,
|
||||
exitval);
|
||||
|
||||
if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
|
||||
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
|
||||
fatal("%s: channel %d missing mux channel %d",
|
||||
__func__, c->self, c->ctl_chan);
|
||||
|
||||
@ -1227,19 +1256,19 @@ mux_exit_message(Channel *c, int exitval)
|
||||
buffer_put_int(&m, c->self);
|
||||
buffer_put_int(&m, exitval);
|
||||
|
||||
buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
|
||||
buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m));
|
||||
buffer_free(&m);
|
||||
}
|
||||
|
||||
void
|
||||
mux_tty_alloc_failed(Channel *c)
|
||||
mux_tty_alloc_failed(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
Buffer m;
|
||||
Channel *mux_chan;
|
||||
|
||||
debug3("%s: channel %d: TTY alloc failed", __func__, c->self);
|
||||
|
||||
if ((mux_chan = channel_by_id(c->ctl_chan)) == NULL)
|
||||
if ((mux_chan = channel_by_id(ssh, c->ctl_chan)) == NULL)
|
||||
fatal("%s: channel %d missing mux channel %d",
|
||||
__func__, c->self, c->ctl_chan);
|
||||
|
||||
@ -1248,13 +1277,13 @@ mux_tty_alloc_failed(Channel *c)
|
||||
buffer_put_int(&m, MUX_S_TTY_ALLOC_FAIL);
|
||||
buffer_put_int(&m, c->self);
|
||||
|
||||
buffer_put_string(&mux_chan->output, buffer_ptr(&m), buffer_len(&m));
|
||||
buffer_put_string(mux_chan->output, buffer_ptr(&m), buffer_len(&m));
|
||||
buffer_free(&m);
|
||||
}
|
||||
|
||||
/* Prepare a mux master to listen on a Unix domain socket. */
|
||||
void
|
||||
muxserver_listen(void)
|
||||
muxserver_listen(struct ssh *ssh)
|
||||
{
|
||||
mode_t old_umask;
|
||||
char *orig_control_path = options.control_path;
|
||||
@ -1327,7 +1356,7 @@ muxserver_listen(void)
|
||||
|
||||
set_nonblock(muxserver_sock);
|
||||
|
||||
mux_listener_channel = channel_new("mux listener",
|
||||
mux_listener_channel = channel_new(ssh, "mux listener",
|
||||
SSH_CHANNEL_MUX_LISTENER, muxserver_sock, muxserver_sock, -1,
|
||||
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
|
||||
0, options.control_path, 1);
|
||||
@ -1338,7 +1367,7 @@ muxserver_listen(void)
|
||||
|
||||
/* Callback on open confirmation in mux master for a mux client session. */
|
||||
static void
|
||||
mux_session_confirm(int id, int success, void *arg)
|
||||
mux_session_confirm(struct ssh *ssh, int id, int success, void *arg)
|
||||
{
|
||||
struct mux_session_confirm_ctx *cctx = arg;
|
||||
const char *display;
|
||||
@ -1348,9 +1377,9 @@ mux_session_confirm(int id, int success, void *arg)
|
||||
|
||||
if (cctx == NULL)
|
||||
fatal("%s: cctx == NULL", __func__);
|
||||
if ((c = channel_by_id(id)) == NULL)
|
||||
if ((c = channel_by_id(ssh, id)) == NULL)
|
||||
fatal("%s: no channel for id %d", __func__, id);
|
||||
if ((cc = channel_by_id(c->ctl_chan)) == NULL)
|
||||
if ((cc = channel_by_id(ssh, c->ctl_chan)) == NULL)
|
||||
fatal("%s: channel %d lacks control channel %d", __func__,
|
||||
id, c->ctl_chan);
|
||||
|
||||
@ -1369,27 +1398,27 @@ mux_session_confirm(int id, int success, void *arg)
|
||||
char *proto, *data;
|
||||
|
||||
/* Get reasonable local authentication information. */
|
||||
if (client_x11_get_proto(display, options.xauth_location,
|
||||
if (client_x11_get_proto(ssh, display, options.xauth_location,
|
||||
options.forward_x11_trusted, options.forward_x11_timeout,
|
||||
&proto, &data) == 0) {
|
||||
/* Request forwarding with authentication spoofing. */
|
||||
debug("Requesting X11 forwarding with authentication "
|
||||
"spoofing.");
|
||||
x11_request_forwarding_with_spoofing(id, display, proto,
|
||||
data, 1);
|
||||
x11_request_forwarding_with_spoofing(ssh, id,
|
||||
display, proto, data, 1);
|
||||
/* XXX exit_on_forward_failure */
|
||||
client_expect_confirm(id, "X11 forwarding",
|
||||
client_expect_confirm(ssh, id, "X11 forwarding",
|
||||
CONFIRM_WARN);
|
||||
}
|
||||
}
|
||||
|
||||
if (cctx->want_agent_fwd && options.forward_agent) {
|
||||
debug("Requesting authentication agent forwarding.");
|
||||
channel_request_start(id, "auth-agent-req@openssh.com", 0);
|
||||
channel_request_start(ssh, id, "auth-agent-req@openssh.com", 0);
|
||||
packet_send();
|
||||
}
|
||||
|
||||
client_session2_setup(id, cctx->want_tty, cctx->want_subsys,
|
||||
client_session2_setup(ssh, id, cctx->want_tty, cctx->want_subsys,
|
||||
cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env);
|
||||
|
||||
debug3("%s: sending success reply", __func__);
|
||||
@ -1401,7 +1430,7 @@ mux_session_confirm(int id, int success, void *arg)
|
||||
|
||||
done:
|
||||
/* Send reply */
|
||||
buffer_put_string(&cc->output, buffer_ptr(&reply), buffer_len(&reply));
|
||||
buffer_put_string(cc->output, buffer_ptr(&reply), buffer_len(&reply));
|
||||
buffer_free(&reply);
|
||||
|
||||
if (cc->mux_pause <= 0)
|
||||
@ -1570,31 +1599,38 @@ mux_client_hello_exchange(int fd)
|
||||
{
|
||||
Buffer m;
|
||||
u_int type, ver;
|
||||
int ret = -1;
|
||||
|
||||
buffer_init(&m);
|
||||
buffer_put_int(&m, MUX_MSG_HELLO);
|
||||
buffer_put_int(&m, SSHMUX_VER);
|
||||
/* no extensions */
|
||||
|
||||
if (mux_client_write_packet(fd, &m) != 0)
|
||||
fatal("%s: write packet: %s", __func__, strerror(errno));
|
||||
if (mux_client_write_packet(fd, &m) != 0) {
|
||||
debug("%s: write packet: %s", __func__, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer_clear(&m);
|
||||
|
||||
/* Read their HELLO */
|
||||
if (mux_client_read_packet(fd, &m) != 0) {
|
||||
buffer_free(&m);
|
||||
return -1;
|
||||
debug("%s: read packet failed", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = buffer_get_int(&m);
|
||||
if (type != MUX_MSG_HELLO)
|
||||
fatal("%s: expected HELLO (%u) received %u",
|
||||
if (type != MUX_MSG_HELLO) {
|
||||
error("%s: expected HELLO (%u) received %u",
|
||||
__func__, MUX_MSG_HELLO, type);
|
||||
goto out;
|
||||
}
|
||||
ver = buffer_get_int(&m);
|
||||
if (ver != SSHMUX_VER)
|
||||
fatal("Unsupported multiplexing protocol version %d "
|
||||
if (ver != SSHMUX_VER) {
|
||||
error("Unsupported multiplexing protocol version %d "
|
||||
"(expected %d)", ver, SSHMUX_VER);
|
||||
goto out;
|
||||
}
|
||||
debug2("%s: master version %u", __func__, ver);
|
||||
/* No extensions are presently defined */
|
||||
while (buffer_len(&m) > 0) {
|
||||
@ -1605,8 +1641,11 @@ mux_client_hello_exchange(int fd)
|
||||
free(name);
|
||||
free(value);
|
||||
}
|
||||
/* success */
|
||||
ret = 0;
|
||||
out:
|
||||
buffer_free(&m);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u_int
|
||||
@ -1962,7 +2001,7 @@ mux_client_request_session(int fd)
|
||||
leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
|
||||
|
||||
if (muxclient_terminate) {
|
||||
debug2("Exiting on signal %d", muxclient_terminate);
|
||||
debug2("Exiting on signal: %s", strsignal(muxclient_terminate));
|
||||
exitval = 255;
|
||||
} else if (!exitval_seen) {
|
||||
debug2("Control master terminated unexpectedly");
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: myproposal.h,v 1.54 2016/09/28 16:33:07 djm Exp $ */
|
||||
/* $OpenBSD: myproposal.h,v 1.55 2017/05/07 23:13:42 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
@ -121,8 +121,7 @@
|
||||
"aes128-ctr,aes192-ctr,aes256-ctr" \
|
||||
AESGCM_CIPHER_MODES
|
||||
|
||||
#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT "," \
|
||||
"aes128-cbc,aes192-cbc,aes256-cbc"
|
||||
#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT
|
||||
|
||||
#define KEX_SERVER_MAC \
|
||||
"umac-64-etm@openssh.com," \
|
||||
|
385
nchan.c
385
nchan.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */
|
||||
/* $OpenBSD: nchan.c,v 1.67 2017/09/12 06:35:32 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -33,9 +33,9 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "openbsd-compat/sys-queue.h"
|
||||
#include "ssh1.h"
|
||||
#include "ssh2.h"
|
||||
#include "buffer.h"
|
||||
#include "sshbuf.h"
|
||||
#include "ssherr.h"
|
||||
#include "packet.h"
|
||||
#include "channels.h"
|
||||
#include "compat.h"
|
||||
@ -74,18 +74,15 @@
|
||||
/*
|
||||
* ACTIONS: should never update the channel states
|
||||
*/
|
||||
static void chan_send_ieof1(Channel *);
|
||||
static void chan_send_oclose1(Channel *);
|
||||
static void chan_send_close2(Channel *);
|
||||
static void chan_send_eof2(Channel *);
|
||||
static void chan_send_eow2(Channel *);
|
||||
static void chan_send_eof2(struct ssh *, Channel *);
|
||||
static void chan_send_eow2(struct ssh *, Channel *);
|
||||
|
||||
/* helper */
|
||||
static void chan_shutdown_write(Channel *);
|
||||
static void chan_shutdown_read(Channel *);
|
||||
static void chan_shutdown_write(struct ssh *, Channel *);
|
||||
static void chan_shutdown_read(struct ssh *, Channel *);
|
||||
|
||||
static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
|
||||
static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
|
||||
static const char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
|
||||
static const char *istates[] = { "open", "drain", "wait_oclose", "closed" };
|
||||
|
||||
static void
|
||||
chan_set_istate(Channel *c, u_int next)
|
||||
@ -96,6 +93,7 @@ chan_set_istate(Channel *c, u_int next)
|
||||
istates[next]);
|
||||
c->istate = next;
|
||||
}
|
||||
|
||||
static void
|
||||
chan_set_ostate(Channel *c, u_int next)
|
||||
{
|
||||
@ -106,41 +104,13 @@ chan_set_ostate(Channel *c, u_int next)
|
||||
c->ostate = next;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH1 specific implementation of event functions
|
||||
*/
|
||||
|
||||
static void
|
||||
chan_rcvd_oclose1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd oclose", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
/* both local read_failed and remote write_failed */
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: rcvd_oclose for istate %d",
|
||||
c->self, c->istate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_read_failed(Channel *c)
|
||||
chan_read_failed(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: read failed", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_shutdown_read(ssh, c);
|
||||
chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
|
||||
break;
|
||||
default:
|
||||
@ -149,25 +119,21 @@ chan_read_failed(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chan_ibuf_empty(Channel *c)
|
||||
chan_ibuf_empty(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: ibuf empty", c->self);
|
||||
if (buffer_len(&c->input)) {
|
||||
if (sshbuf_len(c->input)) {
|
||||
error("channel %d: chan_ibuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
if (compat20) {
|
||||
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
|
||||
chan_send_eof2(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
} else {
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
|
||||
}
|
||||
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
|
||||
chan_send_eof2(ssh, c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: chan_ibuf_empty for istate %d",
|
||||
@ -175,58 +141,19 @@ chan_ibuf_empty(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_ieof1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd ieof", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: rcvd_ieof for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_write_failed1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
chan_shutdown_write(c);
|
||||
chan_send_oclose1(c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
chan_send_oclose1(c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chan_obuf_empty(Channel *c)
|
||||
chan_obuf_empty(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: obuf empty", c->self);
|
||||
if (buffer_len(&c->output)) {
|
||||
if (sshbuf_len(c->output)) {
|
||||
error("channel %d: chan_obuf_empty for non empty buffer",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
if (!compat20)
|
||||
chan_send_oclose1(c);
|
||||
chan_shutdown_write(ssh, c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
@ -235,47 +162,107 @@ chan_obuf_empty(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_ieof1(Channel *c)
|
||||
|
||||
void
|
||||
chan_rcvd_eow(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: send ieof", c->self);
|
||||
debug2("channel %d: rcvd eow", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send ieof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send oclose", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
buffer_clear(&c->output);
|
||||
packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send oclose for ostate %d",
|
||||
c->self, c->ostate);
|
||||
chan_shutdown_read(ssh, c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the same for SSH2
|
||||
*/
|
||||
static void
|
||||
chan_rcvd_close2(Channel *c)
|
||||
chan_send_eof2(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug2("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
if (!c->have_remote_id)
|
||||
fatal("%s: channel %d: no remote_id",
|
||||
__func__, c->self);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EOF)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
|
||||
c->flags |= CHAN_EOF_SENT;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_send_close2(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug2("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: already sent close", c->self);
|
||||
} else {
|
||||
if (!c->have_remote_id)
|
||||
fatal("%s: channel %d: no remote_id",
|
||||
__func__, c->self);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_CLOSE)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_send_eow2(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
int r;
|
||||
|
||||
debug2("channel %d: send eow", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
error("channel %d: must not sent eow on closed output",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
if (!(datafellows & SSH_NEW_OPENSSH))
|
||||
return;
|
||||
if (!c->have_remote_id)
|
||||
fatal("%s: channel %d: no remote_id", __func__, c->self);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_REQUEST)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "eow@openssh.com")) != 0 ||
|
||||
(r = sshpkt_put_u8(ssh, 0)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: send CHANNEL_EOF: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
/* shared */
|
||||
|
||||
void
|
||||
chan_rcvd_ieof(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eof", c->self);
|
||||
c->flags |= CHAN_EOF_RCVD;
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN)
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
|
||||
sshbuf_len(c->output) == 0 &&
|
||||
!CHANNEL_EFD_OUTPUT_ACTIVE(c))
|
||||
chan_obuf_empty(ssh, c);
|
||||
}
|
||||
|
||||
void
|
||||
chan_rcvd_oclose(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd close", c->self);
|
||||
if (!(c->flags & CHAN_LOCAL)) {
|
||||
@ -301,46 +288,27 @@ chan_rcvd_close2(Channel *c)
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_shutdown_read(ssh, c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
if (!(c->flags & CHAN_LOCAL))
|
||||
chan_send_eof2(c);
|
||||
chan_send_eof2(ssh, c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chan_rcvd_eow(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eow", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_eof2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eof", c->self);
|
||||
c->flags |= CHAN_EOF_RCVD;
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN)
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
}
|
||||
static void
|
||||
chan_write_failed2(Channel *c)
|
||||
chan_write_failed(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
debug2("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
chan_shutdown_write(ssh, c);
|
||||
if (strcmp(c->ctype, "session") == 0)
|
||||
chan_send_eow2(c);
|
||||
chan_send_eow2(ssh, c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
@ -349,97 +317,15 @@ chan_write_failed2(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eof2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH2_MSG_CHANNEL_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_EOF_SENT;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_close2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: already sent close", c->self);
|
||||
} else {
|
||||
packet_start(SSH2_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eow2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eow", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
error("channel %d: must not sent eow on closed output",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
if (!(datafellows & SSH_NEW_OPENSSH))
|
||||
return;
|
||||
packet_start(SSH2_MSG_CHANNEL_REQUEST);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_cstring("eow@openssh.com");
|
||||
packet_put_char(0);
|
||||
packet_send();
|
||||
}
|
||||
|
||||
/* shared */
|
||||
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_rcvd_eof2(c);
|
||||
else
|
||||
chan_rcvd_ieof1(c);
|
||||
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
|
||||
buffer_len(&c->output) == 0 &&
|
||||
!CHANNEL_EFD_OUTPUT_ACTIVE(c))
|
||||
chan_obuf_empty(c);
|
||||
}
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_rcvd_close2(c);
|
||||
else
|
||||
chan_rcvd_oclose1(c);
|
||||
}
|
||||
void
|
||||
chan_write_failed(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_write_failed2(c);
|
||||
else
|
||||
chan_write_failed1(c);
|
||||
}
|
||||
|
||||
void
|
||||
chan_mark_dead(Channel *c)
|
||||
chan_mark_dead(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
c->type = SSH_CHANNEL_ZOMBIE;
|
||||
}
|
||||
|
||||
int
|
||||
chan_is_dead(Channel *c, int do_send)
|
||||
chan_is_dead(struct ssh *ssh, Channel *c, int do_send)
|
||||
{
|
||||
if (c->type == SSH_CHANNEL_ZOMBIE) {
|
||||
debug2("channel %d: zombie", c->self);
|
||||
@ -447,16 +333,12 @@ chan_is_dead(Channel *c, int do_send)
|
||||
}
|
||||
if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
|
||||
return 0;
|
||||
if (!compat20) {
|
||||
debug2("channel %d: is dead", c->self);
|
||||
return 1;
|
||||
}
|
||||
if ((datafellows & SSH_BUG_EXTEOF) &&
|
||||
c->extended_usage == CHAN_EXTENDED_WRITE &&
|
||||
c->efd != -1 &&
|
||||
buffer_len(&c->extended) > 0) {
|
||||
debug2("channel %d: active efd: %d len %d",
|
||||
c->self, c->efd, buffer_len(&c->extended));
|
||||
sshbuf_len(c->extended) > 0) {
|
||||
debug2("channel %d: active efd: %d len %zu",
|
||||
c->self, c->efd, sshbuf_len(c->extended));
|
||||
return 0;
|
||||
}
|
||||
if (c->flags & CHAN_LOCAL) {
|
||||
@ -465,7 +347,7 @@ chan_is_dead(Channel *c, int do_send)
|
||||
}
|
||||
if (!(c->flags & CHAN_CLOSE_SENT)) {
|
||||
if (do_send) {
|
||||
chan_send_close2(c);
|
||||
chan_send_close2(ssh, c);
|
||||
} else {
|
||||
/* channel would be dead if we sent a close */
|
||||
if (c->flags & CHAN_CLOSE_RCVD) {
|
||||
@ -485,10 +367,10 @@ chan_is_dead(Channel *c, int do_send)
|
||||
|
||||
/* helper */
|
||||
static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
chan_shutdown_write(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
buffer_clear(&c->output);
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
sshbuf_reset(c->output);
|
||||
if (c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug2("channel %d: close_write", c->self);
|
||||
@ -498,16 +380,17 @@ chan_shutdown_write(Channel *c)
|
||||
"shutdown() failed for fd %d: %.100s",
|
||||
c->self, c->sock, strerror(errno));
|
||||
} else {
|
||||
if (channel_close_fd(&c->wfd) < 0)
|
||||
if (channel_close_fd(ssh, &c->wfd) < 0)
|
||||
logit("channel %d: chan_shutdown_write: "
|
||||
"close() failed for fd %d: %.100s",
|
||||
c->self, c->wfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_shutdown_read(Channel *c)
|
||||
chan_shutdown_read(struct ssh *ssh, Channel *c)
|
||||
{
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
if (c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
debug2("channel %d: close_read", c->self);
|
||||
if (c->sock != -1) {
|
||||
@ -523,7 +406,7 @@ chan_shutdown_read(Channel *c)
|
||||
c->self, c->sock, c->istate, c->ostate,
|
||||
strerror(errno));
|
||||
} else {
|
||||
if (channel_close_fd(&c->rfd) < 0)
|
||||
if (channel_close_fd(ssh, &c->rfd) < 0)
|
||||
logit("channel %d: chan_shutdown_read: "
|
||||
"close() failed for fd %d: %.100s",
|
||||
c->self, c->rfd, strerror(errno));
|
||||
|
20
opacket.c
20
opacket.c
@ -74,16 +74,6 @@ ssh_packet_put_raw(struct ssh *ssh, const void *buf, u_int len)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
void
|
||||
ssh_packet_put_bignum(struct ssh *ssh, BIGNUM * value)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshpkt_put_bignum1(ssh, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
void
|
||||
@ -150,16 +140,6 @@ ssh_packet_get_int64(struct ssh *ssh)
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef WITH_SSH1
|
||||
void
|
||||
ssh_packet_get_bignum(struct ssh *ssh, BIGNUM * value)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = sshpkt_get_bignum1(ssh, value)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
void
|
||||
|
10
opacket.h
10
opacket.h
@ -6,7 +6,6 @@ void ssh_packet_start(struct ssh *, u_char);
|
||||
void ssh_packet_put_char(struct ssh *, int ch);
|
||||
void ssh_packet_put_int(struct ssh *, u_int value);
|
||||
void ssh_packet_put_int64(struct ssh *, u_int64_t value);
|
||||
void ssh_packet_put_bignum(struct ssh *, BIGNUM * value);
|
||||
void ssh_packet_put_bignum2(struct ssh *, BIGNUM * value);
|
||||
void ssh_packet_put_ecpoint(struct ssh *, const EC_GROUP *, const EC_POINT *);
|
||||
void ssh_packet_put_string(struct ssh *, const void *buf, u_int len);
|
||||
@ -17,7 +16,6 @@ void ssh_packet_send(struct ssh *);
|
||||
u_int ssh_packet_get_char(struct ssh *);
|
||||
u_int ssh_packet_get_int(struct ssh *);
|
||||
u_int64_t ssh_packet_get_int64(struct ssh *);
|
||||
void ssh_packet_get_bignum(struct ssh *, BIGNUM * value);
|
||||
void ssh_packet_get_bignum2(struct ssh *, BIGNUM * value);
|
||||
void ssh_packet_get_ecpoint(struct ssh *, const EC_GROUP *, EC_POINT *);
|
||||
void *ssh_packet_get_string(struct ssh *, u_int *length_ptr);
|
||||
@ -62,8 +60,6 @@ void packet_read_expect(int expected_type);
|
||||
ssh_packet_get_protocol_flags(active_state)
|
||||
#define packet_start_compression(level) \
|
||||
ssh_packet_start_compression(active_state, (level))
|
||||
#define packet_set_encryption_key(key, keylen, number) \
|
||||
ssh_packet_set_encryption_key(active_state, (key), (keylen), (number))
|
||||
#define packet_start(type) \
|
||||
ssh_packet_start(active_state, (type))
|
||||
#define packet_put_char(value) \
|
||||
@ -78,8 +74,6 @@ void packet_read_expect(int expected_type);
|
||||
ssh_packet_put_cstring(active_state, (str))
|
||||
#define packet_put_raw(buf, len) \
|
||||
ssh_packet_put_raw(active_state, (buf), (len))
|
||||
#define packet_put_bignum(value) \
|
||||
ssh_packet_put_bignum(active_state, (value))
|
||||
#define packet_put_bignum2(value) \
|
||||
ssh_packet_put_bignum2(active_state, (value))
|
||||
#define packet_send() \
|
||||
@ -88,8 +82,6 @@ void packet_read_expect(int expected_type);
|
||||
ssh_packet_read(active_state)
|
||||
#define packet_get_int64() \
|
||||
ssh_packet_get_int64(active_state)
|
||||
#define packet_get_bignum(value) \
|
||||
ssh_packet_get_bignum(active_state, (value))
|
||||
#define packet_get_bignum2(value) \
|
||||
ssh_packet_get_bignum2(active_state, (value))
|
||||
#define packet_remaining() \
|
||||
@ -157,5 +149,7 @@ void packet_disconnect(const char *, ...)
|
||||
ssh_packet_set_mux(active_state)
|
||||
#define packet_get_mux() \
|
||||
ssh_packet_get_mux(active_state)
|
||||
#define packet_clear_keys() \
|
||||
ssh_packet_clear_keys(active_state)
|
||||
|
||||
#endif /* _OPACKET_H */
|
||||
|
@ -16,9 +16,9 @@ RANLIB=@RANLIB@
|
||||
INSTALL=@INSTALL@
|
||||
LDFLAGS=-L. @LDFLAGS@
|
||||
|
||||
OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strcasestr.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o
|
||||
OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o recallocarray.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strcasestr.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o freezero.o
|
||||
|
||||
COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o
|
||||
COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-getpagesize.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-malloc.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o
|
||||
|
||||
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
|
||||
|
||||
|
@ -27,6 +27,12 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef HAVE_ERR
|
||||
void
|
||||
err(int r, const char *fmt, ...)
|
||||
|
23
openbsd-compat/bsd-getpagesize.c
Normal file
23
openbsd-compat/bsd-getpagesize.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* Placed in the public domain */
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
|
||||
int
|
||||
getpagesize(void)
|
||||
{
|
||||
#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
|
||||
long r = sysconf(_SC_PAGESIZE);
|
||||
if (r > 0 && r < INT_MAX)
|
||||
return (int)r;
|
||||
#endif
|
||||
/*
|
||||
* This is at the lower end of common values and appropriate for
|
||||
* our current use of getpagesize() in recallocarray().
|
||||
*/
|
||||
return 4096;
|
||||
}
|
||||
|
||||
#endif /* HAVE_GETPAGESIZE */
|
55
openbsd-compat/bsd-malloc.c
Normal file
55
openbsd-compat/bsd-malloc.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Darren Tucker (dtucker at zip com au).
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#undef malloc
|
||||
#undef calloc
|
||||
#undef realloc
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(HAVE_MALLOC) && HAVE_MALLOC == 0
|
||||
void *
|
||||
rpl_malloc(size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
return malloc(size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CALLOC) && HAVE_CALLOC == 0
|
||||
void *
|
||||
rpl_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
if (nmemb == 0)
|
||||
nmemb = 1;
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_REALLOC) && HAVE_REALLOC == 0
|
||||
void *
|
||||
rpl_realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
#endif
|
@ -104,6 +104,16 @@ const char *strerror(int e)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STRSIGNAL)
|
||||
char *strsignal(int sig)
|
||||
{
|
||||
static char buf[16];
|
||||
|
||||
(void)snprintf(buf, sizeof(buf), "%d", sig);
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_UTIMES
|
||||
int utimes(char *filename, struct timeval *tvp)
|
||||
{
|
||||
|
@ -49,6 +49,10 @@ int setegid(uid_t);
|
||||
const char *strerror(int);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STRSIGNAL)
|
||||
char *strsignal(int);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_SETLINEBUF)
|
||||
#define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0))
|
||||
#endif
|
||||
|
@ -20,6 +20,8 @@
|
||||
void
|
||||
explicit_bzero(void *p, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
(void)memset_s(p, n, 0, n);
|
||||
}
|
||||
|
||||
@ -34,6 +36,8 @@ static void (* volatile ssh_bzero)(void *, size_t) = bzero;
|
||||
void
|
||||
explicit_bzero(void *p, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
/*
|
||||
* clang -fsanitize=memory needs to intercept memset-like functions
|
||||
* to correctly detect memory initialisation. Make sure one is called
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */
|
||||
/* $OpenBSD: fmt_scaled.c,v 1.16 2017/03/16 02:40:46 dtucker Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
|
||||
@ -125,22 +125,30 @@ scan_scaled(char *scaled, long long *result)
|
||||
/* ignore extra fractional digits */
|
||||
continue;
|
||||
fract_digits++; /* for later scaling */
|
||||
if (fpart >= LLONG_MAX / 10) {
|
||||
if (fpart > LLONG_MAX / 10) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
fpart *= 10;
|
||||
if (i > LLONG_MAX - fpart) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
fpart += i;
|
||||
} else { /* normal digit */
|
||||
if (++ndigits >= MAX_DIGITS) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if (whole >= LLONG_MAX / 10) {
|
||||
if (whole > LLONG_MAX / 10) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
whole *= 10;
|
||||
if (i > LLONG_MAX - whole) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
whole += i;
|
||||
}
|
||||
}
|
||||
@ -170,7 +178,9 @@ scan_scaled(char *scaled, long long *result)
|
||||
}
|
||||
scale_fact = scale_factors[i];
|
||||
|
||||
if (whole >= LLONG_MAX / scale_fact) {
|
||||
/* check for overflow and underflow after scaling */
|
||||
if (whole > LLONG_MAX / scale_fact ||
|
||||
whole < LLONG_MIN / scale_fact) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
|
29
openbsd-compat/freezero.c
Normal file
29
openbsd-compat/freezero.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifndef HAVE_FREEZERO
|
||||
|
||||
void
|
||||
freezero(void *ptr, size_t sz)
|
||||
{
|
||||
explicit_bzero(ptr, sz);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FREEZERO */
|
||||
|
@ -60,6 +60,10 @@ int bindresvport_sa(int sd, struct sockaddr *sa);
|
||||
void closefrom(int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETPAGESIZE
|
||||
int getpagesize(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETCWD
|
||||
char *getcwd(char *pt, size_t size);
|
||||
#endif
|
||||
@ -68,6 +72,10 @@ char *getcwd(char *pt, size_t size);
|
||||
void *reallocarray(void *, size_t, size_t);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_RECALLOCARRAY
|
||||
void *recallocarray(void *, size_t, size_t, size_t);
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
|
||||
/*
|
||||
* glibc's FORTIFY_SOURCE can redefine this and prevent us picking up the
|
||||
@ -296,6 +304,10 @@ int bcrypt_pbkdf(const char *, size_t, const u_int8_t *, size_t,
|
||||
void explicit_bzero(void *p, size_t n);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FREEZERO
|
||||
void freezero(void *, size_t);
|
||||
#endif
|
||||
|
||||
char *xcrypt(const char *password, const char *salt);
|
||||
char *shadow_pw(struct passwd *pw);
|
||||
|
||||
|
@ -199,84 +199,81 @@ sys_tun_open(int tun, int mode)
|
||||
*/
|
||||
|
||||
#if defined(SSH_TUN_FILTER)
|
||||
/*
|
||||
* The tunnel forwarding protocol prepends the address family of forwarded
|
||||
* IP packets using OpenBSD's numbers.
|
||||
*/
|
||||
#define OPENBSD_AF_INET 2
|
||||
#define OPENBSD_AF_INET6 24
|
||||
|
||||
int
|
||||
sys_tun_infilter(struct Channel *c, char *buf, int len)
|
||||
sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
|
||||
{
|
||||
int r;
|
||||
size_t len;
|
||||
char *ptr = buf;
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
char rbuf[CHAN_RBUF];
|
||||
struct ip *iph;
|
||||
struct ip iph;
|
||||
#endif
|
||||
u_int32_t *af;
|
||||
char *ptr = buf;
|
||||
int r;
|
||||
#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
|
||||
u_int32_t af;
|
||||
#endif
|
||||
|
||||
/* XXX update channel input filter API to use unsigned length */
|
||||
if (_len < 0)
|
||||
return -1;
|
||||
len = _len;
|
||||
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
|
||||
return (-1);
|
||||
ptr = (char *)&rbuf[0];
|
||||
bcopy(buf, ptr + sizeof(u_int32_t), len);
|
||||
len += sizeof(u_int32_t);
|
||||
af = (u_int32_t *)ptr;
|
||||
|
||||
iph = (struct ip *)(ptr + sizeof(u_int32_t));
|
||||
switch (iph->ip_v) {
|
||||
case 6:
|
||||
*af = AF_INET6;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
*af = AF_INET;
|
||||
break;
|
||||
}
|
||||
if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
|
||||
return -1;
|
||||
/* Determine address family from packet IP header. */
|
||||
memcpy(&iph, buf, sizeof(iph));
|
||||
af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
|
||||
/* Prepend address family to packet using OpenBSD constants */
|
||||
memcpy(rbuf + 4, buf, len);
|
||||
len += 4;
|
||||
POKE_U32(rbuf, af);
|
||||
ptr = rbuf;
|
||||
#elif defined(SSH_TUN_COMPAT_AF)
|
||||
/* Convert existing address family header to OpenBSD value */
|
||||
if (len <= 4)
|
||||
return -1;
|
||||
af = PEEK_U32(buf);
|
||||
/* Put it back */
|
||||
POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
|
||||
#endif
|
||||
|
||||
#if defined(SSH_TUN_COMPAT_AF)
|
||||
if (len < (int)sizeof(u_int32_t))
|
||||
return (-1);
|
||||
|
||||
af = (u_int32_t *)ptr;
|
||||
if (*af == htonl(AF_INET6))
|
||||
*af = htonl(OPENBSD_AF_INET6);
|
||||
else
|
||||
*af = htonl(OPENBSD_AF_INET);
|
||||
#endif
|
||||
|
||||
if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0)
|
||||
if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
return (0);
|
||||
}
|
||||
|
||||
u_char *
|
||||
sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
|
||||
sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
|
||||
u_char **data, size_t *dlen)
|
||||
{
|
||||
u_char *buf;
|
||||
u_int32_t *af;
|
||||
u_int32_t af;
|
||||
int r;
|
||||
size_t xxx_dlen;
|
||||
|
||||
/* XXX new API is incompatible with this signature. */
|
||||
if ((r = sshbuf_get_string(&c->output, data, &xxx_dlen)) != 0)
|
||||
if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
if (dlen != NULL)
|
||||
*dlen = xxx_dlen;
|
||||
if (*dlen < sizeof(*af))
|
||||
if (*dlen < sizeof(af))
|
||||
return (NULL);
|
||||
buf = *data;
|
||||
|
||||
#if defined(SSH_TUN_PREPEND_AF)
|
||||
*dlen -= sizeof(u_int32_t);
|
||||
buf = *data + sizeof(u_int32_t);
|
||||
/* skip address family */
|
||||
*dlen -= sizeof(af);
|
||||
buf = *data + sizeof(af);
|
||||
#elif defined(SSH_TUN_COMPAT_AF)
|
||||
af = ntohl(*(u_int32_t *)buf);
|
||||
if (*af == OPENBSD_AF_INET6)
|
||||
*af = htonl(AF_INET6);
|
||||
else
|
||||
*af = htonl(AF_INET);
|
||||
/* translate address family */
|
||||
af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
|
||||
POKE_U32(buf, af);
|
||||
#endif
|
||||
|
||||
return (buf);
|
||||
}
|
||||
#endif /* SSH_TUN_FILTER */
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define _PORT_TUN_H
|
||||
|
||||
struct Channel;
|
||||
struct ssh;
|
||||
|
||||
#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
|
||||
# define CUSTOM_SYS_TUN_OPEN
|
||||
@ -26,8 +27,8 @@ int sys_tun_open(int, int);
|
||||
|
||||
#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
|
||||
# define SSH_TUN_FILTER
|
||||
int sys_tun_infilter(struct Channel *, char *, int);
|
||||
u_char *sys_tun_outfilter(struct Channel *, u_char **, u_int *);
|
||||
int sys_tun_infilter(struct ssh *, struct Channel *, char *, int);
|
||||
u_char *sys_tun_outfilter(struct ssh *, struct Channel *, u_char **, size_t *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
90
openbsd-compat/recallocarray.c
Normal file
90
openbsd-compat/recallocarray.c
Normal file
@ -0,0 +1,90 @@
|
||||
/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
|
||||
|
||||
#include "includes.h"
|
||||
#ifndef HAVE_RECALLOCARRAY
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
|
||||
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
|
||||
*/
|
||||
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
|
||||
|
||||
void *
|
||||
recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
|
||||
{
|
||||
size_t oldsize, newsize;
|
||||
void *newptr;
|
||||
|
||||
if (ptr == NULL)
|
||||
return calloc(newnmemb, size);
|
||||
|
||||
if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||
newnmemb > 0 && SIZE_MAX / newnmemb < size) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
newsize = newnmemb * size;
|
||||
|
||||
if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||
oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
oldsize = oldnmemb * size;
|
||||
|
||||
/*
|
||||
* Don't bother too much if we're shrinking just a bit,
|
||||
* we do not shrink for series of small steps, oh well.
|
||||
*/
|
||||
if (newsize <= oldsize) {
|
||||
size_t d = oldsize - newsize;
|
||||
|
||||
if (d < oldsize / 2 && d < (size_t)getpagesize()) {
|
||||
memset((char *)ptr + newsize, 0, d);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
newptr = malloc(newsize);
|
||||
if (newptr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (newsize > oldsize) {
|
||||
memcpy(newptr, ptr, oldsize);
|
||||
memset((char *)newptr + oldsize, 0, newsize - oldsize);
|
||||
} else
|
||||
memcpy(newptr, ptr, newsize);
|
||||
|
||||
explicit_bzero(ptr, oldsize);
|
||||
free(ptr);
|
||||
|
||||
return newptr;
|
||||
}
|
||||
/* DEF_WEAK(recallocarray); */
|
||||
|
||||
#endif /* HAVE_RECALLOCARRAY */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user