From 6f79ebd4c9fdd1a68bcb3f523b4d0004816e0212 Mon Sep 17 00:00:00 2001 From: purplerain Date: Mon, 14 Oct 2024 16:24:39 +0000 Subject: [PATCH] sync with OpenBSD -current --- bin/mv/cp.c | 51 +- distrib/sets/lists/base/mi | 3 + etc/rc | 4 +- lib/libcrypto/ec/ec_asn1.c | 92 ++- lib/libssl/man/SSL_alert_type_string.3 | 6 +- regress/lib/libcrypto/ec/ec_asn1_test.c | 55 +- regress/usr.bin/ssh/test-exec.sh | 7 +- share/man/man4/ddb.4 | 19 +- sys/arch/amd64/amd64/acpi_machdep.c | 8 +- sys/arch/arm64/arm64/process_machdep.c | 3 +- sys/arch/arm64/include/intr.h | 3 +- sys/arch/arm64/include/pte.h | 4 +- sys/arch/armv7/include/intr.h | 3 +- sys/dev/midivar.h | 3 +- sys/net/if_wg.h | 5 +- sys/netinet/ip_mroute.h | 4 +- sys/ufs/ufs/dirhash.h | 4 +- usr.bin/rsync/socket.c | 3 +- usr.bin/ssh/Makefile | 4 +- usr.bin/ssh/Makefile.inc | 8 +- usr.bin/ssh/channels.c | 21 +- usr.bin/ssh/channels.h | 3 +- usr.bin/ssh/clientloop.c | 7 +- usr.bin/ssh/log.c | 6 +- usr.bin/ssh/monitor.c | 109 ++- usr.bin/ssh/monitor.h | 5 +- usr.bin/ssh/monitor_wrap.c | 83 ++- usr.bin/ssh/monitor_wrap.h | 8 +- usr.bin/ssh/pathnames.h | 3 +- usr.bin/ssh/sandbox-pledge.c | 71 -- usr.bin/ssh/sandbox-rlimit.c | 86 --- usr.bin/ssh/servconf.c | 13 +- usr.bin/ssh/servconf.h | 3 +- usr.bin/ssh/session.c | 9 +- usr.bin/ssh/ssh-sandbox.h | 23 - usr.bin/ssh/sshd-auth.c | 836 ++++++++++++++++++++++++ usr.bin/ssh/sshd-auth/Makefile | 71 ++ usr.bin/ssh/sshd-session.c | 316 +++------ usr.bin/ssh/sshd-session/Makefile | 4 +- usr.bin/ssh/sshd.c | 9 +- 40 files changed, 1378 insertions(+), 597 deletions(-) create mode 100644 usr.bin/ssh/sshd-auth.c create mode 100644 usr.bin/ssh/sshd-auth/Makefile diff --git a/bin/mv/cp.c b/bin/mv/cp.c index 246a8273d..91e31688c 100644 --- a/bin/mv/cp.c +++ b/bin/mv/cp.c @@ -1,5 +1,6 @@ -/* $OpenBSD: cp.c,v 1.10 2021/11/28 19:28:41 deraadt Exp $ */ +/* $OpenBSD: cp.c,v 1.11 2024/10/14 08:26:48 jsg Exp $ */ /* $NetBSD: cp.c,v 1.14 1995/09/07 06:14:51 jtc Exp $ */ +/* $NetBSD: utils.c,v 1.6 1997/02/26 14:40:51 cgd Exp $ */ /* * Copyright (c) 1988, 1993, 1994 @@ -385,54 +386,6 @@ copy(char *argv[], enum op type, int fts_options) return (rval); } - -/* $OpenBSD: cp.c,v 1.10 2021/11/28 19:28:41 deraadt Exp $ */ -/* $NetBSD: utils.c,v 1.6 1997/02/26 14:40:51 cgd Exp $ */ - -/*- - * Copyright (c) 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - #define _MAXBSIZE (64 * 1024) static int diff --git a/distrib/sets/lists/base/mi b/distrib/sets/lists/base/mi index 7bce2c9be..bfda0a59c 100644 --- a/distrib/sets/lists/base/mi +++ b/distrib/sets/lists/base/mi @@ -2536,6 +2536,7 @@ ./usr/libexec/ssh-pkcs11-helper ./usr/libexec/ssh-sk-helper ./usr/libexec/sshd-session +./usr/libexec/sshd-auth ./usr/libexec/tradcpp ./usr/libexec/vi.recover ./usr/local @@ -2985,6 +2986,8 @@ ./usr/share/relink/usr/lib/libcrypto.so.55.0.a ./usr/share/relink/usr/libexec ./usr/share/relink/usr/libexec/ld.so.a +./usr/share/relink/usr/libexec/sshd-auth +./usr/share/relink/usr/libexec/sshd-auth/sshd-auth.tar ./usr/share/relink/usr/libexec/sshd-session ./usr/share/relink/usr/libexec/sshd-session/sshd-session.tar ./usr/share/relink/usr/sbin diff --git a/etc/rc b/etc/rc index 85250cceb..5ded55cbd 100644 --- a/etc/rc +++ b/etc/rc @@ -1,4 +1,4 @@ -# $OpenBSD: rc,v 1.576 2024/06/03 10:06:35 florian Exp $ +# $OpenBSD: rc,v 1.577 2024/10/14 02:46:50 deraadt Exp $ # System startup script run by init on autoboot or after single-user. # Output and error are redirected to console by init, and the console is the @@ -242,7 +242,7 @@ reorder_libs() { done for _bin in $_relink/usr/sbin/sshd $_relink/usr/libexec/sshd-session \ - $_relink/usr/bin/ssh-agent ; do + $_relink/usr/bin/sshd-auth $_relink/usr/bin/ssh-agent ; do _tmpdir=$(mktemp -dq $_relink/_rebuild.XXXXXXXXXXXX) && ( set -o errexit diff --git a/lib/libcrypto/ec/ec_asn1.c b/lib/libcrypto/ec/ec_asn1.c index 865934ccf..8d0f03290 100644 --- a/lib/libcrypto/ec/ec_asn1.c +++ b/lib/libcrypto/ec/ec_asn1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ec_asn1.c,v 1.68 2024/10/11 18:58:04 tb Exp $ */ +/* $OpenBSD: ec_asn1.c,v 1.71 2024/10/14 12:50:18 tb Exp $ */ /* * Written by Nils Larsch for the OpenSSL project. */ @@ -601,15 +601,41 @@ ec_asn1_group2fieldid(const EC_GROUP *group, X9_62_FIELDID *field) return ret; } +static int +ec_asn1_encode_field_element(const EC_GROUP *group, const BIGNUM *bn, + ASN1_OCTET_STRING *os) +{ + unsigned char *buf; + int len; + int ret = 0; + + /* Zero-pad field element per SEC 1, section 2.3.5. */ + len = (EC_GROUP_get_degree(group) + 7) / 8; + + /* One extra byte for historic NUL termination of ASN1_STRINGs. */ + if ((buf = calloc(1, len + 1)) == NULL) + goto err; + + if (BN_bn2binpad(bn, buf, len) != len) + goto err; + + ASN1_STRING_set0(os, buf, len); + buf = NULL; + len = 0; + + ret = 1; + + err: + freezero(buf, len); + + return ret; +} + static int ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) { BIGNUM *a = NULL, *b = NULL; - unsigned char *buffer_1 = NULL, *buffer_2 = NULL, *a_buf = NULL, - *b_buf = NULL; - size_t len_1, len_2; - unsigned char char_zero = 0; - int ok = 0; + int ret = 0; if (!group || !curve || !curve->a || !curve->b) return 0; @@ -619,64 +645,30 @@ ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) goto err; } - /* get a and b */ if (!EC_GROUP_get_curve(group, NULL, a, b, NULL)) { ECerror(ERR_R_EC_LIB); goto err; } - len_1 = (size_t) BN_num_bytes(a); - len_2 = (size_t) BN_num_bytes(b); - if (len_1 == 0) { - /* len_1 == 0 => a == 0 */ - a_buf = &char_zero; - len_1 = 1; - } else { - if ((buffer_1 = malloc(len_1)) == NULL) { - ECerror(ERR_R_MALLOC_FAILURE); - goto err; - } - if ((len_1 = BN_bn2bin(a, buffer_1)) == 0) { - ECerror(ERR_R_BN_LIB); - goto err; - } - a_buf = buffer_1; + if (!ec_asn1_encode_field_element(group, a, curve->a)) { + ECerror(ERR_R_EC_LIB); + goto err; } - - if (len_2 == 0) { - /* len_2 == 0 => b == 0 */ - b_buf = &char_zero; - len_2 = 1; - } else { - if ((buffer_2 = malloc(len_2)) == NULL) { - ECerror(ERR_R_MALLOC_FAILURE); - goto err; - } - if ((len_2 = BN_bn2bin(b, buffer_2)) == 0) { - ECerror(ERR_R_BN_LIB); - goto err; - } - b_buf = buffer_2; - } - - /* set a and b */ - if (!ASN1_STRING_set(curve->a, a_buf, len_1) || - !ASN1_STRING_set(curve->b, b_buf, len_2)) { - ECerror(ERR_R_ASN1_LIB); + if (!ec_asn1_encode_field_element(group, b, curve->b)) { + ECerror(ERR_R_EC_LIB); goto err; } ASN1_BIT_STRING_free(curve->seed); curve->seed = NULL; - /* set the seed (optional) */ if (group->seed != NULL) { if ((curve->seed = ASN1_BIT_STRING_new()) == NULL) { ECerror(ERR_R_MALLOC_FAILURE); goto err; } - if (!ASN1_BIT_STRING_set(curve->seed, group->seed, - (int) group->seed_len)) { + if (!ASN1_BIT_STRING_set(curve->seed, + group->seed, group->seed_len)) { ECerror(ERR_R_ASN1_LIB); goto err; } @@ -686,15 +678,13 @@ ec_asn1_group2curve(const EC_GROUP *group, X9_62_CURVE *curve) } } - ok = 1; + ret = 1; err: - free(buffer_1); - free(buffer_2); BN_free(a); BN_free(b); - return (ok); + return ret; } static ECPARAMETERS * diff --git a/lib/libssl/man/SSL_alert_type_string.3 b/lib/libssl/man/SSL_alert_type_string.3 index 42a184e50..354865e54 100644 --- a/lib/libssl/man/SSL_alert_type_string.3 +++ b/lib/libssl/man/SSL_alert_type_string.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: SSL_alert_type_string.3,v 1.6 2024/10/09 08:22:28 tb Exp $ +.\" $OpenBSD: SSL_alert_type_string.3,v 1.7 2024/10/13 08:25:09 jsg Exp $ .\" OpenSSL b97fdb57 Nov 11 09:33:09 2016 +0100 .\" .\" This file was written by Lutz Jaenicke . @@ -48,7 +48,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED .\" OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: October 9 2024 $ +.Dd $Mdocdate: October 13 2024 $ .Dt SSL_ALERT_TYPE_STRING 3 .Os .Sh NAME @@ -233,7 +233,7 @@ This message is always a warning. Sent by the server to indicate that it does not recognize a PSK identity or an SRP identity. .It \(dqCQ\(dq/\(dqcertificate required\(dq -Sent by servers when a client certificate is desired byt none was provided +Sent by servers when a client certificate is desired but none was provided by the client. .It \(dqAP\(dq/\(dqno application protocol\(dq Sent by servers when a client ALPN extension advertises only protocols that diff --git a/regress/lib/libcrypto/ec/ec_asn1_test.c b/regress/lib/libcrypto/ec/ec_asn1_test.c index 321ee5c65..467fd17bc 100644 --- a/regress/lib/libcrypto/ec/ec_asn1_test.c +++ b/regress/lib/libcrypto/ec/ec_asn1_test.c @@ -1,6 +1,7 @@ -/* $OpenBSD: ec_asn1_test.c,v 1.3 2024/10/12 16:15:28 tb Exp $ */ +/* $OpenBSD: ec_asn1_test.c,v 1.4 2024/10/14 13:16:06 tb Exp $ */ /* * Copyright (c) 2017, 2021 Joel Sing + * Copyright (c) 2024 Theo Buehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -62,6 +63,38 @@ const uint8_t ec_secp256r1_pkparameters_parameters[] = { 0x01, 0x01, }; +const uint8_t ec_secp256k1_pkparameters_parameters[] = { + 0x30, 0x81, 0xe0, 0x02, 0x01, 0x01, 0x30, 0x2c, + 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, + 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xfc, 0x2f, 0x30, 0x44, 0x04, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x04, 0x41, 0x04, 0x79, 0xbe, 0x66, + 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, + 0x95, 0xce, 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, + 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, + 0x5b, 0x16, 0xf8, 0x17, 0x98, 0x48, 0x3a, 0xda, + 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, + 0xfc, 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, + 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, + 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 0x02, 0x21, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + 0x02, 0x01, 0x01, +}; + static void hexdump(const unsigned char *buf, size_t len) { @@ -94,7 +127,7 @@ compare_data(const char *label, const unsigned char *d1, size_t d1_len, } static int -ec_group_pkparameters_test(const char *label, int asn1_flag, +ec_group_pkparameters_test(const char *label, int nid, int asn1_flag, const uint8_t *test_data, size_t test_data_len) { EC_GROUP *group_a = NULL, *group_b = NULL; @@ -107,7 +140,7 @@ ec_group_pkparameters_test(const char *label, int asn1_flag, /* * Test i2d_ECPKParameters/d2i_ECPKParameters. */ - if ((group_a = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) + if ((group_a = EC_GROUP_new_by_curve_name(nid)) == NULL) errx(1, "failed to create EC_GROUP"); EC_GROUP_set_asn1_flag(group_a, asn1_flag); @@ -182,7 +215,8 @@ static int ec_group_pkparameters_named_curve_test(void) { return ec_group_pkparameters_test("ECPKPARAMETERS named curve", - OPENSSL_EC_NAMED_CURVE, ec_secp256r1_pkparameters_named_curve, + NID_X9_62_prime256v1, OPENSSL_EC_NAMED_CURVE, + ec_secp256r1_pkparameters_named_curve, sizeof(ec_secp256r1_pkparameters_named_curve)); } @@ -190,10 +224,20 @@ static int ec_group_pkparameters_parameters_test(void) { return ec_group_pkparameters_test("ECPKPARAMETERS parameters", - OPENSSL_EC_EXPLICIT_CURVE, ec_secp256r1_pkparameters_parameters, + NID_X9_62_prime256v1, OPENSSL_EC_EXPLICIT_CURVE, + ec_secp256r1_pkparameters_parameters, sizeof(ec_secp256r1_pkparameters_parameters)); } +static int +ec_group_pkparameters_correct_padding_test(void) +{ + return ec_group_pkparameters_test("ECPKPARAMETERS parameters", + NID_secp256k1, OPENSSL_EC_EXPLICIT_CURVE, + ec_secp256k1_pkparameters_parameters, + sizeof(ec_secp256k1_pkparameters_parameters)); +} + static int ec_group_roundtrip_curve(const EC_GROUP *group, const char *descr, int nid) { @@ -302,6 +346,7 @@ main(int argc, char **argv) failed |= ec_group_pkparameters_named_curve_test(); failed |= ec_group_pkparameters_parameters_test(); + failed |= ec_group_pkparameters_correct_padding_test(); failed |= ec_group_roundtrip_builtin_curves(); return (failed); diff --git a/regress/usr.bin/ssh/test-exec.sh b/regress/usr.bin/ssh/test-exec.sh index 9c15661cc..f05ff8c4a 100644 --- a/regress/usr.bin/ssh/test-exec.sh +++ b/regress/usr.bin/ssh/test-exec.sh @@ -1,4 +1,4 @@ -# $OpenBSD: test-exec.sh,v 1.119 2024/06/20 08:18:34 dtucker Exp $ +# $OpenBSD: test-exec.sh,v 1.120 2024/10/14 03:02:08 djm Exp $ # Placed in the Public Domain. #SUDO=sudo @@ -53,6 +53,7 @@ SSHKEYSCAN=ssh-keyscan SFTP=sftp SFTPSERVER=/usr/libexec/sftp-server SSHD_SESSION=/usr/libexec/sshd-session +SSHD_AUTH=/usr/libexec/sshd-auth SCP=scp # Interop testing @@ -77,6 +78,9 @@ fi if [ "x$TEST_SSH_SSHD_SESSION" != "x" ]; then SSHD_SESSION="${TEST_SSH_SSHD_SESSION}" fi +if [ "x$TEST_SSH_SSHD_AUTH" != "x" ]; then + SSHD_AUTH="${TEST_SSH_SSHD_AUTH}" +fi if [ "x$TEST_SSH_SSHD" != "x" ]; then SSHD="${TEST_SSH_SSHD}" fi @@ -426,6 +430,7 @@ cat << EOF > $OBJ/sshd_config AcceptEnv _XXX_TEST Subsystem sftp $SFTPSERVER SshdSessionPath $SSHD_SESSION + SshdAuthPath $SSHD_AUTH PerSourcePenalties no EOF diff --git a/share/man/man4/ddb.4 b/share/man/man4/ddb.4 index 6ca75c4d5..f0f7b134b 100644 --- a/share/man/man4/ddb.4 +++ b/share/man/man4/ddb.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ddb.4,v 1.108 2024/09/05 08:52:27 bluhm Exp $ +.\" $OpenBSD: ddb.4,v 1.109 2024/10/14 07:05:23 jmc Exp $ .\" $NetBSD: ddb.4,v 1.5 1994/11/30 16:22:09 jtc Exp $ .\" .\" Mach Operating System @@ -25,7 +25,7 @@ .\" any improvements or extensions that they make and grant Carnegie Mellon .\" the rights to redistribute these changes. .\" -.Dd $Mdocdate: September 5 2024 $ +.Dd $Mdocdate: October 14 2024 $ .Dt DDB 4 .Os .Sh NAME @@ -1168,14 +1168,6 @@ Register names can be found with the .Ic show registers command. .Pp -Some variable names are suffixed with numbers, and some may have a modifier -following a colon immediately after the variable name. -For example, register variables can have the -.Ql :u -modifier to indicate a -user register (e.g., -.Ql $eax:u ) . -.Pp Built-in debugger variables currently supported are: .Bl -tag -width 10n -compact -offset indent .It Va $radix @@ -1277,16 +1269,13 @@ command. The last address explicitly specified. .It Li $ Ns Ar variable The value of a register or variable. -The name may be followed by a -.Ql \&: -and modifiers as described above with -.Ar identifier . .It Ar expr Li # Ar expr A binary operator which rounds up the left hand side to the next multiple of right hand side. .It Li * Ns Ar expr Indirection. -It may be followed by a ':' and modifiers as described above. +It may be followed by a ':' as described above with +.Ar identifier . .El .Sh SEE ALSO .Xr ctfstrip 1 , diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index 8342d5f27..0f13691cb 100644 --- a/sys/arch/amd64/amd64/acpi_machdep.c +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.111 2024/09/01 03:08:56 jsg Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.112 2024/10/14 11:49:34 jan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -366,10 +366,10 @@ acpi_attach_machdep(struct acpi_softc *sc) /* Unmap, will be remapped in acpi_sleep_cpu */ pmap_kremove(ACPI_TRAMPOLINE, PAGE_SIZE); pmap_kremove(ACPI_TRAMP_DATA, PAGE_SIZE); -#endif /* SMALL_KERNEL */ +#endif /* ! SMALL_KERNEL */ } -#ifndef SMALL_KERNEL +#if defined(SUSPEND) && !defined(SMALL_KERNEL) /* * This function may not have local variables due to a bug between * acpi_savecpu() and the resume path. @@ -562,7 +562,7 @@ resume_mp(void) } #endif /* MULTIPROCESSOR */ -#endif /* ! SMALL_KERNEL */ +#endif /* defined(SUSPEND) && !defined(SMALL_KERNEL) */ bus_dma_tag_t acpi_iommu_device_map(struct aml_node *node, bus_dma_tag_t dmat) diff --git a/sys/arch/arm64/arm64/process_machdep.c b/sys/arch/arm64/arm64/process_machdep.c index e57d7f371..096786120 100644 --- a/sys/arch/arm64/arm64/process_machdep.c +++ b/sys/arch/arm64/arm64/process_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process_machdep.c,v 1.8 2023/06/10 19:30:48 kettenis Exp $ */ +/* $OpenBSD: process_machdep.c,v 1.9 2024/10/14 12:02:16 jsg Exp $ */ /* * Copyright (c) 2014 Patrick Wildt * @@ -48,6 +48,7 @@ #include #include #include +#include #include diff --git a/sys/arch/arm64/include/intr.h b/sys/arch/arm64/include/intr.h index a16218458..16061695c 100644 --- a/sys/arch/arm64/include/intr.h +++ b/sys/arch/arm64/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.22 2023/09/12 08:29:28 jmatthew Exp $ */ +/* $OpenBSD: intr.h,v 1.23 2024/10/14 10:08:13 jsg Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -79,7 +79,6 @@ #define IST_EDGE_BOTH 6 #ifndef _LOCORE -#include #include int splraise(int); diff --git a/sys/arch/arm64/include/pte.h b/sys/arch/arm64/include/pte.h index 25a72baae..54d1de1de 100644 --- a/sys/arch/arm64/include/pte.h +++ b/sys/arch/arm64/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.9 2024/09/29 12:22:57 jsg Exp $ */ +/* $OpenBSD: pte.h,v 1.10 2024/10/14 12:02:16 jsg Exp $ */ /* * Copyright (c) 2014 Dale Rahn * @@ -17,8 +17,6 @@ #ifndef _ARM_PTE_H_ #define _ARM_PTE_H_ -#include "arm64/vmparam.h" - /* level X descriptor */ #define Lx_TYPE_MASK (0x00000003) /* mask of type bits */ #define Lx_TYPE_S (0x00000001) diff --git a/sys/arch/armv7/include/intr.h b/sys/arch/armv7/include/intr.h index 25f957a0d..4a4d6485d 100644 --- a/sys/arch/armv7/include/intr.h +++ b/sys/arch/armv7/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.14 2020/07/17 08:07:34 patrick Exp $ */ +/* $OpenBSD: intr.h,v 1.15 2024/10/14 10:08:13 jsg Exp $ */ /* $NetBSD: intr.h,v 1.12 2003/06/16 20:00:59 thorpej Exp $ */ /* @@ -78,7 +78,6 @@ #define IST_EDGE_BOTH 6 #ifndef _LOCORE -#include #include struct cpu_info; diff --git a/sys/dev/midivar.h b/sys/dev/midivar.h index 283cbd621..56618c5a5 100644 --- a/sys/dev/midivar.h +++ b/sys/dev/midivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: midivar.h,v 1.14 2023/09/26 19:55:24 mvs Exp $ */ +/* $OpenBSD: midivar.h,v 1.15 2024/10/14 00:47:36 jsg Exp $ */ /* * Copyright (c) 2003, 2004 Alexandre Ratchov @@ -22,7 +22,6 @@ #include #include #include -#include #include #define MIDI_RATE 3125 /* midi uart baud rate in bytes/second */ diff --git a/sys/net/if_wg.h b/sys/net/if_wg.h index adb623ce2..35464b5f4 100644 --- a/sys/net/if_wg.h +++ b/sys/net/if_wg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wg.h,v 1.5 2023/06/01 18:57:53 kn Exp $ */ +/* $OpenBSD: if_wg.h,v 1.6 2024/10/13 00:53:21 jsg Exp $ */ /* * Copyright (C) 2015-2020 Jason A. Donenfeld . All Rights Reserved. @@ -20,9 +20,6 @@ #ifndef __IF_WG_H__ #define __IF_WG_H__ -#include -#include - #include #include diff --git a/sys/netinet/ip_mroute.h b/sys/netinet/ip_mroute.h index b389d63d5..e833fcc27 100644 --- a/sys/netinet/ip_mroute.h +++ b/sys/netinet/ip_mroute.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_mroute.h,v 1.31 2022/05/05 13:57:40 claudio Exp $ */ +/* $OpenBSD: ip_mroute.h,v 1.32 2024/10/13 02:27:44 jsg Exp $ */ /* $NetBSD: ip_mroute.h,v 1.23 2004/04/21 17:49:46 itojun Exp $ */ #ifndef _NETINET_IP_MROUTE_H_ @@ -18,8 +18,6 @@ * advanced API support, bandwidth metering and signaling. */ -#include - /* * Multicast Routing set/getsockopt commands. */ diff --git a/sys/ufs/ufs/dirhash.h b/sys/ufs/ufs/dirhash.h index 1bb235894..3c60283fa 100644 --- a/sys/ufs/ufs/dirhash.h +++ b/sys/ufs/ufs/dirhash.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dirhash.h,v 1.8 2022/01/11 03:13:59 jsg Exp $ */ +/* $OpenBSD: dirhash.h,v 1.9 2024/10/14 02:20:01 jsg Exp $ */ /* * Copyright (c) 2001 Ian Dowse. All rights reserved. * @@ -29,7 +29,7 @@ #ifndef _UFS_UFS_DIRHASH_H_ #define _UFS_UFS_DIRHASH_H_ -#include +#include /* * For fast operations on large directories, we maintain a hash diff --git a/usr.bin/rsync/socket.c b/usr.bin/rsync/socket.c index 12cc46acf..d723d9e7d 100644 --- a/usr.bin/rsync/socket.c +++ b/usr.bin/rsync/socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: socket.c,v 1.33 2022/12/26 19:16:02 jmc Exp $ */ +/* $OpenBSD: socket.c,v 1.34 2024/10/13 03:35:59 jsg Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -31,6 +31,7 @@ #include #include #include +#include #include "extern.h" diff --git a/usr.bin/ssh/Makefile b/usr.bin/ssh/Makefile index 09f8b0ac8..d42cf19d4 100644 --- a/usr.bin/ssh/Makefile +++ b/usr.bin/ssh/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.18 2024/05/17 00:30:23 djm Exp $ +# $OpenBSD: Makefile,v 1.19 2024/10/14 01:57:50 djm Exp $ .include -SUBDIR= ssh sshd sshd-session \ +SUBDIR= ssh sshd sshd-session sshd-auth \ ssh-add ssh-keygen ssh-agent scp sftp-server \ ssh-keysign ssh-keyscan sftp ssh-pkcs11-helper ssh-sk-helper diff --git a/usr.bin/ssh/Makefile.inc b/usr.bin/ssh/Makefile.inc index 772d7451c..85dd55895 100644 --- a/usr.bin/ssh/Makefile.inc +++ b/usr.bin/ssh/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.96 2024/09/09 02:39:57 djm Exp $ +# $OpenBSD: Makefile.inc,v 1.97 2024/10/14 01:57:50 djm Exp $ .include @@ -29,9 +29,9 @@ CDIAGFLAGS+= -Wold-style-definition CDIAGFLAGS+= -Werror .endif -#CDIAGFLAGS+= -fno-common -#DEBUG=-g -#INSTALL_STRIP= +CDIAGFLAGS+= -fno-common +DEBUG=-g +INSTALL_STRIP= WARNINGS=yes diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c index 15e702c32..07e8c0865 100644 --- a/usr.bin/ssh/channels.c +++ b/usr.bin/ssh/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.439 2024/07/25 22:40:08 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.440 2024/10/13 22:20:06 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -5219,3 +5219,22 @@ x11_request_forwarding_with_spoofing(struct ssh *ssh, int client_session_id, fatal_fr(r, "send x11-req"); free(new_data); } + +/* + * Returns whether an x11 channel was used recently (less than a second ago) + */ +int +x11_channel_used_recently(struct ssh *ssh) { + u_int i; + Channel *c; + time_t lastused = 0; + + for (i = 0; i < ssh->chanctxt->channels_alloc; i++) { + c = ssh->chanctxt->channels[i]; + if (c == NULL || c->ctype == NULL || c->lastused == 0 || + strcmp(c->ctype, "x11-connection") != 0) + continue; + lastused = c->lastused; + } + return lastused != 0 && monotime() > lastused + 1; +} diff --git a/usr.bin/ssh/channels.h b/usr.bin/ssh/channels.h index 8a4615eda..c227320af 100644 --- a/usr.bin/ssh/channels.h +++ b/usr.bin/ssh/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.157 2024/07/25 22:40:08 djm Exp $ */ +/* $OpenBSD: channels.h,v 1.158 2024/10/13 22:20:06 djm Exp $ */ /* * Author: Tatu Ylonen @@ -379,6 +379,7 @@ int x11_connect_display(struct ssh *); int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **); void x11_request_forwarding_with_spoofing(struct ssh *, int, const char *, const char *, const char *, int); +int x11_channel_used_recently(struct ssh *ssh); /* channel close */ diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c index c5296e32f..07c321cc3 100644 --- a/usr.bin/ssh/clientloop.c +++ b/usr.bin/ssh/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.408 2024/07/01 04:31:17 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.409 2024/10/13 22:20:06 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -650,9 +650,10 @@ obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout, if (just_started) return 1; - /* Don't arm output fd for poll until the timing interval has elapsed */ + /* Don't arm output fd for poll until the timing interval has elapsed... */ if (timespeccmp(&now, &next_interval, <)) - return 0; + /* ...unless there's x11 communicattion happening */ + return x11_channel_used_recently(ssh); /* Calculate number of intervals missed since the last check */ n = (now.tv_sec - next_interval.tv_sec) * 1000LL * 1000 * 1000; diff --git a/usr.bin/ssh/log.c b/usr.bin/ssh/log.c index 5e12fcb28..8b1b3991a 100644 --- a/usr.bin/ssh/log.c +++ b/usr.bin/ssh/log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: log.c,v 1.62 2024/06/27 22:36:44 djm Exp $ */ +/* $OpenBSD: log.c,v 1.63 2024/10/14 01:57:50 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -418,9 +418,9 @@ sshlogv(const char *file, const char *func, int line, int showfunc, if (nlog_verbose == 0 && level > log_level) return; - snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (pid=%ld)", + snprintf(tag, sizeof(tag), "%.48s:%.48s():%d (bin=%s, pid=%ld)", (cp = strrchr(file, '/')) == NULL ? file : cp + 1, func, line, - (long)getpid()); + argv0 == NULL ? "UNKNOWN" : argv0, (long)getpid()); for (i = 0; i < nlog_verbose; i++) { if (match_pattern_list(tag, log_verbose[i], 0) == 1) { forced = 1; diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index 61a2310f4..a36520b03 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.245 2024/09/22 12:56:21 jsg Exp $ */ +/* $OpenBSD: monitor.c,v 1.246 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -90,7 +90,9 @@ static Gssctxt *gsscontext = NULL; /* Imports */ extern ServerOptions options; extern u_int utmp_len; +extern struct sshbuf *cfg; extern struct sshbuf *loginmsg; +extern struct include_list includes; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ /* State exported from the child */ @@ -111,6 +113,7 @@ int mm_answer_keyverify(struct ssh *, int, struct sshbuf *); int mm_answer_pty(struct ssh *, int, struct sshbuf *); int mm_answer_pty_cleanup(struct ssh *, int, struct sshbuf *); int mm_answer_term(struct ssh *, int, struct sshbuf *); +int mm_answer_state(struct ssh *, int, struct sshbuf *); #ifdef GSSAPI int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); @@ -155,6 +158,7 @@ static int monitor_read(struct ssh *, struct monitor *, struct mon_table *, static int monitor_read_log(struct monitor *); struct mon_table mon_dispatch_proto20[] = { + {MONITOR_REQ_STATE, MON_ONCE, mm_answer_state}, #ifdef WITH_OPENSSL {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, #endif @@ -177,6 +181,7 @@ struct mon_table mon_dispatch_proto20[] = { }; struct mon_table mon_dispatch_postauth20[] = { + {MONITOR_REQ_STATE, MON_ONCE, mm_answer_state}, #ifdef WITH_OPENSSL {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, #endif @@ -236,7 +241,8 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) ssh->authctxt = authctxt; mon_dispatch = mon_dispatch_proto20; - /* Permit requests for moduli and signatures */ + /* Permit requests for state, moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_STATE, 1); monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); @@ -339,6 +345,7 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) mon_dispatch = mon_dispatch_postauth20; /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_STATE, 1); monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -396,7 +403,8 @@ monitor_read_log(struct monitor *pmonitor) /* Log it */ if (log_level_name(level) == NULL) fatal_f("invalid log level %u (corrupted message?)", level); - sshlogdirect(level, forced, "%s [preauth]", msg); + sshlogdirect(level, forced, "%s [%s]", msg, + mon_dispatch == mon_dispatch_postauth20 ? "postauth" : "preauth"); sshbuf_free(logmsg); free(msg); @@ -502,6 +510,82 @@ monitor_reset_key_state(void) hostbased_chost = NULL; } +int +mm_answer_state(struct ssh *ssh, int sock, struct sshbuf *m) +{ + struct sshbuf *inc = NULL, *hostkeys = NULL; + struct sshbuf *opts = NULL, *confdata = NULL; + struct include_item *item = NULL; + int postauth; + int r; + + sshbuf_reset(m); + + debug_f("config len %zu", sshbuf_len(cfg)); + + if ((m = sshbuf_new()) == NULL || + (inc = sshbuf_new()) == NULL || + (opts = sshbuf_new()) == NULL || + (confdata = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + + /* XXX unneccessary? */ + /* pack includes into a string */ + TAILQ_FOREACH(item, &includes, entry) { + if ((r = sshbuf_put_cstring(inc, item->selector)) != 0 || + (r = sshbuf_put_cstring(inc, item->filename)) != 0 || + (r = sshbuf_put_stringb(inc, item->contents)) != 0) + fatal_fr(r, "compose includes"); + } + + hostkeys = pack_hostkeys(); + + /* + * Protocol from monitor to unpriv privsep process: + * string configuration + * uint64 timing_secret XXX move delays to monitor and remove + * string host_keys[] { + * string public_key + * string certificate + * } + * string server_banner + * string client_banner + * string included_files[] { + * string selector + * string filename + * string contents + * } + * string configuration_data (postauth) + * string keystate (postauth) + * string authenticated_user (postauth) + * string session_info (postauth) + * string authopts (postauth) + */ + if ((r = sshbuf_put_stringb(m, cfg)) != 0 || + (r = sshbuf_put_u64(m, options.timing_secret)) != 0 || + (r = sshbuf_put_stringb(m, hostkeys)) != 0 || + (r = sshbuf_put_stringb(m, ssh->kex->server_version)) != 0 || + (r = sshbuf_put_stringb(m, ssh->kex->client_version)) != 0 || + (r = sshbuf_put_stringb(m, inc)) != 0) + fatal_fr(r, "compose config"); + + postauth = (authctxt && authctxt->pw && authctxt->authenticated); + if (postauth) { + /* XXX shouldn't be reachable */ + fatal_f("internal error: called in postauth"); + } + + sshbuf_free(inc); + sshbuf_free(opts); + sshbuf_free(confdata); + + mm_request_send(sock, MONITOR_ANS_STATE, m); + + debug3_f("done"); + + return (0); +} + #ifdef WITH_OPENSSL int mm_answer_moduli(struct ssh *ssh, int sock, struct sshbuf *m) @@ -547,24 +631,27 @@ int mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) { extern int auth_sock; /* XXX move to state struct? */ - struct sshkey *key; + struct sshkey *pubkey, *key; struct sshbuf *sigbuf = NULL; u_char *p = NULL, *signature = NULL; char *alg = NULL; - size_t datlen, siglen, alglen; - int r, is_proof = 0; - u_int keyid, compat; + size_t datlen, siglen; + int r, is_proof = 0, keyid; + u_int compat; const char proof_req[] = "hostkeys-prove-00@openssh.com"; debug3_f("entering"); - if ((r = sshbuf_get_u32(m, &keyid)) != 0 || + if ((r = sshkey_froms(m, &pubkey)) != 0 || (r = sshbuf_get_string(m, &p, &datlen)) != 0 || - (r = sshbuf_get_cstring(m, &alg, &alglen)) != 0 || + (r = sshbuf_get_cstring(m, &alg, NULL)) != 0 || (r = sshbuf_get_u32(m, &compat)) != 0) fatal_fr(r, "parse"); - if (keyid > INT_MAX) - fatal_f("invalid key ID"); + + if ((keyid = get_hostkey_index(pubkey, 1, ssh)) == -1) + fatal_f("unknown hostkey"); + debug_f("hostkey %s index %d", sshkey_ssh_name(pubkey), keyid); + sshkey_free(pubkey); /* * Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), diff --git a/usr.bin/ssh/monitor.h b/usr.bin/ssh/monitor.h index 7049e05db..030309785 100644 --- a/usr.bin/ssh/monitor.h +++ b/usr.bin/ssh/monitor.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.h,v 1.24 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: monitor.h,v 1.25 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -56,6 +56,7 @@ enum monitor_reqtype { MONITOR_REQ_GSSUSEROK = 46, MONITOR_ANS_GSSUSEROK = 47, MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, MONITOR_REQ_TERM = 50, + MONITOR_REQ_STATE = 51, MONITOR_ANS_STATE = 52 }; struct ssh; @@ -89,4 +90,6 @@ void mm_get_keystate(struct ssh *, struct monitor *); /* XXX: should be returned via a monitor call rather than config_fd */ void mm_encode_server_options(struct sshbuf *); +struct sshbuf *pack_hostkeys(void); + #endif /* _MONITOR_H_ */ diff --git a/usr.bin/ssh/monitor_wrap.c b/usr.bin/ssh/monitor_wrap.c index 97ed932b3..a2ff0f8db 100644 --- a/usr.bin/ssh/monitor_wrap.c +++ b/usr.bin/ssh/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.136 2024/06/19 23:24:47 djm Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.137 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -107,16 +107,6 @@ mm_log_handler(LogLevel level, int forced, const char *msg, void *ctx) sshbuf_free(log_msg); } -int -mm_is_monitor(void) -{ - /* - * m_pid is only set in the privileged part, and - * points to the unprivileged child. - */ - return (pmonitor && pmonitor->m_pid > 0); -} - static void mm_reap(void) { @@ -260,15 +250,13 @@ mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, const char *hostkey_alg, const char *sk_provider, const char *sk_pin, u_int compat) { - struct kex *kex = *pmonitor->m_pkex; struct sshbuf *m; - u_int ndx = kex->host_key_index(key, 0, ssh); int r; debug3_f("entering"); if ((m = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); - if ((r = sshbuf_put_u32(m, ndx)) != 0 || + if ((r = sshkey_puts(key, m)) != 0 || (r = sshbuf_put_string(m, data, datalen)) != 0 || (r = sshbuf_put_cstring(m, hostkey_alg)) != 0 || (r = sshbuf_put_u32(m, compat)) != 0) @@ -281,6 +269,7 @@ mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp, if ((r = sshbuf_get_string(m, sigp, lenp)) != 0) fatal_fr(r, "parse"); sshbuf_free(m); + debug3_f("%s signature len=%zu", hostkey_alg, *lenp); return (0); } @@ -686,6 +675,72 @@ mm_terminate(void) sshbuf_free(m); } +/* Request state information */ + +void +mm_get_state(struct ssh *ssh, struct include_list *includes, + struct sshbuf *conf, struct sshbuf **confdatap, + uint64_t *timing_secretp, + struct sshbuf **hostkeysp, struct sshbuf **keystatep, + u_char **pw_namep, + struct sshbuf **authinfop, struct sshbuf **auth_optsp) +{ + struct sshbuf *m, *inc; + u_char *cp; + size_t len; + int r; + struct include_item *item; + + debug3_f("entering"); + + if ((m = sshbuf_new()) == NULL || (inc = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_STATE, m); + + debug3_f("waiting for MONITOR_ANS_STATE"); + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_STATE, m); + + if ((r = sshbuf_get_string(m, &cp, &len)) != 0 || + (r = sshbuf_get_u64(m, timing_secretp)) != 0 || + (r = sshbuf_froms(m, hostkeysp)) != 0 || + (r = sshbuf_get_stringb(m, ssh->kex->server_version)) != 0 || + (r = sshbuf_get_stringb(m, ssh->kex->client_version)) != 0 || + (r = sshbuf_get_stringb(m, inc)) != 0) + fatal_fr(r, "parse config"); + + /* postauth */ + if (confdatap) { + if ((r = sshbuf_froms(m, confdatap)) != 0 || + (r = sshbuf_froms(m, keystatep)) != 0 || + (r = sshbuf_get_string(m, pw_namep, NULL)) != 0 || + (r = sshbuf_froms(m, authinfop)) != 0 || + (r = sshbuf_froms(m, auth_optsp)) != 0) + fatal_fr(r, "parse config postauth"); + } + + if (conf != NULL && (r = sshbuf_put(conf, cp, len))) + fatal_fr(r, "sshbuf_put"); + + while (sshbuf_len(inc) != 0) { + item = xcalloc(1, sizeof(*item)); + if ((item->contents = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + if ((r = sshbuf_get_cstring(inc, &item->selector, NULL)) != 0 || + (r = sshbuf_get_cstring(inc, &item->filename, NULL)) != 0 || + (r = sshbuf_get_stringb(inc, item->contents)) != 0) + fatal_fr(r, "parse includes"); + TAILQ_INSERT_TAIL(includes, item, entry); + } + + free(cp); + sshbuf_free(m); + sshbuf_free(inc); + + debug3_f("done"); +} + static void mm_chall_setup(char **name, char **infotxt, u_int *numprompts, char ***prompts, u_int **echo_on) diff --git a/usr.bin/ssh/monitor_wrap.h b/usr.bin/ssh/monitor_wrap.h index a78099829..af04aa67c 100644 --- a/usr.bin/ssh/monitor_wrap.h +++ b/usr.bin/ssh/monitor_wrap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.h,v 1.51 2024/05/17 06:42:04 jsg Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.52 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright 2002 Niels Provos @@ -75,6 +75,12 @@ void mm_session_pty_cleanup2(struct Session *); void mm_send_keystate(struct ssh *, struct monitor*); +/* state */ +struct include_list; +void mm_get_state(struct ssh *, struct include_list *, struct sshbuf *, + struct sshbuf **, uint64_t *, struct sshbuf **, struct sshbuf **, + u_char **, struct sshbuf **, struct sshbuf **); + /* bsdauth */ int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); int mm_bsdauth_respond(void *, u_int, char **); diff --git a/usr.bin/ssh/pathnames.h b/usr.bin/ssh/pathnames.h index 0b170505f..2d3057d03 100644 --- a/usr.bin/ssh/pathnames.h +++ b/usr.bin/ssh/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.32 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: pathnames.h,v 1.33 2024/10/14 01:57:50 djm Exp $ */ /* * Author: Tatu Ylonen @@ -41,6 +41,7 @@ /* Binary paths for the sshd components */ #define _PATH_SSHD_SESSION "/usr/libexec/sshd-session" +#define _PATH_SSHD_AUTH "/usr/libexec/sshd-auth" /* * The process id of the daemon listening for connections is saved here to diff --git a/usr.bin/ssh/sandbox-pledge.c b/usr.bin/ssh/sandbox-pledge.c index 9a12dbfea..e69de29bb 100644 --- a/usr.bin/ssh/sandbox-pledge.c +++ b/usr.bin/ssh/sandbox-pledge.c @@ -1,71 +0,0 @@ -/* $OpenBSD: sandbox-pledge.c,v 1.2 2020/10/18 11:32:01 djm Exp $ */ -/* - * Copyright (c) 2015 Theo de Raadt - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "ssh-sandbox.h" -#include "xmalloc.h" - -struct ssh_sandbox { - pid_t child_pid; -}; - -struct ssh_sandbox * -ssh_sandbox_init(void) -{ - struct ssh_sandbox *box; - - debug3_f("preparing pledge sandbox"); - box = xcalloc(1, sizeof(*box)); - box->child_pid = 0; - - return box; -} - -void -ssh_sandbox_child(struct ssh_sandbox *box) -{ - if (pledge("stdio", NULL) == -1) - fatal_f("pledge()"); -} - -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) -{ - free(box); - debug3_f("finished"); -} - -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) -{ - box->child_pid = child_pid; - /* Nothing to do here */ -} diff --git a/usr.bin/ssh/sandbox-rlimit.c b/usr.bin/ssh/sandbox-rlimit.c index 4e86174a0..e69de29bb 100644 --- a/usr.bin/ssh/sandbox-rlimit.c +++ b/usr.bin/ssh/sandbox-rlimit.c @@ -1,86 +0,0 @@ -/* $OpenBSD: sandbox-rlimit.c,v 1.5 2020/10/18 11:32:01 djm Exp $ */ -/* - * Copyright (c) 2011 Damien Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "ssh-sandbox.h" -#include "xmalloc.h" - -/* Minimal sandbox that sets zero nfiles, nprocs and filesize rlimits */ - -struct ssh_sandbox { - pid_t child_pid; -}; - -struct ssh_sandbox * -ssh_sandbox_init(void) -{ - struct ssh_sandbox *box; - - /* - * Strictly, we don't need to maintain any state here but we need - * to return non-NULL to satisfy the API. - */ - debug3_f("preparing rlimit sandbox"); - box = xcalloc(1, sizeof(*box)); - box->child_pid = 0; - - return box; -} - -void -ssh_sandbox_child(struct ssh_sandbox *box) -{ - struct rlimit rl_zero; - - rl_zero.rlim_cur = rl_zero.rlim_max = 0; - - if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1) - fatal_f("setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s", - strerror(errno)); - if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1) - fatal_f("setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s", - strerror(errno)); - if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1) - fatal_f("setrlimit(RLIMIT_NPROC, { 0, 0 }): %s", - strerror(errno)); -} - -void -ssh_sandbox_parent_finish(struct ssh_sandbox *box) -{ - free(box); - debug3_f("finished"); -} - -void -ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid) -{ - box->child_pid = child_pid; - /* Nothing to do here */ -} - diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index cd57ca011..fa22d6f55 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.419 2024/09/25 01:24:04 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.420 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -191,6 +191,7 @@ initialize_server_options(ServerOptions *options) options->num_channel_timeouts = 0; options->unused_connection_timeout = -1; options->sshd_session_path = NULL; + options->sshd_auth_path = NULL; options->refuse_connection = -1; } @@ -461,6 +462,8 @@ fill_default_server_options(ServerOptions *options) options->unused_connection_timeout = 0; if (options->sshd_session_path == NULL) options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION); + if (options->sshd_auth_path == NULL) + options->sshd_auth_path = xstrdup(_PATH_SSHD_AUTH); if (options->refuse_connection == -1) options->refuse_connection = 0; @@ -542,7 +545,7 @@ typedef enum { sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout, - sSshdSessionPath, sRefuseConnection, + sSshdSessionPath, sSshdAuthPath, sRefuseConnection, sDeprecated, sIgnore, sUnsupported } ServerOpCodes; @@ -692,6 +695,7 @@ static struct { { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, + { "sshdauthpath", sSshdAuthPath, SSHCFG_GLOBAL }, { "refuseconnection", sRefuseConnection, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -2623,6 +2627,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, charptr = &options->sshd_session_path; goto parse_filename; + case sSshdAuthPath: + charptr = &options->sshd_auth_path; + goto parse_filename; + case sRefuseConnection: intptr = &options->refuse_connection; multistate_ptr = multistate_flag; @@ -3198,6 +3206,7 @@ dump_config(ServerOptions *o) dump_cfg_string(sPubkeyAcceptedAlgorithms, o->pubkey_accepted_algos); dump_cfg_string(sRDomain, o->routing_domain); dump_cfg_string(sSshdSessionPath, o->sshd_session_path); + dump_cfg_string(sSshdAuthPath, o->sshd_auth_path); dump_cfg_string(sPerSourcePenaltyExemptList, o->per_source_penalty_exempt); /* string arguments requiring a lookup */ diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 33ada42e0..f05f5f3c1 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.168 2024/09/15 01:18:26 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.169 2024/10/14 01:57:50 djm Exp $ */ /* * Author: Tatu Ylonen @@ -246,6 +246,7 @@ typedef struct { int unused_connection_timeout; char *sshd_session_path; + char *sshd_auth_path; int refuse_connection; } ServerOptions; diff --git a/usr.bin/ssh/session.c b/usr.bin/ssh/session.c index e0239a28c..70127823c 100644 --- a/usr.bin/ssh/session.c +++ b/usr.bin/ssh/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.338 2024/05/17 00:30:24 djm Exp $ */ +/* $OpenBSD: session.c,v 1.339 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -1224,8 +1224,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); - /* remove hostkey from the child's memory */ - destroy_sensitive_data(); + /* remove keys from memory */ ssh_packet_clear_keys(ssh); /* Force a password change */ @@ -1827,10 +1826,6 @@ session_signal_req(struct ssh *ssh, Session *s) signame, s->forced ? "forced-command" : "subsystem"); goto out; } - if (mm_is_monitor()) { - error_f("session signalling requires privilege separation"); - goto out; - } debug_f("signal %s, killpg(%ld, %d)", signame, (long)s->pid, sig); temporarily_use_uid(s->pw); diff --git a/usr.bin/ssh/ssh-sandbox.h b/usr.bin/ssh/ssh-sandbox.h index dfecd5aa0..e69de29bb 100644 --- a/usr.bin/ssh/ssh-sandbox.h +++ b/usr.bin/ssh/ssh-sandbox.h @@ -1,23 +0,0 @@ -/* $OpenBSD: ssh-sandbox.h,v 1.1 2011/06/23 09:34:13 djm Exp $ */ -/* - * Copyright (c) 2011 Damien Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -struct ssh_sandbox; - -struct ssh_sandbox *ssh_sandbox_init(void); -void ssh_sandbox_child(struct ssh_sandbox *); -void ssh_sandbox_parent_finish(struct ssh_sandbox *); -void ssh_sandbox_parent_preauth(struct ssh_sandbox *, pid_t); diff --git a/usr.bin/ssh/sshd-auth.c b/usr.bin/ssh/sshd-auth.c new file mode 100644 index 000000000..e7225af22 --- /dev/null +++ b/usr.bin/ssh/sshd-auth.c @@ -0,0 +1,836 @@ +/* $OpenBSD: sshd-auth.c,v 1.1 2024/10/14 01:57:50 djm Exp $ */ +/* + * SSH2 implementation: + * Privilege Separation: + * + * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 2002 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WITH_OPENSSL +#include +#include +#endif + +#include "xmalloc.h" +#include "ssh.h" +#include "ssh2.h" +#include "sshpty.h" +#include "packet.h" +#include "log.h" +#include "sshbuf.h" +#include "misc.h" +#include "match.h" +#include "servconf.h" +#include "uidswap.h" +#include "compat.h" +#include "cipher.h" +#include "digest.h" +#include "sshkey.h" +#include "kex.h" +#include "authfile.h" +#include "pathnames.h" +#include "atomicio.h" +#include "canohost.h" +#include "hostfile.h" +#include "auth.h" +#include "authfd.h" +#include "msg.h" +#include "dispatch.h" +#include "channels.h" +#include "session.h" +#include "monitor.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif +#include "monitor_wrap.h" +#include "auth-options.h" +#include "version.h" +#include "ssherr.h" +#include "sk-api.h" +#include "srclimit.h" +#include "dh.h" + +/* Privsep fds */ +#define PRIVSEP_MONITOR_FD (STDERR_FILENO + 1) +#define PRIVSEP_LOG_FD (STDERR_FILENO + 2) +#define PRIVSEP_MIN_FREE_FD (STDERR_FILENO + 3) + +extern char *__progname; + +/* Server configuration options. */ +ServerOptions options; + +/* Name of the server configuration file. */ +char *config_file_name = _PATH_SERVER_CONFIG_FILE; + +/* + * Debug mode flag. This can be set on the command line. If debug + * mode is enabled, extra debugging output will be sent to the system + * log, the daemon will not go to background, and will exit after processing + * the first connection. + */ +int debug_flag = 0; + +/* Flag indicating that the daemon is being started from inetd. */ +static int inetd_flag = 0; + +/* Saved arguments to main(). */ +static char **saved_argv; + +/* Daemon's agent connection */ +int auth_sock = -1; +static int have_agent = 0; + +u_int num_hostkeys; +struct sshkey **host_pubkeys; /* all public host keys */ +struct sshkey **host_certificates; /* all public host certificates */ + +/* record remote hostname or ip */ +u_int utmp_len = HOST_NAME_MAX+1; + +/* variables used for privilege separation */ +struct monitor *pmonitor = NULL; +int privsep_is_preauth = 1; + +/* global connection state and authentication contexts */ +Authctxt *the_authctxt = NULL; +struct ssh *the_active_state; + +/* global key/cert auth options. XXX move to permanent ssh->authctxt? */ +struct sshauthopt *auth_opts = NULL; + +/* sshd_config buffer */ +struct sshbuf *cfg; + +/* Included files from the configuration file */ +struct include_list includes = TAILQ_HEAD_INITIALIZER(includes); + +/* message to be displayed after login */ +struct sshbuf *loginmsg; + +/* Prototypes for various functions defined later in this file. */ +static void do_ssh2_kex(struct ssh *); + +/* XXX stub */ +int +mm_is_monitor(void) +{ + return 0; +} + +static void +privsep_child_demote(void) +{ + gid_t gidset[1]; + struct passwd *pw; + + /* Demote the child */ + if (getuid() == 0 || geteuid() == 0) { + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + pw = pwcopy(pw); /* Ensure mutable */ + endpwent(); + freezero(pw->pw_passwd, strlen(pw->pw_passwd)); + + /* Change our root directory */ + if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) + fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, + strerror(errno)); + if (chdir("/") == -1) + fatal("chdir(\"/\"): %s", strerror(errno)); + + /* + * Drop our privileges + * NB. Can't use setusercontext() after chroot. + */ + debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, + (u_int)pw->pw_gid); + gidset[0] = pw->pw_gid; + if (setgroups(1, gidset) == -1) + fatal("setgroups: %.100s", strerror(errno)); + permanently_set_uid(pw); + } + + /* sandbox ourselves */ + if (pledge("stdio", NULL) == -1) + fatal_f("pledge()"); +} + +static void +append_hostkey_type(struct sshbuf *b, const char *s) +{ + int r; + + if (match_pattern_list(s, options.hostkeyalgorithms, 0) != 1) { + debug3_f("%s key not permitted by HostkeyAlgorithms", s); + return; + } + if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) > 0 ? "," : "", s)) != 0) + fatal_fr(r, "sshbuf_putf"); +} + +static char * +list_hostkey_types(void) +{ + struct sshbuf *b; + struct sshkey *key; + char *ret; + u_int i; + + if ((b = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + for (i = 0; i < options.num_host_key_files; i++) { + key = host_pubkeys[i]; + if (key == NULL) + continue; + switch (key->type) { + case KEY_RSA: + /* for RSA we also support SHA2 signatures */ + append_hostkey_type(b, "rsa-sha2-512"); + append_hostkey_type(b, "rsa-sha2-256"); + /* FALLTHROUGH */ + case KEY_DSA: + case KEY_ECDSA: + case KEY_ED25519: + case KEY_ECDSA_SK: + case KEY_ED25519_SK: + case KEY_XMSS: + append_hostkey_type(b, sshkey_ssh_name(key)); + break; + } + /* If the private key has a cert peer, then list that too */ + key = host_certificates[i]; + if (key == NULL) + continue; + switch (key->type) { + case KEY_RSA_CERT: + /* for RSA we also support SHA2 signatures */ + append_hostkey_type(b, + "rsa-sha2-512-cert-v01@openssh.com"); + append_hostkey_type(b, + "rsa-sha2-256-cert-v01@openssh.com"); + /* FALLTHROUGH */ + case KEY_DSA_CERT: + case KEY_ECDSA_CERT: + case KEY_ED25519_CERT: + case KEY_ECDSA_SK_CERT: + case KEY_ED25519_SK_CERT: + case KEY_XMSS_CERT: + append_hostkey_type(b, sshkey_ssh_name(key)); + break; + } + } + if ((ret = sshbuf_dup_string(b)) == NULL) + fatal_f("sshbuf_dup_string failed"); + sshbuf_free(b); + debug_f("%s", ret); + return ret; +} + +struct sshkey * +get_hostkey_public_by_type(int type, int nid, struct ssh *ssh) +{ + u_int i; + struct sshkey *key; + + for (i = 0; i < options.num_host_key_files; i++) { + switch (type) { + case KEY_RSA_CERT: + case KEY_DSA_CERT: + case KEY_ECDSA_CERT: + case KEY_ED25519_CERT: + case KEY_ECDSA_SK_CERT: + case KEY_ED25519_SK_CERT: + case KEY_XMSS_CERT: + key = host_certificates[i]; + break; + default: + key = host_pubkeys[i]; + break; + } + if (key == NULL || key->type != type) + continue; + switch (type) { + case KEY_ECDSA: + case KEY_ECDSA_SK: + case KEY_ECDSA_CERT: + case KEY_ECDSA_SK_CERT: + if (key->ecdsa_nid != nid) + continue; + /* FALLTHROUGH */ + default: + return key; + } + } + return NULL; +} + +/* XXX remove */ +struct sshkey * +get_hostkey_private_by_type(int type, int nid, struct ssh *ssh) +{ + return NULL; +} + +/* XXX remove */ +struct sshkey * +get_hostkey_by_index(int ind) +{ + return NULL; +} + +struct sshkey * +get_hostkey_public_by_index(int ind, struct ssh *ssh) +{ + if (ind < 0 || (u_int)ind >= options.num_host_key_files) + return (NULL); + return host_pubkeys[ind]; +} + +int +get_hostkey_index(struct sshkey *key, int compare, struct ssh *ssh) +{ + u_int i; + + for (i = 0; i < options.num_host_key_files; i++) { + if (sshkey_is_cert(key)) { + if (key == host_certificates[i] || + (compare && host_certificates[i] && + sshkey_equal(key, host_certificates[i]))) + return (i); + } else { + if (key == host_pubkeys[i] || + (compare && host_pubkeys[i] && + sshkey_equal(key, host_pubkeys[i]))) + return (i); + } + } + return (-1); +} + +static void +usage(void) +{ + fprintf(stderr, "%s, %s\n", SSH_VERSION, SSH_OPENSSL_VERSION); + fprintf(stderr, +"usage: sshd [-46DdeGiqTtV] [-C connection_spec] [-c host_cert_file]\n" +" [-E log_file] [-f config_file] [-g login_grace_time]\n" +" [-h host_key_file] [-o option] [-p port] [-u len]\n" + ); + exit(1); +} + +static void +parse_hostkeys(struct sshbuf *hostkeys) +{ + int r; + u_int num_keys = 0; + struct sshkey *k; + const u_char *cp; + size_t len; + + while (sshbuf_len(hostkeys) != 0) { + if (num_keys > 2048) + fatal_f("too many hostkeys"); + host_pubkeys = xrecallocarray(host_pubkeys, + num_keys, num_keys + 1, sizeof(*host_pubkeys)); + host_certificates = xrecallocarray(host_certificates, + num_keys, num_keys + 1, sizeof(*host_certificates)); + /* public key */ + k = NULL; + if ((r = sshbuf_get_string_direct(hostkeys, &cp, &len)) != 0) + fatal_fr(r, "extract pubkey"); + if (len != 0 && (r = sshkey_from_blob(cp, len, &k)) != 0) + fatal_fr(r, "parse pubkey"); + host_pubkeys[num_keys] = k; + if (k) + debug2_f("key %u: %s", num_keys, sshkey_ssh_name(k)); + /* certificate */ + k = NULL; + if ((r = sshbuf_get_string_direct(hostkeys, &cp, &len)) != 0) + fatal_fr(r, "extract pubkey"); + if (len != 0 && (r = sshkey_from_blob(cp, len, &k)) != 0) + fatal_fr(r, "parse pubkey"); + host_certificates[num_keys] = k; + if (k) + debug2_f("cert %u: %s", num_keys, sshkey_ssh_name(k)); + num_keys++; + } + num_hostkeys = num_keys; +} + +static void +recv_privsep_state(struct ssh *ssh, struct sshbuf *conf, + uint64_t *timing_secretp) +{ + struct sshbuf *hostkeys; + + debug3_f("begin"); + + mm_get_state(ssh, &includes, conf, NULL, timing_secretp, + &hostkeys, NULL, NULL, NULL, NULL); + parse_hostkeys(hostkeys); + + sshbuf_free(hostkeys); + + debug3_f("done"); +} + +/* + * Main program for the daemon. + */ +int +main(int ac, char **av) +{ + struct ssh *ssh = NULL; + extern char *optarg; + extern int optind; + int r, opt, have_key = 0; + int sock_in = -1, sock_out = -1, rexeced_flag = 0; + char *line, *logfile = NULL; + u_int i; + mode_t new_umask; + Authctxt *authctxt; + struct connection_info *connection_info = NULL; + sigset_t sigmask; + uint64_t timing_secret = 0; + + closefrom(PRIVSEP_MIN_FREE_FD); + sigemptyset(&sigmask); + sigprocmask(SIG_SETMASK, &sigmask, NULL); + + /* Save argv. */ + saved_argv = av; + + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ + sanitise_stdfd(); + + /* Initialize configuration options to their default values. */ + initialize_server_options(&options); + + /* Parse command-line arguments. */ + while ((opt = getopt(ac, av, + "C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) { + switch (opt) { + case '4': + options.address_family = AF_INET; + break; + case '6': + options.address_family = AF_INET6; + break; + case 'f': + config_file_name = optarg; + break; + case 'c': + servconf_add_hostcert("[command-line]", 0, + &options, optarg); + break; + case 'd': + if (debug_flag == 0) { + debug_flag = 1; + options.log_level = SYSLOG_LEVEL_DEBUG1; + } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) + options.log_level++; + break; + case 'D': + /* ignore */ + break; + case 'E': + logfile = optarg; + /* FALLTHROUGH */ + case 'e': + /* ignore */ + break; + case 'i': + inetd_flag = 1; + break; + case 'r': + /* ignore */ + break; + case 'R': + rexeced_flag = 1; + break; + case 'Q': + /* ignored */ + break; + case 'q': + options.log_level = SYSLOG_LEVEL_QUIET; + break; + case 'b': + /* protocol 1, ignored */ + break; + case 'p': + options.ports_from_cmdline = 1; + if (options.num_ports >= MAX_PORTS) { + fprintf(stderr, "too many ports.\n"); + exit(1); + } + options.ports[options.num_ports++] = a2port(optarg); + if (options.ports[options.num_ports-1] <= 0) { + fprintf(stderr, "Bad port number.\n"); + exit(1); + } + break; + case 'g': + if ((options.login_grace_time = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid login grace time.\n"); + exit(1); + } + break; + case 'k': + /* protocol 1, ignored */ + break; + case 'h': + servconf_add_hostkey("[command-line]", 0, + &options, optarg, 1); + break; + case 't': + case 'T': + case 'G': + fatal("test/dump modes not supported"); + break; + case 'C': + connection_info = server_get_connection_info(ssh, 0, 0); + if (parse_server_match_testspec(connection_info, + optarg) == -1) + exit(1); + break; + case 'u': + utmp_len = (u_int)strtonum(optarg, 0, HOST_NAME_MAX+1+1, NULL); + if (utmp_len > HOST_NAME_MAX+1) { + fprintf(stderr, "Invalid utmp length.\n"); + exit(1); + } + break; + case 'o': + line = xstrdup(optarg); + if (process_server_config_line(&options, line, + "command-line", 0, NULL, NULL, &includes) != 0) + exit(1); + free(line); + break; + case 'V': + fprintf(stderr, "%s, %s\n", + SSH_VERSION, SSH_OPENSSL_VERSION); + exit(0); + default: + usage(); + break; + } + } + + if (!rexeced_flag) + fatal("sshd-auth should not be executed directly"); + +#ifdef WITH_OPENSSL + OpenSSL_add_all_algorithms(); +#endif + + /* If requested, redirect the logs to the specified logfile. */ + if (logfile != NULL) { + char *cp, pid_s[32]; + + snprintf(pid_s, sizeof(pid_s), "%ld", (unsigned long)getpid()); + cp = percent_expand(logfile, + "p", pid_s, + "P", "sshd-auth", + (char *)NULL); + log_redirect_stderr_to(cp); + free(cp); + } + + log_init(__progname, + options.log_level == SYSLOG_LEVEL_NOT_SET ? + SYSLOG_LEVEL_INFO : options.log_level, + options.log_facility == SYSLOG_FACILITY_NOT_SET ? + SYSLOG_FACILITY_AUTH : options.log_facility, 1); + + /* XXX can't use monitor_init(); it makes fds */ + pmonitor = xcalloc(1, sizeof(*pmonitor)); + pmonitor->m_sendfd = pmonitor->m_log_recvfd = -1; + pmonitor->m_recvfd = PRIVSEP_MONITOR_FD; + pmonitor->m_log_sendfd = PRIVSEP_LOG_FD; + set_log_handler(mm_log_handler, pmonitor); + + /* Check that there are no remaining arguments. */ + if (optind < ac) { + fprintf(stderr, "Extra argument %s.\n", av[optind]); + exit(1); + } + + debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION); + + /* Connection passed by stdin/out */ + if (inetd_flag) { + /* + * NB. must be different fd numbers for the !socket case, + * as packet_connection_is_on_socket() depends on this. + */ + sock_in = dup(STDIN_FILENO); + sock_out = dup(STDOUT_FILENO); + } else { + /* rexec case; accept()ed socket in ancestor listener */ + sock_in = sock_out = dup(STDIN_FILENO); + } + + if (stdfd_devnull(1, 1, 0) == -1) + error("stdfd_devnull failed"); + debug("network sockets: %d, %d", sock_in, sock_out); + + /* + * Register our connection. This turns encryption off because we do + * not have a key. + */ + if ((ssh = ssh_packet_set_connection(NULL, sock_in, sock_out)) == NULL) + fatal("Unable to create connection"); + the_active_state = ssh; + ssh_packet_set_server(ssh); + pmonitor->m_pkex = &ssh->kex; + + /* Fetch our configuration */ + if ((cfg = sshbuf_new()) == NULL) + fatal("sshbuf_new config buf failed"); + setproctitle("%s", "[session-auth early]"); + recv_privsep_state(ssh, cfg, &timing_secret); + parse_server_config(&options, "rexec", cfg, &includes, NULL, 1); + /* Fill in default values for those options not explicitly set. */ + fill_default_server_options(&options); + options.timing_secret = timing_secret; /* XXX eliminate from unpriv */ + +#ifdef WITH_OPENSSL + if (options.moduli_file != NULL) + dh_set_moduli_file(options.moduli_file); +#endif + + if (options.host_key_agent) { + if (strcmp(options.host_key_agent, SSH_AUTHSOCKET_ENV_NAME)) + setenv(SSH_AUTHSOCKET_ENV_NAME, + options.host_key_agent, 1); + if ((r = ssh_get_authentication_socket(NULL)) == 0) + have_agent = 1; + else + error_r(r, "Could not connect to agent \"%s\"", + options.host_key_agent); + } + + if (options.num_host_key_files != num_hostkeys) { + fatal("internal error: hostkeys confused (config %u recvd %u)", + options.num_host_key_files, num_hostkeys); + } + + for (i = 0; i < options.num_host_key_files; i++) { + if (host_pubkeys[i] != NULL) { + have_key = 1; + break; + } + } + if (!have_key) + fatal("internal error: recieved no hostkeys"); + + /* Ensure that umask disallows at least group and world write */ + new_umask = umask(0077) | 0022; + (void) umask(new_umask); + + /* Initialize the log (it is reinitialized below in case we forked). */ + log_init(__progname, options.log_level, options.log_facility, 1); + set_log_handler(mm_log_handler, pmonitor); + for (i = 0; i < options.num_log_verbose; i++) + log_verbose_add(options.log_verbose[i]); + + /* + * Chdir to the root directory so that the current disk can be + * unmounted if desired. + */ + if (chdir("/") == -1) + error("chdir(\"/\"): %s", strerror(errno)); + + /* This is the child authenticating a new connection. */ + setproctitle("%s", "[session-auth]"); + + /* Executed child processes don't need these. */ + fcntl(sock_out, F_SETFD, FD_CLOEXEC); + fcntl(sock_in, F_SETFD, FD_CLOEXEC); + + ssh_signal(SIGPIPE, SIG_IGN); + ssh_signal(SIGALRM, SIG_DFL); + ssh_signal(SIGHUP, SIG_DFL); + ssh_signal(SIGTERM, SIG_DFL); + ssh_signal(SIGQUIT, SIG_DFL); + ssh_signal(SIGCHLD, SIG_DFL); + + /* Prepare the channels layer */ + channel_init_channels(ssh); + channel_set_af(ssh, options.address_family); + server_process_channel_timeouts(ssh); + server_process_permitopen(ssh); + + ssh_packet_set_nonblocking(ssh); + + /* allocate authentication context */ + authctxt = xcalloc(1, sizeof(*authctxt)); + ssh->authctxt = authctxt; + + /* XXX global for cleanup, access from other modules */ + the_authctxt = authctxt; + + /* Set default key authentication options */ + if ((auth_opts = sshauthopt_new_with_keys_defaults()) == NULL) + fatal("allocation failed"); + + /* prepare buffer to collect messages to display to user after login */ + if ((loginmsg = sshbuf_new()) == NULL) + fatal("sshbuf_new loginmsg failed"); + auth_debug_reset(); + + /* Enable challenge-response authentication for privilege separation */ + privsep_challenge_enable(); + +#ifdef GSSAPI + /* Cache supported mechanism OIDs for later use */ + ssh_gssapi_prepare_supported_oids(); +#endif + + privsep_child_demote(); + + /* perform the key exchange */ + /* authenticate user and start session */ + do_ssh2_kex(ssh); + do_authentication2(ssh); + + /* + * The unprivileged child now transfers the current keystate and exits. + */ + mm_send_keystate(ssh, pmonitor); + ssh_packet_clear_keys(ssh); + exit(0); +} + +int +sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, + struct sshkey *pubkey, u_char **signature, size_t *slenp, + const u_char *data, size_t dlen, const char *alg) +{ + if (privkey) { + if (mm_sshkey_sign(ssh, privkey, signature, slenp, + data, dlen, alg, options.sk_provider, NULL, + ssh->compat) < 0) + fatal_f("privkey sign failed"); + } else { + if (mm_sshkey_sign(ssh, pubkey, signature, slenp, + data, dlen, alg, options.sk_provider, NULL, + ssh->compat) < 0) + fatal_f("pubkey sign failed"); + } + return 0; +} + +/* SSH2 key exchange */ +static void +do_ssh2_kex(struct ssh *ssh) +{ + char *hkalgs = NULL, *myproposal[PROPOSAL_MAX]; + const char *compression = NULL; + struct kex *kex; + int r; + + if (options.rekey_limit || options.rekey_interval) + ssh_packet_set_rekey_limits(ssh, options.rekey_limit, + options.rekey_interval); + + if (options.compression == COMP_NONE) + compression = "none"; + hkalgs = list_hostkey_types(); + + kex_proposal_populate_entries(ssh, myproposal, options.kex_algorithms, + options.ciphers, options.macs, compression, hkalgs); + + free(hkalgs); + + /* start key exchange */ + if ((r = kex_setup(ssh, myproposal)) != 0) + fatal_r(r, "kex_setup"); + kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos); + kex = ssh->kex; + +#ifdef WITH_OPENSSL + kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; + kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; + kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; + kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; + kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; + kex->kex[KEX_ECDH_SHA2] = kex_gen_server; +#endif + kex->kex[KEX_C25519_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; + kex->load_host_public_key=&get_hostkey_public_by_type; + kex->load_host_private_key=&get_hostkey_private_by_type; + kex->host_key_index=&get_hostkey_index; + kex->sign = sshd_hostkey_sign; + + ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &kex->done); + kex_proposal_free_entries(myproposal); + +#ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || + (r = sshpkt_put_cstring(ssh, "markus")) != 0 || + (r = sshpkt_send(ssh)) != 0 || + (r = ssh_packet_write_wait(ssh)) != 0) + fatal_fr(r, "send test"); +#endif + debug("KEX done"); +} + +/* server specific fatal cleanup */ +void +cleanup_exit(int i) +{ + _exit(i); +} diff --git a/usr.bin/ssh/sshd-auth/Makefile b/usr.bin/ssh/sshd-auth/Makefile new file mode 100644 index 000000000..25e94157e --- /dev/null +++ b/usr.bin/ssh/sshd-auth/Makefile @@ -0,0 +1,71 @@ +# $OpenBSD: Makefile,v 1.1 2024/10/14 01:57:50 djm Exp $ + +.PATH: ${.CURDIR}/.. + +SRCS= sshd-auth.c auth2-methods.c \ + auth-rhosts.c auth-passwd.c sshpty.c sshlogin.c servconf.c \ + serverloop.c auth.c auth2.c auth-options.c session.c auth2-chall.c \ + groupaccess.c auth-bsdauth.c auth2-hostbased.c auth2-kbdint.c \ + auth2-none.c auth2-passwd.c auth2-pubkey.c auth2-pubkeyfile.c \ + monitor_wrap.c \ + sftp-server.c sftp-common.c sftp-realpath.c +SRCS+= authfd.c compat.c dns.c fatal.c hostfile.c readpass.c utf8.c uidswap.c +SRCS+= ${SRCS_BASE} ${SRCS_KEX} ${SRCS_KEXS} ${SRCS_KEY} ${SRCS_KEYP} \ + ${SRCS_KRL} ${SRCS_PROT} ${SRCS_PKT} ${SRCS_UTL} ${SRCS_PKCS11} \ + ${SRCS_SK_CLIENT} + +PROG= sshd-auth +BINDIR= /usr/libexec +BINMODE=511 +NOMAN= 1 + +.include # for KERBEROS and AFS + +KERBEROS5=no + +.if (${KERBEROS5:L} == "yes") +CFLAGS+=-DKRB5 -I${DESTDIR}/usr/include/kerberosV -DGSSAPI +SRCS+= auth-krb5.c auth2-gss.c gss-serv.c gss-serv-krb5.c +.endif + +.include + +.if (${KERBEROS5:L} == "yes") +LDADD+= -lgssapi -lkrb5 -lasn1 +LDADD+= -lwind -lroken -lcom_err -lpthread -lheimbase -lkafs +DPADD+= ${LIBGSSAPI} ${LIBKRB5} +.endif + +.if (${OPENSSL:L} == "yes") +LDADD+= -lcrypto +DPADD+= ${LIBCRYPTO} +.endif + +LDADD+= -lutil +DPADD+= ${LIBUTIL} + +.if (${ZLIB:L} == "yes") +LDADD+= -lz +DPADD+= ${LIBZ} +.endif + +# The random relink kit, used on OpenBSD by /etc/rc + +CLEANFILES+= ${PROG}.tar install.sh + +install.sh: Makefile + echo "set -o errexit" > $@ + echo "${CC} ${LDFLAGS} ${LDSTATIC} -o ${PROG}" \ + "\`echo " ${OBJS} "| tr ' ' '\\\n' | sort -R\`" ${LDADD} >> $@ + echo "./${PROG} -V # test it works" >> $@ + echo "install -c -s -o root -g bin -m ${BINMODE} ${PROG} " \ + "${BINDIR}/${PROG}" >> $@ + +${PROG}.tar: ${OBJS} install.sh + tar cf $@ ${OBJS} install.sh + +afterinstall: ${PROG}.tar + install -d -o root -g wheel -m 755 \ + ${DESTDIR}/usr/share/relink/${BINDIR}/${PROG} + install -o ${BINOWN} -g ${BINGRP} -m 640 \ + ${PROG}.tar ${DESTDIR}/usr/share/relink/${BINDIR}/${PROG}/${PROG}.tar diff --git a/usr.bin/ssh/sshd-session.c b/usr.bin/ssh/sshd-session.c index e4b698db5..235f818ca 100644 --- a/usr.bin/ssh/sshd-session.c +++ b/usr.bin/ssh/sshd-session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd-session.c,v 1.9 2024/09/09 02:39:57 djm Exp $ */ +/* $OpenBSD: sshd-session.c,v 1.10 2024/10/14 01:57:50 djm Exp $ */ /* * SSH2 implementation: * Privilege Separation: @@ -86,7 +86,6 @@ #include "ssh-gss.h" #endif #include "monitor_wrap.h" -#include "ssh-sandbox.h" #include "auth-options.h" #include "version.h" #include "ssherr.h" @@ -100,6 +99,11 @@ #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) #define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) +/* Privsep fds */ +#define PRIVSEP_MONITOR_FD (STDERR_FILENO + 1) +#define PRIVSEP_LOG_FD (STDERR_FILENO + 2) +#define PRIVSEP_MIN_FREE_FD (STDERR_FILENO + 3) + extern char *__progname; /* Server configuration options. */ @@ -172,7 +176,17 @@ struct sshbuf *loginmsg; /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); void demote_sensitive_data(void); -static void do_ssh2_kex(struct ssh *); + +/* XXX reduce to stub once postauth split */ +int +mm_is_monitor(void) +{ + /* + * m_pid is only set in the privileged part, and + * points to the unprivileged child. + */ + return (pmonitor && pmonitor->m_pid > 0); +} /* * Signal handler for the alarm after the login grace period has expired. @@ -239,50 +253,41 @@ demote_sensitive_data(void) } } -static void -privsep_preauth_child(void) +struct sshbuf * +pack_hostkeys(void) { - gid_t gidset[1]; - struct passwd *pw; + struct sshbuf *keybuf = NULL, *hostkeys = NULL; + int r; + u_int i; - /* Enable challenge-response authentication for privilege separation */ - privsep_challenge_enable(); + if ((hostkeys = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); -#ifdef GSSAPI - /* Cache supported mechanism OIDs for later use */ - ssh_gssapi_prepare_supported_oids(); -#endif - - /* Demote the private keys to public keys. */ - demote_sensitive_data(); - - /* Demote the child */ - if (getuid() == 0 || geteuid() == 0) { - if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) - fatal("Privilege separation user %s does not exist", - SSH_PRIVSEP_USER); - pw = pwcopy(pw); /* Ensure mutable */ - endpwent(); - freezero(pw->pw_passwd, strlen(pw->pw_passwd)); - - /* Change our root directory */ - if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) - fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, - strerror(errno)); - if (chdir("/") == -1) - fatal("chdir(\"/\"): %s", strerror(errno)); - - /* - * Drop our privileges - * NB. Can't use setusercontext() after chroot. - */ - debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, - (u_int)pw->pw_gid); - gidset[0] = pw->pw_gid; - if (setgroups(1, gidset) == -1) - fatal("setgroups: %.100s", strerror(errno)); - permanently_set_uid(pw); + /* pack hostkeys into a string. Empty key slots get empty strings */ + for (i = 0; i < options.num_host_key_files; i++) { + /* public key */ + if (sensitive_data.host_pubkeys[i] != NULL) { + if ((r = sshkey_puts(sensitive_data.host_pubkeys[i], + hostkeys)) != 0) + fatal_fr(r, "compose hostkey public"); + } else { + if ((r = sshbuf_put_string(hostkeys, NULL, 0)) != 0) + fatal_fr(r, "compose hostkey empty public"); + } + /* cert */ + if (sensitive_data.host_certificates[i] != NULL) { + if ((r = sshkey_puts( + sensitive_data.host_certificates[i], + hostkeys)) != 0) + fatal_fr(r, "compose host cert"); + } else { + if ((r = sshbuf_put_string(hostkeys, NULL, 0)) != 0) + fatal_fr(r, "compose host cert empty"); + } } + + sshbuf_free(keybuf); + return hostkeys; } static int @@ -290,20 +295,16 @@ privsep_preauth(struct ssh *ssh) { int status, r; pid_t pid; - struct ssh_sandbox *box = NULL; /* Set up unprivileged child process to deal with network data */ pmonitor = monitor_init(); /* Store a pointer to the kex for later rekeying */ pmonitor->m_pkex = &ssh->kex; - box = ssh_sandbox_init(); - pid = fork(); - if (pid == -1) { + if ((pid = fork()) == -1) fatal("fork of unprivileged child failed"); - } else if (pid != 0) { + else if (pid != 0) { debug2("Network child is on pid %ld", (long)pid); - pmonitor->m_pid = pid; if (have_agent) { r = ssh_get_authentication_socket(&auth_sock); @@ -312,8 +313,6 @@ privsep_preauth(struct ssh *ssh) have_agent = 0; } } - if (box != NULL) - ssh_sandbox_parent_preauth(box, pid); monitor_child_preauth(ssh, pmonitor); /* Wait for the child's exit status */ @@ -332,23 +331,46 @@ privsep_preauth(struct ssh *ssh) } else if (WIFSIGNALED(status)) fatal_f("preauth child terminated by signal %d", WTERMSIG(status)); - if (box != NULL) - ssh_sandbox_parent_finish(box); return 1; } else { /* child */ close(pmonitor->m_sendfd); close(pmonitor->m_log_recvfd); - /* Arrange for logging to be sent to the monitor */ - set_log_handler(mm_log_handler, pmonitor); + /* + * Arrange unpriv-preauth child process fds: + * 0, 1 network socket + * 2 optional stderr + * 3 reserved + * 4 monitor message socket + * 5 monitor logging socket + * + * We know that the monitor sockets will have fds > 4 because + * of the reserved fds in main() + */ - privsep_preauth_child(); - setproctitle("%s", "[net]"); - if (box != NULL) - ssh_sandbox_child(box); + if (ssh_packet_get_connection_in(ssh) != STDIN_FILENO && + dup2(ssh_packet_get_connection_in(ssh), STDIN_FILENO) == -1) + fatal("dup2 stdin failed: %s", strerror(errno)); + if (ssh_packet_get_connection_out(ssh) != STDOUT_FILENO && + dup2(ssh_packet_get_connection_out(ssh), + STDOUT_FILENO) == -1) + fatal("dup2 stdout failed: %s", strerror(errno)); + /* leave stderr as-is */ + log_redirect_stderr_to(NULL); /* dup can clobber log fd */ + if (pmonitor->m_recvfd != PRIVSEP_MONITOR_FD && + dup2(pmonitor->m_recvfd, PRIVSEP_MONITOR_FD) == -1) + fatal("dup2 monitor fd: %s", strerror(errno)); + if (pmonitor->m_log_sendfd != PRIVSEP_LOG_FD && + dup2(pmonitor->m_log_sendfd, PRIVSEP_LOG_FD) == -1) + fatal("dup2 log fd: %s", strerror(errno)); + closefrom(PRIVSEP_MIN_FREE_FD); - return 0; + saved_argv[0] = options.sshd_auth_path; + execv(options.sshd_auth_path, saved_argv); + + fatal_f("exec of %s failed: %s", + options.sshd_auth_path, strerror(errno)); } } @@ -392,79 +414,6 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) ssh_packet_set_authenticated(ssh); } -static void -append_hostkey_type(struct sshbuf *b, const char *s) -{ - int r; - - if (match_pattern_list(s, options.hostkeyalgorithms, 0) != 1) { - debug3_f("%s key not permitted by HostkeyAlgorithms", s); - return; - } - if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) > 0 ? "," : "", s)) != 0) - fatal_fr(r, "sshbuf_putf"); -} - -static char * -list_hostkey_types(void) -{ - struct sshbuf *b; - struct sshkey *key; - char *ret; - u_int i; - - if ((b = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - for (i = 0; i < options.num_host_key_files; i++) { - key = sensitive_data.host_keys[i]; - if (key == NULL) - key = sensitive_data.host_pubkeys[i]; - if (key == NULL) - continue; - switch (key->type) { - case KEY_RSA: - /* for RSA we also support SHA2 signatures */ - append_hostkey_type(b, "rsa-sha2-512"); - append_hostkey_type(b, "rsa-sha2-256"); - /* FALLTHROUGH */ - case KEY_DSA: - case KEY_ECDSA: - case KEY_ED25519: - case KEY_ECDSA_SK: - case KEY_ED25519_SK: - case KEY_XMSS: - append_hostkey_type(b, sshkey_ssh_name(key)); - break; - } - /* If the private key has a cert peer, then list that too */ - key = sensitive_data.host_certificates[i]; - if (key == NULL) - continue; - switch (key->type) { - case KEY_RSA_CERT: - /* for RSA we also support SHA2 signatures */ - append_hostkey_type(b, - "rsa-sha2-512-cert-v01@openssh.com"); - append_hostkey_type(b, - "rsa-sha2-256-cert-v01@openssh.com"); - /* FALLTHROUGH */ - case KEY_DSA_CERT: - case KEY_ECDSA_CERT: - case KEY_ED25519_CERT: - case KEY_ECDSA_SK_CERT: - case KEY_ED25519_SK_CERT: - case KEY_XMSS_CERT: - append_hostkey_type(b, sshkey_ssh_name(key)); - break; - } - } - if ((ret = sshbuf_dup_string(b)) == NULL) - fatal_f("sshbuf_dup_string failed"); - sshbuf_free(b); - debug_f("%s", ret); - return ret; -} - static struct sshkey * get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh) { @@ -801,7 +750,7 @@ main(int ac, char **av) struct ssh *ssh = NULL; extern char *optarg; extern int optind; - int r, opt, on = 1, remote_port; + int devnull, r, opt, on = 1, remote_port; int sock_in = -1, sock_out = -1, rexeced_flag = 0, have_key = 0; const char *remote_ip, *rdomain; char *line, *laddr, *logfile = NULL; @@ -950,6 +899,14 @@ main(int ac, char **av) closefrom(REEXEC_MIN_FREE_FD); + /* Reserve fds we'll need later for reexec things */ + if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) + fatal("open %s: %s", _PATH_DEVNULL, strerror(errno)); + while (devnull < PRIVSEP_MIN_FREE_FD) { + if ((devnull = dup(devnull)) == -1) + fatal("dup %s: %s", _PATH_DEVNULL, strerror(errno)); + } + #ifdef WITH_OPENSSL OpenSSL_add_all_algorithms(); #endif @@ -985,15 +942,21 @@ main(int ac, char **av) fatal("sshbuf_new config buf failed"); setproctitle("%s", "[rexeced]"); recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg, &timing_secret); - close(REEXEC_CONFIG_PASS_FD); + /* close the fd, but keep the slot reserved */ + if (dup2(devnull, REEXEC_CONFIG_PASS_FD) == -1) + fatal("dup2 devnull->config fd: %s", strerror(errno)); parse_server_config(&options, "rexec", cfg, &includes, NULL, 1); /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); options.timing_secret = timing_secret; - if (!debug_flag) { - startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); - close(REEXEC_STARTUP_PIPE_FD); + if (!debug_flag && !inetd_flag) { + if ((startup_pipe = dup(REEXEC_STARTUP_PIPE_FD)) == -1) + fatal("internal error: no startup pipe"); + /* close the fd, but keep the slot reserved */ + if (dup2(devnull, REEXEC_STARTUP_PIPE_FD) == -1) + fatal("dup2 devnull->startup fd: %s", strerror(errno)); + /* * Signal parent that this child is at a point where * they can go away if they have a SIGHUP pending. @@ -1210,22 +1173,11 @@ main(int ac, char **av) fatal("sshbuf_new loginmsg failed"); auth_debug_reset(); - if (privsep_preauth(ssh) == 1) - goto authenticated; + if (privsep_preauth(ssh) != 1) + fatal("privsep_preauth failed"); - /* perform the key exchange */ - /* authenticate user and start session */ - do_ssh2_kex(ssh); - do_authentication2(ssh); + /* Now user is authenticated */ - /* - * The unprivileged child now transfers the current keystate and exits. - */ - mm_send_keystate(ssh, pmonitor); - ssh_packet_clear_keys(ssh); - exit(0); - - authenticated: /* * Cancel the alarm we set to limit the time taken for * authentication. @@ -1294,66 +1246,6 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, return 0; } -/* SSH2 key exchange */ -static void -do_ssh2_kex(struct ssh *ssh) -{ - char *hkalgs = NULL, *myproposal[PROPOSAL_MAX]; - const char *compression = NULL; - struct kex *kex; - int r; - - if (options.rekey_limit || options.rekey_interval) - ssh_packet_set_rekey_limits(ssh, options.rekey_limit, - options.rekey_interval); - - if (options.compression == COMP_NONE) - compression = "none"; - hkalgs = list_hostkey_types(); - - kex_proposal_populate_entries(ssh, myproposal, options.kex_algorithms, - options.ciphers, options.macs, compression, hkalgs); - - free(hkalgs); - - /* start key exchange */ - if ((r = kex_setup(ssh, myproposal)) != 0) - fatal_r(r, "kex_setup"); - kex_set_server_sig_algs(ssh, options.pubkey_accepted_algos); - kex = ssh->kex; - -#ifdef WITH_OPENSSL - kex->kex[KEX_DH_GRP1_SHA1] = kex_gen_server; - kex->kex[KEX_DH_GRP14_SHA1] = kex_gen_server; - kex->kex[KEX_DH_GRP14_SHA256] = kex_gen_server; - kex->kex[KEX_DH_GRP16_SHA512] = kex_gen_server; - kex->kex[KEX_DH_GRP18_SHA512] = kex_gen_server; - kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; - kex->kex[KEX_ECDH_SHA2] = kex_gen_server; -#endif - kex->kex[KEX_C25519_SHA256] = kex_gen_server; - kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; - kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; - kex->load_host_private_key=&get_hostkey_private_by_type; - kex->host_key_index=&get_hostkey_index; - kex->sign = sshd_hostkey_sign; - - ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &kex->done); - kex_proposal_free_entries(myproposal); - -#ifdef DEBUG_KEXDH - /* send 1st encrypted/maced/compressed message */ - if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || - (r = sshpkt_put_cstring(ssh, "markus")) != 0 || - (r = sshpkt_send(ssh)) != 0 || - (r = ssh_packet_write_wait(ssh)) != 0) - fatal_fr(r, "send test"); -#endif - debug("KEX done"); -} - /* server specific fatal cleanup */ void cleanup_exit(int i) diff --git a/usr.bin/ssh/sshd-session/Makefile b/usr.bin/ssh/sshd-session/Makefile index 40d5ee270..04e46449a 100644 --- a/usr.bin/ssh/sshd-session/Makefile +++ b/usr.bin/ssh/sshd-session/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.3 2024/05/17 14:42:00 naddy Exp $ +# $OpenBSD: Makefile,v 1.4 2024/10/14 01:57:50 djm Exp $ .PATH: ${.CURDIR}/.. @@ -8,7 +8,7 @@ SRCS= sshd-session.c auth2-methods.c \ groupaccess.c auth-bsdauth.c auth2-hostbased.c auth2-kbdint.c \ auth2-none.c auth2-passwd.c auth2-pubkey.c auth2-pubkeyfile.c \ monitor.c monitor_wrap.c \ - sftp-server.c sftp-common.c sftp-realpath.c sandbox-pledge.c srclimit.c + sftp-server.c sftp-common.c sftp-realpath.c srclimit.c SRCS+= authfd.c compat.c dns.c fatal.c hostfile.c readpass.c utf8.c uidswap.c SRCS+= ${SRCS_BASE} ${SRCS_KEX} ${SRCS_KEXS} ${SRCS_KEY} ${SRCS_KEYP} \ ${SRCS_KRL} ${SRCS_PROT} ${SRCS_PKT} ${SRCS_UTL} ${SRCS_PKCS11} \ diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c index c02a7b964..07c62bacd 100644 --- a/usr.bin/ssh/sshd.c +++ b/usr.bin/ssh/sshd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshd.c,v 1.612 2024/09/15 01:11:26 djm Exp $ */ +/* $OpenBSD: sshd.c,v 1.613 2024/10/14 01:57:50 djm Exp $ */ /* * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. * Copyright (c) 2002 Niels Provos. All rights reserved. @@ -1573,6 +1573,13 @@ main(int ac, char **av) fatal("%s does not exist or is not executable", rexec_argv[0]); debug3("using %s for re-exec", rexec_argv[0]); + /* Ensure that the privsep binary exists now too. */ + if (stat(options.sshd_auth_path, &sb) != 0 || + !(sb.st_mode & (S_IXOTH|S_IXUSR))) { + fatal("%s does not exist or is not executable", + options.sshd_auth_path); + } + listener_proctitle = prepare_proctitle(ac, av); /* Ensure that umask disallows at least group and world write */