From 568625900ef5c607a2c2596472fbc9f62ec571fe Mon Sep 17 00:00:00 2001 From: Mattias Ellert Date: Oct 24 2021 08:28:51 +0000 Subject: Based on openssh-8.7p1-2.fc35 --- diff --git a/gsi-openssh.spec b/gsi-openssh.spec index 0d61b1f..5d75771 100644 --- a/gsi-openssh.spec +++ b/gsi-openssh.spec @@ -27,13 +27,13 @@ # Do we want libedit support %global libedit 1 -%global openssh_ver 8.6p1 -%global openssh_rel 3 +%global openssh_ver 8.7p1 +%global openssh_rel 1 Summary: An implementation of the SSH protocol with GSI authentication Name: gsi-openssh Version: %{openssh_ver} -Release: %{openssh_rel}%{?dist}.2 +Release: %{openssh_rel}%{?dist} Provides: gsissh = %{version}-%{release} Obsoletes: gsissh < 5.8p2-2 URL: http://www.openssh.com/portable.html @@ -146,24 +146,22 @@ Patch965: openssh-8.2p1-visibility.patch # Do not break X11 without IPv6 Patch966: openssh-8.2p1-x11-without-ipv6.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=3213 -Patch969: openssh-8.4p1-debian-compat.patch -# ssh-keygen printing fingerprint issue with Windows keys (#1901518) Patch974: openssh-8.0p1-keygen-strip-doseol.patch # sshd provides PAM an incorrect error code (#1879503) Patch975: openssh-8.0p1-preserve-pam-errors.patch -# ssh incorrectly restores the blocking mode on standard output (#1942901) -Patch976: openssh-8.0p1-restore-nonblock.patch +# CVE-2021-41617 +Patch978: openssh-8.7p1-upstream-cve-2021-41617.patch # Fix issue with read-only ssh buffer during gssapi key exchange (#1938224) # https://github.com/openssh-gsskex/openssh-gsskex/pull/19 Patch97: openssh-8.0p1-sshbuf-readonly.patch # This is the patch that adds GSI support # Based on hpn_isshd-gsi.7.5p1b.patch from Globus upstream -Patch98: openssh-8.6p1-gsissh.patch +Patch98: openssh-8.7p1-gsissh.patch # This is the HPN patch # Based on https://sourceforge.net/projects/hpnssh/files/Patches/HPN-SSH%2015v2%208.5p1/ -Patch99: openssh-8.6p1-hpn-15.2-modified.patch +Patch99: openssh-8.7p1-hpn-15.2-modified.patch License: BSD Requires: /sbin/nologin @@ -299,10 +297,9 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} %patch964 -p1 -b .openssl-kdf %patch965 -p1 -b .visibility %patch966 -p1 -b .x11-ipv6 -%patch969 -p0 -b .debian %patch974 -p1 -b .keygen-strip-doseol %patch975 -p1 -b .preserve-pam-errors -%patch976 -p1 -b .restore-nonblock +%patch978 -p1 -b .cve-2021-41617 %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race @@ -500,6 +497,9 @@ getent passwd sshd >/dev/null || \ %attr(0644,root,root) %{_unitdir}/gsisshd-keygen.target %changelog +* Sun Oct 24 2021 Mattias Ellert - 8.7p1-1 +- Based on openssh-8.7p1-2.fc35 + * Tue Sep 14 2021 Sahana Prasad - 8.6p1-3.2 - Rebuilt with OpenSSL 3.0.0 diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/openssh-6.6p1-GSSAPIEnablek5users.patch index 6ee2535..cccb3e0 100644 --- a/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -28,7 +28,7 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c + options->enable_k5users = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; + options->permit_empty_passwd = -1; @@ -345,6 +346,8 @@ fill_default_server_options(ServerOption #endif if (options->use_kuserok == -1) @@ -72,9 +72,9 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c + intptr = &options->enable_k5users; + goto parse_flag; + - case sPermitListen: - case sPermitOpen: - if (opcode == sPermitListen) { + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " @@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); diff --git a/openssh-6.6p1-kuserok.patch b/openssh-6.6p1-kuserok.patch index 407ff4c..1831f27 100644 --- a/openssh-6.6p1-kuserok.patch +++ b/openssh-6.6p1-kuserok.patch @@ -182,7 +182,7 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c + options->use_kuserok = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; + options->permit_empty_passwd = -1; @@ -278,6 +279,8 @@ fill_default_server_options(ServerOption if (options->gss_kex_algorithms == NULL) options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); @@ -193,9 +193,9 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) @@ -399,7 +402,7 @@ typedef enum { - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sRhostsRSAAuthentication, sRSAAuthentication, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, + sPort, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, - sKerberosGetAFSToken, sKerberosUniqueCCache, + sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sChallengeResponseAuthentication, @@ -217,16 +217,16 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, @@ -1644,6 +1649,10 @@ process_server_config_line(ServerOptions - *inc_flags &= ~SSHCFG_MATCH_ONLY; - break; - + } + break; + + case sKerberosUseKuserok: + intptr = &options->use_kuserok; + goto parse_flag; + - case sPermitListen: - case sPermitOpen: - if (opcode == sPermitListen) { + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " @@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(client_alive_interval); M_CP_INTOPT(ip_qos_interactive); diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch index 2814c6f..930de69 100644 --- a/openssh-6.7p1-coverity.patch +++ b/openssh-6.7p1-coverity.patch @@ -54,18 +54,6 @@ diff -up openssh-8.5p1/auth-krb5.c.coverity openssh-8.5p1/auth-krb5.c diff -up openssh-8.5p1/auth-options.c.coverity openssh-8.5p1/auth-options.c --- openssh-8.5p1/auth-options.c.coverity 2021-03-02 11:31:47.000000000 +0100 +++ openssh-8.5p1/auth-options.c 2021-03-24 12:03:33.782968159 +0100 -@@ -409,8 +409,10 @@ sshauthopt_parse(const char *opts, const - errstr = "invalid environment string"; - goto fail; - } -- if ((cp = strdup(opt)) == NULL) -+ if ((cp = strdup(opt)) == NULL) { -+ free(opt); - goto alloc_fail; -+ } - cp[tmp - opt] = '\0'; /* truncate at '=' */ - if (!valid_env_name(cp)) { - free(cp); @@ -706,6 +708,7 @@ serialise_array(struct sshbuf *m, char * return r; } @@ -133,13 +121,13 @@ diff -up openssh-8.5p1/dns.c.coverity openssh-8.5p1/dns.c --- openssh-8.5p1/dns.c.coverity 2021-03-02 11:31:47.000000000 +0100 +++ openssh-8.5p1/dns.c 2021-03-24 12:03:33.783968166 +0100 @@ -282,6 +282,7 @@ verify_host_key_dns(const char *hostname - &hostkey_digest_len, hostkey)) { - error("Error calculating key fingerprint."); - freerrset(fingerprints); + &hostkey_digest, &hostkey_digest_len, hostkey)) { + error("Error calculating key fingerprint."); + freerrset(fingerprints); + free(dnskey_digest); - return -1; - } - } + return -1; + } + diff -up openssh-8.5p1/gss-genr.c.coverity openssh-8.5p1/gss-genr.c --- openssh-8.5p1/gss-genr.c.coverity 2021-03-26 11:52:46.613942552 +0100 +++ openssh-8.5p1/gss-genr.c 2021-03-26 11:54:37.881726318 +0100 @@ -316,6 +304,36 @@ diff -up openssh-7.4p1/openbsd-compat/bindresvport.c.coverity openssh-7.4p1/open int i; if (sa == NULL) { +diff -up openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity openssh-8.7p1/openbsd-compat/bsd-pselect.c +--- openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity 2021-08-30 16:36:11.357288009 +0200 ++++ openssh-8.7p1/openbsd-compat/bsd-pselect.c 2021-08-30 16:37:21.791897976 +0200 +@@ -113,13 +113,13 @@ pselect_notify_setup(void) + static void + pselect_notify_parent(void) + { +- if (notify_pipe[1] != -1) ++ if (notify_pipe[1] >= 0) + (void)write(notify_pipe[1], "", 1); + } + static void + pselect_notify_prepare(fd_set *readset) + { +- if (notify_pipe[0] != -1) ++ if (notify_pipe[0] >= 0) + FD_SET(notify_pipe[0], readset); + } + static void +@@ -127,8 +127,8 @@ pselect_notify_done(fd_set *readset) + { + char c; + +- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) { +- while (read(notify_pipe[0], &c, 1) != -1) ++ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) { ++ while (read(notify_pipe[0], &c, 1) >= 0) + debug2_f("reading"); + FD_CLR(notify_pipe[0], readset); + } diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c --- openssh-8.5p1/readconf.c.coverity 2021-03-24 12:03:33.778968131 +0100 +++ openssh-8.5p1/readconf.c 2021-03-24 12:03:33.785968180 +0100 @@ -324,33 +342,29 @@ diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c error("%.200s line %d: glob failed for %s.", filename, linenum, arg2); + free(arg2); - return -1; + goto out; } free(arg2); -diff -up openssh-7.4p1/scp.c.coverity openssh-7.4p1/scp.c ---- openssh-7.4p1/scp.c.coverity 2016-12-23 16:40:26.856788681 +0100 -+++ openssh-7.4p1/scp.c 2016-12-23 16:40:26.901788691 +0100 -@@ -157,7 +157,7 @@ killchild(int signo) +diff -up openssh-8.7p1/scp.c.coverity openssh-8.7p1/scp.c +--- openssh-8.7p1/scp.c.coverity 2021-08-30 16:23:35.389741329 +0200 ++++ openssh-8.7p1/scp.c 2021-08-30 16:27:04.854555296 +0200 +@@ -186,11 +186,11 @@ killchild(int signo) { if (do_cmd_pid > 1) { kill(do_cmd_pid, signo ? signo : SIGTERM); - waitpid(do_cmd_pid, NULL, 0); + (void) waitpid(do_cmd_pid, NULL, 0); } + if (do_cmd_pid2 > 1) { + kill(do_cmd_pid2, signo ? signo : SIGTERM); +- waitpid(do_cmd_pid2, NULL, 0); ++ (void) waitpid(do_cmd_pid2, NULL, 0); + } if (signo) diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c --- openssh-7.4p1/servconf.c.coverity 2016-12-23 16:40:26.896788690 +0100 +++ openssh-7.4p1/servconf.c 2016-12-23 16:40:26.901788691 +0100 -@@ -1547,7 +1547,7 @@ process_server_config_line(ServerOptions - fatal("%s line %d: Missing subsystem name.", - filename, linenum); - if (!*activep) { -- arg = strdelim(&cp); -+ /*arg =*/ (void) strdelim(&cp); - break; - } - for (i = 0; i < options->num_subsystems; i++) @@ -1638,8 +1638,9 @@ process_server_config_line(ServerOptions if (*activep && *charptr == NULL) { *charptr = tilde_expand_filename(arg, getuid()); @@ -363,37 +377,10 @@ diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c } break; -diff -up openssh-7.4p1/serverloop.c.coverity openssh-7.4p1/serverloop.c ---- openssh-7.4p1/serverloop.c.coverity 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/serverloop.c 2016-12-23 16:40:26.902788691 +0100 -@@ -125,13 +125,13 @@ notify_setup(void) - static void - notify_parent(void) - { -- if (notify_pipe[1] != -1) -+ if (notify_pipe[1] >= 0) - (void)write(notify_pipe[1], "", 1); - } - static void - notify_prepare(fd_set *readset) - { -- if (notify_pipe[0] != -1) -+ if (notify_pipe[0] >= 0) - FD_SET(notify_pipe[0], readset); - } - static void -@@ -139,8 +139,8 @@ notify_done(fd_set *readset) - { - char c; - -- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) -- while (read(notify_pipe[0], &c, 1) != -1) -+ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) -+ while (read(notify_pipe[0], &c, 1) >= 0) - debug2_f("reading"); - } - -@@ -518,7 +518,7 @@ server_request_tun(void) +diff -up openssh-8.7p1/serverloop.c.coverity openssh-8.7p1/serverloop.c +--- openssh-8.7p1/serverloop.c.coverity 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/serverloop.c 2021-08-30 16:28:22.416226981 +0200 +@@ -547,7 +547,7 @@ server_request_tun(struct ssh *ssh) debug_f("invalid tun"); goto done; } diff --git a/openssh-7.6p1-audit.patch b/openssh-7.6p1-audit.patch index f3b1334..4473518 100644 --- a/openssh-7.6p1-audit.patch +++ b/openssh-7.6p1-audit.patch @@ -807,15 +807,6 @@ diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c --- openssh-8.6p1/auth.c.audit 2021-04-19 16:47:35.681061553 +0200 +++ openssh-8.6p1/auth.c 2021-04-19 16:47:35.754062114 +0200 -@@ -367,7 +367,7 @@ auth_log(struct ssh *ssh, int authentica - # endif - #endif - #ifdef SSH_AUDIT_EVENTS -- if (authenticated == 0 && !authctxt->postponed) -+ if (authenticated == 0 && !authctxt->postponed && !partial) - audit_event(ssh, audit_classify_auth(method)); - #endif - } @@ -597,9 +597,6 @@ getpwnamallow(struct ssh *ssh, const cha record_failed_login(ssh, user, auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); @@ -1204,9 +1195,9 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c - ret = sshkey_verify(key, signature, signaturelen, data, datalen, - sigalg, ssh->compat, &sig_details); - debug3_f("%s %p signature %s%s%s", auth_method, key, - (ret == 0) ? "verified" : "unverified", - (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); + debug3_f("%s %s signature %s%s%s", auth_method, sshkey_type(key), + (ret == 0) ? "verified" : "unverified", + (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); @@ -1576,13 +1600,19 @@ mm_record_login(struct ssh *ssh, Session } @@ -2065,7 +2056,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c close_startup_pipes(void) { @@ -377,18 +387,45 @@ grace_alarm_handler(int sig) - ssh_remote_port(the_active_state)); + } } -/* Destroy the host and server keys. They will no longer be needed. */ diff --git a/openssh-7.7p1-gssapi-new-unique.patch b/openssh-7.7p1-gssapi-new-unique.patch index 387b7a0..c130022 100644 --- a/openssh-7.7p1-gssapi-new-unique.patch +++ b/openssh-7.7p1-gssapi-new-unique.patch @@ -504,15 +504,15 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c options->gss_authentication = 0; if (options->gss_keyex == -1) @@ -506,7 +509,8 @@ typedef enum { - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sRhostsRSAAuthentication, sRSAAuthentication, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, + sPort, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, - sKerberosGetAFSToken, sChallengeResponseAuthentication, + sKerberosGetAFSToken, sKerberosUniqueCCache, + sChallengeResponseAuthentication, - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sPasswordAuthentication, sKbdInteractiveAuthentication, + sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, @@ -593,11 +597,13 @@ static struct { #else { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, diff --git a/openssh-7.8p1-UsePAM-warning.patch b/openssh-7.8p1-UsePAM-warning.patch index 519ee29..8560c9f 100644 --- a/openssh-7.8p1-UsePAM-warning.patch +++ b/openssh-7.8p1-UsePAM-warning.patch @@ -18,7 +18,7 @@ diff -up openssh-8.6p1/sshd_config.log-usepam-no openssh-8.6p1/sshd_config @@ -87,6 +87,8 @@ 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 ChallengeResponseAuthentication to 'no'. + # and KbdInteractiveAuthentication to 'no'. +# WARNING: 'UsePAM no' is not supported in Fedora and may cause several +# problems. #UsePAM no diff --git a/openssh-7.8p1-role-mls.patch b/openssh-7.8p1-role-mls.patch index 145eac0..48f9f10 100644 --- a/openssh-7.8p1-role-mls.patch +++ b/openssh-7.8p1-role-mls.patch @@ -337,7 +337,7 @@ diff -up openssh/openbsd-compat/Makefile.in.role-mls openssh/openbsd-compat/Make --- openssh/openbsd-compat/Makefile.in.role-mls 2018-08-20 07:57:29.000000000 +0200 +++ openssh/openbsd-compat/Makefile.in 2018-08-22 11:14:56.819430949 +0200 @@ -92,7 +92,8 @@ PORTS= port-aix.o \ - port-linux.o \ + port-prngd.o \ port-solaris.o \ port-net.o \ - port-uw.o diff --git a/openssh-8.0p1-crypto-policies.patch b/openssh-8.0p1-crypto-policies.patch index 4baa024..762825e 100644 --- a/openssh-8.0p1-crypto-policies.patch +++ b/openssh-8.0p1-crypto-policies.patch @@ -1,7 +1,7 @@ -diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 ---- openssh-8.6p1/ssh_config.5.crypto-policies 2021-04-19 15:18:32.071920379 +0200 -+++ openssh-8.6p1/ssh_config.5 2021-04-19 15:21:18.400179265 +0200 -@@ -368,15 +368,13 @@ or +diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5 +--- openssh-8.7p1/ssh_config.5.crypto-policies 2021-08-30 13:29:00.174292872 +0200 ++++ openssh-8.7p1/ssh_config.5 2021-08-30 13:31:32.009548808 +0200 +@@ -373,17 +373,13 @@ or .Qq *.c.example.com domains. .It Cm CASignatureAlgorithms @@ -14,15 +14,17 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 by certificate authorities (CAs). -The default is: -.Bd -literal -offset indent --ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, --sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com, +-ssh-ed25519,ecdsa-sha2-nistp256, +-ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-sk-ssh-ed25519@openssh.com, +-sk-ecdsa-sha2-nistp256@openssh.com, -rsa-sha2-512,rsa-sha2-256 -.Ed -.Pp - .Xr ssh 1 - will not accept host certificates signed using algorithms other than those - specified. -@@ -436,20 +434,25 @@ If the option is set to + If the specified list begins with a + .Sq + + character, then the specified algorithms will be appended to the default set +@@ -445,20 +441,25 @@ If the option is set to (the default), the check will not be executed. .It Cm Ciphers @@ -52,7 +54,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 .Pp The supported ciphers are: .Bd -literal -offset indent -@@ -465,13 +468,6 @@ aes256-gcm@openssh.com +@@ -474,13 +475,6 @@ aes256-gcm@openssh.com chacha20-poly1305@openssh.com .Ed .Pp @@ -66,7 +68,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClearAllForwardings -@@ -826,6 +822,11 @@ command line will be passed untouched to +@@ -874,6 +868,11 @@ command line will be passed untouched to The default is .Dq no . .It Cm GSSAPIKexAlgorithms @@ -78,7 +80,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 The list of key exchange algorithms that are offered for GSSAPI key exchange. Possible values are .Bd -literal -offset 3n -@@ -838,10 +839,8 @@ gss-nistp256-sha256-, +@@ -886,10 +885,8 @@ gss-nistp256-sha256-, gss-curve25519-sha256- .Ed .Pp @@ -90,7 +92,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 .It Cm HashKnownHosts Indicates that .Xr ssh 1 -@@ -1169,29 +1168,25 @@ it may be zero or more of: +@@ -1219,29 +1216,25 @@ it may be zero or more of: and .Cm pam . .It Cm KexAlgorithms @@ -129,7 +131,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 .Pp The list of available key exchange algorithms may also be obtained using .Qq ssh -Q kex . -@@ -1301,37 +1296,33 @@ function, and all code in the +@@ -1351,37 +1344,33 @@ function, and all code in the file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -176,7 +178,7 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm NoHostAuthenticationForLocalhost -@@ -1503,37 +1494,25 @@ instead of continuing to execute and pas +@@ -1553,37 +1542,25 @@ instead of continuing to execute and pas The default is .Cm no . .It Cm PubkeyAcceptedAlgorithms @@ -223,10 +225,10 @@ diff -up openssh-8.6p1/ssh_config.5.crypto-policies openssh-8.6p1/ssh_config.5 .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . -diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 ---- openssh-8.6p1/sshd_config.5.crypto-policies 2021-04-19 15:18:32.062920311 +0200 -+++ openssh-8.6p1/sshd_config.5 2021-04-19 15:20:42.591908243 +0200 -@@ -373,15 +373,13 @@ If the argument is +diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5 +--- openssh-8.7p1/sshd_config.5.crypto-policies 2021-08-30 13:29:00.157292731 +0200 ++++ openssh-8.7p1/sshd_config.5 2021-08-30 13:32:16.263918533 +0200 +@@ -373,17 +373,13 @@ If the argument is then no banner is displayed. By default, no banner is displayed. .It Cm CASignatureAlgorithms @@ -239,15 +241,17 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 by certificate authorities (CAs). -The default is: -.Bd -literal -offset indent --ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, --sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com, +-ssh-ed25519,ecdsa-sha2-nistp256, +-ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-sk-ssh-ed25519@openssh.com, +-sk-ecdsa-sha2-nistp256@openssh.com, -rsa-sha2-512,rsa-sha2-256 -.Ed -.Pp - Certificates signed using other algorithms will not be accepted for - public key or host-based authentication. - .It Cm ChallengeResponseAuthentication -@@ -445,20 +443,25 @@ The default is + If the specified list begins with a + .Sq + + character, then the specified algorithms will be appended to the default set +@@ -450,20 +446,25 @@ The default is indicating not to .Xr chroot 2 . .It Cm Ciphers @@ -277,7 +281,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 .Pp The supported ciphers are: .Pp -@@ -485,13 +488,6 @@ aes256-gcm@openssh.com +@@ -490,13 +491,6 @@ aes256-gcm@openssh.com chacha20-poly1305@openssh.com .El .Pp @@ -291,7 +295,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClientAliveCountMax -@@ -680,21 +676,22 @@ For this to work +@@ -685,21 +679,22 @@ For this to work .Cm GSSAPIKeyExchange needs to be enabled in the server and also used by the client. .It Cm GSSAPIKexAlgorithms @@ -324,7 +328,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 This option only applies to connections using GSSAPI. .It Cm HostbasedAcceptedAlgorithms Specifies the signature algorithms that will be accepted for hostbased -@@ -794,26 +791,13 @@ is specified, the location of the socket +@@ -799,26 +794,13 @@ is specified, the location of the socket .Ev SSH_AUTH_SOCK environment variable. .It Cm HostKeyAlgorithms @@ -356,7 +360,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm IgnoreRhosts -@@ -958,20 +942,25 @@ Specifies whether to look at .k5login fi +@@ -965,20 +947,25 @@ Specifies whether to look at .k5login fi The default is .Cm yes . .It Cm KexAlgorithms @@ -386,7 +390,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 The supported algorithms are: .Pp .Bl -item -compact -offset indent -@@ -1003,15 +992,6 @@ ecdh-sha2-nistp521 +@@ -1010,15 +997,6 @@ ecdh-sha2-nistp521 sntrup761x25519-sha512@openssh.com .El .Pp @@ -402,7 +406,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 The list of available key exchange algorithms may also be obtained using .Qq ssh -Q KexAlgorithms . .It Cm ListenAddress -@@ -1097,21 +1077,26 @@ function, and all code in the +@@ -1104,21 +1082,26 @@ function, and all code in the file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -433,7 +437,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 .Pp The algorithms that contain .Qq -etm -@@ -1154,15 +1139,6 @@ umac-64-etm@openssh.com +@@ -1161,15 +1144,6 @@ umac-64-etm@openssh.com umac-128-etm@openssh.com .El .Pp @@ -449,7 +453,7 @@ diff -up openssh-8.6p1/sshd_config.5.crypto-policies openssh-8.6p1/sshd_config.5 The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm Match -@@ -1541,37 +1517,25 @@ or equivalent.) +@@ -1548,37 +1522,25 @@ or equivalent.) The default is .Cm yes . .It Cm PubkeyAcceptedAlgorithms diff --git a/openssh-8.0p1-gssapi-keyex.patch b/openssh-8.0p1-gssapi-keyex.patch index 2c29486..e26bebd 100644 --- a/openssh-8.0p1-gssapi-keyex.patch +++ b/openssh-8.0p1-gssapi-keyex.patch @@ -19,11 +19,10 @@ index e7549470..b68c1710 100644 loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ srclimit.o sftp-server.o sftp-common.o \ sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff --git a/auth.c b/auth.c -index 086b8ebb..687c57b4 100644 ---- a/auth.c -+++ b/auth.c -@@ -400,7 +400,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) +diff -up a/auth.c.gsskex b/auth.c +--- a/auth.c.gsskex 2021-08-20 06:03:49.000000000 +0200 ++++ b/auth.c 2021-08-27 12:41:51.262788953 +0200 +@@ -402,7 +402,8 @@ auth_root_allowed(struct ssh *ssh, const case PERMIT_NO_PASSWD: if (strcmp(method, "publickey") == 0 || strcmp(method, "hostbased") == 0 || @@ -33,18 +32,15 @@ index 086b8ebb..687c57b4 100644 return 1; break; case PERMIT_FORCED_ONLY: -@@ -724,99 +725,6 @@ fakepw(void) - return (&fake); +@@ -730,97 +731,6 @@ fakepw(void) } --/* + /* - * Returns the remote DNS hostname as a string. The returned string must not - * be freed. NB. this will usually trigger a DNS query the first time it is - * called. - * This function does additional checks on the hostname to mitigate some -- * attacks on legacy rhosts-style authentication. -- * XXX is RhostsRSAAuthentication vulnerable to these? -- * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) +- * attacks on based on conflation of hostnames and IP addresses. - */ - -static char * @@ -130,9 +126,10 @@ index 086b8ebb..687c57b4 100644 - return xstrdup(name); -} - - /* +-/* * Return the canonical name of the host in the other side of the current * connection. The host name is cached, so it is efficient to call this + * several times. diff --git a/auth2-gss.c b/auth2-gss.c index 9351e042..d6446c0c 100644 --- a/auth2-gss.c @@ -2913,10 +2910,9 @@ index 23ab096a..485590c1 100644 #endif #ifdef USE_PAM -diff --git a/readconf.c b/readconf.c -index f3cac6b3..da8022dd 100644 ---- a/readconf.c -+++ b/readconf.c +diff -up a/readconf.c.gsskex b/readconf.c +--- a/readconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 ++++ b/readconf.c 2021-08-27 12:25:42.556421509 +0200 @@ -67,6 +67,7 @@ #include "uidswap.h" #include "myproposal.h" @@ -2925,7 +2921,7 @@ index f3cac6b3..da8022dd 100644 /* Format of the configuration file: -@@ -160,6 +161,8 @@ typedef enum { +@@ -161,6 +162,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -2934,7 +2930,7 @@ index f3cac6b3..da8022dd 100644 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -204,10 +207,22 @@ static struct { +@@ -206,10 +209,22 @@ static struct { /* Sometimes-unsupported options */ #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, @@ -2957,7 +2953,7 @@ index f3cac6b3..da8022dd 100644 #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1029,10 +1044,42 @@ parse_time: +@@ -1113,10 +1128,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -2986,7 +2982,7 @@ index f3cac6b3..da8022dd 100644 + goto parse_flag; + + case oGssKexAlgorithms: -+ arg = strdelim(&s); ++ arg = argv_next(&ac, &av); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", + filename, linenum); @@ -3000,9 +2996,9 @@ index f3cac6b3..da8022dd 100644 case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -1911,7 +1958,13 @@ initialize_options(Options * options) +@@ -2306,7 +2353,13 @@ initialize_options(Options * options) + options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; - options->challenge_response_authentication = -1; options->gss_authentication = -1; + options->gss_keyex = -1; options->gss_deleg_creds = -1; @@ -3014,8 +3010,8 @@ index f3cac6b3..da8022dd 100644 options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -2059,8 +2112,18 @@ fill_default_options(Options * options) - options->challenge_response_authentication = 1; +@@ -2463,8 +2516,18 @@ fill_default_options(Options * options) + options->pubkey_authentication = 1; if (options->gss_authentication == -1) options->gss_authentication = 0; + if (options->gss_keyex == -1) @@ -3033,7 +3029,7 @@ index f3cac6b3..da8022dd 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -2702,7 +2765,14 @@ dump_client_config(Options *o, const char *host) +@@ -3246,7 +3309,14 @@ dump_client_config(Options *o, const cha dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); #ifdef GSSAPI dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); @@ -3048,13 +3044,12 @@ index f3cac6b3..da8022dd 100644 #endif /* GSSAPI */ dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); -diff --git a/readconf.h b/readconf.h -index feedb3d2..a8a8870d 100644 ---- a/readconf.h -+++ b/readconf.h -@@ -41,7 +41,13 @@ typedef struct { - int challenge_response_authentication; - /* Try S/Key or TIS, authentication. */ +diff -up a/readconf.h.gsskex b/readconf.h +--- a/readconf.h.gsskex 2021-08-27 12:05:29.248142431 +0200 ++++ b/readconf.h 2021-08-27 12:22:19.270679852 +0200 +@@ -39,7 +39,13 @@ typedef struct { + int pubkey_authentication; /* Try ssh2 pubkey authentication. */ + int hostbased_authentication; /* ssh2's rhosts_rsa */ int gss_authentication; /* Try GSS authentication */ + int gss_keyex; /* Try GSS key exchange */ int gss_deleg_creds; /* Delegate GSS credentials */ @@ -3066,11 +3061,10 @@ index feedb3d2..a8a8870d 100644 int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff --git a/servconf.c b/servconf.c -index 70f5f73f..191575a1 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -69,6 +69,7 @@ +diff -up a/servconf.c.gsskex b/servconf.c +--- a/servconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 ++++ b/servconf.c 2021-08-27 12:28:15.887735189 +0200 +@@ -70,6 +70,7 @@ #include "auth.h" #include "myproposal.h" #include "digest.h" @@ -3078,7 +3072,7 @@ index 70f5f73f..191575a1 100644 static void add_listen_addr(ServerOptions *, const char *, const char *, int); -@@ -133,8 +134,11 @@ initialize_server_options(ServerOptions *options) +@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3089,8 +3083,8 @@ index 70f5f73f..191575a1 100644 + options->gss_kex_algorithms = NULL; options->password_authentication = -1; options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; -@@ -375,10 +379,18 @@ fill_default_server_options(ServerOptions *options) + options->permit_empty_passwd = -1; +@@ -356,10 +360,18 @@ fill_default_server_options(ServerOption options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3109,7 +3103,7 @@ index 70f5f73f..191575a1 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -531,6 +543,7 @@ typedef enum { +@@ -506,6 +518,7 @@ typedef enum { sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, @@ -3117,7 +3111,7 @@ index 70f5f73f..191575a1 100644 sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -607,12 +620,22 @@ static struct { +@@ -587,12 +600,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3139,8 +3133,8 @@ index 70f5f73f..191575a1 100644 + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, - { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, -@@ -1548,6 +1571,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, + { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ +@@ -1576,6 +1599,10 @@ process_server_config_line_depth(ServerO intptr = &options->gss_authentication; goto parse_flag; @@ -3151,7 +3145,7 @@ index 70f5f73f..191575a1 100644 case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; -@@ -1556,6 +1583,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1584,6 +1611,22 @@ process_server_config_line_depth(ServerO intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3160,7 +3154,7 @@ index 70f5f73f..191575a1 100644 + goto parse_flag; + + case sGssKexAlgorithms: -+ arg = strdelim(&cp); ++ arg = argv_next(&ac, &av); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", + filename, linenum); @@ -3174,7 +3168,7 @@ index 70f5f73f..191575a1 100644 case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2777,6 +2820,10 @@ dump_config(ServerOptions *o) +@@ -2892,6 +2935,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); diff --git a/openssh-8.0p1-pkcs11-uri.patch b/openssh-8.0p1-pkcs11-uri.patch index dc8a7d0..8592607 100644 --- a/openssh-8.0p1-pkcs11-uri.patch +++ b/openssh-8.0p1-pkcs11-uri.patch @@ -1,7 +1,7 @@ -diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac ---- openssh-8.6p1/configure.ac.pkcs11-uri 2021-04-19 14:57:30.307370482 +0200 -+++ openssh-8.6p1/configure.ac 2021-04-19 14:57:30.315370543 +0200 -@@ -1974,12 +1974,14 @@ AC_LINK_IFELSE( +diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac +--- openssh-8.7p1/configure.ac.pkcs11-uri 2021-08-30 13:07:43.646699953 +0200 ++++ openssh-8.7p1/configure.ac 2021-08-30 13:07:43.662700088 +0200 +@@ -1985,12 +1985,14 @@ AC_LINK_IFELSE( [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) ]) @@ -16,7 +16,7 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac fi ] ) -@@ -2008,6 +2010,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) +@@ -2019,6 +2021,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([dlopen]) AC_CHECK_DECL([RTLD_NOW], [], [], [#include ]) @@ -57,7 +57,7 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac # IRIX has a const char return value for gai_strerror() AC_CHECK_FUNCS([gai_strerror], [ AC_DEFINE([HAVE_GAI_STRERROR]) -@@ -5564,6 +5600,7 @@ echo " BSD Auth support +@@ -5624,6 +5660,7 @@ echo " BSD Auth support echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" echo " PKCS#11 support: $enable_pkcs11" @@ -65,9 +65,9 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac echo " U2F/FIDO support: $enable_sk" echo "" -diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in ---- openssh-8.6p1/Makefile.in.pkcs11-uri 2021-04-19 14:57:30.261370134 +0200 -+++ openssh-8.6p1/Makefile.in 2021-04-19 15:14:38.916155695 +0200 +diff -up openssh-8.7p1/Makefile.in.pkcs11-uri openssh-8.7p1/Makefile.in +--- openssh-8.7p1/Makefile.in.pkcs11-uri 2021-08-30 13:07:43.571699324 +0200 ++++ openssh-8.7p1/Makefile.in 2021-08-30 13:07:43.663700096 +0200 @@ -103,7 +103,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ @@ -77,7 +77,7 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ssh-ed25519.o digest-openssl.o digest-libc.o \ hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \ -@@ -300,6 +300,8 @@ clean: regressclean +@@ -302,6 +302,8 @@ clean: regressclean rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT) rm -f regress/unittests/utf8/*.o rm -f regress/unittests/utf8/test_utf8$(EXEEXT) @@ -86,7 +86,7 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in rm -f regress/misc/sk-dummy/*.o rm -f regress/misc/sk-dummy/*.lo rm -f regress/misc/sk-dummy/sk-dummy.so -@@ -337,6 +339,8 @@ distclean: regressclean +@@ -339,6 +341,8 @@ distclean: regressclean rm -f regress/unittests/sshsig/test_sshsig rm -f regress/unittests/utf8/*.o rm -f regress/unittests/utf8/test_utf8 @@ -95,7 +95,7 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in (cd openbsd-compat && $(MAKE) distclean) if test -d pkg ; then \ rm -fr pkg ; \ -@@ -511,6 +515,7 @@ regress-prep: +@@ -513,6 +517,7 @@ regress-prep: $(MKDIR_P) `pwd`/regress/unittests/sshkey $(MKDIR_P) `pwd`/regress/unittests/sshsig $(MKDIR_P) `pwd`/regress/unittests/utf8 @@ -103,7 +103,7 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in $(MKDIR_P) `pwd`/regress/misc/sk-dummy [ -f `pwd`/regress/Makefile ] || \ ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile -@@ -674,6 +679,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT +@@ -677,6 +682,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT regress/unittests/test_helper/libtest_helper.a \ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) @@ -120,17 +120,19 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in # These all need to be compiled -fPIC, so they are treated differently. SK_DUMMY_OBJS=\ regress/misc/sk-dummy/sk-dummy.lo \ -@@ -709,6 +724,7 @@ regress-unit-binaries: regress-prep $(RE +@@ -711,7 +726,8 @@ regress-unit-binaries: regress-prep $(RE + regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) \ regress/unittests/sshsig/test_sshsig$(EXEEXT) \ - regress/unittests/utf8/test_utf8$(EXEEXT) \ +- regress/unittests/utf8/test_utf8$(EXEEXT) ++ regress/unittests/utf8/test_utf8$(EXEEXT) \ + regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ tests: file-tests t-exec interop-tests unit echo all tests passed -diff -up openssh-8.6p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/agent-pkcs11.sh ---- openssh-8.6p1/regress/agent-pkcs11.sh.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/agent-pkcs11.sh 2021-04-19 14:57:30.316370550 +0200 +diff -up openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/agent-pkcs11.sh +--- openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/regress/agent-pkcs11.sh 2021-08-30 13:07:43.663700096 +0200 @@ -113,7 +113,7 @@ else done @@ -140,10 +142,10 @@ diff -up openssh-8.6p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/ r=$? if [ $r -ne 0 ]; then fail "ssh-add -e failed: exit code $r" -diff -up openssh-8.6p1/regress/Makefile.pkcs11-uri openssh-8.6p1/regress/Makefile ---- openssh-8.6p1/regress/Makefile.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/Makefile 2021-04-19 15:15:44.411651410 +0200 -@@ -119,7 +119,8 @@ CLEANFILES= *.core actual agent-key.* au +diff -up openssh-8.7p1/regress/Makefile.pkcs11-uri openssh-8.7p1/regress/Makefile +--- openssh-8.7p1/regress/Makefile.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/regress/Makefile 2021-08-30 13:07:43.663700096 +0200 +@@ -122,7 +122,8 @@ CLEANFILES= *.core actual agent-key.* au known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ modpipe netcat no_identity_config \ pidfile putty.rsa2 ready regress.log remote_pid \ @@ -153,7 +155,7 @@ diff -up openssh-8.6p1/regress/Makefile.pkcs11-uri openssh-8.6p1/regress/Makefil rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ -@@ -249,8 +250,9 @@ unit: +@@ -252,8 +253,9 @@ unit: V="" ; \ test "x${USE_VALGRIND}" = "x" || \ V=${.CURDIR}/valgrind-unit.sh ; \ @@ -165,9 +167,9 @@ diff -up openssh-8.6p1/regress/Makefile.pkcs11-uri openssh-8.6p1/regress/Makefil -d ${.CURDIR}/unittests/sshkey/testdata ; \ $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \ -d ${.CURDIR}/unittests/sshsig/testdata ; \ -diff -up openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/pkcs11.sh ---- openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri 2021-04-19 14:57:30.316370550 +0200 -+++ openssh-8.6p1/regress/pkcs11.sh 2021-04-19 14:57:30.316370550 +0200 +diff -up openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/pkcs11.sh +--- openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri 2021-08-30 13:07:43.663700096 +0200 ++++ openssh-8.7p1/regress/pkcs11.sh 2021-08-30 13:07:43.663700096 +0200 @@ -0,0 +1,349 @@ +# +# Copyright (c) 2017 Red Hat @@ -518,9 +520,9 @@ diff -up openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/pkcs11 + trace "kill agent" + ${SSHAGENT} -k > /dev/null +fi -diff -up openssh-8.6p1/regress/unittests/Makefile.pkcs11-uri openssh-8.6p1/regress/unittests/Makefile ---- openssh-8.6p1/regress/unittests/Makefile.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/unittests/Makefile 2021-04-19 14:57:30.316370550 +0200 +diff -up openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri openssh-8.7p1/regress/unittests/Makefile +--- openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/regress/unittests/Makefile 2021-08-30 13:07:43.663700096 +0200 @@ -2,6 +2,6 @@ REGRESS_FAIL_EARLY?= yes @@ -529,9 +531,9 @@ diff -up openssh-8.6p1/regress/unittests/Makefile.pkcs11-uri openssh-8.6p1/regre +SUBDIR+=authopt misc sshsig pkcs11 .include -diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1/regress/unittests/pkcs11/tests.c ---- openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri 2021-04-19 14:57:30.317370558 +0200 -+++ openssh-8.6p1/regress/unittests/pkcs11/tests.c 2021-04-19 14:57:30.317370558 +0200 +diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1/regress/unittests/pkcs11/tests.c +--- openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri 2021-08-30 13:07:43.664700104 +0200 ++++ openssh-8.7p1/regress/unittests/pkcs11/tests.c 2021-08-30 13:07:43.664700104 +0200 @@ -0,0 +1,337 @@ +/* + * Copyright (c) 2017 Red Hat @@ -870,9 +872,9 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + test_parse_invalid(); + test_generate_valid(); +} -diff -up openssh-8.6p1/ssh-add.c.pkcs11-uri openssh-8.6p1/ssh-add.c ---- openssh-8.6p1/ssh-add.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-add.c 2021-04-19 14:57:30.317370558 +0200 +diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c +--- openssh-8.7p1/ssh-add.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-add.c 2021-08-30 13:07:43.664700104 +0200 @@ -68,6 +68,7 @@ #include "digest.h" #include "ssh-sk.h" @@ -952,9 +954,9 @@ diff -up openssh-8.6p1/ssh-add.c.pkcs11-uri openssh-8.6p1/ssh-add.c ret = 1; goto done; } -diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c ---- openssh-8.6p1/ssh-agent.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-agent.c 2021-04-19 14:57:30.317370558 +0200 +diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c +--- openssh-8.7p1/ssh-agent.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-agent.c 2021-08-30 13:07:43.664700104 +0200 @@ -847,10 +847,72 @@ no_identities(SocketEntry *e) } @@ -1125,10 +1127,10 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c send_status(e, success); } #endif /* ENABLE_PKCS11 */ -diff -up openssh-8.6p1/ssh_config.5.pkcs11-uri openssh-8.6p1/ssh_config.5 ---- openssh-8.6p1/ssh_config.5.pkcs11-uri 2021-04-19 14:57:30.269370194 +0200 -+++ openssh-8.6p1/ssh_config.5 2021-04-19 14:57:30.321370588 +0200 -@@ -1063,6 +1063,21 @@ may also be used in conjunction with +diff -up openssh-8.7p1/ssh_config.5.pkcs11-uri openssh-8.7p1/ssh_config.5 +--- openssh-8.7p1/ssh_config.5.pkcs11-uri 2021-08-30 13:07:43.578699383 +0200 ++++ openssh-8.7p1/ssh_config.5 2021-08-30 13:07:43.664700104 +0200 +@@ -1111,6 +1111,21 @@ may also be used in conjunction with .Cm CertificateFile in order to provide any certificate also needed for authentication with the identity. @@ -1150,10 +1152,10 @@ diff -up openssh-8.6p1/ssh_config.5.pkcs11-uri openssh-8.6p1/ssh_config.5 .It Cm IgnoreUnknown Specifies a pattern-list of unknown options to be ignored if they are encountered in configuration parsing. -diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c ---- openssh-8.6p1/ssh.c.pkcs11-uri 2021-04-19 14:57:30.269370194 +0200 -+++ openssh-8.6p1/ssh.c 2021-04-19 15:17:05.804267447 +0200 -@@ -843,6 +843,14 @@ main(int ac, char **av) +diff -up openssh-8.7p1/ssh.c.pkcs11-uri openssh-8.7p1/ssh.c +--- openssh-8.7p1/ssh.c.pkcs11-uri 2021-08-30 13:07:43.578699383 +0200 ++++ openssh-8.7p1/ssh.c 2021-08-30 13:07:43.666700121 +0200 +@@ -826,6 +826,14 @@ main(int ac, char **av) options.gss_deleg_creds = 1; break; case 'i': @@ -1168,7 +1170,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c p = tilde_expand_filename(optarg, getuid()); if (stat(p, &st) == -1) fprintf(stderr, "Warning: Identity file %s " -@@ -1695,6 +1703,7 @@ main(int ac, char **av) +@@ -1681,6 +1689,7 @@ main(int ac, char **av) #ifdef ENABLE_PKCS11 (void)pkcs11_del_provider(options.pkcs11_provider); #endif @@ -1176,7 +1178,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c skip_connect: exit_status = ssh_session2(ssh, cinfo); -@@ -2211,6 +2220,45 @@ ssh_session2(struct ssh *ssh, const stru +@@ -2197,6 +2206,45 @@ ssh_session2(struct ssh *ssh, const stru options.escape_char : SSH_ESCAPECHAR_NONE, id); } @@ -1222,7 +1224,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c /* Loads all IdentityFile and CertificateFile keys */ static void load_public_identity_files(const struct ssh_conn_info *cinfo) -@@ -2225,11 +2273,6 @@ load_public_identity_files(const struct +@@ -2211,11 +2259,6 @@ load_public_identity_files(const struct char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; @@ -1234,7 +1236,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c n_ids = n_certs = 0; memset(identity_files, 0, sizeof(identity_files)); -@@ -2242,33 +2285,46 @@ load_public_identity_files(const struct +@@ -2228,33 +2271,46 @@ load_public_identity_files(const struct sizeof(certificate_file_userprovided)); #ifdef ENABLE_PKCS11 @@ -1300,9 +1302,9 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c filename = default_client_percent_dollar_expand(cp, cinfo); free(cp); check_load(sshkey_load_public(filename, &public, NULL), -diff -up openssh-8.6p1/ssh-keygen.c.pkcs11-uri openssh-8.6p1/ssh-keygen.c ---- openssh-8.6p1/ssh-keygen.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-keygen.c 2021-04-19 14:57:30.318370565 +0200 +diff -up openssh-8.7p1/ssh-keygen.c.pkcs11-uri openssh-8.7p1/ssh-keygen.c +--- openssh-8.7p1/ssh-keygen.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-keygen.c 2021-08-30 13:07:43.666700121 +0200 @@ -860,8 +860,11 @@ do_download(struct passwd *pw) free(fp); } else { @@ -1317,9 +1319,9 @@ diff -up openssh-8.6p1/ssh-keygen.c.pkcs11-uri openssh-8.6p1/ssh-keygen.c } free(comments[i]); sshkey_free(keys[i]); -diff -up openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-client.c ---- openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11-client.c 2021-04-19 14:57:30.318370565 +0200 +diff -up openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-client.c +--- openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-pkcs11-client.c 2021-08-30 13:07:43.666700121 +0200 @@ -323,6 +323,8 @@ pkcs11_add_provider(char *name, char *pi u_int nkeys, i; struct sshbuf *msg; @@ -1337,9 +1339,9 @@ diff -up openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-c for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || -diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c ---- openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11.c 2021-04-19 14:57:30.320370580 +0200 +diff -up openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11.c +--- openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-pkcs11.c 2021-08-30 13:12:27.709084157 +0200 @@ -55,8 +55,8 @@ struct pkcs11_slotinfo { int logged_in; }; @@ -1383,8 +1385,8 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_RV rv; CK_ULONG i; -- debug("pkcs11_provider_finalize: %p refcount %d valid %d", -- p, p->refcount, p->valid); +- debug_f("provider \"%s\" refcount %d valid %d", +- p->name, p->refcount, p->valid); - if (!p->valid) + debug_f("%p refcount %d valid %d", m, m->refcount, m->valid); + if (!m->valid) @@ -1427,9 +1429,9 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c +} + +/* -+ * finalize a provider shared libarary, it's no longer usable. ++ * finalize a provider shared library, it's no longer usable. + * however, there might still be keys referencing this provider, -+ * so the actuall freeing of memory is handled by pkcs11_provider_unref(). ++ * so the actual freeing of memory is handled by pkcs11_provider_unref(). + * this is called when a provider gets unregistered. + */ +static void @@ -1446,15 +1448,12 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c } /* -@@ -135,13 +178,11 @@ pkcs11_provider_finalize(struct pkcs11_p - static void - pkcs11_provider_unref(struct pkcs11_provider *p) +@@ -137,11 +180,9 @@ pkcs11_provider_unref(struct pkcs11_prov { -- debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount); -+ debug_f("%p refcount %d", p, p->refcount); + debug_f("provider \"%s\" refcount %d", p->name, p->refcount); if (--p->refcount <= 0) { - if (p->valid) -- error("pkcs11_provider_unref: %p still valid", p); +- error_f("provider \"%s\" still valid", p->name); free(p->name); - free(p->slotlist); - free(p->slotinfo); @@ -1543,7 +1542,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c } static RSA_METHOD *rsa_method; -@@ -195,6 +283,55 @@ static EC_KEY_METHOD *ec_key_method; +@@ -195,6 +286,55 @@ static EC_KEY_METHOD *ec_key_method; static int ec_key_idx = 0; #endif @@ -1599,7 +1598,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c /* release a wrapped object */ static void pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, -@@ -208,6 +345,7 @@ pkcs11_k11_free(void *parent, void *ptr, +@@ -208,6 +348,7 @@ pkcs11_k11_free(void *parent, void *ptr, if (k11->provider) pkcs11_provider_unref(k11->provider); free(k11->keyid); @@ -1607,7 +1606,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(k11); } -@@ -222,8 +360,8 @@ pkcs11_find(struct pkcs11_provider *p, C +@@ -222,8 +363,8 @@ pkcs11_find(struct pkcs11_provider *p, C CK_RV rv; int ret = -1; @@ -1618,7 +1617,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); return (-1); -@@ -262,12 +400,12 @@ pkcs11_login_slot(struct pkcs11_provider +@@ -262,12 +403,12 @@ pkcs11_login_slot(struct pkcs11_provider else { snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", si->token.label); @@ -1633,7 +1632,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c (pin != NULL) ? strlen(pin) : 0); if (pin != NULL) freezero(pin, strlen(pin)); -@@ -297,13 +435,14 @@ pkcs11_login_slot(struct pkcs11_provider +@@ -297,13 +438,14 @@ pkcs11_login_slot(struct pkcs11_provider static int pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) { @@ -1650,7 +1649,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c } -@@ -319,13 +458,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs +@@ -319,13 +461,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs *val = 0; @@ -1668,7 +1667,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c attr.type = type; attr.pValue = &flag; -@@ -356,13 +496,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C +@@ -356,13 +499,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C int always_auth = 0; int did_login = 0; @@ -1686,7 +1685,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { if (pkcs11_login(k11, CKU_USER) < 0) { -@@ -439,8 +580,8 @@ pkcs11_rsa_private_encrypt(int flen, con +@@ -439,8 +583,8 @@ pkcs11_rsa_private_encrypt(int flen, con return (-1); } @@ -1697,7 +1696,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c tlen = RSA_size(rsa); /* XXX handle CKR_BUFFER_TOO_SMALL */ -@@ -484,7 +625,7 @@ pkcs11_rsa_start_wrapper(void) +@@ -484,7 +628,7 @@ pkcs11_rsa_start_wrapper(void) /* redirect private key operations for rsa key to pkcs11 token */ static int pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, @@ -1706,7 +1705,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c { struct pkcs11_key *k11; -@@ -502,6 +643,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * +@@ -502,6 +646,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); } @@ -1719,7 +1718,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c RSA_set_method(rsa, rsa_method); RSA_set_ex_data(rsa, rsa_idx, k11); return (0); -@@ -532,8 +679,8 @@ ecdsa_do_sign(const unsigned char *dgst, +@@ -532,8 +682,8 @@ ecdsa_do_sign(const unsigned char *dgst, return (NULL); } @@ -1730,7 +1729,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c siglen = ECDSA_size(ec); sig = xmalloc(siglen); -@@ -598,7 +745,7 @@ pkcs11_ecdsa_start_wrapper(void) +@@ -598,7 +748,7 @@ pkcs11_ecdsa_start_wrapper(void) static int pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, @@ -1739,7 +1738,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c { struct pkcs11_key *k11; -@@ -614,6 +761,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider +@@ -614,6 +764,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider k11->keyid = xmalloc(k11->keyid_len); memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); @@ -1752,7 +1751,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c EC_KEY_set_method(ec, ec_key_method); EC_KEY_set_ex_data(ec, ec_key_idx, k11); -@@ -650,8 +803,8 @@ pkcs11_open_session(struct pkcs11_provid +@@ -650,8 +806,8 @@ pkcs11_open_session(struct pkcs11_provid CK_SESSION_HANDLE session; int login_required, ret; @@ -1763,7 +1762,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c login_required = si->token.flags & CKF_LOGIN_REQUIRED; -@@ -661,9 +814,9 @@ pkcs11_open_session(struct pkcs11_provid +@@ -661,9 +817,9 @@ pkcs11_open_session(struct pkcs11_provid error("pin required"); return (-SSH_PKCS11_ERR_PIN_REQUIRED); } @@ -1775,7 +1774,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c return (-1); } if (login_required && pin != NULL && strlen(pin) != 0) { -@@ -699,7 +852,8 @@ static struct sshkey * +@@ -699,7 +855,8 @@ static struct sshkey * pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) { @@ -1785,7 +1784,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -713,14 +867,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -713,14 +870,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -1806,7 +1805,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return (NULL); -@@ -731,19 +886,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -731,19 +889,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ * ensure that none of the others are zero length. * XXX assumes CKA_ID is always first. */ @@ -1830,7 +1829,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto fail; -@@ -755,8 +910,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -755,8 +913,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1841,7 +1840,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (group == NULL) { ossl_error("d2i_ECPKParameters failed"); goto fail; -@@ -767,13 +922,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -767,13 +925,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1858,7 +1857,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (octet == NULL) { ossl_error("d2i_ASN1_OCTET_STRING failed"); goto fail; -@@ -790,7 +945,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -790,7 +948,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1867,7 +1866,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto fail; key = sshkey_new(KEY_UNSPEC); -@@ -806,7 +961,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -806,7 +964,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ ec = NULL; /* now owned by key */ fail: @@ -1876,7 +1875,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(key_attr[i].pValue); if (ec) EC_KEY_free(ec); -@@ -823,7 +978,8 @@ static struct sshkey * +@@ -823,7 +981,8 @@ static struct sshkey * pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) { @@ -1886,7 +1885,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -834,14 +990,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -834,14 +993,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -1907,7 +1906,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return (NULL); -@@ -852,19 +1009,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -852,19 +1012,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr * ensure that none of the others are zero length. * XXX assumes CKA_ID is always first. */ @@ -1931,7 +1930,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto fail; -@@ -876,8 +1033,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -876,8 +1036,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr goto fail; } @@ -1942,7 +1941,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rsa_n == NULL || rsa_e == NULL) { error("BN_bin2bn failed"); goto fail; -@@ -886,7 +1043,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -886,7 +1046,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr fatal_f("set key"); rsa_n = rsa_e = NULL; /* transferred */ @@ -1951,7 +1950,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto fail; key = sshkey_new(KEY_UNSPEC); -@@ -901,7 +1058,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -901,7 +1061,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr rsa = NULL; /* now owned by key */ fail: @@ -1960,7 +1959,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(key_attr[i].pValue); RSA_free(rsa); -@@ -912,7 +1069,8 @@ static int +@@ -912,7 +1072,8 @@ static int pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) { @@ -1970,7 +1969,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -936,14 +1094,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -936,14 +1097,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p memset(&cert_attr, 0, sizeof(cert_attr)); cert_attr[0].type = CKA_ID; @@ -1991,7 +1990,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return -1; -@@ -955,18 +1114,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -955,18 +1117,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p * XXX assumes CKA_ID is always first. */ if (cert_attr[1].ulValueLen == 0 || @@ -2014,7 +2013,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto out; -@@ -980,8 +1140,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -980,8 +1143,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p subject = xstrdup("invalid subject"); X509_NAME_free(x509_name); @@ -2025,7 +2024,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c error("d2i_x509 failed"); goto out; } -@@ -1001,7 +1161,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1001,7 +1164,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } @@ -2034,7 +2033,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto out; key = sshkey_new(KEY_UNSPEC); -@@ -1031,7 +1191,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1031,7 +1194,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } @@ -2043,7 +2042,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto out; key = sshkey_new(KEY_UNSPEC); -@@ -1051,7 +1211,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1051,7 +1214,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } out: @@ -2052,7 +2051,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(cert_attr[i].pValue); X509_free(x509); RSA_free(rsa); -@@ -1102,11 +1262,12 @@ note_key(struct pkcs11_provider *p, CK_U +@@ -1102,11 +1265,12 @@ note_key(struct pkcs11_provider *p, CK_U */ static int pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -2067,7 +2066,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -1123,10 +1284,23 @@ pkcs11_fetch_certs(struct pkcs11_provide +@@ -1123,10 +1287,23 @@ pkcs11_fetch_certs(struct pkcs11_provide key_attr[0].pValue = &key_class; key_attr[0].ulValueLen = sizeof(key_class); @@ -2094,7 +2093,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_FindObjectsInit failed: %lu", rv); goto fail; -@@ -1207,11 +1381,12 @@ fail: +@@ -1207,11 +1384,12 @@ fail: */ static int pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -2109,7 +2108,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -1227,10 +1402,23 @@ pkcs11_fetch_keys(struct pkcs11_provider +@@ -1227,10 +1405,23 @@ pkcs11_fetch_keys(struct pkcs11_provider key_attr[0].pValue = &key_class; key_attr[0].ulValueLen = sizeof(key_class); @@ -2127,16 +2126,16 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + key_attr[nattr].ulValueLen = strlen(uri->object); + nattr++; + } -+ -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - rv = f->C_FindObjectsInit(session, key_attr, 1); ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ + rv = f->C_FindObjectsInit(session, key_attr, nattr); if (rv != CKR_OK) { error("C_FindObjectsInit failed: %lu", rv); goto fail; -@@ -1499,16 +1687,10 @@ pkcs11_ecdsa_generate_private_key(struct +@@ -1499,16 +1690,10 @@ pkcs11_ecdsa_generate_private_key(struct } #endif /* WITH_PKCS11_KEYGEN */ @@ -2155,7 +2154,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c int ret = -1; struct pkcs11_provider *p = NULL; void *handle = NULL; -@@ -1517,164 +1699,298 @@ pkcs11_register_provider(char *provider_ +@@ -1517,164 +1702,298 @@ pkcs11_register_provider(char *provider_ CK_FUNCTION_LIST *f = NULL; CK_TOKEN_INFO *token; CK_ULONG i; @@ -2241,17 +2240,17 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c error("C_GetInfo for provider %s failed: %lu", - provider_id, rv); + provider_module, rv); - goto fail; - } -- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); -- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); ++ goto fail; ++ } + rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); + if (uri->lib_manuf != NULL && + strcmp(uri->lib_manuf, m->info.manufacturerID)) { + debug_f("Skipping provider %s not matching library_manufacturer", + m->info.manufacturerID); -+ goto fail; -+ } + goto fail; + } +- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); +- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); + rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" " libraryDescription <%s> libraryVersion %d.%d", @@ -2529,7 +2528,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c /* no keys found or some other error, de-register provider */ if (nkeys <= 0 && p != NULL) { -@@ -1683,7 +1999,37 @@ pkcs11_add_provider(char *provider_id, c +@@ -1683,7 +2002,37 @@ pkcs11_add_provider(char *provider_id, c pkcs11_provider_unref(p); } if (nkeys == 0) @@ -2568,9 +2567,9 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c return (nkeys); } -diff -up openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11.h ---- openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11.h 2021-04-19 14:57:30.320370580 +0200 +diff -up openssh-8.7p1/ssh-pkcs11.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11.h +--- openssh-8.7p1/ssh-pkcs11.h.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh-pkcs11.h 2021-08-30 13:07:43.666700121 +0200 @@ -22,10 +22,14 @@ #define SSH_PKCS11_ERR_PIN_REQUIRED 4 #define SSH_PKCS11_ERR_PIN_LOCKED 5 @@ -2586,9 +2585,9 @@ diff -up openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11.h #ifdef WITH_PKCS11_KEYGEN struct sshkey * pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int, -diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri.c ---- openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri 2021-04-19 14:57:30.318370565 +0200 -+++ openssh-8.6p1/ssh-pkcs11-uri.c 2021-04-19 14:57:30.318370565 +0200 +diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.c +--- openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri 2021-08-30 13:07:43.667700130 +0200 ++++ openssh-8.7p1/ssh-pkcs11-uri.c 2021-08-30 13:07:43.667700130 +0200 @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2017 Red Hat @@ -3009,9 +3008,9 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. +} + +#endif /* ENABLE_PKCS11 */ -diff -up openssh-8.6p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri.h ---- openssh-8.6p1/ssh-pkcs11-uri.h.pkcs11-uri 2021-04-19 14:57:30.318370565 +0200 -+++ openssh-8.6p1/ssh-pkcs11-uri.h 2021-04-19 14:57:30.318370565 +0200 +diff -up openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.h +--- openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri 2021-08-30 13:07:43.667700130 +0200 ++++ openssh-8.7p1/ssh-pkcs11-uri.h 2021-08-30 13:07:43.667700130 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 Red Hat diff --git a/openssh-8.0p1-restore-nonblock.patch b/openssh-8.0p1-restore-nonblock.patch deleted file mode 100644 index dbdf7ed..0000000 --- a/openssh-8.0p1-restore-nonblock.patch +++ /dev/null @@ -1,320 +0,0 @@ -diff --git a/channels.c b/channels.c -index 32d1f617..0024f751 100644 ---- a/channels.c -+++ b/channels.c -@@ -333,7 +333,27 @@ channel_register_fds(struct ssh *ssh, Channel *c, int rfd, int wfd, int efd, - #endif - - /* enable nonblocking mode */ -- if (nonblock) { -+ c->restore_block = 0; -+ if (nonblock == CHANNEL_NONBLOCK_STDIO) { -+ /* -+ * Special handling for stdio file descriptors: do not set -+ * non-blocking mode if they are TTYs. Otherwise prepare to -+ * restore their blocking state on exit to avoid interfering -+ * with other programs that follow. -+ */ -+ if (rfd != -1 && !isatty(rfd) && fcntl(rfd, F_GETFL) == 0) { -+ c->restore_block |= CHANNEL_RESTORE_RFD; -+ set_nonblock(rfd); -+ } -+ if (wfd != -1 && !isatty(wfd) && fcntl(wfd, F_GETFL) == 0) { -+ c->restore_block |= CHANNEL_RESTORE_WFD; -+ set_nonblock(wfd); -+ } -+ if (efd != -1 && !isatty(efd) && fcntl(efd, F_GETFL) == 0) { -+ c->restore_block |= CHANNEL_RESTORE_EFD; -+ set_nonblock(efd); -+ } -+ } else if (nonblock) { - if (rfd != -1) - set_nonblock(rfd); - if (wfd != -1) -@@ -422,17 +442,23 @@ channel_find_maxfd(struct ssh_channels *sc) - } - - int --channel_close_fd(struct ssh *ssh, int *fdp) -+channel_close_fd(struct ssh *ssh, Channel *c, int *fdp) - { - struct ssh_channels *sc = ssh->chanctxt; -- int ret = 0, fd = *fdp; -+ int ret, fd = *fdp; - -- if (fd != -1) { -- ret = close(fd); -- *fdp = -1; -- if (fd == sc->channel_max_fd) -- channel_find_maxfd(sc); -- } -+ if (fd == -1) -+ return 0; -+ -+ if ((*fdp == c->rfd && (c->restore_block & CHANNEL_RESTORE_RFD) != 0) || -+ (*fdp == c->wfd && (c->restore_block & CHANNEL_RESTORE_WFD) != 0) || -+ (*fdp == c->efd && (c->restore_block & CHANNEL_RESTORE_EFD) != 0)) -+ (void)fcntl(*fdp, F_SETFL, 0); /* restore blocking */ -+ -+ ret = close(fd); -+ *fdp = -1; -+ if (fd == sc->channel_max_fd) -+ channel_find_maxfd(sc); - return ret; - } - -@@ -442,13 +468,13 @@ channel_close_fds(struct ssh *ssh, Channel *c) - { - int sock = c->sock, rfd = c->rfd, wfd = c->wfd, efd = c->efd; - -- channel_close_fd(ssh, &c->sock); -+ channel_close_fd(ssh, c, &c->sock); - if (rfd != sock) -- channel_close_fd(ssh, &c->rfd); -+ channel_close_fd(ssh, c, &c->rfd); - if (wfd != sock && wfd != rfd) -- channel_close_fd(ssh, &c->wfd); -+ channel_close_fd(ssh, c, &c->wfd); - if (efd != sock && efd != rfd && efd != wfd) -- channel_close_fd(ssh, &c->efd); -+ channel_close_fd(ssh, c, &c->efd); - } - - static void -@@ -702,7 +728,7 @@ channel_stop_listening(struct ssh *ssh) - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_UNIX_LISTENER: - case SSH_CHANNEL_RUNIX_LISTENER: -- channel_close_fd(ssh, &c->sock); -+ channel_close_fd(ssh, c, &c->sock); - channel_free(ssh, c); - break; - } -@@ -1491,7 +1517,8 @@ channel_decode_socks5(Channel *c, struct sshbuf *input, struct sshbuf *output) - - Channel * - channel_connect_stdio_fwd(struct ssh *ssh, -- const char *host_to_connect, u_short port_to_connect, int in, int out) -+ const char *host_to_connect, u_short port_to_connect, -+ int in, int out, int nonblock) - { - Channel *c; - -@@ -1499,7 +1526,7 @@ channel_connect_stdio_fwd(struct ssh *ssh, - - c = channel_new(ssh, "stdio-forward", SSH_CHANNEL_OPENING, in, out, - -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, -- 0, "stdio-forward", /*nonblock*/0); -+ 0, "stdio-forward", nonblock); - - c->path = xstrdup(host_to_connect); - c->host_port = port_to_connect; -@@ -1649,7 +1676,7 @@ channel_post_x11_listener(struct ssh *ssh, Channel *c, - if (c->single_connection) { - oerrno = errno; - debug2("single_connection: closing X11 listener."); -- channel_close_fd(ssh, &c->sock); -+ channel_close_fd(ssh, c, &c->sock); - chan_mark_dead(ssh, c); - errno = oerrno; - } -@@ -2058,7 +2085,7 @@ channel_handle_efd_write(struct ssh *ssh, Channel *c, - return 1; - if (len <= 0) { - debug2("channel %d: closing write-efd %d", c->self, c->efd); -- channel_close_fd(ssh, &c->efd); -+ channel_close_fd(ssh, c, &c->efd); - } else { - if ((r = sshbuf_consume(c->extended, len)) != 0) - fatal_fr(r, "channel %i: consume", c->self); -@@ -2087,7 +2114,7 @@ channel_handle_efd_read(struct ssh *ssh, Channel *c, - return 1; - if (len <= 0) { - debug2("channel %d: closing read-efd %d", c->self, c->efd); -- channel_close_fd(ssh, &c->efd); -+ channel_close_fd(ssh, c, &c->efd); - } else if (c->extended_usage == CHAN_EXTENDED_IGNORE) - debug3("channel %d: discard efd", c->self); - else if ((r = sshbuf_put(c->extended, buf, len)) != 0) -diff --git a/channels.h b/channels.h -index 378d987c..6bf86b00 100644 ---- a/channels.h -+++ b/channels.h -@@ -63,6 +63,16 @@ - - #define CHANNEL_CANCEL_PORT_STATIC -1 - -+/* nonblocking flags for channel_new */ -+#define CHANNEL_NONBLOCK_LEAVE 0 /* don't modify non-blocking state */ -+#define CHANNEL_NONBLOCK_SET 1 /* set non-blocking state */ -+#define CHANNEL_NONBLOCK_STDIO 2 /* set non-blocking and restore on close */ -+ -+/* c->restore_block mask flags */ -+#define CHANNEL_RESTORE_RFD 0x01 -+#define CHANNEL_RESTORE_WFD 0x02 -+#define CHANNEL_RESTORE_EFD 0x04 -+ - /* TCP forwarding */ - #define FORWARD_DENY 0 - #define FORWARD_REMOTE (1) -@@ -139,6 +149,7 @@ struct Channel { - * to a matching pre-select handler. - * this way post-select handlers are not - * accidentally called if a FD gets reused */ -+ int restore_block; /* fd mask to restore blocking status */ - struct sshbuf *input; /* data read from socket, to be sent over - * encrypted connection */ - struct sshbuf *output; /* data received over encrypted connection for -@@ -266,7 +277,7 @@ void channel_register_filter(struct ssh *, int, channel_infilter_fn *, - void channel_register_status_confirm(struct ssh *, int, - channel_confirm_cb *, channel_confirm_abandon_cb *, void *); - void channel_cancel_cleanup(struct ssh *, int); --int channel_close_fd(struct ssh *, int *); -+int channel_close_fd(struct ssh *, Channel *, int *); - void channel_send_window_changes(struct ssh *); - - /* mux proxy support */ -@@ -313,7 +324,7 @@ Channel *channel_connect_to_port(struct ssh *, const char *, u_short, - char *, char *, int *, const char **); - Channel *channel_connect_to_path(struct ssh *, const char *, char *, char *); - Channel *channel_connect_stdio_fwd(struct ssh *, const char*, -- u_short, int, int); -+ u_short, int, int, int); - Channel *channel_connect_by_listen_address(struct ssh *, const char *, - u_short, char *, char *); - Channel *channel_connect_by_listen_path(struct ssh *, const char *, -diff --git a/clientloop.c b/clientloop.c -index 219f0e90..bdd67686 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -1405,14 +1405,6 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, - if (have_pty) - leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE); - -- /* restore blocking io */ -- if (!isatty(fileno(stdin))) -- unset_nonblock(fileno(stdin)); -- if (!isatty(fileno(stdout))) -- unset_nonblock(fileno(stdout)); -- if (!isatty(fileno(stderr))) -- unset_nonblock(fileno(stderr)); -- - /* - * If there was no shell or command requested, there will be no remote - * exit status to be returned. In that case, clear error code if the -diff --git a/mux.c b/mux.c -index faf4ef1e..9454bfed 100644 ---- a/mux.c -+++ b/mux.c -@@ -452,14 +452,6 @@ mux_master_process_new_session(struct ssh *ssh, u_int rid, - if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) - error_f("tcgetattr: %s", strerror(errno)); - -- /* enable nonblocking unless tty */ -- if (!isatty(new_fd[0])) -- set_nonblock(new_fd[0]); -- if (!isatty(new_fd[1])) -- set_nonblock(new_fd[1]); -- if (!isatty(new_fd[2])) -- set_nonblock(new_fd[2]); -- - window = CHAN_SES_WINDOW_DEFAULT; - packetmax = CHAN_SES_PACKET_DEFAULT; - if (cctx->want_tty) { -@@ -469,7 +461,7 @@ mux_master_process_new_session(struct ssh *ssh, u_int rid, - - nc = channel_new(ssh, "session", SSH_CHANNEL_OPENING, - new_fd[0], new_fd[1], new_fd[2], window, packetmax, -- CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); -+ CHAN_EXTENDED_WRITE, "client-session", CHANNEL_NONBLOCK_STDIO); - - nc->ctl_chan = c->self; /* link session -> control channel */ - c->remote_id = nc->self; /* link control -> session channel */ -@@ -1025,13 +1017,8 @@ mux_master_process_stdio_fwd(struct ssh *ssh, u_int rid, - } - } - -- /* enable nonblocking unless tty */ -- if (!isatty(new_fd[0])) -- set_nonblock(new_fd[0]); -- if (!isatty(new_fd[1])) -- set_nonblock(new_fd[1]); -- -- nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1]); -+ nc = channel_connect_stdio_fwd(ssh, chost, cport, new_fd[0], new_fd[1], -+ CHANNEL_NONBLOCK_STDIO); - free(chost); - - nc->ctl_chan = c->self; /* link session -> control channel */ -diff --git a/nchan.c b/nchan.c -index 4a4494b8..7ef3a350 100644 ---- a/nchan.c -+++ b/nchan.c -@@ -384,7 +384,7 @@ chan_shutdown_write(struct ssh *ssh, Channel *c) - c->istate, c->ostate, strerror(errno)); - } - } else { -- if (channel_close_fd(ssh, &c->wfd) < 0) { -+ if (channel_close_fd(ssh, c, &c->wfd) < 0) { - logit_f("channel %d: close() failed for " - "fd %d [i%d o%d]: %.100s", c->self, c->wfd, - c->istate, c->ostate, strerror(errno)); -@@ -412,7 +412,7 @@ chan_shutdown_read(struct ssh *ssh, Channel *c) - c->istate, c->ostate, strerror(errno)); - } - } else { -- if (channel_close_fd(ssh, &c->rfd) < 0) { -+ if (channel_close_fd(ssh, c, &c->rfd) < 0) { - logit_f("channel %d: close() failed for " - "fd %d [i%d o%d]: %.100s", c->self, c->rfd, - c->istate, c->ostate, strerror(errno)); -@@ -431,7 +431,7 @@ chan_shutdown_extended_read(struct ssh *ssh, Channel *c) - debug_f("channel %d: (i%d o%d sock %d wfd %d efd %d [%s])", - c->self, c->istate, c->ostate, c->sock, c->rfd, c->efd, - channel_format_extended_usage(c)); -- if (channel_close_fd(ssh, &c->efd) < 0) { -+ if (channel_close_fd(ssh, c, &c->efd) < 0) { - logit_f("channel %d: close() failed for " - "extended fd %d [i%d o%d]: %.100s", c->self, c->efd, - c->istate, c->ostate, strerror(errno)); -diff --git a/ssh.c b/ssh.c -index 696dc3bc..6243db76 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1876,9 +1876,10 @@ ssh_init_stdio_forwarding(struct ssh *ssh) - - if ((in = dup(STDIN_FILENO)) == -1 || - (out = dup(STDOUT_FILENO)) == -1) -- fatal("channel_connect_stdio_fwd: dup() in/out failed"); -+ fatal_f("dup() in/out failed"); - if ((c = channel_connect_stdio_fwd(ssh, options.stdio_forward_host, -- options.stdio_forward_port, in, out)) == NULL) -+ options.stdio_forward_port, in, out, -+ CHANNEL_NONBLOCK_STDIO)) == NULL) - fatal_f("channel_connect_stdio_fwd failed"); - channel_register_cleanup(ssh, c->self, client_cleanup_stdio_fwd, 0); - channel_register_open_confirm(ssh, c->self, ssh_stdio_confirm, NULL); -@@ -2074,14 +2075,6 @@ ssh_session2_open(struct ssh *ssh) - if (in == -1 || out == -1 || err == -1) - fatal("dup() in/out/err failed"); - -- /* enable nonblocking unless tty */ -- if (!isatty(in)) -- set_nonblock(in); -- if (!isatty(out)) -- set_nonblock(out); -- if (!isatty(err)) -- set_nonblock(err); -- - window = CHAN_SES_WINDOW_DEFAULT; - packetmax = CHAN_SES_PACKET_DEFAULT; - if (tty_flag) { -@@ -2091,7 +2084,7 @@ ssh_session2_open(struct ssh *ssh) - c = channel_new(ssh, - "session", SSH_CHANNEL_OPENING, in, out, err, - window, packetmax, CHAN_EXTENDED_WRITE, -- "client-session", /*nonblock*/0); -+ "client-session", CHANNEL_NONBLOCK_STDIO); - - debug3_f("channel_new: %d", c->self); - diff --git a/openssh-8.4p1-debian-compat.patch b/openssh-8.4p1-debian-compat.patch deleted file mode 100644 index 1285979..0000000 --- a/openssh-8.4p1-debian-compat.patch +++ /dev/null @@ -1,57 +0,0 @@ ---- compat.h.orig 2020-10-05 10:09:02.953505129 -0700 -+++ compat.h 2020-10-05 10:10:17.587733113 -0700 -@@ -34,7 +34,7 @@ - - #define SSH_BUG_UTF8TTYMODE 0x00000001 - #define SSH_BUG_SIGTYPE 0x00000002 --/* #define unused 0x00000004 */ -+#define SSH_BUG_SIGTYPE74 0x00000004 - /* #define unused 0x00000008 */ - #define SSH_OLD_SESSIONID 0x00000010 - /* #define unused 0x00000020 */ ---- compat.c.orig 2020-10-05 10:25:02.088720562 -0700 -+++ compat.c 2020-10-05 10:13:11.637282492 -0700 -@@ -65,11 +65,12 @@ - { "OpenSSH_6.5*," - "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD| - SSH_BUG_SIGTYPE}, -+ { "OpenSSH_7.4*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE| -+ SSH_BUG_SIGTYPE74}, - { "OpenSSH_7.0*," - "OpenSSH_7.1*," - "OpenSSH_7.2*," - "OpenSSH_7.3*," -- "OpenSSH_7.4*," - "OpenSSH_7.5*," - "OpenSSH_7.6*," - "OpenSSH_7.7*", SSH_NEW_OPENSSH|SSH_BUG_SIGTYPE}, ---- sshconnect2.c.orig 2020-09-26 07:26:37.618010545 -0700 -+++ sshconnect2.c 2020-10-05 10:47:22.116315148 -0700 -@@ -1305,6 +1305,26 @@ - break; - } - free(oallowed); -+ /* -+ * OpenSSH 7.4 supports SHA2 sig types, but fails to indicate its -+ * support. For that release, check the local policy against the -+ * SHA2 signature types. -+ */ -+ if (alg == NULL && -+ (key->type == KEY_RSA && (ssh->compat & SSH_BUG_SIGTYPE74))) { -+ oallowed = allowed = xstrdup(options.pubkey_accepted_algos); -+ while ((cp = strsep(&allowed, ",")) != NULL) { -+ if (sshkey_type_from_name(cp) != key->type) -+ continue; -+ tmp = match_list(sshkey_sigalg_by_name(cp), "rsa-sha2-256,rsa-sha2-512", NULL); -+ if (tmp != NULL) -+ alg = xstrdup(cp); -+ free(tmp); -+ if (alg != NULL) -+ break; -+ } -+ free(oallowed); -+ } - return alg; - } - - diff --git a/openssh-8.6p1-gsissh.patch b/openssh-8.6p1-gsissh.patch deleted file mode 100644 index 685dcd9..0000000 --- a/openssh-8.6p1-gsissh.patch +++ /dev/null @@ -1,2449 +0,0 @@ -diff -Nur openssh-8.6p1.orig/auth2.c openssh-8.6p1/auth2.c ---- openssh-8.6p1.orig/auth2.c 2021-05-04 10:47:33.443951396 +0200 -+++ openssh-8.6p1/auth2.c 2021-05-04 10:48:29.601078299 +0200 -@@ -277,7 +277,28 @@ - (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || - (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) - goto out; -- debug("userauth-request for user %s service %s method %s", user, service, method); -+ -+#ifdef GSSAPI -+ if (user[0] == '\0') { -+ debug("received empty username for %s", method); -+ if (strcmp(method, "gssapi-keyex") == 0) { -+ char *lname = NULL; -+ PRIVSEP(ssh_gssapi_localname(&lname)); -+ if (lname && lname[0] != '\0') { -+ free(user); -+ user = lname; -+ debug("set username to %s from gssapi context", user); -+ } else { -+ debug("failed to set username from gssapi context"); -+ ssh_packet_send_debug(ssh, -+ "failed to set username from gssapi context"); -+ } -+ } -+ } -+#endif -+ -+ debug("userauth-request for user %s service %s method %s", -+ user[0] ? user : "", service, method); - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - - #ifdef WITH_SELINUX -@@ -288,17 +309,42 @@ - if ((style = strchr(user, ':')) != NULL) - *style++ = 0; - -- if (authctxt->attempt++ == 0) { -- /* setup auth context */ -- authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); -+ /* If first time or username changed or empty username, -+ setup/reset authentication context. */ -+ if ((authctxt->attempt++ == 0) || -+ (strcmp(user, authctxt->user) != 0) || -+ (strcmp(user, "") == 0)) { -+ if (authctxt->user) { -+ free(authctxt->user); -+ authctxt->user = NULL; -+ } -+ authctxt->valid = 0; - authctxt->user = xstrdup(user); -- if (authctxt->pw && strcmp(service, "ssh-connection")==0) { -+ if (strcmp(service, "ssh-connection") != 0) { -+ ssh_packet_disconnect(ssh, "Unsupported service %s", -+ service); -+ } -+#ifdef GSSAPI -+ /* If we're going to set the username based on the -+ GSSAPI context later, then wait until then to -+ verify it. Just put in placeholders for now. */ -+ if ((strcmp(user, "") == 0) && -+ ((strcmp(method, "gssapi") == 0) || -+ (strcmp(method, "gssapi-with-mic") == 0))) { -+ authctxt->pw = fakepw(); -+ } else { -+#endif -+ authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); -+ if (authctxt->pw) { - authctxt->valid = 1; - debug2_f("setting up authctxt for %s", user); - } else { - /* Invalid user, fake password information */ - authctxt->pw = fakepw(); - } -+#ifdef GSSAPI -+ } /* endif for setting username based on GSSAPI context */ -+#endif - #ifdef USE_PAM - if (options.use_pam) - PRIVSEP(start_pam(ssh)); -@@ -307,6 +353,7 @@ - authctxt->valid ? "authenticating " : "invalid ", user); - setproctitle("%s%s", authctxt->valid ? user : "unknown", - use_privsep ? " [net]" : ""); -+ if (authctxt->attempt == 1) { - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; - #ifdef WITH_SELINUX -@@ -322,9 +369,10 @@ - if (auth2_setup_methods_lists(authctxt) != 0) - ssh_packet_disconnect(ssh, - "no authentication methods enabled"); -- } else if (strcmp(user, authctxt->user) != 0 || -- strcmp(service, authctxt->service) != 0) { -- ssh_packet_disconnect(ssh, "Change of username or service " -+ } -+ } -+ if (strcmp(service, authctxt->service) != 0) { -+ ssh_packet_disconnect(ssh, "Change of service " - "not allowed: (%s,%s) -> (%s,%s)", - authctxt->user, authctxt->service, user, service); - } -diff -Nur openssh-8.6p1.orig/auth2-gss.c openssh-8.6p1/auth2-gss.c ---- openssh-8.6p1.orig/auth2-gss.c 2021-05-04 10:47:33.342951168 +0200 -+++ openssh-8.6p1/auth2-gss.c 2021-05-04 10:48:29.602078301 +0200 -@@ -50,6 +50,7 @@ - - extern ServerOptions options; - -+static void ssh_gssapi_userauth_error(Gssctxt *ctxt, struct ssh *ssh); - static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); - static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); - static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); -@@ -63,8 +64,8 @@ - { - Authctxt *authctxt = ssh->authctxt; - int r, authenticated = 0; -- struct sshbuf *b = NULL; -- gss_buffer_desc mic, gssbuf; -+ struct sshbuf *b = NULL, *b2 = NULL; -+ gss_buffer_desc mic, gssbuf, gssbuf2; - u_char *p; - size_t len; - -@@ -75,6 +76,9 @@ - if ((b = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - -+ if ((b2 = sshbuf_new()) == NULL) -+ fatal_f("sshbuf_new failed"); -+ - mic.value = p; - mic.length = len; - -@@ -85,13 +89,29 @@ - fatal_f("sshbuf_mutable_ptr failed"); - gssbuf.length = sshbuf_len(b); - -+ /* client may have used empty username to determine target -+ name from GSSAPI context */ -+ ssh_gssapi_buildmic(b2, "", authctxt->service, "gssapi-keyex", -+ ssh->kex->session_id); -+ -+ if ((gssbuf2.value = sshbuf_mutable_ptr(b2)) == NULL) -+ fatal_f("sshbuf_mutable_ptr failed"); -+ gssbuf2.length = sshbuf_len(b2); -+ - /* gss_kex_context is NULL with privsep, so we can't check it here */ - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -- &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 1)); -+ &gssbuf, &mic))) || -+ !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf2, &mic)))) { -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); -+ } -+ } - - sshbuf_free(b); -+ sshbuf_free(b2); - free(mic.value); - - return (authenticated); -@@ -146,7 +166,9 @@ - return (0); - } - -- if (!authctxt->valid || authctxt->user == NULL) { -+ /* authctxt->valid may be 0 if we haven't yet determined -+ username from gssapi context. */ -+ if (authctxt->user == NULL) { - debug2_f("disabled because of invalid user"); - free(doid); - return (0); -@@ -184,7 +206,7 @@ - Gssctxt *gssctxt; - gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; - gss_buffer_desc recv_tok; -- OM_uint32 maj_status, min_status, flags; -+ OM_uint32 maj_status, min_status, flags = 0; - u_char *p; - size_t len; - int r; -@@ -205,6 +227,7 @@ - free(p); - - if (GSS_ERROR(maj_status)) { -+ ssh_gssapi_userauth_error(gssctxt, ssh); - if (send_tok.length != 0) { - if ((r = sshpkt_start(ssh, - SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 || -@@ -279,6 +302,34 @@ - return 0; - } - -+static void -+gssapi_set_username(struct ssh *ssh) -+{ -+ Authctxt *authctxt = ssh->authctxt; -+ char *lname = NULL; -+ -+ if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { -+ PRIVSEP(ssh_gssapi_localname(&lname)); -+ if (lname && lname[0] != '\0') { -+ if (authctxt->user) free(authctxt->user); -+ authctxt->user = lname; -+ debug("set username to %s from gssapi context", lname); -+ authctxt->pw = PRIVSEP(getpwnamallow(ssh, authctxt->user)); -+ if (authctxt->pw) { -+ authctxt->valid = 1; -+#ifdef USE_PAM -+ if (options.use_pam) -+ PRIVSEP(start_pam(ssh)); -+#endif -+ } -+ } else { -+ debug("failed to set username from gssapi context"); -+ ssh_packet_send_debug(ssh, -+ "failed to set username from gssapi context"); -+ } -+ } -+} -+ - /* - * This is called when the client thinks we've completed authentication. - * It should only be enabled in the dispatch handler by the function above, -@@ -289,12 +340,14 @@ - input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) - { - Authctxt *authctxt = ssh->authctxt; -- int r, authenticated; -+ int r, authenticated = 0; - const char *displayname; - - if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) - fatal("No authentication or GSSAPI context"); - -+ gssapi_set_username(ssh); -+ - /* - * We don't need to check the status, because we're only enabled in - * the dispatcher once the exchange is complete -@@ -303,8 +356,11 @@ - if ((r = sshpkt_get_end(ssh)) != 0) - fatal_fr(r, "parse packet"); - -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 1)); -+ /* user should be set if valid but we double-check here */ -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); -+ } - - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -356,11 +412,17 @@ - fatal_f("sshbuf_mutable_ptr failed"); - gssbuf.length = sshbuf_len(b); - -- if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 0)); -- else -+ gssapi_set_username(ssh); -+ -+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) { -+ if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0)); -+ } -+ } else { - logit("GSSAPI MIC check failed"); -+ } - - sshbuf_free(b); - if (micuser != authctxt->user) -@@ -380,6 +442,26 @@ - return 0; - } - -+static void ssh_gssapi_userauth_error(Gssctxt *ctxt, struct ssh *ssh) { -+ char *errstr; -+ OM_uint32 maj, min; -+ int r; -+ -+ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); -+ if (errstr) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_USERAUTH_GSSAPI_ERROR)) != 0 || -+ (r = sshpkt_put_u32(ssh, maj)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_cstring(ssh, errstr)) != 0 || -+ (r = sshpkt_put_cstring(ssh, "")) != 0 || -+ (r = sshpkt_send(ssh)) != 0 || -+ (r = ssh_packet_write_wait(ssh)) != 0) -+ fatal_fr(r, ""); -+ free(errstr); -+ } -+} -+ - Authmethod method_gsskeyex = { - "gssapi-keyex", - userauth_gsskeyex, -diff -Nur openssh-8.6p1.orig/auth.c openssh-8.6p1/auth.c ---- openssh-8.6p1.orig/auth.c 2021-05-04 10:47:33.445951400 +0200 -+++ openssh-8.6p1/auth.c 2021-05-04 10:48:29.603078303 +0200 -@@ -344,7 +344,8 @@ - method, - submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, - authctxt->valid ? "" : "invalid user ", -- authctxt->user, -+ (authctxt->user && authctxt->user[0]) ? -+ authctxt->user : "unknown", - ssh_remote_ipaddr(ssh), - ssh_remote_port(ssh), - extra != NULL ? ": " : "", -@@ -586,13 +587,18 @@ - #endif - - pw = getpwnam(user); -+#ifdef USE_PAM -+ if (options.use_pam && options.permit_pam_user_change && pw == NULL) -+ pw = sshpam_getpw(user); -+#endif - - #if defined(_AIX) && defined(HAVE_SETAUTHDB) - aix_restoreauthdb(); - #endif - if (pw == NULL) { - logit("Invalid user %.100s from %.100s port %d", -- user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); -+ (user && user[0]) ? user : "unknown", -+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); - #ifdef CUSTOM_FAILED_LOGIN - record_failed_login(ssh, user, - auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); -diff -Nur openssh-8.6p1.orig/auth.h openssh-8.6p1/auth.h ---- openssh-8.6p1.orig/auth.h 2021-05-04 10:47:33.445951400 +0200 -+++ openssh-8.6p1/auth.h 2021-05-04 10:48:29.603078303 +0200 -@@ -83,6 +83,8 @@ - krb5_principal krb5_user; - char *krb5_ticket_file; - char *krb5_ccname; -+#endif -+#ifdef GSSAPI - int krb5_set_env; - #endif - struct sshbuf *loginmsg; -diff -Nur openssh-8.6p1.orig/auth-pam.c openssh-8.6p1/auth-pam.c ---- openssh-8.6p1.orig/auth-pam.c 2021-05-04 10:47:33.440951389 +0200 -+++ openssh-8.6p1/auth-pam.c 2021-05-04 10:48:29.604078305 +0200 -@@ -253,6 +253,7 @@ - static char *sshpam_rhost = NULL; - static char *sshpam_laddr = NULL; - static char *sshpam_conninfo = NULL; -+static struct ssh *sshpam_ssh = NULL; - - /* Some PAM implementations don't implement this */ - #ifndef HAVE_PAM_GETENVLIST -@@ -301,6 +302,56 @@ - # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) - #endif - -+struct passwd * -+sshpam_getpw(const char *user) -+{ -+ struct passwd *pw; -+ -+ if ((pw = getpwnam(user)) != NULL) -+ return(pw); -+ -+ debug("PAM: faking passwd struct for user '%.100s'", user); -+ if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) -+ return NULL; -+ pw->pw_name = xstrdup(user); /* XXX leak */ -+ pw->pw_shell = "/bin/true"; -+ pw->pw_gecos = "sshd fake PAM user"; -+ return (pw); -+} -+ -+void -+sshpam_check_userchanged(void) -+{ -+ int sshpam_err; -+ struct passwd *pw; -+ const char *user; -+ -+ debug("sshpam_check_userchanged"); -+ sshpam_err = pam_get_item(sshpam_handle, PAM_USER, -+ (sshpam_const void **)&user); -+ if (sshpam_err != PAM_SUCCESS) -+ fatal("PAM: could not get PAM_USER: %s", -+ pam_strerror(sshpam_handle, sshpam_err)); -+ debug("sshpam_check_userchanged: user was '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { -+ debug("PAM: user mapped from '%.100s' to '%.100s'", -+ sshpam_authctxt->pw->pw_name, user); -+ if ((pw = getpwnam(user)) == NULL) -+ fatal("PAM: could not get passwd entry for user " -+ "'%.100s' provided by PAM_USER", user); -+ pwfree(sshpam_authctxt->pw); -+ sshpam_authctxt->pw = pwcopy(pw); -+ sshpam_authctxt->valid = allowed_user(sshpam_ssh, pw); -+ free(sshpam_authctxt->user); -+ sshpam_authctxt->user = xstrdup(user); -+ debug("PAM: user '%.100s' now %svalid", user, -+ sshpam_authctxt->valid ? "" : "in"); -+ } -+ debug("sshpam_check_userchanged: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+} -+ - static void - sshpam_password_change_required(int reqd) - { -@@ -332,7 +383,7 @@ - static void - import_environments(struct sshbuf *b) - { -- char *env; -+ char *env, *user; - u_int n, i, num_env; - int r; - -@@ -348,6 +399,19 @@ - if ((r = sshbuf_get_u32(b, &n)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - sshpam_password_change_required(n != 0); -+ if (options.permit_pam_user_change) { -+ if ((r = sshbuf_get_cstring(b, &user, NULL)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ debug("PAM: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ debug("PAM: got username '%.100s' from thread", user); -+ if ((sshpam_err = pam_set_item(sshpam_handle, PAM_USER, user)) -+ != PAM_SUCCESS) -+ fatal("PAM: failed to set PAM_USER: %s", -+ pam_strerror(sshpam_handle, sshpam_err)); -+ pwfree(sshpam_authctxt->pw); -+ sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); -+ } - - /* Import environment from subprocess */ - if ((r = sshbuf_get_u32(b, &num_env)) != 0) -@@ -522,6 +586,13 @@ - if (sshpam_err != PAM_SUCCESS) - goto auth_fail; - -+ if (options.permit_pam_user_change) { -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ sshpam_check_userchanged(); -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ } - if (!do_pam_account()) { - /* Preserve PAM_PERM_DENIED and PAM_USER_UNKNOWN. - * Backward compatibility for other errors. */ -@@ -546,6 +617,13 @@ - if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 || - (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ if (options.permit_pam_user_change) { -+ debug("sshpam_thread: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ if ((r = sshbuf_put_cstring(buffer, -+ sshpam_authctxt->pw->pw_name)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ } - - /* Export any environment strings set in child */ - for (i = 0; environ[i] != NULL; i++) { -@@ -738,6 +816,8 @@ - xasprintf(&sshpam_conninfo, "SSH_CONNECTION=%.50s %d %.50s %d", - ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), - sshpam_laddr, ssh_local_port(ssh)); -+ /* Save so allowed_user can be called later */ -+ sshpam_ssh = ssh; - } - if (sshpam_rhost != NULL) { - debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); -@@ -1082,6 +1162,18 @@ - debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, - pam_strerror(sshpam_handle, sshpam_err)); - -+ if (options.permit_pam_user_change) { -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ sshpam_check_userchanged(); -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) -+ fatal("PAM: completed authentication but PAM account invalid"); -+ debug("do_pam_account: user is '%.100s'", -+ sshpam_authctxt->pw->pw_name); -+ } -+ - if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { - sshpam_account_status = 0; - return (sshpam_account_status); -@@ -1370,6 +1462,9 @@ - pam_strerror(sshpam_handle, sshpam_err)); - - sshpam_err = pam_authenticate(sshpam_handle, flags); -+ if (options.permit_pam_user_change) { -+ sshpam_check_userchanged(); -+ } - sshpam_password = NULL; - free(fake); - if (sshpam_err == PAM_MAXTRIES) -diff -Nur openssh-8.6p1.orig/auth-pam.h openssh-8.6p1/auth-pam.h ---- openssh-8.6p1.orig/auth-pam.h 2021-05-04 10:47:33.303951079 +0200 -+++ openssh-8.6p1/auth-pam.h 2021-05-04 10:48:29.604078305 +0200 -@@ -43,5 +43,6 @@ - int sshpam_get_maxtries_reached(void); - void sshpam_set_maxtries_reached(int); - int is_pam_session_open(void); -+struct passwd *sshpam_getpw(const char *); - - #endif /* USE_PAM */ -diff -Nur openssh-8.6p1.orig/canohost.c openssh-8.6p1/canohost.c ---- openssh-8.6p1.orig/canohost.c 2021-05-04 10:47:33.343951170 +0200 -+++ openssh-8.6p1/canohost.c 2021-05-04 10:48:29.605078308 +0200 -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include /* for MAXHOSTNAMELEN */ - - #include - #include -@@ -295,3 +296,33 @@ - { - return get_sock_port(sock, 1); - } -+ -+void -+resolve_localhost(char **host) -+{ -+ struct hostent *hostinfo; -+ -+ hostinfo = gethostbyname(*host); -+ if (hostinfo == NULL || hostinfo->h_name == NULL) { -+ debug("gethostbyname(%s) failed", *host); -+ return; -+ } -+ if (hostinfo->h_addrtype == AF_INET) { -+ struct in_addr addr; -+ addr = *(struct in_addr *)(hostinfo->h_addr); -+ if (ntohl(addr.s_addr) == INADDR_LOOPBACK) { -+ char buf[MAXHOSTNAMELEN]; -+ if (gethostname(buf, sizeof(buf)) < 0) { -+ debug("gethostname() failed"); -+ return; -+ } -+ hostinfo = gethostbyname(buf); -+ free(*host); -+ if (hostinfo == NULL || hostinfo->h_name == NULL) { -+ *host = xstrdup(buf); -+ } else { -+ *host = xstrdup(hostinfo->h_name); -+ } -+ } -+ } -+} -diff -Nur openssh-8.6p1.orig/canohost.h openssh-8.6p1/canohost.h ---- openssh-8.6p1.orig/canohost.h 2021-05-04 10:47:33.343951170 +0200 -+++ openssh-8.6p1/canohost.h 2021-05-04 10:48:29.605078308 +0200 -@@ -26,4 +26,6 @@ - - #endif /* _CANOHOST_H */ - -+void resolve_localhost(char **host); -+ - void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); -diff -Nur openssh-8.6p1.orig/configure.ac openssh-8.6p1/configure.ac ---- openssh-8.6p1.orig/configure.ac 2021-05-04 10:47:33.430951367 +0200 -+++ openssh-8.6p1/configure.ac 2021-05-04 10:48:29.607078312 +0200 -@@ -4718,6 +4718,14 @@ - AC_CHECK_HEADER([gssapi_krb5.h], , - [ CPPFLAGS="$oldCPP" ]) - -+ # If we're using some other GSSAPI -+ if test -n "$GSSAPI" ; then -+ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.]) -+ fi -+ -+ if test -z "$GSSAPI"; then -+ GSSAPI="KRB5"; -+ fi - fi - if test -n "${rpath_opt}" ; then - LDFLAGS="$LDFLAGS ${rpath_opt}${KRB5ROOT}/lib" -@@ -4757,6 +4765,40 @@ - AC_SUBST([GSSLIBS]) - AC_SUBST([K5LIBS]) - -+# Check whether the user wants GSI (Globus) support -+gsi="no" -+AC_ARG_WITH(gsi, -+ [ --with-gsi Enable Globus GSI authentication support], -+ [ -+ gsi="$withval" -+ ] -+) -+ -+if test "x$gsi" != "xno" ; then -+ # Globus GSSAPI configuration -+ AC_MSG_CHECKING(for Globus GSI) -+ AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.]) -+ -+ if test -n "$GSSAPI" ; then -+ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.]) -+ fi -+ -+ if test -z "$GSSAPI" ; then -+ GSSAPI="GSI" -+ fi -+ -+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) -+ if test "x$PKGCONFIG" != "xno"; then -+ LIBS="$LIBS `$PKGCONFIG --libs globus-gss-assist globus-gssapi-gsi globus-common`" -+ CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags globus-gss-assist globus-gssapi-gsi globus-common`" -+ fi -+ -+ AC_DEFINE(GSSAPI) -+ AC_DEFINE(HAVE_GSSAPI_H) -+ -+ AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) -+fi -+ - # Check whether user wants systemd support - SYSTEMD_MSG="no" - AC_ARG_WITH(systemd, -diff -Nur openssh-8.6p1.orig/gss-genr.c openssh-8.6p1/gss-genr.c ---- openssh-8.6p1.orig/gss-genr.c 2021-05-04 10:47:33.465951446 +0200 -+++ openssh-8.6p1/gss-genr.c 2021-05-04 10:48:29.607078312 +0200 -@@ -40,6 +40,7 @@ - #include "ssherr.h" - #include "sshbuf.h" - #include "log.h" -+#include "canohost.h" - #include "ssh2.h" - #include "cipher.h" - #include "sshkey.h" -@@ -408,9 +409,18 @@ - ssh_gssapi_import_name(Gssctxt *ctx, const char *host) - { - gss_buffer_desc gssbuf; -+ char *xhost; - char *val; - -- xasprintf(&val, "host@%s", host); -+ /* Make a copy of the host name, in case it was returned by a -+ * previous call to gethostbyname(). */ -+ xhost = xstrdup(host); -+ -+ /* Make sure we have the FQDN. Some GSSAPI implementations don't do -+ * this for us themselves */ -+ resolve_localhost(&xhost); -+ -+ xasprintf(&val, "host@%s", xhost); - gssbuf.value = val; - gssbuf.length = strlen(gssbuf.value); - -@@ -418,6 +428,7 @@ - &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) - ssh_gssapi_error(ctx); - -+ free(xhost); - free(gssbuf.value); - return (ctx->major); - } -diff -Nur openssh-8.6p1.orig/gss-serv.c openssh-8.6p1/gss-serv.c ---- openssh-8.6p1.orig/gss-serv.c 2021-05-04 10:47:33.369951229 +0200 -+++ openssh-8.6p1/gss-serv.c 2021-05-04 10:48:29.608078315 +0200 -@@ -50,10 +50,12 @@ - #include "monitor_wrap.h" - - extern ServerOptions options; -+extern Authctxt *the_authctxt; - - static ssh_gssapi_client gssapi_client = -- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, -- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; -+ { {0, NULL}, GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, -+ GSS_C_NO_NAME, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, -+ GSS_C_NO_CONTEXT, 0, 0}; - - ssh_gssapi_mech gssapi_null_mech = - { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; -@@ -61,14 +63,26 @@ - #ifdef KRB5 - extern ssh_gssapi_mech gssapi_kerberos_mech; - #endif -+#ifdef GSI -+extern ssh_gssapi_mech gssapi_gsi_mech; -+extern ssh_gssapi_mech gssapi_gsi_mech_micv2; -+#endif - - ssh_gssapi_mech* supported_mechs[]= { - #ifdef KRB5 - &gssapi_kerberos_mech, - #endif -+#ifdef GSI -+ &gssapi_gsi_mech_micv2, -+ &gssapi_gsi_mech, -+#endif - &gssapi_null_mech, - }; - -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+static int limited = 0; -+#endif -+ - /* - * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the - * list of supported mechanisms before privsep is set up. -@@ -229,6 +243,10 @@ - (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { - if (ssh_gssapi_getclient(ctx, &gssapi_client)) - fatal("Couldn't convert client name"); -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+ if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG)) -+ limited=1; -+#endif - } - - return (status); -@@ -248,6 +266,20 @@ - - tok = ename->value; - -+#ifdef GSI /* GSI gss_export_name() is broken. */ -+ if (((ctx->oid->length == gssapi_gsi_mech.oid.length) && -+ (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements, -+ gssapi_gsi_mech.oid.length) == 0)) || -+ ((ctx->oid->length == gssapi_gsi_mech_micv2.oid.length) && -+ (memcmp(ctx->oid->elements, gssapi_gsi_mech_micv2.oid.elements, -+ gssapi_gsi_mech_micv2.oid.length) == 0))) { -+ name->length = ename->length; -+ name->value = xmalloc(ename->length+1); -+ memcpy(name->value, ename->value, ename->length); -+ return GSS_S_COMPLETE; -+ } -+#endif -+ - /* - * Check that ename is long enough for all of the fixed length - * header, and that the initial ID bytes are correct -@@ -308,21 +340,24 @@ - gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; - - if (options.gss_store_rekey && client->used && ctx->client_creds) { -- if (client->mech->oid.length != ctx->oid->length || -- (memcmp(client->mech->oid.elements, -+ if (client->oid.length != ctx->oid->length || -+ (memcmp(client->oid.elements, - ctx->oid->elements, ctx->oid->length) !=0)) { - debug("Rekeyed credentials have different mechanism"); - return GSS_S_COMPLETE; - } - -- if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -- ctx->client_creds, ctx->oid, &new_name, -+ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech -+ because GSI doesn't support the latter. -jbasney */ -+ -+ if ((ctx->major = gss_inquire_cred(&ctx->minor, -+ ctx->client_creds, &new_name, - NULL, NULL, NULL))) { - ssh_gssapi_error(ctx); - return (ctx->major); - } - -- ctx->major = gss_compare_name(&ctx->minor, client->name, -+ ctx->major = gss_compare_name(&ctx->minor, client->cred_name, - new_name, &equal); - - if (GSS_ERROR(ctx->major)) { -@@ -337,9 +372,9 @@ - - debug("Marking rekeyed credentials for export"); - -- gss_release_name(&ctx->minor, &client->name); -+ gss_release_name(&ctx->minor, &client->cred_name); - gss_release_cred(&ctx->minor, &client->creds); -- client->name = new_name; -+ client->cred_name = new_name; - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; - client->updated = 1; -@@ -356,12 +391,17 @@ - i++; - } - -+ if (client->oid.elements == NULL) -+ client->oid = *ctx->oid; - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech -+ because GSI doesn't support the latter. -jbasney */ -+ - if (ctx->client_creds && -- (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -- ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ (ctx->major = gss_inquire_cred(&ctx->minor, -+ ctx->client_creds, &client->cred_name, NULL, NULL, NULL))) { - ssh_gssapi_error(ctx); - return (ctx->major); - } -@@ -378,16 +418,25 @@ - return (ctx->major); - } - -- if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, -+ if ((client->mech->oid.elements != NULL) && -+ (ctx->major = ssh_gssapi_parse_ename(ctx,&ename, - &client->exportedname))) { - return (ctx->major); - } - -+ if ((ctx->major = gss_duplicate_name(&ctx->minor, ctx->client, -+ &client->ctx_name))) -+ return ctx->major; -+ - gss_release_buffer(&ctx->minor, &ename); - - /* We can't copy this structure, so we just move the pointer to it */ - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ -+ /* needed for globus_gss_assist_map_and_authorize() */ -+ client->context = ctx->context; -+ - return (ctx->major); - } - -@@ -395,6 +444,7 @@ - void - ssh_gssapi_cleanup_creds(void) - { -+#ifdef KRB5 - krb5_ccache ccache = NULL; - krb5_error_code problem; - -@@ -410,6 +460,14 @@ - gssapi_client.store.data = NULL; - } - } -+#else -+ if (gssapi_client.store.filename != NULL) { -+ /* Unlink probably isn't sufficient */ -+ debug("removing gssapi cred file\"%s\"", -+ gssapi_client.store.filename); -+ unlink(gssapi_client.store.filename); -+ } -+#endif - } - - /* As user */ -@@ -417,6 +475,11 @@ - ssh_gssapi_storecreds(void) - { - if (gssapi_client.mech && gssapi_client.mech->storecreds) { -+ if (options.gss_creds_path) { -+ gssapi_client.store.filename = -+ expand_authorized_keys(options.gss_creds_path, -+ the_authctxt->pw); -+ } - return (*gssapi_client.mech->storecreds)(&gssapi_client); - } else - debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); -@@ -449,11 +512,13 @@ - - (void) kex; /* used in privilege separation */ - -- if (gssapi_client.exportedname.length == 0 || -- gssapi_client.exportedname.value == NULL) { -- debug("No suitable client data"); -+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG -+ if (limited && options.gsi_allow_limited_proxy != 1) { -+ debug("limited proxy not acceptable for remote login"); - return 0; - } -+#endif -+ - if (gssapi_client.mech && gssapi_client.mech->userok) - if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { - gssapi_client.used = 1; -@@ -464,6 +529,7 @@ - gss_release_buffer(&lmin, &gssapi_client.displayname); - gss_release_buffer(&lmin, &gssapi_client.exportedname); - gss_release_cred(&lmin, &gssapi_client.creds); -+ gss_release_name(&lmin, &gssapi_client.ctx_name); - explicit_bzero(&gssapi_client, - sizeof(ssh_gssapi_client)); - return 0; -@@ -473,6 +539,24 @@ - return (0); - } - -+/* Priviledged */ -+int -+ssh_gssapi_localname(char **user) -+{ -+ *user = NULL; -+ if (gssapi_client.displayname.length == 0 || -+ gssapi_client.displayname.value == NULL) { -+ debug("No suitable client data"); -+ return (0); -+ } -+ if (gssapi_client.mech && gssapi_client.mech->localname) { -+ return((*gssapi_client.mech->localname)(&gssapi_client,user)); -+ } else { -+ debug("Unknown client authentication type"); -+ } -+ return (0); -+} -+ - /* These bits are only used for rekeying. The unpriviledged child is running - * as the user, the monitor is root. - * -@@ -499,9 +583,11 @@ - pam_handle_t *pamh = NULL; - struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; - char *envstr; -+ char **p; char **pw; - #endif - -- if (gssapi_client.store.envval == NULL) -+ if (gssapi_client.store.filename == NULL && -+ gssapi_client.store.envval == NULL) - return; - - ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -@@ -526,6 +612,18 @@ - if (ret) - return; - -+ /* Put ssh pam stack env variables in this new pam stack env -+ * Using pam-pkinit, KRB5CCNAME is set during do_pam_session -+ * this addition enables pam-pkinit to access KRB5CCNAME if used -+ * in sshd-rekey stack too -+ */ -+ pw = p = fetch_pam_environment(); -+ while ( *pw != NULL ) { -+ pam_putenv(pamh, *pw); -+ pw++; -+ } -+ free_pam_environment(p); -+ - xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, - gssapi_client.store.envval); - -diff -Nur openssh-8.6p1.orig/gss-serv-gsi.c openssh-8.6p1/gss-serv-gsi.c ---- openssh-8.6p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-8.6p1/gss-serv-gsi.c 2021-05-04 10:48:29.609078317 +0200 -@@ -0,0 +1,328 @@ -+/* -+ * Copyright (c) 2001-2003 Simon Wilkinson. 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 "includes.h" -+ -+#ifdef GSSAPI -+#ifdef GSI -+ -+#include -+ -+#include -+#include -+ -+#include "xmalloc.h" -+#include "hostfile.h" -+#include "auth.h" -+#include "log.h" -+#include "misc.h" -+#include "servconf.h" -+#include "ssh-gss.h" -+ -+extern ServerOptions options; -+ -+#include -+ -+static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name); -+static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user); -+static int ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client); -+static int ssh_gssapi_gsi_storecreds_micv2(ssh_gssapi_client *client); -+static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client); -+static int ssh_gssapi_gsi_updatecreds_micv2(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client); -+ -+ssh_gssapi_mech gssapi_gsi_mech = { -+ "dZuIebMjgUqaxvbF7hDbAw==", -+ "GSI", -+ {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}, -+ NULL, -+ &ssh_gssapi_gsi_userok, -+ &ssh_gssapi_gsi_localname, -+ &ssh_gssapi_gsi_storecreds, -+ &ssh_gssapi_gsi_updatecreds -+}; -+ -+ssh_gssapi_mech gssapi_gsi_mech_micv2 = { -+ "vz8J1E9PzLr8b1K+0remTg==", -+ "GSI", -+ {10, "\x2b\x06\x01\x04\x01\x9b\x50\x01\x01\x01"}, -+ NULL, -+ &ssh_gssapi_gsi_userok, -+ &ssh_gssapi_gsi_localname, -+ &ssh_gssapi_gsi_storecreds_micv2, -+ &ssh_gssapi_gsi_updatecreds_micv2 -+}; -+ -+/* -+ * Check if this user is OK to login under GSI. User has been authenticated -+ * as identity in global 'client_name.value' and is trying to log in as passed -+ * username in 'name'. -+ * -+ * Returns non-zero if user is authorized, 0 otherwise. -+ */ -+static int -+ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name) -+{ -+ int authorized = 0; -+ globus_result_t res; -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ char lname[256] = ""; -+#endif -+ -+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE -+ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { -+ return 0; -+ } -+#endif -+ -+/* use new globus_gss_assist_map_and_authorize() interface if available */ -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ debug("calling globus_gss_assist_map_and_authorize()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", -+ name, lname, 256))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ } else if (lname[0] && strcmp(name, lname) != 0) { -+ debug("GSI user maps to %s, not %s", lname, name); -+ } else { -+ authorized = 1; -+ } -+#else -+ debug("calling globus_gss_assist_userok()"); -+ if (GLOBUS_SUCCESS != -+ (res = (globus_gss_assist_userok(client->displayname.value, -+ name)))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ } else { -+ authorized = 1; -+ } -+#endif -+ -+ logit("GSI user %s is%s authorized as target user %s", -+ (char *) client->displayname.value, (authorized ? "" : " not"), name); -+ -+ return authorized; -+} -+ -+/* -+ * Return the local username associated with the GSI credentials. -+ */ -+int -+ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user) -+{ -+ globus_result_t res; -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ char lname[256] = ""; -+#endif -+ -+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE -+ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { -+ return 0; -+ } -+#endif -+ -+/* use new globus_gss_assist_map_and_authorize() interface if available */ -+#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE -+ debug("calling globus_gss_assist_map_and_authorize()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", -+ NULL, lname, 256))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ logit("failed to map GSI user %s", (char *)client->displayname.value); -+ return 0; -+ } -+ *user = strdup(lname); -+#else -+ debug("calling globus_gss_assist_gridmap()"); -+ if (GLOBUS_SUCCESS != -+ (res = globus_gss_assist_gridmap(client->displayname.value, user))) { -+ debug("%s", globus_error_print_chain(globus_error_get(res))); -+ logit("failed to map GSI user %s", (char *)client->displayname.value); -+ return 0; -+ } -+#endif -+ -+ logit("GSI user %s mapped to target user %s", -+ (char *) client->displayname.value, *user); -+ -+ return 1; -+} -+ -+/* -+ * Export GSI credentials to disk. -+ */ -+static int -+ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) -+{ -+ OM_uint32 major_status; -+ OM_uint32 minor_status; -+ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; -+ char * p; -+ -+ if (!client || !client->creds) { -+ return 0; -+ } -+ -+ major_status = gss_export_cred(&minor_status, -+ client->creds, -+ GSS_C_NO_OID, -+ 1, -+ &export_cred); -+ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { -+ Gssctxt *ctx; -+ ssh_gssapi_build_ctx(&ctx); -+ ctx->major = major_status; -+ ctx->minor = minor_status; -+ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid); -+ ssh_gssapi_error(ctx); -+ ssh_gssapi_delete_ctx(&ctx); -+ return 0; -+ } -+ -+ p = strchr((char *) export_cred.value, '='); -+ if (p == NULL) { -+ logit("Failed to parse exported credentials string '%.100s'", -+ (char *)export_cred.value); -+ gss_release_buffer(&minor_status, &export_cred); -+ return 0; -+ } -+ *p++ = '\0'; -+ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { -+ client->store.envvar = strdup("X509_USER_PROXY"); -+ } else { -+ client->store.envvar = strdup((char *)export_cred.value); -+ } -+ if (access(p, R_OK) == 0) { -+ if (client->store.filename) { -+ if (rename(p, client->store.filename) < 0) { -+ logit("Failed to rename %s to %s: %s", p, -+ client->store.filename, strerror(errno)); -+ free(client->store.filename); -+ client->store.filename = strdup(p); -+ } else { -+ p = client->store.filename; -+ } -+ } else { -+ client->store.filename = strdup(p); -+ } -+ } -+ client->store.envval = strdup(p); -+#ifdef USE_PAM -+ if (options.use_pam) -+ do_pam_putenv(client->store.envvar, client->store.envval); -+#endif -+ gss_release_buffer(&minor_status, &export_cred); -+ -+ return 1; -+} -+ -+/* -+ * Export GSI credentials to disk. -+ */ -+static int -+ssh_gssapi_gsi_storecreds_micv2(ssh_gssapi_client *client) -+{ -+ OM_uint32 major_status; -+ OM_uint32 minor_status; -+ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; -+ char * p; -+ -+ if (!client || !client->creds) { -+ return 0; -+ } -+ -+ major_status = gss_export_cred(&minor_status, -+ client->creds, -+ GSS_C_NO_OID, -+ 1, -+ &export_cred); -+ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { -+ Gssctxt *ctx; -+ ssh_gssapi_build_ctx(&ctx); -+ ctx->major = major_status; -+ ctx->minor = minor_status; -+ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech_micv2.oid); -+ ssh_gssapi_error(ctx); -+ ssh_gssapi_delete_ctx(&ctx); -+ return 0; -+ } -+ -+ p = strchr((char *) export_cred.value, '='); -+ if (p == NULL) { -+ logit("Failed to parse exported credentials string '%.100s'", -+ (char *)export_cred.value); -+ gss_release_buffer(&minor_status, &export_cred); -+ return 0; -+ } -+ *p++ = '\0'; -+ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { -+ client->store.envvar = strdup("X509_USER_PROXY"); -+ } else { -+ client->store.envvar = strdup((char *)export_cred.value); -+ } -+ if (access(p, R_OK) == 0) { -+ if (client->store.filename) { -+ if (rename(p, client->store.filename) < 0) { -+ logit("Failed to rename %s to %s: %s", p, -+ client->store.filename, strerror(errno)); -+ free(client->store.filename); -+ client->store.filename = strdup(p); -+ } else { -+ p = client->store.filename; -+ } -+ } else { -+ client->store.filename = strdup(p); -+ } -+ } -+ client->store.envval = strdup(p); -+#ifdef USE_PAM -+ if (options.use_pam) -+ do_pam_putenv(client->store.envvar, client->store.envval); -+#endif -+ gss_release_buffer(&minor_status, &export_cred); -+ -+ return 1; -+} -+ -+/* -+ * Export updated GSI credentials to disk. -+ */ -+static int -+ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client) -+{ -+ return ssh_gssapi_gsi_storecreds(client); -+} -+ -+/* -+ * Export updated GSI credentials to disk. -+ */ -+static int -+ssh_gssapi_gsi_updatecreds_micv2(ssh_gssapi_ccache *store,ssh_gssapi_client *client) -+{ -+ return ssh_gssapi_gsi_storecreds_micv2(client); -+} -+ -+#endif /* GSI */ -+#endif /* GSSAPI */ -diff -Nur openssh-8.6p1.orig/gss-serv-krb5.c openssh-8.6p1/gss-serv-krb5.c ---- openssh-8.6p1.orig/gss-serv-krb5.c 2021-05-04 10:47:33.392951281 +0200 -+++ openssh-8.6p1/gss-serv-krb5.c 2021-05-04 10:48:29.609078317 +0200 -@@ -379,6 +379,34 @@ - return found_principal; - } - -+/* Retrieve the local username associated with a set of Kerberos -+ * credentials. Hopefully we can use this for the 'empty' username -+ * logins discussed in the draft */ -+static int -+ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) { -+ krb5_principal princ; -+ int retval; -+ -+ if (ssh_gssapi_krb5_init() == 0) -+ return 0; -+ -+ if ((retval=krb5_parse_name(krb_context, client->displayname.value, -+ &princ))) { -+ logit("krb5_parse_name(): %.100s", -+ krb5_get_err_text(krb_context,retval)); -+ return 0; -+ } -+ -+ /* We've got to return a malloc'd string */ -+ *user = (char *)xmalloc(256); -+ if (krb5_aname_to_localname(krb_context, princ, 256, *user)) { -+ free(*user); -+ *user = NULL; -+ return(0); -+ } -+ -+ return(1); -+} - - /* This writes out any forwarded credentials from the structure populated - * during userauth. Called after we have setuid to the user */ -@@ -473,7 +501,7 @@ - return set_env; - } - --int -+static int - ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, - ssh_gssapi_client *client) - { -@@ -544,7 +572,7 @@ - {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, - NULL, - &ssh_gssapi_krb5_userok, -- NULL, -+ &ssh_gssapi_krb5_localname, - &ssh_gssapi_krb5_storecreds, - &ssh_gssapi_krb5_updatecreds - }; -diff -Nur openssh-8.6p1.orig/kexgsss.c openssh-8.6p1/kexgsss.c ---- openssh-8.6p1.orig/kexgsss.c 2021-05-04 10:47:33.475951468 +0200 -+++ openssh-8.6p1/kexgsss.c 2021-05-04 10:48:29.609078317 +0200 -@@ -48,6 +48,7 @@ - #include "digest.h" - #include "ssherr.h" - -+static void kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh); - extern ServerOptions options; - - int -@@ -96,8 +97,10 @@ - - debug2_f("Acquiring credentials"); - -- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { -+ kex_gss_send_error(ctxt, ssh); - fatal("Unable to acquire credentials for the server"); -+ } - - do { - debug("Wait SSH2_MSG_KEXGSS_INIT"); -@@ -195,13 +198,14 @@ - } while (maj_status & GSS_S_CONTINUE_NEEDED); - - if (GSS_ERROR(maj_status)) { -+ kex_gss_send_error(ctxt, ssh); - if (send_tok.length > 0) { - if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || - (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || - (r = sshpkt_send(ssh)) != 0) - fatal("sshpkt failed: %s", ssh_err(r)); - } -- fatal("accept_ctx died"); -+ ssh_packet_disconnect(ssh, "GSSAPI Key Exchange handshake failed"); - } - - if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -@@ -479,4 +483,26 @@ - sshbuf_free(shared_secret); - return r; - } -+ -+static void -+kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh) { -+ char *errstr; -+ OM_uint32 maj, min; -+ int r; -+ -+ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); -+ if (errstr) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_ERROR)) != 0 || -+ (r = sshpkt_put_u32(ssh, maj)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_cstring(ssh, errstr)) != 0 || -+ (r = sshpkt_put_cstring(ssh, "")) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if ((r = ssh_packet_write_wait(ssh)) != 0) -+ fatal("ssh_packet_write_wait: %s", ssh_err(r)); -+ /* XXX - We should probably log the error locally here */ -+ free(errstr); -+ } -+} - #endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff -Nur openssh-8.6p1.orig/Makefile.in openssh-8.6p1/Makefile.in ---- openssh-8.6p1.orig/Makefile.in 2021-05-04 10:47:33.447951405 +0200 -+++ openssh-8.6p1/Makefile.in 2021-05-04 10:48:29.610078319 +0200 -@@ -128,6 +128,7 @@ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor.o monitor_wrap.o auth-krb5.o \ - auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ -+ gss-serv-gsi.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - srclimit.o sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff -Nur openssh-8.6p1.orig/misc.c openssh-8.6p1/misc.c ---- openssh-8.6p1.orig/misc.c 2021-05-04 10:47:33.466951448 +0200 -+++ openssh-8.6p1/misc.c 2021-05-04 10:48:29.612078324 +0200 -@@ -378,11 +378,14 @@ - #define WHITESPACE " \t\r\n" - #define QUOTE "\"" - -+/* Characters considered as quotations. */ -+#define QUOTES "'\"" -+ - /* return next token in configuration line */ - static char * - strdelim_internal(char **s, int split_equals) - { -- char *old; -+ char *old, *p, *q; - int wspace = 0; - - if (*s == NULL) -@@ -390,6 +393,21 @@ - - old = *s; - -+ if ((q=strchr(QUOTES, (int) *old)) && *q) -+ { -+ /* find next quote character, point old to start of quoted -+ * string */ -+ for (p = ++old; *p && *p != *q; p++) -+ ; -+ -+ /* find start of next token */ -+ *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL; -+ -+ /* terminate 'old' token */ -+ *p = '\0'; -+ return (old); -+ } -+ - *s = strpbrk(*s, - split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE); - if (*s == NULL) -@@ -465,6 +483,20 @@ - return copy; - } - -+void -+pwfree(struct passwd *pw) -+{ -+ free(pw->pw_name); -+ free(pw->pw_passwd); -+ free(pw->pw_gecos); -+#ifdef HAVE_PW_CLASS_IN_PASSWD -+ free(pw->pw_class); -+#endif -+ free(pw->pw_dir); -+ free(pw->pw_shell); -+ free(pw); -+} -+ - /* - * Convert ASCII string to TCP/IP port number. - * Port must be >=0 and <=65535. -diff -Nur openssh-8.6p1.orig/misc.h openssh-8.6p1/misc.h ---- openssh-8.6p1.orig/misc.h 2021-05-04 10:47:33.408951317 +0200 -+++ openssh-8.6p1/misc.h 2021-05-04 10:48:29.612078324 +0200 -@@ -98,6 +98,7 @@ - void sock_set_v6only(int); - - struct passwd *pwcopy(struct passwd *); -+void pwfree(struct passwd *); - const char *ssh_gai_strerror(int); - - typedef void privdrop_fn(struct passwd *); -diff -Nur openssh-8.6p1.orig/monitor.c openssh-8.6p1/monitor.c ---- openssh-8.6p1.orig/monitor.c 2021-05-04 10:47:33.467951450 +0200 -+++ openssh-8.6p1/monitor.c 2021-05-04 10:48:29.614078329 +0200 -@@ -154,6 +154,9 @@ - int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); - int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); - int mm_answer_gss_sign(struct ssh *, int, struct sshbuf *); -+int mm_answer_gss_error(struct ssh *, int, struct sshbuf *); -+int mm_answer_gss_indicate_mechs(struct ssh *, int, struct sshbuf *); -+int mm_answer_gss_localname(struct ssh *, int, struct sshbuf *); - int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *); - #endif - -@@ -206,7 +209,7 @@ - {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, - #endif - {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, -- {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, -+ {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow}, - {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, - #ifdef WITH_SELINUX - {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, -@@ -214,7 +217,7 @@ - {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, - {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, - #ifdef USE_PAM -- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, -+ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, - {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, - {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx}, - {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query}, -@@ -238,8 +241,11 @@ - {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, - {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, - {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, -- {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, -+ {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, - {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, -+ {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error}, -+ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, -+ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, - #endif - {0, 0, NULL} - }; -@@ -249,6 +255,8 @@ - {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, - {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, - {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, -+ {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error}, -+ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, - {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, - #endif - #ifdef WITH_OPENSSL -@@ -329,6 +337,8 @@ - #ifdef GSSAPI - /* and for the GSSAPI key exchange */ - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); - #endif - - /* The first few requests do not require asynchronous access */ -@@ -446,6 +456,8 @@ - #ifdef GSSAPI - /* and for the GSSAPI key exchange */ - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); - #endif - - if (auth_opts->permit_pty_flag) { -@@ -762,15 +774,18 @@ - - debug3_f("entering"); - -- if (authctxt->attempt++ != 0) -- fatal_f("multiple attempts for getpwnam"); -- - if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) - fatal_fr(r, "parse"); - - pwent = getpwnamallow(ssh, username); - -+ if (authctxt->user) free(authctxt->user); - authctxt->user = xstrdup(username); -+#ifdef USE_PAM -+ if (options.permit_pam_user_change) -+ setproctitle("%s [priv]", pwent ? "[pam]" : "unknown"); -+ else -+#endif - setproctitle("%s [priv]", pwent ? username : "unknown"); - free(username); - -@@ -2113,6 +2128,79 @@ - } - - int -+mm_answer_gss_error(struct ssh *ssh, int socket, struct sshbuf *m) -+{ -+ OM_uint32 major, minor; -+ char *msg; -+ int r; -+ -+ msg=ssh_gssapi_last_error(gsscontext, &major, &minor); -+ sshbuf_reset(m); -+ if ((r = sshbuf_put_u32(m, major)) != 0 || -+ (r = sshbuf_put_u32(m, minor)) != 0 || -+ (r = sshbuf_put_cstring(m, msg)) != 0) -+ fatal_fr(r, "buffer error"); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSERR, m); -+ -+ free(msg); -+ -+ return(0); -+} -+ -+int -+mm_answer_gss_indicate_mechs(struct ssh *ssh, int socket, struct sshbuf *m) -+{ -+ OM_uint32 major, minor; -+ gss_OID_set mech_set; -+ size_t i; -+ int r; -+ -+ major=gss_indicate_mechs(&minor, &mech_set); -+ -+ sshbuf_reset(m); -+ if ((r = sshbuf_put_u32(m, major)) != 0 || -+ (r = sshbuf_put_u32(m, mech_set->count)) != 0) -+ fatal_fr(r, "buffer error"); -+ for (i = 0; i < mech_set->count; i++) { -+ if ((r = sshbuf_put_string(m, mech_set->elements[i].elements, -+ mech_set->elements[i].length)) != 0) -+ fatal_fr(r, "buffer error"); -+ } -+ -+ gss_release_oid_set(&minor, &mech_set); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSMECHS, m); -+ -+ return(0); -+} -+ -+int -+mm_answer_gss_localname(struct ssh *ssh, int socket, struct sshbuf *m) -+{ -+ char *name; -+ int r; -+ -+ ssh_gssapi_localname(&name); -+ -+ sshbuf_reset(m); -+ if (name) { -+ if ((r = sshbuf_put_cstring(m, name)) != 0) -+ fatal_fr(r, "buffer error"); -+ debug3_f("sending result %s", name); -+ free(name); -+ } else { -+ if ((r = sshbuf_put_cstring(m, "")) != 0) -+ fatal_fr(r, "buffer error"); -+ debug3_f("sending result \"\""); -+ } -+ -+ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); -+ -+ return(0); -+} -+ -+int - mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m) - { - gss_buffer_desc data; -diff -Nur openssh-8.6p1.orig/monitor.h openssh-8.6p1/monitor.h ---- openssh-8.6p1.orig/monitor.h 2021-05-04 10:47:33.447951405 +0200 -+++ openssh-8.6p1/monitor.h 2021-05-04 10:48:29.614078329 +0200 -@@ -75,6 +75,10 @@ - - MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, - MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, -+ -+ MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201, -+ MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203, -+ MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205 - }; - - struct ssh; -diff -Nur openssh-8.6p1.orig/monitor_wrap.c openssh-8.6p1/monitor_wrap.c ---- openssh-8.6p1.orig/monitor_wrap.c 2021-05-04 10:47:33.467951450 +0200 -+++ openssh-8.6p1/monitor_wrap.c 2021-05-04 10:48:29.615078331 +0200 -@@ -1084,6 +1084,94 @@ - return (authenticated); - } - -+char * -+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) -+{ -+ struct sshbuf *m = NULL; -+ OM_uint32 maj,min; -+ char *errstr; -+ int r; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal_f("sshbuf_new failed"); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, m); -+ -+ if ((r = sshbuf_get_u32(m, &maj)) != 0 || -+ (r = sshbuf_get_u32(m, &min)) != 0) -+ fatal_fr(r, "buffer error"); -+ -+ if (major) *major=maj; -+ if (minor) *minor=min; -+ -+ if ((r = sshbuf_get_cstring(m, &errstr, NULL)) != 0) -+ fatal_fr(r, "buffer error"); -+ -+ sshbuf_free(m); -+ -+ return(errstr); -+} -+ -+OM_uint32 -+mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) -+{ -+ struct sshbuf *m = NULL; -+ OM_uint32 major,minor; -+ int count; -+ gss_OID_desc oid; -+ size_t length; -+ int r; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal_f("sshbuf_new failed"); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS, m); -+ if ((r = sshbuf_get_u32(m, &major)) != 0 || -+ (r = sshbuf_get_u32(m, &count)) != 0) -+ fatal_fr(r, "buffer error"); -+ -+ gss_create_empty_oid_set(&minor, mech_set); -+ while(count-->0) { -+ if ((r = sshbuf_get_string(m, (u_char **)&oid.elements, &length)) != 0) -+ fatal_fr(r, "buffer error"); -+ oid.length = length; -+ gss_add_oid_set_member(&minor, &oid, mech_set); -+ } -+ -+ sshbuf_free(m); -+ -+ return(major); -+} -+ -+int -+mm_ssh_gssapi_localname(char **lname) -+{ -+ struct sshbuf *m = NULL; -+ int r; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal_f("sshbuf_new failed"); -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, m); -+ -+ debug3_f("waiting for MONITOR_ANS_GSSLOCALNAME"); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME, -+ m); -+ -+ if ((r = sshbuf_get_cstring(m, lname, NULL)) != 0) -+ fatal_fr(r, "buffer error"); -+ -+ sshbuf_free(m); -+ if ((*lname == NULL) || (*lname[0] == '\0')) { -+ debug3_f("gssapi identity mapping failed"); -+ } else { -+ debug3_f("gssapi identity mapped to %s", *lname); -+ } -+ -+ return(0); -+} -+ - OM_uint32 - mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) - { -diff -Nur openssh-8.6p1.orig/monitor_wrap.h openssh-8.6p1/monitor_wrap.h ---- openssh-8.6p1.orig/monitor_wrap.h 2021-05-04 10:47:33.453951418 +0200 -+++ openssh-8.6p1/monitor_wrap.h 2021-05-04 10:48:29.616078333 +0200 -@@ -73,6 +73,10 @@ - int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex); - OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); -+int mm_ssh_gssapi_localname(char **user); -+OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status, -+ gss_OID_set *mech_set); -+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); - int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); - #endif - -diff -Nur openssh-8.6p1.orig/readconf.c openssh-8.6p1/readconf.c ---- openssh-8.6p1.orig/readconf.c 2021-05-04 10:47:33.468951452 +0200 -+++ openssh-8.6p1/readconf.c 2021-05-04 10:48:29.617078335 +0200 -@@ -2391,11 +2391,11 @@ - if (options->challenge_response_authentication == -1) - options->challenge_response_authentication = 1; - if (options->gss_authentication == -1) -- options->gss_authentication = 0; -+ options->gss_authentication = 1; - if (options->gss_keyex == -1) -- options->gss_keyex = 0; -+ options->gss_keyex = 1; - if (options->gss_deleg_creds == -1) -- options->gss_deleg_creds = 0; -+ options->gss_deleg_creds = 1; - if (options->gss_trust_dns == -1) - options->gss_trust_dns = 0; - if (options->gss_renewal_rekey == -1) -diff -Nur openssh-8.6p1.orig/readconf.h openssh-8.6p1/readconf.h ---- openssh-8.6p1.orig/readconf.h 2021-05-04 10:47:33.355951197 +0200 -+++ openssh-8.6p1/readconf.h 2021-05-04 10:48:29.618078338 +0200 -@@ -80,6 +80,8 @@ - char *host_key_alias; /* hostname alias for .ssh/known_hosts */ - char *proxy_command; /* Proxy command for connecting the host. */ - char *user; /* User to log in as. */ -+ int implicit; /* Login user was not specified. -+ Server may choose based on authctxt. */ - int escape_char; /* Escape character; -2 = none */ - - u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ -diff -Nur openssh-8.6p1.orig/servconf.c openssh-8.6p1/servconf.c ---- openssh-8.6p1.orig/servconf.c 2021-05-04 10:47:33.469951455 +0200 -+++ openssh-8.6p1/servconf.c 2021-05-04 10:48:29.619078340 +0200 -@@ -93,6 +93,7 @@ - - /* Portable-specific options */ - options->use_pam = -1; -+ options->permit_pam_user_change = -1; - - /* Standard Options */ - options->num_ports = 0; -@@ -139,9 +140,11 @@ - options->kerberos_get_afs_token = -1; - options->kerberos_unique_ccache = -1; - options->gss_authentication=-1; -+ options->gss_deleg_creds = -1; - options->gss_keyex = -1; - options->gss_cleanup_creds = -1; - options->gss_strict_acceptor = -1; -+ options->gsi_allow_limited_proxy = -1; - options->gss_store_rekey = -1; - options->gss_kex_algorithms = NULL; - options->use_kuserok = -1; -@@ -292,6 +295,8 @@ - /* Portable-specific options */ - if (options->use_pam == -1) - options->use_pam = 0; -+ if (options->permit_pam_user_change == -1) -+ options->permit_pam_user_change = 0; - - /* Standard Options */ - if (options->num_host_key_files == 0) { -@@ -373,13 +378,17 @@ - if (options->kerberos_unique_ccache == -1) - options->kerberos_unique_ccache = 0; - if (options->gss_authentication == -1) -- options->gss_authentication = 0; -+ options->gss_authentication = 1; -+ if (options->gss_deleg_creds == -1) -+ options->gss_deleg_creds = 1; - if (options->gss_keyex == -1) -- options->gss_keyex = 0; -+ options->gss_keyex = 1; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; - if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 1; -+ if (options->gsi_allow_limited_proxy == -1) -+ options->gsi_allow_limited_proxy = 0; - if (options->gss_store_rekey == -1) - options->gss_store_rekey = 0; - #ifdef GSSAPI -@@ -517,7 +526,7 @@ - typedef enum { - sBadOption, /* == unknown option */ - /* Portable-specific options */ -- sUsePAM, -+ sUsePAM, sPermitPAMUserChange, - /* Standard Options */ - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, -@@ -539,6 +548,9 @@ - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, - sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, -+ sGssDelegateCreds, -+ sGssCredsPath, -+ sGsiAllowLimitedProxy, - sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, - sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, - sAcceptEnv, sSetEnv, sPermitTunnel, -@@ -571,8 +583,10 @@ - /* Portable-specific options */ - #ifdef USE_PAM - { "usepam", sUsePAM, SSHCFG_GLOBAL }, -+ { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }, - #else - { "usepam", sUnsupported, SSHCFG_GLOBAL }, -+ { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, - #endif - { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, - /* Standard Options */ -@@ -625,8 +639,15 @@ - { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, - #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, -+ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, -+#ifdef GSI -+ { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, -+#else -+ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, -+#endif - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, -@@ -634,8 +655,11 @@ - { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, -+ { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, -+ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, -@@ -707,6 +731,8 @@ - { "permitlisten", sPermitListen, SSHCFG_ALL }, - { "forcecommand", sForceCommand, SSHCFG_ALL }, - { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, -+ { "disableusagestats", sUnsupported, SSHCFG_GLOBAL}, -+ { "usagestatstargets", sUnsupported, SSHCFG_GLOBAL}, - { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, - { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, - { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, -@@ -1360,6 +1386,10 @@ - intptr = &options->use_pam; - goto parse_flag; - -+ case sPermitPAMUserChange: -+ intptr = &options->permit_pam_user_change; -+ goto parse_flag; -+ - /* Standard Options */ - case sBadOption: - return -1; -@@ -1606,6 +1636,10 @@ - intptr = &options->gss_authentication; - goto parse_flag; - -+ case sGssDelegateCreds: -+ intptr = &options->gss_deleg_creds; -+ goto parse_flag; -+ - case sGssKeyEx: - intptr = &options->gss_keyex; - goto parse_flag; -@@ -1614,6 +1648,10 @@ - intptr = &options->gss_cleanup_creds; - goto parse_flag; - -+ case sGssCredsPath: -+ charptr = &options->gss_creds_path; -+ goto parse_filename; -+ - case sGssStrictAcceptor: - intptr = &options->gss_strict_acceptor; - goto parse_flag; -@@ -1634,6 +1672,12 @@ - options->gss_kex_algorithms = xstrdup(arg); - break; - -+#ifdef GSI -+ case sGsiAllowLimitedProxy: -+ intptr = &options->gsi_allow_limited_proxy; -+ goto parse_flag; -+#endif -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -@@ -2621,6 +2665,7 @@ - - M_CP_INTOPT(password_authentication); - M_CP_INTOPT(gss_authentication); -+ M_CP_INTOPT(gss_deleg_creds); - M_CP_INTOPT(pubkey_authentication); - M_CP_INTOPT(pubkey_auth_options); - M_CP_INTOPT(kerberos_authentication); -diff -Nur openssh-8.6p1.orig/servconf.h openssh-8.6p1/servconf.h ---- openssh-8.6p1.orig/servconf.h 2021-05-04 10:47:33.402951303 +0200 -+++ openssh-8.6p1/servconf.h 2021-05-04 10:48:29.620078342 +0200 -@@ -146,9 +146,12 @@ - * be stored in per-session ccache */ - int use_kuserok; - int enable_k5users; -+ int gsi_allow_limited_proxy; /* If true, accept limited proxies */ - int gss_authentication; /* If true, permit GSSAPI authentication */ -+ int gss_deleg_creds; /* If true, store delegated GSSAPI credentials*/ - int gss_keyex; /* If true, permit GSSAPI key exchange */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -+ char *gss_creds_path; /* Use non-default credentials path */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ - int gss_store_rekey; - char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ -@@ -210,6 +213,7 @@ - char *adm_forced_command; - - int use_pam; /* Enable auth via PAM */ -+ int permit_pam_user_change; /* Allow PAM to change user name */ - - int permit_tun; - -diff -Nur openssh-8.6p1.orig/ssh.1 openssh-8.6p1/ssh.1 ---- openssh-8.6p1.orig/ssh.1 2021-05-04 10:47:33.357951202 +0200 -+++ openssh-8.6p1/ssh.1 2021-05-04 10:48:29.621078345 +0200 -@@ -1473,6 +1473,18 @@ - on to new connections). - .It Ev USER - Set to the name of the user logging in. -+.It Ev X509_CERT_DIR -+Used for GSI authentication. Specifies a non-standard location for the -+CA certificates directory. -+.It Ev X509_USER_CERT -+Used for GSI authentication. Specifies a non-standard location for the -+certificate to be used for authentication to the server. -+.It Ev X509_USER_KEY -+Used for GSI authentication. Specifies a non-standard location for the -+private key to be used for authentication to the server. -+.It Ev X509_USER_PROXY -+Used for GSI authentication. Specifies a non-standard location for the -+proxy credential to be used for authentication to the server. - .El - .Pp - Additionally, -diff -Nur openssh-8.6p1.orig/ssh.c openssh-8.6p1/ssh.c ---- openssh-8.6p1.orig/ssh.c 2021-05-04 10:47:33.472951462 +0200 -+++ openssh-8.6p1/ssh.c 2021-05-04 10:48:29.622078347 +0200 -@@ -575,6 +575,38 @@ - fatal("Can't open user config file %.100s: " - "%.100s", config, strerror(errno)); - } else { -+ /* -+ * Since the config file parsing code aborts if it sees -+ * options it doesn't recognize, allow users to put -+ * options specific to compile-time add-ons in alternate -+ * config files so their primary config file will -+ * interoperate SSH versions that don't support those -+ * options. -+ */ -+#ifdef GSSAPI -+ r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, -+ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | -+ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); -+#ifdef GSI -+ r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, -+ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | -+ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); -+#endif -+#if defined(KRB5) -+ r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir, -+ _PATH_SSH_USER_CONFFILE); -+ if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, -+ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | -+ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); -+#endif -+#endif - r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, - _PATH_SSH_USER_CONFFILE); - if (r > 0 && (size_t)r < sizeof(buf)) -@@ -1247,8 +1279,12 @@ - if (fill_default_options(&options) != 0) - cleanup_exit(255); - -- if (options.user == NULL) -+ if (options.user == NULL) { - options.user = xstrdup(pw->pw_name); -+ options.implicit = 1; -+ } else { -+ options.implicit = 0; -+ } - - /* - * If ProxyJump option specified, then construct a ProxyCommand now. -diff -Nur openssh-8.6p1.orig/ssh_config openssh-8.6p1/ssh_config ---- openssh-8.6p1.orig/ssh_config 2021-05-04 10:47:33.358951204 +0200 -+++ openssh-8.6p1/ssh_config 2021-05-04 10:48:29.622078347 +0200 -@@ -22,9 +22,9 @@ - # ForwardX11 no - # PasswordAuthentication yes - # HostbasedAuthentication no --# GSSAPIAuthentication no --# GSSAPIDelegateCredentials no --# GSSAPIKeyExchange no -+# GSSAPIAuthentication yes -+# GSSAPIDelegateCredentials yes -+# GSSAPIKeyExchange yes - # GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes -diff -Nur openssh-8.6p1.orig/ssh_config.5 openssh-8.6p1/ssh_config.5 ---- openssh-8.6p1.orig/ssh_config.5 2021-05-04 10:47:33.424951353 +0200 -+++ openssh-8.6p1/ssh_config.5 2021-05-04 10:48:29.623078349 +0200 -@@ -52,6 +52,12 @@ - user's configuration file - .Pq Pa ~/.ssh/config - .It -+GSSAPI configuration file -+.Pq Pa $HOME/.ssh/config.gssapi -+.It -+Kerberos configuration file -+.Pq Pa $HOME/.ssh/config.krb -+.It - system-wide configuration file - .Pq Pa /etc/ssh/ssh_config - .El -@@ -775,7 +781,7 @@ - .It Cm GSSAPIAuthentication - Specifies whether user authentication based on GSSAPI is allowed. - The default is --.Cm no . -+.Cm yes . - .It Cm GSSAPIClientIdentity - If set, specifies the GSSAPI client identity that ssh should use when - connecting to the server. The default is unset, which means that the default -@@ -783,12 +789,12 @@ - .It Cm GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. - The default is --.Cm no . -+.Cm yes . - .It Cm GSSAPIKeyExchange - Specifies whether key exchange based on GSSAPI may be used. When using - GSSAPI key exchange the server need not have a host key. - The default is --.Dq no . -+.Dq yes . - .It Cm GSSAPIRenewalForcesRekey - If set to - .Dq yes -@@ -1410,7 +1416,7 @@ - .Cm password ) . - The default is: - .Bd -literal -offset indent --gssapi-with-mic,hostbased,publickey, -+gssapi-keyex,gssapi-with-mic,hostbased,publickey, - keyboard-interactive,password - .Ed - .It Cm ProxyCommand -diff -Nur openssh-8.6p1.orig/sshconnect2.c openssh-8.6p1/sshconnect2.c ---- openssh-8.6p1.orig/sshconnect2.c 2021-05-04 10:47:33.459951432 +0200 -+++ openssh-8.6p1/sshconnect2.c 2021-05-04 10:48:29.624078351 +0200 -@@ -854,6 +854,11 @@ - gss_OID mech = NULL; - char *gss_host = NULL; - -+ if (!options.gss_authentication) { -+ verbose("GSSAPI authentication disabled."); -+ return 0; -+ } -+ - if (options.gss_server_identity) { - gss_host = xstrdup(options.gss_server_identity); - } else if (options.gss_trust_dns) { -@@ -965,7 +970,8 @@ - - if (status == GSS_S_COMPLETE) { - /* send either complete or MIC, depending on mechanism */ -- if (!(flags & GSS_C_INTEG_FLAG)) { -+ if (strcmp(authctxt->method->name, "gssapi") == 0 || -+ !(flags & GSS_C_INTEG_FLAG)) { - if ((r = sshpkt_start(ssh, - SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 || - (r = sshpkt_send(ssh)) != 0) -@@ -1136,6 +1142,20 @@ - return r; - } - -+#ifdef GSI -+extern -+const gss_OID_desc * const gss_mech_globus_gssapi_openssl; -+extern -+const gss_OID_desc * const gss_mech_globus_gssapi_openssl_micv2; -+#define is_gsi_oid(oid) \ -+ ((oid->length == gss_mech_globus_gssapi_openssl->length && \ -+ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \ -+ oid->length) == 0)) || \ -+ (oid->length == gss_mech_globus_gssapi_openssl_micv2->length && \ -+ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl_micv2->elements, \ -+ oid->length) == 0))) -+#endif -+ - int - userauth_gsskeyex(struct ssh *ssh) - { -@@ -1158,6 +1178,12 @@ - if ((b = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - -+#ifdef GSI -+ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) -+ ssh_gssapi_buildmic(b, "", authctxt->service, -+ "gssapi-keyex", ssh->kex->session_id); -+ else -+#endif - ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, - "gssapi-keyex", ssh->kex->session_id); - -@@ -1171,7 +1197,9 @@ - } - - if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || -- (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || -+ (r = sshpkt_put_cstring(ssh, -+ (options.implicit && is_gsi_oid(gss_kex_context->oid)) ? -+ "" : authctxt->server_user)) != 0 || - (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || - (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || - (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 || -diff -Nur openssh-8.6p1.orig/sshd.8 openssh-8.6p1/sshd.8 ---- openssh-8.6p1.orig/sshd.8 2021-05-04 10:47:33.375951242 +0200 -+++ openssh-8.6p1/sshd.8 2021-05-04 10:48:29.624078351 +0200 -@@ -815,6 +815,29 @@ - # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org - @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... - .Ed -+.Sh ENVIRONMENT -+.Nm -+will normally set the following environment variables: -+.Bl -tag -width "SSH_ORIGINAL_COMMAND" -+.It Ev GRIDMAP -+Applies to GSI authentication/authorization. Specifies the location of the -+gridmapfile. If not specified, the gridmap file is assumed to be available at -+/etc/grid-security/grid-mapfile for services running as root and at -+HOME/.gridmap for services running as non-root where HOME is the home directory -+of the effective user from the password file entry. -+.It Ev X509_CERT_DIR -+Used for GSI authentication. Specifies a non-standard location for the -+CA certificates directory. -+.It Ev X509_USER_CERT -+Used for GSI authentication. Specifies a non-standard location for the -+certificate to be used for authentication to the client. -+.It Ev X509_USER_KEY -+Used for GSI authentication. Specifies a non-standard location for the -+private key to be used for authentication to the client. -+.It Ev X509_USER_PROXY -+Used for GSI authentication. Specifies a non-standard location for the -+proxy credential to be used for authentication to the client. -+.El - .Sh FILES - .Bl -tag -width Ds -compact - .It Pa ~/.hushlogin -diff -Nur openssh-8.6p1.orig/sshd.c openssh-8.6p1/sshd.c ---- openssh-8.6p1.orig/sshd.c 2021-05-04 10:47:33.472951462 +0200 -+++ openssh-8.6p1/sshd.c 2021-05-04 10:48:29.625078353 +0200 -@@ -2364,7 +2364,7 @@ - #endif - - #ifdef GSSAPI -- if (options.gss_authentication) { -+ if (options.gss_authentication && options.gss_deleg_creds) { - temporarily_use_uid(authctxt->pw); - authctxt->krb5_set_env = ssh_gssapi_storecreds(); - restore_uid(); -diff -Nur openssh-8.6p1.orig/sshd_config openssh-8.6p1/sshd_config ---- openssh-8.6p1.orig/sshd_config 2021-05-04 10:47:33.393951283 +0200 -+++ openssh-8.6p1/sshd_config 2021-05-04 10:48:29.626078356 +0200 -@@ -76,10 +76,11 @@ - #KerberosUseKuserok yes - - # GSSAPI options --#GSSAPIAuthentication no -+#GSSAPIAuthentication yes -+#GSSAPIDelegateCredentials yes - #GSSAPICleanupCredentials yes - #GSSAPIStrictAcceptorCheck yes --#GSSAPIKeyExchange no -+#GSSAPIKeyExchange yes - #GSSAPIEnablek5users no - - # Set this to 'yes' to enable PAM authentication, account processing, -@@ -95,6 +96,10 @@ - # problems. - #UsePAM no - -+# Set to 'yes' to allow the PAM stack to change the user name during -+# calls to authentication -+#PermitPAMUserChange no -+ - #AllowAgentForwarding yes - #AllowTcpForwarding yes - #GatewayPorts no -diff -Nur openssh-8.6p1.orig/sshd_config.5 openssh-8.6p1/sshd_config.5 ---- openssh-8.6p1.orig/sshd_config.5 2021-05-04 10:47:33.424951353 +0200 -+++ openssh-8.6p1/sshd_config.5 2021-05-04 10:48:29.627078358 +0200 -@@ -632,15 +632,34 @@ - to allow the client to select the address to which the forwarding is bound. - The default is - .Cm no . -+.It Cm GSIAllowLimitedProxy -+Specifies whether to accept limited proxy credentials for authentication. -+The default is -+.Cm no . - .It Cm GSSAPIAuthentication - Specifies whether user authentication based on GSSAPI is allowed. - The default is --.Cm no . -+.Cm yes . - .It Cm GSSAPICleanupCredentials - Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Cm yes . -+.It Cm GSSAPICredentialsPath -+If specified, the delegated GSSAPI credential is stored in the -+given path, overwriting any existing credentials. -+Paths can be specified with syntax similar to the AuthorizedKeysFile -+option (i.e., accepting %h and %u tokens). -+When using this option, -+setting 'GssapiCleanupCredentials no' is recommended, -+so logging out of one session -+doesn't remove the credentials in use by another session of -+the same user. -+Currently only implemented for the GSI mechanism. -+.It Cm GSSAPIDelegateCredentials -+Specifies whether delegated credentials are stored in the user's environment. -+The default is -+.Cm yes . - .It Cm GSSAPIEnablek5users - Specifies whether to look at .k5users file for GSSAPI authentication - access control. Further details are described in -@@ -651,7 +670,7 @@ - Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange - doesn't rely on ssh keys to verify host identity. - The default is --.Cm no . -+.Cm yes . - .It Cm GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI acceptor - a client authenticates against. -@@ -1783,6 +1802,12 @@ - as a non-root user. - The default is - .Cm no . -+.It Cm PermitPAMUserChange -+If set to -+.Cm yes -+this will enable PAM authentication to change the name of the user being -+authenticated. The default is -+.Cm no . - .It Cm VersionAddendum - Optionally specifies additional text to append to the SSH protocol banner - sent by the server upon connection. -diff -Nur openssh-8.6p1.orig/sshd_config_redhat openssh-8.6p1/sshd_config_redhat ---- openssh-8.6p1.orig/sshd_config_redhat 2021-05-04 10:47:33.336951154 +0200 -+++ openssh-8.6p1/sshd_config_redhat 2021-05-04 10:48:29.627078358 +0200 -@@ -9,9 +9,6 @@ - - ChallengeResponseAuthentication no - --GSSAPIAuthentication yes --GSSAPICleanupCredentials no -- - UsePAM yes - - X11Forwarding yes -diff -Nur openssh-8.6p1.orig/ssh-gss.h openssh-8.6p1/ssh-gss.h ---- openssh-8.6p1.orig/ssh-gss.h 2021-05-04 10:47:33.372951235 +0200 -+++ openssh-8.6p1/ssh-gss.h 2021-05-04 10:48:29.628078360 +0200 -@@ -97,12 +97,14 @@ - } ssh_gssapi_ccache; - - typedef struct { -+ gss_OID_desc oid; - gss_buffer_desc displayname; - gss_buffer_desc exportedname; - gss_cred_id_t creds; -- gss_name_t name; -+ gss_name_t cred_name, ctx_name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */ - int used; - int updated; - } ssh_gssapi_client; -@@ -123,7 +125,7 @@ - OM_uint32 minor; /* both */ - gss_ctx_id_t context; /* both */ - gss_name_t name; /* both */ -- gss_OID oid; /* client */ -+ gss_OID oid; /* both */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ - gss_cred_id_t client_creds; /* both */ -@@ -161,6 +163,9 @@ - OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); - int ssh_gssapi_credentials_updated(Gssctxt *); - -+int ssh_gssapi_localname(char **name); -+void ssh_gssapi_rekey_creds(); -+ - /* In the server */ - typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, - const char *); -diff -Nur openssh-8.6p1.orig/version.h openssh-8.6p1/version.h ---- openssh-8.6p1.orig/version.h 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/version.h 2021-05-04 10:48:29.628078360 +0200 -@@ -2,5 +2,19 @@ - - #define SSH_VERSION "OpenSSH_8.6" - -+#ifdef GSI -+#define GSI_VERSION " GSI" -+#else -+#define GSI_VERSION "" -+#endif -+ -+#ifdef KRB5 -+#define KRB5_VERSION " KRB5" -+#else -+#define KRB5_VERSION "" -+#endif -+ - #define SSH_PORTABLE "p1" --#define SSH_RELEASE SSH_VERSION SSH_PORTABLE -+#define GSI_PORTABLE "c-GSI" -+#define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ -+ GSI_VERSION KRB5_VERSION diff --git a/openssh-8.6p1-hpn-15.2-modified.patch b/openssh-8.6p1-hpn-15.2-modified.patch deleted file mode 100644 index 0c38562..0000000 --- a/openssh-8.6p1-hpn-15.2-modified.patch +++ /dev/null @@ -1,2593 +0,0 @@ -diff -Nur openssh-8.6p1.orig/auth2.c openssh-8.6p1/auth2.c ---- openssh-8.6p1.orig/auth2.c 2021-05-22 08:23:21.056175731 +0200 -+++ openssh-8.6p1/auth2.c 2021-05-22 08:24:33.539345593 +0200 -@@ -53,6 +53,8 @@ - #include "dispatch.h" - #include "pathnames.h" - #include "ssherr.h" -+#include "canohost.h" -+ - #ifdef GSSAPI - #include "ssh-gss.h" - #endif -@@ -75,6 +77,8 @@ - extern Authmethod method_gssapi; - #endif - -+static int log_flag = 0; -+ - Authmethod *authmethods[] = { - &method_none, - &method_pubkey, -@@ -299,6 +303,11 @@ - - debug("userauth-request for user %s service %s method %s", - user[0] ? user : "", service, method); -+ if (!log_flag) { -+ logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", -+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), user); -+ log_flag = 1; -+ } - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - - #ifdef WITH_SELINUX -diff -Nur openssh-8.6p1.orig/channels.c openssh-8.6p1/channels.c ---- openssh-8.6p1.orig/channels.c 2021-05-22 08:23:21.043175700 +0200 -+++ openssh-8.6p1/channels.c 2021-05-22 08:24:33.540345595 +0200 -@@ -220,6 +220,9 @@ - /* Setup helper */ - static void channel_handler_init(struct ssh_channels *sc); - -+static int hpn_disabled = 0; -+static int hpn_buffer_size = 2 * 1024 * 1024; -+ - /* -- channel core */ - - void -@@ -407,6 +410,7 @@ - c->local_window = window; - c->local_window_max = window; - c->local_maxpacket = maxpack; -+ c->dynamic_window = 0; - c->remote_name = xstrdup(remote_name); - c->ctl_chan = -1; - c->delayed = 1; /* prevent call to channel_post handler */ -@@ -1098,6 +1102,28 @@ - FD_SET(c->sock, writeset); - } - -+static int -+channel_tcpwinsz(struct ssh *ssh) -+{ -+ u_int32_t tcpwinsz = 0; -+ socklen_t optsz = sizeof(tcpwinsz); -+ int ret = -1; -+ -+ /* if we aren't on a socket return 128KB */ -+ if (!ssh_packet_connection_is_on_socket(ssh)) -+ return 128 * 1024; -+ -+ ret = getsockopt(ssh_packet_get_connection_in(ssh), -+ SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz); -+ /* return no more than SSHBUF_SIZE_MAX (currently 256MB) */ -+ if ((ret == 0) && tcpwinsz > SSHBUF_SIZE_MAX) -+ tcpwinsz = SSHBUF_SIZE_MAX; -+ -+ debug2("tcpwinsz: tcp connection %d, Receive window: %d", -+ ssh_packet_get_connection_in(ssh), tcpwinsz); -+ return tcpwinsz; -+} -+ - static void - channel_pre_open(struct ssh *ssh, Channel *c, - fd_set *readset, fd_set *writeset) -@@ -2136,22 +2162,31 @@ - - if (c->type == SSH_CHANNEL_OPEN && - !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && -- ((c->local_window_max - c->local_window > -- c->local_maxpacket*3) || -+ ((ssh_packet_is_interactive(ssh) && -+ c->local_window_max - c->local_window > c->local_maxpacket*3) || - c->local_window < c->local_window_max/2) && - c->local_consumed > 0) { -+ u_int addition = 0; -+ u_int32_t tcpwinsz = channel_tcpwinsz(ssh); -+ /* adjust max window size if we are in a dynamic environment */ -+ if (c->dynamic_window && (tcpwinsz > c->local_window_max)) { -+ /* grow the window somewhat aggressively to maintain pressure */ -+ addition = 1.5 * (tcpwinsz - c->local_window_max); -+ c->local_window_max += addition; -+ debug("Channel: Window growth to %d by %d bytes", c->local_window_max, addition); -+ } - if (!c->have_remote_id) - fatal_f("channel %d: no remote id", c->self); - if ((r = sshpkt_start(ssh, - SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || - (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || -- (r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 || -+ (r = sshpkt_put_u32(ssh, c->local_consumed + addition)) != 0 || - (r = sshpkt_send(ssh)) != 0) { - fatal_fr(r, "channel %i", c->self); - } - debug2("channel %d: window %d sent adjust %d", c->self, -- c->local_window, c->local_consumed); -- c->local_window += c->local_consumed; -+ c->local_window, c->local_consumed + addition); -+ c->local_window += c->local_consumed + addition; - c->local_consumed = 0; - } - return 1; -@@ -3318,6 +3353,14 @@ - return addr; - } - -+void -+channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size) -+{ -+ hpn_disabled = external_hpn_disabled; -+ hpn_buffer_size = external_hpn_buffer_size; -+ debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size); -+} -+ - static int - channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, - struct Forward *fwd, int *allocated_listen_port, -@@ -3458,8 +3501,10 @@ - } - - /* Allocate a channel number for the socket. */ -+ /* explicitly test for hpn disabled option. if true use smaller window size */ - c = channel_new(ssh, "port listener", type, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, -+ hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, - 0, "port listener", 1); - c->path = xstrdup(host); - c->host_port = fwd->connect_port; -@@ -4645,7 +4690,8 @@ - sock = socks[n]; - nc = channel_new(ssh, "x11 listener", - SSH_CHANNEL_X11_LISTENER, sock, sock, -1, -- CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, -+ hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : hpn_buffer_size, -+ CHAN_X11_PACKET_DEFAULT, - 0, "X11 inet listener", 1); - nc->single_connection = single_connection; - (*chanids)[n] = nc->self; -diff -Nur openssh-8.6p1.orig/channels.h openssh-8.6p1/channels.h ---- openssh-8.6p1.orig/channels.h 2021-05-22 08:23:21.020175646 +0200 -+++ openssh-8.6p1/channels.h 2021-05-22 08:24:33.541345597 +0200 -@@ -158,8 +158,10 @@ - u_int local_window_max; - u_int local_consumed; - u_int local_maxpacket; -+ int dynamic_window; - int extended_usage; - int single_connection; -+ u_int tcpwinsz; - - char *ctype; /* type */ - -@@ -228,7 +230,7 @@ - #define CHAN_LOCAL 0x10 - - /* Read buffer size */ --#define CHAN_RBUF (16*1024) -+#define CHAN_RBUF CHAN_SES_PACKET_DEFAULT - - /* Maximum channel input buffer size */ - #define CHAN_INPUT_MAX (16*1024*1024) -@@ -359,4 +361,7 @@ - void chan_write_failed(struct ssh *, Channel *); - void chan_obuf_empty(struct ssh *, Channel *); - -+/* hpn handler */ -+void channel_set_hpn(int, int); -+ - #endif -diff -Nur openssh-8.6p1.orig/cipher.c openssh-8.6p1/cipher.c ---- openssh-8.6p1.orig/cipher.c 2021-05-22 08:23:21.024175656 +0200 -+++ openssh-8.6p1/cipher.c 2021-05-22 08:24:33.542345600 +0200 -@@ -48,6 +48,7 @@ - #include "sshbuf.h" - #include "ssherr.h" - #include "digest.h" -+#include "log.h" - - #include "openbsd-compat/openssl-compat.h" - -@@ -55,6 +56,9 @@ - #define EVP_CIPHER_CTX void - #endif - -+/* for multi-threaded aes-ctr cipher */ -+extern const EVP_CIPHER *evp_aes_ctr_mt(void); -+ - struct sshcipher_ctx { - int plaintext; - int encrypt; -@@ -64,7 +68,7 @@ - const struct sshcipher *cipher; - }; - --static const struct sshcipher ciphers[] = { -+static struct sshcipher ciphers[] = { - #ifdef WITH_OPENSSL - #ifndef OPENSSL_NO_DES - { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, -@@ -133,6 +137,29 @@ - #endif - } - -+/* used to get the cipher name so when force rekeying to handle the -+ * single to multithreaded ctr cipher swap we only rekey when appropriate -+ */ -+const char * -+cipher_ctx_name(const struct sshcipher_ctx *cc) -+{ -+ return cc->cipher->name; -+} -+ -+/* in order to get around sandbox and forking issues with a threaded cipher -+ * we set the initial pre-auth aes-ctr cipher to the default OpenSSH cipher -+ * post auth we set them to the new evp as defined by cipher-ctr-mt -+ */ -+#ifdef WITH_OPENSSL -+void -+cipher_reset_multithreaded(void) -+{ -+ cipher_by_name("aes128-ctr")->evptype = evp_aes_ctr_mt; -+ cipher_by_name("aes192-ctr")->evptype = evp_aes_ctr_mt; -+ cipher_by_name("aes256-ctr")->evptype = evp_aes_ctr_mt; -+} -+#endif -+ - u_int - cipher_blocksize(const struct sshcipher *c) - { -@@ -182,10 +209,10 @@ - return cc->plaintext; - } - --const struct sshcipher * -+struct sshcipher * - cipher_by_name(const char *name) - { -- const struct sshcipher *c; -+ struct sshcipher *c; - for (c = ciphers; c->name != NULL; c++) - if (strcmp(c->name, name) == 0) - return c; -@@ -207,7 +234,8 @@ - for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; - (p = strsep(&cp, CIPHER_SEP))) { - c = cipher_by_name(p); -- if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) { -+ if (c == NULL || ((c->flags & CFLAG_INTERNAL) != 0 && -+ (c->flags & CFLAG_NONE) != 0)) { - free(cipher_list); - return 0; - } -diff -Nur openssh-8.6p1.orig/cipher-ctr-mt.c openssh-8.6p1/cipher-ctr-mt.c ---- openssh-8.6p1.orig/cipher-ctr-mt.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-8.6p1/cipher-ctr-mt.c 2021-05-22 08:24:33.543345602 +0200 -@@ -0,0 +1,678 @@ -+/* -+ * OpenSSH Multi-threaded AES-CTR Cipher -+ * -+ * Author: Benjamin Bennett -+ * Author: Mike Tasota -+ * Author: Chris Rapier -+ * Copyright (c) 2008-2013 Pittsburgh Supercomputing Center. All rights reserved. -+ * -+ * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged, -+ * Copyright (c) 2003 Markus Friedl -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+#include "includes.h" -+ -+#if defined(WITH_OPENSSL) -+#include -+ -+#include -+#include -+ -+#include -+ -+#include "xmalloc.h" -+#include "log.h" -+#include -+ -+/* compatibility with old or broken OpenSSL versions */ -+#include "openbsd-compat/openssl-compat.h" -+ -+#ifndef USE_BUILTIN_RIJNDAEL -+#include -+#endif -+ -+#include -+ -+/*-------------------- TUNABLES --------------------*/ -+/* maximum number of threads and queues */ -+#define MAX_THREADS 32 -+#define MAX_NUMKQ (MAX_THREADS * 2) -+ -+/* Number of pregen threads to use */ -+int cipher_threads = 2; -+ -+/* Number of keystream queues */ -+int numkq = 4; -+ -+/* Length of a keystream queue */ -+#define KQLEN 4096 -+ -+/* Processor cacheline length */ -+#define CACHELINE_LEN 64 -+ -+/* Collect thread stats and print at cancellation when in debug mode */ -+#define CIPHER_THREAD_STATS -+ -+/* Can the system do unaligned loads natively? */ -+#if defined(__aarch64__) || \ -+ defined(__i386__) || \ -+ defined(__powerpc__) || \ -+ defined(__x86_64__) -+# define CIPHER_UNALIGNED_OK -+#endif -+#if defined(__SIZEOF_INT128__) -+# define CIPHER_INT128_OK -+#endif -+/*-------------------- END TUNABLES --------------------*/ -+ -+ -+const EVP_CIPHER *evp_aes_ctr_mt(void); -+ -+#ifdef CIPHER_THREAD_STATS -+/* -+ * Struct to collect thread stats -+ */ -+struct thread_stats { -+ u_int fills; -+ u_int skips; -+ u_int waits; -+ u_int drains; -+}; -+ -+/* -+ * Debug print the thread stats -+ * Use with pthread_cleanup_push for displaying at thread cancellation -+ */ -+static void -+thread_loop_stats(void *x) -+{ -+ struct thread_stats *s = x; -+ debug("AES-CTR MT tid %lu - %u fills, %u skips, %u waits", pthread_self(), -+ s->fills, s->skips, s->waits); -+} -+ -+# define STATS_STRUCT(s) struct thread_stats s -+# define STATS_INIT(s) { memset(&s, 0, sizeof(s)); } -+# define STATS_FILL(s) { s.fills++; } -+# define STATS_SKIP(s) { s.skips++; } -+# define STATS_WAIT(s) { s.waits++; } -+# define STATS_DRAIN(s) { s.drains++; } -+#else -+# define STATS_STRUCT(s) -+# define STATS_INIT(s) -+# define STATS_FILL(s) -+# define STATS_SKIP(s) -+# define STATS_WAIT(s) -+# define STATS_DRAIN(s) -+#endif -+ -+/* Keystream Queue state */ -+enum { -+ KQINIT, -+ KQEMPTY, -+ KQFILLING, -+ KQFULL, -+ KQDRAINING -+}; -+ -+/* Keystream Queue struct */ -+struct kq { -+ u_char keys[KQLEN][AES_BLOCK_SIZE]; -+ u_char ctr[AES_BLOCK_SIZE]; -+ u_char pad0[CACHELINE_LEN]; -+ int qstate; -+ pthread_mutex_t lock; -+ pthread_cond_t cond; -+ u_char pad1[CACHELINE_LEN]; -+}; -+ -+/* Context struct */ -+struct ssh_aes_ctr_ctx_mt -+{ -+ int struct_id; -+ struct kq q[MAX_NUMKQ]; -+ AES_KEY aes_ctx; -+ STATS_STRUCT(stats); -+ u_char aes_counter[AES_BLOCK_SIZE]; -+ pthread_t tid[MAX_THREADS]; -+ int id[MAX_THREADS]; -+ pthread_rwlock_t tid_lock; -+#ifdef __APPLE__ -+ pthread_rwlock_t stop_lock; -+ int exit_flag; -+#endif /* __APPLE__ */ -+ int state; -+ int qidx; -+ int ridx; -+}; -+ -+/* -+ * increment counter 'ctr', -+ * the counter is of size 'len' bytes and stored in network-byte-order. -+ * (LSB at ctr[len-1], MSB at ctr[0]) -+ */ -+static void -+ssh_ctr_inc(u_char *ctr, size_t len) -+{ -+ int i; -+ -+ for (i = len - 1; i >= 0; i--) -+ if (++ctr[i]) /* continue on overflow */ -+ return; -+} -+ -+/* -+ * Add num to counter 'ctr' -+ */ -+static void -+ssh_ctr_add(u_char *ctr, uint32_t num, u_int len) -+{ -+ int i; -+ uint16_t n; -+ -+ for (n = 0, i = len - 1; i >= 0 && (num || n); i--) { -+ n = ctr[i] + (num & 0xff) + n; -+ num >>= 8; -+ ctr[i] = n & 0xff; -+ n >>= 8; -+ } -+} -+ -+/* -+ * Threads may be cancelled in a pthread_cond_wait, we must free the mutex -+ */ -+static void -+thread_loop_cleanup(void *x) -+{ -+ pthread_mutex_unlock((pthread_mutex_t *)x); -+} -+ -+#ifdef __APPLE__ -+/* Check if we should exit, we are doing both cancel and exit condition -+ * since on OSX threads seem to occasionally fail to notice when they have -+ * been cancelled. We want to have a backup to make sure that we won't hang -+ * when the main process join()-s the cancelled thread. -+ */ -+static void -+thread_loop_check_exit(struct ssh_aes_ctr_ctx_mt *c) -+{ -+ int exit_flag; -+ -+ pthread_rwlock_rdlock(&c->stop_lock); -+ exit_flag = c->exit_flag; -+ pthread_rwlock_unlock(&c->stop_lock); -+ -+ if (exit_flag) -+ pthread_exit(NULL); -+} -+#else -+# define thread_loop_check_exit(s) -+#endif /* __APPLE__ */ -+ -+/* -+ * Helper function to terminate the helper threads -+ */ -+static void -+stop_and_join_pregen_threads(struct ssh_aes_ctr_ctx_mt *c) -+{ -+ int i; -+ -+#ifdef __APPLE__ -+ /* notify threads that they should exit */ -+ pthread_rwlock_wrlock(&c->stop_lock); -+ c->exit_flag = TRUE; -+ pthread_rwlock_unlock(&c->stop_lock); -+#endif /* __APPLE__ */ -+ -+ /* Cancel pregen threads */ -+ for (i = 0; i < cipher_threads; i++) { -+ debug ("Canceled %lu (%d,%d)", c->tid[i], c->struct_id, c->id[i]); -+ pthread_cancel(c->tid[i]); -+ } -+ /* shouldn't need this - see commit logs for hpn-7_7_P1 -cjr 11/7/19*/ -+ /* for (i = 0; i < numkq; i++) { */ -+ /* pthread_mutex_lock(&c->q[i].lock); */ -+ /* pthread_cond_broadcast(&c->q[i].cond); */ -+ /* pthread_mutex_unlock(&c->q[i].lock); */ -+ /* } */ -+ for (i = 0; i < cipher_threads; i++) { -+ if (pthread_kill(c->tid[i], 0) != 0) -+ debug3("AES-CTR MT pthread_join failure: Invalid thread id %lu in %s", c->tid[i], __FUNCTION__); -+ else { -+ debug ("Joining %lu (%d, %d)", c->tid[i], c->struct_id, c->id[i]); -+ pthread_join(c->tid[i], NULL); -+ } -+ } -+} -+ -+/* -+ * The life of a pregen thread: -+ * Find empty keystream queues and fill them using their counter. -+ * When done, update counter for the next fill. -+ */ -+static void * -+thread_loop(void *x) -+{ -+ AES_KEY key; -+ STATS_STRUCT(stats); -+ struct ssh_aes_ctr_ctx_mt *c = x; -+ struct kq *q; -+ int i; -+ int qidx; -+ pthread_t first_tid; -+ -+ /* Threads stats on cancellation */ -+ STATS_INIT(stats); -+#ifdef CIPHER_THREAD_STATS -+ pthread_cleanup_push(thread_loop_stats, &stats); -+#endif -+ -+ /* Thread local copy of AES key */ -+ memcpy(&key, &c->aes_ctx, sizeof(key)); -+ -+ pthread_rwlock_rdlock(&c->tid_lock); -+ first_tid = c->tid[0]; -+ pthread_rwlock_unlock(&c->tid_lock); -+ -+ /* -+ * Handle the special case of startup, one thread must fill -+ * the first KQ then mark it as draining. Lock held throughout. -+ */ -+ if (pthread_equal(pthread_self(), first_tid)) { -+ q = &c->q[0]; -+ pthread_mutex_lock(&q->lock); -+ if (q->qstate == KQINIT) { -+ for (i = 0; i < KQLEN; i++) { -+ AES_encrypt(q->ctr, q->keys[i], &key); -+ ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); -+ } -+ ssh_ctr_add(q->ctr, KQLEN * (numkq - 1), AES_BLOCK_SIZE); -+ q->qstate = KQDRAINING; -+ STATS_FILL(stats); -+ pthread_cond_broadcast(&q->cond); -+ } -+ pthread_mutex_unlock(&q->lock); -+ } else -+ STATS_SKIP(stats); -+ -+ /* -+ * Normal case is to find empty queues and fill them, skipping over -+ * queues already filled by other threads and stopping to wait for -+ * a draining queue to become empty. -+ * -+ * Multiple threads may be waiting on a draining queue and awoken -+ * when empty. The first thread to wake will mark it as filling, -+ * others will move on to fill, skip, or wait on the next queue. -+ */ -+ for (qidx = 1;; qidx = (qidx + 1) % numkq) { -+ /* Check if I was cancelled, also checked in cond_wait */ -+ pthread_testcancel(); -+ -+ /* Check if we should exit as well */ -+ thread_loop_check_exit(c); -+ -+ /* Lock queue and block if its draining */ -+ q = &c->q[qidx]; -+ pthread_mutex_lock(&q->lock); -+ pthread_cleanup_push(thread_loop_cleanup, &q->lock); -+ while (q->qstate == KQDRAINING || q->qstate == KQINIT) { -+ STATS_WAIT(stats); -+ thread_loop_check_exit(c); -+ pthread_cond_wait(&q->cond, &q->lock); -+ } -+ pthread_cleanup_pop(0); -+ -+ /* If filling or full, somebody else got it, skip */ -+ if (q->qstate != KQEMPTY) { -+ pthread_mutex_unlock(&q->lock); -+ STATS_SKIP(stats); -+ continue; -+ } -+ -+ /* -+ * Empty, let's fill it. -+ * Queue lock is relinquished while we do this so others -+ * can see that it's being filled. -+ */ -+ q->qstate = KQFILLING; -+ pthread_cond_broadcast(&q->cond); -+ pthread_mutex_unlock(&q->lock); -+ for (i = 0; i < KQLEN; i++) { -+ AES_encrypt(q->ctr, q->keys[i], &key); -+ ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); -+ } -+ -+ /* Re-lock, mark full and signal consumer */ -+ pthread_mutex_lock(&q->lock); -+ ssh_ctr_add(q->ctr, KQLEN * (numkq - 1), AES_BLOCK_SIZE); -+ q->qstate = KQFULL; -+ STATS_FILL(stats); -+ pthread_cond_broadcast(&q->cond); -+ pthread_mutex_unlock(&q->lock); -+ } -+ -+#ifdef CIPHER_THREAD_STATS -+ /* Stats */ -+ pthread_cleanup_pop(1); -+#endif -+ -+ return NULL; -+} -+ -+static int -+ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, -+ LIBCRYPTO_EVP_INL_TYPE len) -+{ -+ typedef union { -+#ifdef CIPHER_INT128_OK -+ __uint128_t *u128; -+#endif -+ uint64_t *u64; -+ uint32_t *u32; -+ uint8_t *u8; -+ const uint8_t *cu8; -+ uintptr_t u; -+ } ptrs_t; -+ ptrs_t destp, srcp, bufp; -+ uintptr_t align; -+ struct ssh_aes_ctr_ctx_mt *c; -+ struct kq *q, *oldq; -+ int ridx; -+ u_char *buf; -+ -+ if (len == 0) -+ return 1; -+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) -+ return 0; -+ -+ q = &c->q[c->qidx]; -+ ridx = c->ridx; -+ -+ /* src already padded to block multiple */ -+ srcp.cu8 = src; -+ destp.u8 = dest; -+ while (len > 0) { -+ buf = q->keys[ridx]; -+ bufp.u8 = buf; -+ -+ /* figure out the alignment on the fly */ -+#ifdef CIPHER_UNALIGNED_OK -+ align = 0; -+#else -+ align = destp.u | srcp.u | bufp.u; -+#endif -+ -+#ifdef CIPHER_INT128_OK -+ if ((align & 0xf) == 0) { -+ destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; -+ } else -+#endif -+ if ((align & 0x7) == 0) { -+ destp.u64[0] = srcp.u64[0] ^ bufp.u64[0]; -+ destp.u64[1] = srcp.u64[1] ^ bufp.u64[1]; -+ } else if ((align & 0x3) == 0) { -+ destp.u32[0] = srcp.u32[0] ^ bufp.u32[0]; -+ destp.u32[1] = srcp.u32[1] ^ bufp.u32[1]; -+ destp.u32[2] = srcp.u32[2] ^ bufp.u32[2]; -+ destp.u32[3] = srcp.u32[3] ^ bufp.u32[3]; -+ } else { -+ size_t i; -+ for (i = 0; i < AES_BLOCK_SIZE; ++i) -+ dest[i] = src[i] ^ buf[i]; -+ } -+ -+ destp.u += AES_BLOCK_SIZE; -+ srcp.u += AES_BLOCK_SIZE; -+ len -= AES_BLOCK_SIZE; -+ ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); -+ -+ /* Increment read index, switch queues on rollover */ -+ if ((ridx = (ridx + 1) % KQLEN) == 0) { -+ oldq = q; -+ -+ /* Mark next queue draining, may need to wait */ -+ c->qidx = (c->qidx + 1) % numkq; -+ q = &c->q[c->qidx]; -+ pthread_mutex_lock(&q->lock); -+ while (q->qstate != KQFULL) { -+ STATS_WAIT(c->stats); -+ pthread_cond_wait(&q->cond, &q->lock); -+ } -+ q->qstate = KQDRAINING; -+ pthread_cond_broadcast(&q->cond); -+ pthread_mutex_unlock(&q->lock); -+ -+ /* Mark consumed queue empty and signal producers */ -+ pthread_mutex_lock(&oldq->lock); -+ oldq->qstate = KQEMPTY; -+ STATS_DRAIN(c->stats); -+ pthread_cond_broadcast(&oldq->cond); -+ pthread_mutex_unlock(&oldq->lock); -+ } -+ } -+ c->ridx = ridx; -+ return 1; -+} -+ -+#define HAVE_NONE 0 -+#define HAVE_KEY 1 -+#define HAVE_IV 2 -+ -+int X = 0; -+ -+static int -+ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, -+ int enc) -+{ -+ struct ssh_aes_ctr_ctx_mt *c; -+ int i; -+ -+ /* get the number of cores in the system */ -+ /* if it's not linux it currently defaults to 2 */ -+ /* divide by 2 to get threads for each direction (MODE_IN||MODE_OUT) */ -+#ifdef __linux__ -+ cipher_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2; -+#endif /*__linux__*/ -+#ifdef __APPLE__ -+ cipher_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2; -+#endif /*__APPLE__*/ -+#ifdef __FREEBSD__ -+ int req[2]; -+ size_t len; -+ -+ req[0] = CTL_HW; -+ req[1] = HW_NCPU; -+ -+ len = sizeof(ncpu); -+ sysctl(req, 2, &cipher_threads, &len, NULL, 0); -+ cipher_threads = cipher_threads / 2; -+#endif /*__FREEBSD__*/ -+ -+ /* if they have less than 4 cores spin up 4 threads anyway */ -+ if (cipher_threads < 2) -+ cipher_threads = 2; -+ -+ /* assure that we aren't trying to create more threads */ -+ /* than we have in the struct. cipher_threads is half the */ -+ /* total of allowable threads hence the odd looking math here */ -+ if (cipher_threads * 2 > MAX_THREADS) -+ cipher_threads = MAX_THREADS / 2; -+ -+ /* set the number of keystream queues */ -+ numkq = cipher_threads * 2; -+ -+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { -+ c = xmalloc(sizeof(*c)); -+ pthread_rwlock_init(&c->tid_lock, NULL); -+#ifdef __APPLE__ -+ pthread_rwlock_init(&c->stop_lock, NULL); -+ c->exit_flag = FALSE; -+#endif /* __APPLE__ */ -+ -+ c->state = HAVE_NONE; -+ for (i = 0; i < numkq; i++) { -+ pthread_mutex_init(&c->q[i].lock, NULL); -+ pthread_cond_init(&c->q[i].cond, NULL); -+ } -+ -+ STATS_INIT(c->stats); -+ EVP_CIPHER_CTX_set_app_data(ctx, c); -+ } -+ -+ if (c->state == (HAVE_KEY | HAVE_IV)) { -+ /* tell the pregen threads to exit */ -+ stop_and_join_pregen_threads(c); -+ -+#ifdef __APPLE__ -+ /* reset the exit flag */ -+ c->exit_flag = FALSE; -+#endif /* __APPLE__ */ -+ -+ /* Start over getting key & iv */ -+ c->state = HAVE_NONE; -+ } -+ -+ if (key != NULL) { -+ AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, -+ &c->aes_ctx); -+ c->state |= HAVE_KEY; -+ } -+ -+ if (iv != NULL) { -+ memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); -+ c->state |= HAVE_IV; -+ } -+ -+ if (c->state == (HAVE_KEY | HAVE_IV)) { -+ /* Clear queues */ -+ memcpy(c->q[0].ctr, c->aes_counter, AES_BLOCK_SIZE); -+ c->q[0].qstate = KQINIT; -+ for (i = 1; i < numkq; i++) { -+ memcpy(c->q[i].ctr, c->aes_counter, AES_BLOCK_SIZE); -+ ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE); -+ c->q[i].qstate = KQEMPTY; -+ } -+ c->qidx = 0; -+ c->ridx = 0; -+ -+ /* Start threads */ -+ for (i = 0; i < cipher_threads; i++) { -+ pthread_rwlock_wrlock(&c->tid_lock); -+ if (pthread_create(&c->tid[i], NULL, thread_loop, c) != 0) -+ debug ("AES-CTR MT Could not create thread in %s", __FUNCTION__); /*should die here */ -+ else { -+ if (!c->struct_id) -+ c->struct_id = X++; -+ c->id[i] = i; -+ debug ("AES-CTR MT spawned a thread with id %lu in %s (%d, %d)", c->tid[i], __FUNCTION__, c->struct_id, c->id[i]); -+ } -+ pthread_rwlock_unlock(&c->tid_lock); -+ } -+ pthread_mutex_lock(&c->q[0].lock); -+ while (c->q[0].qstate == KQINIT) -+ pthread_cond_wait(&c->q[0].cond, &c->q[0].lock); -+ pthread_mutex_unlock(&c->q[0].lock); -+ } -+ return 1; -+} -+ -+/* this function is no longer used but might prove handy in the future -+ * this comment also applies to ssh_aes_ctr_thread_reconstruction -+ */ -+void -+ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx) -+{ -+ struct ssh_aes_ctr_ctx_mt *c; -+ -+ c = EVP_CIPHER_CTX_get_app_data(ctx); -+ stop_and_join_pregen_threads(c); -+} -+ -+void -+ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx) -+{ -+ struct ssh_aes_ctr_ctx_mt *c; -+ int i; -+ c = EVP_CIPHER_CTX_get_app_data(ctx); -+ /* reconstruct threads */ -+ for (i = 0; i < cipher_threads; i++) { -+ pthread_rwlock_wrlock(&c->tid_lock); -+ if (pthread_create(&c->tid[i], NULL, thread_loop, c) !=0 ) -+ debug("AES-CTR MT could not create thread in %s", __FUNCTION__); -+ else { -+ c->struct_id = X++; -+ c->id[i] = i; -+ debug ("AES-CTR MT spawned a thread with id %lu in %s (%d, %d)", c->tid[i], __FUNCTION__, c->struct_id, c->id[i]); -+ debug("AES-CTR MT spawned a thread with id %lu in %s", c->tid[i], __FUNCTION__); -+ } -+ pthread_rwlock_unlock(&c->tid_lock); -+ } -+} -+ -+static int -+ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) -+{ -+ struct ssh_aes_ctr_ctx_mt *c; -+ -+ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { -+#ifdef CIPHER_THREAD_STATS -+ debug("AES-CTR MT main thread: %u drains, %u waits", c->stats.drains, -+ c->stats.waits); -+#endif -+ stop_and_join_pregen_threads(c); -+ -+ memset(c, 0, sizeof(*c)); -+ free(c); -+ EVP_CIPHER_CTX_set_app_data(ctx, NULL); -+ } -+ return 1; -+} -+ -+/* */ -+const EVP_CIPHER * -+evp_aes_ctr_mt(void) -+{ -+# if OPENSSL_VERSION_NUMBER >= 0x10100000UL -+ static EVP_CIPHER *aes_ctr; -+ aes_ctr = EVP_CIPHER_meth_new(NID_undef, 16/*block*/, 16/*key*/); -+ EVP_CIPHER_meth_set_iv_length(aes_ctr, AES_BLOCK_SIZE); -+ EVP_CIPHER_meth_set_init(aes_ctr, ssh_aes_ctr_init); -+ EVP_CIPHER_meth_set_cleanup(aes_ctr, ssh_aes_ctr_cleanup); -+ EVP_CIPHER_meth_set_do_cipher(aes_ctr, ssh_aes_ctr); -+# ifndef SSH_OLD_EVP -+ EVP_CIPHER_meth_set_flags(aes_ctr, EVP_CIPH_CBC_MODE -+ | EVP_CIPH_VARIABLE_LENGTH -+ | EVP_CIPH_ALWAYS_CALL_INIT -+ | EVP_CIPH_CUSTOM_IV); -+# endif /*SSH_OLD_EVP*/ -+ return (aes_ctr); -+# else /*earlier versions of openssl*/ -+ static EVP_CIPHER aes_ctr; -+ memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); -+ aes_ctr.nid = NID_undef; -+ aes_ctr.block_size = AES_BLOCK_SIZE; -+ aes_ctr.iv_len = AES_BLOCK_SIZE; -+ aes_ctr.key_len = 16; -+ aes_ctr.init = ssh_aes_ctr_init; -+ aes_ctr.cleanup = ssh_aes_ctr_cleanup; -+ aes_ctr.do_cipher = ssh_aes_ctr; -+# ifndef SSH_OLD_EVP -+ aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | -+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; -+# endif /*SSH_OLD_EVP*/ -+ return &aes_ctr; -+# endif /*OPENSSH_VERSION_NUMBER*/ -+} -+ -+#endif /* defined(WITH_OPENSSL) */ -diff -Nur openssh-8.6p1.orig/cipher.h openssh-8.6p1/cipher.h ---- openssh-8.6p1.orig/cipher.h 2021-05-22 08:23:21.025175658 +0200 -+++ openssh-8.6p1/cipher.h 2021-05-22 08:24:33.543345602 +0200 -@@ -68,7 +68,9 @@ - - struct sshcipher_ctx; - --const struct sshcipher *cipher_by_name(const char *); -+void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); // defined in cipher-ctr-mt.c -+void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx); -+struct sshcipher *cipher_by_name(const char *); - const char *cipher_warning_message(const struct sshcipher_ctx *); - int ciphers_valid(const char *); - char *cipher_alg_list(char, int); -@@ -86,6 +88,8 @@ - u_int cipher_authlen(const struct sshcipher *); - u_int cipher_ivlen(const struct sshcipher *); - u_int cipher_is_cbc(const struct sshcipher *); -+void cipher_reset_multithreaded(void); -+const char *cipher_ctx_name(const struct sshcipher_ctx *); - - u_int cipher_ctx_is_plaintext(struct sshcipher_ctx *); - -diff -Nur openssh-8.6p1.orig/clientloop.c openssh-8.6p1/clientloop.c ---- openssh-8.6p1.orig/clientloop.c 2021-05-22 08:23:20.932175440 +0200 -+++ openssh-8.6p1/clientloop.c 2021-05-22 08:24:33.544345604 +0200 -@@ -1593,7 +1593,9 @@ - return NULL; - c = channel_new(ssh, "x11", - SSH_CHANNEL_X11_OPEN, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); -+ /* again is this really necessary for X11? */ -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); - c->force_drain = 1; - return c; - } -@@ -1622,7 +1624,8 @@ - } - c = channel_new(ssh, "authentication agent connection", - SSH_CHANNEL_OPEN, sock, sock, -1, -- CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, -+ options.hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, - "authentication agent connection", 1); - c->force_drain = 1; - return c; -@@ -1649,7 +1652,8 @@ - debug("Tunnel forwarding using interface %s", ifname); - - c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); - c->datagram = 1; - - #if defined(SSH_TUN_FILTER) -diff -Nur openssh-8.6p1.orig/compat.c openssh-8.6p1/compat.c ---- openssh-8.6p1.orig/compat.c 2021-05-22 08:23:21.044175703 +0200 -+++ openssh-8.6p1/compat.c 2021-05-22 08:24:33.544345604 +0200 -@@ -150,6 +150,17 @@ - debug_f("match: %s pat %s compat 0x%08x", - version, check[i].pat, check[i].bugs); - ssh->compat = check[i].bugs; -+ /* Check to see if the remote side is OpenSSH and not HPN */ -+ /* TODO: See if we can work this into the new method for bug checks */ -+ if (strstr(version, "OpenSSH") != NULL) { -+ if (strstr(version, "hpn") == NULL) { -+ ssh->compat |= SSH_BUG_LARGEWINDOW; -+ debug("Remote is NOT HPN enabled"); -+ } else { -+ debug("Remote is HPN Enabled"); -+ } -+ } -+ debug("ssh->compat is %u", ssh->compat); - return; - } - } -diff -Nur openssh-8.6p1.orig/compat.h openssh-8.6p1/compat.h ---- openssh-8.6p1.orig/compat.h 2021-05-22 08:23:21.013175630 +0200 -+++ openssh-8.6p1/compat.h 2021-05-22 08:24:33.545345607 +0200 -@@ -57,6 +57,7 @@ - #define SSH_BUG_CURVE25519PAD 0x10000000 - #define SSH_BUG_HOSTKEYS 0x20000000 - #define SSH_BUG_DHGEX_LARGE 0x40000000 -+#define SSH_BUG_LARGEWINDOW 0x80000000 - - struct ssh; - -diff -Nur openssh-8.6p1.orig/defines.h openssh-8.6p1/defines.h ---- openssh-8.6p1.orig/defines.h 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/defines.h 2021-05-22 08:24:33.545345607 +0200 -@@ -848,7 +848,7 @@ - #endif - - #ifndef SSH_IOBUFSZ --# define SSH_IOBUFSZ 8192 -+# define SSH_IOBUFSZ 32*1024 - #endif - - /* -diff -Nur openssh-8.6p1.orig/digest.h openssh-8.6p1/digest.h ---- openssh-8.6p1.orig/digest.h 2021-05-22 08:23:21.003175607 +0200 -+++ openssh-8.6p1/digest.h 2021-05-22 08:24:33.545345607 +0200 -@@ -27,7 +27,8 @@ - #define SSH_DIGEST_SHA256 2 - #define SSH_DIGEST_SHA384 3 - #define SSH_DIGEST_SHA512 4 --#define SSH_DIGEST_MAX 5 -+#define SSH_DIGEST_NULL 5 -+#define SSH_DIGEST_MAX 6 - - struct sshbuf; - struct ssh_digest_ctx; -diff -Nur openssh-8.6p1.orig/digest-openssl.c openssh-8.6p1/digest-openssl.c ---- openssh-8.6p1.orig/digest-openssl.c 2021-05-22 08:23:21.003175607 +0200 -+++ openssh-8.6p1/digest-openssl.c 2021-05-22 08:24:33.546345609 +0200 -@@ -61,6 +61,7 @@ - { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, - { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, - { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, -+ { SSH_DIGEST_NULL, "NONEMAC", 0, EVP_md_null}, - { -1, NULL, 0, NULL }, - }; - -diff -Nur openssh-8.6p1.orig/HPN-README openssh-8.6p1/HPN-README ---- openssh-8.6p1.orig/HPN-README 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-8.6p1/HPN-README 2021-05-22 08:24:33.546345609 +0200 -@@ -0,0 +1,153 @@ -+Notes: -+ -+MULTI-THREADED CIPHER: -+The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations -+on hosts with multiple cores to use more than one processing core during encryption. -+Tests have show significant throughput performance increases when using MTR-AES-CTR up -+to and including a full gigabit per second on quad core systems. It should be possible to -+achieve full line rate on dual core systems but OS and data management overhead makes this -+more difficult to achieve. The cipher stream from MTR-AES-CTR is entirely compatible with single -+thread AES-CTR (ST-AES-CTR) implementations and should be 100% backward compatible. Optimal -+performance requires the MTR-AES-CTR mode be enabled on both ends of the connection. -+The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same -+nomenclature. -+Use examples: -+ ssh -caes128-ctr you@host.com -+ scp -oCipher=aes256-ctr file you@host.com:~/file -+ -+NONE CIPHER: -+To use the NONE option you must have the NoneEnabled switch set on the server and -+you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE -+feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not -+spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will -+be disabled. -+ -+The performance increase will only be as good as the network and TCP stack tuning -+on the reciever side of the connection allows. As a rule of thumb a user will need -+at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The -+HPN-SSH home page describes this in greater detail. -+ -+http://www.psc.edu/networking/projects/hpn-ssh -+ -+NONE MAC: -+Starting with HPN 15v1 users will have the option to disable HMAC (message -+authentication ciphers) when using the NONE cipher. You must enable the following: -+NoneEnabled, NoneSwitch, and NoneMacEnabled. If all three are not enabled the None MAC -+will be automatically disabled. In tests the use of the None MAC improved throuput by -+more than 30%. -+ -+ex: scp -oNoneSwitch=yes -oNoneEnabled=yes -oNoneMacEnabled=yes file host:~ -+ -+BUFFER SIZES: -+ -+If HPN is disabled the receive buffer size will be set to the -+OpenSSH default of 2MB (for OpenSSH versions before 4.7: 64KB). -+ -+If an HPN system connects to a nonHPN system the receive buffer will -+be set to the HPNBufferSize value. The default is 2MB but user adjustable. -+ -+If an HPN to HPN connection is established a number of different things might -+happen based on the user options and conditions. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set -+HPN Buffer Size = up to 64MB -+This is the default state. The HPN buffer size will grow to a maximum of 64MB -+as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is -+geared towards 10GigE transcontinental connections. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set -+HPN Buffer Size = TCP receive buffer value. -+Users on non-autotuning systems should disable TCPRcvBufPoll in the -+ssh_config and sshd_config -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set -+HPN Buffer Size = minimum of TCP receive buffer and HPNBufferSize. -+This would be the system defined TCP receive buffer (RWIN). -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET -+HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. -+Generally there is no need to set both. -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set -+HPN Buffer Size = grows to HPNBufferSize -+The buffer will grow up to the maximum size specified here. -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET -+HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. -+Generally there is no need to set both of these, especially on autotuning -+systems. However, if the users wishes to override the autotuning this would be -+one way to do it. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET -+HPN Buffer Size = TCPRcvBuf. -+This will override autotuning and set the TCP recieve buffer to the user defined -+value. -+ -+ -+HPN Specific Configuration options -+ -+TcpRcvBuf=[int]KB client -+ Set the TCP socket receive buffer to n Kilobytes. It can be set up to the -+maximum socket size allowed by the system. This is useful in situations where -+the tcp receive window is set low but the maximum buffer size is set -+higher (as is typical). This works on a per TCP connection basis. You can also -+use this to artifically limit the transfer rate of the connection. In these -+cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. -+Default is the current system wide tcp receive buffer size. -+ -+TcpRcvBufPoll=[yes/no] client/server -+ Enable of disable the polling of the tcp receive buffer through the life -+of the connection. You would want to make sure that this option is enabled -+for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista) -+default is yes. -+ -+NoneEnabled=[yes/no] client/server -+ Enable or disable the use of the None cipher. Care must always be used -+when enabling this as it will allow users to send data in the clear. However, -+it is important to note that authentication information remains encrypted -+even if this option is enabled. Set to no by default. -+ -+NoneMacEnabled=[yes/no] client/server -+ Enable or disable the use of the None MAC. When this is enabled ssh -+will *not* provide data integrity of any data being transmitted between hosts. Use -+with caution as it, unlike just using NoneEnabled, doesn't provide data integrity and -+protection against man-in-the-middle attacks. As with NoneEnabled all authentication -+remains encrypted and integrity is ensured. Default is no. -+ -+NoneSwitch=[yes/no] client -+ Switch the encryption cipher being used to the None cipher after -+authentication takes place. NoneEnabled must be enabled on both the client -+and server side of the connection. When the connection switches to the NONE -+cipher a warning is sent to STDERR. The connection attempt will fail with an -+error if a client requests a NoneSwitch from the server that does not explicitly -+have NoneEnabled set to yes. Note: The NONE cipher cannot be used in -+interactive (shell) sessions and it will fail silently. Set to no by default. -+ -+HPNDisabled=[yes/no] client/server -+ In some situations, such as transfers on a local area network, the impact -+of the HPN code produces a net decrease in performance. In these cases it is -+helpful to disable the HPN functionality. By default HPNDisabled is set to no. -+ -+HPNBufferSize=[int]KB client/server -+ This is the default buffer size the HPN functionality uses when interacting -+with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf -+option as applied to the internal SSH flow control. This value can range from -+1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance -+problems depending on the length of the network path. The default size of this buffer -+is 2MB. -+ -+DisableMTAES=[yes/no] client/server -+ Switch the encryption cipher being used from the multithreaded MT-AES-CTR cipher -+back to the stock single-threaded AES-CTR cipher. Useful on modern processors with -+AES-NI instructions which make the stock single-threaded AES-CTR cipher faster than -+the multithreaded MT-AES-CTR cipher. Set to no by default. -+ -+ -+Credits: This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) -+ The majority of the actual coding for versions up to HPN12v1 was performed -+ by Michael Stevens (mstevens@andrew.cmu.edu). The MT-AES-CTR cipher was -+ implemented by Ben Bennet (ben@psc.edu) and improved by Mike Tasota -+ (tasota@gmail.com) an NSF REU grant recipient for 2013. -+ Allan Jude provided the code for the NoneMac and buffer normalization. -+ This work was financed, in part, by Cisco System, Inc., the National -+ Library of Medicine, and the National Science Foundation. -diff -Nur openssh-8.6p1.orig/kex.c openssh-8.6p1/kex.c ---- openssh-8.6p1.orig/kex.c 2021-05-22 08:23:21.036175684 +0200 -+++ openssh-8.6p1/kex.c 2021-05-22 08:24:33.547345612 +0200 -@@ -64,6 +64,7 @@ - - #include "ssherr.h" - #include "sshbuf.h" -+#include "canohost.h" - #include "digest.h" - #include "audit.h" - -@@ -969,6 +970,11 @@ - int nenc, nmac, ncomp; - u_int mode, ctos, need, dh_need, authlen; - int r, first_kex_follows; -+ int auth_flag = 0; -+ int log_flag = 0; -+ -+ auth_flag = packet_authentication_state(ssh); -+ debug("AUTH STATE IS %d", auth_flag); - - debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); - if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) -@@ -1039,11 +1045,40 @@ - peer[ncomp] = NULL; - goto out; - } -+ debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); -+ debug("REQUESTED MAC.NAME is '%s'", newkeys->mac.name); -+ if (strcmp(newkeys->enc.name, "none") == 0) { -+ if (auth_flag == 1) { -+ debug("None requested post authentication."); -+ ssh->none = 1; -+ } -+ else -+ fatal("Pre-authentication none cipher requests are not allowed."); -+ if (newkeys->mac.name != NULL && strcmp(newkeys->mac.name, "none") == 0) -+ debug("Requesting: NONEMAC. Authflag is %d", auth_flag); -+ } -+ - debug("kex: %s cipher: %s MAC: %s compression: %s", - ctos ? "client->server" : "server->client", - newkeys->enc.name, - authlen == 0 ? newkeys->mac.name : "", - newkeys->comp.name); -+ /* -+ * client starts with ctos = 0 && log flag = 0 and no log. -+ * 2nd client pass ctos = 1 and flag = 1 so no log. -+ * server starts with ctos = 1 && log_flag = 0 so log. -+ * 2nd sever pass ctos = 1 && log flag = 1 so no log. -+ * -cjr -+ */ -+ if (ctos && !log_flag) { -+ logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s", -+ ssh_remote_ipaddr(ssh), -+ ssh_remote_port(ssh), -+ newkeys->enc.name, -+ authlen == 0 ? newkeys->mac.name : "", -+ newkeys->comp.name); -+ } -+ log_flag = 1; - } - need = dh_need = 0; - for (mode = 0; mode < MODE_MAX; mode++) { -@@ -1391,7 +1426,7 @@ - if (version_addendum != NULL && *version_addendum == '\0') - version_addendum = NULL; - if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n", -- PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, -+ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE, - version_addendum == NULL ? "" : " ", - version_addendum == NULL ? "" : version_addendum)) != 0) { - oerrno = errno; -@@ -1527,6 +1562,14 @@ - r = SSH_ERR_INVALID_FORMAT; - goto out; - } -+ -+ /* report the version information to syslog if this is the server */ -+ if (timeout_ms == -1) { /* only the server uses this value */ -+ logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", -+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), -+ remote_major, remote_minor, remote_version); -+ } -+ - debug("Remote protocol version %d.%d, remote software version %.100s", - remote_major, remote_minor, remote_version); - compat_banner(ssh, remote_version); -diff -Nur openssh-8.6p1.orig/log.c openssh-8.6p1/log.c ---- openssh-8.6p1.orig/log.c 2021-05-22 08:23:20.963175513 +0200 -+++ openssh-8.6p1/log.c 2021-05-22 08:24:33.547345612 +0200 -@@ -46,6 +46,11 @@ - #include - #include - #include -+#include "packet.h" /* needed for host and port look ups */ -+#ifdef HAVE_SYS_TIME_H -+# include /* to get current time */ -+#endif -+ - #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) - # include - #endif -@@ -65,6 +70,8 @@ - - extern char *__progname; - -+extern struct ssh *active_state; -+ - #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) - #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) - -diff -Nur openssh-8.6p1.orig/mac.c openssh-8.6p1/mac.c ---- openssh-8.6p1.orig/mac.c 2021-05-22 08:23:21.025175658 +0200 -+++ openssh-8.6p1/mac.c 2021-05-22 08:24:33.547345612 +0200 -@@ -63,6 +63,7 @@ - { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, - { "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 }, - { "hmac-md5-96", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 0 }, -+ { "none", SSH_DIGEST, SSH_DIGEST_NULL, 0, 0, 0, 0 }, - { "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 }, - { "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 }, - -diff -Nur openssh-8.6p1.orig/Makefile.in openssh-8.6p1/Makefile.in ---- openssh-8.6p1.orig/Makefile.in 2021-05-22 08:23:21.061175742 +0200 -+++ openssh-8.6p1/Makefile.in 2021-05-22 08:24:33.548345614 +0200 -@@ -48,7 +48,7 @@ - CFLAGS_NOPIE=@CFLAGS_NOPIE@ - CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ - PICFLAG=@PICFLAG@ --LIBS=@LIBS@ -+LIBS=@LIBS@ -lpthread - K5LIBS=@K5LIBS@ - GSSLIBS=@GSSLIBS@ - SSHDLIBS=@SSHDLIBS@ -@@ -95,7 +95,7 @@ - LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - authfd.o authfile.o \ - canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \ -- cipher-ctr.o cleanup.o \ -+ cipher-ctr.o cleanup.o cipher-ctr-mt.o \ - compat.o fatal.o hostfile.o \ - log.o match.o moduli.o nchan.o packet.o \ - readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \ -diff -Nur openssh-8.6p1.orig/packet.c openssh-8.6p1/packet.c ---- openssh-8.6p1.orig/packet.c 2021-05-22 08:23:21.028175665 +0200 -+++ openssh-8.6p1/packet.c 2021-05-22 08:24:33.549345616 +0200 -@@ -246,7 +246,7 @@ - TAILQ_INIT(&ssh->public_keys); - state->connection_in = -1; - state->connection_out = -1; -- state->max_packet_size = 32768; -+ state->max_packet_size = CHAN_SES_PACKET_DEFAULT; - state->packet_timeout_ms = -1; - state->p_send.packets = state->p_read.packets = 0; - state->initialized = 1; -@@ -294,7 +294,7 @@ - ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) - { - struct session_state *state; -- const struct sshcipher *none = cipher_by_name("none"); -+ struct sshcipher *none = cipher_by_name("none"); - int r; - - if (none == NULL) { -@@ -958,10 +958,19 @@ - * so enforce a 1GB limit for small blocksizes. - * See RFC4344 section 3.2. - */ -- if (enc->block_size >= 16) -- *max_blocks = (u_int64_t)1 << (enc->block_size*2); -- else -- *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; -+ -+ /* we really don't need to rekey if we are using the none cipher -+ * but there isn't a good way to disable it entirely that I can find -+ * and using a blocksize larger that 16 doesn't work (dunno why) -+ * so this seems to be a good limit for now - CJR 10/16/2020*/ -+ if (ssh->none == 1) { -+ *max_blocks = (u_int64_t)1 << (16*2); -+ } else { -+ if (enc->block_size >= 16) -+ *max_blocks = (u_int64_t)1 << (enc->block_size*2); -+ else -+ *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; -+ } - if (state->rekey_limit) - *max_blocks = MINIMUM(*max_blocks, - state->rekey_limit / enc->block_size); -@@ -970,6 +979,24 @@ - return 0; - } - -+/* this supports the forced rekeying required for the NONE cipher */ -+int rekey_requested = 0; -+void -+packet_request_rekeying(void) -+{ -+ rekey_requested = 1; -+} -+ -+/* used to determine if pre or post auth when rekeying for aes-ctr -+ * and none cipher switch */ -+int -+packet_authentication_state(const struct ssh *ssh) -+{ -+ struct session_state *state = ssh->state; -+ -+ return state->after_authentication; -+} -+ - #define MAX_PACKETS (1U<<31) - static int - ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len) -@@ -996,6 +1023,13 @@ - if (state->p_send.packets == 0 && state->p_read.packets == 0) - return 0; - -+ /* used to force rekeying when called for by the none -+ * cipher switch and aes-mt-ctr methods -cjr */ -+ if (rekey_requested == 1) { -+ rekey_requested = 0; -+ return 1; -+ } -+ - /* Time-based rekeying */ - if (state->rekey_interval != 0 && - (int64_t)state->rekey_time + state->rekey_interval <= monotime()) -@@ -1333,7 +1367,7 @@ - struct session_state *state = ssh->state; - int len, r, ms_remain; - fd_set *setp; -- char buf[8192]; -+ char buf[SSH_IOBUFSZ]; - struct timeval timeout, start, *timeoutp = NULL; - - DBG(debug("packet_read()")); -@@ -1865,17 +1899,21 @@ - switch (r) { - case SSH_ERR_CONN_CLOSED: - ssh_packet_clear_keys(ssh); -+ sshpkt_final_log_entry(ssh); - logdie("Connection closed by %s", remote_id); - case SSH_ERR_CONN_TIMEOUT: - ssh_packet_clear_keys(ssh); -+ sshpkt_final_log_entry(ssh); - logdie("Connection %s %s timed out", - ssh->state->server_side ? "from" : "to", remote_id); - case SSH_ERR_DISCONNECTED: - ssh_packet_clear_keys(ssh); -+ sshpkt_final_log_entry(ssh); - logdie("Disconnected from %s", remote_id); - case SSH_ERR_SYSTEM_ERROR: - if (errno == ECONNRESET) { - ssh_packet_clear_keys(ssh); -+ sshpkt_final_log_entry(ssh); - logdie("Connection reset by %s", remote_id); - } - /* FALLTHROUGH */ -@@ -1917,6 +1955,24 @@ - logdie_f("should have exited"); - } - -+/* this prints out the final log entry */ -+void -+sshpkt_final_log_entry (struct ssh *ssh) { -+ double total_time; -+ -+ if (ssh->start_time < 1) -+ /* this will produce a NaN in the output. -cjr */ -+ total_time = 0; -+ else -+ total_time = monotime_double() - ssh->start_time; -+ -+ logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", -+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), -+ ssh->stdin_bytes, ssh->fdout_bytes, total_time, -+ ssh->stdin_bytes / total_time, -+ ssh->fdout_bytes / total_time); -+} -+ - /* - * Logs the error plus constructs and sends a disconnect packet, closes the - * connection, and exits. This function never returns. The error message -@@ -2789,3 +2845,10 @@ - ssh->state->extra_pad = pad; - return 0; - } -+ -+/* need this for the moment for the aes-ctr cipher */ -+void * -+ssh_packet_get_send_context(struct ssh *ssh) -+{ -+ return ssh->state->send_context; -+} -diff -Nur openssh-8.6p1.orig/packet.h openssh-8.6p1/packet.h ---- openssh-8.6p1.orig/packet.h 2021-05-22 08:23:21.028175665 +0200 -+++ openssh-8.6p1/packet.h 2021-05-22 08:24:33.549345616 +0200 -@@ -86,6 +86,14 @@ - - /* APP data */ - void *app_data; -+ -+ /* logging data for ServerLogging patch*/ -+ double start_time; -+ u_long fdout_bytes; -+ u_long stdin_bytes; -+ -+ /* track that we are in a none cipher/mac state */ -+ int none; - }; - - typedef int (ssh_packet_hook_fn)(struct ssh *, struct sshbuf *, -@@ -155,6 +163,8 @@ - int ssh_packet_set_maxsize(struct ssh *, u_int); - u_int ssh_packet_get_maxsize(struct ssh *); - -+int packet_authentication_state(const struct ssh *); -+ - int ssh_packet_get_state(struct ssh *, struct sshbuf *); - int ssh_packet_set_state(struct ssh *, struct sshbuf *); - -@@ -169,6 +179,13 @@ - - void *ssh_packet_get_input(struct ssh *); - void *ssh_packet_get_output(struct ssh *); -+void *ssh_packet_get_receive_context(struct ssh *); -+void *ssh_packet_get_send_context(struct ssh *); -+ -+/* for forced packet rekeying post auth */ -+void packet_request_rekeying(void); -+/* final log entry support */ -+void sshpkt_final_log_entry (struct ssh *); - - /* new API */ - int sshpkt_start(struct ssh *ssh, u_char type); -diff -Nur openssh-8.6p1.orig/progressmeter.c openssh-8.6p1/progressmeter.c ---- openssh-8.6p1.orig/progressmeter.c 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/progressmeter.c 2021-05-22 08:24:33.549345616 +0200 -@@ -68,6 +68,8 @@ - static off_t start_pos; /* initial position of transfer */ - static off_t end_pos; /* ending position of transfer */ - static off_t cur_pos; /* transfer position as of last refresh */ -+static off_t last_pos; -+static off_t max_delta_pos = 0; - static volatile off_t *counter; /* progress counter */ - static long stalled; /* how long we have been stalled */ - static int bytes_per_second; /* current speed in bytes per second */ -@@ -127,6 +129,7 @@ - int cur_speed; - int hours, minutes, seconds; - int file_len; -+ off_t delta_pos; - - if ((!force_update && !alarm_fired && !win_resized) || !can_output()) - return; -@@ -142,6 +145,10 @@ - now = monotime_double(); - bytes_left = end_pos - cur_pos; - -+ delta_pos = cur_pos - last_pos; -+ if (delta_pos > max_delta_pos) -+ max_delta_pos = delta_pos; -+ - if (bytes_left > 0) - elapsed = now - last_update; - else { -@@ -166,7 +173,7 @@ - - /* filename */ - buf[0] = '\0'; -- file_len = win_size - 36; -+ file_len = win_size - 45; - if (file_len > 0) { - buf[0] = '\r'; - snmprintf(buf+1, sizeof(buf)-1, &file_len, "%-*s", -@@ -191,6 +198,15 @@ - (off_t)bytes_per_second); - strlcat(buf, "/s ", win_size); - -+ /* instantaneous rate */ -+ if (bytes_left > 0) -+ format_rate(buf + strlen(buf), win_size - strlen(buf), -+ delta_pos); -+ else -+ format_rate(buf + strlen(buf), win_size - strlen(buf), -+ max_delta_pos); -+ strlcat(buf, "/s ", win_size); -+ - /* ETA */ - if (!transferred) - stalled += elapsed; -@@ -227,6 +243,7 @@ - - atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); - last_update = now; -+ last_pos = cur_pos; - } - - /*ARGSUSED*/ -diff -Nur openssh-8.6p1.orig/readconf.c openssh-8.6p1/readconf.c ---- openssh-8.6p1.orig/readconf.c 2021-05-22 08:23:21.064175750 +0200 -+++ openssh-8.6p1/readconf.c 2021-05-22 08:24:33.550345619 +0200 -@@ -67,6 +67,7 @@ - #include "uidswap.h" - #include "myproposal.h" - #include "digest.h" -+#include "sshbuf.h" - #include "ssh-gss.h" - - /* Format of the configuration file: -@@ -169,6 +170,9 @@ - oHashKnownHosts, - oTunnel, oTunnelDevice, - oLocalCommand, oPermitLocalCommand, oRemoteCommand, -+ oTcpRcvBufPoll, oTcpRcvBuf, oHPNDisabled, oHPNBufferSize, -+ oNoneEnabled, oNoneMacEnabled, oNoneSwitch, -+ oDisableMTAES, - oVisualHostKey, - oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, - oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, -@@ -312,6 +316,10 @@ - { "kexalgorithms", oKexAlgorithms }, - { "ipqos", oIPQoS }, - { "requesttty", oRequestTTY }, -+ { "noneenabled", oNoneEnabled }, -+ { "nonemacenabled", oNoneMacEnabled }, -+ { "noneswitch", oNoneSwitch }, -+ { "disablemtaes", oDisableMTAES }, - { "proxyusefdpass", oProxyUseFdpass }, - { "canonicaldomains", oCanonicalDomains }, - { "canonicalizefallbacklocal", oCanonicalizeFallbackLocal }, -@@ -332,6 +340,11 @@ - { "securitykeyprovider", oSecurityKeyProvider }, - { "knownhostscommand", oKnownHostsCommand }, - -+ { "tcprcvbufpoll", oTcpRcvBufPoll }, -+ { "tcprcvbuf", oTcpRcvBuf }, -+ { "hpndisabled", oHPNDisabled }, -+ { "hpnbuffersize", oHPNBufferSize }, -+ - { NULL, oBadOption } - }; - -@@ -1138,6 +1151,46 @@ - intptr = &options->check_host_ip; - goto parse_flag; - -+ case oHPNDisabled: -+ intptr = &options->hpn_disabled; -+ goto parse_flag; -+ -+ case oHPNBufferSize: -+ intptr = &options->hpn_buffer_size; -+ goto parse_int; -+ -+ case oTcpRcvBufPoll: -+ intptr = &options->tcp_rcv_buf_poll; -+ goto parse_flag; -+ -+ case oNoneEnabled: -+ intptr = &options->none_enabled; -+ goto parse_flag; -+ -+ case oNoneMacEnabled: -+ intptr = &options->nonemac_enabled; -+ goto parse_flag; -+ -+ case oDisableMTAES: -+ intptr = &options->disable_multithreaded; -+ goto parse_flag; -+ -+ /* -+ * We check to see if the command comes from the command -+ * line or not. If it does then enable it otherwise fail. -+ * NONE should never be a default configuration. -+ */ -+ case oNoneSwitch: -+ if (strcmp(filename, "command-line") == 0) { -+ intptr = &options->none_switch; -+ goto parse_flag; -+ } else { -+ error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename); -+ error("Continuing..."); -+ debug("NoneSwitch directive found in %.200s.", filename); -+ return 0; -+ } -+ - case oVerifyHostKeyDNS: - intptr = &options->verify_host_key_dns; - multistate_ptr = multistate_yesnoask; -@@ -1371,6 +1424,10 @@ - *intptr = value; - break; - -+ case oTcpRcvBuf: -+ intptr = &options->tcp_rcv_buf; -+ goto parse_int; -+ - case oCiphers: - arg = strdelim(&s); - if (!arg || *arg == '\0') { -@@ -2316,6 +2373,14 @@ - options->ip_qos_interactive = -1; - options->ip_qos_bulk = -1; - options->request_tty = -1; -+ options->none_switch = -1; -+ options->none_enabled = -1; -+ options->nonemac_enabled = -1; -+ options->disable_multithreaded = -1; -+ options->hpn_disabled = -1; -+ options->hpn_buffer_size = -1; -+ options->tcp_rcv_buf_poll = -1; -+ options->tcp_rcv_buf = -1; - options->proxy_use_fdpass = -1; - options->ignored_unknown = NULL; - options->num_canonical_domains = 0; -@@ -2490,6 +2555,43 @@ - options->server_alive_interval = 0; - if (options->server_alive_count_max == -1) - options->server_alive_count_max = 3; -+ if (options->hpn_disabled == -1) -+ options->hpn_disabled = 0; -+ if (options->hpn_buffer_size > -1) { -+ /* if a user tries to set the size to 0 set it to 1KB */ -+ if (options->hpn_buffer_size == 0) -+ options->hpn_buffer_size = 1; -+ /* limit the buffer to SSHBUF_SIZE_MAX (currently 256MB) */ -+ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { -+ options->hpn_buffer_size = SSHBUF_SIZE_MAX; -+ debug("User requested buffer larger than 256MB. Request reverted to 256MB"); -+ } else -+ options->hpn_buffer_size *= 1024; -+ debug("hpn_buffer_size set to %d", options->hpn_buffer_size); -+ } -+ if (options->tcp_rcv_buf == 0) -+ options->tcp_rcv_buf = 1; -+ if (options->tcp_rcv_buf > -1) -+ options->tcp_rcv_buf *=1024; -+ if (options->tcp_rcv_buf_poll == -1) -+ options->tcp_rcv_buf_poll = 1; -+ if (options->none_switch == -1) -+ options->none_switch = 0; -+ if (options->none_enabled == -1) -+ options->none_enabled = 0; -+ if (options->none_enabled == 0 && options->none_switch > 0) { -+ fprintf(stderr, "NoneEnabled must be enabled to use the None Switch option. None cipher disabled.\n"); -+ options->none_enabled = 0; -+ } -+ if (options->nonemac_enabled == -1) -+ options->nonemac_enabled = 0; -+ if (options->nonemac_enabled > 0 && (options->none_enabled == 0 || -+ options->none_switch == 0)) { -+ fprintf(stderr, "None MAC can only be used with the None cipher. None MAC disabled.\n"); -+ options->nonemac_enabled = 0; -+ } -+ if (options->disable_multithreaded == -1) -+ options->disable_multithreaded = 0; - if (options->control_master == -1) - options->control_master = 0; - if (options->control_persist == -1) { -diff -Nur openssh-8.6p1.orig/readconf.h openssh-8.6p1/readconf.h ---- openssh-8.6p1.orig/readconf.h 2021-05-22 08:23:21.064175750 +0200 -+++ openssh-8.6p1/readconf.h 2021-05-22 08:24:33.551345621 +0200 -@@ -57,6 +57,10 @@ - int strict_host_key_checking; /* Strict host key checking. */ - int compression; /* Compress packets in both directions. */ - int tcp_keep_alive; /* Set SO_KEEPALIVE. */ -+ int tcp_rcv_buf; /* user switch to set tcp recv buffer */ -+ int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ -+ int hpn_disabled; /* Switch to disable HPN buffer management */ -+ int hpn_buffer_size; /* User definable size for HPN buffer window */ - int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ - int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ - SyslogFacility log_facility; /* Facility for system logging. */ -@@ -128,7 +132,12 @@ - - int enable_ssh_keysign; - int64_t rekey_limit; -+ int none_switch; /* Use none cipher */ -+ int none_enabled; /* Allow none to be used */ -+ int nonemac_enabled; /* Allow none to be used */ -+ int disable_multithreaded; /*disable multithreaded aes-ctr*/ - int rekey_interval; -+ - int no_host_authentication_for_localhost; - int identities_only; - int server_alive_interval; -diff -Nur openssh-8.6p1.orig/regress/integrity.sh openssh-8.6p1/regress/integrity.sh ---- openssh-8.6p1.orig/regress/integrity.sh 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/integrity.sh 2021-05-22 08:24:33.551345621 +0200 -@@ -21,6 +21,12 @@ - cmd="$SUDO env SSH_SK_HELPER="$SSH_SK_HELPER" sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" - - for m in $macs; do -+ # the none mac is now valid but tests against it will succeed when we expect it to -+ # fail. so we need to explicity remove it from the list of macs returned. -+ if [ "$m" = "none" ]; then -+ continue -+ fi -+ - trace "test $tid: mac $m" - elen=0 - epad=0 -diff -Nur openssh-8.6p1.orig/sandbox-seccomp-filter.c openssh-8.6p1/sandbox-seccomp-filter.c ---- openssh-8.6p1.orig/sandbox-seccomp-filter.c 2021-05-22 08:23:21.037175686 +0200 -+++ openssh-8.6p1/sandbox-seccomp-filter.c 2021-05-22 08:24:33.552345623 +0200 -@@ -225,6 +225,9 @@ - #ifdef __NR_geteuid32 - SC_ALLOW(__NR_geteuid32), - #endif -+#ifdef __NR_getpeername /* not defined on archs that go via socketcall(2) */ -+ SC_ALLOW(__NR_getpeername), -+#endif - #ifdef __NR_getpgid - SC_ALLOW(__NR_getpgid), - #endif -@@ -318,6 +321,9 @@ - #ifdef __NR_sigprocmask - SC_ALLOW(__NR_sigprocmask), - #endif -+#ifdef __NR_socketcall -+ SC_ALLOW(__NR_socketcall), -+#endif - #ifdef __NR_time - SC_ALLOW(__NR_time), - #endif -diff -Nur openssh-8.6p1.orig/scp.c openssh-8.6p1/scp.c ---- openssh-8.6p1.orig/scp.c 2021-05-22 08:23:21.048175712 +0200 -+++ openssh-8.6p1/scp.c 2021-05-22 08:24:33.552345623 +0200 -@@ -1251,7 +1251,7 @@ - off_t size, statbytes; - unsigned long long ull; - int setimes, targisdir, wrerr; -- char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; -+ char ch, *cp, *np, *targ, *why, *vect[1], buf[16384], visbuf[16384]; - char **patterns = NULL; - size_t n, npatterns = 0; - struct timeval tv[2]; -diff -Nur openssh-8.6p1.orig/servconf.c openssh-8.6p1/servconf.c ---- openssh-8.6p1.orig/servconf.c 2021-05-22 08:23:21.064175750 +0200 -+++ openssh-8.6p1/servconf.c 2021-05-22 08:24:33.553345625 +0200 -@@ -70,6 +70,7 @@ - #include "auth.h" - #include "myproposal.h" - #include "digest.h" -+#include "sshbuf.h" - #include "ssh-gss.h" - - static void add_listen_addr(ServerOptions *, const char *, -@@ -201,6 +202,12 @@ - options->authorized_principals_file = NULL; - options->authorized_principals_command = NULL; - options->authorized_principals_command_user = NULL; -+ options->tcp_rcv_buf_poll = -1; -+ options->hpn_disabled = -1; -+ options->hpn_buffer_size = -1; -+ options->none_enabled = -1; -+ options->nonemac_enabled = -1; -+ options->disable_multithreaded = -1; - options->ip_qos_interactive = -1; - options->ip_qos_bulk = -1; - options->version_addendum = NULL; -@@ -291,6 +298,10 @@ - fill_default_server_options(ServerOptions *options) - { - u_int i; -+ /* needed for hpn socket tests */ -+ int sock; -+ int socksize; -+ int socksizelen = sizeof(int); - - /* Portable-specific options */ - if (options->use_pam == -1) -@@ -464,6 +475,51 @@ - } - if (options->permit_tun == -1) - options->permit_tun = SSH_TUNMODE_NO; -+ if (options->none_enabled == -1) -+ options->none_enabled = 0; -+ if (options->nonemac_enabled == -1) -+ options->nonemac_enabled = 0; -+ if (options->nonemac_enabled > 0 && options->none_enabled == 0) { -+ debug ("Attempted to enabled None MAC without setting None Enabled to true. None MAC disabled."); -+ options->nonemac_enabled = 0; -+ } -+ if (options->disable_multithreaded == -1) -+ options->disable_multithreaded = 0; -+ if (options->hpn_disabled == -1) -+ options->hpn_disabled = 0; -+ -+ if (options->hpn_buffer_size == -1) { -+ /* option not explicitly set. Now we have to figure out */ -+ /* what value to use */ -+ if (options->hpn_disabled == 1) { -+ options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; -+ } else { -+ /* get the current RCV size and set it to that */ -+ /*create a socket but don't connect it */ -+ /* we use that the get the rcv socket size */ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ options->hpn_buffer_size = socksize; -+ debug("HPN Buffer Size: %d", options->hpn_buffer_size); -+ } -+ } else { -+ /* we have to do this in case the user sets both values in a contradictory */ -+ /* manner. hpn_disabled overrrides hpn_buffer_size*/ -+ if (options->hpn_disabled <= 0) { -+ if (options->hpn_buffer_size == 0) -+ options->hpn_buffer_size = 1; -+ /* limit the maximum buffer to SSHBUF_SIZE_MAX (currently 256MB) */ -+ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { -+ options->hpn_buffer_size = SSHBUF_SIZE_MAX; -+ } else { -+ options->hpn_buffer_size *= 1024; -+ } -+ } else -+ options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; -+ } -+ - if (options->ip_qos_interactive == -1) - options->ip_qos_interactive = IPTOS_DSCP_AF21; - if (options->ip_qos_bulk == -1) -@@ -537,6 +593,9 @@ - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, -+ sNoneEnabled, sNoneMacEnabled, -+ sDisableMTAES, -+ sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, - sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, - sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, - sPermitUserEnvironment, sAllowTcpForwarding, sCompression, -@@ -737,6 +796,12 @@ - { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, - { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, - { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, -+ { "hpndisabled", sHPNDisabled, SSHCFG_ALL }, -+ { "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL }, -+ { "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL }, -+ { "noneenabled", sNoneEnabled, SSHCFG_ALL }, -+ { "disableMTAES", sDisableMTAES, SSHCFG_ALL }, -+ { "nonemacenabled", sNoneMacEnabled, SSHCFG_ALL }, - { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, - { "include", sInclude, SSHCFG_ALL }, - { "ipqos", sIPQoS, SSHCFG_ALL }, -@@ -795,6 +860,7 @@ - - for (i = 0; keywords[i].name; i++) - if (strcasecmp(cp, keywords[i].name) == 0) { -+ debug("Config token is %s", keywords[i].name); - *flags = keywords[i].flags; - return keywords[i].opcode; - } -@@ -1546,12 +1612,36 @@ - multistate_ptr = multistate_ignore_rhosts; - goto parse_multistate; - -+ case sTcpRcvBufPoll: -+ intptr = &options->tcp_rcv_buf_poll; -+ goto parse_flag; -+ -+ case sHPNDisabled: -+ intptr = &options->hpn_disabled; -+ goto parse_flag; -+ -+ case sHPNBufferSize: -+ intptr = &options->hpn_buffer_size; -+ goto parse_int; -+ - case sIgnoreUserKnownHosts: - intptr = &options->ignore_user_known_hosts; - parse_flag: - multistate_ptr = multistate_flag; - goto parse_multistate; - -+ case sNoneEnabled: -+ intptr = &options->none_enabled; -+ goto parse_flag; -+ -+ case sNoneMacEnabled: -+ intptr = &options->nonemac_enabled; -+ goto parse_flag; -+ -+ case sDisableMTAES: -+ intptr = &options->disable_multithreaded; -+ goto parse_flag; -+ - case sHostbasedAuthentication: - intptr = &options->hostbased_authentication; - goto parse_flag; -diff -Nur openssh-8.6p1.orig/servconf.h openssh-8.6p1/servconf.h ---- openssh-8.6p1.orig/servconf.h 2021-05-22 08:23:21.065175752 +0200 -+++ openssh-8.6p1/servconf.h 2021-05-22 08:24:33.554345628 +0200 -@@ -215,6 +215,13 @@ - int use_pam; /* Enable auth via PAM */ - int permit_pam_user_change; /* Allow PAM to change user name */ - -+ int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ -+ int hpn_disabled; /* disable hpn functionality. false by default */ -+ int hpn_buffer_size; /* set the hpn buffer size - default 3MB */ -+ int none_enabled; /* Enable NONE cipher switch */ -+ int disable_multithreaded; /*disable multithreaded aes-ctr cipher */ -+ int nonemac_enabled; /* Enable NONE MAC switch */ -+ - int permit_tun; - - char **permitted_opens; /* May also be one of PERMITOPEN_* */ -diff -Nur openssh-8.6p1.orig/serverloop.c openssh-8.6p1/serverloop.c ---- openssh-8.6p1.orig/serverloop.c 2021-05-22 08:23:21.049175714 +0200 -+++ openssh-8.6p1/serverloop.c 2021-05-22 08:24:33.554345628 +0200 -@@ -322,7 +322,7 @@ - process_input(struct ssh *ssh, fd_set *readset, int connection_in) - { - int r, len; -- char buf[16384]; -+ char buf[SSH_IOBUFSZ]; - - /* Read and buffer any input data from the client. */ - if (FD_ISSET(connection_in, readset)) { -@@ -343,6 +343,7 @@ - /* Buffer any received data. */ - if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0) - fatal_fr(r, "ssh_packet_process_incoming"); -+ ssh->fdout_bytes += len; - } - return 0; - } -@@ -401,6 +402,7 @@ - u_int64_t rekey_timeout_ms = 0; - - debug("Entering interactive session for SSH2."); -+ ssh->start_time = monotime_double(); - - ssh_signal(SIGCHLD, sigchld_handler); - child_terminated = 0; -@@ -439,6 +441,7 @@ - - if (received_sigterm) { - logit("Exiting on signal %d", (int)received_sigterm); -+ sshpkt_final_log_entry(ssh); - /* Clean up sessions, utmp, etc. */ - cleanup_exit(255); - } -@@ -458,6 +461,9 @@ - /* free all channels, no more reads and writes */ - channel_free_all(ssh); - -+ /* final entry must come after channels close -cjr */ -+ sshpkt_final_log_entry(ssh); -+ - /* free remaining sessions, e.g. remove wtmp entries */ - session_destroy_all(ssh, NULL); - } -@@ -608,7 +614,8 @@ - debug("Tunnel forwarding using interface %s", ifname); - - c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); - c->datagram = 1; - #if defined(SSH_TUN_FILTER) - if (mode == SSH_TUNMODE_POINTOPOINT) -@@ -659,6 +666,8 @@ - c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL, - -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, - 0, "server-session", 1); -+ if ((options.tcp_rcv_buf_poll) && (!options.hpn_disabled)) -+ c->dynamic_window = 1; - if (session_open(the_authctxt, c->self) != 1) { - debug("session open failed, free channel %d", c->self); - channel_free(ssh, c); -diff -Nur openssh-8.6p1.orig/session.c openssh-8.6p1/session.c ---- openssh-8.6p1.orig/session.c 2021-05-22 08:23:21.050175717 +0200 -+++ openssh-8.6p1/session.c 2021-05-22 08:24:33.555345630 +0200 -@@ -228,6 +228,7 @@ - goto authsock_err; - - /* Allocate a channel for the authentication agent socket. */ -+ /* this shouldn't matter if its hpn or not - cjr */ - nc = channel_new(ssh, "auth socket", - SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, - CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, -@@ -2364,7 +2365,8 @@ - channel_set_fds(ssh, s->chanid, - fdout, fdin, fderr, - ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, -- 1, is_tty, CHAN_SES_WINDOW_DEFAULT); -+ 1, is_tty, -+ options.hpn_disabled ? CHAN_SES_WINDOW_DEFAULT : options.hpn_buffer_size); - } - - /* -diff -Nur openssh-8.6p1.orig/sftp.1 openssh-8.6p1/sftp.1 ---- openssh-8.6p1.orig/sftp.1 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp.1 2021-05-22 08:24:33.556345633 +0200 -@@ -296,7 +296,8 @@ - Specify how many requests may be outstanding at any one time. - Increasing this may slightly improve file transfer speed - but will increase memory usage. --The default is 64 outstanding requests. -+The default is 256 outstanding requests providing for 8MB -+of outstanding data with a 32KB buffer. - .It Fl r - Recursively copy entire directories when uploading and downloading. - Note that -diff -Nur openssh-8.6p1.orig/sftp-client.c openssh-8.6p1/sftp-client.c ---- openssh-8.6p1.orig/sftp-client.c 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp-client.c 2021-05-22 08:24:33.556345633 +0200 -@@ -65,7 +65,7 @@ - #define DEFAULT_COPY_BUFLEN 32768 - - /* Default number of concurrent outstanding requests */ --#define DEFAULT_NUM_REQUESTS 64 -+#define DEFAULT_NUM_REQUESTS 256 - - /* Minimum amount of data to read at a time */ - #define MIN_READ_SIZE 512 -diff -Nur openssh-8.6p1.orig/ssh_api.c openssh-8.6p1/ssh_api.c ---- openssh-8.6p1.orig/ssh_api.c 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh_api.c 2021-05-22 08:24:33.557345635 +0200 -@@ -410,7 +410,7 @@ - char *cp; - int r; - -- if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0) -+ if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_RELEASE)) != 0) - return r; - if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) - return r; -diff -Nur openssh-8.6p1.orig/sshbuf.h openssh-8.6p1/sshbuf.h ---- openssh-8.6p1.orig/sshbuf.h 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sshbuf.h 2021-05-22 08:24:33.557345635 +0200 -@@ -28,7 +28,7 @@ - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ - --#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ -+#define SSHBUF_SIZE_MAX 0xF000000 /* Hard maximum size 256MB */ - #define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */ - #define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */ - #define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */ -diff -Nur openssh-8.6p1.orig/ssh.c openssh-8.6p1/ssh.c ---- openssh-8.6p1.orig/ssh.c 2021-05-22 08:23:21.066175754 +0200 -+++ openssh-8.6p1/ssh.c 2021-05-22 08:24:33.558345637 +0200 -@@ -1070,6 +1070,10 @@ - break; - case 'T': - options.request_tty = REQUEST_TTY_NO; -+ /* ensure that the user doesn't try to backdoor a */ -+ /* null cipher switch on an interactive session */ -+ /* so explicitly disable it no matter what */ -+ options.none_switch=0; - break; - case 'o': - line = xstrdup(optarg); -@@ -1797,6 +1801,8 @@ - setproctitle("%s [mux]", options.control_path); - } - -+extern const EVP_CIPHER *evp_aes_ctr_mt(void); -+ - /* Do fork() after authentication. Used by "ssh -f" */ - static void - fork_postauth(void) -@@ -2109,6 +2115,79 @@ - NULL, fileno(stdin), command, environ); - } - -+static void -+hpn_options_init(struct ssh *ssh) -+{ -+ /* -+ * We need to check to see if what they want to do about buffer -+ * sizes here. In a hpn to nonhpn connection we want to limit -+ * the window size to something reasonable in case the far side -+ * has the large window bug. In hpn to hpn connection we want to -+ * use the max window size but allow the user to override it -+ * lastly if they disabled hpn then use the ssh std window size. -+ * -+ * So why don't we just do a getsockopt() here and set the -+ * ssh window to that? In the case of a autotuning receive -+ * window the window would get stuck at the initial buffer -+ * size generally less than 96k. Therefore we need to set the -+ * maximum ssh window size to the maximum hpn buffer size -+ * unless the user has specifically set the tcprcvbufpoll -+ * to no. In which case we *can* just set the window to the -+ * minimum of the hpn buffer size and tcp receive buffer size. -+ */ -+ -+ if (tty_flag) -+ options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; -+ else -+ options.hpn_buffer_size = 2 * 1024 * 1024; -+ -+ if (ssh->compat & SSH_BUG_LARGEWINDOW) { -+ debug("HPN to Non-HPN connection"); -+ } else { -+ debug("HPN to HPN connection"); -+ int sock, socksize; -+ socklen_t socksizelen; -+ if (options.tcp_rcv_buf_poll <= 0) { -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ socksizelen = sizeof(socksize); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ debug("socksize %d", socksize); -+ options.hpn_buffer_size = socksize; -+ debug("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size); -+ } else { -+ if (options.tcp_rcv_buf > 0) { -+ /* -+ * Create a socket but don't connect it: -+ * we use that the get the rcv socket size -+ */ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ /* -+ * If they are using the tcp_rcv_buf option, -+ * attempt to set the buffer size to that. -+ */ -+ if (options.tcp_rcv_buf) { -+ socksizelen = sizeof(options.tcp_rcv_buf); -+ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &options.tcp_rcv_buf, socksizelen); -+ } -+ socksizelen = sizeof(socksize); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ debug("socksize %d", socksize); -+ options.hpn_buffer_size = socksize; -+ debug("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size); -+ } -+ } -+ } -+ -+ debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); -+ -+ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); -+} -+ - /* open new channel for a session */ - static int - ssh_session2_open(struct ssh *ssh) -@@ -2127,9 +2206,11 @@ - if (in == -1 || out == -1 || err == -1) - fatal("dup() in/out/err failed"); - -- window = CHAN_SES_WINDOW_DEFAULT; -+ window = options.hpn_buffer_size; -+ - packetmax = CHAN_SES_PACKET_DEFAULT; - if (tty_flag) { -+ window = CHAN_SES_WINDOW_DEFAULT; - window >>= 1; - packetmax >>= 1; - } -@@ -2140,6 +2221,11 @@ - - debug3_f("channel_new: %d", c->self); - -+ if (options.tcp_rcv_buf_poll > 0 && !options.hpn_disabled) { -+ c->dynamic_window = 1; -+ debug("Enabled Dynamic Window Scaling"); -+ } -+ - channel_send_open(ssh, c->self); - if (!no_shell_flag) - channel_register_open_confirm(ssh, c->self, -@@ -2154,6 +2240,13 @@ - int r, id = -1; - char *cp, *tun_fwd_ifname = NULL; - -+ /* -+ * We need to initialize this early because the forwarding logic below -+ * might open channels that use the hpn buffer sizes. We can't send a -+ * window of -1 (the default) to the server as it breaks things. -+ */ -+ hpn_options_init(ssh); -+ - /* XXX should be pre-session */ - if (!options.control_persist) - ssh_init_stdio_forwarding(ssh); -diff -Nur openssh-8.6p1.orig/sshconnect2.c openssh-8.6p1/sshconnect2.c ---- openssh-8.6p1.orig/sshconnect2.c 2021-05-22 08:23:21.067175757 +0200 -+++ openssh-8.6p1/sshconnect2.c 2021-05-22 08:24:33.559345640 +0200 -@@ -86,6 +86,13 @@ - extern Options options; - - /* -+ * tty_flag is set in ssh.c. Use this in ssh_userauth2: -+ * if it is set, then prevent the switch to the null cipher. -+ */ -+ -+extern int tty_flag; -+ -+/* - * SSH2 key exchange - */ - -@@ -212,6 +219,8 @@ - return ret; - } - -+static char *myproposal[PROPOSAL_MAX]; -+static const char *myproposal_default[PROPOSAL_MAX] = { KEX_CLIENT }; - void - ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - const struct ssh_conn_info *cinfo) -@@ -225,6 +234,10 @@ - char *gss_host = NULL; - #endif - -+ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); -+ -+ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); -+ - xxx_host = host; - xxx_hostaddr = hostaddr; - xxx_conn_info = cinfo; -@@ -571,6 +584,53 @@ - - if (!authctxt.success) - fatal("Authentication failed."); -+ -+ /* -+ * If the user wants to use the none cipher and/or none mac, do it post authentication -+ * and only if the right conditions are met -- both of the NONE commands -+ * must be true and there must be no tty allocated. -+ */ -+ if (options.none_switch == 1 && options.none_enabled == 1) { -+ if (!tty_flag) { /* no null on tty sessions */ -+ debug("Requesting none rekeying..."); -+ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); -+ myproposal[PROPOSAL_ENC_ALGS_STOC] = "none"; -+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none"; -+ fprintf(stderr, "WARNING: ENABLED NONE CIPHER!!!\n"); -+ /* NONEMAC can only be used in context of the NONE CIPHER */ -+ if (options.nonemac_enabled == 1) { -+ myproposal[PROPOSAL_MAC_ALGS_STOC] = "none"; -+ myproposal[PROPOSAL_MAC_ALGS_CTOS] = "none"; -+ fprintf(stderr, "WARNING: ENABLED NONE MAC\n"); -+ } -+ kex_prop2buf(ssh->kex->my, myproposal); -+ packet_request_rekeying(); -+ } else { -+ /* requested NONE cipher when in a tty */ -+ debug("Cannot switch to NONE cipher with tty allocated"); -+ fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n"); -+ } -+ } -+ -+#ifdef WITH_OPENSSL -+ if (options.disable_multithreaded == 0) { -+ /* if we are using aes-ctr there can be issues in either a fork or sandbox -+ * so the initial aes-ctr is defined to point to the original single process -+ * evp. After authentication we'll be past the fork and the sandboxed privsep -+ * so we repoint the define to the multithreaded evp. To start the threads we -+ * then force a rekey -+ */ -+ const void *cc = ssh_packet_get_send_context(ssh); -+ -+ /* only do this for the ctr cipher. otherwise gcm mode breaks. Don't know why though */ -+ if (strstr(cipher_ctx_name(cc), "ctr")) { -+ debug("Single to Multithread CTR cipher swap - client request"); -+ cipher_reset_multithreaded(); -+ packet_request_rekeying(); -+ } -+ } -+#endif -+ - debug("Authentication succeeded (%s).", authctxt.method->name); - } - -diff -Nur openssh-8.6p1.orig/sshconnect.c openssh-8.6p1/sshconnect.c ---- openssh-8.6p1.orig/sshconnect.c 2021-05-22 08:23:20.987175569 +0200 -+++ openssh-8.6p1/sshconnect.c 2021-05-22 08:24:33.560345642 +0200 -@@ -345,6 +345,30 @@ - #endif - - /* -+ * Set TCP receive buffer if requested. -+ * Note: tuning needs to happen after the socket is -+ * created but before the connection happens -+ * so winscale is negotiated properly -cjr -+ */ -+static void -+ssh_set_socket_recvbuf(int sock) -+{ -+ void *buf = (void *)&options.tcp_rcv_buf; -+ int sz = sizeof(options.tcp_rcv_buf); -+ int socksize; -+ int socksizelen = sizeof(int); -+ -+ debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf); -+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen); -+ debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize); -+ } -+ else -+ error("Couldn't set socket receive buffer to %d: %.100s", -+ options.tcp_rcv_buf, strerror(errno)); -+} -+ -+/* - * Creates a socket for use as the ssh connection. - */ - static int -@@ -366,6 +390,9 @@ - } - fcntl(sock, F_SETFD, FD_CLOEXEC); - -+ if (options.tcp_rcv_buf > 0) -+ ssh_set_socket_recvbuf(sock); -+ - /* Use interactive QOS (if specified) until authentication completed */ - if (options.ip_qos_interactive != INT_MAX) - set_sock_tos(sock, options.ip_qos_interactive); -diff -Nur openssh-8.6p1.orig/sshd.c openssh-8.6p1/sshd.c ---- openssh-8.6p1.orig/sshd.c 2021-05-22 08:23:21.068175759 +0200 -+++ openssh-8.6p1/sshd.c 2021-05-22 08:24:33.561345644 +0200 -@@ -1107,6 +1107,8 @@ - int ret, listen_sock; - struct addrinfo *ai; - char ntop[NI_MAXHOST], strport[NI_MAXSERV]; -+ int socksize; -+ int socksizelen = sizeof(int); - - for (ai = la->addrs; ai; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) -@@ -1152,6 +1154,11 @@ - - debug("Bind to port %s on %s.", strport, ntop); - -+ getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ debug("Server TCP RWIN socket size: %d", socksize); -+ debug("HPN Buffer Size: %d", options.hpn_buffer_size); -+ - /* Bind the socket to the desired port. */ - if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) == -1) { - error("Bind to port %s on %s failed: %.200s.", -@@ -1834,6 +1841,19 @@ - /* Fill in default values for those options not explicitly set. */ - fill_default_server_options(&options); - -+ if (options.none_enabled == 1) { -+ char *old_ciphers = options.ciphers; -+ xasprintf(&options.ciphers, "%s,none", old_ciphers); -+ free(old_ciphers); -+ -+ /* only enable the none MAC in context of the none cipher -cjr */ -+ if (options.nonemac_enabled == 1) { -+ char *old_macs = options.macs; -+ xasprintf(&options.macs, "%s,none", old_macs); -+ free(old_macs); -+ } -+ } -+ - /* challenge-response is implemented via keyboard interactive */ - if (options.challenge_response_authentication) - options.kbd_interactive_authentication = 1; -@@ -2285,6 +2305,9 @@ - rdomain == NULL ? "" : "\""); - free(laddr); - -+ /* set the HPN options for the child */ -+ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); -+ - /* - * We don't want to listen forever unless the other side - * successfully authenticates itself. So we set up an alarm which is -@@ -2397,6 +2420,25 @@ - /* Try to send all our hostkeys to the client */ - notify_hostkeys(ssh); - -+#ifdef WITH_OPENSSL -+ if (options.disable_multithreaded == 0) { -+ /* if we are using aes-ctr there can be issues in either a fork or sandbox -+ * so the initial aes-ctr is defined to point ot the original single process -+ * evp. After authentication we'll be past the fork and the sandboxed privsep -+ * so we repoint the define to the multithreaded evp. To start the threads we -+ * then force a rekey -+ */ -+ const void *cc = ssh_packet_get_send_context(the_active_state); -+ -+ /* only rekey if necessary. If we don't do this gcm mode cipher breaks */ -+ if (strstr(cipher_ctx_name(cc), "ctr")) { -+ debug("Single to Multithreaded CTR cipher swap - server request"); -+ cipher_reset_multithreaded(); -+ packet_request_rekeying(); -+ } -+ } -+#endif -+ - /* Start session. */ - do_authenticated(ssh, authctxt); - -@@ -2470,6 +2512,11 @@ - struct kex *kex; - int r; - -+ if (options.none_enabled == 1) -+ debug("WARNING: None cipher enabled"); -+ if (options.nonemac_enabled == 1) -+ debug("WARNING: None MAC enabled"); -+ - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, - options.kex_algorithms); - myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh, -diff -Nur openssh-8.6p1.orig/sshd_config openssh-8.6p1/sshd_config ---- openssh-8.6p1.orig/sshd_config 2021-05-22 08:23:21.068175759 +0200 -+++ openssh-8.6p1/sshd_config 2021-05-22 08:24:33.561345644 +0200 -@@ -127,6 +127,28 @@ - # override default of no subsystems - Subsystem sftp /usr/libexec/sftp-server - -+# the following are HPN related configuration options -+# tcp receive buffer polling. disable in non autotuning kernels -+#TcpRcvBufPoll yes -+ -+# disable hpn performance boosts -+#HPNDisabled no -+ -+# buffer size for hpn to non-hpn connections -+#HPNBufferSize 2048 -+ -+# allow the use of the none cipher -+#NoneEnabled no -+ -+# allow the use of the none MAC -+#NoneMacEnabled no -+ -+# Disable MT-AES-CTR cipher on server -+# * needed for GSI-OpenSSH 7.4p1 because it's broken on the server side there -+# * useful for modern processors with AES-NI instructions making the stock -+# AES-CTR cipher faster than the MT-AES-CTR cipher -+DisableMTAES yes -+ - # Example of overriding settings on a per-user basis - #Match User anoncvs - # X11Forwarding no -diff -Nur openssh-8.6p1.orig/version.h openssh-8.6p1/version.h ---- openssh-8.6p1.orig/version.h 2021-05-22 08:23:21.069175761 +0200 -+++ openssh-8.6p1/version.h 2021-05-22 08:24:33.561345644 +0200 -@@ -16,5 +16,6 @@ - - #define SSH_PORTABLE "p1" - #define GSI_PORTABLE "c-GSI" -+#define SSH_HPN "-hpn15v2" - #define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ -- GSI_VERSION KRB5_VERSION -+ GSI_VERSION SSH_HPN KRB5_VERSION diff --git a/openssh-8.7p1-gsissh.patch b/openssh-8.7p1-gsissh.patch new file mode 100644 index 0000000..f19161c --- /dev/null +++ b/openssh-8.7p1-gsissh.patch @@ -0,0 +1,2449 @@ +diff -Nur openssh-8.7p1.orig/auth2.c openssh-8.7p1/auth2.c +--- openssh-8.7p1.orig/auth2.c 2021-10-24 07:32:35.517723813 +0200 ++++ openssh-8.7p1/auth2.c 2021-10-24 07:33:38.862876709 +0200 +@@ -277,7 +277,28 @@ + (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || + (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) + goto out; +- debug("userauth-request for user %s service %s method %s", user, service, method); ++ ++#ifdef GSSAPI ++ if (user[0] == '\0') { ++ debug("received empty username for %s", method); ++ if (strcmp(method, "gssapi-keyex") == 0) { ++ char *lname = NULL; ++ PRIVSEP(ssh_gssapi_localname(&lname)); ++ if (lname && lname[0] != '\0') { ++ free(user); ++ user = lname; ++ debug("set username to %s from gssapi context", user); ++ } else { ++ debug("failed to set username from gssapi context"); ++ ssh_packet_send_debug(ssh, ++ "failed to set username from gssapi context"); ++ } ++ } ++ } ++#endif ++ ++ debug("userauth-request for user %s service %s method %s", ++ user[0] ? user : "", service, method); + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + + #ifdef WITH_SELINUX +@@ -288,17 +309,42 @@ + if ((style = strchr(user, ':')) != NULL) + *style++ = 0; + +- if (authctxt->attempt++ == 0) { +- /* setup auth context */ +- authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); ++ /* If first time or username changed or empty username, ++ setup/reset authentication context. */ ++ if ((authctxt->attempt++ == 0) || ++ (strcmp(user, authctxt->user) != 0) || ++ (strcmp(user, "") == 0)) { ++ if (authctxt->user) { ++ free(authctxt->user); ++ authctxt->user = NULL; ++ } ++ authctxt->valid = 0; + authctxt->user = xstrdup(user); +- if (authctxt->pw && strcmp(service, "ssh-connection")==0) { ++ if (strcmp(service, "ssh-connection") != 0) { ++ ssh_packet_disconnect(ssh, "Unsupported service %s", ++ service); ++ } ++#ifdef GSSAPI ++ /* If we're going to set the username based on the ++ GSSAPI context later, then wait until then to ++ verify it. Just put in placeholders for now. */ ++ if ((strcmp(user, "") == 0) && ++ ((strcmp(method, "gssapi") == 0) || ++ (strcmp(method, "gssapi-with-mic") == 0))) { ++ authctxt->pw = fakepw(); ++ } else { ++#endif ++ authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); ++ if (authctxt->pw) { + authctxt->valid = 1; + debug2_f("setting up authctxt for %s", user); + } else { + /* Invalid user, fake password information */ + authctxt->pw = fakepw(); + } ++#ifdef GSSAPI ++ } /* endif for setting username based on GSSAPI context */ ++#endif + #ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(ssh)); +@@ -307,6 +353,7 @@ + authctxt->valid ? "authenticating " : "invalid ", user); + setproctitle("%s%s", authctxt->valid ? user : "unknown", + use_privsep ? " [net]" : ""); ++ if (authctxt->attempt == 1) { + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; + #ifdef WITH_SELINUX +@@ -322,9 +369,10 @@ + if (auth2_setup_methods_lists(authctxt) != 0) + ssh_packet_disconnect(ssh, + "no authentication methods enabled"); +- } else if (strcmp(user, authctxt->user) != 0 || +- strcmp(service, authctxt->service) != 0) { +- ssh_packet_disconnect(ssh, "Change of username or service " ++ } ++ } ++ if (strcmp(service, authctxt->service) != 0) { ++ ssh_packet_disconnect(ssh, "Change of service " + "not allowed: (%s,%s) -> (%s,%s)", + authctxt->user, authctxt->service, user, service); + } +diff -Nur openssh-8.7p1.orig/auth2-gss.c openssh-8.7p1/auth2-gss.c +--- openssh-8.7p1.orig/auth2-gss.c 2021-10-24 07:32:35.388723503 +0200 ++++ openssh-8.7p1/auth2-gss.c 2021-10-24 07:33:38.863876712 +0200 +@@ -50,6 +50,7 @@ + + extern ServerOptions options; + ++static void ssh_gssapi_userauth_error(Gssctxt *ctxt, struct ssh *ssh); + static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); + static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); + static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); +@@ -63,8 +64,8 @@ + { + Authctxt *authctxt = ssh->authctxt; + int r, authenticated = 0; +- struct sshbuf *b = NULL; +- gss_buffer_desc mic, gssbuf; ++ struct sshbuf *b = NULL, *b2 = NULL; ++ gss_buffer_desc mic, gssbuf, gssbuf2; + u_char *p; + size_t len; + +@@ -75,6 +76,9 @@ + if ((b = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + ++ if ((b2 = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ + mic.value = p; + mic.length = len; + +@@ -85,13 +89,29 @@ + fatal_f("sshbuf_mutable_ptr failed"); + gssbuf.length = sshbuf_len(b); + ++ /* client may have used empty username to determine target ++ name from GSSAPI context */ ++ ssh_gssapi_buildmic(b2, "", authctxt->service, "gssapi-keyex", ++ ssh->kex->session_id); ++ ++ if ((gssbuf2.value = sshbuf_mutable_ptr(b2)) == NULL) ++ fatal_f("sshbuf_mutable_ptr failed"); ++ gssbuf2.length = sshbuf_len(b2); ++ + /* gss_kex_context is NULL with privsep, so we can't check it here */ + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, +- &gssbuf, &mic)))) +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, +- authctxt->pw, 1)); ++ &gssbuf, &mic))) || ++ !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf2, &mic)))) { ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1)); ++ } ++ } + + sshbuf_free(b); ++ sshbuf_free(b2); + free(mic.value); + + return (authenticated); +@@ -146,7 +166,9 @@ + return (0); + } + +- if (!authctxt->valid || authctxt->user == NULL) { ++ /* authctxt->valid may be 0 if we haven't yet determined ++ username from gssapi context. */ ++ if (authctxt->user == NULL) { + debug2_f("disabled because of invalid user"); + free(doid); + return (0); +@@ -184,7 +206,7 @@ + Gssctxt *gssctxt; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok; +- OM_uint32 maj_status, min_status, flags; ++ OM_uint32 maj_status, min_status, flags = 0; + u_char *p; + size_t len; + int r; +@@ -205,6 +227,7 @@ + free(p); + + if (GSS_ERROR(maj_status)) { ++ ssh_gssapi_userauth_error(gssctxt, ssh); + if (send_tok.length != 0) { + if ((r = sshpkt_start(ssh, + SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 || +@@ -279,6 +302,34 @@ + return 0; + } + ++static void ++gssapi_set_username(struct ssh *ssh) ++{ ++ Authctxt *authctxt = ssh->authctxt; ++ char *lname = NULL; ++ ++ if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { ++ PRIVSEP(ssh_gssapi_localname(&lname)); ++ if (lname && lname[0] != '\0') { ++ if (authctxt->user) free(authctxt->user); ++ authctxt->user = lname; ++ debug("set username to %s from gssapi context", lname); ++ authctxt->pw = PRIVSEP(getpwnamallow(ssh, authctxt->user)); ++ if (authctxt->pw) { ++ authctxt->valid = 1; ++#ifdef USE_PAM ++ if (options.use_pam) ++ PRIVSEP(start_pam(ssh)); ++#endif ++ } ++ } else { ++ debug("failed to set username from gssapi context"); ++ ssh_packet_send_debug(ssh, ++ "failed to set username from gssapi context"); ++ } ++ } ++} ++ + /* + * This is called when the client thinks we've completed authentication. + * It should only be enabled in the dispatch handler by the function above, +@@ -289,12 +340,14 @@ + input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) + { + Authctxt *authctxt = ssh->authctxt; +- int r, authenticated; ++ int r, authenticated = 0; + const char *displayname; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + ++ gssapi_set_username(ssh); ++ + /* + * We don't need to check the status, because we're only enabled in + * the dispatcher once the exchange is complete +@@ -303,8 +356,11 @@ + if ((r = sshpkt_get_end(ssh)) != 0) + fatal_fr(r, "parse packet"); + +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, +- authctxt->pw, 1)); ++ /* user should be set if valid but we double-check here */ ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1)); ++ } + + if ((!use_privsep || mm_is_monitor()) && + (displayname = ssh_gssapi_displayname()) != NULL) +@@ -356,11 +412,17 @@ + fatal_f("sshbuf_mutable_ptr failed"); + gssbuf.length = sshbuf_len(b); + +- if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, +- authctxt->pw, 0)); +- else ++ gssapi_set_username(ssh); ++ ++ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) { ++ if (authctxt->valid && authctxt->user && authctxt->user[0]) { ++ authenticated = ++ PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 0)); ++ } ++ } else { + logit("GSSAPI MIC check failed"); ++ } + + sshbuf_free(b); + if (micuser != authctxt->user) +@@ -380,6 +442,26 @@ + return 0; + } + ++static void ssh_gssapi_userauth_error(Gssctxt *ctxt, struct ssh *ssh) { ++ char *errstr; ++ OM_uint32 maj, min; ++ int r; ++ ++ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); ++ if (errstr) { ++ if ((r = sshpkt_start(ssh, ++ SSH2_MSG_USERAUTH_GSSAPI_ERROR)) != 0 || ++ (r = sshpkt_put_u32(ssh, maj)) != 0 || ++ (r = sshpkt_put_u32(ssh, min)) != 0 || ++ (r = sshpkt_put_cstring(ssh, errstr)) != 0 || ++ (r = sshpkt_put_cstring(ssh, "")) != 0 || ++ (r = sshpkt_send(ssh)) != 0 || ++ (r = ssh_packet_write_wait(ssh)) != 0) ++ fatal_fr(r, ""); ++ free(errstr); ++ } ++} ++ + Authmethod method_gsskeyex = { + "gssapi-keyex", + userauth_gsskeyex, +diff -Nur openssh-8.7p1.orig/auth.c openssh-8.7p1/auth.c +--- openssh-8.7p1.orig/auth.c 2021-10-24 07:32:35.519723818 +0200 ++++ openssh-8.7p1/auth.c 2021-10-24 07:33:38.864876714 +0200 +@@ -344,7 +344,8 @@ + method, + submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, + authctxt->valid ? "" : "invalid user ", +- authctxt->user, ++ (authctxt->user && authctxt->user[0]) ? ++ authctxt->user : "unknown", + ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh), + extra != NULL ? ": " : "", +@@ -588,13 +589,18 @@ + #endif + + pw = getpwnam(user); ++#ifdef USE_PAM ++ if (options.use_pam && options.permit_pam_user_change && pw == NULL) ++ pw = sshpam_getpw(user); ++#endif + + #if defined(_AIX) && defined(HAVE_SETAUTHDB) + aix_restoreauthdb(); + #endif + if (pw == NULL) { + logit("Invalid user %.100s from %.100s port %d", +- user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); ++ (user && user[0]) ? user : "unknown", ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); + #ifdef CUSTOM_FAILED_LOGIN + record_failed_login(ssh, user, + auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); +diff -Nur openssh-8.7p1.orig/auth.h openssh-8.7p1/auth.h +--- openssh-8.7p1.orig/auth.h 2021-10-24 07:32:35.519723818 +0200 ++++ openssh-8.7p1/auth.h 2021-10-24 07:33:38.864876714 +0200 +@@ -83,6 +83,8 @@ + krb5_principal krb5_user; + char *krb5_ticket_file; + char *krb5_ccname; ++#endif ++#ifdef GSSAPI + int krb5_set_env; + #endif + struct sshbuf *loginmsg; +diff -Nur openssh-8.7p1.orig/auth-pam.c openssh-8.7p1/auth-pam.c +--- openssh-8.7p1.orig/auth-pam.c 2021-10-24 07:32:35.510723796 +0200 ++++ openssh-8.7p1/auth-pam.c 2021-10-24 07:33:38.865876716 +0200 +@@ -253,6 +253,7 @@ + static char *sshpam_rhost = NULL; + static char *sshpam_laddr = NULL; + static char *sshpam_conninfo = NULL; ++static struct ssh *sshpam_ssh = NULL; + + /* Some PAM implementations don't implement this */ + #ifndef HAVE_PAM_GETENVLIST +@@ -301,6 +302,56 @@ + # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) + #endif + ++struct passwd * ++sshpam_getpw(const char *user) ++{ ++ struct passwd *pw; ++ ++ if ((pw = getpwnam(user)) != NULL) ++ return(pw); ++ ++ debug("PAM: faking passwd struct for user '%.100s'", user); ++ if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) ++ return NULL; ++ pw->pw_name = xstrdup(user); /* XXX leak */ ++ pw->pw_shell = "/bin/true"; ++ pw->pw_gecos = "sshd fake PAM user"; ++ return (pw); ++} ++ ++void ++sshpam_check_userchanged(void) ++{ ++ int sshpam_err; ++ struct passwd *pw; ++ const char *user; ++ ++ debug("sshpam_check_userchanged"); ++ sshpam_err = pam_get_item(sshpam_handle, PAM_USER, ++ (sshpam_const void **)&user); ++ if (sshpam_err != PAM_SUCCESS) ++ fatal("PAM: could not get PAM_USER: %s", ++ pam_strerror(sshpam_handle, sshpam_err)); ++ debug("sshpam_check_userchanged: user was '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ if (strcmp(user, sshpam_authctxt->pw->pw_name) != 0) { ++ debug("PAM: user mapped from '%.100s' to '%.100s'", ++ sshpam_authctxt->pw->pw_name, user); ++ if ((pw = getpwnam(user)) == NULL) ++ fatal("PAM: could not get passwd entry for user " ++ "'%.100s' provided by PAM_USER", user); ++ pwfree(sshpam_authctxt->pw); ++ sshpam_authctxt->pw = pwcopy(pw); ++ sshpam_authctxt->valid = allowed_user(sshpam_ssh, pw); ++ free(sshpam_authctxt->user); ++ sshpam_authctxt->user = xstrdup(user); ++ debug("PAM: user '%.100s' now %svalid", user, ++ sshpam_authctxt->valid ? "" : "in"); ++ } ++ debug("sshpam_check_userchanged: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++} ++ + static void + sshpam_password_change_required(int reqd) + { +@@ -332,7 +383,7 @@ + static void + import_environments(struct sshbuf *b) + { +- char *env; ++ char *env, *user; + u_int n, i, num_env; + int r; + +@@ -348,6 +399,19 @@ + if ((r = sshbuf_get_u32(b, &n)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + sshpam_password_change_required(n != 0); ++ if (options.permit_pam_user_change) { ++ if ((r = sshbuf_get_cstring(b, &user, NULL)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ debug("PAM: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ debug("PAM: got username '%.100s' from thread", user); ++ if ((sshpam_err = pam_set_item(sshpam_handle, PAM_USER, user)) ++ != PAM_SUCCESS) ++ fatal("PAM: failed to set PAM_USER: %s", ++ pam_strerror(sshpam_handle, sshpam_err)); ++ pwfree(sshpam_authctxt->pw); ++ sshpam_authctxt->pw = pwcopy(sshpam_getpw(user)); ++ } + + /* Import environment from subprocess */ + if ((r = sshbuf_get_u32(b, &num_env)) != 0) +@@ -522,6 +586,13 @@ + if (sshpam_err != PAM_SUCCESS) + goto auth_fail; + ++ if (options.permit_pam_user_change) { ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ sshpam_check_userchanged(); ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ } + if (!do_pam_account()) { + /* Preserve PAM_PERM_DENIED and PAM_USER_UNKNOWN. + * Backward compatibility for other errors. */ +@@ -546,6 +617,13 @@ + if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 || + (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if (options.permit_pam_user_change) { ++ debug("sshpam_thread: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ if ((r = sshbuf_put_cstring(buffer, ++ sshpam_authctxt->pw->pw_name)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } + + /* Export any environment strings set in child */ + for (i = 0; environ[i] != NULL; i++) { +@@ -738,6 +816,8 @@ + xasprintf(&sshpam_conninfo, "SSH_CONNECTION=%.50s %d %.50s %d", + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), + sshpam_laddr, ssh_local_port(ssh)); ++ /* Save so allowed_user can be called later */ ++ sshpam_ssh = ssh; + } + if (sshpam_rhost != NULL) { + debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); +@@ -1082,6 +1162,18 @@ + debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, + pam_strerror(sshpam_handle, sshpam_err)); + ++ if (options.permit_pam_user_change) { ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ sshpam_check_userchanged(); ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ if (getpwnam(sshpam_authctxt->pw->pw_name) == NULL) ++ fatal("PAM: completed authentication but PAM account invalid"); ++ debug("do_pam_account: user is '%.100s'", ++ sshpam_authctxt->pw->pw_name); ++ } ++ + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { + sshpam_account_status = 0; + return (sshpam_account_status); +@@ -1370,6 +1462,9 @@ + pam_strerror(sshpam_handle, sshpam_err)); + + sshpam_err = pam_authenticate(sshpam_handle, flags); ++ if (options.permit_pam_user_change) { ++ sshpam_check_userchanged(); ++ } + sshpam_password = NULL; + free(fake); + if (sshpam_err == PAM_MAXTRIES) +diff -Nur openssh-8.7p1.orig/auth-pam.h openssh-8.7p1/auth-pam.h +--- openssh-8.7p1.orig/auth-pam.h 2021-10-24 07:32:35.356723425 +0200 ++++ openssh-8.7p1/auth-pam.h 2021-10-24 07:33:38.865876716 +0200 +@@ -43,5 +43,6 @@ + int sshpam_get_maxtries_reached(void); + void sshpam_set_maxtries_reached(int); + int is_pam_session_open(void); ++struct passwd *sshpam_getpw(const char *); + + #endif /* USE_PAM */ +diff -Nur openssh-8.7p1.orig/canohost.c openssh-8.7p1/canohost.c +--- openssh-8.7p1.orig/canohost.c 2021-10-24 07:32:35.388723503 +0200 ++++ openssh-8.7p1/canohost.c 2021-10-24 07:33:38.866876718 +0200 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include /* for MAXHOSTNAMELEN */ + + #include + #include +@@ -295,3 +296,33 @@ + { + return get_sock_port(sock, 1); + } ++ ++void ++resolve_localhost(char **host) ++{ ++ struct hostent *hostinfo; ++ ++ hostinfo = gethostbyname(*host); ++ if (hostinfo == NULL || hostinfo->h_name == NULL) { ++ debug("gethostbyname(%s) failed", *host); ++ return; ++ } ++ if (hostinfo->h_addrtype == AF_INET) { ++ struct in_addr addr; ++ addr = *(struct in_addr *)(hostinfo->h_addr); ++ if (ntohl(addr.s_addr) == INADDR_LOOPBACK) { ++ char buf[MAXHOSTNAMELEN]; ++ if (gethostname(buf, sizeof(buf)) < 0) { ++ debug("gethostname() failed"); ++ return; ++ } ++ hostinfo = gethostbyname(buf); ++ free(*host); ++ if (hostinfo == NULL || hostinfo->h_name == NULL) { ++ *host = xstrdup(buf); ++ } else { ++ *host = xstrdup(hostinfo->h_name); ++ } ++ } ++ } ++} +diff -Nur openssh-8.7p1.orig/canohost.h openssh-8.7p1/canohost.h +--- openssh-8.7p1.orig/canohost.h 2021-10-24 07:32:35.388723503 +0200 ++++ openssh-8.7p1/canohost.h 2021-10-24 07:33:38.866876718 +0200 +@@ -26,4 +26,6 @@ + + #endif /* _CANOHOST_H */ + ++void resolve_localhost(char **host); ++ + void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); +diff -Nur openssh-8.7p1.orig/configure.ac openssh-8.7p1/configure.ac +--- openssh-8.7p1.orig/configure.ac 2021-10-24 07:32:35.498723767 +0200 ++++ openssh-8.7p1/configure.ac 2021-10-24 07:49:48.431180638 +0200 +@@ -4777,6 +4777,14 @@ + AC_CHECK_HEADER([gssapi_krb5.h], , + [ CPPFLAGS="$oldCPP" ]) + ++ # If we're using some other GSSAPI ++ if test -n "$GSSAPI" ; then ++ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Kerberos GSI.]) ++ fi ++ ++ if test -z "$GSSAPI"; then ++ GSSAPI="KRB5"; ++ fi + fi + fi + if test -n "${rpath_opt}" ; then +@@ -4817,6 +4825,40 @@ + AC_SUBST([GSSLIBS]) + AC_SUBST([K5LIBS]) + ++# Check whether the user wants GSI (Globus) support ++gsi="no" ++AC_ARG_WITH(gsi, ++ [ --with-gsi Enable Globus GSI authentication support], ++ [ ++ gsi="$withval" ++ ] ++) ++ ++if test "x$gsi" != "xno" ; then ++ # Globus GSSAPI configuration ++ AC_MSG_CHECKING(for Globus GSI) ++ AC_DEFINE(GSI, 1, [Define if you want GSI/Globus authentication support.]) ++ ++ if test -n "$GSSAPI" ; then ++ AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus GSI.]) ++ fi ++ ++ if test -z "$GSSAPI" ; then ++ GSSAPI="GSI" ++ fi ++ ++ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) ++ if test "x$PKGCONFIG" != "xno"; then ++ LIBS="$LIBS `$PKGCONFIG --libs globus-gss-assist globus-gssapi-gsi globus-common`" ++ CPPFLAGS="$CPPFLAGS `$PKGCONFIG --cflags globus-gss-assist globus-gssapi-gsi globus-common`" ++ fi ++ ++ AC_DEFINE(GSSAPI) ++ AC_DEFINE(HAVE_GSSAPI_H) ++ ++ AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) ++fi ++ + # Check whether user wants systemd support + SYSTEMD_MSG="no" + AC_ARG_WITH(systemd, +diff -Nur openssh-8.7p1.orig/gss-genr.c openssh-8.7p1/gss-genr.c +--- openssh-8.7p1.orig/gss-genr.c 2021-10-24 07:32:35.551723895 +0200 ++++ openssh-8.7p1/gss-genr.c 2021-10-24 07:33:38.870876728 +0200 +@@ -40,6 +40,7 @@ + #include "ssherr.h" + #include "sshbuf.h" + #include "log.h" ++#include "canohost.h" + #include "ssh2.h" + #include "cipher.h" + #include "sshkey.h" +@@ -408,9 +409,18 @@ + ssh_gssapi_import_name(Gssctxt *ctx, const char *host) + { + gss_buffer_desc gssbuf; ++ char *xhost; + char *val; + +- xasprintf(&val, "host@%s", host); ++ /* Make a copy of the host name, in case it was returned by a ++ * previous call to gethostbyname(). */ ++ xhost = xstrdup(host); ++ ++ /* Make sure we have the FQDN. Some GSSAPI implementations don't do ++ * this for us themselves */ ++ resolve_localhost(&xhost); ++ ++ xasprintf(&val, "host@%s", xhost); + gssbuf.value = val; + gssbuf.length = strlen(gssbuf.value); + +@@ -418,6 +428,7 @@ + &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) + ssh_gssapi_error(ctx); + ++ free(xhost); + free(gssbuf.value); + return (ctx->major); + } +diff -Nur openssh-8.7p1.orig/gss-serv.c openssh-8.7p1/gss-serv.c +--- openssh-8.7p1.orig/gss-serv.c 2021-10-24 07:32:35.410723555 +0200 ++++ openssh-8.7p1/gss-serv.c 2021-10-24 07:33:38.870876728 +0200 +@@ -50,10 +50,12 @@ + #include "monitor_wrap.h" + + extern ServerOptions options; ++extern Authctxt *the_authctxt; + + static ssh_gssapi_client gssapi_client = +- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, +- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; ++ { {0, NULL}, GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, ++ GSS_C_NO_NAME, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, ++ GSS_C_NO_CONTEXT, 0, 0}; + + ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; +@@ -61,14 +63,26 @@ + #ifdef KRB5 + extern ssh_gssapi_mech gssapi_kerberos_mech; + #endif ++#ifdef GSI ++extern ssh_gssapi_mech gssapi_gsi_mech; ++extern ssh_gssapi_mech gssapi_gsi_mech_micv2; ++#endif + + ssh_gssapi_mech* supported_mechs[]= { + #ifdef KRB5 + &gssapi_kerberos_mech, + #endif ++#ifdef GSI ++ &gssapi_gsi_mech_micv2, ++ &gssapi_gsi_mech, ++#endif + &gssapi_null_mech, + }; + ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++static int limited = 0; ++#endif ++ + /* + * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the + * list of supported mechanisms before privsep is set up. +@@ -229,6 +243,10 @@ + (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { + if (ssh_gssapi_getclient(ctx, &gssapi_client)) + fatal("Couldn't convert client name"); ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++ if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG)) ++ limited=1; ++#endif + } + + return (status); +@@ -248,6 +266,20 @@ + + tok = ename->value; + ++#ifdef GSI /* GSI gss_export_name() is broken. */ ++ if (((ctx->oid->length == gssapi_gsi_mech.oid.length) && ++ (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements, ++ gssapi_gsi_mech.oid.length) == 0)) || ++ ((ctx->oid->length == gssapi_gsi_mech_micv2.oid.length) && ++ (memcmp(ctx->oid->elements, gssapi_gsi_mech_micv2.oid.elements, ++ gssapi_gsi_mech_micv2.oid.length) == 0))) { ++ name->length = ename->length; ++ name->value = xmalloc(ename->length+1); ++ memcpy(name->value, ename->value, ename->length); ++ return GSS_S_COMPLETE; ++ } ++#endif ++ + /* + * Check that ename is long enough for all of the fixed length + * header, and that the initial ID bytes are correct +@@ -308,21 +340,24 @@ + gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + + if (options.gss_store_rekey && client->used && ctx->client_creds) { +- if (client->mech->oid.length != ctx->oid->length || +- (memcmp(client->mech->oid.elements, ++ if (client->oid.length != ctx->oid->length || ++ (memcmp(client->oid.elements, + ctx->oid->elements, ctx->oid->length) !=0)) { + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } + +- if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, +- ctx->client_creds, ctx->oid, &new_name, ++ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech ++ because GSI doesn't support the latter. -jbasney */ ++ ++ if ((ctx->major = gss_inquire_cred(&ctx->minor, ++ ctx->client_creds, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + +- ctx->major = gss_compare_name(&ctx->minor, client->name, ++ ctx->major = gss_compare_name(&ctx->minor, client->cred_name, + new_name, &equal); + + if (GSS_ERROR(ctx->major)) { +@@ -337,9 +372,9 @@ + + debug("Marking rekeyed credentials for export"); + +- gss_release_name(&ctx->minor, &client->name); ++ gss_release_name(&ctx->minor, &client->cred_name); + gss_release_cred(&ctx->minor, &client->creds); +- client->name = new_name; ++ client->cred_name = new_name; + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + client->updated = 1; +@@ -356,12 +391,17 @@ + i++; + } + ++ if (client->oid.elements == NULL) ++ client->oid = *ctx->oid; + if (client->mech == NULL) + return GSS_S_FAILURE; + ++ /* Call gss_inquire_cred rather than gss_inquire_cred_by_mech ++ because GSI doesn't support the latter. -jbasney */ ++ + if (ctx->client_creds && +- (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, +- ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { ++ (ctx->major = gss_inquire_cred(&ctx->minor, ++ ctx->client_creds, &client->cred_name, NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } +@@ -378,16 +418,25 @@ + return (ctx->major); + } + +- if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, ++ if ((client->mech->oid.elements != NULL) && ++ (ctx->major = ssh_gssapi_parse_ename(ctx,&ename, + &client->exportedname))) { + return (ctx->major); + } + ++ if ((ctx->major = gss_duplicate_name(&ctx->minor, ctx->client, ++ &client->ctx_name))) ++ return ctx->major; ++ + gss_release_buffer(&ctx->minor, &ename); + + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; ++ ++ /* needed for globus_gss_assist_map_and_authorize() */ ++ client->context = ctx->context; ++ + return (ctx->major); + } + +@@ -395,6 +444,7 @@ + void + ssh_gssapi_cleanup_creds(void) + { ++#ifdef KRB5 + krb5_ccache ccache = NULL; + krb5_error_code problem; + +@@ -410,6 +460,14 @@ + gssapi_client.store.data = NULL; + } + } ++#else ++ if (gssapi_client.store.filename != NULL) { ++ /* Unlink probably isn't sufficient */ ++ debug("removing gssapi cred file\"%s\"", ++ gssapi_client.store.filename); ++ unlink(gssapi_client.store.filename); ++ } ++#endif + } + + /* As user */ +@@ -417,6 +475,11 @@ + ssh_gssapi_storecreds(void) + { + if (gssapi_client.mech && gssapi_client.mech->storecreds) { ++ if (options.gss_creds_path) { ++ gssapi_client.store.filename = ++ expand_authorized_keys(options.gss_creds_path, ++ the_authctxt->pw); ++ } + return (*gssapi_client.mech->storecreds)(&gssapi_client); + } else + debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); +@@ -449,11 +512,13 @@ + + (void) kex; /* used in privilege separation */ + +- if (gssapi_client.exportedname.length == 0 || +- gssapi_client.exportedname.value == NULL) { +- debug("No suitable client data"); ++#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG ++ if (limited && options.gsi_allow_limited_proxy != 1) { ++ debug("limited proxy not acceptable for remote login"); + return 0; + } ++#endif ++ + if (gssapi_client.mech && gssapi_client.mech->userok) + if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { + gssapi_client.used = 1; +@@ -464,6 +529,7 @@ + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); + gss_release_cred(&lmin, &gssapi_client.creds); ++ gss_release_name(&lmin, &gssapi_client.ctx_name); + explicit_bzero(&gssapi_client, + sizeof(ssh_gssapi_client)); + return 0; +@@ -473,6 +539,24 @@ + return (0); + } + ++/* Priviledged */ ++int ++ssh_gssapi_localname(char **user) ++{ ++ *user = NULL; ++ if (gssapi_client.displayname.length == 0 || ++ gssapi_client.displayname.value == NULL) { ++ debug("No suitable client data"); ++ return (0); ++ } ++ if (gssapi_client.mech && gssapi_client.mech->localname) { ++ return((*gssapi_client.mech->localname)(&gssapi_client,user)); ++ } else { ++ debug("Unknown client authentication type"); ++ } ++ return (0); ++} ++ + /* These bits are only used for rekeying. The unpriviledged child is running + * as the user, the monitor is root. + * +@@ -499,9 +583,11 @@ + pam_handle_t *pamh = NULL; + struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; + char *envstr; ++ char **p; char **pw; + #endif + +- if (gssapi_client.store.envval == NULL) ++ if (gssapi_client.store.filename == NULL && ++ gssapi_client.store.envval == NULL) + return; + + ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); +@@ -526,6 +612,18 @@ + if (ret) + return; + ++ /* Put ssh pam stack env variables in this new pam stack env ++ * Using pam-pkinit, KRB5CCNAME is set during do_pam_session ++ * this addition enables pam-pkinit to access KRB5CCNAME if used ++ * in sshd-rekey stack too ++ */ ++ pw = p = fetch_pam_environment(); ++ while ( *pw != NULL ) { ++ pam_putenv(pamh, *pw); ++ pw++; ++ } ++ free_pam_environment(p); ++ + xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, + gssapi_client.store.envval); + +diff -Nur openssh-8.7p1.orig/gss-serv-gsi.c openssh-8.7p1/gss-serv-gsi.c +--- openssh-8.7p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-8.7p1/gss-serv-gsi.c 2021-10-24 07:33:38.871876730 +0200 +@@ -0,0 +1,328 @@ ++/* ++ * Copyright (c) 2001-2003 Simon Wilkinson. 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 "includes.h" ++ ++#ifdef GSSAPI ++#ifdef GSI ++ ++#include ++ ++#include ++#include ++ ++#include "xmalloc.h" ++#include "hostfile.h" ++#include "auth.h" ++#include "log.h" ++#include "misc.h" ++#include "servconf.h" ++#include "ssh-gss.h" ++ ++extern ServerOptions options; ++ ++#include ++ ++static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name); ++static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user); ++static int ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client); ++static int ssh_gssapi_gsi_storecreds_micv2(ssh_gssapi_client *client); ++static int ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store, ++ ssh_gssapi_client *client); ++static int ssh_gssapi_gsi_updatecreds_micv2(ssh_gssapi_ccache *store, ++ ssh_gssapi_client *client); ++ ++ssh_gssapi_mech gssapi_gsi_mech = { ++ "dZuIebMjgUqaxvbF7hDbAw==", ++ "GSI", ++ {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}, ++ NULL, ++ &ssh_gssapi_gsi_userok, ++ &ssh_gssapi_gsi_localname, ++ &ssh_gssapi_gsi_storecreds, ++ &ssh_gssapi_gsi_updatecreds ++}; ++ ++ssh_gssapi_mech gssapi_gsi_mech_micv2 = { ++ "vz8J1E9PzLr8b1K+0remTg==", ++ "GSI", ++ {10, "\x2b\x06\x01\x04\x01\x9b\x50\x01\x01\x01"}, ++ NULL, ++ &ssh_gssapi_gsi_userok, ++ &ssh_gssapi_gsi_localname, ++ &ssh_gssapi_gsi_storecreds_micv2, ++ &ssh_gssapi_gsi_updatecreds_micv2 ++}; ++ ++/* ++ * Check if this user is OK to login under GSI. User has been authenticated ++ * as identity in global 'client_name.value' and is trying to log in as passed ++ * username in 'name'. ++ * ++ * Returns non-zero if user is authorized, 0 otherwise. ++ */ ++static int ++ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name) ++{ ++ int authorized = 0; ++ globus_result_t res; ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ char lname[256] = ""; ++#endif ++ ++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE ++ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { ++ return 0; ++ } ++#endif ++ ++/* use new globus_gss_assist_map_and_authorize() interface if available */ ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ debug("calling globus_gss_assist_map_and_authorize()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", ++ name, lname, 256))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ } else if (lname[0] && strcmp(name, lname) != 0) { ++ debug("GSI user maps to %s, not %s", lname, name); ++ } else { ++ authorized = 1; ++ } ++#else ++ debug("calling globus_gss_assist_userok()"); ++ if (GLOBUS_SUCCESS != ++ (res = (globus_gss_assist_userok(client->displayname.value, ++ name)))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ } else { ++ authorized = 1; ++ } ++#endif ++ ++ logit("GSI user %s is%s authorized as target user %s", ++ (char *) client->displayname.value, (authorized ? "" : " not"), name); ++ ++ return authorized; ++} ++ ++/* ++ * Return the local username associated with the GSI credentials. ++ */ ++int ++ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user) ++{ ++ globus_result_t res; ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ char lname[256] = ""; ++#endif ++ ++#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE ++ if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) { ++ return 0; ++ } ++#endif ++ ++/* use new globus_gss_assist_map_and_authorize() interface if available */ ++#ifdef HAVE_GLOBUS_GSS_ASSIST_MAP_AND_AUTHORIZE ++ debug("calling globus_gss_assist_map_and_authorize()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_map_and_authorize(client->context, "ssh", ++ NULL, lname, 256))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ logit("failed to map GSI user %s", (char *)client->displayname.value); ++ return 0; ++ } ++ *user = strdup(lname); ++#else ++ debug("calling globus_gss_assist_gridmap()"); ++ if (GLOBUS_SUCCESS != ++ (res = globus_gss_assist_gridmap(client->displayname.value, user))) { ++ debug("%s", globus_error_print_chain(globus_error_get(res))); ++ logit("failed to map GSI user %s", (char *)client->displayname.value); ++ return 0; ++ } ++#endif ++ ++ logit("GSI user %s mapped to target user %s", ++ (char *) client->displayname.value, *user); ++ ++ return 1; ++} ++ ++/* ++ * Export GSI credentials to disk. ++ */ ++static int ++ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) ++{ ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; ++ char * p; ++ ++ if (!client || !client->creds) { ++ return 0; ++ } ++ ++ major_status = gss_export_cred(&minor_status, ++ client->creds, ++ GSS_C_NO_OID, ++ 1, ++ &export_cred); ++ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { ++ Gssctxt *ctx; ++ ssh_gssapi_build_ctx(&ctx); ++ ctx->major = major_status; ++ ctx->minor = minor_status; ++ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid); ++ ssh_gssapi_error(ctx); ++ ssh_gssapi_delete_ctx(&ctx); ++ return 0; ++ } ++ ++ p = strchr((char *) export_cred.value, '='); ++ if (p == NULL) { ++ logit("Failed to parse exported credentials string '%.100s'", ++ (char *)export_cred.value); ++ gss_release_buffer(&minor_status, &export_cred); ++ return 0; ++ } ++ *p++ = '\0'; ++ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { ++ client->store.envvar = strdup("X509_USER_PROXY"); ++ } else { ++ client->store.envvar = strdup((char *)export_cred.value); ++ } ++ if (access(p, R_OK) == 0) { ++ if (client->store.filename) { ++ if (rename(p, client->store.filename) < 0) { ++ logit("Failed to rename %s to %s: %s", p, ++ client->store.filename, strerror(errno)); ++ free(client->store.filename); ++ client->store.filename = strdup(p); ++ } else { ++ p = client->store.filename; ++ } ++ } else { ++ client->store.filename = strdup(p); ++ } ++ } ++ client->store.envval = strdup(p); ++#ifdef USE_PAM ++ if (options.use_pam) ++ do_pam_putenv(client->store.envvar, client->store.envval); ++#endif ++ gss_release_buffer(&minor_status, &export_cred); ++ ++ return 1; ++} ++ ++/* ++ * Export GSI credentials to disk. ++ */ ++static int ++ssh_gssapi_gsi_storecreds_micv2(ssh_gssapi_client *client) ++{ ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER; ++ char * p; ++ ++ if (!client || !client->creds) { ++ return 0; ++ } ++ ++ major_status = gss_export_cred(&minor_status, ++ client->creds, ++ GSS_C_NO_OID, ++ 1, ++ &export_cred); ++ if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) { ++ Gssctxt *ctx; ++ ssh_gssapi_build_ctx(&ctx); ++ ctx->major = major_status; ++ ctx->minor = minor_status; ++ ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech_micv2.oid); ++ ssh_gssapi_error(ctx); ++ ssh_gssapi_delete_ctx(&ctx); ++ return 0; ++ } ++ ++ p = strchr((char *) export_cred.value, '='); ++ if (p == NULL) { ++ logit("Failed to parse exported credentials string '%.100s'", ++ (char *)export_cred.value); ++ gss_release_buffer(&minor_status, &export_cred); ++ return 0; ++ } ++ *p++ = '\0'; ++ if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) { ++ client->store.envvar = strdup("X509_USER_PROXY"); ++ } else { ++ client->store.envvar = strdup((char *)export_cred.value); ++ } ++ if (access(p, R_OK) == 0) { ++ if (client->store.filename) { ++ if (rename(p, client->store.filename) < 0) { ++ logit("Failed to rename %s to %s: %s", p, ++ client->store.filename, strerror(errno)); ++ free(client->store.filename); ++ client->store.filename = strdup(p); ++ } else { ++ p = client->store.filename; ++ } ++ } else { ++ client->store.filename = strdup(p); ++ } ++ } ++ client->store.envval = strdup(p); ++#ifdef USE_PAM ++ if (options.use_pam) ++ do_pam_putenv(client->store.envvar, client->store.envval); ++#endif ++ gss_release_buffer(&minor_status, &export_cred); ++ ++ return 1; ++} ++ ++/* ++ * Export updated GSI credentials to disk. ++ */ ++static int ++ssh_gssapi_gsi_updatecreds(ssh_gssapi_ccache *store,ssh_gssapi_client *client) ++{ ++ return ssh_gssapi_gsi_storecreds(client); ++} ++ ++/* ++ * Export updated GSI credentials to disk. ++ */ ++static int ++ssh_gssapi_gsi_updatecreds_micv2(ssh_gssapi_ccache *store,ssh_gssapi_client *client) ++{ ++ return ssh_gssapi_gsi_storecreds_micv2(client); ++} ++ ++#endif /* GSI */ ++#endif /* GSSAPI */ +diff -Nur openssh-8.7p1.orig/gss-serv-krb5.c openssh-8.7p1/gss-serv-krb5.c +--- openssh-8.7p1.orig/gss-serv-krb5.c 2021-10-24 07:32:35.440723628 +0200 ++++ openssh-8.7p1/gss-serv-krb5.c 2021-10-24 07:33:38.871876730 +0200 +@@ -379,6 +379,34 @@ + return found_principal; + } + ++/* Retrieve the local username associated with a set of Kerberos ++ * credentials. Hopefully we can use this for the 'empty' username ++ * logins discussed in the draft */ ++static int ++ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) { ++ krb5_principal princ; ++ int retval; ++ ++ if (ssh_gssapi_krb5_init() == 0) ++ return 0; ++ ++ if ((retval=krb5_parse_name(krb_context, client->displayname.value, ++ &princ))) { ++ logit("krb5_parse_name(): %.100s", ++ krb5_get_err_text(krb_context,retval)); ++ return 0; ++ } ++ ++ /* We've got to return a malloc'd string */ ++ *user = (char *)xmalloc(256); ++ if (krb5_aname_to_localname(krb_context, princ, 256, *user)) { ++ free(*user); ++ *user = NULL; ++ return(0); ++ } ++ ++ return(1); ++} + + /* This writes out any forwarded credentials from the structure populated + * during userauth. Called after we have setuid to the user */ +@@ -473,7 +501,7 @@ + return set_env; + } + +-int ++static int + ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, + ssh_gssapi_client *client) + { +@@ -544,7 +572,7 @@ + {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, + NULL, + &ssh_gssapi_krb5_userok, +- NULL, ++ &ssh_gssapi_krb5_localname, + &ssh_gssapi_krb5_storecreds, + &ssh_gssapi_krb5_updatecreds + }; +diff -Nur openssh-8.7p1.orig/kexgsss.c openssh-8.7p1/kexgsss.c +--- openssh-8.7p1.orig/kexgsss.c 2021-10-24 07:32:35.567723933 +0200 ++++ openssh-8.7p1/kexgsss.c 2021-10-24 07:33:38.871876730 +0200 +@@ -48,6 +48,7 @@ + #include "digest.h" + #include "ssherr.h" + ++static void kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh); + extern ServerOptions options; + + int +@@ -96,8 +97,10 @@ + + debug2_f("Acquiring credentials"); + +- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { ++ kex_gss_send_error(ctxt, ssh); + fatal("Unable to acquire credentials for the server"); ++ } + + do { + debug("Wait SSH2_MSG_KEXGSS_INIT"); +@@ -195,13 +198,14 @@ + } while (maj_status & GSS_S_CONTINUE_NEEDED); + + if (GSS_ERROR(maj_status)) { ++ kex_gss_send_error(ctxt, ssh); + if (send_tok.length > 0) { + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || + (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || + (r = sshpkt_send(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } +- fatal("accept_ctx died"); ++ ssh_packet_disconnect(ssh, "GSSAPI Key Exchange handshake failed"); + } + + if (!(ret_flags & GSS_C_MUTUAL_FLAG)) +@@ -479,4 +483,26 @@ + sshbuf_free(shared_secret); + return r; + } ++ ++static void ++kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh) { ++ char *errstr; ++ OM_uint32 maj, min; ++ int r; ++ ++ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); ++ if (errstr) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_ERROR)) != 0 || ++ (r = sshpkt_put_u32(ssh, maj)) != 0 || ++ (r = sshpkt_put_u32(ssh, min)) != 0 || ++ (r = sshpkt_put_cstring(ssh, errstr)) != 0 || ++ (r = sshpkt_put_cstring(ssh, "")) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if ((r = ssh_packet_write_wait(ssh)) != 0) ++ fatal("ssh_packet_write_wait: %s", ssh_err(r)); ++ /* XXX - We should probably log the error locally here */ ++ free(errstr); ++ } ++} + #endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ +diff -Nur openssh-8.7p1.orig/Makefile.in openssh-8.7p1/Makefile.in +--- openssh-8.7p1.orig/Makefile.in 2021-10-24 07:32:35.522723825 +0200 ++++ openssh-8.7p1/Makefile.in 2021-10-24 07:33:38.872876733 +0200 +@@ -128,6 +128,7 @@ + auth2-none.o auth2-passwd.o auth2-pubkey.o \ + monitor.o monitor_wrap.o auth-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ ++ gss-serv-gsi.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ + srclimit.o sftp-server.o sftp-common.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ +diff -Nur openssh-8.7p1.orig/misc.c openssh-8.7p1/misc.c +--- openssh-8.7p1.orig/misc.c 2021-10-24 07:32:35.553723900 +0200 ++++ openssh-8.7p1/misc.c 2021-10-24 07:33:38.873876735 +0200 +@@ -393,11 +393,14 @@ + #define WHITESPACE " \t\r\n" + #define QUOTE "\"" + ++/* Characters considered as quotations. */ ++#define QUOTES "'\"" ++ + /* return next token in configuration line */ + static char * + strdelim_internal(char **s, int split_equals) + { +- char *old; ++ char *old, *p, *q; + int wspace = 0; + + if (*s == NULL) +@@ -405,6 +408,21 @@ + + old = *s; + ++ if ((q=strchr(QUOTES, (int) *old)) && *q) ++ { ++ /* find next quote character, point old to start of quoted ++ * string */ ++ for (p = ++old; *p && *p != *q; p++) ++ ; ++ ++ /* find start of next token */ ++ *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL; ++ ++ /* terminate 'old' token */ ++ *p = '\0'; ++ return (old); ++ } ++ + *s = strpbrk(*s, + split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE); + if (*s == NULL) +@@ -480,6 +498,20 @@ + return copy; + } + ++void ++pwfree(struct passwd *pw) ++{ ++ free(pw->pw_name); ++ free(pw->pw_passwd); ++ free(pw->pw_gecos); ++#ifdef HAVE_PW_CLASS_IN_PASSWD ++ free(pw->pw_class); ++#endif ++ free(pw->pw_dir); ++ free(pw->pw_shell); ++ free(pw); ++} ++ + /* + * Convert ASCII string to TCP/IP port number. + * Port must be >=0 and <=65535. +diff -Nur openssh-8.7p1.orig/misc.h openssh-8.7p1/misc.h +--- openssh-8.7p1.orig/misc.h 2021-10-24 07:32:35.466723690 +0200 ++++ openssh-8.7p1/misc.h 2021-10-24 07:33:38.874876737 +0200 +@@ -100,6 +100,7 @@ + void sock_set_v6only(int); + + struct passwd *pwcopy(struct passwd *); ++void pwfree(struct passwd *); + const char *ssh_gai_strerror(int); + + typedef void privdrop_fn(struct passwd *); +diff -Nur openssh-8.7p1.orig/monitor.c openssh-8.7p1/monitor.c +--- openssh-8.7p1.orig/monitor.c 2021-10-24 07:32:35.554723902 +0200 ++++ openssh-8.7p1/monitor.c 2021-10-24 07:33:38.875876740 +0200 +@@ -152,6 +152,9 @@ + int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); + int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); + int mm_answer_gss_sign(struct ssh *, int, struct sshbuf *); ++int mm_answer_gss_error(struct ssh *, int, struct sshbuf *); ++int mm_answer_gss_indicate_mechs(struct ssh *, int, struct sshbuf *); ++int mm_answer_gss_localname(struct ssh *, int, struct sshbuf *); + int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *); + #endif + +@@ -204,7 +207,7 @@ + {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, + #endif + {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, +- {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, ++ {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, + #ifdef WITH_SELINUX + {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, +@@ -212,7 +215,7 @@ + {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, + #ifdef USE_PAM +- {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, ++ {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start}, + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query}, +@@ -236,8 +239,11 @@ + {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, + {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, +- {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, ++ {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, + {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, ++ {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error}, ++ {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, ++ {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, + #endif + {0, 0, NULL} + }; +@@ -247,6 +253,8 @@ + {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, + {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, ++ {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error}, ++ {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, + #endif + #ifdef WITH_OPENSSL +@@ -327,6 +335,8 @@ + #ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); + #endif + + /* The first few requests do not require asynchronous access */ +@@ -444,6 +454,8 @@ + #ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); ++ monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); + #endif + + if (auth_opts->permit_pty_flag) { +@@ -760,15 +772,18 @@ + + debug3_f("entering"); + +- if (authctxt->attempt++ != 0) +- fatal_f("multiple attempts for getpwnam"); +- + if ((r = sshbuf_get_cstring(m, &username, NULL)) != 0) + fatal_fr(r, "parse"); + + pwent = getpwnamallow(ssh, username); + ++ if (authctxt->user) free(authctxt->user); + authctxt->user = xstrdup(username); ++#ifdef USE_PAM ++ if (options.permit_pam_user_change) ++ setproctitle("%s [priv]", pwent ? "[pam]" : "unknown"); ++ else ++#endif + setproctitle("%s [priv]", pwent ? username : "unknown"); + free(username); + +@@ -2109,6 +2124,79 @@ + } + + int ++mm_answer_gss_error(struct ssh *ssh, int socket, struct sshbuf *m) ++{ ++ OM_uint32 major, minor; ++ char *msg; ++ int r; ++ ++ msg=ssh_gssapi_last_error(gsscontext, &major, &minor); ++ sshbuf_reset(m); ++ if ((r = sshbuf_put_u32(m, major)) != 0 || ++ (r = sshbuf_put_u32(m, minor)) != 0 || ++ (r = sshbuf_put_cstring(m, msg)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSERR, m); ++ ++ free(msg); ++ ++ return(0); ++} ++ ++int ++mm_answer_gss_indicate_mechs(struct ssh *ssh, int socket, struct sshbuf *m) ++{ ++ OM_uint32 major, minor; ++ gss_OID_set mech_set; ++ size_t i; ++ int r; ++ ++ major=gss_indicate_mechs(&minor, &mech_set); ++ ++ sshbuf_reset(m); ++ if ((r = sshbuf_put_u32(m, major)) != 0 || ++ (r = sshbuf_put_u32(m, mech_set->count)) != 0) ++ fatal_fr(r, "buffer error"); ++ for (i = 0; i < mech_set->count; i++) { ++ if ((r = sshbuf_put_string(m, mech_set->elements[i].elements, ++ mech_set->elements[i].length)) != 0) ++ fatal_fr(r, "buffer error"); ++ } ++ ++ gss_release_oid_set(&minor, &mech_set); ++ ++ mm_request_send(socket, MONITOR_ANS_GSSMECHS, m); ++ ++ return(0); ++} ++ ++int ++mm_answer_gss_localname(struct ssh *ssh, int socket, struct sshbuf *m) ++{ ++ char *name; ++ int r; ++ ++ ssh_gssapi_localname(&name); ++ ++ sshbuf_reset(m); ++ if (name) { ++ if ((r = sshbuf_put_cstring(m, name)) != 0) ++ fatal_fr(r, "buffer error"); ++ debug3_f("sending result %s", name); ++ free(name); ++ } else { ++ if ((r = sshbuf_put_cstring(m, "")) != 0) ++ fatal_fr(r, "buffer error"); ++ debug3_f("sending result \"\""); ++ } ++ ++ mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); ++ ++ return(0); ++} ++ ++int + mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m) + { + gss_buffer_desc data; +diff -Nur openssh-8.7p1.orig/monitor.h openssh-8.7p1/monitor.h +--- openssh-8.7p1.orig/monitor.h 2021-10-24 07:32:35.523723828 +0200 ++++ openssh-8.7p1/monitor.h 2021-10-24 07:33:38.876876743 +0200 +@@ -75,6 +75,10 @@ + + MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, + MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, ++ ++ MONITOR_REQ_GSSMECHS = 200, MONITOR_ANS_GSSMECHS = 201, ++ MONITOR_REQ_GSSLOCALNAME = 202, MONITOR_ANS_GSSLOCALNAME = 203, ++ MONITOR_REQ_GSSERR = 204, MONITOR_ANS_GSSERR = 205 + }; + + struct ssh; +diff -Nur openssh-8.7p1.orig/monitor_wrap.c openssh-8.7p1/monitor_wrap.c +--- openssh-8.7p1.orig/monitor_wrap.c 2021-10-24 07:32:35.555723904 +0200 ++++ openssh-8.7p1/monitor_wrap.c 2021-10-24 07:33:38.876876743 +0200 +@@ -1084,6 +1084,94 @@ + return (authenticated); + } + ++char * ++mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) ++{ ++ struct sshbuf *m = NULL; ++ OM_uint32 maj,min; ++ char *errstr; ++ int r; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, m); ++ ++ if ((r = sshbuf_get_u32(m, &maj)) != 0 || ++ (r = sshbuf_get_u32(m, &min)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ if (major) *major=maj; ++ if (minor) *minor=min; ++ ++ if ((r = sshbuf_get_cstring(m, &errstr, NULL)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ sshbuf_free(m); ++ ++ return(errstr); ++} ++ ++OM_uint32 ++mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) ++{ ++ struct sshbuf *m = NULL; ++ OM_uint32 major,minor; ++ int count; ++ gss_OID_desc oid; ++ size_t length; ++ int r; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS, m); ++ if ((r = sshbuf_get_u32(m, &major)) != 0 || ++ (r = sshbuf_get_u32(m, &count)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ gss_create_empty_oid_set(&minor, mech_set); ++ while(count-->0) { ++ if ((r = sshbuf_get_string(m, (u_char **)&oid.elements, &length)) != 0) ++ fatal_fr(r, "buffer error"); ++ oid.length = length; ++ gss_add_oid_set_member(&minor, &oid, mech_set); ++ } ++ ++ sshbuf_free(m); ++ ++ return(major); ++} ++ ++int ++mm_ssh_gssapi_localname(char **lname) ++{ ++ struct sshbuf *m = NULL; ++ int r; ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, m); ++ ++ debug3_f("waiting for MONITOR_ANS_GSSLOCALNAME"); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME, ++ m); ++ ++ if ((r = sshbuf_get_cstring(m, lname, NULL)) != 0) ++ fatal_fr(r, "buffer error"); ++ ++ sshbuf_free(m); ++ if ((*lname == NULL) || (*lname[0] == '\0')) { ++ debug3_f("gssapi identity mapping failed"); ++ } else { ++ debug3_f("gssapi identity mapped to %s", *lname); ++ } ++ ++ return(0); ++} ++ + OM_uint32 + mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) + { +diff -Nur openssh-8.7p1.orig/monitor_wrap.h openssh-8.7p1/monitor_wrap.h +--- openssh-8.7p1.orig/monitor_wrap.h 2021-10-24 07:32:35.533723852 +0200 ++++ openssh-8.7p1/monitor_wrap.h 2021-10-24 07:33:38.877876745 +0200 +@@ -73,6 +73,10 @@ + int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex); + OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); + OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); ++int mm_ssh_gssapi_localname(char **user); ++OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status, ++ gss_OID_set *mech_set); ++char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); + int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); + #endif + +diff -Nur openssh-8.7p1.orig/readconf.c openssh-8.7p1/readconf.c +--- openssh-8.7p1.orig/readconf.c 2021-10-24 07:32:35.557723909 +0200 ++++ openssh-8.7p1/readconf.c 2021-10-24 07:33:38.878876747 +0200 +@@ -2516,11 +2516,11 @@ + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; + if (options->gss_authentication == -1) +- options->gss_authentication = 0; ++ options->gss_authentication = 1; + if (options->gss_keyex == -1) +- options->gss_keyex = 0; ++ options->gss_keyex = 1; + if (options->gss_deleg_creds == -1) +- options->gss_deleg_creds = 0; ++ options->gss_deleg_creds = 1; + if (options->gss_trust_dns == -1) + options->gss_trust_dns = 0; + if (options->gss_renewal_rekey == -1) +diff -Nur openssh-8.7p1.orig/readconf.h openssh-8.7p1/readconf.h +--- openssh-8.7p1.orig/readconf.h 2021-10-24 07:32:35.395723519 +0200 ++++ openssh-8.7p1/readconf.h 2021-10-24 07:33:38.879876750 +0200 +@@ -78,6 +78,8 @@ + char *host_key_alias; /* hostname alias for .ssh/known_hosts */ + char *proxy_command; /* Proxy command for connecting the host. */ + char *user; /* User to log in as. */ ++ int implicit; /* Login user was not specified. ++ Server may choose based on authctxt. */ + int escape_char; /* Escape character; -2 = none */ + + u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ +diff -Nur openssh-8.7p1.orig/servconf.c openssh-8.7p1/servconf.c +--- openssh-8.7p1.orig/servconf.c 2021-10-24 07:32:35.558723912 +0200 ++++ openssh-8.7p1/servconf.c 2021-10-24 07:33:38.880876752 +0200 +@@ -93,6 +93,7 @@ + + /* Portable-specific options */ + options->use_pam = -1; ++ options->permit_pam_user_change = -1; + + /* Standard Options */ + options->num_ports = 0; +@@ -139,9 +140,11 @@ + options->kerberos_get_afs_token = -1; + options->kerberos_unique_ccache = -1; + options->gss_authentication=-1; ++ options->gss_deleg_creds = -1; + options->gss_keyex = -1; + options->gss_cleanup_creds = -1; + options->gss_strict_acceptor = -1; ++ options->gsi_allow_limited_proxy = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; + options->use_kuserok = -1; +@@ -291,6 +294,8 @@ + /* Portable-specific options */ + if (options->use_pam == -1) + options->use_pam = 0; ++ if (options->permit_pam_user_change == -1) ++ options->permit_pam_user_change = 0; + + /* Standard Options */ + if (options->num_host_key_files == 0) { +@@ -372,13 +377,17 @@ + if (options->kerberos_unique_ccache == -1) + options->kerberos_unique_ccache = 0; + if (options->gss_authentication == -1) +- options->gss_authentication = 0; ++ options->gss_authentication = 1; ++ if (options->gss_deleg_creds == -1) ++ options->gss_deleg_creds = 1; + if (options->gss_keyex == -1) +- options->gss_keyex = 0; ++ options->gss_keyex = 1; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; + if (options->gss_strict_acceptor == -1) + options->gss_strict_acceptor = 1; ++ if (options->gsi_allow_limited_proxy == -1) ++ options->gsi_allow_limited_proxy = 0; + if (options->gss_store_rekey == -1) + options->gss_store_rekey = 0; + #ifdef GSSAPI +@@ -514,7 +523,7 @@ + typedef enum { + sBadOption, /* == unknown option */ + /* Portable-specific options */ +- sUsePAM, ++ sUsePAM, sPermitPAMUserChange, + /* Standard Options */ + sPort, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, +@@ -535,6 +544,9 @@ + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, + sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, ++ sGssDelegateCreds, ++ sGssCredsPath, ++ sGsiAllowLimitedProxy, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, + sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, +@@ -567,8 +579,10 @@ + /* Portable-specific options */ + #ifdef USE_PAM + { "usepam", sUsePAM, SSHCFG_GLOBAL }, ++ { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }, + #else + { "usepam", sUnsupported, SSHCFG_GLOBAL }, ++ { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, + /* Standard Options */ +@@ -621,8 +635,15 @@ + { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, + #ifdef GSSAPI + { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, ++ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_ALL }, + { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, ++ { "gssapicredentialspath", sGssCredsPath, SSHCFG_GLOBAL }, ++#ifdef GSI ++ { "gsiallowlimitedproxy", sGsiAllowLimitedProxy, SSHCFG_GLOBAL }, ++#else ++ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, ++#endif + { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, +@@ -630,8 +651,11 @@ + { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, ++ { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, + { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, ++ { "gssapicredentialspath", sUnsupported, SSHCFG_GLOBAL }, ++ { "gsiallowlimitedproxy", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, +@@ -703,6 +727,8 @@ + { "permitlisten", sPermitListen, SSHCFG_ALL }, + { "forcecommand", sForceCommand, SSHCFG_ALL }, + { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, ++ { "disableusagestats", sUnsupported, SSHCFG_GLOBAL}, ++ { "usagestatstargets", sUnsupported, SSHCFG_GLOBAL}, + { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, +@@ -1381,6 +1407,10 @@ + intptr = &options->use_pam; + goto parse_flag; + ++ case sPermitPAMUserChange: ++ intptr = &options->permit_pam_user_change; ++ goto parse_flag; ++ + /* Standard Options */ + case sBadOption: + goto out; +@@ -1628,6 +1658,10 @@ + intptr = &options->gss_authentication; + goto parse_flag; + ++ case sGssDelegateCreds: ++ intptr = &options->gss_deleg_creds; ++ goto parse_flag; ++ + case sGssKeyEx: + intptr = &options->gss_keyex; + goto parse_flag; +@@ -1636,6 +1670,10 @@ + intptr = &options->gss_cleanup_creds; + goto parse_flag; + ++ case sGssCredsPath: ++ charptr = &options->gss_creds_path; ++ goto parse_filename; ++ + case sGssStrictAcceptor: + intptr = &options->gss_strict_acceptor; + goto parse_flag; +@@ -1656,6 +1694,12 @@ + options->gss_kex_algorithms = xstrdup(arg); + break; + ++#ifdef GSI ++ case sGsiAllowLimitedProxy: ++ intptr = &options->gsi_allow_limited_proxy; ++ goto parse_flag; ++#endif ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -2661,6 +2705,7 @@ + + M_CP_INTOPT(password_authentication); + M_CP_INTOPT(gss_authentication); ++ M_CP_INTOPT(gss_deleg_creds); + M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(pubkey_auth_options); + M_CP_INTOPT(kerberos_authentication); +diff -Nur openssh-8.7p1.orig/servconf.h openssh-8.7p1/servconf.h +--- openssh-8.7p1.orig/servconf.h 2021-10-24 07:32:35.456723666 +0200 ++++ openssh-8.7p1/servconf.h 2021-10-24 07:33:38.881876754 +0200 +@@ -146,9 +146,12 @@ + * be stored in per-session ccache */ + int use_kuserok; + int enable_k5users; ++ int gsi_allow_limited_proxy; /* If true, accept limited proxies */ + int gss_authentication; /* If true, permit GSSAPI authentication */ ++ int gss_deleg_creds; /* If true, store delegated GSSAPI credentials*/ + int gss_keyex; /* If true, permit GSSAPI key exchange */ + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ ++ char *gss_creds_path; /* Use non-default credentials path */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; + char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ +@@ -209,6 +212,7 @@ + char *adm_forced_command; + + int use_pam; /* Enable auth via PAM */ ++ int permit_pam_user_change; /* Allow PAM to change user name */ + + int permit_tun; + +diff -Nur openssh-8.7p1.orig/ssh.1 openssh-8.7p1/ssh.1 +--- openssh-8.7p1.orig/ssh.1 2021-10-24 07:32:35.397723524 +0200 ++++ openssh-8.7p1/ssh.1 2021-10-24 07:33:38.882876757 +0200 +@@ -1492,6 +1492,18 @@ + on to new connections). + .It Ev USER + Set to the name of the user logging in. ++.It Ev X509_CERT_DIR ++Used for GSI authentication. Specifies a non-standard location for the ++CA certificates directory. ++.It Ev X509_USER_CERT ++Used for GSI authentication. Specifies a non-standard location for the ++certificate to be used for authentication to the server. ++.It Ev X509_USER_KEY ++Used for GSI authentication. Specifies a non-standard location for the ++private key to be used for authentication to the server. ++.It Ev X509_USER_PROXY ++Used for GSI authentication. Specifies a non-standard location for the ++proxy credential to be used for authentication to the server. + .El + .Pp + Additionally, +diff -Nur openssh-8.7p1.orig/ssh.c openssh-8.7p1/ssh.c +--- openssh-8.7p1.orig/ssh.c 2021-10-24 07:32:35.562723921 +0200 ++++ openssh-8.7p1/ssh.c 2021-10-24 07:33:38.883876759 +0200 +@@ -558,6 +558,38 @@ + fatal("Can't open user config file %.100s: " + "%.100s", config, strerror(errno)); + } else { ++ /* ++ * Since the config file parsing code aborts if it sees ++ * options it doesn't recognize, allow users to put ++ * options specific to compile-time add-ons in alternate ++ * config files so their primary config file will ++ * interoperate SSH versions that don't support those ++ * options. ++ */ ++#ifdef GSSAPI ++ r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_name, ++ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | ++ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); ++#ifdef GSI ++ r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_name, ++ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | ++ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); ++#endif ++#if defined(KRB5) ++ r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir, ++ _PATH_SSH_USER_CONFFILE); ++ if (r > 0 && (size_t)r < sizeof(buf)) ++ (void)read_config_file(buf, pw, host, host_name, ++ &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | ++ (final_pass ? SSHCONF_FINAL : 0), want_final_pass); ++#endif ++#endif + r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + if (r > 0 && (size_t)r < sizeof(buf)) +@@ -1236,8 +1268,12 @@ + if (fill_default_options(&options) != 0) + cleanup_exit(255); + +- if (options.user == NULL) ++ if (options.user == NULL) { + options.user = xstrdup(pw->pw_name); ++ options.implicit = 1; ++ } else { ++ options.implicit = 0; ++ } + + /* + * If ProxyJump option specified, then construct a ProxyCommand now. +diff -Nur openssh-8.7p1.orig/ssh_config openssh-8.7p1/ssh_config +--- openssh-8.7p1.orig/ssh_config 2021-10-24 07:32:35.398723526 +0200 ++++ openssh-8.7p1/ssh_config 2021-10-24 07:33:38.884876762 +0200 +@@ -22,9 +22,9 @@ + # ForwardX11 no + # PasswordAuthentication yes + # HostbasedAuthentication no +-# GSSAPIAuthentication no +-# GSSAPIDelegateCredentials no +-# GSSAPIKeyExchange no ++# GSSAPIAuthentication yes ++# GSSAPIDelegateCredentials yes ++# GSSAPIKeyExchange yes + # GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes +diff -Nur openssh-8.7p1.orig/ssh_config.5 openssh-8.7p1/ssh_config.5 +--- openssh-8.7p1.orig/ssh_config.5 2021-10-24 07:32:35.489723746 +0200 ++++ openssh-8.7p1/ssh_config.5 2021-10-24 07:33:38.885876764 +0200 +@@ -52,6 +52,12 @@ + user's configuration file + .Pq Pa ~/.ssh/config + .It ++GSSAPI configuration file ++.Pq Pa $HOME/.ssh/config.gssapi ++.It ++Kerberos configuration file ++.Pq Pa $HOME/.ssh/config.krb ++.It + system-wide configuration file + .Pq Pa /etc/ssh/ssh_config + .El +@@ -821,7 +827,7 @@ + .It Cm GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is +-.Cm no . ++.Cm yes . + .It Cm GSSAPIClientIdentity + If set, specifies the GSSAPI client identity that ssh should use when + connecting to the server. The default is unset, which means that the default +@@ -829,12 +835,12 @@ + .It Cm GSSAPIDelegateCredentials + Forward (delegate) credentials to the server. + The default is +-.Cm no . ++.Cm yes . + .It Cm GSSAPIKeyExchange + Specifies whether key exchange based on GSSAPI may be used. When using + GSSAPI key exchange the server need not have a host key. + The default is +-.Dq no . ++.Dq yes . + .It Cm GSSAPIRenewalForcesRekey + If set to + .Dq yes +@@ -1458,7 +1464,7 @@ + .Cm password ) . + The default is: + .Bd -literal -offset indent +-gssapi-with-mic,hostbased,publickey, ++gssapi-keyex,gssapi-with-mic,hostbased,publickey, + keyboard-interactive,password + .Ed + .It Cm ProxyCommand +diff -Nur openssh-8.7p1.orig/sshconnect2.c openssh-8.7p1/sshconnect2.c +--- openssh-8.7p1.orig/sshconnect2.c 2021-10-24 07:32:35.542723873 +0200 ++++ openssh-8.7p1/sshconnect2.c 2021-10-24 07:33:38.886876767 +0200 +@@ -860,6 +860,11 @@ + gss_OID mech = NULL; + char *gss_host = NULL; + ++ if (!options.gss_authentication) { ++ verbose("GSSAPI authentication disabled."); ++ return 0; ++ } ++ + if (options.gss_server_identity) { + gss_host = xstrdup(options.gss_server_identity); + } else if (options.gss_trust_dns) { +@@ -971,7 +976,8 @@ + + if (status == GSS_S_COMPLETE) { + /* send either complete or MIC, depending on mechanism */ +- if (!(flags & GSS_C_INTEG_FLAG)) { ++ if (strcmp(authctxt->method->name, "gssapi") == 0 || ++ !(flags & GSS_C_INTEG_FLAG)) { + if ((r = sshpkt_start(ssh, + SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 || + (r = sshpkt_send(ssh)) != 0) +@@ -1142,6 +1148,20 @@ + return r; + } + ++#ifdef GSI ++extern ++const gss_OID_desc * const gss_mech_globus_gssapi_openssl; ++extern ++const gss_OID_desc * const gss_mech_globus_gssapi_openssl_micv2; ++#define is_gsi_oid(oid) \ ++ ((oid->length == gss_mech_globus_gssapi_openssl->length && \ ++ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \ ++ oid->length) == 0)) || \ ++ (oid->length == gss_mech_globus_gssapi_openssl_micv2->length && \ ++ (memcmp(oid->elements, gss_mech_globus_gssapi_openssl_micv2->elements, \ ++ oid->length) == 0))) ++#endif ++ + int + userauth_gsskeyex(struct ssh *ssh) + { +@@ -1164,6 +1184,12 @@ + if ((b = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + ++#ifdef GSI ++ if (options.implicit && is_gsi_oid(gss_kex_context->oid)) ++ ssh_gssapi_buildmic(b, "", authctxt->service, ++ "gssapi-keyex", ssh->kex->session_id); ++ else ++#endif + ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, + "gssapi-keyex", ssh->kex->session_id); + +@@ -1177,7 +1203,9 @@ + } + + if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || +- (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || ++ (r = sshpkt_put_cstring(ssh, ++ (options.implicit && is_gsi_oid(gss_kex_context->oid)) ? ++ "" : authctxt->server_user)) != 0 || + (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || + (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || + (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 || +diff -Nur openssh-8.7p1.orig/sshd.8 openssh-8.7p1/sshd.8 +--- openssh-8.7p1.orig/sshd.8 2021-10-24 07:32:35.418723575 +0200 ++++ openssh-8.7p1/sshd.8 2021-10-24 07:33:38.887876769 +0200 +@@ -818,6 +818,29 @@ + # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org + @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... + .Ed ++.Sh ENVIRONMENT ++.Nm ++will normally set the following environment variables: ++.Bl -tag -width "SSH_ORIGINAL_COMMAND" ++.It Ev GRIDMAP ++Applies to GSI authentication/authorization. Specifies the location of the ++gridmapfile. If not specified, the gridmap file is assumed to be available at ++/etc/grid-security/grid-mapfile for services running as root and at ++HOME/.gridmap for services running as non-root where HOME is the home directory ++of the effective user from the password file entry. ++.It Ev X509_CERT_DIR ++Used for GSI authentication. Specifies a non-standard location for the ++CA certificates directory. ++.It Ev X509_USER_CERT ++Used for GSI authentication. Specifies a non-standard location for the ++certificate to be used for authentication to the client. ++.It Ev X509_USER_KEY ++Used for GSI authentication. Specifies a non-standard location for the ++private key to be used for authentication to the client. ++.It Ev X509_USER_PROXY ++Used for GSI authentication. Specifies a non-standard location for the ++proxy credential to be used for authentication to the client. ++.El + .Sh FILES + .Bl -tag -width Ds -compact + .It Pa ~/.hushlogin +diff -Nur openssh-8.7p1.orig/sshd.c openssh-8.7p1/sshd.c +--- openssh-8.7p1.orig/sshd.c 2021-10-24 07:32:35.563723924 +0200 ++++ openssh-8.7p1/sshd.c 2021-10-24 07:33:38.888876772 +0200 +@@ -2380,7 +2380,7 @@ + #endif + + #ifdef GSSAPI +- if (options.gss_authentication) { ++ if (options.gss_authentication && options.gss_deleg_creds) { + temporarily_use_uid(authctxt->pw); + authctxt->krb5_set_env = ssh_gssapi_storecreds(); + restore_uid(); +diff -Nur openssh-8.7p1.orig/sshd_config openssh-8.7p1/sshd_config +--- openssh-8.7p1.orig/sshd_config 2021-10-24 07:32:35.443723635 +0200 ++++ openssh-8.7p1/sshd_config 2021-10-24 07:33:38.889876774 +0200 +@@ -76,10 +76,11 @@ + #KerberosUseKuserok yes + + # GSSAPI options +-#GSSAPIAuthentication no ++#GSSAPIAuthentication yes ++#GSSAPIDelegateCredentials yes + #GSSAPICleanupCredentials yes + #GSSAPIStrictAcceptorCheck yes +-#GSSAPIKeyExchange no ++#GSSAPIKeyExchange yes + #GSSAPIEnablek5users no + + # Set this to 'yes' to enable PAM authentication, account processing, +@@ -95,6 +96,10 @@ + # problems. + #UsePAM no + ++# Set to 'yes' to allow the PAM stack to change the user name during ++# calls to authentication ++#PermitPAMUserChange no ++ + #AllowAgentForwarding yes + #AllowTcpForwarding yes + #GatewayPorts no +diff -Nur openssh-8.7p1.orig/sshd_config.5 openssh-8.7p1/sshd_config.5 +--- openssh-8.7p1.orig/sshd_config.5 2021-10-24 07:32:35.490723748 +0200 ++++ openssh-8.7p1/sshd_config.5 2021-10-24 07:33:38.890876776 +0200 +@@ -635,15 +635,34 @@ + to allow the client to select the address to which the forwarding is bound. + The default is + .Cm no . ++.It Cm GSIAllowLimitedProxy ++Specifies whether to accept limited proxy credentials for authentication. ++The default is ++.Cm no . + .It Cm GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is +-.Cm no . ++.Cm yes . + .It Cm GSSAPICleanupCredentials + Specifies whether to automatically destroy the user's credentials cache + on logout. + The default is + .Cm yes . ++.It Cm GSSAPICredentialsPath ++If specified, the delegated GSSAPI credential is stored in the ++given path, overwriting any existing credentials. ++Paths can be specified with syntax similar to the AuthorizedKeysFile ++option (i.e., accepting %h and %u tokens). ++When using this option, ++setting 'GssapiCleanupCredentials no' is recommended, ++so logging out of one session ++doesn't remove the credentials in use by another session of ++the same user. ++Currently only implemented for the GSI mechanism. ++.It Cm GSSAPIDelegateCredentials ++Specifies whether delegated credentials are stored in the user's environment. ++The default is ++.Cm yes . + .It Cm GSSAPIEnablek5users + Specifies whether to look at .k5users file for GSSAPI authentication + access control. Further details are described in +@@ -654,7 +673,7 @@ + Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange + doesn't rely on ssh keys to verify host identity. + The default is +-.Cm no . ++.Cm yes . + .It Cm GSSAPIStrictAcceptorCheck + Determines whether to be strict about the identity of the GSSAPI acceptor + a client authenticates against. +@@ -1788,6 +1807,12 @@ + as a non-root user. + The default is + .Cm no . ++.It Cm PermitPAMUserChange ++If set to ++.Cm yes ++this will enable PAM authentication to change the name of the user being ++authenticated. The default is ++.Cm no . + .It Cm VersionAddendum + Optionally specifies additional text to append to the SSH protocol banner + sent by the server upon connection. +diff -Nur openssh-8.7p1.orig/sshd_config_redhat openssh-8.7p1/sshd_config_redhat +--- openssh-8.7p1.orig/sshd_config_redhat 2021-10-24 07:32:35.382723488 +0200 ++++ openssh-8.7p1/sshd_config_redhat 2021-10-24 07:33:38.891876779 +0200 +@@ -9,9 +9,6 @@ + + ChallengeResponseAuthentication no + +-GSSAPIAuthentication yes +-GSSAPICleanupCredentials no +- + UsePAM yes + + X11Forwarding yes +diff -Nur openssh-8.7p1.orig/ssh-gss.h openssh-8.7p1/ssh-gss.h +--- openssh-8.7p1.orig/ssh-gss.h 2021-10-24 07:32:35.415723567 +0200 ++++ openssh-8.7p1/ssh-gss.h 2021-10-24 07:33:38.891876779 +0200 +@@ -97,12 +97,14 @@ + } ssh_gssapi_ccache; + + typedef struct { ++ gss_OID_desc oid; + gss_buffer_desc displayname; + gss_buffer_desc exportedname; + gss_cred_id_t creds; +- gss_name_t name; ++ gss_name_t cred_name, ctx_name; + struct ssh_gssapi_mech_struct *mech; + ssh_gssapi_ccache store; ++ gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */ + int used; + int updated; + } ssh_gssapi_client; +@@ -123,7 +125,7 @@ + OM_uint32 minor; /* both */ + gss_ctx_id_t context; /* both */ + gss_name_t name; /* both */ +- gss_OID oid; /* client */ ++ gss_OID oid; /* both */ + gss_cred_id_t creds; /* server */ + gss_name_t client; /* server */ + gss_cred_id_t client_creds; /* both */ +@@ -161,6 +163,9 @@ + OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); + int ssh_gssapi_credentials_updated(Gssctxt *); + ++int ssh_gssapi_localname(char **name); ++void ssh_gssapi_rekey_creds(); ++ + /* In the server */ + typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, + const char *); +diff -Nur openssh-8.7p1.orig/version.h openssh-8.7p1/version.h +--- openssh-8.7p1.orig/version.h 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/version.h 2021-10-24 07:33:38.891876779 +0200 +@@ -2,5 +2,19 @@ + + #define SSH_VERSION "OpenSSH_8.7" + ++#ifdef GSI ++#define GSI_VERSION " GSI" ++#else ++#define GSI_VERSION "" ++#endif ++ ++#ifdef KRB5 ++#define KRB5_VERSION " KRB5" ++#else ++#define KRB5_VERSION "" ++#endif ++ + #define SSH_PORTABLE "p1" +-#define SSH_RELEASE SSH_VERSION SSH_PORTABLE ++#define GSI_PORTABLE "c-GSI" ++#define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ ++ GSI_VERSION KRB5_VERSION diff --git a/openssh-8.7p1-hpn-15.2-modified.patch b/openssh-8.7p1-hpn-15.2-modified.patch new file mode 100644 index 0000000..75a4908 --- /dev/null +++ b/openssh-8.7p1-hpn-15.2-modified.patch @@ -0,0 +1,2593 @@ +diff -Nur openssh-8.7p1.orig/auth2.c openssh-8.7p1/auth2.c +--- openssh-8.7p1.orig/auth2.c 2021-10-24 07:54:36.863834186 +0200 ++++ openssh-8.7p1/auth2.c 2021-10-24 07:56:04.844029990 +0200 +@@ -53,6 +53,8 @@ + #include "dispatch.h" + #include "pathnames.h" + #include "ssherr.h" ++#include "canohost.h" ++ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif +@@ -75,6 +77,8 @@ + extern Authmethod method_gssapi; + #endif + ++static int log_flag = 0; ++ + Authmethod *authmethods[] = { + &method_none, + &method_pubkey, +@@ -299,6 +303,11 @@ + + debug("userauth-request for user %s service %s method %s", + user[0] ? user : "", service, method); ++ if (!log_flag) { ++ logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), user); ++ log_flag = 1; ++ } + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + + #ifdef WITH_SELINUX +diff -Nur openssh-8.7p1.orig/channels.c openssh-8.7p1/channels.c +--- openssh-8.7p1.orig/channels.c 2021-10-24 07:54:36.849834155 +0200 ++++ openssh-8.7p1/channels.c 2021-10-24 07:56:04.845029992 +0200 +@@ -220,6 +220,9 @@ + /* Setup helper */ + static void channel_handler_init(struct ssh_channels *sc); + ++static int hpn_disabled = 0; ++static int hpn_buffer_size = 2 * 1024 * 1024; ++ + /* -- channel core */ + + void +@@ -415,6 +418,7 @@ + c->local_window = window; + c->local_window_max = window; + c->local_maxpacket = maxpack; ++ c->dynamic_window = 0; + c->remote_name = xstrdup(remote_name); + c->ctl_chan = -1; + c->delayed = 1; /* prevent call to channel_post handler */ +@@ -1108,6 +1112,28 @@ + FD_SET(c->sock, writeset); + } + ++static int ++channel_tcpwinsz(struct ssh *ssh) ++{ ++ u_int32_t tcpwinsz = 0; ++ socklen_t optsz = sizeof(tcpwinsz); ++ int ret = -1; ++ ++ /* if we aren't on a socket return 128KB */ ++ if (!ssh_packet_connection_is_on_socket(ssh)) ++ return 128 * 1024; ++ ++ ret = getsockopt(ssh_packet_get_connection_in(ssh), ++ SOL_SOCKET, SO_RCVBUF, &tcpwinsz, &optsz); ++ /* return no more than SSHBUF_SIZE_MAX (currently 256MB) */ ++ if ((ret == 0) && tcpwinsz > SSHBUF_SIZE_MAX) ++ tcpwinsz = SSHBUF_SIZE_MAX; ++ ++ debug2("tcpwinsz: tcp connection %d, Receive window: %d", ++ ssh_packet_get_connection_in(ssh), tcpwinsz); ++ return tcpwinsz; ++} ++ + static void + channel_pre_open(struct ssh *ssh, Channel *c, + fd_set *readset, fd_set *writeset) +@@ -2147,22 +2173,31 @@ + + if (c->type == SSH_CHANNEL_OPEN && + !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && +- ((c->local_window_max - c->local_window > +- c->local_maxpacket*3) || ++ ((ssh_packet_is_interactive(ssh) && ++ c->local_window_max - c->local_window > c->local_maxpacket*3) || + c->local_window < c->local_window_max/2) && + c->local_consumed > 0) { ++ u_int addition = 0; ++ u_int32_t tcpwinsz = channel_tcpwinsz(ssh); ++ /* adjust max window size if we are in a dynamic environment */ ++ if (c->dynamic_window && (tcpwinsz > c->local_window_max)) { ++ /* grow the window somewhat aggressively to maintain pressure */ ++ addition = 1.5 * (tcpwinsz - c->local_window_max); ++ c->local_window_max += addition; ++ debug("Channel: Window growth to %d by %d bytes", c->local_window_max, addition); ++ } + if (!c->have_remote_id) + fatal_f("channel %d: no remote id", c->self); + if ((r = sshpkt_start(ssh, + SSH2_MSG_CHANNEL_WINDOW_ADJUST)) != 0 || + (r = sshpkt_put_u32(ssh, c->remote_id)) != 0 || +- (r = sshpkt_put_u32(ssh, c->local_consumed)) != 0 || ++ (r = sshpkt_put_u32(ssh, c->local_consumed + addition)) != 0 || + (r = sshpkt_send(ssh)) != 0) { + fatal_fr(r, "channel %i", c->self); + } + debug2("channel %d: window %d sent adjust %d", c->self, +- c->local_window, c->local_consumed); +- c->local_window += c->local_consumed; ++ c->local_window, c->local_consumed + addition); ++ c->local_window += c->local_consumed + addition; + c->local_consumed = 0; + } + return 1; +@@ -3329,6 +3364,14 @@ + return addr; + } + ++void ++channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size) ++{ ++ hpn_disabled = external_hpn_disabled; ++ hpn_buffer_size = external_hpn_buffer_size; ++ debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size); ++} ++ + static int + channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, + struct Forward *fwd, int *allocated_listen_port, +@@ -3468,8 +3511,10 @@ + } + + /* Allocate a channel number for the socket. */ ++ /* explicitly test for hpn disabled option. if true use smaller window size */ + c = channel_new(ssh, "port listener", type, sock, sock, -1, +- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, ++ hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : hpn_buffer_size, ++ CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); + c->path = xstrdup(host); + c->host_port = fwd->connect_port; +@@ -4655,7 +4700,8 @@ + sock = socks[n]; + nc = channel_new(ssh, "x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, +- CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, ++ hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : hpn_buffer_size, ++ CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); + nc->single_connection = single_connection; + (*chanids)[n] = nc->self; +diff -Nur openssh-8.7p1.orig/channels.h openssh-8.7p1/channels.h +--- openssh-8.7p1.orig/channels.h 2021-10-24 07:54:36.785834012 +0200 ++++ openssh-8.7p1/channels.h 2021-10-24 07:56:04.846029995 +0200 +@@ -169,8 +169,10 @@ + u_int local_window_max; + u_int local_consumed; + u_int local_maxpacket; ++ int dynamic_window; + int extended_usage; + int single_connection; ++ u_int tcpwinsz; + + char *ctype; /* type */ + +@@ -232,7 +234,7 @@ + #define CHAN_LOCAL 0x10 + + /* Read buffer size */ +-#define CHAN_RBUF (16*1024) ++#define CHAN_RBUF CHAN_SES_PACKET_DEFAULT + + /* Maximum channel input buffer size */ + #define CHAN_INPUT_MAX (16*1024*1024) +@@ -363,4 +365,7 @@ + void chan_write_failed(struct ssh *, Channel *); + void chan_obuf_empty(struct ssh *, Channel *); + ++/* hpn handler */ ++void channel_set_hpn(int, int); ++ + #endif +diff -Nur openssh-8.7p1.orig/cipher.c openssh-8.7p1/cipher.c +--- openssh-8.7p1.orig/cipher.c 2021-10-24 07:54:36.828834108 +0200 ++++ openssh-8.7p1/cipher.c 2021-10-24 07:56:04.847029997 +0200 +@@ -48,6 +48,7 @@ + #include "sshbuf.h" + #include "ssherr.h" + #include "digest.h" ++#include "log.h" + + #include "openbsd-compat/openssl-compat.h" + +@@ -55,6 +56,9 @@ + #define EVP_CIPHER_CTX void + #endif + ++/* for multi-threaded aes-ctr cipher */ ++extern const EVP_CIPHER *evp_aes_ctr_mt(void); ++ + struct sshcipher_ctx { + int plaintext; + int encrypt; +@@ -64,7 +68,7 @@ + const struct sshcipher *cipher; + }; + +-static const struct sshcipher ciphers[] = { ++static struct sshcipher ciphers[] = { + #ifdef WITH_OPENSSL + #ifndef OPENSSL_NO_DES + { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, +@@ -133,6 +137,29 @@ + #endif + } + ++/* used to get the cipher name so when force rekeying to handle the ++ * single to multithreaded ctr cipher swap we only rekey when appropriate ++ */ ++const char * ++cipher_ctx_name(const struct sshcipher_ctx *cc) ++{ ++ return cc->cipher->name; ++} ++ ++/* in order to get around sandbox and forking issues with a threaded cipher ++ * we set the initial pre-auth aes-ctr cipher to the default OpenSSH cipher ++ * post auth we set them to the new evp as defined by cipher-ctr-mt ++ */ ++#ifdef WITH_OPENSSL ++void ++cipher_reset_multithreaded(void) ++{ ++ cipher_by_name("aes128-ctr")->evptype = evp_aes_ctr_mt; ++ cipher_by_name("aes192-ctr")->evptype = evp_aes_ctr_mt; ++ cipher_by_name("aes256-ctr")->evptype = evp_aes_ctr_mt; ++} ++#endif ++ + u_int + cipher_blocksize(const struct sshcipher *c) + { +@@ -182,10 +209,10 @@ + return cc->plaintext; + } + +-const struct sshcipher * ++struct sshcipher * + cipher_by_name(const char *name) + { +- const struct sshcipher *c; ++ struct sshcipher *c; + for (c = ciphers; c->name != NULL; c++) + if (strcmp(c->name, name) == 0) + return c; +@@ -207,7 +234,8 @@ + for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; + (p = strsep(&cp, CIPHER_SEP))) { + c = cipher_by_name(p); +- if (c == NULL || (c->flags & CFLAG_INTERNAL) != 0) { ++ if (c == NULL || ((c->flags & CFLAG_INTERNAL) != 0 && ++ (c->flags & CFLAG_NONE) != 0)) { + free(cipher_list); + return 0; + } +diff -Nur openssh-8.7p1.orig/cipher-ctr-mt.c openssh-8.7p1/cipher-ctr-mt.c +--- openssh-8.7p1.orig/cipher-ctr-mt.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-8.7p1/cipher-ctr-mt.c 2021-10-24 07:56:04.848029999 +0200 +@@ -0,0 +1,678 @@ ++/* ++ * OpenSSH Multi-threaded AES-CTR Cipher ++ * ++ * Author: Benjamin Bennett ++ * Author: Mike Tasota ++ * Author: Chris Rapier ++ * Copyright (c) 2008-2013 Pittsburgh Supercomputing Center. All rights reserved. ++ * ++ * Based on original OpenSSH AES-CTR cipher. Small portions remain unchanged, ++ * Copyright (c) 2003 Markus Friedl ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++#include "includes.h" ++ ++#if defined(WITH_OPENSSL) ++#include ++ ++#include ++#include ++ ++#include ++ ++#include "xmalloc.h" ++#include "log.h" ++#include ++ ++/* compatibility with old or broken OpenSSL versions */ ++#include "openbsd-compat/openssl-compat.h" ++ ++#ifndef USE_BUILTIN_RIJNDAEL ++#include ++#endif ++ ++#include ++ ++/*-------------------- TUNABLES --------------------*/ ++/* maximum number of threads and queues */ ++#define MAX_THREADS 32 ++#define MAX_NUMKQ (MAX_THREADS * 2) ++ ++/* Number of pregen threads to use */ ++int cipher_threads = 2; ++ ++/* Number of keystream queues */ ++int numkq = 4; ++ ++/* Length of a keystream queue */ ++#define KQLEN 4096 ++ ++/* Processor cacheline length */ ++#define CACHELINE_LEN 64 ++ ++/* Collect thread stats and print at cancellation when in debug mode */ ++#define CIPHER_THREAD_STATS ++ ++/* Can the system do unaligned loads natively? */ ++#if defined(__aarch64__) || \ ++ defined(__i386__) || \ ++ defined(__powerpc__) || \ ++ defined(__x86_64__) ++# define CIPHER_UNALIGNED_OK ++#endif ++#if defined(__SIZEOF_INT128__) ++# define CIPHER_INT128_OK ++#endif ++/*-------------------- END TUNABLES --------------------*/ ++ ++ ++const EVP_CIPHER *evp_aes_ctr_mt(void); ++ ++#ifdef CIPHER_THREAD_STATS ++/* ++ * Struct to collect thread stats ++ */ ++struct thread_stats { ++ u_int fills; ++ u_int skips; ++ u_int waits; ++ u_int drains; ++}; ++ ++/* ++ * Debug print the thread stats ++ * Use with pthread_cleanup_push for displaying at thread cancellation ++ */ ++static void ++thread_loop_stats(void *x) ++{ ++ struct thread_stats *s = x; ++ debug("AES-CTR MT tid %lu - %u fills, %u skips, %u waits", pthread_self(), ++ s->fills, s->skips, s->waits); ++} ++ ++# define STATS_STRUCT(s) struct thread_stats s ++# define STATS_INIT(s) { memset(&s, 0, sizeof(s)); } ++# define STATS_FILL(s) { s.fills++; } ++# define STATS_SKIP(s) { s.skips++; } ++# define STATS_WAIT(s) { s.waits++; } ++# define STATS_DRAIN(s) { s.drains++; } ++#else ++# define STATS_STRUCT(s) ++# define STATS_INIT(s) ++# define STATS_FILL(s) ++# define STATS_SKIP(s) ++# define STATS_WAIT(s) ++# define STATS_DRAIN(s) ++#endif ++ ++/* Keystream Queue state */ ++enum { ++ KQINIT, ++ KQEMPTY, ++ KQFILLING, ++ KQFULL, ++ KQDRAINING ++}; ++ ++/* Keystream Queue struct */ ++struct kq { ++ u_char keys[KQLEN][AES_BLOCK_SIZE]; ++ u_char ctr[AES_BLOCK_SIZE]; ++ u_char pad0[CACHELINE_LEN]; ++ int qstate; ++ pthread_mutex_t lock; ++ pthread_cond_t cond; ++ u_char pad1[CACHELINE_LEN]; ++}; ++ ++/* Context struct */ ++struct ssh_aes_ctr_ctx_mt ++{ ++ int struct_id; ++ struct kq q[MAX_NUMKQ]; ++ AES_KEY aes_ctx; ++ STATS_STRUCT(stats); ++ u_char aes_counter[AES_BLOCK_SIZE]; ++ pthread_t tid[MAX_THREADS]; ++ int id[MAX_THREADS]; ++ pthread_rwlock_t tid_lock; ++#ifdef __APPLE__ ++ pthread_rwlock_t stop_lock; ++ int exit_flag; ++#endif /* __APPLE__ */ ++ int state; ++ int qidx; ++ int ridx; ++}; ++ ++/* ++ * increment counter 'ctr', ++ * the counter is of size 'len' bytes and stored in network-byte-order. ++ * (LSB at ctr[len-1], MSB at ctr[0]) ++ */ ++static void ++ssh_ctr_inc(u_char *ctr, size_t len) ++{ ++ int i; ++ ++ for (i = len - 1; i >= 0; i--) ++ if (++ctr[i]) /* continue on overflow */ ++ return; ++} ++ ++/* ++ * Add num to counter 'ctr' ++ */ ++static void ++ssh_ctr_add(u_char *ctr, uint32_t num, u_int len) ++{ ++ int i; ++ uint16_t n; ++ ++ for (n = 0, i = len - 1; i >= 0 && (num || n); i--) { ++ n = ctr[i] + (num & 0xff) + n; ++ num >>= 8; ++ ctr[i] = n & 0xff; ++ n >>= 8; ++ } ++} ++ ++/* ++ * Threads may be cancelled in a pthread_cond_wait, we must free the mutex ++ */ ++static void ++thread_loop_cleanup(void *x) ++{ ++ pthread_mutex_unlock((pthread_mutex_t *)x); ++} ++ ++#ifdef __APPLE__ ++/* Check if we should exit, we are doing both cancel and exit condition ++ * since on OSX threads seem to occasionally fail to notice when they have ++ * been cancelled. We want to have a backup to make sure that we won't hang ++ * when the main process join()-s the cancelled thread. ++ */ ++static void ++thread_loop_check_exit(struct ssh_aes_ctr_ctx_mt *c) ++{ ++ int exit_flag; ++ ++ pthread_rwlock_rdlock(&c->stop_lock); ++ exit_flag = c->exit_flag; ++ pthread_rwlock_unlock(&c->stop_lock); ++ ++ if (exit_flag) ++ pthread_exit(NULL); ++} ++#else ++# define thread_loop_check_exit(s) ++#endif /* __APPLE__ */ ++ ++/* ++ * Helper function to terminate the helper threads ++ */ ++static void ++stop_and_join_pregen_threads(struct ssh_aes_ctr_ctx_mt *c) ++{ ++ int i; ++ ++#ifdef __APPLE__ ++ /* notify threads that they should exit */ ++ pthread_rwlock_wrlock(&c->stop_lock); ++ c->exit_flag = TRUE; ++ pthread_rwlock_unlock(&c->stop_lock); ++#endif /* __APPLE__ */ ++ ++ /* Cancel pregen threads */ ++ for (i = 0; i < cipher_threads; i++) { ++ debug ("Canceled %lu (%d,%d)", c->tid[i], c->struct_id, c->id[i]); ++ pthread_cancel(c->tid[i]); ++ } ++ /* shouldn't need this - see commit logs for hpn-7_7_P1 -cjr 11/7/19*/ ++ /* for (i = 0; i < numkq; i++) { */ ++ /* pthread_mutex_lock(&c->q[i].lock); */ ++ /* pthread_cond_broadcast(&c->q[i].cond); */ ++ /* pthread_mutex_unlock(&c->q[i].lock); */ ++ /* } */ ++ for (i = 0; i < cipher_threads; i++) { ++ if (pthread_kill(c->tid[i], 0) != 0) ++ debug3("AES-CTR MT pthread_join failure: Invalid thread id %lu in %s", c->tid[i], __FUNCTION__); ++ else { ++ debug ("Joining %lu (%d, %d)", c->tid[i], c->struct_id, c->id[i]); ++ pthread_join(c->tid[i], NULL); ++ } ++ } ++} ++ ++/* ++ * The life of a pregen thread: ++ * Find empty keystream queues and fill them using their counter. ++ * When done, update counter for the next fill. ++ */ ++static void * ++thread_loop(void *x) ++{ ++ AES_KEY key; ++ STATS_STRUCT(stats); ++ struct ssh_aes_ctr_ctx_mt *c = x; ++ struct kq *q; ++ int i; ++ int qidx; ++ pthread_t first_tid; ++ ++ /* Threads stats on cancellation */ ++ STATS_INIT(stats); ++#ifdef CIPHER_THREAD_STATS ++ pthread_cleanup_push(thread_loop_stats, &stats); ++#endif ++ ++ /* Thread local copy of AES key */ ++ memcpy(&key, &c->aes_ctx, sizeof(key)); ++ ++ pthread_rwlock_rdlock(&c->tid_lock); ++ first_tid = c->tid[0]; ++ pthread_rwlock_unlock(&c->tid_lock); ++ ++ /* ++ * Handle the special case of startup, one thread must fill ++ * the first KQ then mark it as draining. Lock held throughout. ++ */ ++ if (pthread_equal(pthread_self(), first_tid)) { ++ q = &c->q[0]; ++ pthread_mutex_lock(&q->lock); ++ if (q->qstate == KQINIT) { ++ for (i = 0; i < KQLEN; i++) { ++ AES_encrypt(q->ctr, q->keys[i], &key); ++ ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); ++ } ++ ssh_ctr_add(q->ctr, KQLEN * (numkq - 1), AES_BLOCK_SIZE); ++ q->qstate = KQDRAINING; ++ STATS_FILL(stats); ++ pthread_cond_broadcast(&q->cond); ++ } ++ pthread_mutex_unlock(&q->lock); ++ } else ++ STATS_SKIP(stats); ++ ++ /* ++ * Normal case is to find empty queues and fill them, skipping over ++ * queues already filled by other threads and stopping to wait for ++ * a draining queue to become empty. ++ * ++ * Multiple threads may be waiting on a draining queue and awoken ++ * when empty. The first thread to wake will mark it as filling, ++ * others will move on to fill, skip, or wait on the next queue. ++ */ ++ for (qidx = 1;; qidx = (qidx + 1) % numkq) { ++ /* Check if I was cancelled, also checked in cond_wait */ ++ pthread_testcancel(); ++ ++ /* Check if we should exit as well */ ++ thread_loop_check_exit(c); ++ ++ /* Lock queue and block if its draining */ ++ q = &c->q[qidx]; ++ pthread_mutex_lock(&q->lock); ++ pthread_cleanup_push(thread_loop_cleanup, &q->lock); ++ while (q->qstate == KQDRAINING || q->qstate == KQINIT) { ++ STATS_WAIT(stats); ++ thread_loop_check_exit(c); ++ pthread_cond_wait(&q->cond, &q->lock); ++ } ++ pthread_cleanup_pop(0); ++ ++ /* If filling or full, somebody else got it, skip */ ++ if (q->qstate != KQEMPTY) { ++ pthread_mutex_unlock(&q->lock); ++ STATS_SKIP(stats); ++ continue; ++ } ++ ++ /* ++ * Empty, let's fill it. ++ * Queue lock is relinquished while we do this so others ++ * can see that it's being filled. ++ */ ++ q->qstate = KQFILLING; ++ pthread_cond_broadcast(&q->cond); ++ pthread_mutex_unlock(&q->lock); ++ for (i = 0; i < KQLEN; i++) { ++ AES_encrypt(q->ctr, q->keys[i], &key); ++ ssh_ctr_inc(q->ctr, AES_BLOCK_SIZE); ++ } ++ ++ /* Re-lock, mark full and signal consumer */ ++ pthread_mutex_lock(&q->lock); ++ ssh_ctr_add(q->ctr, KQLEN * (numkq - 1), AES_BLOCK_SIZE); ++ q->qstate = KQFULL; ++ STATS_FILL(stats); ++ pthread_cond_broadcast(&q->cond); ++ pthread_mutex_unlock(&q->lock); ++ } ++ ++#ifdef CIPHER_THREAD_STATS ++ /* Stats */ ++ pthread_cleanup_pop(1); ++#endif ++ ++ return NULL; ++} ++ ++static int ++ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, ++ LIBCRYPTO_EVP_INL_TYPE len) ++{ ++ typedef union { ++#ifdef CIPHER_INT128_OK ++ __uint128_t *u128; ++#endif ++ uint64_t *u64; ++ uint32_t *u32; ++ uint8_t *u8; ++ const uint8_t *cu8; ++ uintptr_t u; ++ } ptrs_t; ++ ptrs_t destp, srcp, bufp; ++ uintptr_t align; ++ struct ssh_aes_ctr_ctx_mt *c; ++ struct kq *q, *oldq; ++ int ridx; ++ u_char *buf; ++ ++ if (len == 0) ++ return 1; ++ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) ++ return 0; ++ ++ q = &c->q[c->qidx]; ++ ridx = c->ridx; ++ ++ /* src already padded to block multiple */ ++ srcp.cu8 = src; ++ destp.u8 = dest; ++ while (len > 0) { ++ buf = q->keys[ridx]; ++ bufp.u8 = buf; ++ ++ /* figure out the alignment on the fly */ ++#ifdef CIPHER_UNALIGNED_OK ++ align = 0; ++#else ++ align = destp.u | srcp.u | bufp.u; ++#endif ++ ++#ifdef CIPHER_INT128_OK ++ if ((align & 0xf) == 0) { ++ destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; ++ } else ++#endif ++ if ((align & 0x7) == 0) { ++ destp.u64[0] = srcp.u64[0] ^ bufp.u64[0]; ++ destp.u64[1] = srcp.u64[1] ^ bufp.u64[1]; ++ } else if ((align & 0x3) == 0) { ++ destp.u32[0] = srcp.u32[0] ^ bufp.u32[0]; ++ destp.u32[1] = srcp.u32[1] ^ bufp.u32[1]; ++ destp.u32[2] = srcp.u32[2] ^ bufp.u32[2]; ++ destp.u32[3] = srcp.u32[3] ^ bufp.u32[3]; ++ } else { ++ size_t i; ++ for (i = 0; i < AES_BLOCK_SIZE; ++i) ++ dest[i] = src[i] ^ buf[i]; ++ } ++ ++ destp.u += AES_BLOCK_SIZE; ++ srcp.u += AES_BLOCK_SIZE; ++ len -= AES_BLOCK_SIZE; ++ ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); ++ ++ /* Increment read index, switch queues on rollover */ ++ if ((ridx = (ridx + 1) % KQLEN) == 0) { ++ oldq = q; ++ ++ /* Mark next queue draining, may need to wait */ ++ c->qidx = (c->qidx + 1) % numkq; ++ q = &c->q[c->qidx]; ++ pthread_mutex_lock(&q->lock); ++ while (q->qstate != KQFULL) { ++ STATS_WAIT(c->stats); ++ pthread_cond_wait(&q->cond, &q->lock); ++ } ++ q->qstate = KQDRAINING; ++ pthread_cond_broadcast(&q->cond); ++ pthread_mutex_unlock(&q->lock); ++ ++ /* Mark consumed queue empty and signal producers */ ++ pthread_mutex_lock(&oldq->lock); ++ oldq->qstate = KQEMPTY; ++ STATS_DRAIN(c->stats); ++ pthread_cond_broadcast(&oldq->cond); ++ pthread_mutex_unlock(&oldq->lock); ++ } ++ } ++ c->ridx = ridx; ++ return 1; ++} ++ ++#define HAVE_NONE 0 ++#define HAVE_KEY 1 ++#define HAVE_IV 2 ++ ++int X = 0; ++ ++static int ++ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, ++ int enc) ++{ ++ struct ssh_aes_ctr_ctx_mt *c; ++ int i; ++ ++ /* get the number of cores in the system */ ++ /* if it's not linux it currently defaults to 2 */ ++ /* divide by 2 to get threads for each direction (MODE_IN||MODE_OUT) */ ++#ifdef __linux__ ++ cipher_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2; ++#endif /*__linux__*/ ++#ifdef __APPLE__ ++ cipher_threads = sysconf(_SC_NPROCESSORS_ONLN) / 2; ++#endif /*__APPLE__*/ ++#ifdef __FREEBSD__ ++ int req[2]; ++ size_t len; ++ ++ req[0] = CTL_HW; ++ req[1] = HW_NCPU; ++ ++ len = sizeof(ncpu); ++ sysctl(req, 2, &cipher_threads, &len, NULL, 0); ++ cipher_threads = cipher_threads / 2; ++#endif /*__FREEBSD__*/ ++ ++ /* if they have less than 4 cores spin up 4 threads anyway */ ++ if (cipher_threads < 2) ++ cipher_threads = 2; ++ ++ /* assure that we aren't trying to create more threads */ ++ /* than we have in the struct. cipher_threads is half the */ ++ /* total of allowable threads hence the odd looking math here */ ++ if (cipher_threads * 2 > MAX_THREADS) ++ cipher_threads = MAX_THREADS / 2; ++ ++ /* set the number of keystream queues */ ++ numkq = cipher_threads * 2; ++ ++ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { ++ c = xmalloc(sizeof(*c)); ++ pthread_rwlock_init(&c->tid_lock, NULL); ++#ifdef __APPLE__ ++ pthread_rwlock_init(&c->stop_lock, NULL); ++ c->exit_flag = FALSE; ++#endif /* __APPLE__ */ ++ ++ c->state = HAVE_NONE; ++ for (i = 0; i < numkq; i++) { ++ pthread_mutex_init(&c->q[i].lock, NULL); ++ pthread_cond_init(&c->q[i].cond, NULL); ++ } ++ ++ STATS_INIT(c->stats); ++ EVP_CIPHER_CTX_set_app_data(ctx, c); ++ } ++ ++ if (c->state == (HAVE_KEY | HAVE_IV)) { ++ /* tell the pregen threads to exit */ ++ stop_and_join_pregen_threads(c); ++ ++#ifdef __APPLE__ ++ /* reset the exit flag */ ++ c->exit_flag = FALSE; ++#endif /* __APPLE__ */ ++ ++ /* Start over getting key & iv */ ++ c->state = HAVE_NONE; ++ } ++ ++ if (key != NULL) { ++ AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, ++ &c->aes_ctx); ++ c->state |= HAVE_KEY; ++ } ++ ++ if (iv != NULL) { ++ memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); ++ c->state |= HAVE_IV; ++ } ++ ++ if (c->state == (HAVE_KEY | HAVE_IV)) { ++ /* Clear queues */ ++ memcpy(c->q[0].ctr, c->aes_counter, AES_BLOCK_SIZE); ++ c->q[0].qstate = KQINIT; ++ for (i = 1; i < numkq; i++) { ++ memcpy(c->q[i].ctr, c->aes_counter, AES_BLOCK_SIZE); ++ ssh_ctr_add(c->q[i].ctr, i * KQLEN, AES_BLOCK_SIZE); ++ c->q[i].qstate = KQEMPTY; ++ } ++ c->qidx = 0; ++ c->ridx = 0; ++ ++ /* Start threads */ ++ for (i = 0; i < cipher_threads; i++) { ++ pthread_rwlock_wrlock(&c->tid_lock); ++ if (pthread_create(&c->tid[i], NULL, thread_loop, c) != 0) ++ debug ("AES-CTR MT Could not create thread in %s", __FUNCTION__); /*should die here */ ++ else { ++ if (!c->struct_id) ++ c->struct_id = X++; ++ c->id[i] = i; ++ debug ("AES-CTR MT spawned a thread with id %lu in %s (%d, %d)", c->tid[i], __FUNCTION__, c->struct_id, c->id[i]); ++ } ++ pthread_rwlock_unlock(&c->tid_lock); ++ } ++ pthread_mutex_lock(&c->q[0].lock); ++ while (c->q[0].qstate == KQINIT) ++ pthread_cond_wait(&c->q[0].cond, &c->q[0].lock); ++ pthread_mutex_unlock(&c->q[0].lock); ++ } ++ return 1; ++} ++ ++/* this function is no longer used but might prove handy in the future ++ * this comment also applies to ssh_aes_ctr_thread_reconstruction ++ */ ++void ++ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx) ++{ ++ struct ssh_aes_ctr_ctx_mt *c; ++ ++ c = EVP_CIPHER_CTX_get_app_data(ctx); ++ stop_and_join_pregen_threads(c); ++} ++ ++void ++ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx) ++{ ++ struct ssh_aes_ctr_ctx_mt *c; ++ int i; ++ c = EVP_CIPHER_CTX_get_app_data(ctx); ++ /* reconstruct threads */ ++ for (i = 0; i < cipher_threads; i++) { ++ pthread_rwlock_wrlock(&c->tid_lock); ++ if (pthread_create(&c->tid[i], NULL, thread_loop, c) !=0 ) ++ debug("AES-CTR MT could not create thread in %s", __FUNCTION__); ++ else { ++ c->struct_id = X++; ++ c->id[i] = i; ++ debug ("AES-CTR MT spawned a thread with id %lu in %s (%d, %d)", c->tid[i], __FUNCTION__, c->struct_id, c->id[i]); ++ debug("AES-CTR MT spawned a thread with id %lu in %s", c->tid[i], __FUNCTION__); ++ } ++ pthread_rwlock_unlock(&c->tid_lock); ++ } ++} ++ ++static int ++ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) ++{ ++ struct ssh_aes_ctr_ctx_mt *c; ++ ++ if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { ++#ifdef CIPHER_THREAD_STATS ++ debug("AES-CTR MT main thread: %u drains, %u waits", c->stats.drains, ++ c->stats.waits); ++#endif ++ stop_and_join_pregen_threads(c); ++ ++ memset(c, 0, sizeof(*c)); ++ free(c); ++ EVP_CIPHER_CTX_set_app_data(ctx, NULL); ++ } ++ return 1; ++} ++ ++/* */ ++const EVP_CIPHER * ++evp_aes_ctr_mt(void) ++{ ++# if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++ static EVP_CIPHER *aes_ctr; ++ aes_ctr = EVP_CIPHER_meth_new(NID_undef, 16/*block*/, 16/*key*/); ++ EVP_CIPHER_meth_set_iv_length(aes_ctr, AES_BLOCK_SIZE); ++ EVP_CIPHER_meth_set_init(aes_ctr, ssh_aes_ctr_init); ++ EVP_CIPHER_meth_set_cleanup(aes_ctr, ssh_aes_ctr_cleanup); ++ EVP_CIPHER_meth_set_do_cipher(aes_ctr, ssh_aes_ctr); ++# ifndef SSH_OLD_EVP ++ EVP_CIPHER_meth_set_flags(aes_ctr, EVP_CIPH_CBC_MODE ++ | EVP_CIPH_VARIABLE_LENGTH ++ | EVP_CIPH_ALWAYS_CALL_INIT ++ | EVP_CIPH_CUSTOM_IV); ++# endif /*SSH_OLD_EVP*/ ++ return (aes_ctr); ++# else /*earlier versions of openssl*/ ++ static EVP_CIPHER aes_ctr; ++ memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); ++ aes_ctr.nid = NID_undef; ++ aes_ctr.block_size = AES_BLOCK_SIZE; ++ aes_ctr.iv_len = AES_BLOCK_SIZE; ++ aes_ctr.key_len = 16; ++ aes_ctr.init = ssh_aes_ctr_init; ++ aes_ctr.cleanup = ssh_aes_ctr_cleanup; ++ aes_ctr.do_cipher = ssh_aes_ctr; ++# ifndef SSH_OLD_EVP ++ aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | ++ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; ++# endif /*SSH_OLD_EVP*/ ++ return &aes_ctr; ++# endif /*OPENSSH_VERSION_NUMBER*/ ++} ++ ++#endif /* defined(WITH_OPENSSL) */ +diff -Nur openssh-8.7p1.orig/cipher.h openssh-8.7p1/cipher.h +--- openssh-8.7p1.orig/cipher.h 2021-10-24 07:54:36.829834110 +0200 ++++ openssh-8.7p1/cipher.h 2021-10-24 07:56:04.848029999 +0200 +@@ -68,7 +68,9 @@ + + struct sshcipher_ctx; + +-const struct sshcipher *cipher_by_name(const char *); ++void ssh_aes_ctr_thread_destroy(EVP_CIPHER_CTX *ctx); // defined in cipher-ctr-mt.c ++void ssh_aes_ctr_thread_reconstruction(EVP_CIPHER_CTX *ctx); ++struct sshcipher *cipher_by_name(const char *); + const char *cipher_warning_message(const struct sshcipher_ctx *); + int ciphers_valid(const char *); + char *cipher_alg_list(char, int); +@@ -86,6 +88,8 @@ + u_int cipher_authlen(const struct sshcipher *); + u_int cipher_ivlen(const struct sshcipher *); + u_int cipher_is_cbc(const struct sshcipher *); ++void cipher_reset_multithreaded(void); ++const char *cipher_ctx_name(const struct sshcipher_ctx *); + + u_int cipher_ctx_is_plaintext(struct sshcipher_ctx *); + +diff -Nur openssh-8.7p1.orig/clientloop.c openssh-8.7p1/clientloop.c +--- openssh-8.7p1.orig/clientloop.c 2021-10-24 07:54:36.738833908 +0200 ++++ openssh-8.7p1/clientloop.c 2021-10-24 07:56:04.849030001 +0200 +@@ -1582,7 +1582,9 @@ + return NULL; + c = channel_new(ssh, "x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, +- CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); ++ /* again is this really necessary for X11? */ ++ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, ++ CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); + c->force_drain = 1; + return c; + } +@@ -1611,7 +1613,8 @@ + } + c = channel_new(ssh, "authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, +- CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, ++ options.hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : options.hpn_buffer_size, ++ CHAN_TCP_PACKET_DEFAULT, 0, + "authentication agent connection", 1); + c->force_drain = 1; + return c; +@@ -1638,7 +1641,8 @@ + debug("Tunnel forwarding using interface %s", ifname); + + c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, +- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); ++ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, ++ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + c->datagram = 1; + + #if defined(SSH_TUN_FILTER) +diff -Nur openssh-8.7p1.orig/compat.c openssh-8.7p1/compat.c +--- openssh-8.7p1.orig/compat.c 2021-10-24 07:54:36.849834155 +0200 ++++ openssh-8.7p1/compat.c 2021-10-24 07:56:04.850030003 +0200 +@@ -151,6 +151,17 @@ + debug_f("match: %s pat %s compat 0x%08x", + version, check[i].pat, check[i].bugs); + ssh->compat = check[i].bugs; ++ /* Check to see if the remote side is OpenSSH and not HPN */ ++ /* TODO: See if we can work this into the new method for bug checks */ ++ if (strstr(version, "OpenSSH") != NULL) { ++ if (strstr(version, "hpn") == NULL) { ++ ssh->compat |= SSH_BUG_LARGEWINDOW; ++ debug("Remote is NOT HPN enabled"); ++ } else { ++ debug("Remote is HPN Enabled"); ++ } ++ } ++ debug("ssh->compat is %u", ssh->compat); + return; + } + } +diff -Nur openssh-8.7p1.orig/compat.h openssh-8.7p1/compat.h +--- openssh-8.7p1.orig/compat.h 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/compat.h 2021-10-24 07:56:04.850030003 +0200 +@@ -57,6 +57,7 @@ + #define SSH_BUG_CURVE25519PAD 0x10000000 + #define SSH_BUG_HOSTKEYS 0x20000000 + #define SSH_BUG_DHGEX_LARGE 0x40000000 ++#define SSH_BUG_LARGEWINDOW 0x80000000 + + struct ssh; + +diff -Nur openssh-8.7p1.orig/defines.h openssh-8.7p1/defines.h +--- openssh-8.7p1.orig/defines.h 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/defines.h 2021-10-24 07:56:04.851030005 +0200 +@@ -854,7 +854,7 @@ + #endif + + #ifndef SSH_IOBUFSZ +-# define SSH_IOBUFSZ 8192 ++# define SSH_IOBUFSZ 32*1024 + #endif + + /* +diff -Nur openssh-8.7p1.orig/digest.h openssh-8.7p1/digest.h +--- openssh-8.7p1.orig/digest.h 2021-10-24 07:54:36.811834070 +0200 ++++ openssh-8.7p1/digest.h 2021-10-24 07:56:04.852030007 +0200 +@@ -27,7 +27,8 @@ + #define SSH_DIGEST_SHA256 2 + #define SSH_DIGEST_SHA384 3 + #define SSH_DIGEST_SHA512 4 +-#define SSH_DIGEST_MAX 5 ++#define SSH_DIGEST_NULL 5 ++#define SSH_DIGEST_MAX 6 + + struct sshbuf; + struct ssh_digest_ctx; +diff -Nur openssh-8.7p1.orig/digest-openssl.c openssh-8.7p1/digest-openssl.c +--- openssh-8.7p1.orig/digest-openssl.c 2021-10-24 07:54:36.810834068 +0200 ++++ openssh-8.7p1/digest-openssl.c 2021-10-24 07:56:04.852030007 +0200 +@@ -61,6 +61,7 @@ + { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, + { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, + { SSH_DIGEST_SHA512, "SHA512", 64, EVP_sha512 }, ++ { SSH_DIGEST_NULL, "NONEMAC", 0, EVP_md_null}, + { -1, NULL, 0, NULL }, + }; + +diff -Nur openssh-8.7p1.orig/HPN-README openssh-8.7p1/HPN-README +--- openssh-8.7p1.orig/HPN-README 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-8.7p1/HPN-README 2021-10-24 07:56:04.852030007 +0200 +@@ -0,0 +1,153 @@ ++Notes: ++ ++MULTI-THREADED CIPHER: ++The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations ++on hosts with multiple cores to use more than one processing core during encryption. ++Tests have show significant throughput performance increases when using MTR-AES-CTR up ++to and including a full gigabit per second on quad core systems. It should be possible to ++achieve full line rate on dual core systems but OS and data management overhead makes this ++more difficult to achieve. The cipher stream from MTR-AES-CTR is entirely compatible with single ++thread AES-CTR (ST-AES-CTR) implementations and should be 100% backward compatible. Optimal ++performance requires the MTR-AES-CTR mode be enabled on both ends of the connection. ++The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same ++nomenclature. ++Use examples: ++ ssh -caes128-ctr you@host.com ++ scp -oCipher=aes256-ctr file you@host.com:~/file ++ ++NONE CIPHER: ++To use the NONE option you must have the NoneEnabled switch set on the server and ++you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE ++feature works with ALL ssh subsystems (as far as we can tell) *AS LONG AS* a tty is not ++spawned. If a user uses the -T switch to prevent a tty being created the NONE cipher will ++be disabled. ++ ++The performance increase will only be as good as the network and TCP stack tuning ++on the reciever side of the connection allows. As a rule of thumb a user will need ++at least 10Mb/s connection with a 100ms RTT to see a doubling of performance. The ++HPN-SSH home page describes this in greater detail. ++ ++http://www.psc.edu/networking/projects/hpn-ssh ++ ++NONE MAC: ++Starting with HPN 15v1 users will have the option to disable HMAC (message ++authentication ciphers) when using the NONE cipher. You must enable the following: ++NoneEnabled, NoneSwitch, and NoneMacEnabled. If all three are not enabled the None MAC ++will be automatically disabled. In tests the use of the None MAC improved throuput by ++more than 30%. ++ ++ex: scp -oNoneSwitch=yes -oNoneEnabled=yes -oNoneMacEnabled=yes file host:~ ++ ++BUFFER SIZES: ++ ++If HPN is disabled the receive buffer size will be set to the ++OpenSSH default of 2MB (for OpenSSH versions before 4.7: 64KB). ++ ++If an HPN system connects to a nonHPN system the receive buffer will ++be set to the HPNBufferSize value. The default is 2MB but user adjustable. ++ ++If an HPN to HPN connection is established a number of different things might ++happen based on the user options and conditions. ++ ++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set ++HPN Buffer Size = up to 64MB ++This is the default state. The HPN buffer size will grow to a maximum of 64MB ++as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is ++geared towards 10GigE transcontinental connections. ++ ++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set ++HPN Buffer Size = TCP receive buffer value. ++Users on non-autotuning systems should disable TCPRcvBufPoll in the ++ssh_config and sshd_config ++ ++Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set ++HPN Buffer Size = minimum of TCP receive buffer and HPNBufferSize. ++This would be the system defined TCP receive buffer (RWIN). ++ ++Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET ++HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. ++Generally there is no need to set both. ++ ++Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set ++HPN Buffer Size = grows to HPNBufferSize ++The buffer will grow up to the maximum size specified here. ++ ++Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET ++HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. ++Generally there is no need to set both of these, especially on autotuning ++systems. However, if the users wishes to override the autotuning this would be ++one way to do it. ++ ++Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET ++HPN Buffer Size = TCPRcvBuf. ++This will override autotuning and set the TCP recieve buffer to the user defined ++value. ++ ++ ++HPN Specific Configuration options ++ ++TcpRcvBuf=[int]KB client ++ Set the TCP socket receive buffer to n Kilobytes. It can be set up to the ++maximum socket size allowed by the system. This is useful in situations where ++the tcp receive window is set low but the maximum buffer size is set ++higher (as is typical). This works on a per TCP connection basis. You can also ++use this to artifically limit the transfer rate of the connection. In these ++cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. ++Default is the current system wide tcp receive buffer size. ++ ++TcpRcvBufPoll=[yes/no] client/server ++ Enable of disable the polling of the tcp receive buffer through the life ++of the connection. You would want to make sure that this option is enabled ++for systems making use of autotuning kernels (linux 2.4.24+, 2.6, MS Vista) ++default is yes. ++ ++NoneEnabled=[yes/no] client/server ++ Enable or disable the use of the None cipher. Care must always be used ++when enabling this as it will allow users to send data in the clear. However, ++it is important to note that authentication information remains encrypted ++even if this option is enabled. Set to no by default. ++ ++NoneMacEnabled=[yes/no] client/server ++ Enable or disable the use of the None MAC. When this is enabled ssh ++will *not* provide data integrity of any data being transmitted between hosts. Use ++with caution as it, unlike just using NoneEnabled, doesn't provide data integrity and ++protection against man-in-the-middle attacks. As with NoneEnabled all authentication ++remains encrypted and integrity is ensured. Default is no. ++ ++NoneSwitch=[yes/no] client ++ Switch the encryption cipher being used to the None cipher after ++authentication takes place. NoneEnabled must be enabled on both the client ++and server side of the connection. When the connection switches to the NONE ++cipher a warning is sent to STDERR. The connection attempt will fail with an ++error if a client requests a NoneSwitch from the server that does not explicitly ++have NoneEnabled set to yes. Note: The NONE cipher cannot be used in ++interactive (shell) sessions and it will fail silently. Set to no by default. ++ ++HPNDisabled=[yes/no] client/server ++ In some situations, such as transfers on a local area network, the impact ++of the HPN code produces a net decrease in performance. In these cases it is ++helpful to disable the HPN functionality. By default HPNDisabled is set to no. ++ ++HPNBufferSize=[int]KB client/server ++ This is the default buffer size the HPN functionality uses when interacting ++with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf ++option as applied to the internal SSH flow control. This value can range from ++1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance ++problems depending on the length of the network path. The default size of this buffer ++is 2MB. ++ ++DisableMTAES=[yes/no] client/server ++ Switch the encryption cipher being used from the multithreaded MT-AES-CTR cipher ++back to the stock single-threaded AES-CTR cipher. Useful on modern processors with ++AES-NI instructions which make the stock single-threaded AES-CTR cipher faster than ++the multithreaded MT-AES-CTR cipher. Set to no by default. ++ ++ ++Credits: This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) ++ The majority of the actual coding for versions up to HPN12v1 was performed ++ by Michael Stevens (mstevens@andrew.cmu.edu). The MT-AES-CTR cipher was ++ implemented by Ben Bennet (ben@psc.edu) and improved by Mike Tasota ++ (tasota@gmail.com) an NSF REU grant recipient for 2013. ++ Allan Jude provided the code for the NoneMac and buffer normalization. ++ This work was financed, in part, by Cisco System, Inc., the National ++ Library of Medicine, and the National Science Foundation. +diff -Nur openssh-8.7p1.orig/kex.c openssh-8.7p1/kex.c +--- openssh-8.7p1.orig/kex.c 2021-10-24 07:54:36.841834137 +0200 ++++ openssh-8.7p1/kex.c 2021-10-24 07:56:04.853030010 +0200 +@@ -64,6 +64,7 @@ + + #include "ssherr.h" + #include "sshbuf.h" ++#include "canohost.h" + #include "digest.h" + #include "audit.h" + +@@ -969,6 +970,11 @@ + int nenc, nmac, ncomp; + u_int mode, ctos, need, dh_need, authlen; + int r, first_kex_follows; ++ int auth_flag = 0; ++ int log_flag = 0; ++ ++ auth_flag = packet_authentication_state(ssh); ++ debug("AUTH STATE IS %d", auth_flag); + + debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); + if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) +@@ -1039,11 +1045,40 @@ + peer[ncomp] = NULL; + goto out; + } ++ debug("REQUESTED ENC.NAME is '%s'", newkeys->enc.name); ++ debug("REQUESTED MAC.NAME is '%s'", newkeys->mac.name); ++ if (strcmp(newkeys->enc.name, "none") == 0) { ++ if (auth_flag == 1) { ++ debug("None requested post authentication."); ++ ssh->none = 1; ++ } ++ else ++ fatal("Pre-authentication none cipher requests are not allowed."); ++ if (newkeys->mac.name != NULL && strcmp(newkeys->mac.name, "none") == 0) ++ debug("Requesting: NONEMAC. Authflag is %d", auth_flag); ++ } ++ + debug("kex: %s cipher: %s MAC: %s compression: %s", + ctos ? "client->server" : "server->client", + newkeys->enc.name, + authlen == 0 ? newkeys->mac.name : "", + newkeys->comp.name); ++ /* ++ * client starts with ctos = 0 && log flag = 0 and no log. ++ * 2nd client pass ctos = 1 and flag = 1 so no log. ++ * server starts with ctos = 1 && log_flag = 0 so log. ++ * 2nd sever pass ctos = 1 && log flag = 1 so no log. ++ * -cjr ++ */ ++ if (ctos && !log_flag) { ++ logit("SSH: Server;Ltype: Kex;Remote: %s-%d;Enc: %s;MAC: %s;Comp: %s", ++ ssh_remote_ipaddr(ssh), ++ ssh_remote_port(ssh), ++ newkeys->enc.name, ++ authlen == 0 ? newkeys->mac.name : "", ++ newkeys->comp.name); ++ } ++ log_flag = 1; + } + need = dh_need = 0; + for (mode = 0; mode < MODE_MAX; mode++) { +@@ -1391,7 +1426,7 @@ + if (version_addendum != NULL && *version_addendum == '\0') + version_addendum = NULL; + if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n", +- PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, ++ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE, + version_addendum == NULL ? "" : " ", + version_addendum == NULL ? "" : version_addendum)) != 0) { + oerrno = errno; +@@ -1527,6 +1562,14 @@ + r = SSH_ERR_INVALID_FORMAT; + goto out; + } ++ ++ /* report the version information to syslog if this is the server */ ++ if (timeout_ms == -1) { /* only the server uses this value */ ++ logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ++ remote_major, remote_minor, remote_version); ++ } ++ + debug("Remote protocol version %d.%d, remote software version %.100s", + remote_major, remote_minor, remote_version); + compat_banner(ssh, remote_version); +diff -Nur openssh-8.7p1.orig/log.c openssh-8.7p1/log.c +--- openssh-8.7p1.orig/log.c 2021-10-24 07:54:36.769833977 +0200 ++++ openssh-8.7p1/log.c 2021-10-24 07:56:04.853030010 +0200 +@@ -46,6 +46,11 @@ + #include + #include + #include ++#include "packet.h" /* needed for host and port look ups */ ++#ifdef HAVE_SYS_TIME_H ++# include /* to get current time */ ++#endif ++ + #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) + # include + #endif +@@ -65,6 +70,8 @@ + + extern char *__progname; + ++extern struct ssh *active_state; ++ + #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) + #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) + +diff -Nur openssh-8.7p1.orig/mac.c openssh-8.7p1/mac.c +--- openssh-8.7p1.orig/mac.c 2021-10-24 07:54:36.830834112 +0200 ++++ openssh-8.7p1/mac.c 2021-10-24 07:56:04.854030012 +0200 +@@ -63,6 +63,7 @@ + { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, + { "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 }, + { "hmac-md5-96", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 0 }, ++ { "none", SSH_DIGEST, SSH_DIGEST_NULL, 0, 0, 0, 0 }, + { "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 }, + { "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 }, + +diff -Nur openssh-8.7p1.orig/Makefile.in openssh-8.7p1/Makefile.in +--- openssh-8.7p1.orig/Makefile.in 2021-10-24 07:54:36.867834195 +0200 ++++ openssh-8.7p1/Makefile.in 2021-10-24 07:56:04.854030012 +0200 +@@ -48,7 +48,7 @@ + CFLAGS_NOPIE=@CFLAGS_NOPIE@ + CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ + PICFLAG=@PICFLAG@ +-LIBS=@LIBS@ ++LIBS=@LIBS@ -lpthread + K5LIBS=@K5LIBS@ + GSSLIBS=@GSSLIBS@ + SSHDLIBS=@SSHDLIBS@ +@@ -95,7 +95,7 @@ + LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + authfd.o authfile.o \ + canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \ +- cipher-ctr.o cleanup.o \ ++ cipher-ctr.o cleanup.o cipher-ctr-mt.o \ + compat.o fatal.o hostfile.o \ + log.o match.o moduli.o nchan.o packet.o \ + readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \ +diff -Nur openssh-8.7p1.orig/packet.c openssh-8.7p1/packet.c +--- openssh-8.7p1.orig/packet.c 2021-10-24 07:54:36.832834117 +0200 ++++ openssh-8.7p1/packet.c 2021-10-24 07:56:04.855030014 +0200 +@@ -246,7 +246,7 @@ + TAILQ_INIT(&ssh->public_keys); + state->connection_in = -1; + state->connection_out = -1; +- state->max_packet_size = 32768; ++ state->max_packet_size = CHAN_SES_PACKET_DEFAULT; + state->packet_timeout_ms = -1; + state->p_send.packets = state->p_read.packets = 0; + state->initialized = 1; +@@ -294,7 +294,7 @@ + ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) + { + struct session_state *state; +- const struct sshcipher *none = cipher_by_name("none"); ++ struct sshcipher *none = cipher_by_name("none"); + int r; + + if (none == NULL) { +@@ -958,10 +958,19 @@ + * so enforce a 1GB limit for small blocksizes. + * See RFC4344 section 3.2. + */ +- if (enc->block_size >= 16) +- *max_blocks = (u_int64_t)1 << (enc->block_size*2); +- else +- *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; ++ ++ /* we really don't need to rekey if we are using the none cipher ++ * but there isn't a good way to disable it entirely that I can find ++ * and using a blocksize larger that 16 doesn't work (dunno why) ++ * so this seems to be a good limit for now - CJR 10/16/2020*/ ++ if (ssh->none == 1) { ++ *max_blocks = (u_int64_t)1 << (16*2); ++ } else { ++ if (enc->block_size >= 16) ++ *max_blocks = (u_int64_t)1 << (enc->block_size*2); ++ else ++ *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; ++ } + if (state->rekey_limit) + *max_blocks = MINIMUM(*max_blocks, + state->rekey_limit / enc->block_size); +@@ -970,6 +979,24 @@ + return 0; + } + ++/* this supports the forced rekeying required for the NONE cipher */ ++int rekey_requested = 0; ++void ++packet_request_rekeying(void) ++{ ++ rekey_requested = 1; ++} ++ ++/* used to determine if pre or post auth when rekeying for aes-ctr ++ * and none cipher switch */ ++int ++packet_authentication_state(const struct ssh *ssh) ++{ ++ struct session_state *state = ssh->state; ++ ++ return state->after_authentication; ++} ++ + #define MAX_PACKETS (1U<<31) + static int + ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len) +@@ -996,6 +1023,13 @@ + if (state->p_send.packets == 0 && state->p_read.packets == 0) + return 0; + ++ /* used to force rekeying when called for by the none ++ * cipher switch and aes-mt-ctr methods -cjr */ ++ if (rekey_requested == 1) { ++ rekey_requested = 0; ++ return 1; ++ } ++ + /* Time-based rekeying */ + if (state->rekey_interval != 0 && + (int64_t)state->rekey_time + state->rekey_interval <= monotime()) +@@ -1342,7 +1376,7 @@ + struct session_state *state = ssh->state; + int len, r, ms_remain; + fd_set *setp; +- char buf[8192]; ++ char buf[SSH_IOBUFSZ]; + struct timeval timeout, start, *timeoutp = NULL; + + DBG(debug("packet_read()")); +@@ -1870,17 +1904,21 @@ + switch (r) { + case SSH_ERR_CONN_CLOSED: + ssh_packet_clear_keys(ssh); ++ sshpkt_final_log_entry(ssh); + logdie("Connection closed by %s", remote_id); + case SSH_ERR_CONN_TIMEOUT: + ssh_packet_clear_keys(ssh); ++ sshpkt_final_log_entry(ssh); + logdie("Connection %s %s timed out", + ssh->state->server_side ? "from" : "to", remote_id); + case SSH_ERR_DISCONNECTED: + ssh_packet_clear_keys(ssh); ++ sshpkt_final_log_entry(ssh); + logdie("Disconnected from %s", remote_id); + case SSH_ERR_SYSTEM_ERROR: + if (errno == ECONNRESET) { + ssh_packet_clear_keys(ssh); ++ sshpkt_final_log_entry(ssh); + logdie("Connection reset by %s", remote_id); + } + /* FALLTHROUGH */ +@@ -1922,6 +1960,24 @@ + logdie_f("should have exited"); + } + ++/* this prints out the final log entry */ ++void ++sshpkt_final_log_entry (struct ssh *ssh) { ++ double total_time; ++ ++ if (ssh->start_time < 1) ++ /* this will produce a NaN in the output. -cjr */ ++ total_time = 0; ++ else ++ total_time = monotime_double() - ssh->start_time; ++ ++ logit("SSH: Server;LType: Throughput;Remote: %s-%d;IN: %lu;OUT: %lu;Duration: %.1f;tPut_in: %.1f;tPut_out: %.1f", ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ++ ssh->stdin_bytes, ssh->fdout_bytes, total_time, ++ ssh->stdin_bytes / total_time, ++ ssh->fdout_bytes / total_time); ++} ++ + /* + * Logs the error plus constructs and sends a disconnect packet, closes the + * connection, and exits. This function never returns. The error message +@@ -2794,3 +2850,10 @@ + ssh->state->extra_pad = pad; + return 0; + } ++ ++/* need this for the moment for the aes-ctr cipher */ ++void * ++ssh_packet_get_send_context(struct ssh *ssh) ++{ ++ return ssh->state->send_context; ++} +diff -Nur openssh-8.7p1.orig/packet.h openssh-8.7p1/packet.h +--- openssh-8.7p1.orig/packet.h 2021-10-24 07:54:36.833834119 +0200 ++++ openssh-8.7p1/packet.h 2021-10-24 07:56:04.856030016 +0200 +@@ -86,6 +86,14 @@ + + /* APP data */ + void *app_data; ++ ++ /* logging data for ServerLogging patch*/ ++ double start_time; ++ u_long fdout_bytes; ++ u_long stdin_bytes; ++ ++ /* track that we are in a none cipher/mac state */ ++ int none; + }; + + typedef int (ssh_packet_hook_fn)(struct ssh *, struct sshbuf *, +@@ -156,6 +164,8 @@ + int ssh_packet_set_maxsize(struct ssh *, u_int); + u_int ssh_packet_get_maxsize(struct ssh *); + ++int packet_authentication_state(const struct ssh *); ++ + int ssh_packet_get_state(struct ssh *, struct sshbuf *); + int ssh_packet_set_state(struct ssh *, struct sshbuf *); + +@@ -170,6 +180,13 @@ + + void *ssh_packet_get_input(struct ssh *); + void *ssh_packet_get_output(struct ssh *); ++void *ssh_packet_get_receive_context(struct ssh *); ++void *ssh_packet_get_send_context(struct ssh *); ++ ++/* for forced packet rekeying post auth */ ++void packet_request_rekeying(void); ++/* final log entry support */ ++void sshpkt_final_log_entry (struct ssh *); + + /* new API */ + int sshpkt_start(struct ssh *ssh, u_char type); +diff -Nur openssh-8.7p1.orig/progressmeter.c openssh-8.7p1/progressmeter.c +--- openssh-8.7p1.orig/progressmeter.c 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/progressmeter.c 2021-10-24 07:56:04.857030018 +0200 +@@ -68,6 +68,8 @@ + static off_t start_pos; /* initial position of transfer */ + static off_t end_pos; /* ending position of transfer */ + static off_t cur_pos; /* transfer position as of last refresh */ ++static off_t last_pos; ++static off_t max_delta_pos = 0; + static volatile off_t *counter; /* progress counter */ + static long stalled; /* how long we have been stalled */ + static int bytes_per_second; /* current speed in bytes per second */ +@@ -127,6 +129,7 @@ + int cur_speed; + int hours, minutes, seconds; + int file_len; ++ off_t delta_pos; + + if ((!force_update && !alarm_fired && !win_resized) || !can_output()) + return; +@@ -142,6 +145,10 @@ + now = monotime_double(); + bytes_left = end_pos - cur_pos; + ++ delta_pos = cur_pos - last_pos; ++ if (delta_pos > max_delta_pos) ++ max_delta_pos = delta_pos; ++ + if (bytes_left > 0) + elapsed = now - last_update; + else { +@@ -166,7 +173,7 @@ + + /* filename */ + buf[0] = '\0'; +- file_len = win_size - 36; ++ file_len = win_size - 45; + if (file_len > 0) { + buf[0] = '\r'; + snmprintf(buf+1, sizeof(buf)-1, &file_len, "%-*s", +@@ -191,6 +198,15 @@ + (off_t)bytes_per_second); + strlcat(buf, "/s ", win_size); + ++ /* instantaneous rate */ ++ if (bytes_left > 0) ++ format_rate(buf + strlen(buf), win_size - strlen(buf), ++ delta_pos); ++ else ++ format_rate(buf + strlen(buf), win_size - strlen(buf), ++ max_delta_pos); ++ strlcat(buf, "/s ", win_size); ++ + /* ETA */ + if (!transferred) + stalled += elapsed; +@@ -227,6 +243,7 @@ + + atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); + last_update = now; ++ last_pos = cur_pos; + } + + /*ARGSUSED*/ +diff -Nur openssh-8.7p1.orig/readconf.c openssh-8.7p1/readconf.c +--- openssh-8.7p1.orig/readconf.c 2021-10-24 07:54:36.870834202 +0200 ++++ openssh-8.7p1/readconf.c 2021-10-24 08:13:34.654331392 +0200 +@@ -67,6 +67,7 @@ + #include "uidswap.h" + #include "myproposal.h" + #include "digest.h" ++#include "sshbuf.h" + #include "ssh-gss.h" + + /* Format of the configuration file: +@@ -169,6 +170,9 @@ + oHashKnownHosts, + oTunnel, oTunnelDevice, + oLocalCommand, oPermitLocalCommand, oRemoteCommand, ++ oTcpRcvBufPoll, oTcpRcvBuf, oHPNDisabled, oHPNBufferSize, ++ oNoneEnabled, oNoneMacEnabled, oNoneSwitch, ++ oDisableMTAES, + oVisualHostKey, + oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull, + oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass, +@@ -313,6 +317,10 @@ + { "kexalgorithms", oKexAlgorithms }, + { "ipqos", oIPQoS }, + { "requesttty", oRequestTTY }, ++ { "noneenabled", oNoneEnabled }, ++ { "nonemacenabled", oNoneMacEnabled }, ++ { "noneswitch", oNoneSwitch }, ++ { "disablemtaes", oDisableMTAES }, + { "sessiontype", oSessionType }, + { "stdinnull", oStdinNull }, + { "forkafterauthentication", oForkAfterAuthentication }, +@@ -336,6 +344,11 @@ + { "securitykeyprovider", oSecurityKeyProvider }, + { "knownhostscommand", oKnownHostsCommand }, + ++ { "tcprcvbufpoll", oTcpRcvBufPoll }, ++ { "tcprcvbuf", oTcpRcvBuf }, ++ { "hpndisabled", oHPNDisabled }, ++ { "hpnbuffersize", oHPNBufferSize }, ++ + { NULL, oBadOption } + }; + +@@ -1172,6 +1185,46 @@ + intptr = &options->check_host_ip; + goto parse_flag; + ++ case oHPNDisabled: ++ intptr = &options->hpn_disabled; ++ goto parse_flag; ++ ++ case oHPNBufferSize: ++ intptr = &options->hpn_buffer_size; ++ goto parse_int; ++ ++ case oTcpRcvBufPoll: ++ intptr = &options->tcp_rcv_buf_poll; ++ goto parse_flag; ++ ++ case oNoneEnabled: ++ intptr = &options->none_enabled; ++ goto parse_flag; ++ ++ case oNoneMacEnabled: ++ intptr = &options->nonemac_enabled; ++ goto parse_flag; ++ ++ case oDisableMTAES: ++ intptr = &options->disable_multithreaded; ++ goto parse_flag; ++ ++ /* ++ * We check to see if the command comes from the command ++ * line or not. If it does then enable it otherwise fail. ++ * NONE should never be a default configuration. ++ */ ++ case oNoneSwitch: ++ if (strcmp(filename, "command-line") == 0) { ++ intptr = &options->none_switch; ++ goto parse_flag; ++ } else { ++ error("NoneSwitch is found in %.200s.\nYou may only use this configuration option from the command line", filename); ++ error("Continuing..."); ++ debug("NoneSwitch directive found in %.200s.", filename); ++ return 0; ++ } ++ + case oVerifyHostKeyDNS: + intptr = &options->verify_host_key_dns; + multistate_ptr = multistate_yesnoask; +@@ -1426,6 +1479,10 @@ + *intptr = value; + break; + ++ case oTcpRcvBuf: ++ intptr = &options->tcp_rcv_buf; ++ goto parse_int; ++ + case oCiphers: + arg = argv_next(&ac, &av); + if (!arg || *arg == '\0') { +@@ -2440,6 +2497,14 @@ + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; + options->request_tty = -1; ++ options->none_switch = -1; ++ options->none_enabled = -1; ++ options->nonemac_enabled = -1; ++ options->disable_multithreaded = -1; ++ options->hpn_disabled = -1; ++ options->hpn_buffer_size = -1; ++ options->tcp_rcv_buf_poll = -1; ++ options->tcp_rcv_buf = -1; + options->session_type = -1; + options->stdin_null = -1; + options->fork_after_authentication = -1; +@@ -2615,6 +2680,43 @@ + options->server_alive_interval = 0; + if (options->server_alive_count_max == -1) + options->server_alive_count_max = 3; ++ if (options->hpn_disabled == -1) ++ options->hpn_disabled = 0; ++ if (options->hpn_buffer_size > -1) { ++ /* if a user tries to set the size to 0 set it to 1KB */ ++ if (options->hpn_buffer_size == 0) ++ options->hpn_buffer_size = 1; ++ /* limit the buffer to SSHBUF_SIZE_MAX (currently 256MB) */ ++ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { ++ options->hpn_buffer_size = SSHBUF_SIZE_MAX; ++ debug("User requested buffer larger than 256MB. Request reverted to 256MB"); ++ } else ++ options->hpn_buffer_size *= 1024; ++ debug("hpn_buffer_size set to %d", options->hpn_buffer_size); ++ } ++ if (options->tcp_rcv_buf == 0) ++ options->tcp_rcv_buf = 1; ++ if (options->tcp_rcv_buf > -1) ++ options->tcp_rcv_buf *=1024; ++ if (options->tcp_rcv_buf_poll == -1) ++ options->tcp_rcv_buf_poll = 1; ++ if (options->none_switch == -1) ++ options->none_switch = 0; ++ if (options->none_enabled == -1) ++ options->none_enabled = 0; ++ if (options->none_enabled == 0 && options->none_switch > 0) { ++ fprintf(stderr, "NoneEnabled must be enabled to use the None Switch option. None cipher disabled.\n"); ++ options->none_enabled = 0; ++ } ++ if (options->nonemac_enabled == -1) ++ options->nonemac_enabled = 0; ++ if (options->nonemac_enabled > 0 && (options->none_enabled == 0 || ++ options->none_switch == 0)) { ++ fprintf(stderr, "None MAC can only be used with the None cipher. None MAC disabled.\n"); ++ options->nonemac_enabled = 0; ++ } ++ if (options->disable_multithreaded == -1) ++ options->disable_multithreaded = 0; + if (options->control_master == -1) + options->control_master = 0; + if (options->control_persist == -1) { +diff -Nur openssh-8.7p1.orig/readconf.h openssh-8.7p1/readconf.h +--- openssh-8.7p1.orig/readconf.h 2021-10-24 07:54:36.870834202 +0200 ++++ openssh-8.7p1/readconf.h 2021-10-24 07:56:04.860030025 +0200 +@@ -55,6 +55,10 @@ + int strict_host_key_checking; /* Strict host key checking. */ + int compression; /* Compress packets in both directions. */ + int tcp_keep_alive; /* Set SO_KEEPALIVE. */ ++ int tcp_rcv_buf; /* user switch to set tcp recv buffer */ ++ int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ ++ int hpn_disabled; /* Switch to disable HPN buffer management */ ++ int hpn_buffer_size; /* User definable size for HPN buffer window */ + int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ + int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ + SyslogFacility log_facility; /* Facility for system logging. */ +@@ -126,7 +130,12 @@ + + int enable_ssh_keysign; + int64_t rekey_limit; ++ int none_switch; /* Use none cipher */ ++ int none_enabled; /* Allow none to be used */ ++ int nonemac_enabled; /* Allow none to be used */ ++ int disable_multithreaded; /*disable multithreaded aes-ctr*/ + int rekey_interval; ++ + int no_host_authentication_for_localhost; + int identities_only; + int server_alive_interval; +diff -Nur openssh-8.7p1.orig/regress/integrity.sh openssh-8.7p1/regress/integrity.sh +--- openssh-8.7p1.orig/regress/integrity.sh 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/regress/integrity.sh 2021-10-24 07:56:04.860030025 +0200 +@@ -21,6 +21,12 @@ + cmd="$SUDO env SSH_SK_HELPER="$SSH_SK_HELPER" sh ${SRC}/sshd-log-wrapper.sh ${TEST_SSHD_LOGFILE} ${SSHD} -i -f $OBJ/sshd_proxy" + + for m in $macs; do ++ # the none mac is now valid but tests against it will succeed when we expect it to ++ # fail. so we need to explicity remove it from the list of macs returned. ++ if [ "$m" = "none" ]; then ++ continue ++ fi ++ + trace "test $tid: mac $m" + elen=0 + epad=0 +diff -Nur openssh-8.7p1.orig/sandbox-seccomp-filter.c openssh-8.7p1/sandbox-seccomp-filter.c +--- openssh-8.7p1.orig/sandbox-seccomp-filter.c 2021-10-24 07:54:36.842834139 +0200 ++++ openssh-8.7p1/sandbox-seccomp-filter.c 2021-10-24 07:56:04.861030027 +0200 +@@ -225,6 +225,9 @@ + #ifdef __NR_geteuid32 + SC_ALLOW(__NR_geteuid32), + #endif ++#ifdef __NR_getpeername /* not defined on archs that go via socketcall(2) */ ++ SC_ALLOW(__NR_getpeername), ++#endif + #ifdef __NR_getpgid + SC_ALLOW(__NR_getpgid), + #endif +@@ -318,6 +321,9 @@ + #ifdef __NR_sigprocmask + SC_ALLOW(__NR_sigprocmask), + #endif ++#ifdef __NR_socketcall ++ SC_ALLOW(__NR_socketcall), ++#endif + #ifdef __NR_time + SC_ALLOW(__NR_time), + #endif +diff -Nur openssh-8.7p1.orig/scp.c openssh-8.7p1/scp.c +--- openssh-8.7p1.orig/scp.c 2021-10-24 07:54:36.854834166 +0200 ++++ openssh-8.7p1/scp.c 2021-10-24 07:56:04.861030027 +0200 +@@ -1566,7 +1566,7 @@ + off_t size, statbytes; + unsigned long long ull; + int setimes, targisdir, wrerr; +- char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; ++ char ch, *cp, *np, *targ, *why, *vect[1], buf[16384], visbuf[16384]; + char **patterns = NULL; + size_t n, npatterns = 0; + struct timeval tv[2]; +diff -Nur openssh-8.7p1.orig/servconf.c openssh-8.7p1/servconf.c +--- openssh-8.7p1.orig/servconf.c 2021-10-24 07:54:36.871834204 +0200 ++++ openssh-8.7p1/servconf.c 2021-10-24 07:56:04.863030032 +0200 +@@ -70,6 +70,7 @@ + #include "auth.h" + #include "myproposal.h" + #include "digest.h" ++#include "sshbuf.h" + #include "ssh-gss.h" + + static void add_listen_addr(ServerOptions *, const char *, +@@ -200,6 +201,12 @@ + options->authorized_principals_file = NULL; + options->authorized_principals_command = NULL; + options->authorized_principals_command_user = NULL; ++ options->tcp_rcv_buf_poll = -1; ++ options->hpn_disabled = -1; ++ options->hpn_buffer_size = -1; ++ options->none_enabled = -1; ++ options->nonemac_enabled = -1; ++ options->disable_multithreaded = -1; + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; + options->version_addendum = NULL; +@@ -290,6 +297,10 @@ + fill_default_server_options(ServerOptions *options) + { + u_int i; ++ /* needed for hpn socket tests */ ++ int sock; ++ int socksize; ++ int socksizelen = sizeof(int); + + /* Portable-specific options */ + if (options->use_pam == -1) +@@ -461,6 +472,51 @@ + } + if (options->permit_tun == -1) + options->permit_tun = SSH_TUNMODE_NO; ++ if (options->none_enabled == -1) ++ options->none_enabled = 0; ++ if (options->nonemac_enabled == -1) ++ options->nonemac_enabled = 0; ++ if (options->nonemac_enabled > 0 && options->none_enabled == 0) { ++ debug ("Attempted to enabled None MAC without setting None Enabled to true. None MAC disabled."); ++ options->nonemac_enabled = 0; ++ } ++ if (options->disable_multithreaded == -1) ++ options->disable_multithreaded = 0; ++ if (options->hpn_disabled == -1) ++ options->hpn_disabled = 0; ++ ++ if (options->hpn_buffer_size == -1) { ++ /* option not explicitly set. Now we have to figure out */ ++ /* what value to use */ ++ if (options->hpn_disabled == 1) { ++ options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; ++ } else { ++ /* get the current RCV size and set it to that */ ++ /*create a socket but don't connect it */ ++ /* we use that the get the rcv socket size */ ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, ++ &socksize, &socksizelen); ++ close(sock); ++ options->hpn_buffer_size = socksize; ++ debug("HPN Buffer Size: %d", options->hpn_buffer_size); ++ } ++ } else { ++ /* we have to do this in case the user sets both values in a contradictory */ ++ /* manner. hpn_disabled overrrides hpn_buffer_size*/ ++ if (options->hpn_disabled <= 0) { ++ if (options->hpn_buffer_size == 0) ++ options->hpn_buffer_size = 1; ++ /* limit the maximum buffer to SSHBUF_SIZE_MAX (currently 256MB) */ ++ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { ++ options->hpn_buffer_size = SSHBUF_SIZE_MAX; ++ } else { ++ options->hpn_buffer_size *= 1024; ++ } ++ } else ++ options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; ++ } ++ + if (options->ip_qos_interactive == -1) + options->ip_qos_interactive = IPTOS_DSCP_AF21; + if (options->ip_qos_bulk == -1) +@@ -533,6 +589,9 @@ + sPasswordAuthentication, sKbdInteractiveAuthentication, + sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, ++ sNoneEnabled, sNoneMacEnabled, ++ sDisableMTAES, ++ sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, + sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, + sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, + sPermitUserEnvironment, sAllowTcpForwarding, sCompression, +@@ -733,6 +792,12 @@ + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, + { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, ++ { "hpndisabled", sHPNDisabled, SSHCFG_ALL }, ++ { "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL }, ++ { "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL }, ++ { "noneenabled", sNoneEnabled, SSHCFG_ALL }, ++ { "disableMTAES", sDisableMTAES, SSHCFG_ALL }, ++ { "nonemacenabled", sNoneMacEnabled, SSHCFG_ALL }, + { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, + { "include", sInclude, SSHCFG_ALL }, + { "ipqos", sIPQoS, SSHCFG_ALL }, +@@ -791,6 +856,7 @@ + + for (i = 0; keywords[i].name; i++) + if (strcasecmp(cp, keywords[i].name) == 0) { ++ debug("Config token is %s", keywords[i].name); + *flags = keywords[i].flags; + return keywords[i].opcode; + } +@@ -1568,12 +1634,36 @@ + multistate_ptr = multistate_ignore_rhosts; + goto parse_multistate; + ++ case sTcpRcvBufPoll: ++ intptr = &options->tcp_rcv_buf_poll; ++ goto parse_flag; ++ ++ case sHPNDisabled: ++ intptr = &options->hpn_disabled; ++ goto parse_flag; ++ ++ case sHPNBufferSize: ++ intptr = &options->hpn_buffer_size; ++ goto parse_int; ++ + case sIgnoreUserKnownHosts: + intptr = &options->ignore_user_known_hosts; + parse_flag: + multistate_ptr = multistate_flag; + goto parse_multistate; + ++ case sNoneEnabled: ++ intptr = &options->none_enabled; ++ goto parse_flag; ++ ++ case sNoneMacEnabled: ++ intptr = &options->nonemac_enabled; ++ goto parse_flag; ++ ++ case sDisableMTAES: ++ intptr = &options->disable_multithreaded; ++ goto parse_flag; ++ + case sHostbasedAuthentication: + intptr = &options->hostbased_authentication; + goto parse_flag; +diff -Nur openssh-8.7p1.orig/servconf.h openssh-8.7p1/servconf.h +--- openssh-8.7p1.orig/servconf.h 2021-10-24 07:54:36.871834204 +0200 ++++ openssh-8.7p1/servconf.h 2021-10-24 07:56:04.864030034 +0200 +@@ -214,6 +214,13 @@ + int use_pam; /* Enable auth via PAM */ + int permit_pam_user_change; /* Allow PAM to change user name */ + ++ int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ ++ int hpn_disabled; /* disable hpn functionality. false by default */ ++ int hpn_buffer_size; /* set the hpn buffer size - default 3MB */ ++ int none_enabled; /* Enable NONE cipher switch */ ++ int disable_multithreaded; /*disable multithreaded aes-ctr cipher */ ++ int nonemac_enabled; /* Enable NONE MAC switch */ ++ + int permit_tun; + + char **permitted_opens; /* May also be one of PERMITOPEN_* */ +diff -Nur openssh-8.7p1.orig/serverloop.c openssh-8.7p1/serverloop.c +--- openssh-8.7p1.orig/serverloop.c 2021-10-24 07:54:36.855834168 +0200 ++++ openssh-8.7p1/serverloop.c 2021-10-24 07:56:04.865030036 +0200 +@@ -266,7 +266,7 @@ + process_input(struct ssh *ssh, fd_set *readset, int connection_in) + { + int r, len; +- char buf[16384]; ++ char buf[SSH_IOBUFSZ]; + + /* Read and buffer any input data from the client. */ + if (FD_ISSET(connection_in, readset)) { +@@ -287,6 +287,7 @@ + /* Buffer any received data. */ + if ((r = ssh_packet_process_incoming(ssh, buf, len)) != 0) + fatal_fr(r, "ssh_packet_process_incoming"); ++ ssh->fdout_bytes += len; + } + return 0; + } +@@ -340,6 +341,7 @@ + sigset_t bsigset, osigset; + + debug("Entering interactive session for SSH2."); ++ ssh->start_time = monotime_double(); + + if (sigemptyset(&bsigset) == -1 || sigaddset(&bsigset, SIGCHLD) == -1) + error_f("bsigset setup: %s", strerror(errno)); +@@ -388,6 +390,7 @@ + + if (received_sigterm) { + logit("Exiting on signal %d", (int)received_sigterm); ++ sshpkt_final_log_entry(ssh); + /* Clean up sessions, utmp, etc. */ + cleanup_exit(255); + } +@@ -409,6 +412,9 @@ + /* free all channels, no more reads and writes */ + channel_free_all(ssh); + ++ /* final entry must come after channels close -cjr */ ++ sshpkt_final_log_entry(ssh); ++ + /* free remaining sessions, e.g. remove wtmp entries */ + session_destroy_all(ssh, NULL); + } +@@ -559,7 +565,8 @@ + debug("Tunnel forwarding using interface %s", ifname); + + c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1, +- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); ++ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, ++ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); + c->datagram = 1; + #if defined(SSH_TUN_FILTER) + if (mode == SSH_TUNMODE_POINTOPOINT) +@@ -610,6 +617,8 @@ + c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL, + -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, + 0, "server-session", 1); ++ if ((options.tcp_rcv_buf_poll) && (!options.hpn_disabled)) ++ c->dynamic_window = 1; + if (session_open(the_authctxt, c->self) != 1) { + debug("session open failed, free channel %d", c->self); + channel_free(ssh, c); +diff -Nur openssh-8.7p1.orig/session.c openssh-8.7p1/session.c +--- openssh-8.7p1.orig/session.c 2021-10-24 07:54:36.855834168 +0200 ++++ openssh-8.7p1/session.c 2021-10-24 07:56:04.866030038 +0200 +@@ -228,6 +228,7 @@ + goto authsock_err; + + /* Allocate a channel for the authentication agent socket. */ ++ /* this shouldn't matter if its hpn or not - cjr */ + nc = channel_new(ssh, "auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, +@@ -2363,7 +2364,8 @@ + channel_set_fds(ssh, s->chanid, + fdout, fdin, fderr, + ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, +- 1, is_tty, CHAN_SES_WINDOW_DEFAULT); ++ 1, is_tty, ++ options.hpn_disabled ? CHAN_SES_WINDOW_DEFAULT : options.hpn_buffer_size); + } + + /* +diff -Nur openssh-8.7p1.orig/sftp.1 openssh-8.7p1/sftp.1 +--- openssh-8.7p1.orig/sftp.1 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sftp.1 2021-10-24 07:56:04.867030041 +0200 +@@ -295,7 +295,8 @@ + Specify how many requests may be outstanding at any one time. + Increasing this may slightly improve file transfer speed + but will increase memory usage. +-The default is 64 outstanding requests. ++The default is 256 outstanding requests providing for 8MB ++of outstanding data with a 32KB buffer. + .It Fl r + Recursively copy entire directories when uploading and downloading. + Note that +diff -Nur openssh-8.7p1.orig/sftp-client.c openssh-8.7p1/sftp-client.c +--- openssh-8.7p1.orig/sftp-client.c 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sftp-client.c 2021-10-24 07:56:04.868030043 +0200 +@@ -72,7 +72,7 @@ + #define DEFAULT_COPY_BUFLEN 32768 + + /* Default number of concurrent outstanding requests */ +-#define DEFAULT_NUM_REQUESTS 64 ++#define DEFAULT_NUM_REQUESTS 256 + + /* Minimum amount of data to read at a time */ + #define MIN_READ_SIZE 512 +diff -Nur openssh-8.7p1.orig/ssh_api.c openssh-8.7p1/ssh_api.c +--- openssh-8.7p1.orig/ssh_api.c 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/ssh_api.c 2021-10-24 07:56:04.869030045 +0200 +@@ -410,7 +410,7 @@ + char *cp; + int r; + +- if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_VERSION)) != 0) ++ if ((r = sshbuf_putf(banner, "SSH-2.0-%.100s\r\n", SSH_RELEASE)) != 0) + return r; + if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) + return r; +diff -Nur openssh-8.7p1.orig/sshbuf.h openssh-8.7p1/sshbuf.h +--- openssh-8.7p1.orig/sshbuf.h 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/sshbuf.h 2021-10-24 07:56:04.870030047 +0200 +@@ -28,7 +28,7 @@ + # endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ + +-#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ ++#define SSHBUF_SIZE_MAX 0xF000000 /* Hard maximum size 256MB */ + #define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */ + #define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */ + #define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */ +diff -Nur openssh-8.7p1.orig/ssh.c openssh-8.7p1/ssh.c +--- openssh-8.7p1.orig/ssh.c 2021-10-24 07:54:36.872834206 +0200 ++++ openssh-8.7p1/ssh.c 2021-10-24 07:56:04.871030049 +0200 +@@ -1056,6 +1056,10 @@ + break; + case 'T': + options.request_tty = REQUEST_TTY_NO; ++ /* ensure that the user doesn't try to backdoor a */ ++ /* null cipher switch on an interactive session */ ++ /* so explicitly disable it no matter what */ ++ options.none_switch=0; + break; + case 'o': + line = xstrdup(optarg); +@@ -1784,6 +1788,8 @@ + setproctitle("%s [mux]", options.control_path); + } + ++extern const EVP_CIPHER *evp_aes_ctr_mt(void); ++ + /* Do fork() after authentication. Used by "ssh -f" */ + static void + fork_postauth(void) +@@ -2101,6 +2107,79 @@ + NULL, fileno(stdin), command, environ); + } + ++static void ++hpn_options_init(struct ssh *ssh) ++{ ++ /* ++ * We need to check to see if what they want to do about buffer ++ * sizes here. In a hpn to nonhpn connection we want to limit ++ * the window size to something reasonable in case the far side ++ * has the large window bug. In hpn to hpn connection we want to ++ * use the max window size but allow the user to override it ++ * lastly if they disabled hpn then use the ssh std window size. ++ * ++ * So why don't we just do a getsockopt() here and set the ++ * ssh window to that? In the case of a autotuning receive ++ * window the window would get stuck at the initial buffer ++ * size generally less than 96k. Therefore we need to set the ++ * maximum ssh window size to the maximum hpn buffer size ++ * unless the user has specifically set the tcprcvbufpoll ++ * to no. In which case we *can* just set the window to the ++ * minimum of the hpn buffer size and tcp receive buffer size. ++ */ ++ ++ if (tty_flag) ++ options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; ++ else ++ options.hpn_buffer_size = 2 * 1024 * 1024; ++ ++ if (ssh->compat & SSH_BUG_LARGEWINDOW) { ++ debug("HPN to Non-HPN connection"); ++ } else { ++ debug("HPN to HPN connection"); ++ int sock, socksize; ++ socklen_t socksizelen; ++ if (options.tcp_rcv_buf_poll <= 0) { ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ socksizelen = sizeof(socksize); ++ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, ++ &socksize, &socksizelen); ++ close(sock); ++ debug("socksize %d", socksize); ++ options.hpn_buffer_size = socksize; ++ debug("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size); ++ } else { ++ if (options.tcp_rcv_buf > 0) { ++ /* ++ * Create a socket but don't connect it: ++ * we use that the get the rcv socket size ++ */ ++ sock = socket(AF_INET, SOCK_STREAM, 0); ++ /* ++ * If they are using the tcp_rcv_buf option, ++ * attempt to set the buffer size to that. ++ */ ++ if (options.tcp_rcv_buf) { ++ socksizelen = sizeof(options.tcp_rcv_buf); ++ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, ++ &options.tcp_rcv_buf, socksizelen); ++ } ++ socksizelen = sizeof(socksize); ++ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, ++ &socksize, &socksizelen); ++ close(sock); ++ debug("socksize %d", socksize); ++ options.hpn_buffer_size = socksize; ++ debug("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size); ++ } ++ } ++ } ++ ++ debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); ++ ++ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); ++} ++ + /* open new channel for a session */ + static int + ssh_session2_open(struct ssh *ssh) +@@ -2119,9 +2198,11 @@ + if (in == -1 || out == -1 || err == -1) + fatal("dup() in/out/err failed"); + +- window = CHAN_SES_WINDOW_DEFAULT; ++ window = options.hpn_buffer_size; ++ + packetmax = CHAN_SES_PACKET_DEFAULT; + if (tty_flag) { ++ window = CHAN_SES_WINDOW_DEFAULT; + window >>= 1; + packetmax >>= 1; + } +@@ -2132,6 +2213,11 @@ + + debug3_f("channel_new: %d", c->self); + ++ if (options.tcp_rcv_buf_poll > 0 && !options.hpn_disabled) { ++ c->dynamic_window = 1; ++ debug("Enabled Dynamic Window Scaling"); ++ } ++ + channel_send_open(ssh, c->self); + if (options.session_type != SESSION_TYPE_NONE) + channel_register_open_confirm(ssh, c->self, +@@ -2146,6 +2232,13 @@ + int r, id = -1; + char *cp, *tun_fwd_ifname = NULL; + ++ /* ++ * We need to initialize this early because the forwarding logic below ++ * might open channels that use the hpn buffer sizes. We can't send a ++ * window of -1 (the default) to the server as it breaks things. ++ */ ++ hpn_options_init(ssh); ++ + /* XXX should be pre-session */ + if (!options.control_persist) + ssh_init_stdio_forwarding(ssh); +diff -Nur openssh-8.7p1.orig/sshconnect2.c openssh-8.7p1/sshconnect2.c +--- openssh-8.7p1.orig/sshconnect2.c 2021-10-24 07:54:36.873834208 +0200 ++++ openssh-8.7p1/sshconnect2.c 2021-10-24 08:06:47.586411958 +0200 +@@ -86,6 +86,13 @@ + extern Options options; + + /* ++ * tty_flag is set in ssh.c. Use this in ssh_userauth2: ++ * if it is set, then prevent the switch to the null cipher. ++ */ ++ ++extern int tty_flag; ++ ++/* + * SSH2 key exchange + */ + +@@ -212,6 +219,8 @@ + return ret; + } + ++static char *myproposal[PROPOSAL_MAX]; ++static const char *myproposal_default[PROPOSAL_MAX] = { KEX_CLIENT }; + void + ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, + const struct ssh_conn_info *cinfo) +@@ -225,6 +234,10 @@ + char *gss_host = NULL; + #endif + ++ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); ++ ++ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); ++ + xxx_host = host; + xxx_hostaddr = hostaddr; + xxx_conn_info = cinfo; +@@ -569,6 +582,53 @@ + + if (!authctxt.success) + fatal("Authentication failed."); ++ ++ /* ++ * If the user wants to use the none cipher and/or none mac, do it post authentication ++ * and only if the right conditions are met -- both of the NONE commands ++ * must be true and there must be no tty allocated. ++ */ ++ if (options.none_switch == 1 && options.none_enabled == 1) { ++ if (!tty_flag) { /* no null on tty sessions */ ++ debug("Requesting none rekeying..."); ++ memcpy(&myproposal, &myproposal_default, sizeof(myproposal)); ++ myproposal[PROPOSAL_ENC_ALGS_STOC] = "none"; ++ myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none"; ++ fprintf(stderr, "WARNING: ENABLED NONE CIPHER!!!\n"); ++ /* NONEMAC can only be used in context of the NONE CIPHER */ ++ if (options.nonemac_enabled == 1) { ++ myproposal[PROPOSAL_MAC_ALGS_STOC] = "none"; ++ myproposal[PROPOSAL_MAC_ALGS_CTOS] = "none"; ++ fprintf(stderr, "WARNING: ENABLED NONE MAC\n"); ++ } ++ kex_prop2buf(ssh->kex->my, myproposal); ++ packet_request_rekeying(); ++ } else { ++ /* requested NONE cipher when in a tty */ ++ debug("Cannot switch to NONE cipher with tty allocated"); ++ fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n"); ++ } ++ } ++ ++#ifdef WITH_OPENSSL ++ if (options.disable_multithreaded == 0) { ++ /* if we are using aes-ctr there can be issues in either a fork or sandbox ++ * so the initial aes-ctr is defined to point to the original single process ++ * evp. After authentication we'll be past the fork and the sandboxed privsep ++ * so we repoint the define to the multithreaded evp. To start the threads we ++ * then force a rekey ++ */ ++ const void *cc = ssh_packet_get_send_context(ssh); ++ ++ /* only do this for the ctr cipher. otherwise gcm mode breaks. Don't know why though */ ++ if (strstr(cipher_ctx_name(cc), "ctr")) { ++ debug("Single to Multithread CTR cipher swap - client request"); ++ cipher_reset_multithreaded(); ++ packet_request_rekeying(); ++ } ++ } ++#endif ++ + if (ssh_packet_connection_is_on_socket(ssh)) { + verbose("Authenticated to %s ([%s]:%d) using \"%s\".", host, + ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), +diff -Nur openssh-8.7p1.orig/sshconnect.c openssh-8.7p1/sshconnect.c +--- openssh-8.7p1.orig/sshconnect.c 2021-10-24 07:54:36.794834032 +0200 ++++ openssh-8.7p1/sshconnect.c 2021-10-24 07:56:04.873030054 +0200 +@@ -345,6 +345,30 @@ + #endif + + /* ++ * Set TCP receive buffer if requested. ++ * Note: tuning needs to happen after the socket is ++ * created but before the connection happens ++ * so winscale is negotiated properly -cjr ++ */ ++static void ++ssh_set_socket_recvbuf(int sock) ++{ ++ void *buf = (void *)&options.tcp_rcv_buf; ++ int sz = sizeof(options.tcp_rcv_buf); ++ int socksize; ++ int socksizelen = sizeof(int); ++ ++ debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf); ++ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { ++ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen); ++ debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize); ++ } ++ else ++ error("Couldn't set socket receive buffer to %d: %.100s", ++ options.tcp_rcv_buf, strerror(errno)); ++} ++ ++/* + * Creates a socket for use as the ssh connection. + */ + static int +@@ -366,6 +390,9 @@ + } + fcntl(sock, F_SETFD, FD_CLOEXEC); + ++ if (options.tcp_rcv_buf > 0) ++ ssh_set_socket_recvbuf(sock); ++ + /* Use interactive QOS (if specified) until authentication completed */ + if (options.ip_qos_interactive != INT_MAX) + set_sock_tos(sock, options.ip_qos_interactive); +diff -Nur openssh-8.7p1.orig/sshd.c openssh-8.7p1/sshd.c +--- openssh-8.7p1.orig/sshd.c 2021-10-24 07:54:36.874834211 +0200 ++++ openssh-8.7p1/sshd.c 2021-10-24 08:00:18.185586742 +0200 +@@ -1110,6 +1110,8 @@ + int ret, listen_sock; + struct addrinfo *ai; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; ++ int socksize; ++ int socksizelen = sizeof(int); + + for (ai = la->addrs; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) +@@ -1155,6 +1157,11 @@ + + debug("Bind to port %s on %s.", strport, ntop); + ++ getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, ++ &socksize, &socksizelen); ++ debug("Server TCP RWIN socket size: %d", socksize); ++ debug("HPN Buffer Size: %d", options.hpn_buffer_size); ++ + /* Bind the socket to the desired port. */ + if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) == -1) { + error("Bind to port %s on %s failed: %.200s.", +@@ -1854,6 +1861,19 @@ + /* Fill in default values for those options not explicitly set. */ + fill_default_server_options(&options); + ++ if (options.none_enabled == 1) { ++ char *old_ciphers = options.ciphers; ++ xasprintf(&options.ciphers, "%s,none", old_ciphers); ++ free(old_ciphers); ++ ++ /* only enable the none MAC in context of the none cipher -cjr */ ++ if (options.nonemac_enabled == 1) { ++ char *old_macs = options.macs; ++ xasprintf(&options.macs, "%s,none", old_macs); ++ free(old_macs); ++ } ++ } ++ + /* Check that options are sensible */ + if (options.authorized_keys_command_user == NULL && + (options.authorized_keys_command != NULL && +@@ -2301,6 +2321,9 @@ + rdomain == NULL ? "" : "\""); + free(laddr); + ++ /* set the HPN options for the child */ ++ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); ++ + /* + * We don't want to listen forever unless the other side + * successfully authenticates itself. So we set up an alarm which is +@@ -2413,6 +2436,25 @@ + /* Try to send all our hostkeys to the client */ + notify_hostkeys(ssh); + ++#ifdef WITH_OPENSSL ++ if (options.disable_multithreaded == 0) { ++ /* if we are using aes-ctr there can be issues in either a fork or sandbox ++ * so the initial aes-ctr is defined to point ot the original single process ++ * evp. After authentication we'll be past the fork and the sandboxed privsep ++ * so we repoint the define to the multithreaded evp. To start the threads we ++ * then force a rekey ++ */ ++ const void *cc = ssh_packet_get_send_context(the_active_state); ++ ++ /* only rekey if necessary. If we don't do this gcm mode cipher breaks */ ++ if (strstr(cipher_ctx_name(cc), "ctr")) { ++ debug("Single to Multithreaded CTR cipher swap - server request"); ++ cipher_reset_multithreaded(); ++ packet_request_rekeying(); ++ } ++ } ++#endif ++ + /* Start session. */ + do_authenticated(ssh, authctxt); + +@@ -2486,6 +2528,11 @@ + struct kex *kex; + int r; + ++ if (options.none_enabled == 1) ++ debug("WARNING: None cipher enabled"); ++ if (options.nonemac_enabled == 1) ++ debug("WARNING: None MAC enabled"); ++ + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, + options.kex_algorithms); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh, +diff -Nur openssh-8.7p1.orig/sshd_config openssh-8.7p1/sshd_config +--- openssh-8.7p1.orig/sshd_config 2021-10-24 07:54:36.874834211 +0200 ++++ openssh-8.7p1/sshd_config 2021-10-24 07:56:04.875030058 +0200 +@@ -127,6 +127,28 @@ + # override default of no subsystems + Subsystem sftp /usr/libexec/sftp-server + ++# the following are HPN related configuration options ++# tcp receive buffer polling. disable in non autotuning kernels ++#TcpRcvBufPoll yes ++ ++# disable hpn performance boosts ++#HPNDisabled no ++ ++# buffer size for hpn to non-hpn connections ++#HPNBufferSize 2048 ++ ++# allow the use of the none cipher ++#NoneEnabled no ++ ++# allow the use of the none MAC ++#NoneMacEnabled no ++ ++# Disable MT-AES-CTR cipher on server ++# * needed for GSI-OpenSSH 7.4p1 because it's broken on the server side there ++# * useful for modern processors with AES-NI instructions making the stock ++# AES-CTR cipher faster than the MT-AES-CTR cipher ++DisableMTAES yes ++ + # Example of overriding settings on a per-user basis + #Match User anoncvs + # X11Forwarding no +diff -Nur openssh-8.7p1.orig/version.h openssh-8.7p1/version.h +--- openssh-8.7p1.orig/version.h 2021-10-24 07:54:36.876834215 +0200 ++++ openssh-8.7p1/version.h 2021-10-24 07:56:04.876030061 +0200 +@@ -16,5 +16,6 @@ + + #define SSH_PORTABLE "p1" + #define GSI_PORTABLE "c-GSI" ++#define SSH_HPN "-hpn15v2" + #define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ +- GSI_VERSION KRB5_VERSION ++ GSI_VERSION SSH_HPN KRB5_VERSION diff --git a/openssh-8.7p1-upstream-cve-2021-41617.patch b/openssh-8.7p1-upstream-cve-2021-41617.patch new file mode 100644 index 0000000..0bca544 --- /dev/null +++ b/openssh-8.7p1-upstream-cve-2021-41617.patch @@ -0,0 +1,31 @@ +diff --git a/misc.c b/misc.c +index b8d1040d..0134d694 100644 +--- a/misc.c ++++ b/misc.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: misc.c,v 1.169 2021/08/09 23:47:44 djm Exp $ */ ++/* $OpenBSD: misc.c,v 1.170 2021/09/26 14:01:03 djm Exp $ */ + /* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 2005-2020 Damien Miller. All rights reserved. +@@ -56,6 +56,7 @@ + #ifdef HAVE_PATHS_H + # include + #include ++#include + #endif + #ifdef SSH_TUN_OPENBSD + #include +@@ -2695,6 +2696,12 @@ subprocess(const char *tag, const char *command, + } + closefrom(STDERR_FILENO + 1); + ++ if (geteuid() == 0 && ++ initgroups(pw->pw_name, pw->pw_gid) == -1) { ++ error("%s: initgroups(%s, %u): %s", tag, ++ pw->pw_name, (u_int)pw->pw_gid, strerror(errno)); ++ _exit(1); ++ } + if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { + error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, + strerror(errno)); diff --git a/sources b/sources index cbbba40..d393884 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (openssh-8.6p1.tar.gz) = 9854eda0b773c64c9f1f74844ce466b2b42ee8845f58ad062b73141d617af944fa4ebafdf72069f400106d2c2bd0a69c92fe805ec1fc26d4f0faadf06c3fbbe6 -SHA512 (openssh-8.6p1.tar.gz.asc) = ea75d7fe350fd1761ee5490b222249e9b8915b2a02a1d41979195f15d239def387e4c6467362ab9515d517087750fa66bc368f5baa15c325502f725172631967 +SHA512 (openssh-8.7p1.tar.gz) = 08c81024d9e1248abfda6cc874886ff5ae916669b93cd6aff640e0614ee8cbcbc3fe87a9ce47136b6443ddbb1168b114367c74e117551905994e1a7e3fa2c0c2 +SHA512 (openssh-8.7p1.tar.gz.asc) = 08b4bda855ca3ef202c271f1c0e3486082b93d1009a794d020e7ba223978bc87bf34b1fbccaae3379a47639bd849935fdaaf63bdb781d0a44625066ccf00fbfc SHA512 (gpgkey-736060BA.gpg) = df44f3fdbcd1d596705348c7f5aed3f738c5f626a55955e0642f7c6c082995cf36a1b1891bb41b8715cb2aff34fef1c877e0eff0d3507dd00a055ba695757a21