diff --git a/security/openssh-portable/Makefile b/security/openssh-portable/Makefile index 979f9cdd3da9..5855a233fbc2 100644 --- a/security/openssh-portable/Makefile +++ b/security/openssh-portable/Makefile @@ -1,247 +1,247 @@ PORTNAME= openssh DISTVERSION= 10.2p1 -PORTREVISION= 4 +PORTREVISION= 5 PORTEPOCH= 1 CATEGORIES= security MASTER_SITES= OPENBSD/OpenSSH/portable PKGNAMESUFFIX?= -portable MAINTAINER= bdrewery@FreeBSD.org COMMENT= The portable version of OpenBSD's OpenSSH WWW= https://www.openssh.com/portable.html LICENSE= OPENSSH LICENSE_NAME= OpenSSH Licenses LICENSE_FILE= ${WRKSRC}/LICENCE LICENSE_PERMS= dist-mirror dist-sell pkg-mirror pkg-sell auto-accept CONFLICTS?= openssh-3.* ssh-1.* ssh2-3.* openssh-portable-devel USES= autoreconf compiler:c11 cpe localbase ncurses \ pkgconfig ssl GNU_CONFIGURE= yes GNU_CONFIGURE_MANPREFIX= ${PREFIX}/share CONFIGURE_ARGS= --prefix=${PREFIX} \ --without-zlib-version-check \ --with-ssl-engine \ --with-mantype=man ETCOLD= ${PREFIX}/etc CPE_VENDOR= openbsd FLAVORS= default hpn gssapi default_CONFLICTS_INSTALL= openssh-portable-hpn openssh-portable-gssapi \ openssh-portable-x509 hpn_CONFLICTS_INSTALL= openssh-portable openssh-portable-gssapi \ openssh-portable-x509 hpn_PKGNAMESUFFIX= -portable-hpn gssapi_CONFLICTS_INSTALL= openssh-portable openssh-portable-hpn \ openssh-portable-x509 gssapi_PKGNAMESUFFIX= -portable-gssapi OPTIONS_DEFINE= DOCS PAM TCP_WRAPPERS LIBEDIT BSM \ HPN KERB_GSSAPI \ LDNS NONECIPHER FIDO_U2F BLACKLISTD OPTIONS_DEFAULT= BLACKLISTD LIBEDIT PAM TCP_WRAPPERS LDNS FIDO_U2F .if ${FLAVOR:U} == hpn OPTIONS_DEFAULT+= HPN NONECIPHER .endif .if ${FLAVOR:U} == gssapi OPTIONS_DEFAULT+= KERB_GSSAPI MIT .endif OPTIONS_RADIO= KERBEROS OPTIONS_RADIO_KERBEROS= MIT HEIMDAL HEIMDAL_BASE TCP_WRAPPERS_DESC= tcp_wrappers support BSM_DESC= OpenBSM Auditing KERB_GSSAPI_DESC= Kerberos/GSSAPI patch (req: GSSAPI) HPN_DESC= HPN-SSH patch LDNS_DESC= SSHFP/LDNS support HEIMDAL_DESC= Heimdal Kerberos (security/heimdal) HEIMDAL_BASE_DESC= Heimdal Kerberos (base) MIT_DESC= MIT Kerberos (security/krb5) NONECIPHER_DESC= NONE Cipher support FIDO_U2F_DESC= FIDO/U2F support (security/libfido2) BLACKLISTD_DESC= FreeBSD blacklistd(8) support OPTIONS_SUB= yes PAM_EXTRA_PATCHES= ${FILESDIR}/extra-patch-pam-sshd_config TCP_WRAPPERS_EXTRA_PATCHES=${FILESDIR}/extra-patch-tcpwrappers LDNS_CONFIGURE_WITH= ldns=${LOCALBASE} LDNS_LIB_DEPENDS= libldns.so:dns/ldns HPN_CONFIGURE_WITH= hpn NONECIPHER_CONFIGURE_WITH= nonecipher MIT_LIB_DEPENDS= libkrb5.so.3:security/krb5 HEIMDAL_LIB_DEPENDS= libkrb5.so.26:security/heimdal PAM_CONFIGURE_WITH= pam TCP_WRAPPERS_CONFIGURE_WITH= tcp-wrappers LIBEDIT_CONFIGURE_WITH= libedit LIBEDIT_USES= libedit BSM_CONFIGURE_ON= --with-audit=bsm FIDO_U2F_LIB_DEPENDS= libfido2.so:security/libfido2 FIDO_U2F_CONFIGURE_ON= --with-security-key-builtin FIDO_U2F_CONFIGURE_OFF= --disable-security-key BLACKLISTD_EXTRA_PATCHES= ${FILESDIR}/extra-patch-blacklistd ETCDIR?= ${PREFIX}/etc/ssh .include PATCH_SITES+= http://mirror.shatow.net/freebsd/${PORTNAME}/:DEFAULT,hpn,gsskex # Must add this patch before HPN due to conflicts .if !${PORT_OPTIONS:MBLACKLISTD} . if ${PORT_OPTIONS:MHPN} || ${PORT_OPTIONS:MNONECIPHER} # Needed glue for applying HPN patch without conflict EXTRA_PATCHES+= ${FILESDIR}/extra-patch-no-blocklistd-hpn-glue . endif .endif # Must add this patch before HPN due to conflicts .if ${PORT_OPTIONS:MKERB_GSSAPI} || ${FLAVOR:U} == gssapi # BROKEN= KERB_GSSAPI No patch for ${DISTVERSION} yet. . if ${PORT_OPTIONS:MHPN} || ${PORT_OPTIONS:MNONECIPHER} # Needed glue for applying HPN patch without conflict EXTRA_PATCHES+= ${FILESDIR}/extra-patch-hpn-gss-glue . endif # - See https://sources.debian.org/data/main/o/openssh/ for which subdir to # pull from. GSSAPI_DEBIAN_VERSION= 10.2p1 GSSAPI_DEBIAN_SUBDIR= ${GSSAPI_DEBIAN_VERSION:U${DISTVERSION}}-1 # - Debian does not use a versioned filename so we trick fetch to make one for # us with the ?=/ trick. PATCH_SITES+= https://sources.debian.org/data/main/o/openssh/1:${GSSAPI_DEBIAN_SUBDIR}/debian/patches/gssapi.patch?dummy=/:gsskex # Bump this when updating the patch location GSSAPI_DISTVERSION= 10.2p1 PATCHFILES+= openssh-${GSSAPI_DISTVERSION:U${DISTVERSION}}-gsskex-all-debian-rh-${GSSAPI_DISTVERSION}.patch:-p1:gsskex EXTRA_PATCHES+= ${FILESDIR}/extra-patch-gssapi-kexgssc.c EXTRA_PATCHES+= ${FILESDIR}/extra-patch-gssapi-kexgsss.c .endif .if ${PORT_OPTIONS:MBLACKLISTD} CONFIGURE_LIBS+= -lblacklist .endif # https://www.psc.edu/hpn-ssh https://github.com/rapier1/openssh-portable/tree/hpn-openssl1.1-7_7_P1 .if ${PORT_OPTIONS:MHPN} || ${PORT_OPTIONS:MNONECIPHER} #BROKEN= HPN: Not yet updated for ${DISTVERSION} yet. PORTDOCS+= HPN-README HPN_VERSION= 14v15 HPN_DISTVERSION= 7.7p1 #PATCH_SITES+= SOURCEFORGE/hpnssh/HPN-SSH%20${HPN_VERSION}%20${HPN_DISTVERSION}/:hpn #PATCHFILES+= ${PORTNAME}-${HPN_DISTVERSION}-hpnssh${HPN_VERSION}.diff.gz:-p1:hpn EXTRA_PATCHES+= ${FILESDIR}/extra-patch-hpn:-p2 .elif !${PORT_OPTIONS:MHPN} && !${PORT_OPTIONS:MNONECIPHER} # Apply compatibility patch EXTRA_PATCHES+= ${FILESDIR}/extra-patch-hpn-compat .endif CONFIGURE_ARGS+= --disable-utmp --disable-wtmp --disable-wtmpx --without-lastlog # Keep this last EXTRA_PATCHES+= ${FILESDIR}/extra-patch-version-addendum .if ${PORT_OPTIONS:MHEIMDAL_BASE} && ${PORT_OPTIONS:MKERB_GSSAPI} BROKEN= KERB_GSSAPI Requires either MIT or HEMIDAL, does not build with base Heimdal currently .endif .if ${PORT_OPTIONS:MHEIMDAL_BASE} && !exists(/usr/lib/libkrb5.so) IGNORE= you have selected HEIMDAL_BASE but do not have heimdal installed in base .endif .if ${PORT_OPTIONS:MMIT} || ${PORT_OPTIONS:MHEIMDAL} || ${PORT_OPTIONS:MHEIMDAL_BASE} . if ${PORT_OPTIONS:MHEIMDAL_BASE} CONFIGURE_LIBS+= -lgssapi_krb5 CONFIGURE_ARGS+= --with-kerberos5=/usr . else CONFIGURE_LIBS+= -lgssapi_krb5 CONFIGURE_ARGS+= --with-kerberos5=${LOCALBASE} . endif . if ${OPENSSLBASE} == "/usr" CONFIGURE_ARGS+= --without-rpath LDFLAGS= # empty . endif .else . if ${PORT_OPTIONS:MKERB_GSSAPI} IGNORE= KERB_GSSAPI requires one of MIT HEIMDAL or HEIMDAL_BASE . endif .endif .if ${OPENSSLBASE} != "/usr" CONFIGURE_ARGS+= --with-ssl-dir=${OPENSSLBASE} .endif EMPTYDIR= /var/empty USE_RC_SUBR= openssh # After all CONFIGURE_ARGS+= --sysconfdir=${ETCDIR} --with-privsep-path=${EMPTYDIR} .if !empty(CONFIGURE_LIBS) CONFIGURE_ARGS+= --with-libs='${CONFIGURE_LIBS}' .endif CONFIGURE_ARGS+= --with-xauth=${LOCALBASE}/bin/xauth RC_SCRIPT_NAME= openssh VERSION_ADDENDUM_DEFAULT?= ${OPSYS}-${PKGNAME} CFLAGS+= ${CFLAGS_${CHOSEN_COMPILER_TYPE}} CFLAGS_gcc= -Wno-stringop-truncation -Wno-stringop-overflow SSH_ASKPASS_PATH?= ${LOCALBASE}/bin/ssh-askpass post-patch: @${REINPLACE_CMD} \ -e 's|install: \(.*\) host-key check-config|install: \1|g' \ ${WRKSRC}/Makefile.in @${REINPLACE_CMD} \ -e 's|$$[{(]libexecdir[})]/ssh-askpass|${SSH_ASKPASS_PATH}|' \ ${WRKSRC}/Makefile.in ${WRKSRC}/configure.ac @${REINPLACE_CMD} \ -e 's|\(VersionAddendum\) none|\1 ${VERSION_ADDENDUM_DEFAULT}|' \ ${WRKSRC}/sshd_config @${REINPLACE_CMD} \ -e 's|%%SSH_VERSION_FREEBSD_PORT%%|${VERSION_ADDENDUM_DEFAULT}|' \ ${WRKSRC}/sshd_config.5 @${ECHO_CMD} '#define SSH_VERSION_FREEBSD_PORT "${VERSION_ADDENDUM_DEFAULT}"' >> \ ${WRKSRC}/version.h post-configure-BLACKLISTD-on: @${ECHO_CMD} "#define USE_BLACKLIST 1" >> ${WRKSRC}/config.h post-install: ${MV} ${STAGEDIR}${ETCDIR}/moduli \ ${STAGEDIR}${ETCDIR}/moduli.sample ${MV} ${STAGEDIR}${ETCDIR}/ssh_config \ ${STAGEDIR}${ETCDIR}/ssh_config.sample ${MV} ${STAGEDIR}${ETCDIR}/sshd_config \ ${STAGEDIR}${ETCDIR}/sshd_config.sample ${MKDIR} ${STAGEDIR}${ETCDIR}/ssh_config.d \ ${STAGEDIR}${ETCDIR}/sshd_config.d .if ${PORT_OPTIONS:MHPN} || ${PORT_OPTIONS:MNONECIPHER} ${MKDIR} ${STAGEDIR}${DOCSDIR} ${INSTALL_DATA} ${WRKSRC}/HPN-README ${STAGEDIR}${DOCSDIR} .endif test: build cd ${WRKSRC} && ${SETENV} -i \ OBJ=${WRKDIR} ${MAKE_ENV:NHOME=*} \ TEST_SHELL=${SH} \ SUDO="${SUDO}" \ LOGNAME="${LOGNAME}" \ HOME="${HOME}" \ TEST_SSH_TRACE=yes \ PATH=${WRKSRC}:${PREFIX}/bin:${PREFIX}/sbin:${PATH} \ ${MAKE_CMD} ${MAKE_FLAGS} ${MAKEFILE} ${MAKE_ARGS} tests .include diff --git a/security/openssh-portable/files/extra-patch-pam-sshd_config b/security/openssh-portable/files/extra-patch-pam-sshd_config index aa80ceeeb2c3..7d003cfc7f3f 100644 --- a/security/openssh-portable/files/extra-patch-pam-sshd_config +++ b/security/openssh-portable/files/extra-patch-pam-sshd_config @@ -1,31 +1,32 @@ --- sshd_config.orig 2025-04-09 00:02:43.000000000 -0700 +++ sshd_config 2025-04-10 21:52:39.463528000 -0700 -@@ -53,8 +53,8 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -53,8 +53,9 @@ AuthorizedKeysFile .ssh/authorized_keys # Don't read the user's ~/.rhosts and ~/.shosts files #IgnoreRhosts yes -# To disable tunneled clear text passwords, change to "no" here! -#PasswordAuthentication yes -+# To enable tunneled clear text passwords, change to yes here! ++# Change to "yes" to enable built-in password authentication. ++# Note that passwords may also be accepted via KbdInteractiveAuthentication. +#PasswordAuthentication no #PermitEmptyPasswords no # Change to "no" to disable keyboard-interactive authentication. Depending on @@ -72,7 +72,7 @@ AuthorizedKeysFile .ssh/authorized_keys #GSSAPIAuthentication no #GSSAPICleanupCredentials yes -# Set this to 'yes' to enable PAM authentication, account processing, +# Set this to 'no' to disable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will # be allowed through the KbdInteractiveAuthentication and # PasswordAuthentication. Depending on your PAM configuration, @@ -81,7 +81,7 @@ AuthorizedKeysFile .ssh/authorized_keys # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and KbdInteractiveAuthentication to 'no'. -#UsePAM no +#UsePAM yes #AllowAgentForwarding yes #AllowTcpForwarding yes diff --git a/security/openssh-portable/files/extra-patch-tcpwrappers b/security/openssh-portable/files/extra-patch-tcpwrappers index 5d9e8aced144..27fd19cbcfb0 100644 --- a/security/openssh-portable/files/extra-patch-tcpwrappers +++ b/security/openssh-portable/files/extra-patch-tcpwrappers @@ -1,151 +1,221 @@ Revert TCPWRAPPER removal -bdrewery +Syncs in sshd.c changes from src as well. commit f2719b7c2b8a3b14d778d8a6d8dc729b5174b054 Author: Damien Miller Date: Sun Apr 20 13:22:18 2014 +1000 - tedu@cvs.openbsd.org 2014/03/26 19:58:37 [sshd.8 sshd.c] remove libwrap support. ok deraadt djm mfriedl diff --git sshd.8 sshd.8 index 289e13d..e6a900b 100644 --- sshd.8 +++ sshd.8 @@ -851,6 +851,12 @@ the user's home directory becomes accessible. This file should be writable only by the user, and need not be readable by anyone else. .Pp +.It Pa /etc/hosts.allow +.It Pa /etc/hosts.deny +Access controls that should be enforced by tcp-wrappers are defined here. +Further details are described in +.Xr hosts_access 5 . +.Pp .It Pa /etc/hosts.equiv This file is for host-based authentication (see .Xr ssh 1 ) . @@ -954,6 +960,7 @@ The content of this file is not sensitive; it can be world-readable. .Xr ssh-keygen 1 , .Xr ssh-keyscan 1 , .Xr chroot 2 , +.Xr hosts_access 5 , .Xr login.conf 5 , .Xr moduli 5 , .Xr sshd_config 5 , --- sshd-session.c.orig 2024-07-01 13:26:10.677919000 -0700 +++ sshd-session.c 2024-07-01 13:26:58.873906000 -0700 @@ -110,6 +110,13 @@ #include "srclimit.h" #include "dh.h" +#ifdef LIBWRAP +#include +#include +int allow_severity; +int deny_severity; +#endif /* LIBWRAP */ + /* Re-exec fds */ #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) @@ -1256,7 +1263,26 @@ main(int ac, char **av) #endif rdomain = ssh_packet_rdomain_in(ssh); + +#ifdef LIBWRAP + allow_severity = options.log_facility|LOG_INFO; + deny_severity = options.log_facility|LOG_WARNING; + /* Check whether logins are denied from this host. */ + if (ssh_packet_connection_is_on_socket(ssh)) { + struct request_info req; + request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); + fromhost(&req); + + if (!hosts_access(&req)) { + debug("Connection refused by tcp wrapper"); + refuse(&req); + /* NOTREACHED */ + fatal("libwrap refuse returns"); + } + } +#endif /* LIBWRAP */ + /* Log the connection. */ laddr = get_local_ipaddr(sock_in); verbose("Connection from %s port %d on %s port %d%s%s%s", --- configure.ac.orig 2022-02-23 03:31:11.000000000 -0800 +++ configure.ac 2022-03-02 12:47:49.958341000 -0800 @@ -1599,6 +1599,62 @@ else AC_MSG_RESULT([no]) fi +# Check whether user wants TCP wrappers support +TCPW_MSG="no" +AC_ARG_WITH([tcp-wrappers], + [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], + [ + if test "x$withval" != "xno" ; then + saved_LIBS="$LIBS" + saved_LDFLAGS="$LDFLAGS" + saved_CPPFLAGS="$CPPFLAGS" + if test -n "${withval}" && \ + test "x${withval}" != "xyes"; then + if test -d "${withval}/lib"; then + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + fi + else + if test -n "${need_dash_r}"; then + LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + fi + if test -d "${withval}/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + fi + LIBS="-lwrap $LIBS" + AC_MSG_CHECKING([for libwrap]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include +#include +#include +int deny_severity = 0, allow_severity = 0; + ]], [[ + hosts_access(0); + ]])], [ + AC_MSG_RESULT([yes]) + AC_DEFINE([LIBWRAP], [1], + [Define if you want + TCP Wrappers support]) + SSHDLIBS="$SSHDLIBS -lwrap" + TCPW_MSG="yes" + ], [ + AC_MSG_ERROR([*** libwrap missing]) + + ]) + LIBS="$saved_LIBS" + fi + ] +) + # Check whether user wants to use ldns LDNS_MSG="no" AC_ARG_WITH(ldns, @@ -5593,6 +5649,7 @@ echo " PAM support: $PAM_MSG" echo " OSF SIA support: $SIA_MSG" echo " KerberosV support: $KRB5_MSG" echo " SELinux support: $SELINUX_MSG" +echo " TCP Wrappers support: $TCPW_MSG" echo " libedit support: $LIBEDIT_MSG" echo " libldns support: $LDNS_MSG" echo " Solaris process contract support: $SPC_MSG" +--- sshd.c.orig 2024-06-30 21:36:28.000000000 -0700 ++++ sshd.c 2024-07-01 13:44:05.739756000 -0700 +@@ -90,6 +100,10 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#ifdef LIBWRAP ++#include ++#include ++#endif /* LIBWRAP */ + + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) +@@ -925,7 +939,12 @@ server_accept_loop(int *sock_in, int *sock_out, int *n + socklen_t fromlen; + u_char rnd[256]; + sigset_t nsigset, osigset; ++#ifdef LIBWRAP ++ struct request_info req; + ++ request_init(&req, RQ_DAEMON, __progname, 0); ++#endif ++ + /* pipes connected to unauthenticated child sshd processes */ + child_alloc(); + startup_pollfd = xcalloc(options.max_startups, sizeof(int)); +@@ -1133,6 +1152,42 @@ server_accept_loop(int *sock_in, int *sock_out, int *n + usleep(100 * 1000); + continue; + } ++#ifdef LIBWRAP ++ /* Check whether logins are denied from this host. */ ++ request_set(&req, RQ_FILE, *newsock, ++ RQ_CLIENT_NAME, "", RQ_CLIENT_ADDR, "", 0); ++ sock_host(&req); ++ if (!hosts_access(&req)) { ++ const struct linger l = { .l_onoff = 1, ++ .l_linger = 0 }; ++ ++ (void )setsockopt(*newsock, SOL_SOCKET, ++ SO_LINGER, &l, sizeof(l)); ++ (void )close(*newsock); ++ /* ++ * Mimic message from libwrap's refuse() as ++ * precisely as we can afford. The authentic ++ * message prints the IP address and the ++ * hostname it resolves to in parentheses. If ++ * the IP address cannot be resolved to a ++ * hostname, the IP address will be repeated ++ * in parentheses. As name resolution in the ++ * main server loop could stall, and logging ++ * resolved names adds little or no value to ++ * incident investigation, this implementation ++ * only repeats the IP address in parentheses. ++ * This should resemble librwap's refuse() ++ * closely enough not to break auditing ++ * software like sshguard or custom scripts. ++ */ ++ syslog(LOG_WARNING, ++ "refused connect from %s (%s)", ++ eval_hostaddr(req.client), ++ eval_hostaddr(req.client)); ++ debug("Connection refused by tcp wrapper"); ++ continue; ++ } ++#endif /* LIBWRAP */ + if (unset_nonblock(*newsock) == -1) { + close(*newsock); + continue; diff --git a/security/openssh-portable/files/patch-regress__test-exec.sh b/security/openssh-portable/files/patch-regress__test-exec.sh index 0213e8cd5415..1f20e3ff8d27 100644 --- a/security/openssh-portable/files/patch-regress__test-exec.sh +++ b/security/openssh-portable/files/patch-regress__test-exec.sh @@ -1,10 +1,10 @@ --- regress/test-exec.sh.orig 2015-04-03 18:20:32.256126000 UTC +++ regress/test-exec.sh 2015-04-03 18:20:41.599903000 -0500 -@@ -408,6 +408,7 @@ cat << EOF > $OBJ/sshd_config +@@ -618,6 +618,7 @@ cat << EOF > $OBJ/sshd_config LogLevel DEBUG3 AcceptEnv _XXX_TEST_* AcceptEnv _XXX_TEST + PermitRootLogin yes Subsystem sftp $SFTPSERVER - EOF - + SshdSessionPath $SSHD_SESSION + SshdAuthPath $SSHD_AUTH diff --git a/security/openssh-portable/files/patch-session.c b/security/openssh-portable/files/patch-session.c index b0b9e08008f8..da35125897b5 100644 --- a/security/openssh-portable/files/patch-session.c +++ b/security/openssh-portable/files/patch-session.c @@ -1,78 +1,109 @@ bdrewery: - Refactor and simplify original commit. - Stop setting TERM=su without a term. ------------------------------------------------------------------------ r99055 | des | 2002-06-29 04:21:58 -0700 (Sat, 29 Jun 2002) | 6 lines Changed paths: M /head/crypto/openssh/session.c Make sure the environment variables set by setusercontext() are passed on to the child process. Reviewed by: ache Sponsored by: DARPA, NAI Labs --- session.c.orig 2021-04-15 20:55:25.000000000 -0700 +++ session.c 2021-04-27 13:11:13.515917000 -0700 -@@ -942,7 +942,7 @@ read_etc_default_login(char ***env, u_int *envsize, ui - } - #endif /* HAVE_ETC_DEFAULT_LOGIN */ +@@ -939,6 +939,9 @@ do_setup_env(struct ssh *ssh, Session *s, const char * + struct passwd *pw = s->pw; + #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) + char *path = NULL; ++#else ++ extern char **environ; ++ char **senv, **var, *val; + #endif --#if defined(USE_PAM) || defined(HAVE_CYGWIN) -+#if defined(USE_PAM) || defined(HAVE_CYGWIN) || defined(HAVE_LOGIN_CAP) - static void - copy_environment_denylist(char **source, char ***env, u_int *envsize, - const char *denylist) -@@ -1052,7 +1052,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char * + /* Initialize the environment. */ +@@ -960,6 +963,9 @@ do_setup_env(struct ssh *ssh, Session *s, const char * + } + #endif + ++ if (getenv("TZ")) ++ child_set_env(&env, &envsize, "TZ", getenv("TZ")); ++ + #ifdef GSSAPI + /* Allow any GSSAPI methods that we've used to alter + * the child's environment as they see fit +@@ -977,11 +983,30 @@ do_setup_env(struct ssh *ssh, Session *s, const char * + child_set_env(&env, &envsize, "LOGIN", pw->pw_name); + #endif + child_set_env(&env, &envsize, "HOME", pw->pw_dir); ++ snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); ++ child_set_env(&env, &envsize, "MAIL", buf); + #ifdef HAVE_LOGIN_CAP +- if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) +- child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); +- else +- child_set_env(&env, &envsize, "PATH", getenv("PATH")); ++ child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); ++ child_set_env(&env, &envsize, "TERM", "su"); ++ /* ++ * Temporarily swap out our real environment with an empty one, ++ * let setusercontext() apply any environment variables defined ++ * for the user's login class, copy those variables to the child, ++ * free the temporary environment, and restore the original. ++ */ ++ senv = environ; ++ environ = xmalloc(sizeof(*environ)); ++ *environ = NULL; ++ (void)setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV|LOGIN_SETPATH); ++ for (var = environ; *var != NULL; ++var) { ++ if ((val = strchr(*var, '=')) != NULL) { ++ *val++ = '\0'; ++ child_set_env(&env, &envsize, *var, val); ++ } ++ free(*var); ++ } ++ free(environ); ++ environ = senv; + #else /* HAVE_LOGIN_CAP */ + # ifndef HAVE_CYGWIN + /* +@@ -1001,17 +1026,9 @@ do_setup_env(struct ssh *ssh, Session *s, const char * # endif /* HAVE_CYGWIN */ #endif /* HAVE_LOGIN_CAP */ - if (!options.use_pam) { -+ /* FreeBSD PAM doesn't set default "MAIL" */ -+ if (1 || !options.use_pam) { - snprintf(buf, sizeof buf, "%.200s/%.50s", - _PATH_MAILDIR, pw->pw_name); - child_set_env(&env, &envsize, "MAIL", buf); -@@ -1063,6 +1064,23 @@ do_setup_env(struct ssh *ssh, Session *s, const char * +- snprintf(buf, sizeof buf, "%.200s/%.50s", +- _PATH_MAILDIR, pw->pw_name); +- child_set_env(&env, &envsize, "MAIL", buf); +- } +- + /* Normal systems set SHELL by default. */ + child_set_env(&env, &envsize, "SHELL", shell); - if (getenv("TZ")) - child_set_env(&env, &envsize, "TZ", getenv("TZ")); -+#ifdef HAVE_LOGIN_CAP -+ /* Load environment from /etc/login.conf setenv directives. */ -+ { -+ extern char **environ; -+ char **senv, **var; -+ -+ senv = environ; -+ environ = xmalloc(sizeof(char *)); -+ *environ = NULL; -+ (void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETENV); -+ copy_environment_denylist(environ, &env, &envsize, NULL); -+ for (var = environ; *var != NULL; ++var) -+ free(*var); -+ free(environ); -+ environ = senv; -+ } -+#endif +- if (getenv("TZ")) +- child_set_env(&env, &envsize, "TZ", getenv("TZ")); if (s->term) child_set_env(&env, &envsize, "TERM", s->term); if (s->display) -@@ -1281,7 +1299,7 @@ do_nologin(struct passwd *pw) +@@ -1225,7 +1242,8 @@ do_nologin(struct passwd *pw) + do_nologin(struct passwd *pw) + { + FILE *f = NULL; +- char buf[1024], *nl, *def_nl = _PATH_NOLOGIN; ++ const char *nl; ++ char buf[1024], *def_nl = _PATH_NOLOGIN; + struct stat sb; + #ifdef HAVE_LOGIN_CAP - if (login_getcapbool(lc, "ignorenologin", 0) || pw->pw_uid == 0) - return; -- nl = login_getcapstr(lc, "nologin", def_nl, def_nl); -+ nl = (char*)login_getcapstr(lc, "nologin", def_nl, def_nl); - #else - if (pw->pw_uid == 0) - return; -@@ -1365,7 +1383,7 @@ do_setusercontext(struct passwd *pw) +@@ -1315,7 +1333,7 @@ do_setusercontext(struct passwd *pw) if (platform_privileged_uidswap()) { #ifdef HAVE_LOGIN_CAP if (setusercontext(lc, pw, pw->pw_uid, - (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { + (LOGIN_SETALL & ~(LOGIN_SETENV|LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { perror("unable to set user context"); exit(1); } diff --git a/security/openssh-portable/files/patch-ssh-agent.c b/security/openssh-portable/files/patch-ssh-agent.c index b17027d0e340..6f049a8847e5 100644 --- a/security/openssh-portable/files/patch-ssh-agent.c +++ b/security/openssh-portable/files/patch-ssh-agent.c @@ -1,97 +1,97 @@ --- UTC r110506 | des | 2003-02-07 09:48:27 -0600 (Fri, 07 Feb 2003) | 4 lines Set the ruid to the euid at startup as a workaround for a bug in pam_ssh. r226103 | des | 2011-10-07 08:10:16 -0500 (Fri, 07 Oct 2011) | 5 lines Add a -x option that causes ssh-agent(1) to exit when all clients have disconnected. --- ssh-agent.c.orig 2025-10-05 19:25:16.000000000 -0700 +++ ssh-agent.c 2025-10-06 08:33:47.247562000 -0700 @@ -193,11 +193,28 @@ static char *websafe_allowlist; static int restrict_websafe = 1; static char *websafe_allowlist; +/* + * Client connection count; incremented in new_socket() and decremented in + * close_socket(). When it reaches 0, ssh-agent will exit. Since it is + * normally initialized to 1, it will never reach 0. However, if the -x + * option is specified, it is initialized to 0 in main(); in that case, + * ssh-agent will exit as soon as it has had at least one client but no + * longer has any. + */ +static int xcount = 1; + static void close_socket(SocketEntry *e) { size_t i; + int last = 0; + if (e->type == AUTH_CONNECTION) { + debug("xcount %d -> %d", xcount, xcount - 1); + if (--xcount == 0) + last = 1; + } + close(e->fd); sshbuf_free(e->input); sshbuf_free(e->output); @@ -210,6 +227,8 @@ close_socket(SocketEntry *e) memset(e, '\0', sizeof(*e)); e->fd = -1; e->type = AUTH_UNUSED; + if (last) + cleanup_exit(0); } static void @@ -1887,6 +1906,10 @@ new_socket(sock_type type, int fd) debug_f("type = %s", type == AUTH_CONNECTION ? "CONNECTION" : (type == AUTH_SOCKET ? "SOCKET" : "UNKNOWN")); + if (type == AUTH_CONNECTION) { + debug("xcount %d -> %d", xcount, xcount + 1); + ++xcount; + } set_nonblock(fd); if (fd > max_fd) @@ -2177,7 +2200,7 @@ usage(void) usage(void) { fprintf(stderr, - "usage: ssh-agent [-c | -s] [-DdTU] [-a bind_address] [-E fingerprint_hash]\n" + "usage: ssh-agent [-c | -s] [-DdTUx] [-a bind_address] [-E fingerprint_hash]\n" " [-O option] [-P allowed_providers] [-t life]\n" " ssh-agent [-TU] [-a bind_address] [-E fingerprint_hash] [-O option]\n" " [-P allowed_providers] [-t life] command [arg ...]\n" @@ -2218,6 +2241,7 @@ main(int ac, char **av) /* drop */ (void)setegid(getgid()); (void)setgid(getgid()); + (void)setuid(geteuid()); platform_disable_tracing(0); /* strict=no */ @@ -2229,7 +2253,7 @@ main(int ac, char **av) __progname = ssh_get_progname(av[0]); seed_rng(); - while ((ch = getopt(ac, av, "cDdksTuUE:a:O:P:t:")) != -1) { + while ((ch = getopt(ac, av, "cDdksTuUE:a:O:P:t:x")) != -1) { switch (ch) { case 'E': fingerprint_hash = ssh_digest_alg_by_name(optarg); -@@ -2286,6 +2310,9 @@ main(int ac, char **av) +@@ -2285,6 +2309,9 @@ main(int ac, char **av) + fprintf(stderr, "Invalid lifetime\n"); usage(); } - break; ++ break; + case 'x': + xcount = 0; -+ break; + break; case 'T': T_flag++; - break; diff --git a/security/openssh-portable/files/patch-ssh.c b/security/openssh-portable/files/patch-ssh.c index c49535dcf868..09da82981369 100644 --- a/security/openssh-portable/files/patch-ssh.c +++ b/security/openssh-portable/files/patch-ssh.c @@ -1,33 +1,33 @@ --- UTC r99054 | des | 2002-06-29 05:57:53 -0500 (Sat, 29 Jun 2002) | 4 lines Changed paths: M /head/crypto/openssh/ssh.c Canonicize the host name before looking it up in the host file. --- ssh.c.orig 2018-04-02 05:38:28 UTC +++ ssh.c -@@ -1281,6 +1281,23 @@ main(int ac, char **av) - ssh_digest_free(md); - conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); +@@ -1289,6 +1289,23 @@ main(int ac, char **av) + check_follow_cname(direct, &host, cname); + } + /* Find canonic host name. */ + if (strchr(host, '.') == 0) { + struct addrinfo hints; + struct addrinfo *ai = NULL; + int errgai; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = options.address_family; + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + errgai = getaddrinfo(host, NULL, &hints, &ai); + if (errgai == 0) { + if (ai->ai_canonname != NULL) + host = xstrdup(ai->ai_canonname); + freeaddrinfo(ai); + } + } + /* - * Expand tokens in arguments. NB. LocalCommand is expanded later, - * after port-forwarding is set up, so it may pick up any local + * If canonicalisation is enabled then re-parse the configuration + * files as new stanzas may match. diff --git a/security/openssh-portable/files/patch-ssh_config.5 b/security/openssh-portable/files/patch-ssh_config.5 deleted file mode 100644 index 8c0e2bf1d5be..000000000000 --- a/security/openssh-portable/files/patch-ssh_config.5 +++ /dev/null @@ -1,13 +0,0 @@ ---- UTC - ---- ssh_config.5.orig 2020-11-16 11:53:55.871161000 -0800 -+++ ssh_config.5 2020-11-16 12:43:41.763006000 -0800 -@@ -434,6 +433,8 @@ in the process, regardless of the setting of - If the option is set to - .Cm no , - the check will not be executed. -+The default is -+.Cm no . - .It Cm Ciphers - Specifies the ciphers allowed and their order of preference. - Multiple ciphers must be comma-separated. diff --git a/security/openssh-portable/files/patch-sshd.8 b/security/openssh-portable/files/patch-sshd.8 index 4d2a477899c6..eff25147d9dd 100644 --- a/security/openssh-portable/files/patch-sshd.8 +++ b/security/openssh-portable/files/patch-sshd.8 @@ -1,26 +1,26 @@ --- UTC Document FreeBSD/port-specific paths --- sshd.8.orig 2010-08-04 21:03:13.000000000 -0600 +++ sshd.8 2010-09-14 16:14:14.000000000 -0600 -@@ -70,7 +70,7 @@ +@@ -64,7 +64,7 @@ .Nm listens for connections from clients. It is normally started at boot from -.Pa /etc/rc . +.Pa /usr/local/etc/rc.d/openssh . It forks a new daemon for each incoming connection. The forked daemons handle -@@ -384,8 +384,9 @@ +@@ -355,8 +355,9 @@ If the login is on a tty, records login time. .It Checks -.Pa /etc/nologin ; -if it exists, prints contents and quits +.Pa /etc/nologin and +.Pa /var/run/nologin ; +if one exists, it prints the contents and quits (unless root). .It Changes to run with normal user privileges. diff --git a/security/openssh-portable/files/patch-sshd.c b/security/openssh-portable/files/patch-sshd.c index 6d522d520e90..f91c0da69b9f 100644 --- a/security/openssh-portable/files/patch-sshd.c +++ b/security/openssh-portable/files/patch-sshd.c @@ -1,101 +1,101 @@ --- UTC r109683 | des | 2003-01-22 08:12:59 -0600 (Wed, 22 Jan 2003) | 7 lines Changed paths: M /head/crypto/openssh/sshd.c Force early initialization of the resolver library, since the resolver configuration files will no longer be available once sshd is chrooted. PR: 39953, 40894 Submitted by: dinoex r199804 | attilio | 2009-11-25 09:12:24 -0600 (Wed, 25 Nov 2009) | 13 lines Changed paths: M /head/crypto/openssh/sshd.c M /head/usr.sbin/cron/cron/cron.c M /head/usr.sbin/inetd/inetd.c M /head/usr.sbin/syslogd/syslogd.c Avoid sshd, cron, syslogd and inetd to be killed under high-pressure swap environments. Please note that this can't be done while such processes run in jails. Note: in future it would be interesting to find a way to do that selectively for any desired proccess (choosen by user himself), probabilly via a ptrace interface or whatever. r206397 | kib | 2010-04-08 07:07:40 -0500 (Thu, 08 Apr 2010) | 8 lines Changed paths: M /head/crypto/openssh/sshd.c Enhance r199804 by marking the daemonised child as immune to OOM instead of short-living parent. Only mark the master process that accepts connections, do not protect connection handlers spawned from inetd. --- sshd.c.orig 2024-06-30 21:36:28.000000000 -0700 +++ sshd.c 2024-07-01 13:44:05.739756000 -0700 @@ -28,6 +28,7 @@ #include #include +#include #include - #ifdef HAVE_SYS_STAT_H - # include -@@ -69,6 +70,13 @@ + #include + #include +@@ -63,6 +64,15 @@ #include #endif +#ifdef __FreeBSD__ +#include -+#ifdef GSSAPI -+#include "ssh-gss.h" ++#if defined(GSSAPI) && defined(HAVE_GSSAPI_GSSAPI_H) ++#include ++#elif defined(GSSAPI) && defined(HAVE_GSSAPI_H) ++#include +#endif +#endif + #include "xmalloc.h" #include "ssh.h" #include "sshpty.h" -@@ -1671,7 +1679,30 @@ main(int ac, char **av) - for (i = 0; i < options.num_log_verbose; i++) - log_verbose_add(options.log_verbose[i]); +@@ -1825,6 +1880,10 @@ main(int ac, char **av) + /* Reinitialize the log (because of the fork above). */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); -+#ifdef __FreeBSD__ ++ /* Avoid killing the process in high-pressure swapping environments. */ ++ if (!inetd_flag && madvise(NULL, 0, MADV_PROTECT) != 0) ++ debug("madvise(): %.200s", strerror(errno)); ++ /* + * Chdir to the root directory so that the current disk can be + * unmounted if desired. +@@ -1910,6 +1969,28 @@ main(int ac, char **av) + execv(rexec_argv[0], rexec_argv); + + fatal("rexec of %s failed: %s", rexec_argv[0], strerror(errno)); ++#ifdef __FreeBSD__ ++ /* + * Initialize the resolver. This may not happen automatically + * before privsep chroot(). + */ + if ((_res.options & RES_INIT) == 0) { + debug("res_init()"); + res_init(); + } +#ifdef GSSAPI + /* + * Force GSS-API to parse its configuration and load any + * mechanism plugins. + */ + { + gss_OID_set mechs; + OM_uint32 minor_status; + gss_indicate_mechs(&minor_status, &mechs); + gss_release_oid_set(&minor_status, &mechs); + } +#endif +#endif -+ -+ /* - * If not in debugging mode, not started from inetd and not already - * daemonized (eg re-exec via SIGHUP), disconnect from the controlling - * terminal, and fork. The original process exits. -@@ -1687,6 +1718,10 @@ main(int ac, char **av) - /* Reinitialize the log (because of the fork above). */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); + } -+ /* Avoid killing the process in high-pressure swapping environments. */ -+ if (!inetd_flag && madvise(NULL, 0, MADV_PROTECT) != 0) -+ debug("madvise(): %.200s", strerror(errno)); -+ - /* - * Chdir to the root directory so that the current disk can be - * unmounted if desired. + /* server specific fatal cleanup */ diff --git a/security/openssh-portable/files/patch-uidswap.c b/security/openssh-portable/files/patch-uidswap.c index b906d1d67480..daf522c58993 100644 --- a/security/openssh-portable/files/patch-uidswap.c +++ b/security/openssh-portable/files/patch-uidswap.c @@ -1,57 +1,57 @@ commit 239e8c98636a7578cc67a6f9d54d14c71b095e36 Author: Kyle Evans Date: Sat Aug 9 11:01:57 2025 -0500 ssh: sshd-session: properly save off the privileged gid Current and traditional FreeBSD behavior means that getegid() here is the first element in the prior setgroups() call, if any, so we may inadvertently wipe out our rgid with the unprivileged gid. This is rendered somewhat harmless by the fact that we're losing the privileged gid -- we'll still regain it as the egid in restore_uid() later by way of restoring saved_egroups, rather than by intentionally restoring it from getgid(). This will be promptly reverted if we can get setgroups(2)/getgroups(2) changed in FreeBSD 15.0, but it seemed wise to get this technically correct for previous branches. Reviewed by: jlduran Differential Revision: https://reviews.freebsd.org/D51753 diff --git uidswap.c uidswap.c index 6ed3024d0180..0143f4994611 100644 --- uidswap.c +++ uidswap.c @@ -14,6 +14,10 @@ #include "includes.h" +#ifdef __FreeBSD__ +#include +#include +#endif #include #include #include -@@ -121,8 +124,20 @@ temporarily_use_uid(struct passwd *pw) +@@ -121,8 +125,20 @@ temporarily_use_uid(struct passwd *pw) fatal("setgroups: %.100s", strerror(errno)); #ifndef SAVED_IDS_WORK_WITH_SETEUID /* Propagate the privileged gid to all of our gids. */ +#if defined(__FreeBSD__) && __FreeBSD_version < 1500061 + /* + * FreeBSD traditionally includes the egid as the first element. If we + * use getegid() here then we effectively propagate user_groups[0], + * which is probably pw->pw_gid. Fix it to work as intended by using + * the egid we already have stashed off. + */ + assert(saved_egroupslen > 0); + if (setgid(saved_egroups[0]) == -1) + debug("setgid %u: %.100s", (u_int) saved_egroups[0], strerror(errno)); +#else if (setgid(getegid()) == -1) debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno)); +#endif /* Propagate the privileged uid to all of our uids. */ if (setuid(geteuid()) == -1) debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno));