Vendor import of OpenSSH 9.5p1

This commit is contained in:
Ed Maste 2023-10-04 08:06:41 -04:00
parent 78f30535bc
commit b3ced7f268
57 changed files with 1712 additions and 1634 deletions

View File

@ -6,6 +6,10 @@ master :
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh)
[![Coverity Status](https://scan.coverity.com/projects/21341/badge.svg)](https://scan.coverity.com/projects/openssh-portable)
9.4 :
[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_9_4)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_9_4)
[![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_9_4)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_9_4)
9.3 :
[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg?branch=V_9_3)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml?query=branch:V_9_3)
[![C/C++ CI self-hosted](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml/badge.svg?branch=V_9_3)](https://github.com/openssh/openssh-portable-selfhosted/actions/workflows/selfhosted.yml?query=branch:V_9_3)

11
.github/configs vendored
View File

@ -30,6 +30,13 @@ case "$config" in
default|sol64)
;;
c89)
# If we don't have LLONG_MAX, configure will figure out that it can
# get it by setting -std=gnu99, at which point we won't be testing
# C89 any more. To avoid this, feed it in via CFLAGS.
llong_max=`gcc -E -dM - </dev/null | \
awk '$2=="__LONG_LONG_MAX__"{print $3}'`
CPPFLAGS="-DLLONG_MAX=${llong_max}"
CC="gcc"
CFLAGS="-Wall -std=c89 -pedantic -Werror=vla"
CONFIGFLAGS="--without-zlib"
@ -205,6 +212,10 @@ case "$config" in
;;
esac
;;
zlib-develop)
INSTALL_ZLIB=develop
CONFIGFLAGS="--with-zlib=/opt/zlib --with-rpath=-Wl,-rpath,"
;;
*)
echo "Unknown configuration $config"
exit 1

8
.github/setup_ci.sh vendored
View File

@ -133,6 +133,8 @@ for TARGET in $TARGETS; do
valgrind*)
PACKAGES="$PACKAGES valgrind"
;;
zlib-*)
;;
*) echo "Invalid option '${TARGET}'"
exit 1
;;
@ -214,3 +216,9 @@ if [ ! -z "${INSTALL_BORINGSSL}" ]; then
cp ${HOME}/boringssl/build/crypto/libcrypto.a /opt/boringssl/lib &&
cp -r ${HOME}/boringssl/include /opt/boringssl)
fi
if [ ! -z "${INSTALL_ZLIB}" ]; then
(cd ${HOME} && git clone https://github.com/madler/zlib.git &&
cd ${HOME}/zlib && ./configure && make &&
sudo make install prefix=/opt/zlib)
fi

View File

@ -73,6 +73,7 @@ jobs:
- { target: ubuntu-latest, config: openssl-3.1.0 }
- { target: ubuntu-latest, config: openssl-1.1.1_stable }
- { target: ubuntu-latest, config: openssl-3.0 } # stable branch
- { target: ubuntu-latest, config: zlib-develop }
- { target: ubuntu-22.04, config: pam }
- { target: ubuntu-22.04, config: krb5 }
- { target: ubuntu-22.04, config: heimdal }

View File

@ -40,6 +40,8 @@ jobs:
- obsd67
- obsd69
- obsd70
- obsd72
- obsd73
- obsdsnap
- obsdsnap-i386
- openindiana
@ -76,6 +78,7 @@ jobs:
- { target: ARM64, config: default, host: ARM64 }
- { target: ARM64, config: pam, host: ARM64 }
- { target: debian-riscv64, config: default, host: debian-riscv64 }
- { target: obsd-arm64, config: default, host: obsd-arm64 }
- { target: openwrt-mips, config: default, host: openwrt-mips }
- { target: openwrt-mipsel, config: default, host: openwrt-mipsel }
steps:

1611
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,39 @@ http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.o
This is identical to curve25519-sha256 as later published in RFC8731.
1.9 transport: ping facility
OpenSSH implements a transport level ping message SSH2_MSG_PING
and a corresponding SSH2_MSG_PONG reply.
#define SSH2_MSG_PING 192
#define SSH2_MSG_PONG 193
The ping message is simply:
byte SSH_MSG_PING
string data
The reply copies the data (which may be the empty string) from the
ping:
byte SSH_MSG_PONG
string data
Replies are sent in order. They are sent immediately except when rekeying
is in progress, in which case they are queued until rekeying completes.
The server advertises support for these messages using the
SSH2_MSG_EXT_INFO mechanism (RFC8308), with the following message:
string "ping@openssh.com"
string "0" (version)
The ping/reply message is implemented at the transport layer rather
than as a named global or channel request to allow pings with very
short packet lengths, which would not be possible with other
approaches.
2. Connection protocol changes
2.1. connection: Channel write close extension "eow@openssh.com"
@ -712,4 +745,4 @@ master instance and later clients.
OpenSSH extends the usual agent protocol. These changes are documented
in the PROTOCOL.agent file.
$OpenBSD: PROTOCOL,v 1.48 2022/11/07 01:53:01 dtucker Exp $
$OpenBSD: PROTOCOL,v 1.49 2023/08/28 03:28:43 djm Exp $

View File

@ -1,5 +1,5 @@
The SSH agent protocol is described in
https://tools.ietf.org/html/draft-miller-ssh-agent-04
https://tools.ietf.org/html/draft-miller-ssh-agent
This file documents OpenSSH's extensions to the agent protocol.
@ -81,4 +81,4 @@ the constraint is:
This option is only valid for XMSS keys.
$OpenBSD: PROTOCOL.agent,v 1.19 2023/04/12 08:53:54 jsg Exp $
$OpenBSD: PROTOCOL.agent,v 1.20 2023/10/03 23:56:10 djm Exp $

2
README
View File

@ -1,4 +1,4 @@
See https://www.openssh.com/releasenotes.html#9.4p1 for the release
See https://www.openssh.com/releasenotes.html#9.5p1 for the release
notes.
Please read https://www.openssh.com/report.html for bug reporting

