Compare commits
6 Commits
imports/c8
...
c8
Author | SHA1 | Date |
---|---|---|
eabdullin | 6d16bfdb3c | |
eabdullin | b6a876a1a7 | |
Andrew Lukoshko | f47dcec1ba | |
CentOS Sources | 8098341697 | |
CentOS Sources | d538637397 | |
CentOS Sources | d7c51ce412 |
|
@ -136,18 +136,6 @@ diff -up openssh-7.4p1/serverloop.c.coverity openssh-7.4p1/serverloop.c
|
|||
if (tun != SSH_TUNID_ANY &&
|
||||
auth_opts->force_tun_device != (int)tun)
|
||||
goto done;
|
||||
diff -up openssh-7.4p1/sftp.c.coverity openssh-7.4p1/sftp.c
|
||||
--- openssh-7.4p1/sftp.c.coverity 2016-12-19 05:59:41.000000000 +0100
|
||||
+++ openssh-7.4p1/sftp.c 2016-12-23 16:40:26.903788691 +0100
|
||||
@@ -224,7 +224,7 @@ killchild(int signo)
|
||||
{
|
||||
if (sshpid > 1) {
|
||||
kill(sshpid, SIGTERM);
|
||||
- waitpid(sshpid, NULL, 0);
|
||||
+ (void) waitpid(sshpid, NULL, 0);
|
||||
}
|
||||
|
||||
_exit(1);
|
||||
diff -up openssh-7.4p1/ssh-agent.c.coverity openssh-7.4p1/ssh-agent.c
|
||||
--- openssh-7.4p1/ssh-agent.c.coverity 2016-12-19 05:59:41.000000000 +0100
|
||||
+++ openssh-7.4p1/ssh-agent.c 2016-12-23 16:40:26.903788691 +0100
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8
|
||||
--- openssh-7.2p2/sftp-server.8.sftp-force-mode 2016-03-09 19:04:48.000000000 +0100
|
||||
+++ openssh-7.2p2/sftp-server.8 2016-06-23 16:18:20.463854117 +0200
|
||||
diff --color -ru a/sftp-server.8 b/sftp-server.8
|
||||
--- a/sftp-server.8 2019-04-18 00:52:57.000000000 +0200
|
||||
+++ b/sftp-server.8 2022-06-20 16:03:47.892540068 +0200
|
||||
@@ -38,6 +38,7 @@
|
||||
.Op Fl P Ar blacklisted_requests
|
||||
.Op Fl p Ar whitelisted_requests
|
||||
|
@ -9,21 +9,23 @@ diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8
|
|||
.Ek
|
||||
.Nm
|
||||
.Fl Q Ar protocol_feature
|
||||
@@ -138,6 +139,10 @@ Sets an explicit
|
||||
@@ -138,6 +139,12 @@
|
||||
.Xr umask 2
|
||||
to be applied to newly-created files and directories, instead of the
|
||||
user's default mask.
|
||||
+.It Fl m Ar force_file_perms
|
||||
+Sets explicit file permissions to be applied to newly-created files instead
|
||||
+of the default or client requested mode. Numeric values include:
|
||||
+777, 755, 750, 666, 644, 640, etc. Option -u is ineffective if -m is set.
|
||||
+777, 755, 750, 666, 644, 640, etc. Using both -m and -u switches makes the
|
||||
+umask (-u) effective only for newly created directories and explicit mode (-m)
|
||||
+for newly created files.
|
||||
.El
|
||||
.Pp
|
||||
On some systems,
|
||||
diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
||||
--- openssh-7.2p2/sftp-server.c.sftp-force-mode 2016-06-23 16:18:20.446854128 +0200
|
||||
+++ openssh-7.2p2/sftp-server.c 2016-06-23 16:20:37.950766082 +0200
|
||||
@@ -69,6 +69,10 @@ struct sshbuf *oqueue;
|
||||
diff --color -ru a/sftp-server.c b/sftp-server.c
|
||||
--- a/sftp-server.c 2022-06-20 16:01:26.183793633 +0200
|
||||
+++ b/sftp-server.c 2022-06-20 16:02:12.442690608 +0200
|
||||
@@ -65,6 +65,10 @@
|
||||
/* Version of client */
|
||||
static u_int version;
|
||||
|
||||
|
@ -34,7 +36,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
/* SSH2_FXP_INIT received */
|
||||
static int init_done;
|
||||
|
||||
@@ -683,6 +687,7 @@ process_open(u_int32_t id)
|
||||
@@ -683,6 +687,7 @@
|
||||
Attrib a;
|
||||
char *name;
|
||||
int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE;
|
||||
|
@ -42,7 +44,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
|
||||
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
|
||||
(r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
|
||||
@@ -692,6 +697,10 @@ process_open(u_int32_t id)
|
||||
@@ -692,6 +697,10 @@
|
||||
debug3("request %u: open flags %d", id, pflags);
|
||||
flags = flags_from_portable(pflags);
|
||||
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
|
||||
|
@ -53,7 +55,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
logit("open \"%s\" flags %s mode 0%o",
|
||||
name, string_from_portable(pflags), mode);
|
||||
if (readonly &&
|
||||
@@ -713,6 +722,8 @@ process_open(u_int32_t id)
|
||||
@@ -713,6 +722,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +64,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
if (status != SSH2_FX_OK)
|
||||
send_status(id, status);
|
||||
free(name);
|
||||
@@ -1494,7 +1505,7 @@ sftp_server_usage(void)
|
||||
@@ -1555,7 +1566,7 @@
|
||||
fprintf(stderr,
|
||||
"usage: %s [-ehR] [-d start_directory] [-f log_facility] "
|
||||
"[-l log_level]\n\t[-P blacklisted_requests] "
|
||||
|
@ -71,7 +73,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
" %s -Q protocol_feature\n",
|
||||
__progname, __progname);
|
||||
exit(1);
|
||||
@@ -1520,7 +1531,7 @@ sftp_server_main(int argc, char **argv,
|
||||
@@ -1581,7 +1592,7 @@
|
||||
pw = pwcopy(user_pw);
|
||||
|
||||
while (!skipargs && (ch = getopt(argc, argv,
|
||||
|
@ -80,7 +82,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
|
|||
switch (ch) {
|
||||
case 'Q':
|
||||
if (strcasecmp(optarg, "requests") != 0) {
|
||||
@@ -1580,6 +1591,15 @@ sftp_server_main(int argc, char **argv,
|
||||
@@ -1643,6 +1654,15 @@
|
||||
fatal("Invalid umask \"%s\"", optarg);
|
||||
(void)umask((mode_t)mask);
|
||||
break;
|
||||
|
|
|
@ -32,7 +32,7 @@ diff -up openssh-7.9p1/dh.c.fips openssh-7.9p1/dh.c
|
|||
struct dhgroup dhg;
|
||||
|
||||
+ if (FIPS_mode()) {
|
||||
+ logit("Using arbitrary primes is not allowed in FIPS mode."
|
||||
+ verbose("Using arbitrary primes is not allowed in FIPS mode."
|
||||
+ " Falling back to known groups.");
|
||||
+ return (dh_new_group_fallback(max));
|
||||
+ }
|
||||
|
@ -471,12 +471,53 @@ diff -up openssh-7.9p1/sshkey.c.fips openssh-7.9p1/sshkey.c
|
|||
|
||||
#include "xmss_fast.h"
|
||||
|
||||
@@ -392,7 +394,8 @@ sshkey_calculate_signature(EVP_PKEY *pkey
|
||||
{
|
||||
EVP_MD_CTX *ctx = NULL;
|
||||
u_char *sig = NULL;
|
||||
- int ret, slen, len;
|
||||
+ int ret, slen;
|
||||
+ size_t len;
|
||||
|
||||
if (sigp == NULL || lenp == NULL) {
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
@@ -411,9 +414,10 @@ sshkey_calculate_signature(EVP_PKEY *pkey
|
||||
ret = SSH_ERR_ALLOC_FAIL;
|
||||
goto error;
|
||||
}
|
||||
- if (EVP_SignInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 ||
|
||||
- EVP_SignUpdate(ctx, data, datalen) <= 0 ||
|
||||
- EVP_SignFinal(ctx, sig, &len, pkey) <= 0) {
|
||||
+ if (EVP_DigestSignInit(ctx, NULL, ssh_digest_to_md(hash_alg),
|
||||
+ NULL, pkey) != 1 ||
|
||||
+ EVP_DigestSignUpdate(ctx, data, datalen) != 1 ||
|
||||
+ EVP_DigestSignFinal(ctx, sig, &len) != 1) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto error;
|
||||
}
|
||||
@@ -440,12 +444,13 @@ sshkey_verify_signature(EVP_PKEY *pkey
|
||||
if ((ctx = EVP_MD_CTX_new()) == NULL) {
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
- if (EVP_VerifyInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 ||
|
||||
- EVP_VerifyUpdate(ctx, data, datalen) <= 0) {
|
||||
+ if (EVP_DigestVerifyInit(ctx, NULL, ssh_digest_to_md(hash_alg),
|
||||
+ NULL, pkey) != 1 ||
|
||||
+ EVP_DigestVerifyUpdate(ctx, data, datalen) != 1) {
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto done;
|
||||
}
|
||||
- ret = EVP_VerifyFinal(ctx, sigbuf, siglen, pkey);
|
||||
+ ret = EVP_DigestVerifyFinal(ctx, sigbuf, siglen);
|
||||
switch (ret) {
|
||||
case 1:
|
||||
ret = 0;
|
||||
@@ -1514,6 +1516,8 @@ rsa_generate_private_key(u_int bits, RSA
|
||||
}
|
||||
if (!BN_set_word(f4, RSA_F4) ||
|
||||
!RSA_generate_key_ex(private, bits, f4, NULL)) {
|
||||
+ if (FIPS_mode())
|
||||
+ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__);
|
||||
+ if (FIPS_mode())
|
||||
+ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__);
|
||||
ret = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
@ -515,3 +556,14 @@ diff -up openssh-7.9p1/ssh-keygen.c.fips openssh-7.9p1/ssh-keygen.c
|
|||
if ((fd = mkstemp(prv_tmp)) == -1) {
|
||||
error("Could not save your public key in %s: %s",
|
||||
prv_tmp, strerror(errno));
|
||||
diff -up openssh-8.0p1/sshd_config.xxx openssh-8.0p1/sshd_config
|
||||
--- openssh-8.0p1/sshd_config.xxx 2023-10-30 13:01:59.150952364 +0100
|
||||
+++ openssh-8.0p1/sshd_config 2023-10-30 13:02:56.662231354 +0100
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
HostKey /etc/ssh/ssh_host_rsa_key
|
||||
HostKey /etc/ssh/ssh_host_ecdsa_key
|
||||
+#In FIPS mode Ed25519 keys are not supported, please comment out the next line
|
||||
HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
# Ciphers and keying
|
||||
|
|
|
@ -5,9 +5,9 @@ diff --git a/sshd.c b/sshd.c
|
|||
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
|
||||
cfg, NULL);
|
||||
|
||||
+ /* 'UsePAM no' is not supported in Fedora */
|
||||
+ /* 'UsePAM no' is not supported in RHEL */
|
||||
+ if (! options.use_pam)
|
||||
+ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems.");
|
||||
+ logit("WARNING: 'UsePAM no' is not supported in RHEL and may cause several problems.");
|
||||
+
|
||||
/* Fill in default values for those options not explicitly set. */
|
||||
fill_default_server_options(&options);
|
||||
|
@ -19,7 +19,7 @@ diff --git a/sshd_config b/sshd_config
|
|||
# If you just want the PAM account and session checks to run without
|
||||
# PAM authentication, then enable this but set PasswordAuthentication
|
||||
# and ChallengeResponseAuthentication to 'no'.
|
||||
+# WARNING: 'UsePAM no' is not supported in Fedora and may cause several
|
||||
+# WARNING: 'UsePAM no' is not supported in RHEL and may cause several
|
||||
+# problems.
|
||||
UsePAM yes
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
diff --git a/sftp.c b/sftp.c
|
||||
index b66037f1..54538ff9 100644
|
||||
--- a/sftp.c
|
||||
+++ b/sftp.c
|
||||
@@ -220,9 +220,12 @@ static const struct CMD cmds[] = {
|
||||
static void
|
||||
killchild(int signo)
|
||||
{
|
||||
- if (sshpid > 1) {
|
||||
- kill(sshpid, SIGTERM);
|
||||
- waitpid(sshpid, NULL, 0);
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ pid = sshpid;
|
||||
+ if (pid > 1) {
|
||||
+ kill(pid, SIGTERM);
|
||||
+ (void)waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
_exit(1);
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/msg.c b/msg.c
|
||||
index 99c25cd2..574a566e 100644
|
||||
--- a/msg.c
|
||||
+++ b/msg.c
|
||||
@@ -77,7 +77,7 @@ ssh_msg_recv(int fd, struct sshbuf *m)
|
||||
return (-1);
|
||||
}
|
||||
msg_len = get_u32(buf);
|
||||
- if (msg_len > 256 * 1024) {
|
||||
+ if (msg_len > sshbuf_max_size(m)) {
|
||||
error("ssh_msg_recv: read: bad msg_len %u", msg_len);
|
||||
return (-1);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
diff --git a/serverloop.c b/serverloop.c
|
||||
index e16eabe2..a8c99e2e 100644
|
||||
--- a/serverloop.c
|
||||
+++ b/serverloop.c
|
||||
@@ -184,7 +184,8 @@ client_alive_check(struct ssh *ssh)
|
||||
int r, channel_id;
|
||||
|
||||
/* timeout, check to see how many we have had */
|
||||
- if (ssh_packet_inc_alive_timeouts(ssh) >
|
||||
+ if (options.client_alive_count_max > 0 &&
|
||||
+ ssh_packet_inc_alive_timeouts(ssh) >
|
||||
options.client_alive_count_max) {
|
||||
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
|
||||
logit("Timeout, client not responding from %s", remote_id);
|
||||
diff --git a/sshd_config.5 b/sshd_config.5
|
||||
index d47cb0d2..2cddbd59 100644
|
||||
--- a/sshd_config.5
|
||||
+++ b/sshd_config.5
|
||||
@@ -519,6 +519,9 @@ is set to 15, and
|
||||
.Cm ClientAliveCountMax
|
||||
is left at the default, unresponsive SSH clients
|
||||
will be disconnected after approximately 45 seconds.
|
||||
+Setting a zero
|
||||
+.Cm ClientAliveCountMax
|
||||
+disables connection termination.
|
||||
.It Cm ClientAliveInterval
|
||||
Sets a timeout interval in seconds after which if no data has been received
|
||||
from the client,
|
|
@ -0,0 +1,25 @@
|
|||
diff --color -ru a/sshd.8 b/sshd.8
|
||||
--- a/sshd.8 2022-05-31 13:39:10.231843926 +0200
|
||||
+++ b/sshd.8 2022-05-31 14:34:01.460815420 +0200
|
||||
@@ -78,6 +78,7 @@
|
||||
.Xr sshd_config 5 ) ;
|
||||
command-line options override values specified in the
|
||||
configuration file.
|
||||
+This mechanism is used by systemd to apply system-wide crypto-policies to ssh server.
|
||||
.Nm
|
||||
rereads its configuration file when it receives a hangup signal,
|
||||
.Dv SIGHUP ,
|
||||
@@ -207,6 +208,13 @@
|
||||
rules may be applied by specifying the connection parameters using one or more
|
||||
.Fl C
|
||||
options.
|
||||
+The configuration does not contain the system-wide crypto-policy configuration.
|
||||
+To show the most accurate runtime configuration, use:
|
||||
+.Bd -literal -offset 3n
|
||||
+source /etc/crypto-policies/back-ends/opensshserver.config
|
||||
+source /etc/sysconfig/sshd
|
||||
+sshd -T $OPTIONS $CRYPTO_POLICY
|
||||
+.Ed
|
||||
.It Fl t
|
||||
Test mode.
|
||||
Only check the validity of the configuration file and sanity of the keys.
|
|
@ -1509,7 +1509,7 @@ new file mode 100644
|
|||
index 00000000..0b2f6a56
|
||||
--- /dev/null
|
||||
+++ b/kexgssc.c
|
||||
@@ -0,0 +1,595 @@
|
||||
@@ -0,0 +1,618 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
|
||||
+ *
|
||||
|
@ -1571,7 +1571,7 @@ index 00000000..0b2f6a56
|
|||
+ struct sshbuf *server_blob = NULL;
|
||||
+ struct sshbuf *shared_secret = NULL;
|
||||
+ struct sshbuf *server_host_key_blob = NULL;
|
||||
+ struct sshbuf *empty = sshbuf_new();
|
||||
+ struct sshbuf *empty = NULL;
|
||||
+ u_char *msg;
|
||||
+ int type = 0;
|
||||
+ int first = 1;
|
||||
|
@ -1610,8 +1610,10 @@ index 00000000..0b2f6a56
|
|||
+ default:
|
||||
+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type);
|
||||
+ }
|
||||
+ if (r != 0)
|
||||
+ if (r != 0) {
|
||||
+ ssh_gssapi_delete_ctx(&ctxt);
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
+ token_ptr = GSS_C_NO_BUFFER;
|
||||
+
|
||||
|
@ -1674,11 +1676,16 @@ index 00000000..0b2f6a56
|
|||
+ do {
|
||||
+ type = ssh_packet_read(ssh);
|
||||
+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
|
||||
+ char *tmp = NULL;
|
||||
+ size_t tmp_len = 0;
|
||||
+
|
||||
+ debug("Received KEXGSS_HOSTKEY");
|
||||
+ if (server_host_key_blob)
|
||||
+ fatal("Server host key received more than once");
|
||||
+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
|
||||
+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0)
|
||||
+ fatal("Failed to read server host key: %s", ssh_err(r));
|
||||
+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL)
|
||||
+ fatal("sshbuf_from failed");
|
||||
+ }
|
||||
+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
|
||||
+
|
||||
|
@ -1779,6 +1786,11 @@ index 00000000..0b2f6a56
|
|||
+ if (r != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if ((empty = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ hashlen = sizeof(hash);
|
||||
+ if ((r = kex_gen_hash(
|
||||
+ kex->hash_alg,
|
||||
|
@ -1848,7 +1860,7 @@ index 00000000..0b2f6a56
|
|||
+ size_t hashlen;
|
||||
+ const BIGNUM *pub_key, *dh_p, *dh_g;
|
||||
+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX;
|
||||
+ struct sshbuf *empty = sshbuf_new();
|
||||
+ struct sshbuf *empty = NULL;
|
||||
+ u_char c;
|
||||
+ int r;
|
||||
+
|
||||
|
@ -1960,11 +1972,16 @@ index 00000000..0b2f6a56
|
|||
+ do {
|
||||
+ type = ssh_packet_read(ssh);
|
||||
+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
|
||||
+ char *tmp = NULL;
|
||||
+ size_t tmp_len = 0;
|
||||
+
|
||||
+ debug("Received KEXGSS_HOSTKEY");
|
||||
+ if (server_host_key_blob)
|
||||
+ fatal("Server host key received more than once");
|
||||
+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
|
||||
+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0)
|
||||
+ fatal("sshpkt failed: %s", ssh_err(r));
|
||||
+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL)
|
||||
+ fatal("sshbuf_from failed");
|
||||
+ }
|
||||
+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
|
||||
+
|
||||
|
@ -2040,6 +2057,7 @@ index 00000000..0b2f6a56
|
|||
+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0)
|
||||
+ goto out;
|
||||
+ sshbuf_free(buf);
|
||||
+ buf = NULL;
|
||||
+
|
||||
+ if ((shared_secret = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
|
@ -2048,6 +2066,10 @@ index 00000000..0b2f6a56
|
|||
+
|
||||
+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
|
||||
+ goto out;
|
||||
+ if ((empty = sshbuf_new()) == NULL) {
|
||||
+ r = SSH_ERR_ALLOC_FAIL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
|
||||
+ hashlen = sizeof(hash);
|
||||
|
@ -2094,6 +2116,7 @@ index 00000000..0b2f6a56
|
|||
+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
+ r = kex_send_newkeys(ssh);
|
||||
+out:
|
||||
+ sshbuf_free(buf);
|
||||
+ sshbuf_free(server_blob);
|
||||
+ sshbuf_free(empty);
|
||||
+ explicit_bzero(hash, sizeof(hash));
|
||||
|
@ -2110,7 +2133,7 @@ new file mode 100644
|
|||
index 00000000..60bc02de
|
||||
--- /dev/null
|
||||
+++ b/kexgsss.c
|
||||
@@ -0,0 +1,474 @@
|
||||
@@ -0,0 +1,482 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved.
|
||||
+ *
|
||||
|
@ -2177,7 +2200,7 @@ index 00000000..60bc02de
|
|||
+ */
|
||||
+
|
||||
+ OM_uint32 ret_flags = 0;
|
||||
+ gss_buffer_desc gssbuf, recv_tok, msg_tok;
|
||||
+ gss_buffer_desc gssbuf = {0, NULL}, recv_tok, msg_tok;
|
||||
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
|
||||
+ Gssctxt *ctxt = NULL;
|
||||
+ struct sshbuf *shared_secret = NULL;
|
||||
|
@ -2217,7 +2240,7 @@ index 00000000..60bc02de
|
|||
+ type = ssh_packet_read(ssh);
|
||||
+ switch(type) {
|
||||
+ case SSH2_MSG_KEXGSS_INIT:
|
||||
+ if (client_pubkey != NULL)
|
||||
+ if (gssbuf.value != NULL)
|
||||
+ fatal("Received KEXGSS_INIT after initialising");
|
||||
+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
|
||||
+ &recv_tok)) != 0 ||
|
||||
|
@ -2248,6 +2271,31 @@ index 00000000..60bc02de
|
|||
+ goto out;
|
||||
+
|
||||
+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
|
||||
+
|
||||
+ /* Calculate the hash early so we can free the
|
||||
+ * client_pubkey, which has reference to the parent
|
||||
+ * buffer state->incoming_packet
|
||||
+ */
|
||||
+ hashlen = sizeof(hash);
|
||||
+ if ((r = kex_gen_hash(
|
||||
+ kex->hash_alg,
|
||||
+ kex->client_version,
|
||||
+ kex->server_version,
|
||||
+ kex->peer,
|
||||
+ kex->my,
|
||||
+ empty,
|
||||
+ client_pubkey,
|
||||
+ server_pubkey,
|
||||
+ shared_secret,
|
||||
+ hash, &hashlen)) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ gssbuf.value = hash;
|
||||
+ gssbuf.length = hashlen;
|
||||
+
|
||||
+ sshbuf_free(client_pubkey);
|
||||
+ client_pubkey = NULL;
|
||||
+
|
||||
+ break;
|
||||
+ case SSH2_MSG_KEXGSS_CONTINUE:
|
||||
+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh,
|
||||
|
@ -2269,7 +2317,7 @@ index 00000000..60bc02de
|
|||
+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
|
||||
+ fatal("Zero length token output when incomplete");
|
||||
+
|
||||
+ if (client_pubkey == NULL)
|
||||
+ if (gssbuf.value == NULL)
|
||||
+ fatal("No client public key");
|
||||
+
|
||||
+ if (maj_status & GSS_S_CONTINUE_NEEDED) {
|
||||
|
@ -2298,23 +2346,6 @@ index 00000000..60bc02de
|
|||
+ if (!(ret_flags & GSS_C_INTEG_FLAG))
|
||||
+ fatal("Integrity flag wasn't set");
|
||||
+
|
||||
+ hashlen = sizeof(hash);
|
||||
+ if ((r = kex_gen_hash(
|
||||
+ kex->hash_alg,
|
||||
+ kex->client_version,
|
||||
+ kex->server_version,
|
||||
+ kex->peer,
|
||||
+ kex->my,
|
||||
+ empty,
|
||||
+ client_pubkey,
|
||||
+ server_pubkey,
|
||||
+ shared_secret,
|
||||
+ hash, &hashlen)) != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ gssbuf.value = hash;
|
||||
+ gssbuf.length = hashlen;
|
||||
+
|
||||
+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok))))
|
||||
+ fatal("Couldn't get MIC");
|
||||
+
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
diff --git a/sftp.c b/sftp.c
|
||||
index 04881c83..03c7a5c7 100644
|
||||
--- a/sftp.c
|
||||
+++ b/sftp.c
|
||||
@@ -2527,12 +2527,17 @@ main(int argc, char **argv)
|
||||
port = tmp;
|
||||
break;
|
||||
default:
|
||||
+ /* Try with user, host and path. */
|
||||
if (parse_user_host_path(*argv, &user, &host,
|
||||
- &file1) == -1) {
|
||||
- /* Treat as a plain hostname. */
|
||||
- host = xstrdup(*argv);
|
||||
- host = cleanhostname(host);
|
||||
- }
|
||||
+ &file1) == 0)
|
||||
+ break;
|
||||
+ /* Try with user and host. */
|
||||
+ if (parse_user_host_port(*argv, &user, &host, NULL)
|
||||
+ == 0)
|
||||
+ break;
|
||||
+ /* Treat as a plain hostname. */
|
||||
+ host = xstrdup(*argv);
|
||||
+ host = cleanhostname(host);
|
||||
break;
|
||||
}
|
||||
file2 = *(argv + 1);
|
|
@ -0,0 +1,273 @@
|
|||
diff --color -ruN a/Makefile.in b/Makefile.in
|
||||
--- a/Makefile.in 2022-06-23 11:31:10.168186838 +0200
|
||||
+++ b/Makefile.in 2022-06-23 11:32:19.146513347 +0200
|
||||
@@ -125,7 +125,7 @@
|
||||
monitor.o monitor_wrap.o auth-krb5.o \
|
||||
auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
|
||||
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
|
||||
- sftp-server.o sftp-common.o \
|
||||
+ sftp-server.o sftp-common.o sftp-realpath.o \
|
||||
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
|
||||
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
|
||||
sandbox-solaris.o uidswap.o
|
||||
@@ -217,8 +217,8 @@
|
||||
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
|
||||
$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
|
||||
|
||||
-sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
|
||||
- $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
|
||||
+sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-realpath.o sftp-server.o sftp-server-main.o
|
||||
+ $(LD) -o $@ sftp-server.o sftp-common.o sftp-realpath.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
|
||||
|
||||
sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
|
||||
$(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
|
||||
diff --color -ruN a/sftp-realpath.c b/sftp-realpath.c
|
||||
--- a/sftp-realpath.c 1970-01-01 01:00:00.000000000 +0100
|
||||
+++ b/sftp-realpath.c 2022-06-23 11:35:33.193244873 +0200
|
||||
@@ -0,0 +1,225 @@
|
||||
+/* $OpenBSD: sftp-realpath.c,v 1.2 2021/09/02 21:03:54 deraadt Exp $ */
|
||||
+/*
|
||||
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ * 3. The names of the authors may not be used to endorse or promote
|
||||
+ * products derived from this software without specific prior written
|
||||
+ * permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
+ * SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include "includes.h"
|
||||
+
|
||||
+#include <sys/types.h>
|
||||
+#include <sys/stat.h>
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <stddef.h>
|
||||
+#include <string.h>
|
||||
+#include <unistd.h>
|
||||
+#include <limits.h>
|
||||
+
|
||||
+#ifndef SYMLOOP_MAX
|
||||
+# define SYMLOOP_MAX 32
|
||||
+#endif
|
||||
+
|
||||
+/* XXX rewrite sftp-server to use POSIX realpath and remove this hack */
|
||||
+
|
||||
+char *sftp_realpath(const char *path, char *resolved);
|
||||
+
|
||||
+/*
|
||||
+ * char *realpath(const char *path, char resolved[PATH_MAX]);
|
||||
+ *
|
||||
+ * Find the real name of path, by removing all ".", ".." and symlink
|
||||
+ * components. Returns (resolved) on success, or (NULL) on failure,
|
||||
+ * in which case the path which caused trouble is left in (resolved).
|
||||
+ */
|
||||
+char *
|
||||
+sftp_realpath(const char *path, char *resolved)
|
||||
+{
|
||||
+ struct stat sb;
|
||||
+ char *p, *q, *s;
|
||||
+ size_t left_len, resolved_len;
|
||||
+ unsigned symlinks;
|
||||
+ int serrno, slen, mem_allocated;
|
||||
+ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
|
||||
+
|
||||
+ if (path[0] == '\0') {
|
||||
+ errno = ENOENT;
|
||||
+ return (NULL);
|
||||
+ }
|
||||
+
|
||||
+ serrno = errno;
|
||||
+
|
||||
+ if (resolved == NULL) {
|
||||
+ resolved = malloc(PATH_MAX);
|
||||
+ if (resolved == NULL)
|
||||
+ return (NULL);
|
||||
+ mem_allocated = 1;
|
||||
+ } else
|
||||
+ mem_allocated = 0;
|
||||
+
|
||||
+ symlinks = 0;
|
||||
+ if (path[0] == '/') {
|
||||
+ resolved[0] = '/';
|
||||
+ resolved[1] = '\0';
|
||||
+ if (path[1] == '\0')
|
||||
+ return (resolved);
|
||||
+ resolved_len = 1;
|
||||
+ left_len = strlcpy(left, path + 1, sizeof(left));
|
||||
+ } else {
|
||||
+ if (getcwd(resolved, PATH_MAX) == NULL) {
|
||||
+ if (mem_allocated)
|
||||
+ free(resolved);
|
||||
+ else
|
||||
+ strlcpy(resolved, ".", PATH_MAX);
|
||||
+ return (NULL);
|
||||
+ }
|
||||
+ resolved_len = strlen(resolved);
|
||||
+ left_len = strlcpy(left, path, sizeof(left));
|
||||
+ }
|
||||
+ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Iterate over path components in `left'.
|
||||
+ */
|
||||
+ while (left_len != 0) {
|
||||
+ /*
|
||||
+ * Extract the next path component and adjust `left'
|
||||
+ * and its length.
|
||||
+ */
|
||||
+ p = strchr(left, '/');
|
||||
+ s = p ? p : left + left_len;
|
||||
+ if (s - left >= (ptrdiff_t)sizeof(next_token)) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ memcpy(next_token, left, s - left);
|
||||
+ next_token[s - left] = '\0';
|
||||
+ left_len -= s - left;
|
||||
+ if (p != NULL)
|
||||
+ memmove(left, s + 1, left_len + 1);
|
||||
+ if (resolved[resolved_len - 1] != '/') {
|
||||
+ if (resolved_len + 1 >= PATH_MAX) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ resolved[resolved_len++] = '/';
|
||||
+ resolved[resolved_len] = '\0';
|
||||
+ }
|
||||
+ if (next_token[0] == '\0')
|
||||
+ continue;
|
||||
+ else if (strcmp(next_token, ".") == 0)
|
||||
+ continue;
|
||||
+ else if (strcmp(next_token, "..") == 0) {
|
||||
+ /*
|
||||
+ * Strip the last path component except when we have
|
||||
+ * single "/"
|
||||
+ */
|
||||
+ if (resolved_len > 1) {
|
||||
+ resolved[resolved_len - 1] = '\0';
|
||||
+ q = strrchr(resolved, '/') + 1;
|
||||
+ *q = '\0';
|
||||
+ resolved_len = q - resolved;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Append the next path component and lstat() it. If
|
||||
+ * lstat() fails we still can return successfully if
|
||||
+ * there are no more path components left.
|
||||
+ */
|
||||
+ resolved_len = strlcat(resolved, next_token, PATH_MAX);
|
||||
+ if (resolved_len >= PATH_MAX) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (lstat(resolved, &sb) != 0) {
|
||||
+ if (errno == ENOENT && p == NULL) {
|
||||
+ errno = serrno;
|
||||
+ return (resolved);
|
||||
+ }
|
||||
+ goto err;
|
||||
+ }
|
||||
+ if (S_ISLNK(sb.st_mode)) {
|
||||
+ if (symlinks++ > SYMLOOP_MAX) {
|
||||
+ errno = ELOOP;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ slen = readlink(resolved, symlink, sizeof(symlink) - 1);
|
||||
+ if (slen < 0)
|
||||
+ goto err;
|
||||
+ symlink[slen] = '\0';
|
||||
+ if (symlink[0] == '/') {
|
||||
+ resolved[1] = 0;
|
||||
+ resolved_len = 1;
|
||||
+ } else if (resolved_len > 1) {
|
||||
+ /* Strip the last path component. */
|
||||
+ resolved[resolved_len - 1] = '\0';
|
||||
+ q = strrchr(resolved, '/') + 1;
|
||||
+ *q = '\0';
|
||||
+ resolved_len = q - resolved;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If there are any path components left, then
|
||||
+ * append them to symlink. The result is placed
|
||||
+ * in `left'.
|
||||
+ */
|
||||
+ if (p != NULL) {
|
||||
+ if (symlink[slen - 1] != '/') {
|
||||
+ if (slen + 1 >=
|
||||
+ (ptrdiff_t)sizeof(symlink)) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ symlink[slen] = '/';
|
||||
+ symlink[slen + 1] = 0;
|
||||
+ }
|
||||
+ left_len = strlcat(symlink, left, sizeof(symlink));
|
||||
+ if (left_len >= sizeof(symlink)) {
|
||||
+ errno = ENAMETOOLONG;
|
||||
+ goto err;
|
||||
+ }
|
||||
+ }
|
||||
+ left_len = strlcpy(left, symlink, sizeof(left));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Remove trailing slash except when the resolved pathname
|
||||
+ * is a single "/".
|
||||
+ */
|
||||
+ if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
|
||||
+ resolved[resolved_len - 1] = '\0';
|
||||
+ return (resolved);
|
||||
+
|
||||
+err:
|
||||
+ if (mem_allocated)
|
||||
+ free(resolved);
|
||||
+ return (NULL);
|
||||
+}
|
||||
diff --color -ruN a/sftp-server.c b/sftp-server.c
|
||||
--- a/sftp-server.c 2022-06-23 11:31:10.147186434 +0200
|
||||
+++ b/sftp-server.c 2022-06-23 11:32:19.147513366 +0200
|
||||
@@ -51,6 +51,8 @@
|
||||
#include "sftp.h"
|
||||
#include "sftp-common.h"
|
||||
|
||||
+char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
|
||||
+
|
||||
/* Our verbosity */
|
||||
static LogLevel log_level = SYSLOG_LEVEL_ERROR;
|
||||
|
||||
@@ -1185,7 +1187,7 @@
|
||||
}
|
||||
debug3("request %u: realpath", id);
|
||||
verbose("realpath \"%s\"", path);
|
||||
- if (realpath(path, resolvedname) == NULL) {
|
||||
+ if (sftp_realpath(path, resolvedname) == NULL) {
|
||||
send_status(id, errno_to_portable(errno));
|
||||
} else {
|
||||
Stat s;
|
|
@ -0,0 +1,805 @@
|
|||
diff -up openssh-8.0p1/auth.c.sshdinclude openssh-8.0p1/auth.c
|
||||
--- openssh-8.0p1/auth.c.sshdinclude 2021-10-20 15:18:49.740331098 +0200
|
||||
+++ openssh-8.0p1/auth.c 2021-10-20 15:19:41.324781344 +0200
|
||||
@@ -80,6 +80,7 @@
|
||||
|
||||
/* import */
|
||||
extern ServerOptions options;
|
||||
+extern struct include_list includes;
|
||||
extern int use_privsep;
|
||||
extern struct sshbuf *loginmsg;
|
||||
extern struct passwd *privsep_pw;
|
||||
@@ -573,7 +574,7 @@ getpwnamallow(struct ssh *ssh, const cha
|
||||
|
||||
ci = get_connection_info(ssh, 1, options.use_dns);
|
||||
ci->user = user;
|
||||
- parse_server_match_config(&options, ci);
|
||||
+ parse_server_match_config(&options, &includes, ci);
|
||||
log_change_level(options.log_level);
|
||||
process_permitopen(ssh, &options);
|
||||
|
||||
diff -up openssh-8.0p1/readconf.c.sshdinclude openssh-8.0p1/readconf.c
|
||||
--- openssh-8.0p1/readconf.c.sshdinclude 2021-10-20 15:21:43.541848103 +0200
|
||||
+++ openssh-8.0p1/readconf.c 2021-10-20 15:22:06.302046768 +0200
|
||||
@@ -711,7 +711,7 @@ match_cfg_line(Options *options, char **
|
||||
static void
|
||||
rm_env(Options *options, const char *arg, const char *filename, int linenum)
|
||||
{
|
||||
- int i, j;
|
||||
+ int i, j, onum_send_env = options->num_send_env;
|
||||
char *cp;
|
||||
|
||||
/* Remove an environment variable */
|
||||
@@ -734,6 +734,11 @@ rm_env(Options *options, const char *arg
|
||||
options->num_send_env--;
|
||||
/* NB. don't increment i */
|
||||
}
|
||||
+ if (onum_send_env != options->num_send_env) {
|
||||
+ options->send_env = xrecallocarray(options->send_env,
|
||||
+ onum_send_env, options->num_send_env,
|
||||
+ sizeof(*options->send_env));
|
||||
+ }
|
||||
}
|
||||
|
||||
/*
|
||||
diff -up openssh-8.0p1/regress/Makefile.sshdinclude openssh-8.0p1/regress/Makefile
|
||||
--- openssh-8.0p1/regress/Makefile.sshdinclude 2021-10-20 15:18:49.742331115 +0200
|
||||
+++ openssh-8.0p1/regress/Makefile 2021-10-20 15:19:41.324781344 +0200
|
||||
@@ -82,6 +82,7 @@ LTESTS= connect \
|
||||
principals-command \
|
||||
cert-file \
|
||||
cfginclude \
|
||||
+ servcfginclude \
|
||||
allow-deny-users \
|
||||
authinfo
|
||||
|
||||
@@ -118,7 +119,7 @@ CLEANFILES= *.core actual agent-key.* au
|
||||
sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
|
||||
ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
|
||||
ssh_proxy_envpass sshd.log sshd_config sshd_config_minimal \
|
||||
- sshd_config.orig sshd_proxy sshd_proxy.* sshd_proxy_bak \
|
||||
+ sshd_config.* sshd_proxy sshd_proxy.* sshd_proxy_bak \
|
||||
sshd_proxy_orig t10.out t10.out.pub t12.out t12.out.pub \
|
||||
t2.out t3.out t6.out1 t6.out2 t7.out t7.out.pub \
|
||||
t8.out t8.out.pub t9.out t9.out.pub testdata \
|
||||
diff -up openssh-8.0p1/regress/servcfginclude.sh.sshdinclude openssh-8.0p1/regress/servcfginclude.sh
|
||||
--- openssh-8.0p1/regress/servcfginclude.sh.sshdinclude 2021-10-20 15:18:49.744331132 +0200
|
||||
+++ openssh-8.0p1/regress/servcfginclude.sh 2021-10-20 15:22:06.303046777 +0200
|
||||
@@ -0,0 +1,188 @@
|
||||
+# Placed in the Public Domain.
|
||||
+
|
||||
+tid="server config include"
|
||||
+
|
||||
+cat > $OBJ/sshd_config.i << _EOF
|
||||
+HostKey $OBJ/host.ssh-ed25519
|
||||
+Match host a
|
||||
+ Banner /aa
|
||||
+
|
||||
+Match host b
|
||||
+ Banner /bb
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+
|
||||
+Match host c
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+ Banner /cc
|
||||
+
|
||||
+Match host m
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+
|
||||
+Match Host d
|
||||
+ Banner /dd
|
||||
+
|
||||
+Match Host e
|
||||
+ Banner /ee
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+
|
||||
+Match Host f
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+ Banner /ff
|
||||
+
|
||||
+Match Host n
|
||||
+ Include $OBJ/sshd_config.i.*
|
||||
+_EOF
|
||||
+
|
||||
+cat > $OBJ/sshd_config.i.0 << _EOF
|
||||
+Match host xxxxxx
|
||||
+_EOF
|
||||
+
|
||||
+cat > $OBJ/sshd_config.i.1 << _EOF
|
||||
+Match host a
|
||||
+ Banner /aaa
|
||||
+
|
||||
+Match host b
|
||||
+ Banner /bbb
|
||||
+
|
||||
+Match host c
|
||||
+ Banner /ccc
|
||||
+
|
||||
+Match Host d
|
||||
+ Banner /ddd
|
||||
+
|
||||
+Match Host e
|
||||
+ Banner /eee
|
||||
+
|
||||
+Match Host f
|
||||
+ Banner /fff
|
||||
+_EOF
|
||||
+
|
||||
+cat > $OBJ/sshd_config.i.2 << _EOF
|
||||
+Match host a
|
||||
+ Banner /aaaa
|
||||
+
|
||||
+Match host b
|
||||
+ Banner /bbbb
|
||||
+
|
||||
+Match host c
|
||||
+ Banner /cccc
|
||||
+
|
||||
+Match Host d
|
||||
+ Banner /dddd
|
||||
+
|
||||
+Match Host e
|
||||
+ Banner /eeee
|
||||
+
|
||||
+Match Host f
|
||||
+ Banner /ffff
|
||||
+
|
||||
+Match all
|
||||
+ Banner /xxxx
|
||||
+_EOF
|
||||
+
|
||||
+trial() {
|
||||
+ _host="$1"
|
||||
+ _exp="$2"
|
||||
+ _desc="$3"
|
||||
+ test -z "$_desc" && _desc="test match"
|
||||
+ trace "$_desc host=$_host expect=$_exp"
|
||||
+ ${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i -T \
|
||||
+ -C "host=$_host,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out ||
|
||||
+ fatal "ssh config parse failed: $_desc host=$_host expect=$_exp"
|
||||
+ _got=`grep -i '^banner ' $OBJ/sshd_config.out | awk '{print $2}'`
|
||||
+ if test "x$_exp" != "x$_got" ; then
|
||||
+ fail "$desc_ host $_host include fail: expected $_exp got $_got"
|
||||
+ fi
|
||||
+}
|
||||
+
|
||||
+trial a /aa
|
||||
+trial b /bb
|
||||
+trial c /ccc
|
||||
+trial d /dd
|
||||
+trial e /ee
|
||||
+trial f /fff
|
||||
+trial m /xxxx
|
||||
+trial n /xxxx
|
||||
+trial x none
|
||||
+
|
||||
+# Prepare an included config with an error.
|
||||
+
|
||||
+cat > $OBJ/sshd_config.i.3 << _EOF
|
||||
+Banner xxxx
|
||||
+ Junk
|
||||
+_EOF
|
||||
+
|
||||
+trace "disallow invalid config host=a"
|
||||
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i \
|
||||
+ -C "host=a,user=test,addr=127.0.0.1" 2>/dev/null && \
|
||||
+ fail "sshd include allowed invalid config"
|
||||
+
|
||||
+trace "disallow invalid config host=x"
|
||||
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i \
|
||||
+ -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
|
||||
+ fail "sshd include allowed invalid config"
|
||||
+
|
||||
+rm -f $OBJ/sshd_config.i.*
|
||||
+
|
||||
+# Ensure that a missing include is not fatal.
|
||||
+cat > $OBJ/sshd_config.i << _EOF
|
||||
+HostKey $OBJ/host.ssh-ed25519
|
||||
+Include $OBJ/sshd_config.i.*
|
||||
+Banner /aa
|
||||
+_EOF
|
||||
+
|
||||
+trial a /aa "missing include non-fatal"
|
||||
+
|
||||
+# Ensure that Match/Host in an included config does not affect parent.
|
||||
+cat > $OBJ/sshd_config.i.x << _EOF
|
||||
+Match host x
|
||||
+_EOF
|
||||
+
|
||||
+trial a /aa "included file does not affect match state"
|
||||
+
|
||||
+# Ensure the empty include directive is not accepted
|
||||
+cat > $OBJ/sshd_config.i.x << _EOF
|
||||
+Include
|
||||
+_EOF
|
||||
+
|
||||
+trace "disallow invalid with no argument"
|
||||
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i.x -T \
|
||||
+ -C "host=x,user=test,addr=127.0.0.1" 2>/dev/null && \
|
||||
+ fail "sshd allowed Include with no argument"
|
||||
+
|
||||
+# Ensure the Include before any Match block works as expected (bug #3122)
|
||||
+cat > $OBJ/sshd_config.i << _EOF
|
||||
+Banner /xx
|
||||
+HostKey $OBJ/host.ssh-ed25519
|
||||
+Include $OBJ/sshd_config.i.2
|
||||
+Match host a
|
||||
+ Banner /aaaa
|
||||
+_EOF
|
||||
+cat > $OBJ/sshd_config.i.2 << _EOF
|
||||
+Match host a
|
||||
+ Banner /aa
|
||||
+_EOF
|
||||
+
|
||||
+trace "Include before match blocks"
|
||||
+trial a /aa "included file before match blocks is properly evaluated"
|
||||
+
|
||||
+# Port in included file is correctly interpretted (bug #3169)
|
||||
+cat > $OBJ/sshd_config.i << _EOF
|
||||
+Include $OBJ/sshd_config.i.2
|
||||
+Port 7722
|
||||
+_EOF
|
||||
+cat > $OBJ/sshd_config.i.2 << _EOF
|
||||
+HostKey $OBJ/host.ssh-ed25519
|
||||
+_EOF
|
||||
+
|
||||
+trace "Port after included files"
|
||||
+${SUDO} ${REAL_SSHD} -f $OBJ/sshd_config.i -T \
|
||||
+ -C "host=x,user=test,addr=127.0.0.1" > $OBJ/sshd_config.out || \
|
||||
+ fail "failed to parse Port after included files"
|
||||
+_port=`grep -i '^port ' $OBJ/sshd_config.out | awk '{print $2}'`
|
||||
+if test "x7722" != "x$_port" ; then
|
||||
+ fail "The Port in included file was intertepretted wrongly. Expected 7722, got $_port"
|
||||
+fi
|
||||
+
|
||||
+# cleanup
|
||||
+rm -f $OBJ/sshd_config.i $OBJ/sshd_config.i.* $OBJ/sshd_config.out
|
||||
diff -up openssh-8.0p1/regress/test-exec.sh.sshdinclude openssh-8.0p1/regress/test-exec.sh
|
||||
--- openssh-8.0p1/regress/test-exec.sh.sshdinclude 2021-10-20 15:18:49.746331150 +0200
|
||||
+++ openssh-8.0p1/regress/test-exec.sh 2021-10-20 15:19:41.324781344 +0200
|
||||
@@ -220,6 +220,7 @@ echo "exec ${SSH} -E${TEST_SSH_LOGFILE}
|
||||
|
||||
chmod a+rx $OBJ/ssh-log-wrapper.sh
|
||||
REAL_SSH="$SSH"
|
||||
+REAL_SSHD="$SSHD"
|
||||
SSH="$SSHLOGWRAP"
|
||||
|
||||
# Some test data. We make a copy because some tests will overwrite it.
|
||||
diff -up openssh-8.0p1/servconf.c.sshdinclude openssh-8.0p1/servconf.c
|
||||
--- openssh-8.0p1/servconf.c.sshdinclude 2021-10-20 15:18:49.748331167 +0200
|
||||
+++ openssh-8.0p1/servconf.c 2021-10-20 15:22:06.303046777 +0200
|
||||
@@ -40,6 +40,11 @@
|
||||
#ifdef HAVE_UTIL_H
|
||||
#include <util.h>
|
||||
#endif
|
||||
+#ifdef USE_SYSTEM_GLOB
|
||||
+# include <glob.h>
|
||||
+#else
|
||||
+# include "openbsd-compat/glob.h"
|
||||
+#endif
|
||||
|
||||
#include "openbsd-compat/sys-queue.h"
|
||||
#include "xmalloc.h"
|
||||
@@ -70,6 +75,9 @@ static void add_listen_addr(ServerOption
|
||||
const char *, int);
|
||||
static void add_one_listen_addr(ServerOptions *, const char *,
|
||||
const char *, int);
|
||||
+static void parse_server_config_depth(ServerOptions *options,
|
||||
+ const char *filename, struct sshbuf *conf, struct include_list *includes,
|
||||
+ struct connection_info *connectinfo, int flags, int *activep, int depth);
|
||||
|
||||
/* Use of privilege separation or not */
|
||||
extern int use_privsep;
|
||||
@@ -528,7 +536,7 @@ typedef enum {
|
||||
sAcceptEnv, sSetEnv, sPermitTunnel,
|
||||
sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
|
||||
sUsePrivilegeSeparation, sAllowAgentForwarding,
|
||||
- sHostCertificate,
|
||||
+ sHostCertificate, sInclude,
|
||||
sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
|
||||
sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
|
||||
sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
|
||||
@@ -540,9 +548,11 @@ typedef enum {
|
||||
sDeprecated, sIgnore, sUnsupported
|
||||
} ServerOpCodes;
|
||||
|
||||
-#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */
|
||||
-#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
|
||||
-#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
|
||||
+#define SSHCFG_GLOBAL 0x01 /* allowed in main section of config */
|
||||
+#define SSHCFG_MATCH 0x02 /* allowed inside a Match section */
|
||||
+#define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH)
|
||||
+#define SSHCFG_NEVERMATCH 0x04 /* Match never matches; internal only */
|
||||
+#define SSHCFG_MATCH_ONLY 0x08 /* Match only in conditional blocks; internal only */
|
||||
|
||||
/* Textual representation of the tokens. */
|
||||
static struct {
|
||||
@@ -687,6 +697,7 @@ static struct {
|
||||
{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
|
||||
{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
|
||||
{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
|
||||
+ { "include", sInclude, SSHCFG_ALL },
|
||||
{ "ipqos", sIPQoS, SSHCFG_ALL },
|
||||
{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
|
||||
{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
|
||||
@@ -1259,13 +1270,14 @@ static const struct multistate multistat
|
||||
{ NULL, -1 }
|
||||
};
|
||||
|
||||
-int
|
||||
-process_server_config_line(ServerOptions *options, char *line,
|
||||
+static int
|
||||
+process_server_config_line_depth(ServerOptions *options, char *line,
|
||||
const char *filename, int linenum, int *activep,
|
||||
- struct connection_info *connectinfo)
|
||||
+ struct connection_info *connectinfo, int *inc_flags, int depth,
|
||||
+ struct include_list *includes)
|
||||
{
|
||||
char ch, *cp, ***chararrayptr, **charptr, *arg, *arg2, *p;
|
||||
- int cmdline = 0, *intptr, value, value2, n, port;
|
||||
+ int cmdline = 0, *intptr, value, value2, n, port, oactive, r, found;
|
||||
SyslogFacility *log_facility_ptr;
|
||||
LogLevel *log_level_ptr;
|
||||
ServerOpCodes opcode;
|
||||
@@ -1274,6 +1286,8 @@ process_server_config_line(ServerOptions
|
||||
long long val64;
|
||||
const struct multistate *multistate_ptr;
|
||||
const char *errstr;
|
||||
+ struct include_item *item;
|
||||
+ glob_t gbuf;
|
||||
|
||||
/* Strip trailing whitespace. Allow \f (form feed) at EOL only */
|
||||
if ((len = strlen(line)) == 0)
|
||||
@@ -1300,7 +1314,7 @@ process_server_config_line(ServerOptions
|
||||
cmdline = 1;
|
||||
activep = &cmdline;
|
||||
}
|
||||
- if (*activep && opcode != sMatch)
|
||||
+ if (*activep && opcode != sMatch && opcode != sInclude)
|
||||
debug3("%s:%d setting %s %s", filename, linenum, arg, cp);
|
||||
if (*activep == 0 && !(flags & SSHCFG_MATCH)) {
|
||||
if (connectinfo == NULL) {
|
||||
@@ -1980,15 +1994,112 @@ process_server_config_line(ServerOptions
|
||||
*intptr = value;
|
||||
break;
|
||||
|
||||
+ case sInclude:
|
||||
+ if (cmdline) {
|
||||
+ fatal("Include directive not supported as a "
|
||||
+ "command-line option");
|
||||
+ }
|
||||
+ value = 0;
|
||||
+ while ((arg2 = strdelim(&cp)) != NULL && *arg2 != '\0') {
|
||||
+ value++;
|
||||
+ found = 0;
|
||||
+ if (*arg2 != '/' && *arg2 != '~') {
|
||||
+ xasprintf(&arg, "%s/%s", SSHDIR, arg2);
|
||||
+ } else
|
||||
+ arg = xstrdup(arg2);
|
||||
+
|
||||
+ /*
|
||||
+ * Don't let included files clobber the containing
|
||||
+ * file's Match state.
|
||||
+ */
|
||||
+ oactive = *activep;
|
||||
+
|
||||
+ /* consult cache of include files */
|
||||
+ TAILQ_FOREACH(item, includes, entry) {
|
||||
+ if (strcmp(item->selector, arg) != 0)
|
||||
+ continue;
|
||||
+ if (item->filename != NULL) {
|
||||
+ parse_server_config_depth(options,
|
||||
+ item->filename, item->contents,
|
||||
+ includes, connectinfo,
|
||||
+ (*inc_flags & SSHCFG_MATCH_ONLY
|
||||
+ ? SSHCFG_MATCH_ONLY : (oactive
|
||||
+ ? 0 : SSHCFG_NEVERMATCH)),
|
||||
+ activep, depth + 1);
|
||||
+ }
|
||||
+ found = 1;
|
||||
+ *activep = oactive;
|
||||
+ }
|
||||
+ if (found != 0) {
|
||||
+ free(arg);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* requested glob was not in cache */
|
||||
+ debug2("%s line %d: new include %s",
|
||||
+ filename, linenum, arg);
|
||||
+ if ((r = glob(arg, 0, NULL, &gbuf)) != 0) {
|
||||
+ if (r != GLOB_NOMATCH) {
|
||||
+ fatal("%s line %d: include \"%s\" "
|
||||
+ "glob failed", filename,
|
||||
+ linenum, arg);
|
||||
+ }
|
||||
+ /*
|
||||
+ * If no entry matched then record a
|
||||
+ * placeholder to skip later glob calls.
|
||||
+ */
|
||||
+ debug2("%s line %d: no match for %s",
|
||||
+ filename, linenum, arg);
|
||||
+ item = xcalloc(1, sizeof(*item));
|
||||
+ item->selector = strdup(arg);
|
||||
+ TAILQ_INSERT_TAIL(includes,
|
||||
+ item, entry);
|
||||
+ }
|
||||
+ if (gbuf.gl_pathc > INT_MAX)
|
||||
+ fatal("%s: too many glob results", __func__);
|
||||
+ for (n = 0; n < (int)gbuf.gl_pathc; n++) {
|
||||
+ debug2("%s line %d: including %s",
|
||||
+ filename, linenum, gbuf.gl_pathv[n]);
|
||||
+ item = xcalloc(1, sizeof(*item));
|
||||
+ item->selector = strdup(arg);
|
||||
+ item->filename = strdup(gbuf.gl_pathv[n]);
|
||||
+ if ((item->contents = sshbuf_new()) == NULL) {
|
||||
+ fatal("%s: sshbuf_new failed",
|
||||
+ __func__);
|
||||
+ }
|
||||
+ load_server_config(item->filename,
|
||||
+ item->contents);
|
||||
+ parse_server_config_depth(options,
|
||||
+ item->filename, item->contents,
|
||||
+ includes, connectinfo,
|
||||
+ (*inc_flags & SSHCFG_MATCH_ONLY
|
||||
+ ? SSHCFG_MATCH_ONLY : (oactive
|
||||
+ ? 0 : SSHCFG_NEVERMATCH)),
|
||||
+ activep, depth + 1);
|
||||
+ *activep = oactive;
|
||||
+ TAILQ_INSERT_TAIL(includes, item, entry);
|
||||
+ }
|
||||
+ globfree(&gbuf);
|
||||
+ free(arg);
|
||||
+ }
|
||||
+ if (value == 0) {
|
||||
+ fatal("%s line %d: Include missing filename argument",
|
||||
+ filename, linenum);
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
case sMatch:
|
||||
if (cmdline)
|
||||
fatal("Match directive not supported as a command-line "
|
||||
"option");
|
||||
- value = match_cfg_line(&cp, linenum, connectinfo);
|
||||
+ value = match_cfg_line(&cp, linenum,
|
||||
+ (*inc_flags & SSHCFG_NEVERMATCH ? NULL : connectinfo));
|
||||
if (value < 0)
|
||||
fatal("%s line %d: Bad Match condition", filename,
|
||||
linenum);
|
||||
- *activep = value;
|
||||
+ *activep = (*inc_flags & SSHCFG_NEVERMATCH) ? 0 : value;
|
||||
+ /* The MATCH_ONLY is applicable only until the first match block */
|
||||
+ *inc_flags &= ~SSHCFG_MATCH_ONLY;
|
||||
break;
|
||||
|
||||
case sKerberosUseKuserok:
|
||||
@@ -2275,6 +2386,18 @@ process_server_config_line(ServerOptions
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int
|
||||
+process_server_config_line(ServerOptions *options, char *line,
|
||||
+ const char *filename, int linenum, int *activep,
|
||||
+ struct connection_info *connectinfo, struct include_list *includes)
|
||||
+{
|
||||
+ int inc_flags = 0;
|
||||
+
|
||||
+ return process_server_config_line_depth(options, line, filename,
|
||||
+ linenum, activep, connectinfo, &inc_flags, 0, includes);
|
||||
+}
|
||||
+
|
||||
+
|
||||
/* Reads the server configuration file. */
|
||||
|
||||
void
|
||||
@@ -2313,12 +2436,13 @@ load_server_config(const char *filename,
|
||||
|
||||
void
|
||||
parse_server_match_config(ServerOptions *options,
|
||||
- struct connection_info *connectinfo)
|
||||
+ struct include_list *includes, struct connection_info *connectinfo)
|
||||
{
|
||||
ServerOptions mo;
|
||||
|
||||
initialize_server_options(&mo);
|
||||
- parse_server_config(&mo, "reprocess config", cfg, connectinfo);
|
||||
+ parse_server_config(&mo, "reprocess config", cfg, includes,
|
||||
+ connectinfo);
|
||||
copy_set_server_options(options, &mo, 0);
|
||||
}
|
||||
|
||||
@@ -2464,28 +2588,44 @@ copy_set_server_options(ServerOptions *d
|
||||
#undef M_CP_STROPT
|
||||
#undef M_CP_STRARRAYOPT
|
||||
|
||||
-void
|
||||
-parse_server_config(ServerOptions *options, const char *filename,
|
||||
- struct sshbuf *conf, struct connection_info *connectinfo)
|
||||
+#define SERVCONF_MAX_DEPTH 16
|
||||
+static void
|
||||
+parse_server_config_depth(ServerOptions *options, const char *filename,
|
||||
+ struct sshbuf *conf, struct include_list *includes,
|
||||
+ struct connection_info *connectinfo, int flags, int *activep, int depth)
|
||||
{
|
||||
- int active, linenum, bad_options = 0;
|
||||
+ int linenum, bad_options = 0;
|
||||
char *cp, *obuf, *cbuf;
|
||||
|
||||
- debug2("%s: config %s len %zu", __func__, filename, sshbuf_len(conf));
|
||||
+ if (depth < 0 || depth > SERVCONF_MAX_DEPTH)
|
||||
+ fatal("Too many recursive configuration includes");
|
||||
+
|
||||
+ debug2("%s: config %s len %zu%s", __func__, filename, sshbuf_len(conf),
|
||||
+ (flags & SSHCFG_NEVERMATCH ? " [checking syntax only]" : ""));
|
||||
|
||||
if ((obuf = cbuf = sshbuf_dup_string(conf)) == NULL)
|
||||
fatal("%s: sshbuf_dup_string failed", __func__);
|
||||
- active = connectinfo ? 0 : 1;
|
||||
linenum = 1;
|
||||
while ((cp = strsep(&cbuf, "\n")) != NULL) {
|
||||
- if (process_server_config_line(options, cp, filename,
|
||||
- linenum++, &active, connectinfo) != 0)
|
||||
+ if (process_server_config_line_depth(options, cp,
|
||||
+ filename, linenum++, activep, connectinfo, &flags,
|
||||
+ depth, includes) != 0)
|
||||
bad_options++;
|
||||
}
|
||||
free(obuf);
|
||||
if (bad_options > 0)
|
||||
fatal("%s: terminating, %d bad configuration options",
|
||||
filename, bad_options);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+parse_server_config(ServerOptions *options, const char *filename,
|
||||
+ struct sshbuf *conf, struct include_list *includes,
|
||||
+ struct connection_info *connectinfo)
|
||||
+{
|
||||
+ int active = connectinfo ? 0 : 1;
|
||||
+ parse_server_config_depth(options, filename, conf, includes,
|
||||
+ connectinfo, (connectinfo ? SSHCFG_MATCH_ONLY : 0), &active, 0);
|
||||
process_queued_listen_addrs(options);
|
||||
}
|
||||
|
||||
diff -up openssh-8.0p1/servconf.h.sshdinclude openssh-8.0p1/servconf.h
|
||||
--- openssh-8.0p1/servconf.h.sshdinclude 2021-10-20 15:18:49.750331185 +0200
|
||||
+++ openssh-8.0p1/servconf.h 2021-10-20 15:19:41.325781353 +0200
|
||||
@@ -16,6 +16,8 @@
|
||||
#ifndef SERVCONF_H
|
||||
#define SERVCONF_H
|
||||
|
||||
+#include <sys/queue.h>
|
||||
+
|
||||
#define MAX_PORTS 256 /* Max # ports. */
|
||||
|
||||
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
|
||||
@@ -234,6 +236,15 @@ struct connection_info {
|
||||
* unspecified */
|
||||
};
|
||||
|
||||
+/* List of included files for re-exec from the parsed configuration */
|
||||
+struct include_item {
|
||||
+ char *selector;
|
||||
+ char *filename;
|
||||
+ struct sshbuf *contents;
|
||||
+ TAILQ_ENTRY(include_item) entry;
|
||||
+};
|
||||
+TAILQ_HEAD(include_list, include_item);
|
||||
+
|
||||
|
||||
/*
|
||||
* These are string config options that must be copied between the
|
||||
@@ -273,12 +284,13 @@ struct connection_info *get_connection_i
|
||||
void initialize_server_options(ServerOptions *);
|
||||
void fill_default_server_options(ServerOptions *);
|
||||
int process_server_config_line(ServerOptions *, char *, const char *, int,
|
||||
- int *, struct connection_info *);
|
||||
+ int *, struct connection_info *, struct include_list *includes);
|
||||
void process_permitopen(struct ssh *ssh, ServerOptions *options);
|
||||
void load_server_config(const char *, struct sshbuf *);
|
||||
void parse_server_config(ServerOptions *, const char *, struct sshbuf *,
|
||||
- struct connection_info *);
|
||||
-void parse_server_match_config(ServerOptions *, struct connection_info *);
|
||||
+ struct include_list *includes, struct connection_info *);
|
||||
+void parse_server_match_config(ServerOptions *,
|
||||
+ struct include_list *includes, struct connection_info *);
|
||||
int parse_server_match_testspec(struct connection_info *, char *);
|
||||
int server_match_spec_complete(struct connection_info *);
|
||||
void copy_set_server_options(ServerOptions *, ServerOptions *, int);
|
||||
diff -up openssh-8.0p1/sshd_config.5.sshdinclude openssh-8.0p1/sshd_config.5
|
||||
--- openssh-8.0p1/sshd_config.5.sshdinclude 2021-10-20 15:18:49.754331220 +0200
|
||||
+++ openssh-8.0p1/sshd_config.5 2021-10-20 15:19:41.325781353 +0200
|
||||
@@ -825,7 +825,20 @@ during
|
||||
and use only the system-wide known hosts file
|
||||
.Pa /etc/ssh/known_hosts .
|
||||
The default is
|
||||
-.Cm no .
|
||||
+.Dq no .
|
||||
+.It Cm Include
|
||||
+Include the specified configuration file(s).
|
||||
+Multiple path names may be specified and each pathname may contain
|
||||
+.Xr glob 7
|
||||
+wildcards.
|
||||
+Files without absolute paths are assumed to be in
|
||||
+.Pa /etc/ssh .
|
||||
+A
|
||||
+.Cm Include
|
||||
+directive may appear inside a
|
||||
+.Cm Match
|
||||
+block
|
||||
+to perform conditional inclusion.
|
||||
.It Cm IPQoS
|
||||
Specifies the IPv4 type-of-service or DSCP class for the connection.
|
||||
Accepted values are
|
||||
diff -up openssh-8.0p1/sshd.c.sshdinclude openssh-8.0p1/sshd.c
|
||||
--- openssh-8.0p1/sshd.c.sshdinclude 2021-10-20 15:18:49.752331202 +0200
|
||||
+++ openssh-8.0p1/sshd.c 2021-10-20 15:19:41.325781353 +0200
|
||||
@@ -257,6 +257,9 @@ struct sshauthopt *auth_opts = NULL;
|
||||
/* sshd_config buffer */
|
||||
struct sshbuf *cfg;
|
||||
|
||||
+/* Included files from the configuration file */
|
||||
+struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
|
||||
+
|
||||
/* message to be displayed after login */
|
||||
struct sshbuf *loginmsg;
|
||||
|
||||
@@ -927,30 +930,45 @@ usage(void)
|
||||
static void
|
||||
send_rexec_state(int fd, struct sshbuf *conf)
|
||||
{
|
||||
- struct sshbuf *m;
|
||||
+ struct sshbuf *m = NULL, *inc = NULL;
|
||||
+ struct include_item *item = NULL;
|
||||
int r;
|
||||
|
||||
debug3("%s: entering fd = %d config len %zu", __func__, fd,
|
||||
sshbuf_len(conf));
|
||||
|
||||
+ if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
|
||||
+ fatal("%s: sshbuf_new failed", __func__);
|
||||
+
|
||||
+ /* pack includes into a string */
|
||||
+ TAILQ_FOREACH(item, &includes, entry) {
|
||||
+ if ((r = sshbuf_put_cstring(inc, item->selector)) != 0 ||
|
||||
+ (r = sshbuf_put_cstring(inc, item->filename)) != 0 ||
|
||||
+ (r = sshbuf_put_stringb(inc, item->contents)) != 0)
|
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Protocol from reexec master to child:
|
||||
* string configuration
|
||||
- * string rngseed (only if OpenSSL is not self-seeded)
|
||||
+ * string included_files[] {
|
||||
+ * string selector
|
||||
+ * string filename
|
||||
+ * string contents
|
||||
+ * }
|
||||
+ * string rng_seed (if required)
|
||||
*/
|
||||
- if ((m = sshbuf_new()) == NULL)
|
||||
- fatal("%s: sshbuf_new failed", __func__);
|
||||
- if ((r = sshbuf_put_stringb(m, conf)) != 0)
|
||||
+ if ((r = sshbuf_put_stringb(m, conf)) != 0 ||
|
||||
+ (r = sshbuf_put_stringb(m, inc)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
-
|
||||
#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
|
||||
rexec_send_rng_seed(m);
|
||||
#endif
|
||||
-
|
||||
if (ssh_msg_send(fd, 0, m) == -1)
|
||||
fatal("%s: ssh_msg_send failed", __func__);
|
||||
|
||||
sshbuf_free(m);
|
||||
+ sshbuf_free(inc);
|
||||
|
||||
debug3("%s: done", __func__);
|
||||
}
|
||||
@@ -958,14 +976,15 @@ send_rexec_state(int fd, struct sshbuf *
|
||||
static void
|
||||
recv_rexec_state(int fd, struct sshbuf *conf)
|
||||
{
|
||||
- struct sshbuf *m;
|
||||
+ struct sshbuf *m, *inc;
|
||||
u_char *cp, ver;
|
||||
size_t len;
|
||||
int r;
|
||||
+ struct include_item *item;
|
||||
|
||||
debug3("%s: entering fd = %d", __func__, fd);
|
||||
|
||||
- if ((m = sshbuf_new()) == NULL)
|
||||
+ if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if (ssh_msg_recv(fd, m) == -1)
|
||||
fatal("%s: ssh_msg_recv failed", __func__);
|
||||
@@ -973,14 +992,28 @@ recv_rexec_state(int fd, struct sshbuf *
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
if (ver != 0)
|
||||
fatal("%s: rexec version mismatch", __func__);
|
||||
- if ((r = sshbuf_get_string(m, &cp, &len)) != 0)
|
||||
- fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
- if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
|
||||
+ if ((r = sshbuf_get_string(m, &cp, &len)) != 0 ||
|
||||
+ (r = sshbuf_get_stringb(m, inc)) != 0)
|
||||
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
+
|
||||
#if defined(WITH_OPENSSL) && !defined(OPENSSL_PRNG_ONLY)
|
||||
rexec_recv_rng_seed(m);
|
||||
#endif
|
||||
|
||||
+ if (conf != NULL && (r = sshbuf_put(conf, cp, len)))
|
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
+
|
||||
+ while (sshbuf_len(inc) != 0) {
|
||||
+ item = xcalloc(1, sizeof(*item));
|
||||
+ if ((item->contents = sshbuf_new()) == NULL)
|
||||
+ fatal("%s: sshbuf_new failed", __func__);
|
||||
+ if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 ||
|
||||
+ (r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 ||
|
||||
+ (r = sshbuf_get_stringb(inc, item->contents)) != 0)
|
||||
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
||||
+ TAILQ_INSERT_TAIL(&includes, item, entry);
|
||||
+ }
|
||||
+
|
||||
free(cp);
|
||||
sshbuf_free(m);
|
||||
|
||||
@@ -1661,7 +1694,7 @@ main(int ac, char **av)
|
||||
case 'o':
|
||||
line = xstrdup(optarg);
|
||||
if (process_server_config_line(&options, line,
|
||||
- "command-line", 0, NULL, NULL) != 0)
|
||||
+ "command-line", 0, NULL, NULL, &includes) != 0)
|
||||
exit(1);
|
||||
free(line);
|
||||
break;
|
||||
@@ -1692,7 +1725,7 @@ main(int ac, char **av)
|
||||
SYSLOG_LEVEL_INFO : options.log_level,
|
||||
options.log_facility == SYSLOG_FACILITY_NOT_SET ?
|
||||
SYSLOG_FACILITY_AUTH : options.log_facility,
|
||||
- log_stderr || !inetd_flag);
|
||||
+ log_stderr || !inetd_flag || debug_flag);
|
||||
|
||||
/*
|
||||
* Unset KRB5CCNAME, otherwise the user's session may inherit it from
|
||||
@@ -1725,12 +1758,11 @@ main(int ac, char **av)
|
||||
*/
|
||||
(void)atomicio(vwrite, startup_pipe, "\0", 1);
|
||||
}
|
||||
- }
|
||||
- else if (strcasecmp(config_file_name, "none") != 0)
|
||||
+ } else if (strcasecmp(config_file_name, "none") != 0)
|
||||
load_server_config(config_file_name, cfg);
|
||||
|
||||
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
|
||||
- cfg, NULL);
|
||||
+ cfg, &includes, NULL);
|
||||
|
||||
/* 'UsePAM no' is not supported in RHEL */
|
||||
if (! options.use_pam)
|
||||
@@ -1946,7 +1978,7 @@ main(int ac, char **av)
|
||||
if (connection_info == NULL)
|
||||
connection_info = get_connection_info(ssh, 0, 0);
|
||||
connection_info->test = 1;
|
||||
- parse_server_match_config(&options, connection_info);
|
||||
+ parse_server_match_config(&options, &includes, connection_info);
|
||||
dump_config(&options);
|
||||
}
|
||||
|
||||
diff -up openssh-8.0p1/sshbuf-getput-basic.c.stringb openssh-8.0p1/sshbuf-getput-basic.c
|
||||
--- openssh-8.0p1/sshbuf-getput-basic.c.stringb 2022-12-21 12:18:43.274799163 +0100
|
||||
+++ openssh-8.0p1/sshbuf-getput-basic.c 2022-12-21 12:19:19.758081516 +0100
|
||||
@@ -371,6 +371,9 @@ sshbuf_put_cstring(struct sshbuf *buf, c
|
||||
int
|
||||
sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
|
||||
{
|
||||
+ if (v == NULL)
|
||||
+ return sshbuf_put_string(buf, NULL, 0);
|
||||
+
|
||||
return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
diff --color -ru a/kex.c b/kex.c
|
||||
--- a/kex.c 2022-06-23 10:25:29.529922670 +0200
|
||||
+++ b/kex.c 2022-06-23 10:26:12.911762100 +0200
|
||||
@@ -906,6 +906,18 @@
|
||||
return (1);
|
||||
}
|
||||
|
||||
+/* returns non-zero if proposal contains any algorithm from algs */
|
||||
+static int
|
||||
+has_any_alg(const char *proposal, const char *algs)
|
||||
+{
|
||||
+ char *cp;
|
||||
+
|
||||
+ if ((cp = match_list(proposal, algs, NULL)) == NULL)
|
||||
+ return 0;
|
||||
+ free(cp);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
kex_choose_conf(struct ssh *ssh)
|
||||
{
|
||||
@@ -941,6 +953,16 @@
|
||||
free(ext);
|
||||
}
|
||||
|
||||
+ /* Check whether client supports rsa-sha2 algorithms */
|
||||
+ if (kex->server && (kex->flags & KEX_INITIAL)) {
|
||||
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
|
||||
+ "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com"))
|
||||
+ kex->flags |= KEX_RSA_SHA2_256_SUPPORTED;
|
||||
+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
|
||||
+ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com"))
|
||||
+ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED;
|
||||
+ }
|
||||
+
|
||||
/* Algorithm Negotiation */
|
||||
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
|
||||
sprop[PROPOSAL_KEX_ALGS])) != 0) {
|
||||
diff --color -ru a/kex.h b/kex.h
|
||||
--- a/kex.h 2022-06-23 10:25:29.511922322 +0200
|
||||
+++ b/kex.h 2022-06-23 10:26:12.902761926 +0200
|
||||
@@ -117,6 +117,8 @@
|
||||
|
||||
#define KEX_INIT_SENT 0x0001
|
||||
#define KEX_INITIAL 0x0002
|
||||
+#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */
|
||||
+#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */
|
||||
|
||||
struct sshenc {
|
||||
char *name;
|
||||
diff --color -ru a/serverloop.c b/serverloop.c
|
||||
--- a/serverloop.c 2022-06-23 10:25:29.537922825 +0200
|
||||
+++ b/serverloop.c 2022-06-23 10:26:12.918762235 +0200
|
||||
@@ -736,16 +736,17 @@
|
||||
struct sshbuf *resp = NULL;
|
||||
struct sshbuf *sigbuf = NULL;
|
||||
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
|
||||
- int r, ndx, kexsigtype, use_kexsigtype, success = 0;
|
||||
+ int r, ndx, success = 0;
|
||||
const u_char *blob;
|
||||
+ const char *sigalg, *kex_rsa_sigalg = NULL;
|
||||
u_char *sig = 0;
|
||||
size_t blen, slen;
|
||||
|
||||
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
|
||||
fatal("%s: sshbuf_new", __func__);
|
||||
-
|
||||
- kexsigtype = sshkey_type_plain(
|
||||
- sshkey_type_from_name(ssh->kex->hostkey_alg));
|
||||
+ if (sshkey_type_plain(sshkey_type_from_name(
|
||||
+ ssh->kex->hostkey_alg)) == KEY_RSA)
|
||||
+ kex_rsa_sigalg = ssh->kex->hostkey_alg;
|
||||
while (ssh_packet_remaining(ssh) > 0) {
|
||||
sshkey_free(key);
|
||||
key = NULL;
|
||||
@@ -780,16 +781,24 @@
|
||||
* For RSA keys, prefer to use the signature type negotiated
|
||||
* during KEX to the default (SHA1).
|
||||
*/
|
||||
- use_kexsigtype = kexsigtype == KEY_RSA &&
|
||||
- sshkey_type_plain(key->type) == KEY_RSA;
|
||||
+ sigalg = NULL;
|
||||
+ if (sshkey_type_plain(key->type) == KEY_RSA) {
|
||||
+ if (kex_rsa_sigalg != NULL)
|
||||
+ sigalg = kex_rsa_sigalg;
|
||||
+ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED)
|
||||
+ sigalg = "rsa-sha2-512";
|
||||
+ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED)
|
||||
+ sigalg = "rsa-sha2-256";
|
||||
+ }
|
||||
+ debug3("%s: sign %s key (index %d) using sigalg %s", __func__,
|
||||
+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg);
|
||||
if ((r = sshbuf_put_cstring(sigbuf,
|
||||
"hostkeys-prove-00@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_string(sigbuf,
|
||||
ssh->kex->session_id, ssh->kex->session_id_len)) != 0 ||
|
||||
(r = sshkey_puts(key, sigbuf)) != 0 ||
|
||||
(r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen,
|
||||
- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf),
|
||||
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 ||
|
||||
+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 ||
|
||||
(r = sshbuf_put_string(resp, sig, slen)) != 0) {
|
||||
error("%s: couldn't prepare signature: %s",
|
||||
__func__, ssh_err(r));
|
||||
diff --color -ru a/sshkey.c b/sshkey.c
|
||||
--- a/sshkey.c 2022-06-23 10:25:29.532922728 +0200
|
||||
+++ b/sshkey.c 2022-06-23 10:26:12.914762158 +0200
|
||||
@@ -82,7 +82,6 @@
|
||||
struct sshbuf *buf, enum sshkey_serialize_rep);
|
||||
static int sshkey_from_blob_internal(struct sshbuf *buf,
|
||||
struct sshkey **keyp, int allow_cert);
|
||||
-static int get_sigtype(const u_char *sig, size_t siglen, char **sigtypep);
|
||||
|
||||
/* Supported key types */
|
||||
struct keytype {
|
||||
@@ -2092,7 +2091,8 @@
|
||||
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
|
||||
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
|
||||
goto out;
|
||||
- if ((ret = get_sigtype(sig, slen, &key->cert->signature_type)) != 0)
|
||||
+ if ((ret = sshkey_get_sigtype(sig, slen,
|
||||
+ &key->cert->signature_type)) != 0)
|
||||
goto out;
|
||||
|
||||
/* Success */
|
||||
@@ -2394,8 +2394,8 @@
|
||||
return r;
|
||||
}
|
||||
|
||||
-static int
|
||||
-get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
|
||||
+int
|
||||
+sshkey_get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
|
||||
{
|
||||
int r;
|
||||
struct sshbuf *b = NULL;
|
||||
@@ -2477,7 +2477,7 @@
|
||||
return 0;
|
||||
if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
- if ((r = get_sigtype(sig, siglen, &sigtype)) != 0)
|
||||
+ if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0)
|
||||
return r;
|
||||
r = strcmp(expected_alg, sigtype) == 0;
|
||||
free(sigtype);
|
||||
@@ -2739,7 +2739,7 @@
|
||||
sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
|
||||
goto out;
|
||||
/* Check and update signature_type against what was actually used */
|
||||
- if ((ret = get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
|
||||
+ if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
|
||||
goto out;
|
||||
if (alg != NULL && strcmp(alg, sigtype) != 0) {
|
||||
ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
|
||||
diff --color -ru a/sshkey.h b/sshkey.h
|
||||
--- a/sshkey.h 2022-06-23 10:25:29.521922515 +0200
|
||||
+++ b/sshkey.h 2022-06-23 10:26:12.907762022 +0200
|
||||
@@ -211,6 +211,7 @@
|
||||
const u_char *, size_t, const char *, u_int);
|
||||
int sshkey_check_sigtype(const u_char *, size_t, const char *);
|
||||
const char *sshkey_sigalg_by_name(const char *);
|
||||
+int sshkey_get_sigtype(const u_char *, size_t, char **);
|
||||
|
||||
/* for debug */
|
||||
void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);
|
|
@ -0,0 +1,46 @@
|
|||
diff -up openssh-8.7p1/pathnames.h.kill-scp openssh-8.7p1/pathnames.h
|
||||
--- openssh-8.7p1/pathnames.h.kill-scp 2021-09-16 11:37:57.240171687 +0200
|
||||
+++ openssh-8.7p1/pathnames.h 2021-09-16 11:42:29.183427917 +0200
|
||||
@@ -42,6 +42,7 @@
|
||||
#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key"
|
||||
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
|
||||
#define _PATH_DH_MODULI SSHDIR "/moduli"
|
||||
+#define _PATH_SCP_KILL_SWITCH SSHDIR "/disable_scp"
|
||||
|
||||
#ifndef _PATH_SSH_PROGRAM
|
||||
#define _PATH_SSH_PROGRAM "/usr/bin/ssh"
|
||||
diff -up openssh-8.7p1/scp.1.kill-scp openssh-8.7p1/scp.1
|
||||
--- openssh-8.7p1/scp.1.kill-scp 2021-09-16 12:09:02.646714578 +0200
|
||||
+++ openssh-8.7p1/scp.1 2021-09-16 12:26:49.978628226 +0200
|
||||
@@ -278,6 +278,13 @@ to print debugging messages about their
|
||||
This is helpful in
|
||||
debugging connection, authentication, and configuration problems.
|
||||
.El
|
||||
+.Pp
|
||||
+Usage of SCP protocol can be blocked by creating a world-readable
|
||||
+.Ar /etc/ssh/disable_scp
|
||||
+file. If this file exists, when SCP protocol is in use (either remotely or
|
||||
+via the
|
||||
+.Fl O
|
||||
+option), the program will exit.
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std scp
|
||||
.Sh SEE ALSO
|
||||
diff -up openssh-8.7p1/scp.c.kill-scp openssh-8.7p1/scp.c
|
||||
--- openssh-8.7p1/scp.c.kill-scp 2021-09-16 11:42:56.013650519 +0200
|
||||
+++ openssh-8.7p1/scp.c 2021-09-16 11:53:03.249713836 +0200
|
||||
@@ -596,6 +596,14 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
+ {
|
||||
+ FILE *f = fopen(_PATH_SCP_KILL_SWITCH, "r");
|
||||
+ if (f != NULL) {
|
||||
+ fclose(f);
|
||||
+ fatal("SCP protocol is forbidden via %s", _PATH_SCP_KILL_SWITCH);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if ((pwd = getpwuid(userid = getuid())) == NULL)
|
||||
fatal("unknown user %u", (u_int) userid);
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
diff --git a/auth.c b/auth.c
|
||||
index b8d1040d..0134d694 100644
|
||||
--- a/auth.c
|
||||
+++ b/auth.c
|
||||
@@ -56,6 +56,7 @@
|
||||
# include <paths.h>
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
+#include <grp.h>
|
||||
#ifdef HAVE_LOGIN_H
|
||||
#include <login.h>
|
||||
#endif
|
||||
@@ -2695,6 +2696,12 @@ subprocess(const char *tag, const char *command,
|
||||
}
|
||||
closefrom(STDERR_FILENO + 1);
|
||||
|
||||
+ if (geteuid() == 0 &&
|
||||
+ initgroups(pw->pw_name, pw->pw_gid) == -1) {
|
||||
+ error("%s: initgroups(%s, %u): %s", tag,
|
||||
+ pw->pw_name, (u_int)pw->pw_gid, strerror(errno));
|
||||
+ _exit(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,
|
|
@ -0,0 +1,32 @@
|
|||
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
|
||||
index d29a03b4..d7283136 100644
|
||||
--- a/ssh-keyscan.c
|
||||
+++ b/ssh-keyscan.c
|
||||
@@ -490,6 +490,15 @@ congreet(int s)
|
||||
return;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * Read the server banner as per RFC4253 section 4.2. The "SSH-"
|
||||
+ * protocol identification string may be preceeded by an arbitarily
|
||||
+ * large banner which we must read and ignore. Loop while reading
|
||||
+ * newline-terminated lines until we have one starting with "SSH-".
|
||||
+ * The ID string cannot be longer than 255 characters although the
|
||||
+ * preceeding banner lines may (in which case they'll be discarded
|
||||
+ * in multiple iterations of the outer loop).
|
||||
+ */
|
||||
for (;;) {
|
||||
memset(buf, '\0', sizeof(buf));
|
||||
bufsiz = sizeof(buf);
|
||||
@@ -517,6 +526,11 @@ congreet(int s)
|
||||
conrecycle(s);
|
||||
return;
|
||||
}
|
||||
+ if (cp >= buf + sizeof(buf)) {
|
||||
+ error("%s: greeting exceeds allowable length", c->c_name);
|
||||
+ confree(s);
|
||||
+ return;
|
||||
+ }
|
||||
if (*cp != '\n' && *cp != '\r') {
|
||||
error("%s: bad greeting", c->c_name);
|
||||
confree(s);
|
|
@ -0,0 +1,17 @@
|
|||
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
|
||||
index 6be647ec..ebddf6c3 100644
|
||||
--- a/ssh-pkcs11.c
|
||||
+++ b/ssh-pkcs11.c
|
||||
@@ -1537,10 +1537,8 @@ pkcs11_register_provider(char *provider_id, char *pin,
|
||||
error("dlopen %s failed: %s", provider_module, dlerror());
|
||||
goto fail;
|
||||
}
|
||||
- if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
|
||||
- error("dlsym(C_GetFunctionList) failed: %s", dlerror());
|
||||
- goto fail;
|
||||
- }
|
||||
+ if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
|
||||
+ fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
|
||||
|
||||
p->module->handle = handle;
|
||||
/* setup the pkcs11 callbacks */
|
|
@ -0,0 +1,33 @@
|
|||
diff -u -p -r1.166 auth2.c
|
||||
--- a/auth2.c 8 Mar 2023 04:43:12 -0000 1.166
|
||||
+++ b/auth2.c 28 Aug 2023 08:32:44 -0000
|
||||
@@ -208,6 +208,7 @@ input_service_request(int type, u_int32_
|
||||
}
|
||||
|
||||
#define MIN_FAIL_DELAY_SECONDS 0.005
|
||||
+#define MAX_FAIL_DELAY_SECONDS 5.0
|
||||
static double
|
||||
user_specific_delay(const char *user)
|
||||
{
|
||||
@@ -233,6 +234,12 @@ ensure_minimum_time_since(double start,
|
||||
struct timespec ts;
|
||||
double elapsed = monotime_double() - start, req = seconds, remain;
|
||||
|
||||
+ if (elapsed > MAX_FAIL_DELAY_SECONDS) {
|
||||
+ debug3("elapsed %0.3lfms exceeded the max delay "
|
||||
+ "requested %0.3lfms)", elapsed*1000, req*1000);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
/* if we've already passed the requested time, scale up */
|
||||
while ((remain = seconds - elapsed) < 0.0)
|
||||
seconds *= 2;
|
||||
@@ -317,7 +324,7 @@ input_userauth_request(int type, u_int32
|
||||
debug2("input_userauth_request: try method %s", method);
|
||||
authenticated = m->userauth(ssh);
|
||||
}
|
||||
- if (!authctxt->authenticated)
|
||||
+ if (!authctxt->authenticated && strcmp(method, "none") != 0)
|
||||
ensure_minimum_time_since(tstart,
|
||||
user_specific_delay(authctxt->user));
|
||||
userauth_finish(ssh, authenticated, method, NULL);
|
|
@ -0,0 +1,447 @@
|
|||
diff --git a/PROTOCOL b/PROTOCOL
|
||||
index d453c779..ded935eb 100644
|
||||
--- a/PROTOCOL
|
||||
+++ b/PROTOCOL
|
||||
@@ -137,6 +137,32 @@ than as a named global or channel request to allow pings with very
|
||||
described at:
|
||||
http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519
|
||||
|
||||
+1.9 transport: strict key exchange extension
|
||||
+
|
||||
+OpenSSH supports a number of transport-layer hardening measures under
|
||||
+a "strict KEX" feature. This feature is signalled similarly to the
|
||||
+RFC8308 ext-info feature: by including a additional algorithm in the
|
||||
+initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append
|
||||
+"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server
|
||||
+may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms
|
||||
+are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
|
||||
+if they are present in subsequent SSH2_MSG_KEXINIT packets.
|
||||
+
|
||||
+When an endpoint that supports this extension observes this algorithm
|
||||
+name in a peer's KEXINIT packet, it MUST make the following changes to
|
||||
+the the protocol:
|
||||
+
|
||||
+a) During initial KEX, terminate the connection if any unexpected or
|
||||
+ out-of-sequence packet is received. This includes terminating the
|
||||
+ connection if the first packet received is not SSH2_MSG_KEXINIT.
|
||||
+ Unexpected packets for the purpose of strict KEX include messages
|
||||
+ that are otherwise valid at any time during the connection such as
|
||||
+ SSH2_MSG_DEBUG and SSH2_MSG_IGNORE.
|
||||
+b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
|
||||
+ packet sequence number to zero. This behaviour persists for the
|
||||
+ duration of the connection (i.e. not just the first
|
||||
+ SSH2_MSG_NEWKEYS).
|
||||
+
|
||||
2. Connection protocol changes
|
||||
|
||||
2.1. connection: Channel write close extension "eow@openssh.com"
|
||||
diff --git a/kex.c b/kex.c
|
||||
index aa5e792d..d478ff6e 100644
|
||||
--- a/kex.c
|
||||
+++ b/kex.c
|
||||
@@ -65,7 +65,7 @@
|
||||
#endif
|
||||
|
||||
/* prototype */
|
||||
-static int kex_choose_conf(struct ssh *);
|
||||
+static int kex_choose_conf(struct ssh *, uint32_t seq);
|
||||
static int kex_input_newkeys(int, u_int32_t, struct ssh *);
|
||||
|
||||
static const char *proposal_names[PROPOSAL_MAX] = {
|
||||
@@ -177,6 +177,18 @@ kex_names_valid(const char *names)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+/* returns non-zero if proposal contains any algorithm from algs */
|
||||
+static int
|
||||
+has_any_alg(const char *proposal, const char *algs)
|
||||
+{
|
||||
+ char *cp;
|
||||
+
|
||||
+ if ((cp = match_list(proposal, algs, NULL)) == NULL)
|
||||
+ return 0;
|
||||
+ free(cp);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Concatenate algorithm names, avoiding duplicates in the process.
|
||||
* Caller must free returned string.
|
||||
@@ -184,7 +196,7 @@ kex_names_valid(const char *names)
|
||||
char *
|
||||
kex_names_cat(const char *a, const char *b)
|
||||
{
|
||||
- char *ret = NULL, *tmp = NULL, *cp, *p, *m;
|
||||
+ char *ret = NULL, *tmp = NULL, *cp, *p;
|
||||
size_t len;
|
||||
|
||||
if (a == NULL || *a == '\0')
|
||||
@@ -201,10 +213,8 @@ kex_names_cat(const char *a, const char *b)
|
||||
}
|
||||
strlcpy(ret, a, len);
|
||||
for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
|
||||
- if ((m = match_list(ret, p, NULL)) != NULL) {
|
||||
- free(m);
|
||||
+ if (has_any_alg(ret, p))
|
||||
continue; /* Algorithm already present */
|
||||
- }
|
||||
if (strlcat(ret, ",", len) >= len ||
|
||||
strlcat(ret, p, len) >= len) {
|
||||
free(tmp);
|
||||
@@ -466,7 +485,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
|
||||
{
|
||||
int r;
|
||||
|
||||
- error("kex protocol error: type %d seq %u", type, seq);
|
||||
+ /* If in strict mode, any unexpected message is an error */
|
||||
+ if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
|
||||
+ ssh_packet_disconnect(ssh, "strict KEX violation: "
|
||||
+ "unexpected packet type %u (seqnr %u)", type, seq);
|
||||
+ }
|
||||
+ error("type %u seq %u", type, seq);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
@@ -548,6 +572,11 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
|
||||
if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
|
||||
return r;
|
||||
+ if (ninfo >= 1024) {
|
||||
+ error("SSH2_MSG_EXT_INFO with too many entries, expected "
|
||||
+ "<=1024, received %u", ninfo);
|
||||
+ return dispatch_protocol_error(type, seq, ssh);
|
||||
+ }
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
|
||||
return r;
|
||||
@@ -681,7 +705,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||
if (kex == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
|
||||
- ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
|
||||
+ ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
|
||||
ptr = sshpkt_ptr(ssh, &dlen);
|
||||
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
|
||||
return r;
|
||||
@@ -717,7 +741,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||
if (!(kex->flags & KEX_INIT_SENT))
|
||||
if ((r = kex_send_kexinit(ssh)) != 0)
|
||||
return r;
|
||||
- if ((r = kex_choose_conf(ssh)) != 0)
|
||||
+ if ((r = kex_choose_conf(ssh, seq)) != 0)
|
||||
return r;
|
||||
|
||||
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
|
||||
@@ -981,20 +1005,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
|
||||
return (1);
|
||||
}
|
||||
|
||||
-/* returns non-zero if proposal contains any algorithm from algs */
|
||||
static int
|
||||
-has_any_alg(const char *proposal, const char *algs)
|
||||
+kexalgs_contains(char **peer, const char *ext)
|
||||
{
|
||||
- char *cp;
|
||||
-
|
||||
- if ((cp = match_list(proposal, algs, NULL)) == NULL)
|
||||
- return 0;
|
||||
- free(cp);
|
||||
- return 1;
|
||||
+ return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
|
||||
}
|
||||
|
||||
static int
|
||||
-kex_choose_conf(struct ssh *ssh)
|
||||
+kex_choose_conf(struct ssh *ssh, uint32_t seq)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
struct newkeys *newkeys;
|
||||
@@ -1019,13 +1037,23 @@ kex_choose_conf(struct ssh *ssh)
|
||||
sprop=peer;
|
||||
}
|
||||
|
||||
- /* Check whether client supports ext_info_c */
|
||||
- if (kex->server && (kex->flags & KEX_INITIAL)) {
|
||||
- char *ext;
|
||||
-
|
||||
- ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
|
||||
- kex->ext_info_c = (ext != NULL);
|
||||
- free(ext);
|
||||
+ /* Check whether peer supports ext_info/kex_strict */
|
||||
+ if ((kex->flags & KEX_INITIAL) != 0) {
|
||||
+ if (kex->server) {
|
||||
+ kex->ext_info_c = kexalgs_contains(peer, "ext-info-c");
|
||||
+ kex->kex_strict = kexalgs_contains(peer,
|
||||
+ "kex-strict-c-v00@openssh.com");
|
||||
+ } else {
|
||||
+ kex->kex_strict = kexalgs_contains(peer,
|
||||
+ "kex-strict-s-v00@openssh.com");
|
||||
+ }
|
||||
+ if (kex->kex_strict) {
|
||||
+ debug3("will use strict KEX ordering");
|
||||
+ if (seq != 0)
|
||||
+ ssh_packet_disconnect(ssh,
|
||||
+ "strict KEX violation: "
|
||||
+ "KEXINIT was not the first packet");
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Check whether client supports rsa-sha2 algorithms */
|
||||
diff --git a/kex.h b/kex.h
|
||||
index 5f7ef784..272ebb43 100644
|
||||
--- a/kex.h
|
||||
+++ b/kex.h
|
||||
@@ -149,6 +149,7 @@ struct kex {
|
||||
u_int kex_type;
|
||||
char *server_sig_algs;
|
||||
int ext_info_c;
|
||||
+ int kex_strict;
|
||||
struct sshbuf *my;
|
||||
struct sshbuf *peer;
|
||||
struct sshbuf *client_version;
|
||||
diff --git a/packet.c b/packet.c
|
||||
index 52017def..beb214f9 100644
|
||||
--- a/packet.c
|
||||
+++ b/packet.c
|
||||
@@ -1207,8 +1207,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
|
||||
sshbuf_dump(state->output, stderr);
|
||||
#endif
|
||||
/* increment sequence number for outgoing packets */
|
||||
- if (++state->p_send.seqnr == 0)
|
||||
+ if (++state->p_send.seqnr == 0) {
|
||||
+ if ((ssh->kex->flags & KEX_INITIAL) != 0) {
|
||||
+ ssh_packet_disconnect(ssh, "outgoing sequence number "
|
||||
+ "wrapped during initial key exchange");
|
||||
+ }
|
||||
logit("outgoing seqnr wraps around");
|
||||
+ }
|
||||
if (++state->p_send.packets == 0)
|
||||
if (!(ssh->compat & SSH_BUG_NOREKEY))
|
||||
return SSH_ERR_NEED_REKEY;
|
||||
@@ -1216,6 +1221,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
|
||||
state->p_send.bytes += len;
|
||||
sshbuf_reset(state->outgoing_packet);
|
||||
|
||||
+ if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
|
||||
+ debug("resetting send seqnr %u", state->p_send.seqnr);
|
||||
+ state->p_send.seqnr = 0;
|
||||
+ }
|
||||
+
|
||||
if (type == SSH2_MSG_NEWKEYS)
|
||||
r = ssh_set_newkeys(ssh, MODE_OUT);
|
||||
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
|
||||
@@ -1344,8 +1354,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
/* Stay in the loop until we have received a complete packet. */
|
||||
for (;;) {
|
||||
/* Try to read a packet from the buffer. */
|
||||
- r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
|
||||
- if (r != 0)
|
||||
+ if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0)
|
||||
break;
|
||||
/* If we got a packet, return it. */
|
||||
if (*typep != SSH_MSG_NONE)
|
||||
@@ -1629,10 +1615,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
|
||||
goto out;
|
||||
}
|
||||
+
|
||||
if (seqnr_p != NULL)
|
||||
*seqnr_p = state->p_read.seqnr;
|
||||
- if (++state->p_read.seqnr == 0)
|
||||
+ if (++state->p_read.seqnr == 0) {
|
||||
+ if ((ssh->kex->flags & KEX_INITIAL) != 0) {
|
||||
+ ssh_packet_disconnect(ssh, "incoming sequence number "
|
||||
+ "wrapped during initial key exchange");
|
||||
+ }
|
||||
logit("incoming seqnr wraps around");
|
||||
+ }
|
||||
if (++state->p_read.packets == 0)
|
||||
if (!(ssh->compat & SSH_BUG_NOREKEY))
|
||||
return SSH_ERR_NEED_REKEY;
|
||||
@@ -1698,6 +1690,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
#endif
|
||||
/* reset for next packet */
|
||||
state->packlen = 0;
|
||||
+ if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
|
||||
+ debug("resetting read seqnr %u", state->p_read.seqnr);
|
||||
+ state->p_read.seqnr = 0;
|
||||
+ }
|
||||
|
||||
/* do we need to rekey? */
|
||||
if (ssh_packet_need_rekeying(ssh, 0)) {
|
||||
@@ -1720,10 +1716,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
- if (*typep) {
|
||||
- state->keep_alive_timeouts = 0;
|
||||
- DBG(debug("received packet type %d", *typep));
|
||||
+ if (*typep == 0) {
|
||||
+ /* no message ready */
|
||||
+ return 0;
|
||||
}
|
||||
+ state->keep_alive_timeouts = 0;
|
||||
+ DBG(debug("received packet type %d", *typep));
|
||||
+
|
||||
+ /* Always process disconnect messages */
|
||||
+ if (*typep == SSH2_MSG_DISCONNECT) {
|
||||
+ if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
+ return r;
|
||||
+ /* Ignore normal client exit notifications */
|
||||
+ do_log2(ssh->state->server_side &&
|
||||
+ reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
+ SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
+ "Received disconnect from %s port %d:"
|
||||
+ "%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
+ ssh_remote_port(ssh), reason, msg);
|
||||
+ free(msg);
|
||||
+ return SSH_ERR_DISCONNECTED;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Do not implicitly handle any messages here during initial
|
||||
+ * KEX when in strict mode. They will be need to be allowed
|
||||
+ * explicitly by the KEX dispatch table or they will generate
|
||||
+ * protocol errors.
|
||||
+ */
|
||||
+ if (ssh->kex != NULL &&
|
||||
+ (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict)
|
||||
+ return 0;
|
||||
+ /* Implicitly handle transport-level messages */
|
||||
switch (*typep) {
|
||||
case SSH2_MSG_IGNORE:
|
||||
debug3("Received SSH2_MSG_IGNORE");
|
||||
@@ -1738,19 +1763,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
debug("Remote: %.900s", msg);
|
||||
free(msg);
|
||||
break;
|
||||
- case SSH2_MSG_DISCONNECT:
|
||||
- if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
- (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
- return r;
|
||||
- /* Ignore normal client exit notifications */
|
||||
- do_log2(ssh->state->server_side &&
|
||||
- reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
- SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
- "Received disconnect from %s port %d:"
|
||||
- "%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
- ssh_remote_port(ssh), reason, msg);
|
||||
- free(msg);
|
||||
- return SSH_ERR_DISCONNECTED;
|
||||
case SSH2_MSG_UNIMPLEMENTED:
|
||||
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
|
||||
return r;
|
||||
@@ -2242,6 +2254,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
|
||||
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
|
||||
+ (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->my)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
|
||||
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
|
||||
@@ -2404,6 +2417,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
|
||||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
|
||||
+ (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->my)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
|
||||
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
|
||||
@@ -2732,6 +2746,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
+ debug2("sending SSH2_MSG_DISCONNECT: %s", buf);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
diff --git a/sshconnect2.c b/sshconnect2.c
|
||||
index df6caf81..0cccbcc4 100644
|
||||
--- a/sshconnect2.c
|
||||
+++ b/sshconnect2.c
|
||||
@@ -253,7 +253,8 @@ ssh_kex2(struct ssh *ssh, char *host, st
|
||||
xxx_host = host;
|
||||
xxx_hostaddr = hostaddr;
|
||||
|
||||
- if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
|
||||
+ if ((s = kex_names_cat(options.kex_algorithms,
|
||||
+ "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
|
||||
fatal("%s: kex_names_cat", __func__);
|
||||
myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
|
||||
@@ -358,7 +358,6 @@ struct cauthmethod {
|
||||
};
|
||||
|
||||
static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
|
||||
-static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_success(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_failure(int, u_int32_t, struct ssh *);
|
||||
static int input_userauth_banner(int, u_int32_t, struct ssh *);
|
||||
@@ -472,7 +471,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
|
||||
|
||||
ssh->authctxt = &authctxt;
|
||||
ssh_dispatch_init(ssh, &input_userauth_error);
|
||||
- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
|
||||
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
|
||||
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */
|
||||
pubkey_cleanup(ssh);
|
||||
@@ -531,12 +530,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
-static int
|
||||
-input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
|
||||
-{
|
||||
- return kex_input_ext_info(type, seqnr, ssh);
|
||||
-}
|
||||
-
|
||||
void
|
||||
userauth(struct ssh *ssh, char *authlist)
|
||||
{
|
||||
@@ -615,6 +608,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
|
||||
free(authctxt->methoddata);
|
||||
authctxt->methoddata = NULL;
|
||||
authctxt->success = 1; /* break out */
|
||||
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff -up openssh-8.7p1/sshd.c.kexstrict openssh-8.7p1/sshd.c
|
||||
--- openssh-8.7p1/sshd.c.kexstrict 2023-11-27 13:19:18.855433602 +0100
|
||||
+++ openssh-8.7p1/sshd.c 2023-11-27 13:28:10.441325314 +0100
|
||||
@@ -2531,10 +2531,14 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
{
|
||||
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
|
||||
struct kex *kex;
|
||||
+ char *cp;
|
||||
int r;
|
||||
|
||||
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
|
||||
- options.kex_algorithms);
|
||||
+ if ((cp = kex_names_cat(options.kex_algorithms,
|
||||
+ "kex-strict-s-v00@openssh.com")) == NULL)
|
||||
+ fatal("kex_names_cat");
|
||||
+
|
||||
+ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(cp);
|
||||
myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(
|
||||
options.ciphers);
|
||||
myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(
|
||||
@@ -2586,7 +2586,7 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
if (gss && orig)
|
||||
xasprintf(&newstr, "%s,%s", gss, orig);
|
||||
else if (gss)
|
||||
- newstr = gss;
|
||||
+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com");
|
||||
else if (orig)
|
||||
newstr = orig;
|
||||
|
||||
@@ -2650,6 +2654,7 @@ do_ssh2_kex(struct ssh *ssh)
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
#endif
|
||||
+ free(cp);
|
||||
debug("KEX done");
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
diff --git a/ssh.c b/ssh.c
|
||||
index 35c48e62..48d93ddf 100644
|
||||
--- a/ssh.c
|
||||
+++ b/ssh.c
|
||||
@@ -626,6 +626,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo)
|
||||
}
|
||||
}
|
||||
|
||||
+static int
|
||||
+valid_hostname(const char *s)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (*s == '-')
|
||||
+ return 0;
|
||||
+ for (i = 0; s[i] != 0; i++) {
|
||||
+ if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL ||
|
||||
+ isspace((u_char)s[i]) || iscntrl((u_char)s[i]))
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+valid_ruser(const char *s)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ if (*s == '-')
|
||||
+ return 0;
|
||||
+ for (i = 0; s[i] != 0; i++) {
|
||||
+ if (strchr("'`\";&<>|(){}", s[i]) != NULL)
|
||||
+ return 0;
|
||||
+ /* Disallow '-' after whitespace */
|
||||
+ if (isspace((u_char)s[i]) && s[i + 1] == '-')
|
||||
+ return 0;
|
||||
+ /* Disallow \ in last position */
|
||||
+ if (s[i] == '\\' && s[i + 1] == '\0')
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Main program for the ssh client.
|
||||
*/
|
||||
@@ -1118,6 +1153,10 @@ main(int ac, char **av)
|
||||
if (!host)
|
||||
usage();
|
||||
|
||||
+ if (!valid_hostname(host))
|
||||
+ fatal("hostname contains invalid characters");
|
||||
+ if (options.user != NULL && !valid_ruser(options.user))
|
||||
+ fatal("remote username contains invalid characters");
|
||||
host_arg = xstrdup(host);
|
||||
|
||||
/* Initialize the command to execute on remote host. */
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1
|
||||
%global openssh_ver 8.0p1
|
||||
%global openssh_rel 10
|
||||
%global openssh_rel 24
|
||||
%global pam_ssh_agent_ver 0.10.3
|
||||
%global pam_ssh_agent_rel 7
|
||||
|
||||
|
@ -245,6 +245,53 @@ Patch976: openssh-8.0p1-restore-nonblock.patch
|
|||
Patch977: openssh-8.0p1-cve-2020-14145.patch
|
||||
# sshd -T requires -C when "Match" is used in sshd_config (#1836277)
|
||||
Patch978: openssh-8.0p1-sshd_config.patch
|
||||
# CVE-2021-41617
|
||||
Patch980: openssh-8.7p1-upstream-cve-2021-41617.patch
|
||||
# support sshd Include directive
|
||||
# upstream commits:
|
||||
# c2bd7f74b0e0f3a3ee9d19ac549e6ba89013abaf~1..677d0ece67634262b3b96c3cd6410b19f3a603b7
|
||||
# 8bdc3bb7cf4c82c3344cfcb82495a43406e87e83
|
||||
# 47adfdc07f4f8ea0064a1495500244de08d311ed~1..7af1e92cd289b7eaa9a683e9a6f2fddd98f37a01
|
||||
# supplementary commit 612b1dd1ec91ffb1e01f58cca0c6eb1d47bf4423
|
||||
Patch981: openssh-8.0p1-sshd_include.patch
|
||||
# Port upstream ClientAliveCountMax behaviour
|
||||
# upstream commit:
|
||||
# 69334996ae203c51c70bf01d414c918a44618f8e
|
||||
Patch982: openssh-8.0p1-client_alive_count_max.patch
|
||||
# add a local implementation of BSD realpath() for sftp-server
|
||||
# use ahead of OpenBSD's realpath changing to match POSIX
|
||||
# upstream commits:
|
||||
# 569b650f93b561c09c655f83f128e1dfffe74101
|
||||
# 53a6ebf1445a857f5e487b18ee5e5830a9575149
|
||||
# 5428b0d239f6b516c81d1dd15aa9fe9e60af75d4
|
||||
Patch983: openssh-8.0p1-sftp-realpath.patch
|
||||
# include caveat for crypto-policy in sshd manpage (#2044354)
|
||||
Patch984: openssh-8.0p1-crypto-policy-doc.patch
|
||||
# minimize the use of SHA1 as a proof of possession for RSA key (#2093897)
|
||||
# upstream commits:
|
||||
# 291721bc7c840d113a49518f3fca70e86248b8e8
|
||||
# 0fa33683223c76289470a954404047bc762be84c
|
||||
# f8df0413f0a057b6a3d3dd7bd8bc7c5d80911d3a
|
||||
Patch985: openssh-8.7p1-minimize-sha1-use.patch
|
||||
# Upstream ff89b1bed80721295555bd083b173247a9c0484e
|
||||
Patch986: openssh-9.1p1-sshbanner.patch
|
||||
# Upstream 25e3bccbaa63d27b9d5e09c123f1eb28594d2bd6
|
||||
Patch987: openssh-8.0p1-ipv6-process.patch
|
||||
# Upstream 4332b4fe49360679647a8705bc08f4e81323f6b4
|
||||
Patch988: openssh-8.0p1-avoidkillall.patch
|
||||
# Upstream 89b54900ac61986760452f132bbe3fb7249cfdac
|
||||
Patch989: openssh-8.0p1-bigsshdconfig.patch
|
||||
# upsream commit
|
||||
# b23fe83f06ee7e721033769cfa03ae840476d280
|
||||
Patch1015: openssh-9.3p1-upstream-cve-2023-38408.patch
|
||||
#upstream commit 01dbf3d46651b7d6ddf5e45d233839bbfffaeaec
|
||||
Patch1017: openssh-9.4p2-limit-delay.patch
|
||||
#upstream commit 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5
|
||||
Patch1018: openssh-9.6p1-CVE-2023-48795.patch
|
||||
#upstream commit 7ef3787c84b6b524501211b11a26c742f829af1a
|
||||
Patch1019: openssh-9.6p1-CVE-2023-51385.patch
|
||||
# SCP kill switch
|
||||
Patch1020: openssh-8.7p1-scp-kill-switch.patch
|
||||
|
||||
License: BSD
|
||||
Group: Applications/Internet
|
||||
|
@ -470,6 +517,16 @@ popd
|
|||
%patch976 -p1 -b .restore-nonblock
|
||||
%patch977 -p1 -b .cve-2020-14145
|
||||
%patch978 -p1 -b .sshd_config
|
||||
%patch980 -p1 -b .cve-2021-41617
|
||||
%patch981 -p1 -b .sshdinclude
|
||||
%patch982 -p1 -b .client_alive_count_max
|
||||
%patch983 -p1 -b .sftp-realpath
|
||||
%patch984 -p1 -b .crypto-policy-doc
|
||||
%patch985 -p1 -b .minimize-sha1-use
|
||||
%patch986 -p1 -b .banner
|
||||
%patch987 -p1 -b .sftp_ipv6
|
||||
%patch988 -p1 -b .killall
|
||||
%patch989 -p1 -b .bigsshdconfig
|
||||
|
||||
%patch200 -p1 -b .audit
|
||||
%patch201 -p1 -b .audit-race
|
||||
|
@ -477,6 +534,12 @@ popd
|
|||
|
||||
%patch100 -p1 -b .coverity
|
||||
|
||||
%patch1015 -p1 -b .cve-2023-38408
|
||||
%patch1017 -p1 -b .limitdelay
|
||||
%patch1018 -p1 -b .cve-2023-48795
|
||||
%patch1019 -p1 -b .cve-2023-51385
|
||||
%patch1020 -p1 -b .scp-kill-switch
|
||||
|
||||
autoreconf
|
||||
pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
|
||||
autoreconf
|
||||
|
@ -761,6 +824,74 @@ getent passwd sshd >/dev/null || \
|
|||
%endif
|
||||
|
||||
%changelog
|
||||
* Tue Feb 06 2024 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-24
|
||||
- Providing a kill switch for scp to deal with CVE-2020-15778
|
||||
Resolves: RHEL-22870
|
||||
|
||||
* Fri Jan 05 2024 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-23
|
||||
- Fix Terrapin attack
|
||||
Resolves: RHEL-19308
|
||||
|
||||
* Thu Dec 21 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-22
|
||||
- Fix Terrapin attack
|
||||
Resolves: RHEL-19308
|
||||
- Forbid shell metasymbols in username/hostname
|
||||
Resolves: RHEL-19788
|
||||
|
||||
* Tue Nov 07 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-21
|
||||
- Using DigestSign/DigestVerify functions for better FIPS compatibility
|
||||
Resolves: RHEL-5217
|
||||
|
||||
* Mon Oct 30 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-20
|
||||
- Limit artificial delays in sshd while login using AD user
|
||||
Resolves: RHEL-1684
|
||||
- Add comment to OpenSSH server config about FIPS-incompatible key
|
||||
Resolves: RHEL-5221
|
||||
- Avoid killing all processes on system in case of race condition
|
||||
Resolves: RHEL-11548
|
||||
- Avoid sshd_config 256K limit
|
||||
Resolves: RHEL-5279
|
||||
- Using DigestSign/DigestVerify functions for better FIPS compatibility
|
||||
Resolves: RHEL-5217
|
||||
- Fix GSS KEX causing ssh failures when connecting to WinSSHD
|
||||
Resolves: RHEL-5321
|
||||
|
||||
* Thu Aug 24 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19
|
||||
- rebuilt
|
||||
Related: CVE-2023-38408
|
||||
|
||||
* Thu Jul 20 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-18
|
||||
- Avoid remote code execution in ssh-agent PKCS#11 support
|
||||
Resolves: CVE-2023-38408
|
||||
|
||||
* Tue Dec 20 2022 Dmitry Belyavskiy - 8.0p1-17
|
||||
- Fix parsing of IPv6 IPs in sftp client (#2151334)
|
||||
- Avoid ssh banner one-byte overflow (#2138344)
|
||||
- Avoid crash of sshd when Include folder does not exist (#2133087)
|
||||
|
||||
* Wed Jun 29 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-16
|
||||
- Omit client side from minimize-sha1-use.patch to prevent regression (#2093897)
|
||||
|
||||
* Thu Jun 23 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-15
|
||||
- Fix new issues found by static analyzers
|
||||
|
||||
* Wed Jun 01 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-14
|
||||
- Upstream: add a local implementation of BSD realpath() for sftp-server (#2064249)
|
||||
- Change product name from Fedora to RHEL in openssh-7.8p1-UsePAM-warning.patch (#1953807)
|
||||
- Include caveat for crypto-policy in sshd manpage (#2044354)
|
||||
- Change log level of FIPS specific log message to verbose (#2050511)
|
||||
- Clarify force_file_perms (-m) documentation in sftp-server manpage (#1862504)
|
||||
- Minimize the use of SHA1 as a proof of possession for RSA key (#2093897)
|
||||
|
||||
* Tue Oct 26 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-13
|
||||
- Upstream: ClientAliveCountMax=0 disable the connection killing behaviour (#2015828)
|
||||
|
||||
* Wed Oct 20 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-12
|
||||
- Add support for "Include" directive in sshd_config file (#1926103)
|
||||
|
||||
* Fri Oct 01 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-11
|
||||
- CVE-2021-41617 upstream fix (#2008885)
|
||||
|
||||
* Mon Jun 21 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-10
|
||||
- sshd -T requires -C when "Match" is used in sshd_config (#1836277)
|
||||
|
||||
|
|
Loading…
Reference in New Issue