11
auth2.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2.c,v 1.166 2023/03/08 04:43:12 guenther Exp $ */
/* $OpenBSD: auth2.c,v 1.167 2023/08/28 09:48:11 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -218,6 +218,7 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh)
}
#define MIN_FAIL_DELAY_SECONDS 0.005
#define MAX_FAIL_DELAY_SECONDS 5.0
static double
user_specific_delay(const char *user)
{
@ -243,6 +244,12 @@ ensure_minimum_time_since(double start, double seconds)
struct timespec ts;
double elapsed = monotime_double() - start, req = seconds, remain;
if (elapsed > MAX_FAIL_DELAY_SECONDS) {
debug3_f("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;
@ -334,7 +341,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh)
debug2("input_userauth_request: try method %s", method);
authenticated = m->userauth(ssh, method);
}
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);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.c,v 1.432 2023/07/04 03:59:21 dlg Exp $ */
/* $OpenBSD: channels.c,v 1.433 2023/09/04 00:01:46 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -2890,8 +2890,9 @@ channel_after_poll(struct ssh *ssh, struct pollfd *pfd, u_int npfd)
/*
* Enqueue data for channels with open or draining c->input.
* Returns non-zero if a packet was enqueued.
*/
static void
static int
channel_output_poll_input_open(struct ssh *ssh, Channel *c)
{
size_t len, plen;
@ -2914,7 +2915,7 @@ channel_output_poll_input_open(struct ssh *ssh, Channel *c)
else
chan_ibuf_empty(ssh, c);
}
return;
return 0;
}
if (!c->have_remote_id)
@ -2931,7 +2932,7 @@ channel_output_poll_input_open(struct ssh *ssh, Channel *c)
*/
if (plen > c->remote_window || plen > c->remote_maxpacket) {
debug("channel %d: datagram too big", c->self);
return;
return 0;
}
/* Enqueue it */
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
@ -2940,7 +2941,7 @@ channel_output_poll_input_open(struct ssh *ssh, Channel *c)
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "channel %i: send datagram", c->self);
c->remote_window -= plen;
return;
return 1;
}
/* Enqueue packet for buffered data. */
@ -2949,7 +2950,7 @@ channel_output_poll_input_open(struct ssh *ssh, Channel *c)
if (len > c->remote_maxpacket)
len = c->remote_maxpacket;
if (len == 0)
return;
return 0;
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_DATA)) != 0 ||
(r = sshpkt_put_u32(ssh, c->remote_id)) != 0 ||
(r = sshpkt_put_string(ssh, sshbuf_ptr(c->input), len)) != 0 ||
@ -2958,19 +2959,21 @@ channel_output_poll_input_open(struct ssh *ssh, Channel *c)
if ((r = sshbuf_consume(c->input, len)) != 0)
fatal_fr(r, "channel %i: consume", c->self);
c->remote_window -= len;
return 1;
}
/*
* Enqueue data for channels with open c->extended in read mode.
* Returns non-zero if a packet was enqueued.
*/
static void
static int
channel_output_poll_extended_read(struct ssh *ssh, Channel *c)
{
size_t len;
int r;
if ((len = sshbuf_len(c->extended)) == 0)
return;
return 0;
debug2("channel %d: rwin %u elen %zu euse %d", c->self,
c->remote_window, sshbuf_len(c->extended), c->extended_usage);
@ -2979,7 +2982,7 @@ channel_output_poll_extended_read(struct ssh *ssh, Channel *c)
if (len > c->remote_maxpacket)
len = c->remote_maxpacket;
if (len == 0)
return;
return 0;
if (!c->have_remote_id)
fatal_f("channel %d: no remote id", c->self);
if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_EXTENDED_DATA)) != 0 ||
@ -2992,15 +2995,20 @@ channel_output_poll_extended_read(struct ssh *ssh, Channel *c)
fatal_fr(r, "channel %i: consume", c->self);
c->remote_window -= len;
debug2("channel %d: sent ext data %zu", c->self, len);
return 1;
}
/* If there is data to send to the connection, enqueue some of it now. */
void
/*
* If there is data to send to the connection, enqueue some of it now.
* Returns non-zero if data was enqueued.
*/
int
channel_output_poll(struct ssh *ssh)
{
struct ssh_channels *sc = ssh->chanctxt;
Channel *c;
u_int i;
int ret = 0;
for (i = 0; i < sc->channels_alloc; i++) {
c = sc->channels[i];
@ -3023,12 +3031,13 @@ channel_output_poll(struct ssh *ssh)
/* Get the amount of buffered data for this channel. */
if (c->istate == CHAN_INPUT_OPEN ||
c->istate == CHAN_INPUT_WAIT_DRAIN)
channel_output_poll_input_open(ssh, c);
ret |= channel_output_poll_input_open(ssh, c);
/* Send extended data, i.e. stderr */
if (!(c->flags & CHAN_EOF_SENT) &&
c->extended_usage == CHAN_EXTENDED_READ)
channel_output_poll_extended_read(ssh, c);
ret |= channel_output_poll_extended_read(ssh, c);
}
return ret;
}
/* -- mux proxy support */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: channels.h,v 1.151 2023/07/04 03:59:21 dlg Exp $ */
/* $OpenBSD: channels.h,v 1.152 2023/09/04 00:01:46 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -335,7 +335,7 @@ struct timespec;
void channel_prepare_poll(struct ssh *, struct pollfd **,
u_int *, u_int *, u_int, struct timespec *);
void channel_after_poll(struct ssh *, struct pollfd *, u_int);
void channel_output_poll(struct ssh *);
int channel_output_poll(struct ssh *);
int channel_not_very_much_buffered_data(struct ssh *);
void channel_close_all(struct ssh *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.392 2023/04/03 08:10:54 dtucker Exp $ */
/* $OpenBSD: clientloop.c,v 1.398 2023/09/10 03:51:55 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -118,6 +118,9 @@
/* Permitted RSA signature algorithms for UpdateHostkeys proofs */
#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256"
/* Uncertainty (in percent) of keystroke timing intervals */
#define SSH_KEYSTROKE_TIMING_FUZZ 10
/* import options */
extern Options options;
@ -507,17 +510,181 @@ server_alive_check(struct ssh *ssh)
schedule_server_alive_check();
}
/* Try to send a dummy keystroke */
static int
send_chaff(struct ssh *ssh)
{
int r;
if ((ssh->kex->flags & KEX_HAS_PING) == 0)
return 0;
/* XXX probabilistically send chaff? */
/*
* a SSH2_MSG_CHANNEL_DATA payload is 9 bytes:
* 4 bytes channel ID + 4 bytes string length + 1 byte string data
* simulate that here.
*/
if ((r = sshpkt_start(ssh, SSH2_MSG_PING)) != 0 ||
(r = sshpkt_put_cstring(ssh, "PING!")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal_fr(r, "send packet");
return 1;
}
/* Sets the next interval to send a keystroke or chaff packet */
static void
set_next_interval(const struct timespec *now, struct timespec *next_interval,
u_int interval_ms, int starting)
{
struct timespec tmp;
long long interval_ns, fuzz_ns;
static long long rate_fuzz;
interval_ns = interval_ms * (1000LL * 1000);
fuzz_ns = (interval_ns * SSH_KEYSTROKE_TIMING_FUZZ) / 100;
/* Center fuzz around requested interval */
if (fuzz_ns > INT_MAX)
fuzz_ns = INT_MAX;
if (fuzz_ns > interval_ns) {
/* Shouldn't happen */
fatal_f("internal error: fuzz %u%% %lldns > interval %lldns",
SSH_KEYSTROKE_TIMING_FUZZ, fuzz_ns, interval_ns);
}
/*
* Randomise the keystroke/chaff intervals in two ways:
* 1. Each interval has some random jitter applied to make the
* interval-to-interval time unpredictable.
* 2. The overall interval rate is also randomly perturbed for each
* chaffing session to make the average rate unpredictable.
*/
if (starting)
rate_fuzz = arc4random_uniform(fuzz_ns);
interval_ns -= fuzz_ns;
interval_ns += arc4random_uniform(fuzz_ns) + rate_fuzz;
tmp.tv_sec = interval_ns / (1000 * 1000 * 1000);
tmp.tv_nsec = interval_ns % (1000 * 1000 * 1000);
timespecadd(now, &tmp, next_interval);
}
/*
* Performs keystroke timing obfuscation. Returns non-zero if the
* output fd should be polled.
*/
static int
obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout,
int channel_did_enqueue)
{
static int active;
static struct timespec next_interval, chaff_until;
struct timespec now, tmp;
int just_started = 0, had_keystroke = 0;
static unsigned long long nchaff;
char *stop_reason = NULL;
long long n;
monotime_ts(&now);
if (options.obscure_keystroke_timing_interval <= 0)
return 1; /* disabled in config */
if (!channel_still_open(ssh) || quit_pending) {
/* Stop if no channels left of we're waiting for one to close */
stop_reason = "no active channels";
} else if (ssh_packet_is_rekeying(ssh)) {
/* Stop if we're rekeying */
stop_reason = "rekeying started";
} else if (!ssh_packet_interactive_data_to_write(ssh) &&
ssh_packet_have_data_to_write(ssh)) {
/* Stop if the output buffer has more than a few keystrokes */
stop_reason = "output buffer filling";
} else if (active && channel_did_enqueue &&
ssh_packet_have_data_to_write(ssh)) {
/* Still in active mode and have a keystroke queued. */
had_keystroke = 1;
} else if (active) {
if (timespeccmp(&now, &chaff_until, >=)) {
/* Stop if there have been no keystrokes for a while */
stop_reason = "chaff time expired";
} else if (timespeccmp(&now, &next_interval, >=)) {
/* Otherwise if we were due to send, then send chaff */
if (send_chaff(ssh))
nchaff++;
}
}
if (stop_reason != NULL) {
if (active) {
debug3_f("stopping: %s (%llu chaff packets sent)",
stop_reason, nchaff);
active = 0;
}
return 1;
}
/*
* If we're in interactive mode, and only have a small amount
* of outbound data, then we assume that the user is typing
* interactively. In this case, start quantising outbound packets to
* fixed time intervals to hide inter-keystroke timing.
*/
if (!active && ssh_packet_interactive_data_to_write(ssh) &&
channel_did_enqueue && ssh_packet_have_data_to_write(ssh)) {
debug3_f("starting: interval ~%dms",
options.obscure_keystroke_timing_interval);
just_started = had_keystroke = active = 1;
nchaff = 0;
set_next_interval(&now, &next_interval,
options.obscure_keystroke_timing_interval, 1);
}
/* Don't hold off if obfuscation inactive */
if (!active)
return 1;
if (had_keystroke) {
/*
* Arrange to send chaff packets for a random interval after
* the last keystroke was sent.
*/
ms_to_timespec(&tmp, SSH_KEYSTROKE_CHAFF_MIN_MS +
arc4random_uniform(SSH_KEYSTROKE_CHAFF_RNG_MS));
timespecadd(&now, &tmp, &chaff_until);
}
ptimeout_deadline_monotime_tsp(timeout, &next_interval);
if (just_started)
return 1;
/* Don't arm output fd for poll until the timing interval has elapsed */
if (timespeccmp(&now, &next_interval, <))
return 0;
/* Calculate number of intervals missed since the last check */
n = (now.tv_sec - next_interval.tv_sec) * 1000LL * 1000 * 1000;
n += now.tv_nsec - next_interval.tv_nsec;
n /= options.obscure_keystroke_timing_interval * 1000LL * 1000;
n = (n < 0) ? 1 : n + 1;
/* Advance to the next interval */
set_next_interval(&now, &next_interval,
options.obscure_keystroke_timing_interval * n, 0);
return 1;
}
/*
* Waits until the client can do something (some data becomes available on
* one of the file descriptors).
*/
static void
client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
u_int *npfd_allocp, u_int *npfd_activep, int rekeying,
u_int *npfd_allocp, u_int *npfd_activep, int channel_did_enqueue,
int *conn_in_readyp, int *conn_out_readyp)
{
struct timespec timeout;
int ret;
int ret, oready;
u_int p;
*conn_in_readyp = *conn_out_readyp = 0;
@ -537,11 +704,14 @@ client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
return;
}
oready = obfuscate_keystroke_timing(ssh, &timeout, channel_did_enqueue);
/* Monitor server connection on reserved pollfd entries */
(*pfdp)[0].fd = connection_in;
(*pfdp)[0].events = POLLIN;
(*pfdp)[1].fd = connection_out;
(*pfdp)[1].events = ssh_packet_have_data_to_write(ssh) ? POLLOUT : 0;
(*pfdp)[1].events = (oready && ssh_packet_have_data_to_write(ssh)) ?
POLLOUT : 0;
/*
* Wait for something to happen. This will suspend the process until
@ -553,12 +723,12 @@ client_wait_until_can_do_something(struct ssh *ssh, struct pollfd **pfdp,
ptimeout_deadline_monotime(&timeout, control_persist_exit_time);
if (options.server_alive_interval > 0)
ptimeout_deadline_monotime(&timeout, server_alive_time);
if (options.rekey_interval > 0 && !rekeying) {
if (options.rekey_interval > 0 && !ssh_packet_is_rekeying(ssh)) {
ptimeout_deadline_sec(&timeout,
ssh_packet_get_rekey_timeout(ssh));
}
ret = poll(*pfdp, *npfd_activep, ptimeout_get_ms(&timeout));
ret = ppoll(*pfdp, *npfd_activep, ptimeout_get_tsp(&timeout), NULL);
if (ret == -1) {
/*
@ -1275,7 +1445,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
struct pollfd *pfd = NULL;
u_int npfd_alloc = 0, npfd_active = 0;
double start_time, total_time;
int r, len;
int channel_did_enqueue = 0, r, len;
u_int64_t ibytes, obytes;
int conn_in_ready, conn_out_ready;
@ -1365,6 +1535,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
/* Main loop of the client for the interactive session mode. */
while (!quit_pending) {
channel_did_enqueue = 0;
/* Process buffered packets sent by the server. */
client_process_buffered_input_packets(ssh);
@ -1386,7 +1557,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
* enqueue them for sending to the server.
*/
if (ssh_packet_not_very_much_data_to_write(ssh))
channel_output_poll(ssh);
channel_did_enqueue = channel_output_poll(ssh);
/*
* Check if the window size has changed, and buffer a
@ -1402,7 +1573,7 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg,
* available on one of the descriptors).
*/
client_wait_until_can_do_something(ssh, &pfd, &npfd_alloc,
&npfd_active, ssh_packet_is_rekeying(ssh),
&npfd_active, channel_did_enqueue,
&conn_in_ready, &conn_out_ready);
if (quit_pending)

12
configure vendored
View File

@ -6083,7 +6083,13 @@ printf "%s\n" "$GCC_VER" >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking clang version" >&5
printf %s "checking clang version... " >&6; }
CLANG_VER=`$CC -v 2>&1 | $AWK '/clang version /{print $3}'`
ver="`$CC -v 2>&1`"
if echo "$ver" | grep "Apple" >/dev/null; then
CLANG_VER="apple-`echo "$ver" | \
awk '/Apple LLVM/ {print $4"-"$5}'`"
else
CLANG_VER=`echo "$ver" | $AWK '/clang version /{print $3}'`
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CLANG_VER" >&5
printf "%s\n" "$CLANG_VER" >&6; }
@ -7492,7 +7498,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \
# https://bugzilla.mindrot.org/show_bug.cgi?id=3475 and
# https://github.com/llvm/llvm-project/issues/59242
case "$CLANG_VER" in
15.*) {
15.*|apple*) {
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC supports compile flag -fzero-call-used-regs=used" >&5
printf %s "checking if $CC supports compile flag -fzero-call-used-regs=used... " >&6; }
saved_CFLAGS="$CFLAGS"
@ -10889,7 +10895,7 @@ main (void)
int a=0, b=0, c=0, d=0, n, v;
n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
if (n != 3 && n != 4)
if (n < 1)
exit(1);
v = a*1000000 + b*10000 + c*100 + d;
fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);

View File

@ -187,7 +187,13 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
AC_MSG_RESULT([$GCC_VER])
AC_MSG_CHECKING([clang version])
CLANG_VER=`$CC -v 2>&1 | $AWK '/clang version /{print $3}'`
ver="`$CC -v 2>&1`"
if echo "$ver" | grep "Apple" >/dev/null; then
CLANG_VER="apple-`echo "$ver" | \
awk '/Apple LLVM/ {print $4"-"$5}'`"
else
CLANG_VER=`echo "$ver" | $AWK '/clang version /{print $3}'`
fi
AC_MSG_RESULT([$CLANG_VER])
OSSH_CHECK_CFLAG_COMPILE([-pipe])
@ -225,7 +231,7 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then
# https://bugzilla.mindrot.org/show_bug.cgi?id=3475 and
# https://github.com/llvm/llvm-project/issues/59242
case "$CLANG_VER" in
15.*) OSSH_CHECK_CFLAG_COMPILE([-fzero-call-used-regs=used]) ;;
15.*|apple*) OSSH_CHECK_CFLAG_COMPILE([-fzero-call-used-regs=used]) ;;
*) OSSH_CHECK_CFLAG_COMPILE([-fzero-call-used-regs=all]) ;;
esac
OSSH_CHECK_CFLAG_COMPILE([-ftrivial-auto-var-init=zero])
@ -1464,7 +1470,7 @@ else
[[
int a=0, b=0, c=0, d=0, n, v;
n = sscanf(ZLIB_VERSION, "%d.%d.%d.%d", &a, &b, &c, &d);
if (n != 3 && n != 4)
if (n < 1)
exit(1);
v = a*1000000 + b*10000 + c*100 + d;
fprintf(stderr, "found zlib version %s (%d)\n", ZLIB_VERSION, v);

View File

@ -1,4 +1,4 @@
%global ver 9.4p1
%global ver 9.5p1
%global rel 1%{?dist}
# OpenSSH privilege separation requires a user & group ID

View File

@ -13,7 +13,7 @@
Summary: OpenSSH, a free Secure Shell (SSH) protocol implementation
Name: openssh
Version: 9.4p1
Version: 9.5p1
URL: https://www.openssh.com/
Release: 1
Source0: openssh-%{version}.tar.gz

57
kex.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.178 2023/03/12 10:40:39 dtucker Exp $ */
/* $OpenBSD: kex.c,v 1.181 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@ -492,12 +492,14 @@ kex_send_ext_info(struct ssh *ssh)
return SSH_ERR_ALLOC_FAIL;
/* XXX filter algs list by allowed pubkey/hostbased types */
if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 ||
(r = sshpkt_put_u32(ssh, 2)) != 0 ||
(r = sshpkt_put_u32(ssh, 3)) != 0 ||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
(r = sshpkt_put_cstring(ssh, algs)) != 0 ||
(r = sshpkt_put_cstring(ssh,
"publickey-hostbound@openssh.com")) != 0 ||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
(r = sshpkt_put_cstring(ssh, "ping@openssh.com")) != 0 ||
(r = sshpkt_put_cstring(ssh, "0")) != 0 ||
(r = sshpkt_send(ssh)) != 0) {
error_fr(r, "compose");
goto out;
@ -527,6 +529,23 @@ kex_send_newkeys(struct ssh *ssh)
return 0;
}
/* Check whether an ext_info value contains the expected version string */
static int
kex_ext_info_check_ver(struct kex *kex, const char *name,
const u_char *val, size_t len, const char *want_ver, u_int flag)
{
if (memchr(val, '\0', len) != NULL) {
error("SSH2_MSG_EXT_INFO: %s value contains nul byte", name);
return SSH_ERR_INVALID_FORMAT;
}
debug_f("%s=<%s>", name, val);
if (strcmp(val, want_ver) == 0)
kex->flags |= flag;
else
debug_f("unsupported version of %s extension", name);
return 0;
}
int
kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
{
@ -557,6 +576,8 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error_f("nul byte in %s", name);
free(name);
free(val);
return SSH_ERR_INVALID_FORMAT;
}
debug_f("%s=<%s>", name, val);
@ -564,18 +585,18 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
val = NULL;
} else if (strcmp(name,
"publickey-hostbound@openssh.com") == 0) {
/* XXX refactor */
/* Ensure no \0 lurking in value */
if (memchr(val, '\0', vlen) != NULL) {
error_f("nul byte in %s", name);
return SSH_ERR_INVALID_FORMAT;
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
"0", KEX_HAS_PUBKEY_HOSTBOUND)) != 0) {
free(name);
free(val);
return r;
}
debug_f("%s=<%s>", name, val);
if (strcmp(val, "0") == 0)
kex->flags |= KEX_HAS_PUBKEY_HOSTBOUND;
else {
debug_f("unsupported version of %s extension",
name);
} else if (strcmp(name, "ping@openssh.com") == 0) {
if ((r = kex_ext_info_check_ver(kex, name, val, vlen,
"0", KEX_HAS_PING)) != 0) {
free(name);
free(val);
return r;
}
} else
debug_f("%s (unrecognised)", name);
@ -1334,7 +1355,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
for (;;) {
if (timeout_ms > 0) {
r = waitrfd(ssh_packet_get_connection_in(ssh),
&timeout_ms);
&timeout_ms, NULL);
if (r == -1 && errno == ETIMEDOUT) {
send_error(ssh, "Timed out waiting "
"for SSH identification string.");
@ -1353,7 +1374,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
len = atomicio(read, ssh_packet_get_connection_in(ssh),
&c, 1);
if (len != 1 && errno == EPIPE) {
error_f("Connection closed by remote host");
verbose_f("Connection closed by remote host");
r = SSH_ERR_CONN_CLOSED;
goto out;
} else if (len != 1) {
@ -1369,7 +1390,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
if (c == '\n')
break;
if (c == '\0' || expect_nl) {
error_f("banner line contains invalid "
verbose_f("banner line contains invalid "
"characters");
goto invalid;
}
@ -1379,7 +1400,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
goto out;
}
if (sshbuf_len(peer_version) > SSH_MAX_BANNER_LEN) {
error_f("banner line too long");
verbose_f("banner line too long");
goto invalid;
}
}
@ -1395,7 +1416,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms,
}
/* Do not accept lines before the SSH ident from a client */
if (ssh->kex->server) {
error_f("client sent invalid protocol identifier "
verbose_f("client sent invalid protocol identifier "
"\"%.256s\"", cp);
free(cp);
goto invalid;

3
kex.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.118 2023/03/06 12:14:48 dtucker Exp $ */
/* $OpenBSD: kex.h,v 1.119 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -111,6 +111,7 @@ enum kex_exchange {
#define KEX_HAS_PUBKEY_HOSTBOUND 0x0004
#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 */
#define KEX_HAS_PING 0x0020
struct sshenc {
char *name;

71
misc.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.c,v 1.185 2023/08/04 06:32:40 dtucker Exp $ */
/* $OpenBSD: misc.c,v 1.187 2023/08/28 03:31:16 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005-2020 Damien Miller. All rights reserved.
@ -313,20 +313,38 @@ set_sock_tos(int fd, int tos)
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
static int
waitfd(int fd, int *timeoutp, short events)
waitfd(int fd, int *timeoutp, short events, volatile sig_atomic_t *stop)
{
struct pollfd pfd;
struct timeval t_start;
int oerrno, r, have_timeout = (*timeoutp >= 0);
struct timespec timeout;
int oerrno, r;
sigset_t nsigset, osigset;
if (timeoutp && *timeoutp == -1)
timeoutp = NULL;
pfd.fd = fd;
pfd.events = events;
for (; !have_timeout || *timeoutp >= 0;) {
monotime_tv(&t_start);
r = poll(&pfd, 1, *timeoutp);
ptimeout_init(&timeout);
if (timeoutp != NULL)
ptimeout_deadline_ms(&timeout, *timeoutp);
if (stop != NULL)
sigfillset(&nsigset);
for (; timeoutp == NULL || *timeoutp >= 0;) {
if (stop != NULL) {
sigprocmask(SIG_BLOCK, &nsigset, &osigset);
if (*stop) {
sigprocmask(SIG_SETMASK, &osigset, NULL);
errno = EINTR;
return -1;
}
}
r = ppoll(&pfd, 1, ptimeout_get_tsp(&timeout),
stop != NULL ? &osigset : NULL);
oerrno = errno;
if (have_timeout)
ms_subtract_diff(&t_start, timeoutp);
if (stop != NULL)
sigprocmask(SIG_SETMASK, &osigset, NULL);
if (timeoutp)
*timeoutp = ptimeout_get_ms(&timeout);
errno = oerrno;
if (r > 0)
return 0;
@ -346,8 +364,8 @@ waitfd(int fd, int *timeoutp, short events)
* Returns 0 if fd ready or -1 on timeout or error (see errno).
*/
int
waitrfd(int fd, int *timeoutp) {
return waitfd(fd, timeoutp, POLLIN);
waitrfd(int fd, int *timeoutp, volatile sig_atomic_t *stop) {
return waitfd(fd, timeoutp, POLLIN, stop);
}
/*
@ -381,7 +399,7 @@ timeout_connect(int sockfd, const struct sockaddr *serv_addr,
break;
}
if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT) == -1)
if (waitfd(sockfd, timeoutp, POLLIN | POLLOUT, NULL) == -1)
return -1;
/* Completed or failed */
@ -2883,22 +2901,33 @@ ptimeout_deadline_ms(struct timespec *pt, long ms)
ptimeout_deadline_tsp(pt, &p);
}
/* Specify a poll/ppoll deadline at wall clock monotime 'when' (timespec) */
void
ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when)
{
struct timespec now, t;
monotime_ts(&now);
if (timespeccmp(&now, when, >=)) {
/* 'when' is now or in the past. Timeout ASAP */
pt->tv_sec = 0;
pt->tv_nsec = 0;
} else {
timespecsub(when, &now, &t);
ptimeout_deadline_tsp(pt, &t);
}
}
/* Specify a poll/ppoll deadline at wall clock monotime 'when' */
void
ptimeout_deadline_monotime(struct timespec *pt, time_t when)
{
struct timespec now, t;
struct timespec t;
t.tv_sec = when;
t.tv_nsec = 0;
monotime_ts(&now);
if (timespeccmp(&now, &t, >=))
ptimeout_deadline_sec(pt, 0);
else {
timespecsub(&t, &now, &t);
ptimeout_deadline_tsp(pt, &t);
}
ptimeout_deadline_monotime_tsp(pt, &t);
}
/* Get a poll(2) timeout value in milliseconds */

6
misc.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: misc.h,v 1.103 2023/07/19 14:02:27 djm Exp $ */
/* $OpenBSD: misc.h,v 1.105 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -19,6 +19,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <signal.h>
/* Data structure for representing a forwarding request. */
struct Forward {
@ -57,7 +58,7 @@ char *get_rdomain(int);
int set_rdomain(int, const char *);
int get_sock_af(int);
void set_sock_tos(int, int);
int waitrfd(int, int *);
int waitrfd(int, int *, volatile sig_atomic_t *);
int timeout_connect(int, const struct sockaddr *, socklen_t, int *);
int a2port(const char *);
int a2tun(const char *, int *);
@ -213,6 +214,7 @@ struct timespec;
void ptimeout_init(struct timespec *pt);
void ptimeout_deadline_sec(struct timespec *pt, long sec);
void ptimeout_deadline_ms(struct timespec *pt, long ms);
void ptimeout_deadline_monotime_tsp(struct timespec *pt, struct timespec *when);
void ptimeout_deadline_monotime(struct timespec *pt, time_t when);
int ptimeout_get_ms(struct timespec *pt);
struct timespec *ptimeout_get_tsp(struct timespec *pt);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: monitor.c,v 1.236 2023/05/10 10:04:20 dtucker Exp $ */
/* $OpenBSD: monitor.c,v 1.237 2023/08/16 16:14:11 djm Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@ -342,6 +342,11 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor)
auth_method, auth_submethod);
}
}
if (authctxt->failures > options.max_authtries) {
/* Shouldn't happen */
fatal_f("privsep child made too many authentication "
"attempts");
}
}
if (!authctxt->valid)

6
mux.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: mux.c,v 1.99 2023/08/04 06:32:40 dtucker Exp $ */
/* $OpenBSD: mux.c,v 1.100 2023/08/18 01:37:41 djm Exp $ */
/*
* Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
*
@ -1480,7 +1480,9 @@ mux_client_read(int fd, struct sshbuf *b, size_t need, int timeout_ms)
case EWOULDBLOCK:
#endif
case EAGAIN:
if (waitrfd(fd, &timeout_ms) == -1)
if (waitrfd(fd, &timeout_ms,
&muxclient_terminate) == -1 &&
errno != EINTR)
return -1; /* timeout */
/* FALLTHROUGH */
case EINTR:

View File

@ -28,7 +28,6 @@
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.310 2023/04/06 03:21:31 djm Exp $ */
/* $OpenBSD: packet.c,v 1.312 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -1054,6 +1054,8 @@ int
ssh_packet_log_type(u_char type)
{
switch (type) {
case SSH2_MSG_PING:
case SSH2_MSG_PONG:
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
@ -1675,7 +1677,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
goto out;
if (ssh_packet_log_type(*typep))
debug3("receive packet: type %u", *typep);
if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
if (*typep < SSH2_MSG_MIN) {
if ((r = sshpkt_disconnect(ssh,
"Invalid ssh2 packet type: %d", *typep)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
@ -1710,6 +1712,8 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
u_int reason, seqnr;
int r;
u_char *msg;
const u_char *d;
size_t len;
for (;;) {
msg = NULL;
@ -1753,6 +1757,21 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
seqnr);
break;
case SSH2_MSG_PING:
if ((r = sshpkt_get_string_direct(ssh, &d, &len)) != 0)
return r;
DBG(debug("Received SSH2_MSG_PING len %zu", len));
if ((r = sshpkt_start(ssh, SSH2_MSG_PONG)) != 0 ||
(r = sshpkt_put_string(ssh, d, len)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
break;
case SSH2_MSG_PONG:
if ((r = sshpkt_get_string_direct(ssh,
NULL, &len)) != 0)
return r;
DBG(debug("Received SSH2_MSG_PONG len %zu", len));
break;
default:
return 0;
}
@ -2064,6 +2083,18 @@ ssh_packet_not_very_much_data_to_write(struct ssh *ssh)
return sshbuf_len(ssh->state->output) < 128 * 1024;
}
/*
* returns true when there are at most a few keystrokes of data to write
* and the connection is in interactive mode.
*/
int
ssh_packet_interactive_data_to_write(struct ssh *ssh)
{
return ssh->state->interactive_mode &&
sshbuf_len(ssh->state->output) < 256;
}
void
ssh_packet_set_tos(struct ssh *ssh, int tos)
{

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.h,v 1.94 2022/01/22 00:49:34 djm Exp $ */
/* $OpenBSD: packet.h,v 1.95 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -145,6 +145,7 @@ int ssh_packet_write_poll(struct ssh *);
int ssh_packet_write_wait(struct ssh *);
int ssh_packet_have_data_to_write(struct ssh *);
int ssh_packet_not_very_much_data_to_write(struct ssh *);
int ssh_packet_interactive_data_to_write(struct ssh *);
int ssh_packet_connection_is_on_socket(struct ssh *);
int ssh_packet_remaining(struct ssh *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.380 2023/07/17 06:16:33 djm Exp $ */
/* $OpenBSD: readconf.c,v 1.381 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -178,7 +178,7 @@ typedef enum {
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
oEnableEscapeCommandline,
oEnableEscapeCommandline, oObscureKeystrokeTiming,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@ -327,6 +327,7 @@ static struct {
{ "knownhostscommand", oKnownHostsCommand },
{ "requiredrsasize", oRequiredRSASize },
{ "enableescapecommandline", oEnableEscapeCommandline },
{ "obscurekeystroketiming", oObscureKeystrokeTiming },
{ NULL, oBadOption }
};
@ -2280,6 +2281,48 @@ parse_pubkey_algos:
intptr = &options->required_rsa_size;
goto parse_int;
case oObscureKeystrokeTiming:
value = -1;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (value != -1) {
error("%s line %d: invalid arguments",
filename, linenum);
goto out;
}
if (strcmp(arg, "yes") == 0 ||
strcmp(arg, "true") == 0)
value = SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
else if (strcmp(arg, "no") == 0 ||
strcmp(arg, "false") == 0)
value = 0;
else if (strncmp(arg, "interval:", 9) == 0) {
if ((errstr = atoi_err(arg + 9,
&value)) != NULL) {
error("%s line %d: integer value %s.",
filename, linenum, errstr);
goto out;
}
if (value <= 0 || value > 1000) {
error("%s line %d: value out of range.",
filename, linenum);
goto out;
}
} else {
error("%s line %d: unsupported argument \"%s\"",
filename, linenum, arg);
goto out;
}
}
if (value == -1) {
error("%s line %d: missing argument",
filename, linenum);
goto out;
}
intptr = &options->obscure_keystroke_timing_interval;
if (*activep && *intptr == -1)
*intptr = value;
break;
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@ -2530,6 +2573,7 @@ initialize_options(Options * options)
options->known_hosts_command = NULL;
options->required_rsa_size = -1;
options->enable_escape_commandline = -1;
options->obscure_keystroke_timing_interval = -1;
options->tag = NULL;
}
@ -2731,6 +2775,10 @@ fill_default_options(Options * options)
options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
if (options->enable_escape_commandline == -1)
options->enable_escape_commandline = 0;
if (options->obscure_keystroke_timing_interval == -1) {
options->obscure_keystroke_timing_interval =
SSH_KEYSTROKE_DEFAULT_INTERVAL_MS;
}
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
@ -3273,6 +3321,16 @@ lookup_opcode_name(OpCodes code)
static void
dump_cfg_int(OpCodes code, int val)
{
if (code == oObscureKeystrokeTiming) {
if (val == 0) {
printf("%s no\n", lookup_opcode_name(code));
return;
} else if (val == SSH_KEYSTROKE_DEFAULT_INTERVAL_MS) {
printf("%s yes\n", lookup_opcode_name(code));
return;
}
/* FALLTHROUGH */
}
printf("%s %d\n", lookup_opcode_name(code), val);
}
@ -3423,6 +3481,8 @@ dump_client_config(Options *o, const char *host)
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
dump_cfg_int(oObscureKeystrokeTiming,
o->obscure_keystroke_timing_interval);
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.151 2023/07/17 04:08:31 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.152 2023/08/28 03:31:16 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -180,6 +180,7 @@ typedef struct {
int required_rsa_size; /* minimum size of RSA keys */
int enable_escape_commandline; /* ~C commandline */
int obscure_keystroke_timing_interval;
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
@ -222,6 +223,11 @@ typedef struct {
#define SSH_STRICT_HOSTKEY_YES 2
#define SSH_STRICT_HOSTKEY_ASK 3
/* ObscureKeystrokes parameters */
#define SSH_KEYSTROKE_DEFAULT_INTERVAL_MS 20
#define SSH_KEYSTROKE_CHAFF_MIN_MS 1024
#define SSH_KEYSTROKE_CHAFF_RNG_MS 2048
const char *kex_default_pk_alg(void);
char *ssh_connection_hash(const char *thishost, const char *host,
const char *portstr, const char *user);

View File

@ -1,4 +1,4 @@
# $OpenBSD: Makefile,v 1.125 2023/05/17 05:52:01 djm Exp $
# $OpenBSD: Makefile,v 1.126 2023/09/06 23:36:09 djm Exp $
tests: prep file-tests t-exec unit
@ -103,7 +103,8 @@ LTESTS= connect \
agent-restrict \
hostbased \
channel-timeout \
connection-timeout
connection-timeout \
match-subsystem
INTEROP_TESTS= putty-transfer putty-ciphers putty-kex conch-ciphers
#INTEROP_TESTS+=ssh-com ssh-com-client ssh-com-keygen ssh-com-sftp

View File

@ -0,0 +1,90 @@
# $OpenBSD: match-subsystem.sh,v 1.1 2023/09/06 23:36:09 djm Exp $
# Placed in the Public Domain.
tid="sshd_config match subsystem"
cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak
try_subsystem() {
_id=$1
_subsystem=$2
_expect=$3
${SSHD} -tf $OBJ/sshd_proxy || fatal "$_id: bad config"
${SSH} -sF $OBJ/ssh_proxy somehost $_subsystem
_exit=$?
trace "$_id subsystem $_subsystem"
if [ $_exit -ne $_expect ] ; then
fail "$_id: subsystem $_subsystem exit $_exit expected $_expect"
fi
return $?
}
# Simple case: subsystem in main config.
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Subsystem xxx /bin/sh -c "exit 23"
_EOF
try_subsystem "main config" xxx 23
# No clobber in main config.
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Subsystem xxx /bin/sh -c "exit 23"
Subsystem xxx /bin/sh -c "exit 24"
_EOF
try_subsystem "main config no clobber" xxx 23
# Subsystem in match all block
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Match all
Subsystem xxx /bin/sh -c "exit 21"
_EOF
try_subsystem "match all" xxx 21
# No clobber in match all block
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Match all
Subsystem xxx /bin/sh -c "exit 21"
Subsystem xxx /bin/sh -c "exit 24"
_EOF
try_subsystem "match all no clobber" xxx 21
# Subsystem in match user block
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Match user *
Subsystem xxx /bin/sh -c "exit 20"
_EOF
try_subsystem "match user" xxx 20
# No clobber in match user block
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Match user *
Subsystem xxx /bin/sh -c "exit 20"
Subsystem xxx /bin/sh -c "exit 24"
Match all
Subsystem xxx /bin/sh -c "exit 24"
_EOF
try_subsystem "match user no clobber" xxx 20
# Override main with match all
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Subsystem xxx /bin/sh -c "exit 23"
Match all
Subsystem xxx /bin/sh -c "exit 19"
_EOF
try_subsystem "match all override" xxx 19
# Override main with match user
cp $OBJ/sshd_proxy_bak $OBJ/sshd_proxy
cat >> $OBJ/sshd_proxy << _EOF
Subsystem xxx /bin/sh -c "exit 23"
Match user *
Subsystem xxx /bin/sh -c "exit 18"
_EOF
try_subsystem "match user override" xxx 18

View File

@ -1,4 +1,4 @@
# $OpenBSD: scp.sh,v 1.18 2023/01/13 04:47:34 dtucker Exp $
# $OpenBSD: scp.sh,v 1.19 2023/09/08 05:50:57 djm Exp $
# Placed in the Public Domain.
tid="scp"
@ -30,13 +30,25 @@ scpclean() {
chmod 755 ${DIR} ${DIR2} ${DIR3}
}
# Create directory structure for recursive copy tests.
forest() {
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
ln -s ${DIR}/copy ${DIR}/copy-sym
mkdir ${DIR}/subdir
cp ${DATA} ${DIR}/subdir/copy
ln -s ${DIR}/subdir ${DIR}/subdir-sym
}
for mode in scp sftp ; do
tag="$tid: $mode mode"
if test $mode = scp ; then
scpopts="-O -q -S ${OBJ}/scp-ssh-wrapper.scp"
else
scpopts="-s -D ${SFTPSERVER}"
scpopts="-qs -D ${SFTPSERVER}"
fi
verbose "$tag: simple copy local file to local file"
scpclean
$SCP $scpopts ${DATA} ${COPY} || fail "copy failed"
@ -96,21 +108,19 @@ for mode in scp sftp ; do
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: recursive local dir to remote dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
forest
$SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed"
diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tag: recursive local dir to local dir"
scpclean
forest
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r ${DIR} ${DIR2} || fail "copy failed"
diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy"
verbose "$tag: recursive remote dir to local dir"
scpclean
forest
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
$SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed"

View File

@ -1,10 +1,8 @@
# $OpenBSD: scp3.sh,v 1.4 2023/01/13 04:47:34 dtucker Exp $
# $OpenBSD: scp3.sh,v 1.5 2023/09/08 06:10:57 djm Exp $
# Placed in the Public Domain.
tid="scp3"
set -x
COPY2=${OBJ}/copy2
DIR=${COPY}.dd
DIR2=${COPY}.dd2
@ -22,6 +20,17 @@ scpclean() {
chmod 755 ${DIR} ${DIR2}
}
# Create directory structure for recursive copy tests.
forest() {
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
ln -s ${DIR}/copy ${DIR}/copy-sym
mkdir ${DIR}/subdir
cp ${DATA} ${DIR}/subdir/copy
ln -s ${DIR}/subdir ${DIR}/subdir-sym
}
for mode in scp sftp ; do
scpopts="-F${OBJ}/ssh_proxy -S ${SSH} -q"
tag="$tid: $mode mode"
@ -43,9 +52,7 @@ for mode in scp sftp ; do
cmp ${COPY} ${DIR}/copy || fail "corrupted copy"
verbose "$tag: recursive remote dir to remote dir"
scpclean
rm -rf ${DIR2}
cp ${DATA} ${DIR}/copy
forest
$SCP $scpopts -3r hostA:${DIR} hostB:${DIR2} || fail "copy failed"
diff -r ${DIR} ${DIR2} || fail "corrupted copy"
diff -r ${DIR2} ${DIR} || fail "corrupted copy"

50
scp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: scp.c,v 1.257 2023/07/14 05:31:44 djm Exp $ */
/* $OpenBSD: scp.c,v 1.259 2023/09/10 23:12:32 djm Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@ -186,7 +186,7 @@ size_t sftp_nrequests;
/* Needed for sftp */
volatile sig_atomic_t interrupted = 0;
int remote_glob(struct sftp_conn *, const char *, int,
int sftp_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
static void
@ -1028,7 +1028,7 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
reminp, remoutp, pidp) < 0)
return NULL;
}
return do_init(*reminp, *remoutp,
return sftp_init(*reminp, *remoutp,
sftp_copy_buflen, sftp_nrequests, limit_kbps);
}
@ -1324,8 +1324,8 @@ prepare_remote_path(struct sftp_conn *conn, const char *path)
return xstrdup(".");
return xstrdup(path + 2 + nslash);
}
if (can_expand_path(conn))
return do_expand_path(conn, path);
if (sftp_can_expand_path(conn))
return sftp_expand_path(conn, path);
/* No protocol extension */
error("server expand-path extension is required "
"for ~user paths in SFTP mode");
@ -1353,17 +1353,17 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
*/
if ((target = prepare_remote_path(conn, targ)) == NULL)
cleanup_exit(255);
target_is_dir = remote_is_dir(conn, target);
target_is_dir = sftp_remote_is_dir(conn, target);
if (targetshouldbedirectory && !target_is_dir) {
debug("target directory \"%s\" does not exist", target);
a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = st.st_mode | 0700; /* ensure writable */
if (do_mkdir(conn, target, &a, 1) != 0)
if (sftp_mkdir(conn, target, &a, 1) != 0)
cleanup_exit(255); /* error already logged */
target_is_dir = 1;
}
if (target_is_dir)
abs_dst = path_append(target, filename);
abs_dst = sftp_path_append(target, filename);
else {
abs_dst = target;
target = NULL;
@ -1371,12 +1371,12 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
debug3_f("copying local %s to remote %s", src, abs_dst);
if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
if (sftp_upload_dir(conn, src, abs_dst, pflag,
SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
error("failed to upload directory %s to %s", src, targ);
errs = 1;
}
} else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
} else if (sftp_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
error("failed to upload file %s to %s", src, targ);
errs = 1;
}
@ -1568,7 +1568,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
}
debug3_f("copying remote %s to local %s", abs_src, dst);
if ((r = remote_glob(conn, abs_src, GLOB_NOCHECK|GLOB_MARK,
if ((r = sftp_glob(conn, abs_src, GLOB_NOCHECK|GLOB_MARK,
NULL, &g)) != 0) {
if (r == GLOB_NOSPACE)
error("%s: too many glob matches", src);
@ -1585,7 +1585,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
* a GLOB_NOCHECK result. Check whether the unglobbed path
* exists so we can give a nice error message early.
*/
if (do_stat(conn, g.gl_pathv[0], 1) == NULL) {
if (sftp_stat(conn, g.gl_pathv[0], 1, NULL) != 0) {
error("%s: %s", src, strerror(ENOENT));
err = -1;
goto out;
@ -1621,17 +1621,17 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
}
if (dst_is_dir)
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
else
abs_dst = xstrdup(dst);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag, 0, 0, 1) == -1)
err = -1;
}
@ -1993,7 +1993,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
cleanup_exit(255);
memset(&g, 0, sizeof(g));
targetisdir = remote_is_dir(to, target);
targetisdir = sftp_remote_is_dir(to, target);
if (!targetisdir && targetshouldbedirectory) {
error("%s: destination is not a directory", targ);
err = -1;
@ -2001,7 +2001,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
}
debug3_f("copying remote %s to remote %s", abs_src, target);
if ((r = remote_glob(from, abs_src, GLOB_NOCHECK|GLOB_MARK,
if ((r = sftp_glob(from, abs_src, GLOB_NOCHECK|GLOB_MARK,
NULL, &g)) != 0) {
if (r == GLOB_NOSPACE)
error("%s: too many glob matches", src);
@ -2018,7 +2018,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
* a GLOB_NOCHECK result. Check whether the unglobbed path
* exists so we can give a nice error message early.
*/
if (do_stat(from, g.gl_pathv[0], 1) == NULL) {
if (sftp_stat(from, g.gl_pathv[0], 1, NULL) != 0) {
error("%s: %s", src, strerror(ENOENT));
err = -1;
goto out;
@ -2034,18 +2034,18 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
}
if (targetisdir)
abs_dst = path_append(target, filename);
abs_dst = sftp_path_append(target, filename);
else
abs_dst = xstrdup(target);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst,
if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (sftp_crossload_dir(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
err = -1;
} else {
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL,
pflag) == -1)
if (sftp_crossload(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag) == -1)
err = -1;
}
free(abs_dst);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.c,v 1.396 2023/07/17 05:26:38 djm Exp $ */
/* $OpenBSD: servconf.c,v 1.402 2023/09/08 06:34:24 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -643,7 +643,7 @@ static struct {
{ "macs", sMacs, SSHCFG_GLOBAL },
{ "protocol", sIgnore, SSHCFG_GLOBAL },
{ "gatewayports", sGatewayPorts, SSHCFG_ALL },
{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
{ "subsystem", sSubsystem, SSHCFG_ALL },
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
{ "persourcemaxstartups", sPerSourceMaxStartups, SSHCFG_GLOBAL },
{ "persourcenetblocksize", sPerSourceNetBlockSize, SSHCFG_GLOBAL },
@ -1933,39 +1933,54 @@ process_server_config_line_depth(ServerOptions *options, char *line,
break;
case sSubsystem:
if (options->num_subsystems >= MAX_SUBSYSTEMS) {
fatal("%s line %d: too many subsystems defined.",
filename, linenum);
}
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
fatal("%s line %d: %s missing argument.",
filename, linenum, keyword);
if (!*activep) {
arg = argv_next(&ac, &av);
argv_consume(&ac);
break;
}
for (i = 0; i < options->num_subsystems; i++)
if (strcmp(arg, options->subsystem_name[i]) == 0)
fatal("%s line %d: Subsystem '%s' "
"already defined.", filename, linenum, arg);
found = 0;
for (i = 0; i < options->num_subsystems; i++) {
if (strcmp(arg, options->subsystem_name[i]) == 0) {
found = 1;
break;
}
}
if (found) {
debug("%s line %d: Subsystem '%s' already defined.",
filename, linenum, arg);
argv_consume(&ac);
break;
}
options->subsystem_name = xrecallocarray(
options->subsystem_name, options->num_subsystems,
options->num_subsystems + 1,
sizeof(*options->subsystem_name));
options->subsystem_command = xrecallocarray(
options->subsystem_command, options->num_subsystems,
options->num_subsystems + 1,
sizeof(*options->subsystem_command));
options->subsystem_args = xrecallocarray(
options->subsystem_args, options->num_subsystems,
options->num_subsystems + 1,
sizeof(*options->subsystem_args));
options->subsystem_name[options->num_subsystems] = xstrdup(arg);
arg = argv_next(&ac, &av);
if (!arg || *arg == '\0')
if (!arg || *arg == '\0') {
fatal("%s line %d: Missing subsystem command.",
filename, linenum);
options->subsystem_command[options->num_subsystems] = xstrdup(arg);
/* Collect arguments (separate to executable) */
p = xstrdup(arg);
len = strlen(p) + 1;
while ((arg = argv_next(&ac, &av)) != NULL) {
len += 1 + strlen(arg);
p = xreallocarray(p, 1, len);
strlcat(p, " ", len);
strlcat(p, arg, len);
}
options->subsystem_args[options->num_subsystems] = p;
options->subsystem_command[options->num_subsystems] =
xstrdup(arg);
/* Collect arguments (separate to executable) */
arg = argv_assemble(1, &arg); /* quote command correctly */
arg2 = argv_assemble(ac, av); /* rest of command */
xasprintf(&options->subsystem_args[options->num_subsystems],
"%s %s", arg, arg2);
free(arg2);
argv_consume(&ac);
options->num_subsystems++;
break;
@ -2030,7 +2045,7 @@ process_server_config_line_depth(ServerOptions *options, char *line,
fatal("%s line %d: %s integer value %s.",
filename, linenum, keyword, errstr);
}
if (*activep)
if (*activep && options->per_source_max_startups == -1)
options->per_source_max_startups = value;
break;
@ -2679,6 +2694,47 @@ int parse_server_match_testspec(struct connection_info *ci, char *spec)
return 0;
}
void
servconf_merge_subsystems(ServerOptions *dst, ServerOptions *src)
{
u_int i, j, found;
for (i = 0; i < src->num_subsystems; i++) {
found = 0;
for (j = 0; j < dst->num_subsystems; j++) {
if (strcmp(src->subsystem_name[i],
dst->subsystem_name[j]) == 0) {
found = 1;
break;
}
}
if (found) {
debug_f("override \"%s\"", dst->subsystem_name[j]);
free(dst->subsystem_command[j]);
free(dst->subsystem_args[j]);
dst->subsystem_command[j] =
xstrdup(src->subsystem_command[i]);
dst->subsystem_args[j] =
xstrdup(src->subsystem_args[i]);
continue;
}
debug_f("add \"%s\"", src->subsystem_name[i]);
dst->subsystem_name = xrecallocarray(
dst->subsystem_name, dst->num_subsystems,
dst->num_subsystems + 1, sizeof(*dst->subsystem_name));
dst->subsystem_command = xrecallocarray(
dst->subsystem_command, dst->num_subsystems,
dst->num_subsystems + 1, sizeof(*dst->subsystem_command));
dst->subsystem_args = xrecallocarray(
dst->subsystem_args, dst->num_subsystems,
dst->num_subsystems + 1, sizeof(*dst->subsystem_args));
j = dst->num_subsystems++;
dst->subsystem_name[j] = xstrdup(src->subsystem_name[i]);
dst->subsystem_command[j] = xstrdup(src->subsystem_command[i]);
dst->subsystem_args[j] = xstrdup(src->subsystem_args[i]);
}
}
/*
* Copy any supported values that are set.
*
@ -2785,6 +2841,9 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
free(dst->chroot_directory);
dst->chroot_directory = NULL;
}
/* Subsystems require merging. */
servconf_merge_subsystems(dst, src);
}
#undef M_CP_INTOPT

View File

@ -1,4 +1,4 @@
/* $OpenBSD: servconf.h,v 1.159 2023/01/17 09:44:48 djm Exp $ */
/* $OpenBSD: servconf.h,v 1.160 2023/09/06 23:35:35 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -20,8 +20,6 @@
#define MAX_PORTS 256 /* Max # ports. */
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
/* permit_root_login */
#define PERMIT_NOT_SET -1
#define PERMIT_NO 0
@ -165,9 +163,9 @@ typedef struct {
char **deny_groups;
u_int num_subsystems;
char *subsystem_name[MAX_SUBSYSTEMS];
char *subsystem_command[MAX_SUBSYSTEMS];
char *subsystem_args[MAX_SUBSYSTEMS];
char **subsystem_name;
char **subsystem_command;
char **subsystem_args;
u_int num_accept_env;
char **accept_env;
@ -294,6 +292,9 @@ TAILQ_HEAD(include_list, include_item);
M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \
M_CP_STRARRAYOPT(channel_timeouts, num_channel_timeouts); \
M_CP_STRARRAYOPT(log_verbose, num_log_verbose); \
M_CP_STRARRAYOPT(subsystem_name, num_subsystems); \
M_CP_STRARRAYOPT(subsystem_command, num_subsystems); \
M_CP_STRARRAYOPT(subsystem_args, num_subsystems); \
} while (0)
struct connection_info *get_connection_info(struct ssh *, int, int);
@ -310,6 +311,7 @@ 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 servconf_merge_subsystems(ServerOptions *, ServerOptions *);
void copy_set_server_options(ServerOptions *, ServerOptions *, int);
void dump_config(ServerOptions *);
char *derelativise_path(const char *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: serverloop.c,v 1.236 2023/03/08 04:43:12 guenther Exp $ */
/* $OpenBSD: serverloop.c,v 1.237 2023/08/21 04:59:54 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -253,7 +253,7 @@ wait_until_can_do_something(struct ssh *ssh,
/* ClientAliveInterval probing */
if (client_alive_scheduled) {
if (ret == 0 &&
now > last_client_time + options.client_alive_interval) {
now >= last_client_time + options.client_alive_interval) {
/* ppoll timed out and we're due to probe */
client_alive_check(ssh);
last_client_time = now;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: session.c,v 1.335 2023/03/07 06:09:14 dtucker Exp $ */
/* $OpenBSD: session.c,v 1.336 2023/08/10 23:05:48 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@ -2380,17 +2380,17 @@ session_exit_message(struct ssh *ssh, Session *s, int status)
{
Channel *c;
int r;
char *note = NULL;
if ((c = channel_lookup(ssh, s->chanid)) == NULL)
fatal_f("session %d: no channel %d", s->self, s->chanid);
debug_f("session %d channel %d pid %ld",
s->self, s->chanid, (long)s->pid);
if (WIFEXITED(status)) {
channel_request_start(ssh, s->chanid, "exit-status", 0);
if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
xasprintf(&note, "exit %d", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
channel_request_start(ssh, s->chanid, "exit-signal", 0);
#ifndef WCOREDUMP
@ -2402,11 +2402,18 @@ session_exit_message(struct ssh *ssh, Session *s, int status)
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
(r = sshpkt_send(ssh)) != 0)
sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
xasprintf(&note, "signal %d%s", WTERMSIG(status),
WCOREDUMP(status) ? " core dumped" : "");
} else {
/* Some weird exit cause. Just exit. */
ssh_packet_disconnect(ssh, "wait returned status %04x.", status);
ssh_packet_disconnect(ssh, "wait returned status %04x.",
status);
}
debug_f("session %d channel %d pid %ld %s", s->self, s->chanid,
(long)s->pid, note == NULL ? "UNKNOWN" : note);
free(note);
/* disconnect channel */
debug_f("release channel %d", s->chanid);

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.38 2022/09/19 10:43:12 djm Exp $ */
/* $OpenBSD: sftp-client.h,v 1.39 2023/09/08 05:56:13 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@ -70,107 +70,106 @@ struct sftp_limits {
* Initialise a SSH filexfer connection. Returns NULL on error or
* a pointer to a initialized sftp_conn struct on success.
*/
struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t);
struct sftp_conn *sftp_init(int, int, u_int, u_int, u_int64_t);
u_int sftp_proto_version(struct sftp_conn *);
/* Query server limits */
int do_limits(struct sftp_conn *, struct sftp_limits *);
int sftp_get_limits(struct sftp_conn *, struct sftp_limits *);
/* Close file referred to by 'handle' */
int do_close(struct sftp_conn *, const u_char *, u_int);
int sftp_close(struct sftp_conn *, const u_char *, u_int);
/* Read contents of 'path' to NULL-terminated array 'dir' */
int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
int sftp_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */
void free_sftp_dirents(SFTP_DIRENT **);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from sftp_readdir) */
void sftp_free_dirents(SFTP_DIRENT **);
/* Delete file 'path' */
int do_rm(struct sftp_conn *, const char *);
int sftp_rm(struct sftp_conn *, const char *);
/* Create directory 'path' */
int do_mkdir(struct sftp_conn *, const char *, Attrib *, int);
int sftp_mkdir(struct sftp_conn *, const char *, Attrib *, int);
/* Remove directory 'path' */
int do_rmdir(struct sftp_conn *, const char *);
int sftp_rmdir(struct sftp_conn *, const char *);
/* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(struct sftp_conn *, const char *, int);
int sftp_stat(struct sftp_conn *, const char *, int, Attrib *);
/* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(struct sftp_conn *, const char *, int);
int sftp_lstat(struct sftp_conn *, const char *, int, Attrib *);
/* Set file attributes of 'path' */
int do_setstat(struct sftp_conn *, const char *, Attrib *);
int sftp_setstat(struct sftp_conn *, const char *, Attrib *);
/* Set file attributes of open file 'handle' */
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
/* Set file attributes of 'path', not following symlinks */
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
int sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, const char *);
char *sftp_realpath(struct sftp_conn *, const char *);
/* Canonicalisation with tilde expansion (requires server extension) */
char *do_expand_path(struct sftp_conn *, const char *);
char *sftp_expand_path(struct sftp_conn *, const char *);
/* Returns non-zero if server can tilde-expand paths */
int can_expand_path(struct sftp_conn *);
int sftp_can_expand_path(struct sftp_conn *);
/* Get statistics for filesystem hosting file at "path" */
int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
int sftp_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
/* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, const char *, const char *, int);
int sftp_rename(struct sftp_conn *, const char *, const char *, int);
/* Copy 'oldpath' to 'newpath' */
int do_copy(struct sftp_conn *, const char *, const char *);
int sftp_copy(struct sftp_conn *, const char *, const char *);
/* Link 'oldpath' to 'newpath' */
int do_hardlink(struct sftp_conn *, const char *, const char *);
int sftp_hardlink(struct sftp_conn *, const char *, const char *);
/* Rename 'oldpath' to 'newpath' */
int do_symlink(struct sftp_conn *, const char *, const char *);
int sftp_symlink(struct sftp_conn *, const char *, const char *);
/* Call fsync() on open file 'handle' */
int do_fsync(struct sftp_conn *conn, u_char *, u_int);
int sftp_fsync(struct sftp_conn *conn, u_char *, u_int);
/*
* Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_download(struct sftp_conn *, const char *, const char *, Attrib *,
int sftp_download(struct sftp_conn *, const char *, const char *, Attrib *,
int, int, int, int);
/*
* Recursively download 'remote_directory' to 'local_directory'. Preserve
* times if 'pflag' is set
*/
int download_dir(struct sftp_conn *, const char *, const char *, Attrib *,
int sftp_download_dir(struct sftp_conn *, const char *, const char *, Attrib *,
int, int, int, int, int, int);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
int do_upload(struct sftp_conn *, const char *, const char *,
int sftp_upload(struct sftp_conn *, const char *, const char *,
int, int, int, int);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set
*/
int upload_dir(struct sftp_conn *, const char *, const char *,
int sftp_upload_dir(struct sftp_conn *, const char *, const char *,
int, int, int, int, int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to
* to 'to' connection at 'to_path'.
*/
int
do_crossload(struct sftp_conn *from, struct sftp_conn *to,
int sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *a, int preserve_flag);
@ -178,7 +177,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
* Recursively download a directory from 'from_path' from the 'from'
* connection and upload it to 'to' connection at 'to_path'.
*/
int crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
int sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
Attrib *dirattrib, int preserve_flag, int print_flag,
int follow_link_flag);
@ -186,26 +185,23 @@ int crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
/*
* User/group ID to name translation.
*/
int can_get_users_groups_by_id(struct sftp_conn *conn);
int do_get_users_groups_by_id(struct sftp_conn *conn,
int sftp_can_get_users_groups_by_id(struct sftp_conn *conn);
int sftp_get_users_groups_by_id(struct sftp_conn *conn,
const u_int *uids, u_int nuids,
const u_int *gids, u_int ngids,
char ***usernamesp, char ***groupnamesp);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(const char *, const char *);
char *sftp_path_append(const char *, const char *);
/* Make absolute path if relative path and CWD is given. Does not modify
* original if the path is already absolute. */
char *make_absolute(char *, const char *);
char *sftp_make_absolute(char *, const char *);
/* Check if remote path is directory */
int remote_is_dir(struct sftp_conn *conn, const char *path);
/* Check if local path is directory */
int local_is_dir(const char *path);
int sftp_remote_is_dir(struct sftp_conn *conn, const char *path);
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
int globpath_is_dir(const char *pathname);
int sftp_globpath_is_dir(const char *pathname);
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-glob.c,v 1.31 2022/10/24 21:51:55 djm Exp $ */
/* $OpenBSD: sftp-glob.c,v 1.33 2023/09/10 23:12:32 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -32,7 +32,7 @@
#include "sftp-common.h"
#include "sftp-client.h"
int remote_glob(struct sftp_conn *, const char *, int,
int sftp_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *);
struct SFTP_OPENDIR {
@ -51,7 +51,7 @@ fudge_opendir(const char *path)
r = xcalloc(1, sizeof(*r));
if (do_readdir(cur.conn, path, &r->dir)) {
if (sftp_readdir(cur.conn, path, &r->dir)) {
free(r);
return(NULL);
}
@ -103,38 +103,38 @@ fudge_readdir(struct SFTP_OPENDIR *od)
static void
fudge_closedir(struct SFTP_OPENDIR *od)
{
free_sftp_dirents(od->dir);
sftp_free_dirents(od->dir);
free(od);
}
static int
fudge_lstat(const char *path, struct stat *st)
{
Attrib *a;
Attrib a;
if (!(a = do_lstat(cur.conn, path, 1)))
return(-1);
if (sftp_lstat(cur.conn, path, 1, &a) != 0)
return -1;
attrib_to_stat(a, st);
attrib_to_stat(&a, st);
return(0);
return 0;
}
static int
fudge_stat(const char *path, struct stat *st)
{
Attrib *a;
Attrib a;
if (!(a = do_stat(cur.conn, path, 1)))
return(-1);
if (sftp_stat(cur.conn, path, 1, &a) != 0)
return -1;
attrib_to_stat(a, st);
attrib_to_stat(&a, st);
return(0);
}
int
remote_glob(struct sftp_conn *conn, const char *pattern, int flags,
sftp_glob(struct sftp_conn *conn, const char *pattern, int flags,
int (*errfunc)(const char *, int), glob_t *pglob)
{
int r;

View File

@ -106,9 +106,9 @@ lookup_and_record(struct sftp_conn *conn,
u_int i;
char **usernames = NULL, **groupnames = NULL;
if ((r = do_get_users_groups_by_id(conn, uids, nuids, gids, ngids,
if ((r = sftp_get_users_groups_by_id(conn, uids, nuids, gids, ngids,
&usernames, &groupnames)) != 0) {
debug_fr(r, "do_get_users_groups_by_id");
debug_fr(r, "sftp_get_users_groups_by_id");
return;
}
for (i = 0; i < nuids; i++) {
@ -176,7 +176,7 @@ get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g)
{
u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
if (!can_get_users_groups_by_id(conn))
if (!sftp_can_get_users_groups_by_id(conn))
return;
collect_ids_from_glob(g, 1, &uids, &nuids);
@ -215,7 +215,7 @@ get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d)
{
u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
if (!can_get_users_groups_by_id(conn))
if (!sftp_can_get_users_groups_by_id(conn))
return;
collect_ids_from_dirents(d, 1, &uids, &nuids);

138
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.234 2023/04/12 08:53:54 jsg Exp $ */
/* $OpenBSD: sftp.c,v 1.236 2023/09/10 23:12:32 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -110,7 +110,7 @@ struct complete_ctx {
char **remote_pathp;
};
int remote_glob(struct sftp_conn *, const char *, int,
int sftp_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
extern char *__progname;
@ -628,11 +628,21 @@ make_absolute_pwd_glob(char *p, const char *pwd)
escpwd = escape_glob(pwd);
if (p == NULL)
return escpwd;
ret = make_absolute(p, escpwd);
ret = sftp_make_absolute(p, escpwd);
free(escpwd);
return ret;
}
static int
local_is_dir(const char *path)
{
struct stat sb;
if (stat(path, &sb) == -1)
return 0;
return S_ISDIR(sb.st_mode);
}
static int
process_get(struct sftp_conn *conn, const char *src, const char *dst,
const char *pwd, int pflag, int rflag, int resume, int fflag)
@ -645,7 +655,7 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
memset(&g, 0, sizeof(g));
debug3("Looking up %s", abs_src);
if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
if ((r = sftp_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) {
if (r == GLOB_NOSPACE) {
error("Too many matches for \"%s\".", abs_src);
} else {
@ -677,12 +687,12 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
if (g.gl_matchc == 1 && dst) {
if (local_is_dir(dst)) {
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
} else {
abs_dst = xstrdup(dst);
}
} else if (dst) {
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
} else {
abs_dst = xstrdup(filename);
}
@ -696,13 +706,14 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
mprintf("Fetching %s to %s\n",
g.gl_pathv[i], abs_dst);
/* XXX follow link flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, 1, resume,
if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
(rflag || global_rflag)) {
if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
NULL, pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, resume,
fflag || global_fflag, 0) == -1)
err = -1;
@ -731,7 +742,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
if (dst) {
tmp_dst = xstrdup(dst);
tmp_dst = make_absolute(tmp_dst, pwd);
tmp_dst = sftp_make_absolute(tmp_dst, pwd);
}
memset(&g, 0, sizeof(g));
@ -744,7 +755,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
/* If we aren't fetching to pwd then stash this status for later */
if (tmp_dst != NULL)
dst_is_dir = remote_is_dir(conn, tmp_dst);
dst_is_dir = sftp_remote_is_dir(conn, tmp_dst);
/* If multiple matches, dst may be directory or unspecified */
if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
@ -774,13 +785,13 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
if (g.gl_matchc == 1 && tmp_dst) {
/* If directory specified, append filename */
if (dst_is_dir)
abs_dst = path_append(tmp_dst, filename);
abs_dst = sftp_path_append(tmp_dst, filename);
else
abs_dst = xstrdup(tmp_dst);
} else if (tmp_dst) {
abs_dst = path_append(tmp_dst, filename);
abs_dst = sftp_path_append(tmp_dst, filename);
} else {
abs_dst = make_absolute(xstrdup(filename), pwd);
abs_dst = sftp_make_absolute(xstrdup(filename), pwd);
}
free(tmp);
@ -792,13 +803,14 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
mprintf("Uploading %s to %s\n",
g.gl_pathv[i], abs_dst);
/* XXX follow_link_flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
(rflag || global_rflag)) {
if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
if (sftp_upload(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, resume,
fflag || global_fflag, 0) == -1)
err = -1;
@ -839,7 +851,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
u_int c = 1, colspace = 0, columns = 1;
SFTP_DIRENT **d;
if ((n = do_readdir(conn, path, &d)) != 0)
if ((n = sftp_readdir(conn, path, &d)) != 0)
return (n);
if (!(lflag & LS_SHORT_VIEW)) {
@ -881,13 +893,13 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
continue;
tmp = path_append(path, d[n]->filename);
tmp = sftp_path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path);
free(tmp);
if (lflag & LS_LONG_VIEW) {
if ((lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) != 0 ||
can_get_users_groups_by_id(conn)) {
sftp_can_get_users_groups_by_id(conn)) {
char *lname;
struct stat sb;
@ -916,7 +928,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
free_sftp_dirents(d);
sftp_free_dirents(d);
return (0);
}
@ -965,7 +977,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path,
memset(&g, 0, sizeof(g));
if ((r = remote_glob(conn, path,
if ((r = sftp_glob(conn, path,
GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
NULL, &g)) != 0 ||
(g.gl_pathc && !g.gl_matchc)) {
@ -1070,7 +1082,7 @@ do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
char s_icapacity[16], s_dcapacity[16];
if (do_statvfs(conn, path, &st, 1) == -1)
if (sftp_statvfs(conn, path, &st, 1) == -1)
return -1;
if (st.f_files == 0)
strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
@ -1544,7 +1556,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
int cmdnum, i;
unsigned long n_arg = 0;
Attrib a, *aa;
Attrib a, aa;
char path_buf[PATH_MAX];
int err = 0;
glob_t g;
@ -1585,66 +1597,67 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
rflag, aflag, fflag);
break;
case I_COPY:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_copy(conn, path1, path2);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = sftp_copy(conn, path1, path2);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_rename(conn, path1, path2, lflag);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = sftp_rename(conn, path1, path2, lflag);
break;
case I_SYMLINK:
sflag = 1;
/* FALLTHROUGH */
case I_LINK:
if (!sflag)
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = (sflag ? sftp_symlink : sftp_hardlink)(conn,
path1, path2);
break;
case I_RM:
path1 = make_absolute_pwd_glob(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
sftp_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!quiet)
mprintf("Removing %s\n", g.gl_pathv[i]);
err = do_rm(conn, g.gl_pathv[i]);
err = sftp_rm(conn, g.gl_pathv[i]);
if (err != 0 && err_abort)
break;
}
break;
case I_MKDIR:
path1 = make_absolute(path1, *pwd);
path1 = sftp_make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
err = do_mkdir(conn, path1, &a, 1);
err = sftp_mkdir(conn, path1, &a, 1);
break;
case I_RMDIR:
path1 = make_absolute(path1, *pwd);
err = do_rmdir(conn, path1);
path1 = sftp_make_absolute(path1, *pwd);
err = sftp_rmdir(conn, path1);
break;
case I_CHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL) {
path1 = sftp_make_absolute(path1, *pwd);
if ((tmp = sftp_realpath(conn, path1)) == NULL) {
err = 1;
break;
}
if ((aa = do_stat(conn, tmp, 0)) == NULL) {
if (sftp_stat(conn, tmp, 0, &aa) != 0) {
free(tmp);
err = 1;
break;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
if (!(aa.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
error("Can't change directory: Can't check target");
free(tmp);
err = 1;
break;
}
if (!S_ISDIR(aa->perm)) {
if (!S_ISDIR(aa.perm)) {
error("Can't change directory: \"%s\" is not "
"a directory", tmp);
free(tmp);
@ -1672,7 +1685,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
/* Default to current directory if no path specified */
if (path1 == NULL)
path1 = xstrdup(*pwd);
path1 = make_absolute(path1, *pwd);
path1 = sftp_make_absolute(path1, *pwd);
err = do_df(conn, path1, hflag, iflag);
break;
case I_LCHDIR:
@ -1709,12 +1722,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = n_arg;
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
sftp_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!quiet)
mprintf("Changing mode on %s\n",
g.gl_pathv[i]);
err = (hflag ? do_lsetstat : do_setstat)(conn,
err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], &a);
if (err != 0 && err_abort)
break;
@ -1723,17 +1736,17 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
case I_CHOWN:
case I_CHGRP:
path1 = make_absolute_pwd_glob(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
sftp_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!(aa = (hflag ? do_lstat : do_stat)(conn,
g.gl_pathv[i], 0))) {
if ((hflag ? sftp_lstat : sftp_stat)(conn,
g.gl_pathv[i], 0, &aa) != 0) {
if (err_abort) {
err = -1;
break;
} else
continue;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
if (!(aa.flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]);
if (err_abort) {
@ -1742,20 +1755,20 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
} else
continue;
}
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
aa.flags &= SSH2_FILEXFER_ATTR_UIDGID;
if (cmdnum == I_CHOWN) {
if (!quiet)
mprintf("Changing owner on %s\n",
g.gl_pathv[i]);
aa->uid = n_arg;
aa.uid = n_arg;
} else {
if (!quiet)
mprintf("Changing group on %s\n",
g.gl_pathv[i]);
aa->gid = n_arg;
aa.gid = n_arg;
}
err = (hflag ? do_lsetstat : do_setstat)(conn,
g.gl_pathv[i], aa);
err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], &aa);
if (err != 0 && err_abort)
break;
}
@ -2004,7 +2017,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
memset(&g, 0, sizeof(g));
if (remote != LOCAL) {
tmp = make_absolute_pwd_glob(tmp, remote_path);
remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
sftp_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
} else
(void)glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
@ -2234,16 +2247,15 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
}
#endif /* USE_LIBEDIT */
remote_path = do_realpath(conn, ".");
if (remote_path == NULL)
if ((remote_path = sftp_realpath(conn, ".")) == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);
if (file1 != NULL) {
dir = xstrdup(file1);
dir = make_absolute(dir, remote_path);
dir = sftp_make_absolute(dir, remote_path);
if (remote_is_dir(conn, dir) && file2 == NULL) {
if (sftp_remote_is_dir(conn, dir) && file2 == NULL) {
if (!quiet)
mprintf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
@ -2652,7 +2664,7 @@ main(int argc, char **argv)
}
freeargs(&args);
conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
conn = sftp_init(in, out, copy_buffer_len, num_requests, limit_kbps);
if (conn == NULL)
fatal("Couldn't initialise connection to server");

View File

@ -48,7 +48,7 @@ DESCRIPTION
only local clients may perform this operation. Note that
signalling that an ssh-agent client is remote is performed by
ssh(1), and use of other tools to forward access to the agent
socket, may circumvent this restriction.
socket may circumvent this restriction.
The no-restrict-websafe option instructs ssh-agent to permit
signatures using FIDO keys that might be web authentication
@ -66,7 +66,7 @@ DESCRIPTION
used with the -S or -s options to ssh-add(1). Libraries that do
not match the pattern list will be refused. See PATTERNS in
ssh_config(5) for a description of pattern-list syntax. The
default list is M-bM-^@M-^\/usr/lib/*,/usr/local/lib/*M-bM-^@M-^].
default list is M-bM-^@M-^\usr/lib*/*,/usr/local/lib*/*M-bM-^@M-^].
-s Generate Bourne shell commands on stdout. This is the default if
SHELL does not look like it's a csh style of shell.
@ -137,4 +137,4 @@ AUTHORS
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
OpenBSD 7.3 July 23, 2023 OpenBSD 7.3
OpenBSD 7.3 August 10, 2023 OpenBSD 7.3

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-agent.1,v 1.78 2023/07/23 20:04:45 naddy Exp $
.\" $OpenBSD: ssh-agent.1,v 1.79 2023/08/10 14:37:32 naddy Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -34,7 +34,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: July 23 2023 $
.Dd $Mdocdate: August 10 2023 $
.Dt SSH-AGENT 1
.Os
.Sh NAME
@ -122,7 +122,7 @@ Note that signalling that an
.Nm
client is remote is performed by
.Xr ssh 1 ,
and use of other tools to forward access to the agent socket, may circumvent
and use of other tools to forward access to the agent socket may circumvent
this restriction.
.Pp
The
@ -156,7 +156,7 @@ See PATTERNS in
.Xr ssh_config 5
for a description of pattern-list syntax.
The default list is
.Dq /usr/lib/*,/usr/local/lib/* .
.Dq usr/lib*/*,/usr/local/lib*/* .
.It Fl s
Generate Bourne shell commands on
.Dv stdout .

View File

@ -46,7 +46,7 @@ DESCRIPTION
ssh(1). ssh-keygen can create keys for use by SSH protocol version 2.
The type of key to be generated is specified with the -t option. If
invoked without any arguments, ssh-keygen will generate an RSA key.
invoked without any arguments, ssh-keygen will generate an Ed25519 key.
ssh-keygen is also used to generate groups for use in Diffie-Hellman
group exchange (DH-GEX). See the MODULI GENERATION section for details.
@ -907,4 +907,4 @@ AUTHORS
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
OpenBSD 7.3 July 23, 2023 OpenBSD 7.3
OpenBSD 7.3 September 4, 2023 OpenBSD 7.3

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.229 2023/07/23 20:04:45 naddy Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.230 2023/09/04 10:29:58 job Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: July 23 2023 $
.Dd $Mdocdate: September 4 2023 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
@ -185,7 +185,7 @@ The type of key to be generated is specified with the
option.
If invoked without any arguments,
.Nm
will generate an RSA key.
will generate an Ed25519 key.
.Pp
.Nm
is also used to generate groups for use in Diffie-Hellman group

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.470 2023/07/17 04:01:10 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.471 2023/09/04 10:29:58 job Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -67,11 +67,7 @@
#include "sk-api.h" /* XXX for SSH_SK_USER_PRESENCE_REQD; remove */
#include "cipher.h"
#ifdef WITH_OPENSSL
# define DEFAULT_KEY_TYPE_NAME "rsa"
#else
# define DEFAULT_KEY_TYPE_NAME "ed25519"
#endif
#define DEFAULT_KEY_TYPE_NAME "ed25519"
/*
* Default number of bits in the RSA, DSA and ECDSA keys. These value can be
@ -263,7 +259,7 @@ ask_filename(struct passwd *pw, const char *prompt)
char *name = NULL;
if (key_type_name == NULL)
name = _PATH_SSH_CLIENT_ID_RSA;
name = _PATH_SSH_CLIENT_ID_ED25519;
else {
switch (sshkey_type_from_name(key_type_name)) {
case KEY_DSA_CERT:

11
ssh.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh.c,v 1.593 2023/07/26 23:06:00 djm Exp $ */
/* $OpenBSD: ssh.c,v 1.594 2023/09/03 23:59:32 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -2140,7 +2140,7 @@ ssh_session2_open(struct ssh *ssh)
static int
ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo)
{
int r, id = -1;
int r, interactive, id = -1;
char *cp, *tun_fwd_ifname = NULL;
/* XXX should be pre-session */
@ -2197,8 +2197,11 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo)
if (options.session_type != SESSION_TYPE_NONE)
id = ssh_session2_open(ssh);
else {
ssh_packet_set_interactive(ssh,
options.control_master == SSHCTL_MASTER_NO,
interactive = options.control_master == SSHCTL_MASTER_NO;
/* ControlPersist may have clobbered ControlMaster, so check */
if (need_controlpersist_detach)
interactive = otty_flag != 0;
ssh_packet_set_interactive(ssh, interactive,
options.ip_qos_interactive, options.ip_qos_bulk);
}

7
ssh2.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh2.h,v 1.19 2020/11/19 23:05:05 dtucker Exp $ */
/* $OpenBSD: ssh2.h,v 1.21 2023/08/28 03:28:43 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
@ -85,6 +85,7 @@
#define SSH2_MSG_SERVICE_REQUEST 5
#define SSH2_MSG_SERVICE_ACCEPT 6
#define SSH2_MSG_EXT_INFO 7
#define SSH2_MSG_NEWCOMPRESS 8
/* transport layer: alg negotiation */
@ -107,6 +108,10 @@
#define SSH2_MSG_KEX_ECDH_INIT 30
#define SSH2_MSG_KEX_ECDH_REPLY 31
/* transport layer: OpenSSH extensions */
#define SSH2_MSG_PING 192
#define SSH2_MSG_PONG 193
/* user authentication: generic */
#define SSH2_MSG_USERAUTH_REQUEST 50

View File

@ -805,6 +805,18 @@ DESCRIPTION
Specifies the number of password prompts before giving up. The
argument to this keyword must be an integer. The default is 3.
ObscureKeystrokeTiming
Specifies whether ssh(1) should try to obscure inter-keystroke
timings from passive observers of network traffic. If enabled,
then for interactive sessions, ssh(1) will send keystrokes at
fixed intervals of a few tens of milliseconds and will send fake
keystroke packets for some time after typing ceases. The
argument to this keyword must be yes, no or an interval specifier
of the form interval:milliseconds (e.g. interval:80 for 80
milliseconds). The default is to obscure keystrokes using a 20ms
packet interval. Note that smaller intervals will result in
higher fake keystroke packet rates.
PasswordAuthentication
Specifies whether to use password authentication. The argument
to this keyword must be yes (the default) or no.
@ -1306,6 +1318,13 @@ TOKENS
ProxyCommand and ProxyJump accept the tokens %%, %h, %n, %p, and %r.
Note that some of these directives build commands for execution via the
shell. Because ssh(1) performs no filtering or escaping of characters
that have special meaning in shell commands (e.g. quotes), it is the
user's reposibility to ensure that the arguments passed to ssh(1) do not
contain such characters and that tokens are appropriately quoted when
used.
ENVIRONMENT VARIABLES
Arguments to some keywords can be expanded at runtime from environment
variables on the client by enclosing them in ${}, for example
@ -1341,4 +1360,4 @@ AUTHORS
created OpenSSH. Markus Friedl contributed the support for SSH protocol
versions 1.5 and 2.0.
OpenBSD 7.3 July 17, 2023 OpenBSD 7.3
OpenBSD 7.3 October 4, 2023 OpenBSD 7.3

View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: ssh_config.5,v 1.383 2023/07/17 05:36:14 jsg Exp $
.Dd $Mdocdate: July 17 2023 $
.\" $OpenBSD: ssh_config.5,v 1.387 2023/10/04 04:03:50 djm Exp $
.Dd $Mdocdate: October 4 2023 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@ -1358,6 +1358,25 @@ or
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
The default is 3.
.It Cm ObscureKeystrokeTiming
Specifies whether
.Xr ssh 1
should try to obscure inter-keystroke timings from passive observers of
network traffic.
If enabled, then for interactive sessions,
.Xr ssh 1
will send keystrokes at fixed intervals of a few tens of milliseconds
and will send fake keystroke packets for some time after typing ceases.
The argument to this keyword must be
.Cm yes ,
.Cm no
or an interval specifier of the form
.Cm interval:milliseconds
(e.g.\&
.Cm interval:80
for 80 milliseconds).
The default is to obscure keystrokes using a 20ms packet interval.
Note that smaller intervals will result in higher fake keystroke packet rates.
.It Cm PasswordAuthentication
Specifies whether to use password authentication.
The argument to this keyword must be
@ -2187,6 +2206,16 @@ accepts all tokens.
and
.Cm ProxyJump
accept the tokens %%, %h, %n, %p, and %r.
.Pp
Note that some of these directives build commands for execution via the shell.
Because
.Xr ssh 1
performs no filtering or escaping of characters that have special meaning in
shell commands (e.g. quotes), it is the user's reposibility to ensure that
the arguments passed to
.Xr ssh 1
do not contain such characters and that tokens are appropriately quoted
when used.
.Sh ENVIRONMENT VARIABLES
Arguments to some keywords can be expanded at runtime from environment
variables on the client by enclosing them in

4
sshd.0
View File

@ -168,7 +168,7 @@ AUTHENTICATION
secure channel.
After this, the client either requests an interactive shell or execution
or a non-interactive command, which sshd will execute via the user's
of a non-interactive command, which sshd will execute via the user's
shell using its -c option. The sides then enter session mode. In this
mode, either side may send data at any time, and such data is forwarded
to/from the shell or command on the server side, and the user terminal in
@ -683,4 +683,4 @@ AUTHORS
versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support
for privilege separation.
OpenBSD 7.3 February 10, 2023 OpenBSD 7.3
OpenBSD 7.3 September 19, 2023 OpenBSD 7.3

6
sshd.8
View File

@ -33,8 +33,8 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $OpenBSD: sshd.8,v 1.324 2023/02/10 06:39:27 jmc Exp $
.Dd $Mdocdate: February 10 2023 $
.\" $OpenBSD: sshd.8,v 1.325 2023/09/19 20:37:07 deraadt Exp $
.Dd $Mdocdate: September 19 2023 $
.Dt SSHD 8
.Os
.Sh NAME
@ -320,7 +320,7 @@ forwarding TCP connections, or forwarding the authentication agent
connection over the secure channel.
.Pp
After this, the client either requests an interactive shell or execution
or a non-interactive command, which
of a non-interactive command, which
.Nm
will execute via the user's shell using its
.Fl c

2
sshd.c
View File

@ -1697,7 +1697,7 @@ main(int ac, char **av)
break;
case 'V':
fprintf(stderr, "%s, %s\n",
SSH_VERSION, SSH_OPENSSL_VERSION);
SSH_RELEASE, SSH_OPENSSL_VERSION);
exit(0);
default:
usage();

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshkey.c,v 1.137 2023/07/27 22:23:05 djm Exp $ */
/* $OpenBSD: sshkey.c,v 1.138 2023/08/21 04:36:46 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@ -41,6 +41,7 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <resolv.h>
#include <time.h>

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshsig.c,v 1.32 2023/04/06 03:56:02 djm Exp $ */
/* $OpenBSD: sshsig.c,v 1.33 2023/09/06 23:18:15 djm Exp $ */
/*
* Copyright (c) 2019 Google LLC
*
@ -38,7 +38,7 @@
#define SIG_VERSION 0x01
#define MAGIC_PREAMBLE "SSHSIG"
#define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1)
#define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----\n"
#define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
#define END_SIGNATURE "-----END SSH SIGNATURE-----"
#define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */
#define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
@ -59,8 +59,7 @@ sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
goto out;
}
if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
sizeof(BEGIN_SIGNATURE)-1)) != 0) {
if ((r = sshbuf_putf(buf, "%s\n", BEGIN_SIGNATURE)) != 0) {
error_fr(r, "sshbuf_putf");
goto out;
}
@ -99,23 +98,35 @@ sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
return SSH_ERR_ALLOC_FAIL;
}
/* Expect and consume preamble + lf/crlf */
if ((r = sshbuf_cmp(sbuf, 0,
BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error("Couldn't parse signature: missing header");
goto done;
}
if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error_fr(r, "consume");
goto done;
}
if ((r = sshbuf_cmp(sbuf, 0, "\r\n", 2)) == 0)
eoffset = 2;
else if ((r = sshbuf_cmp(sbuf, 0, "\n", 1)) == 0)
eoffset = 1;
else {
r = SSH_ERR_INVALID_FORMAT;
error_f("no header eol");
goto done;
}
if ((r = sshbuf_consume(sbuf, eoffset)) != 0) {
error_fr(r, "consume eol");
goto done;
}
/* Find and consume lf + suffix (any prior cr would be ignored) */
if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
sizeof(END_SIGNATURE), &eoffset)) != 0) {
error("Couldn't parse signature: missing footer");
goto done;
}
if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
error_fr(r, "consume");
goto done;

View File

@ -1,6 +1,6 @@
/* $OpenBSD: version.h,v 1.98 2023/08/10 01:01:07 djm Exp $ */
/* $OpenBSD: version.h,v 1.99 2023/10/04 04:04:09 djm Exp $ */
#define SSH_VERSION "OpenSSH_9.4"
#define SSH_VERSION "OpenSSH_9.5"
#define SSH_PORTABLE "p1"
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE