From 2d0df78df5c6474b7a042342740f5e088c9ecd83 Mon Sep 17 00:00:00 2001 From: Lu zhiping Date: Thu, 16 Jun 2022 16:57:14 +0800 Subject: [PATCH] changed debian/source/format to native --- .../patches/authorized-keys-man-symlink.patch | 26 - debian/patches/conch-old-privkey-format.patch | 68 - debian/patches/debian-banner.patch | 163 - debian/patches/debian-config.patch | 270 -- debian/patches/dnssec-sshfp.patch | 94 - debian/patches/doc-hash-tab-completion.patch | 28 - debian/patches/gnome-ssh-askpass2-icon.patch | 26 - debian/patches/gssapi.patch | 3983 ----------------- debian/patches/keepalive-extensions.patch | 135 - .../mention-ssh-keygen-on-keychange.patch | 44 - .../patches/no-openssl-version-status.patch | 62 - debian/patches/openbsd-docs.patch | 148 - debian/patches/package-versioning.patch | 47 - debian/patches/restore-authorized_keys2.patch | 35 - debian/patches/restore-tcp-wrappers.patch | 172 - debian/patches/revert-ipqos-defaults.patch | 93 - debian/patches/scp-quoting.patch | 41 - debian/patches/selinux-role.patch | 472 -- debian/patches/series | 25 - debian/patches/shell-path.patch | 39 - debian/patches/ssh-agent-setgid.patch | 40 - debian/patches/ssh-argv0.patch | 31 - debian/patches/ssh-vulnkey-compat.patch | 42 - debian/patches/syslog-level-silent.patch | 47 - debian/patches/systemd-readiness.patch | 84 - debian/patches/user-group-modes.patch | 210 - debian/source/format | 2 +- 27 files changed, 1 insertion(+), 6426 deletions(-) delete mode 100644 debian/patches/authorized-keys-man-symlink.patch delete mode 100644 debian/patches/conch-old-privkey-format.patch delete mode 100644 debian/patches/debian-banner.patch delete mode 100644 debian/patches/debian-config.patch delete mode 100644 debian/patches/dnssec-sshfp.patch delete mode 100644 debian/patches/doc-hash-tab-completion.patch delete mode 100644 debian/patches/gnome-ssh-askpass2-icon.patch delete mode 100644 debian/patches/gssapi.patch delete mode 100644 debian/patches/keepalive-extensions.patch delete mode 100644 debian/patches/mention-ssh-keygen-on-keychange.patch delete mode 100644 debian/patches/no-openssl-version-status.patch delete mode 100644 debian/patches/openbsd-docs.patch delete mode 100644 debian/patches/package-versioning.patch delete mode 100644 debian/patches/restore-authorized_keys2.patch delete mode 100644 debian/patches/restore-tcp-wrappers.patch delete mode 100644 debian/patches/revert-ipqos-defaults.patch delete mode 100644 debian/patches/scp-quoting.patch delete mode 100644 debian/patches/selinux-role.patch delete mode 100644 debian/patches/series delete mode 100644 debian/patches/shell-path.patch delete mode 100644 debian/patches/ssh-agent-setgid.patch delete mode 100644 debian/patches/ssh-argv0.patch delete mode 100644 debian/patches/ssh-vulnkey-compat.patch delete mode 100644 debian/patches/syslog-level-silent.patch delete mode 100644 debian/patches/systemd-readiness.patch delete mode 100644 debian/patches/user-group-modes.patch diff --git a/debian/patches/authorized-keys-man-symlink.patch b/debian/patches/authorized-keys-man-symlink.patch deleted file mode 100644 index 43a160a..0000000 --- a/debian/patches/authorized-keys-man-symlink.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b0cb3badf4d423f8ea7bf950e55ca72878cc224b Mon Sep 17 00:00:00 2001 -From: Tomas Pospisek -Date: Sun, 9 Feb 2014 16:10:07 +0000 -Subject: Install authorized_keys(5) as a symlink to sshd(8) - -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1720 -Bug-Debian: http://bugs.debian.org/441817 -Last-Update: 2013-09-14 - -Patch-Name: authorized-keys-man-symlink.patch ---- - Makefile.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Makefile.in b/Makefile.in -index b68c1710f..bff1db49b 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -402,6 +402,7 @@ install-files: - $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 - $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5 - $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 -+ ln -s ../$(mansubdir)8/sshd.8 $(DESTDIR)$(mandir)/$(mansubdir)5/authorized_keys.5 - $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 - $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 - $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 diff --git a/debian/patches/conch-old-privkey-format.patch b/debian/patches/conch-old-privkey-format.patch deleted file mode 100644 index c48220f..0000000 --- a/debian/patches/conch-old-privkey-format.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 39d3bb41ec288e8ba2384c65248440603f65349c Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Thu, 30 Aug 2018 00:58:56 +0100 -Subject: Work around conch interoperability failure - -Twisted Conch fails to read private keys in the new format -(https://twistedmatrix.com/trac/ticket/9515). Work around this until it -can be fixed in Twisted. - -Forwarded: not-needed -Last-Update: 2019-10-09 - -Patch-Name: conch-old-privkey-format.patch ---- - regress/Makefile | 2 +- - regress/conch-ciphers.sh | 2 +- - regress/test-exec.sh | 12 ++++++++++++ - 3 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/regress/Makefile b/regress/Makefile -index 774c10d41..01e257a94 100644 ---- a/regress/Makefile -+++ b/regress/Makefile -@@ -120,7 +120,7 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ - 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 \ -- ssh-rsa_oldfmt \ -+ ssh-rsa_oldfmt ssh-rsa_oldfmt.pub \ - ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \ - ssh_proxy_envpass sshd.log sshd_config sshd_config_minimal \ - sshd_config.* sshd_proxy sshd_proxy.* sshd_proxy_bak \ -diff --git a/regress/conch-ciphers.sh b/regress/conch-ciphers.sh -index 6678813a2..6ff5da20b 100644 ---- a/regress/conch-ciphers.sh -+++ b/regress/conch-ciphers.sh -@@ -16,7 +16,7 @@ for c in aes256-ctr aes256-cbc aes192-ctr aes192-cbc aes128-ctr aes128-cbc \ - rm -f ${COPY} - # XXX the 2nd "cat" seems to be needed because of buggy FD handling - # in conch -- ${CONCH} --identity $OBJ/ssh-rsa --port $PORT --user $USER -e none \ -+ ${CONCH} --identity $OBJ/ssh-rsa_oldfmt --port $PORT --user $USER -e none \ - --known-hosts $OBJ/known_hosts --notty --noagent --nox11 -n \ - 127.0.0.1 "cat ${DATA}" 2>/dev/null | cat > ${COPY} - if [ $? -ne 0 ]; then -diff --git a/regress/test-exec.sh b/regress/test-exec.sh -index f5e3ee6f5..a3a40719f 100644 ---- a/regress/test-exec.sh -+++ b/regress/test-exec.sh -@@ -573,6 +573,18 @@ REGRESS_INTEROP_CONCH=no - if test -x "$CONCH" ; then - REGRESS_INTEROP_CONCH=yes - fi -+case "$SCRIPT" in -+*conch*) ;; -+*) REGRESS_INTEROP_CONCH=no -+esac -+ -+if test "$REGRESS_INTEROP_CONCH" = "yes" ; then -+ # Convert rsa key to old format to work around -+ # https://twistedmatrix.com/trac/ticket/9515 -+ cp $OBJ/ssh-rsa $OBJ/ssh-rsa_oldfmt -+ cp $OBJ/ssh-rsa.pub $OBJ/ssh-rsa_oldfmt.pub -+ ${SSHKEYGEN} -p -N '' -m PEM -f $OBJ/ssh-rsa_oldfmt >/dev/null -+fi - - # If PuTTY is present and we are running a PuTTY test, prepare keys and - # configuration diff --git a/debian/patches/debian-banner.patch b/debian/patches/debian-banner.patch deleted file mode 100644 index 0d998fd..0000000 --- a/debian/patches/debian-banner.patch +++ /dev/null @@ -1,163 +0,0 @@ -From 7d20d00ea24ec0c3fffacc80ab271d0699d198c6 Mon Sep 17 00:00:00 2001 -From: Kees Cook -Date: Sun, 9 Feb 2014 16:10:06 +0000 -Subject: Add DebianBanner server configuration option - -Setting this to "no" causes sshd to omit the Debian revision from its -initial protocol handshake, for those scared by package-versioning.patch. - -Bug-Debian: http://bugs.debian.org/562048 -Forwarded: not-needed -Last-Update: 2020-02-21 - -Patch-Name: debian-banner.patch ---- - kex.c | 5 +++-- - kex.h | 2 +- - servconf.c | 9 +++++++++ - servconf.h | 2 ++ - sshconnect.c | 2 +- - sshd.c | 3 ++- - sshd_config.5 | 5 +++++ - 7 files changed, 23 insertions(+), 5 deletions(-) - -diff --git a/kex.c b/kex.c -index f638942d3..2abfbb95a 100644 ---- a/kex.c -+++ b/kex.c -@@ -1226,7 +1226,7 @@ send_error(struct ssh *ssh, char *msg) - */ - int - kex_exchange_identification(struct ssh *ssh, int timeout_ms, -- const char *version_addendum) -+ int debian_banner, const char *version_addendum) - { - int remote_major, remote_minor, mismatch; - size_t len, i, n; -@@ -1244,7 +1244,8 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, - 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_RELEASE, -+ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, -+ debian_banner ? SSH_RELEASE : SSH_RELEASE_MINIMUM, - version_addendum == NULL ? "" : " ", - version_addendum == NULL ? "" : version_addendum)) != 0) { - error("%s: sshbuf_putf: %s", __func__, ssh_err(r)); -diff --git a/kex.h b/kex.h -index fe7141414..938dca03b 100644 ---- a/kex.h -+++ b/kex.h -@@ -194,7 +194,7 @@ char *kex_names_cat(const char *, const char *); - int kex_assemble_names(char **, const char *, const char *); - int kex_gss_names_valid(const char *); - --int kex_exchange_identification(struct ssh *, int, const char *); -+int kex_exchange_identification(struct ssh *, int, int, const char *); - - struct kex *kex_new(void); - int kex_ready(struct ssh *, char *[PROPOSAL_MAX]); -diff --git a/servconf.c b/servconf.c -index bf3cd84a4..7bbc25c2e 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -194,6 +194,7 @@ initialize_server_options(ServerOptions *options) - options->fingerprint_hash = -1; - options->disable_forwarding = -1; - options->expose_userauth_info = -1; -+ options->debian_banner = -1; - } - - /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ -@@ -468,6 +469,8 @@ fill_default_server_options(ServerOptions *options) - options->expose_userauth_info = 0; - if (options->sk_provider == NULL) - options->sk_provider = xstrdup("internal"); -+ if (options->debian_banner == -1) -+ options->debian_banner = 1; - - assemble_algorithms(options); - -@@ -556,6 +559,7 @@ typedef enum { - sStreamLocalBindMask, sStreamLocalBindUnlink, - sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, - sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, -+ sDebianBanner, - sDeprecated, sIgnore, sUnsupported - } ServerOpCodes; - -@@ -719,6 +723,7 @@ static struct { - { "rdomain", sRDomain, SSHCFG_ALL }, - { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, - { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, -+ { "debianbanner", sDebianBanner, SSHCFG_GLOBAL }, - { NULL, sBadOption, 0 } - }; - -@@ -2382,6 +2387,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, - *charptr = xstrdup(arg); - break; - -+ case sDebianBanner: -+ intptr = &options->debian_banner; -+ goto parse_flag; -+ - case sDeprecated: - case sIgnore: - case sUnsupported: -diff --git a/servconf.h b/servconf.h -index 3f47ea25e..3fa05fcac 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -221,6 +221,8 @@ typedef struct { - int expose_userauth_info; - u_int64_t timing_secret; - char *sk_provider; -+ -+ int debian_banner; - } ServerOptions; - - /* Information about the incoming connection as used by Match */ -diff --git a/sshconnect.c b/sshconnect.c -index b796d3c8a..9f2412e0d 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -1292,7 +1292,7 @@ ssh_login(struct ssh *ssh, Sensitive *sensitive, const char *orighost, - lowercase(host); - - /* Exchange protocol version identification strings with the server. */ -- if (kex_exchange_identification(ssh, timeout_ms, NULL) != 0) -+ if (kex_exchange_identification(ssh, timeout_ms, 1, NULL) != 0) - cleanup_exit(255); /* error already logged */ - - /* Put the connection into non-blocking mode. */ -diff --git a/sshd.c b/sshd.c -index 65916fc6d..da876a900 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2187,7 +2187,8 @@ main(int ac, char **av) - if (!debug_flag) - alarm(options.login_grace_time); - -- if (kex_exchange_identification(ssh, -1, options.version_addendum) != 0) -+ if (kex_exchange_identification(ssh, -1, options.debian_banner, -+ options.version_addendum) != 0) - cleanup_exit(255); /* error already logged */ - - ssh_packet_set_nonblocking(ssh); -diff --git a/sshd_config.5 b/sshd_config.5 -index ebd09f891..c926f584c 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -542,6 +542,11 @@ or - .Cm no . - The default is - .Cm yes . -+.It Cm DebianBanner -+Specifies whether the distribution-specified extra version suffix is -+included during initial protocol handshake. -+The default is -+.Cm yes . - .It Cm DenyGroups - This keyword can be followed by a list of group name patterns, separated - by spaces. diff --git a/debian/patches/debian-config.patch b/debian/patches/debian-config.patch deleted file mode 100644 index 35c71b0..0000000 --- a/debian/patches/debian-config.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 8086961f9f4ad834e9c3b09b6e2c80273be1c506 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:18 +0000 -Subject: Various Debian-specific configuration changes - -ssh: Enable ForwardX11Trusted, returning to earlier semantics which cause -fewer problems with existing setups (http://bugs.debian.org/237021). - -ssh: Set 'SendEnv LANG LC_*' by default (http://bugs.debian.org/264024). - -ssh: Enable HashKnownHosts by default to try to limit the spread of ssh -worms. - -ssh: Enable GSSAPIAuthentication by default. - -ssh: Include /etc/ssh/ssh_config.d/*.conf. - -sshd: Enable PAM, disable ChallengeResponseAuthentication, and disable -PrintMotd. - -sshd: Enable X11Forwarding. - -sshd: Set 'AcceptEnv LANG LC_*' by default. - -sshd: Change sftp subsystem path to /usr/lib/openssh/sftp-server. - -sshd: Include /etc/ssh/sshd_config.d/*.conf. - -Document all of this. - -Author: Russ Allbery -Forwarded: not-needed -Last-Update: 2020-02-21 - -Patch-Name: debian-config.patch ---- - readconf.c | 2 +- - ssh.1 | 24 ++++++++++++++++++++++++ - ssh_config | 8 +++++++- - ssh_config.5 | 26 +++++++++++++++++++++++++- - sshd_config | 18 ++++++++++++------ - sshd_config.5 | 29 +++++++++++++++++++++++++++++ - 6 files changed, 98 insertions(+), 9 deletions(-) - -diff --git a/readconf.c b/readconf.c -index 7f251dd4a..e82024678 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -2087,7 +2087,7 @@ fill_default_options(Options * options) - if (options->forward_x11 == -1) - options->forward_x11 = 0; - if (options->forward_x11_trusted == -1) -- options->forward_x11_trusted = 0; -+ options->forward_x11_trusted = 1; - if (options->forward_x11_timeout == -1) - options->forward_x11_timeout = 1200; - /* -diff --git a/ssh.1 b/ssh.1 -index b33a8049f..a8967c2f8 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -809,6 +809,16 @@ directive in - .Xr ssh_config 5 - for more information. - .Pp -+(Debian-specific: X11 forwarding is not subjected to X11 SECURITY extension -+restrictions by default, because too many programs currently crash in this -+mode. -+Set the -+.Cm ForwardX11Trusted -+option to -+.Dq no -+to restore the upstream behaviour. -+This may change in future depending on client-side improvements.) -+.Pp - .It Fl x - Disables X11 forwarding. - .Pp -@@ -817,6 +827,20 @@ Enables trusted X11 forwarding. - Trusted X11 forwardings are not subjected to the X11 SECURITY extension - controls. - .Pp -+(Debian-specific: In the default configuration, this option is equivalent to -+.Fl X , -+since -+.Cm ForwardX11Trusted -+defaults to -+.Dq yes -+as described above. -+Set the -+.Cm ForwardX11Trusted -+option to -+.Dq no -+to restore the upstream behaviour. -+This may change in future depending on client-side improvements.) -+.Pp - .It Fl y - Send log information using the - .Xr syslog 3 -diff --git a/ssh_config b/ssh_config -index 1ff999b68..8a55237b9 100644 ---- a/ssh_config -+++ b/ssh_config -@@ -17,9 +17,12 @@ - # list of available options, their meanings and defaults, please see the - # ssh_config(5) man page. - --# Host * -+Include /etc/ssh/ssh_config.d/*.conf -+ -+Host * - # ForwardAgent no - # ForwardX11 no -+# ForwardX11Trusted yes - # PasswordAuthentication yes - # HostbasedAuthentication no - # GSSAPIAuthentication no -@@ -45,3 +48,6 @@ - # VisualHostKey no - # ProxyCommand ssh -q -W %h:%p gateway.example.com - # RekeyLimit 1G 1h -+ SendEnv LANG LC_* -+ HashKnownHosts yes -+ GSSAPIAuthentication yes -diff --git a/ssh_config.5 b/ssh_config.5 -index c6eaa63e7..34dc2d51b 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -71,6 +71,29 @@ Since the first obtained value for each parameter is used, more - host-specific declarations should be given near the beginning of the - file, and general defaults at the end. - .Pp -+Note that the Debian -+.Ic openssh-client -+package sets several options as standard in -+.Pa /etc/ssh/ssh_config -+which are not the default in -+.Xr ssh 1 : -+.Pp -+.Bl -bullet -offset indent -compact -+.It -+.Cm Include /etc/ssh/ssh_config.d/*.conf -+.It -+.Cm SendEnv No LANG LC_* -+.It -+.Cm HashKnownHosts No yes -+.It -+.Cm GSSAPIAuthentication No yes -+.El -+.Pp -+.Pa /etc/ssh/ssh_config.d/*.conf -+files are included at the start of the system-wide configuration file, so -+options set there will override those in -+.Pa /etc/ssh/ssh_config. -+.Pp - The file contains keyword-argument pairs, one per line. - Lines starting with - .Ql # -@@ -729,11 +752,12 @@ elapsed. - .It Cm ForwardX11Trusted - If this option is set to - .Cm yes , -+(the Debian-specific default), - remote X11 clients will have full access to the original X11 display. - .Pp - If this option is set to - .Cm no --(the default), -+(the upstream default), - remote X11 clients will be considered untrusted and prevented - from stealing or tampering with data belonging to trusted X11 - clients. -diff --git a/sshd_config b/sshd_config -index 2c48105f8..459c1b230 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -10,6 +10,8 @@ - # possible, but leave them commented. Uncommented options override the - # default value. - -+Include /etc/ssh/sshd_config.d/*.conf -+ - #Port 22 - #AddressFamily any - #ListenAddress 0.0.0.0 -@@ -57,8 +59,9 @@ AuthorizedKeysFile .ssh/authorized_keys - #PasswordAuthentication yes - #PermitEmptyPasswords no - --# Change to no to disable s/key passwords --#ChallengeResponseAuthentication yes -+# Change to yes to enable challenge-response passwords (beware issues with -+# some PAM modules and threads) -+ChallengeResponseAuthentication no - - # Kerberos options - #KerberosAuthentication no -@@ -81,16 +84,16 @@ 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'. --#UsePAM no -+UsePAM yes - - #AllowAgentForwarding yes - #AllowTcpForwarding yes - #GatewayPorts no --#X11Forwarding no -+X11Forwarding yes - #X11DisplayOffset 10 - #X11UseLocalhost yes - #PermitTTY yes --#PrintMotd yes -+PrintMotd no - #PrintLastLog yes - #TCPKeepAlive yes - #PermitUserEnvironment no -@@ -107,8 +110,11 @@ AuthorizedKeysFile .ssh/authorized_keys - # no default banner path - #Banner none - -+# Allow client to pass locale environment variables -+AcceptEnv LANG LC_* -+ - # override default of no subsystems --Subsystem sftp /usr/libexec/sftp-server -+Subsystem sftp /usr/lib/openssh/sftp-server - - # Example of overriding settings on a per-user basis - #Match User anoncvs -diff --git a/sshd_config.5 b/sshd_config.5 -index 25f4b8117..e8271be74 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -56,6 +56,35 @@ Arguments may optionally be enclosed in double quotes - .Pq \&" - in order to represent arguments containing spaces. - .Pp -+Note that the Debian -+.Ic openssh-server -+package sets several options as standard in -+.Pa /etc/ssh/sshd_config -+which are not the default in -+.Xr sshd 8 : -+.Pp -+.Bl -bullet -offset indent -compact -+.It -+.Cm Include /etc/ssh/sshd_config.d/*.conf -+.It -+.Cm ChallengeResponseAuthentication No no -+.It -+.Cm X11Forwarding No yes -+.It -+.Cm PrintMotd No no -+.It -+.Cm AcceptEnv No LANG LC_* -+.It -+.Cm Subsystem No sftp /usr/lib/openssh/sftp-server -+.It -+.Cm UsePAM No yes -+.El -+.Pp -+.Pa /etc/ssh/sshd_config.d/*.conf -+files are included at the start of the configuration file, so options set -+there will override those in -+.Pa /etc/ssh/sshd_config. -+.Pp - The possible - keywords and their meanings are as follows (note that - keywords are case-insensitive and arguments are case-sensitive): diff --git a/debian/patches/dnssec-sshfp.patch b/debian/patches/dnssec-sshfp.patch deleted file mode 100644 index 3744218..0000000 --- a/debian/patches/dnssec-sshfp.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 74c1c0ef7689ea68dc8263f73c00ff8675f9f0fe Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:01 +0000 -Subject: Force use of DNSSEC even if "options edns0" isn't in resolv.conf - -This allows SSHFP DNS records to be verified if glibc 2.11 is installed. - -Origin: vendor, https://cvs.fedoraproject.org/viewvc/F-12/openssh/openssh-5.2p1-edns.patch?revision=1.1&view=markup -Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049 -Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=572049 -Last-Update: 2010-04-06 - -Patch-Name: dnssec-sshfp.patch ---- - dns.c | 14 +++++++++++++- - openbsd-compat/getrrsetbyname.c | 10 +++++----- - openbsd-compat/getrrsetbyname.h | 3 +++ - 3 files changed, 21 insertions(+), 6 deletions(-) - -diff --git a/dns.c b/dns.c -index e4f9bf830..9c9fe6413 100644 ---- a/dns.c -+++ b/dns.c -@@ -210,6 +210,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, - { - u_int counter; - int result; -+ unsigned int rrset_flags = 0; - struct rrsetinfo *fingerprints = NULL; - - u_int8_t hostkey_algorithm; -@@ -233,8 +234,19 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, - return -1; - } - -+ /* -+ * Original getrrsetbyname function, found on OpenBSD for example, -+ * doesn't accept any flag and prerequisite for obtaining AD bit in -+ * DNS response is set by "options edns0" in resolv.conf. -+ * -+ * Our version is more clever and use RRSET_FORCE_EDNS0 flag. -+ */ -+#ifndef HAVE_GETRRSETBYNAME -+ rrset_flags |= RRSET_FORCE_EDNS0; -+#endif - result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, -- DNS_RDATATYPE_SSHFP, 0, &fingerprints); -+ DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints); -+ - if (result) { - verbose("DNS lookup error: %s", dns_result_totext(result)); - return -1; -diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c -index dc6fe0533..e061a290a 100644 ---- a/openbsd-compat/getrrsetbyname.c -+++ b/openbsd-compat/getrrsetbyname.c -@@ -209,8 +209,8 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, - goto fail; - } - -- /* don't allow flags yet, unimplemented */ -- if (flags) { -+ /* Allow RRSET_FORCE_EDNS0 flag only. */ -+ if ((flags & !RRSET_FORCE_EDNS0) != 0) { - result = ERRSET_INVAL; - goto fail; - } -@@ -226,9 +226,9 @@ getrrsetbyname(const char *hostname, unsigned int rdclass, - #endif /* DEBUG */ - - #ifdef RES_USE_DNSSEC -- /* turn on DNSSEC if EDNS0 is configured */ -- if (_resp->options & RES_USE_EDNS0) -- _resp->options |= RES_USE_DNSSEC; -+ /* turn on DNSSEC if required */ -+ if (flags & RRSET_FORCE_EDNS0) -+ _resp->options |= (RES_USE_EDNS0|RES_USE_DNSSEC); - #endif /* RES_USE_DNSEC */ - - /* make query */ -diff --git a/openbsd-compat/getrrsetbyname.h b/openbsd-compat/getrrsetbyname.h -index 1283f5506..dbbc85a2a 100644 ---- a/openbsd-compat/getrrsetbyname.h -+++ b/openbsd-compat/getrrsetbyname.h -@@ -72,6 +72,9 @@ - #ifndef RRSET_VALIDATED - # define RRSET_VALIDATED 1 - #endif -+#ifndef RRSET_FORCE_EDNS0 -+# define RRSET_FORCE_EDNS0 0x0001 -+#endif - - /* - * Return codes for getrrsetbyname() diff --git a/debian/patches/doc-hash-tab-completion.patch b/debian/patches/doc-hash-tab-completion.patch deleted file mode 100644 index b0faea7..0000000 --- a/debian/patches/doc-hash-tab-completion.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a14ddfc3f607b0bf29046bfb4b26a6d827fa58c7 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:11 +0000 -Subject: Document that HashKnownHosts may break tab-completion - -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1727 -Bug-Debian: http://bugs.debian.org/430154 -Last-Update: 2013-09-14 - -Patch-Name: doc-hash-tab-completion.patch ---- - ssh_config.5 | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ssh_config.5 b/ssh_config.5 -index e61a0fd43..c6eaa63e7 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -848,6 +848,9 @@ Note that existing names and addresses in known hosts files - will not be converted automatically, - but may be manually hashed using - .Xr ssh-keygen 1 . -+Use of this option may break facilities such as tab-completion that rely -+on being able to read unhashed host names from -+.Pa ~/.ssh/known_hosts . - .It Cm HostbasedAuthentication - Specifies whether to try rhosts based authentication with public key - authentication. diff --git a/debian/patches/gnome-ssh-askpass2-icon.patch b/debian/patches/gnome-ssh-askpass2-icon.patch deleted file mode 100644 index 35b3707..0000000 --- a/debian/patches/gnome-ssh-askpass2-icon.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 63da84c3570afb4fa6bab38fdac3e9af45d0ec54 Mon Sep 17 00:00:00 2001 -From: Vincent Untz -Date: Sun, 9 Feb 2014 16:10:16 +0000 -Subject: Give the ssh-askpass-gnome window a default icon - -Bug-Ubuntu: https://bugs.launchpad.net/bugs/27152 -Last-Update: 2010-02-28 - -Patch-Name: gnome-ssh-askpass2-icon.patch ---- - contrib/gnome-ssh-askpass2.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c -index bc83a2d67..88cdfaeff 100644 ---- a/contrib/gnome-ssh-askpass2.c -+++ b/contrib/gnome-ssh-askpass2.c -@@ -233,6 +233,8 @@ main(int argc, char **argv) - - gtk_init(&argc, &argv); - -+ gtk_window_set_default_icon_from_file ("/usr/share/pixmaps/ssh-askpass-gnome.png", NULL); -+ - if (argc > 1) { - message = g_strjoinv(" ", argv + 1); - } else { diff --git a/debian/patches/gssapi.patch b/debian/patches/gssapi.patch deleted file mode 100644 index 4bf1d3f..0000000 --- a/debian/patches/gssapi.patch +++ /dev/null @@ -1,3983 +0,0 @@ -From 34aff3aa136e5a65f441b25811dd466488fda087 Mon Sep 17 00:00:00 2001 -From: Simon Wilkinson -Date: Sun, 9 Feb 2014 16:09:48 +0000 -Subject: GSSAPI key exchange support - -This patch has been rejected upstream: "None of the OpenSSH developers are -in favour of adding this, and this situation has not changed for several -years. This is not a slight on Simon's patch, which is of fine quality, but -just that a) we don't trust GSSAPI implementations that much and b) we don't -like adding new KEX since they are pre-auth attack surface. This one is -particularly scary, since it requires hooks out to typically root-owned -system resources." - -However, quite a lot of people rely on this in Debian, and it's better to -have it merged into the main openssh package rather than having separate --krb5 packages (as we used to have). It seems to have a generally good -security history. - -Origin: other, https://github.com/openssh-gsskex/openssh-gsskex/commits/debian/master -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1242 -Last-Updated: 2020-02-21 - -Patch-Name: gssapi.patch ---- - Makefile.in | 3 +- - README.md | 33 +++ - auth.c | 96 +------- - auth2-gss.c | 56 ++++- - auth2.c | 2 + - canohost.c | 93 ++++++++ - canohost.h | 3 + - clientloop.c | 15 +- - configure.ac | 24 ++ - gss-genr.c | 300 +++++++++++++++++++++++- - gss-serv-krb5.c | 85 ++++++- - gss-serv.c | 186 +++++++++++++-- - kex.c | 66 +++++- - kex.h | 29 +++ - kexdh.c | 10 + - kexgen.c | 2 +- - kexgssc.c | 606 ++++++++++++++++++++++++++++++++++++++++++++++++ - kexgsss.c | 474 +++++++++++++++++++++++++++++++++++++ - monitor.c | 139 ++++++++++- - monitor.h | 2 + - monitor_wrap.c | 57 ++++- - monitor_wrap.h | 4 +- - readconf.c | 70 ++++++ - readconf.h | 6 + - servconf.c | 47 ++++ - servconf.h | 3 + - session.c | 10 +- - ssh-gss.h | 50 +++- - ssh.1 | 8 + - ssh.c | 6 +- - ssh_config | 2 + - ssh_config.5 | 57 +++++ - sshconnect2.c | 142 +++++++++++- - sshd.c | 62 ++++- - sshd_config | 2 + - sshd_config.5 | 30 +++ - sshkey.c | 3 +- - sshkey.h | 1 + - 38 files changed, 2624 insertions(+), 160 deletions(-) - create mode 100644 kexgssc.c - create mode 100644 kexgsss.c - -diff --git a/Makefile.in b/Makefile.in -index e7549470c..b68c1710f 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -109,6 +109,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ - kexgexc.o kexgexs.o \ - sntrup4591761.o kexsntrup4591761x25519.o kexgen.o \ -+ kexgssc.o \ - sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o - -@@ -125,7 +126,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ - auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ - 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 \ -+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff --git a/README.md b/README.md -index 28fb43d2a..5b73d24c0 100644 ---- a/README.md -+++ b/README.md -@@ -1,3 +1,36 @@ -+Portable OpenSSH with GSSAPI Key Exchange patches -+================================================= -+ -+Currently, there are two branches with gssapi key exchange related -+patches: -+ -+ * fedora/master: Changes that are shipped in Fedora -+ * debian/master: Changes that are shipped in Debian -+ -+The target is to converge to a shared repository with single master -+branch from where we could build releases for both OSes. -+ -+ -+What is in: -+ -+ * The original patch implementing missing parts of RFC4462 by Simon Wilkinson -+ adapted to the current OpenSSH versions and with several fixes -+ * New methods for GSSAPI Kex from IETF draft [1] from Jakub Jelen -+ -+ -+Missing kerberos-related parts: -+ -+ * .k5login and .kusers support available in Fedora [2] [3]. -+ * Improved handling of kerberos ccache location [4] -+ -+ -+[1] https://tools.ietf.org/html/draft-ietf-curdle-gss-keyex-sha2-08 -+[2] https://src.fedoraproject.org/rpms/openssh/blob/master/f/openssh-6.6p1-kuserok.patch -+[3] https://src.fedoraproject.org/rpms/openssh/blob/master/f/openssh-6.6p1-GSSAPIEnablek5users.patch -+[4] https://bugzilla.mindrot.org/show_bug.cgi?id=2775 -+ -+------------------------------------------------------------------------------- -+ - # Portable OpenSSH - - [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh) -diff --git a/auth.c b/auth.c -index 086b8ebb1..687c57b42 100644 ---- a/auth.c -+++ b/auth.c -@@ -400,7 +400,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) - case PERMIT_NO_PASSWD: - if (strcmp(method, "publickey") == 0 || - strcmp(method, "hostbased") == 0 || -- strcmp(method, "gssapi-with-mic") == 0) -+ strcmp(method, "gssapi-with-mic") == 0 || -+ strcmp(method, "gssapi-keyex") == 0) - return 1; - break; - case PERMIT_FORCED_ONLY: -@@ -724,99 +725,6 @@ fakepw(void) - return (&fake); - } - --/* -- * 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?) -- */ -- --static char * --remote_hostname(struct ssh *ssh) --{ -- struct sockaddr_storage from; -- socklen_t fromlen; -- struct addrinfo hints, *ai, *aitop; -- char name[NI_MAXHOST], ntop2[NI_MAXHOST]; -- const char *ntop = ssh_remote_ipaddr(ssh); -- -- /* Get IP address of client. */ -- fromlen = sizeof(from); -- memset(&from, 0, sizeof(from)); -- if (getpeername(ssh_packet_get_connection_in(ssh), -- (struct sockaddr *)&from, &fromlen) == -1) { -- debug("getpeername failed: %.100s", strerror(errno)); -- return xstrdup(ntop); -- } -- -- ipv64_normalise_mapped(&from, &fromlen); -- if (from.ss_family == AF_INET6) -- fromlen = sizeof(struct sockaddr_in6); -- -- debug3("Trying to reverse map address %.100s.", ntop); -- /* Map the IP address to a host name. */ -- if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), -- NULL, 0, NI_NAMEREQD) != 0) { -- /* Host name not found. Use ip address. */ -- return xstrdup(ntop); -- } -- -- /* -- * if reverse lookup result looks like a numeric hostname, -- * someone is trying to trick us by PTR record like following: -- * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_socktype = SOCK_DGRAM; /*dummy*/ -- hints.ai_flags = AI_NUMERICHOST; -- if (getaddrinfo(name, NULL, &hints, &ai) == 0) { -- logit("Nasty PTR record \"%s\" is set up for %s, ignoring", -- name, ntop); -- freeaddrinfo(ai); -- return xstrdup(ntop); -- } -- -- /* Names are stored in lowercase. */ -- lowercase(name); -- -- /* -- * Map it back to an IP address and check that the given -- * address actually is an address of this host. This is -- * necessary because anyone with access to a name server can -- * define arbitrary names for an IP address. Mapping from -- * name to IP address can be trusted better (but can still be -- * fooled if the intruder has access to the name server of -- * the domain). -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_family = from.ss_family; -- hints.ai_socktype = SOCK_STREAM; -- if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { -- logit("reverse mapping checking getaddrinfo for %.700s " -- "[%s] failed.", name, ntop); -- return xstrdup(ntop); -- } -- /* Look for the address from the list of addresses. */ -- for (ai = aitop; ai; ai = ai->ai_next) { -- if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, -- sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && -- (strcmp(ntop, ntop2) == 0)) -- break; -- } -- freeaddrinfo(aitop); -- /* If we reached the end of the list, the address was not there. */ -- if (ai == NULL) { -- /* Address not found for the host name. */ -- logit("Address %.100s maps to %.600s, but this does not " -- "map back to the address.", ntop, name); -- return xstrdup(ntop); -- } -- 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 -diff --git a/auth2-gss.c b/auth2-gss.c -index 9351e0428..d6446c0cf 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: auth2-gss.c,v 1.29 2018/07/31 03:10:27 djm Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -54,6 +54,48 @@ 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); - static int input_gssapi_errtok(int, u_int32_t, struct ssh *); - -+/* -+ * The 'gssapi_keyex' userauth mechanism. -+ */ -+static int -+userauth_gsskeyex(struct ssh *ssh) -+{ -+ Authctxt *authctxt = ssh->authctxt; -+ int r, authenticated = 0; -+ struct sshbuf *b = NULL; -+ gss_buffer_desc mic, gssbuf; -+ u_char *p; -+ size_t len; -+ -+ if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("%s: %s", __func__, ssh_err(r)); -+ -+ if ((b = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ mic.value = p; -+ mic.length = len; -+ -+ ssh_gssapi_buildmic(b, authctxt->user, authctxt->service, -+ "gssapi-keyex"); -+ -+ if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) -+ fatal("%s: sshbuf_mutable_ptr failed", __func__); -+ gssbuf.length = sshbuf_len(b); -+ -+ /* 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)); -+ -+ sshbuf_free(b); -+ free(mic.value); -+ -+ return (authenticated); -+} -+ - /* - * We only support those mechanisms that we know about (ie ones that we know - * how to check local user kuserok and the like) -@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) - if ((r = sshpkt_get_end(ssh)) != 0) - fatal("%s: %s", __func__, ssh_err(r)); - -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); - - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -306,7 +349,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) - gssbuf.length = sshbuf_len(b); - - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0)); - else - logit("GSSAPI MIC check failed"); - -@@ -326,6 +370,12 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) - return 0; - } - -+Authmethod method_gsskeyex = { -+ "gssapi-keyex", -+ userauth_gsskeyex, -+ &options.gss_authentication -+}; -+ - Authmethod method_gssapi = { - "gssapi-with-mic", - userauth_gssapi, -diff --git a/auth2.c b/auth2.c -index 0e7762242..1c217268c 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -73,6 +73,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -80,6 +81,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - &method_passwd, -diff --git a/canohost.c b/canohost.c -index abea9c6e6..8e81b5193 100644 ---- a/canohost.c -+++ b/canohost.c -@@ -35,6 +35,99 @@ - #include "canohost.h" - #include "misc.h" - -+/* -+ * 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?) -+ */ -+ -+char * -+remote_hostname(struct ssh *ssh) -+{ -+ struct sockaddr_storage from; -+ socklen_t fromlen; -+ struct addrinfo hints, *ai, *aitop; -+ char name[NI_MAXHOST], ntop2[NI_MAXHOST]; -+ const char *ntop = ssh_remote_ipaddr(ssh); -+ -+ /* Get IP address of client. */ -+ fromlen = sizeof(from); -+ memset(&from, 0, sizeof(from)); -+ if (getpeername(ssh_packet_get_connection_in(ssh), -+ (struct sockaddr *)&from, &fromlen) == -1) { -+ debug("getpeername failed: %.100s", strerror(errno)); -+ return xstrdup(ntop); -+ } -+ -+ ipv64_normalise_mapped(&from, &fromlen); -+ if (from.ss_family == AF_INET6) -+ fromlen = sizeof(struct sockaddr_in6); -+ -+ debug3("Trying to reverse map address %.100s.", ntop); -+ /* Map the IP address to a host name. */ -+ if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), -+ NULL, 0, NI_NAMEREQD) != 0) { -+ /* Host name not found. Use ip address. */ -+ return xstrdup(ntop); -+ } -+ -+ /* -+ * if reverse lookup result looks like a numeric hostname, -+ * someone is trying to trick us by PTR record like following: -+ * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 -+ */ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/ -+ hints.ai_flags = AI_NUMERICHOST; -+ if (getaddrinfo(name, NULL, &hints, &ai) == 0) { -+ logit("Nasty PTR record \"%s\" is set up for %s, ignoring", -+ name, ntop); -+ freeaddrinfo(ai); -+ return xstrdup(ntop); -+ } -+ -+ /* Names are stored in lowercase. */ -+ lowercase(name); -+ -+ /* -+ * Map it back to an IP address and check that the given -+ * address actually is an address of this host. This is -+ * necessary because anyone with access to a name server can -+ * define arbitrary names for an IP address. Mapping from -+ * name to IP address can be trusted better (but can still be -+ * fooled if the intruder has access to the name server of -+ * the domain). -+ */ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_family = from.ss_family; -+ hints.ai_socktype = SOCK_STREAM; -+ if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { -+ logit("reverse mapping checking getaddrinfo for %.700s " -+ "[%s] failed.", name, ntop); -+ return xstrdup(ntop); -+ } -+ /* Look for the address from the list of addresses. */ -+ for (ai = aitop; ai; ai = ai->ai_next) { -+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, -+ sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && -+ (strcmp(ntop, ntop2) == 0)) -+ break; -+ } -+ freeaddrinfo(aitop); -+ /* If we reached the end of the list, the address was not there. */ -+ if (ai == NULL) { -+ /* Address not found for the host name. */ -+ logit("Address %.100s maps to %.600s, but this does not " -+ "map back to the address.", ntop, name); -+ return xstrdup(ntop); -+ } -+ return xstrdup(name); -+} -+ - void - ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) - { -diff --git a/canohost.h b/canohost.h -index 26d62855a..0cadc9f18 100644 ---- a/canohost.h -+++ b/canohost.h -@@ -15,6 +15,9 @@ - #ifndef _CANOHOST_H - #define _CANOHOST_H - -+struct ssh; -+ -+char *remote_hostname(struct ssh *); - char *get_peer_ipaddr(int); - int get_peer_port(int); - char *get_local_ipaddr(int); -diff --git a/clientloop.c b/clientloop.c -index ebd0dbca1..1bdac6a46 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -112,6 +112,10 @@ - #include "ssherr.h" - #include "hostfile.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* import options */ - extern Options options; - -@@ -1379,9 +1383,18 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, - break; - - /* Do channel operations unless rekeying in progress. */ -- if (!ssh_packet_is_rekeying(ssh)) -+ if (!ssh_packet_is_rekeying(ssh)) { - channel_after_select(ssh, readset, writeset); - -+#ifdef GSSAPI -+ if (options.gss_renewal_rekey && -+ ssh_gssapi_credentials_updated(NULL)) { -+ debug("credentials updated - forcing rekey"); -+ need_rekeying = 1; -+ } -+#endif -+ } -+ - /* Buffer input from the connection. */ - client_process_net_input(ssh, readset); - -diff --git a/configure.ac b/configure.ac -index b689db4b5..efafb6bd8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) - [Use tunnel device compatibility to OpenBSD]) - AC_DEFINE([SSH_TUN_PREPEND_AF], [1], - [Prepend the address family to IP tunnel traffic]) -+ AC_MSG_CHECKING([if we have the Security Authorization Session API]) -+ AC_TRY_COMPILE([#include ], -+ [SessionCreate(0, 0);], -+ [ac_cv_use_security_session_api="yes" -+ AC_DEFINE([USE_SECURITY_SESSION_API], [1], -+ [platform has the Security Authorization Session API]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT([yes])], -+ [ac_cv_use_security_session_api="no" -+ AC_MSG_RESULT([no])]) -+ AC_MSG_CHECKING([if we have an in-memory credentials cache]) -+ AC_TRY_COMPILE( -+ [#include ], -+ [cc_context_t c; -+ (void) cc_initialize (&c, 0, NULL, NULL);], -+ [AC_DEFINE([USE_CCAPI], [1], -+ [platform uses an in-memory credentials cache]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT([yes]) -+ if test "x$ac_cv_use_security_session_api" = "xno"; then -+ AC_MSG_ERROR([*** Need a security framework to use the credentials cache API ***]) -+ fi], -+ [AC_MSG_RESULT([no])] -+ ) - m4_pattern_allow([AU_IPv]) - AC_CHECK_DECL([AU_IPv4], [], - AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) -diff --git a/gss-genr.c b/gss-genr.c -index d56257b4a..763a63ffa 100644 ---- a/gss-genr.c -+++ b/gss-genr.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-genr.c,v 1.26 2018/07/10 09:13:30 djm Exp $ */ - - /* -- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -41,12 +41,36 @@ - #include "sshbuf.h" - #include "log.h" - #include "ssh2.h" -+#include "cipher.h" -+#include "sshkey.h" -+#include "kex.h" -+#include "digest.h" -+#include "packet.h" - - #include "ssh-gss.h" - - extern u_char *session_id2; - extern u_int session_id2_len; - -+typedef struct { -+ char *encoded; -+ gss_OID oid; -+} ssh_gss_kex_mapping; -+ -+/* -+ * XXX - It would be nice to find a more elegant way of handling the -+ * XXX passing of the key exchange context to the userauth routines -+ */ -+ -+Gssctxt *gss_kex_context = NULL; -+ -+static ssh_gss_kex_mapping *gss_enc2oid = NULL; -+ -+int -+ssh_gssapi_oid_table_ok(void) { -+ return (gss_enc2oid != NULL); -+} -+ - /* sshbuf_get for gss_buffer_desc */ - int - ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) -@@ -62,6 +86,162 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) - return 0; - } - -+/* sshpkt_get of gss_buffer_desc */ -+int -+ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *ssh, gss_buffer_desc *g) -+{ -+ int r; -+ u_char *p; -+ size_t len; -+ -+ if ((r = sshpkt_get_string(ssh, &p, &len)) != 0) -+ return r; -+ g->value = p; -+ g->length = len; -+ return 0; -+} -+ -+/* -+ * Return a list of the gss-group1-sha1 mechanisms supported by this program -+ * -+ * We test mechanisms to ensure that we can use them, to avoid starting -+ * a key exchange with a bad mechanism -+ */ -+ -+char * -+ssh_gssapi_client_mechanisms(const char *host, const char *client, -+ const char *kex) { -+ gss_OID_set gss_supported = NULL; -+ OM_uint32 min_status; -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) -+ return NULL; -+ -+ return ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, -+ host, client, kex); -+} -+ -+char * -+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, -+ const char *host, const char *client, const char *kex) { -+ struct sshbuf *buf = NULL; -+ size_t i; -+ int r = SSH_ERR_ALLOC_FAIL; -+ int oidpos, enclen; -+ char *mechs, *encoded; -+ u_char digest[SSH_DIGEST_MAX_LENGTH]; -+ char deroid[2]; -+ struct ssh_digest_ctx *md = NULL; -+ char *s, *cp, *p; -+ -+ if (gss_enc2oid != NULL) { -+ for (i = 0; gss_enc2oid[i].encoded != NULL; i++) -+ free(gss_enc2oid[i].encoded); -+ free(gss_enc2oid); -+ } -+ -+ gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping) * -+ (gss_supported->count + 1)); -+ -+ if ((buf = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ oidpos = 0; -+ s = cp = xstrdup(kex); -+ for (i = 0; i < gss_supported->count; i++) { -+ if (gss_supported->elements[i].length < 128 && -+ (*check)(NULL, &(gss_supported->elements[i]), host, client)) { -+ -+ deroid[0] = SSH_GSS_OIDTYPE; -+ deroid[1] = gss_supported->elements[i].length; -+ -+ if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || -+ (r = ssh_digest_update(md, deroid, 2)) != 0 || -+ (r = ssh_digest_update(md, -+ gss_supported->elements[i].elements, -+ gss_supported->elements[i].length)) != 0 || -+ (r = ssh_digest_final(md, digest, sizeof(digest))) != 0) -+ fatal("%s: digest failed: %s", __func__, -+ ssh_err(r)); -+ ssh_digest_free(md); -+ md = NULL; -+ -+ encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5) -+ * 2); -+ enclen = __b64_ntop(digest, -+ ssh_digest_bytes(SSH_DIGEST_MD5), encoded, -+ ssh_digest_bytes(SSH_DIGEST_MD5) * 2); -+ -+ cp = strncpy(s, kex, strlen(kex)); -+ for ((p = strsep(&cp, ",")); p && *p != '\0'; -+ (p = strsep(&cp, ","))) { -+ if (sshbuf_len(buf) != 0 && -+ (r = sshbuf_put_u8(buf, ',')) != 0) -+ fatal("%s: sshbuf_put_u8 error: %s", -+ __func__, ssh_err(r)); -+ if ((r = sshbuf_put(buf, p, strlen(p))) != 0 || -+ (r = sshbuf_put(buf, encoded, enclen)) != 0) -+ fatal("%s: sshbuf_put error: %s", -+ __func__, ssh_err(r)); -+ } -+ -+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); -+ gss_enc2oid[oidpos].encoded = encoded; -+ oidpos++; -+ } -+ } -+ free(s); -+ gss_enc2oid[oidpos].oid = NULL; -+ gss_enc2oid[oidpos].encoded = NULL; -+ -+ if ((mechs = sshbuf_dup_string(buf)) == NULL) -+ fatal("%s: sshbuf_dup_string failed", __func__); -+ -+ sshbuf_free(buf); -+ -+ if (strlen(mechs) == 0) { -+ free(mechs); -+ mechs = NULL; -+ } -+ -+ return (mechs); -+} -+ -+gss_OID -+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int kex_type) { -+ int i = 0; -+ -+#define SKIP_KEX_NAME(type) \ -+ case type: \ -+ if (strlen(name) < sizeof(type##_ID)) \ -+ return GSS_C_NO_OID; \ -+ name += sizeof(type##_ID) - 1; \ -+ break; -+ -+ switch (kex_type) { -+ SKIP_KEX_NAME(KEX_GSS_GRP1_SHA1) -+ SKIP_KEX_NAME(KEX_GSS_GRP14_SHA1) -+ SKIP_KEX_NAME(KEX_GSS_GRP14_SHA256) -+ SKIP_KEX_NAME(KEX_GSS_GRP16_SHA512) -+ SKIP_KEX_NAME(KEX_GSS_GEX_SHA1) -+ SKIP_KEX_NAME(KEX_GSS_NISTP256_SHA256) -+ SKIP_KEX_NAME(KEX_GSS_C25519_SHA256) -+ default: -+ return GSS_C_NO_OID; -+ } -+ -+#undef SKIP_KEX_NAME -+ -+ while (gss_enc2oid[i].encoded != NULL && -+ strcmp(name, gss_enc2oid[i].encoded) != 0) -+ i++; -+ -+ if (gss_enc2oid[i].oid != NULL && ctx != NULL) -+ ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid); -+ -+ return gss_enc2oid[i].oid; -+} -+ - /* Check that the OID in a data stream matches that in the context */ - int - ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) -@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, - } - - ctx->major = gss_init_sec_context(&ctx->minor, -- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, -+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid, - GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, - 0, NULL, recv_tok, NULL, send_tok, flags, NULL); - -@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) - return (ctx->major); - } - -+OM_uint32 -+ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) -+{ -+ gss_buffer_desc gssbuf; -+ gss_name_t gssname; -+ OM_uint32 status; -+ gss_OID_set oidset; -+ -+ gssbuf.value = (void *) name; -+ gssbuf.length = strlen(gssbuf.value); -+ -+ gss_create_empty_oid_set(&status, &oidset); -+ gss_add_oid_set_member(&status, ctx->oid, &oidset); -+ -+ ctx->major = gss_import_name(&ctx->minor, &gssbuf, -+ GSS_C_NT_USER_NAME, &gssname); -+ -+ if (!ctx->major) -+ ctx->major = gss_acquire_cred(&ctx->minor, -+ gssname, 0, oidset, GSS_C_INITIATE, -+ &ctx->client_creds, NULL, NULL); -+ -+ gss_release_name(&status, &gssname); -+ gss_release_oid_set(&status, &oidset); -+ -+ if (ctx->major) -+ ssh_gssapi_error(ctx); -+ -+ return(ctx->major); -+} -+ - OM_uint32 - ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) - { -+ if (ctx == NULL) -+ return -1; -+ - if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, - GSS_C_QOP_DEFAULT, buffer, hash))) - ssh_gssapi_error(ctx); -@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) - return (ctx->major); - } - -+/* Priviledged when used by server */ -+OM_uint32 -+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+{ -+ if (ctx == NULL) -+ return -1; -+ -+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -+ gssbuf, gssmic, NULL); -+ -+ return (ctx->major); -+} -+ - void - ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, - const char *context) -@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, - } - - int --ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) -+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, -+ const char *client) - { - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - OM_uint32 major, minor; - gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; -+ Gssctxt *intctx = NULL; -+ -+ if (ctx == NULL) -+ ctx = &intctx; - - /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) - ssh_gssapi_build_ctx(ctx); - ssh_gssapi_set_oid(*ctx, oid); - major = ssh_gssapi_import_name(*ctx, host); -+ -+ if (!GSS_ERROR(major) && client) -+ major = ssh_gssapi_client_identity(*ctx, client); -+ - if (!GSS_ERROR(major)) { - major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, - NULL); -@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) - GSS_C_NO_BUFFER); - } - -- if (GSS_ERROR(major)) -+ if (GSS_ERROR(major) || intctx != NULL) - ssh_gssapi_delete_ctx(ctx); - - return (!GSS_ERROR(major)); - } - -+int -+ssh_gssapi_credentials_updated(Gssctxt *ctxt) { -+ static gss_name_t saved_name = GSS_C_NO_NAME; -+ static OM_uint32 saved_lifetime = 0; -+ static gss_OID saved_mech = GSS_C_NO_OID; -+ static gss_name_t name; -+ static OM_uint32 last_call = 0; -+ OM_uint32 lifetime, now, major, minor; -+ int equal; -+ -+ now = time(NULL); -+ -+ if (ctxt) { -+ debug("Rekey has happened - updating saved versions"); -+ -+ if (saved_name != GSS_C_NO_NAME) -+ gss_release_name(&minor, &saved_name); -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &saved_name, &saved_lifetime, NULL, NULL); -+ -+ if (!GSS_ERROR(major)) { -+ saved_mech = ctxt->oid; -+ saved_lifetime+= now; -+ } else { -+ /* Handle the error */ -+ } -+ return 0; -+ } -+ -+ if (now - last_call < 10) -+ return 0; -+ -+ last_call = now; -+ -+ if (saved_mech == GSS_C_NO_OID) -+ return 0; -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &name, &lifetime, NULL, NULL); -+ if (major == GSS_S_CREDENTIALS_EXPIRED) -+ return 0; -+ else if (GSS_ERROR(major)) -+ return 0; -+ -+ major = gss_compare_name(&minor, saved_name, name, &equal); -+ gss_release_name(&minor, &name); -+ if (GSS_ERROR(major)) -+ return 0; -+ -+ if (equal && (saved_lifetime < lifetime + now - 10)) -+ return 1; -+ -+ return 0; -+} -+ - #endif /* GSSAPI */ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a151bc1e4..ef9beb67c 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -120,8 +120,8 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - krb5_error_code problem; - krb5_principal princ; - OM_uint32 maj_status, min_status; -- int len; - const char *errmsg; -+ const char *new_ccname; - - if (client->creds == NULL) { - debug("No credentials stored"); -@@ -180,11 +180,16 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_ccname = krb5_cc_get_name(krb_context, ccache); -+ - client->store.envvar = "KRB5CCNAME"; -- len = strlen(client->store.filename) + 6; -- client->store.envval = xmalloc(len); -- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); -+#ifdef USE_CCAPI -+ xasprintf(&client->store.envval, "API:%s", new_ccname); -+ client->store.filename = NULL; -+#else -+ xasprintf(&client->store.envval, "FILE:%s", new_ccname); -+ client->store.filename = xstrdup(new_ccname); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -196,6 +201,71 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - return; - } - -+int -+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client) -+{ -+ krb5_ccache ccache = NULL; -+ krb5_principal principal = NULL; -+ char *name = NULL; -+ krb5_error_code problem; -+ OM_uint32 maj_status, min_status; -+ -+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { -+ logit("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ return 0; -+ } -+ -+ /* Find out who the principal in this cache is */ -+ if ((problem = krb5_cc_get_principal(krb_context, ccache, -+ &principal))) { -+ logit("krb5_cc_get_principal(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { -+ logit("krb5_unparse_name(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ -+ if (strcmp(name,client->exportedname.value)!=0) { -+ debug("Name in local credentials cache differs. Not storing"); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ krb5_free_unparsed_name(krb_context, name); -+ return 0; -+ } -+ krb5_free_unparsed_name(krb_context, name); -+ -+ /* Name matches, so lets get on with it! */ -+ -+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { -+ logit("krb5_cc_initialize(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ krb5_free_principal(krb_context, principal); -+ -+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, -+ ccache))) { -+ logit("gss_krb5_copy_ccache() failed. Sorry!"); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ return 1; -+} -+ - ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", -@@ -203,7 +273,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { - NULL, - &ssh_gssapi_krb5_userok, - NULL, -- &ssh_gssapi_krb5_storecreds -+ &ssh_gssapi_krb5_storecreds, -+ &ssh_gssapi_krb5_updatecreds - }; - - #endif /* KRB5 */ -diff --git a/gss-serv.c b/gss-serv.c -index ab3a15f0f..1d47870e7 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv.c,v 1.31 2018/07/09 21:37:55 markus Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -44,17 +44,19 @@ - #include "session.h" - #include "misc.h" - #include "servconf.h" -+#include "uidswap.h" - - #include "ssh-gss.h" -+#include "monitor_wrap.h" - - extern ServerOptions options; - - static ssh_gssapi_client gssapi_client = -- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, -- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; -+ { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, -+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; - - ssh_gssapi_mech gssapi_null_mech = -- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; -+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; - - #ifdef KRB5 - extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) - return (ssh_gssapi_acquire_cred(*ctx)); - } - -+/* Unprivileged */ -+char * -+ssh_gssapi_server_mechanisms(void) { -+ if (supported_oids == NULL) -+ ssh_gssapi_prepare_supported_oids(); -+ return (ssh_gssapi_kex_mechs(supported_oids, -+ &ssh_gssapi_server_check_mech, NULL, NULL, -+ options.gss_kex_algorithms)); -+} -+ -+/* Unprivileged */ -+int -+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, -+ const char *dummy) { -+ Gssctxt *ctx = NULL; -+ int res; -+ -+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); -+ ssh_gssapi_delete_ctx(&ctx); -+ -+ return (res); -+} -+ - /* Unprivileged */ - void - ssh_gssapi_supported_oids(gss_OID_set *oidset) -@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) - gss_OID_set supported; - - gss_create_empty_oid_set(&min_status, oidset); -- gss_indicate_mechs(&min_status, &supported); -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) -+ return; - - while (supported_mechs[i]->name != NULL) { - if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -276,8 +303,48 @@ OM_uint32 - ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - { - int i = 0; -+ int equal = 0; -+ gss_name_t new_name = GSS_C_NO_NAME; -+ 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, -+ 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, -+ NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ ctx->major = gss_compare_name(&ctx->minor, client->name, -+ new_name, &equal); -+ -+ if (GSS_ERROR(ctx->major)) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ if (!equal) { -+ debug("Rekeyed credentials have different name"); -+ return GSS_S_COMPLETE; -+ } - -- gss_buffer_desc ename; -+ debug("Marking rekeyed credentials for export"); -+ -+ gss_release_name(&ctx->minor, &client->name); -+ gss_release_cred(&ctx->minor, &client->creds); -+ client->name = new_name; -+ client->creds = ctx->client_creds; -+ ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ client->updated = 1; -+ return GSS_S_COMPLETE; -+ } - - client->mech = NULL; - -@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ if (ctx->client_creds && -+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ - if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, - &client->displayname, NULL))) { - ssh_gssapi_error(ctx); -@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - 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; -@@ -356,19 +432,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) - - /* Privileged */ - int --ssh_gssapi_userok(char *user) -+ssh_gssapi_userok(char *user, struct passwd *pw, int kex) - { - OM_uint32 lmin; - -+ (void) kex; /* used in privilege separation */ -+ - if (gssapi_client.exportedname.length == 0 || - gssapi_client.exportedname.value == NULL) { - debug("No suitable client data"); - return 0; - } - if (gssapi_client.mech && gssapi_client.mech->userok) -- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) -+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { -+ gssapi_client.used = 1; -+ gssapi_client.store.owner = pw; - return 1; -- else { -+ } else { - /* Destroy delegated credentials if userok fails */ - gss_release_buffer(&lmin, &gssapi_client.displayname); - gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -382,14 +462,90 @@ ssh_gssapi_userok(char *user) - return (0); - } - --/* Privileged */ --OM_uint32 --ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+/* These bits are only used for rekeying. The unpriviledged child is running -+ * as the user, the monitor is root. -+ * -+ * In the child, we want to : -+ * *) Ask the monitor to store our credentials into the store we specify -+ * *) If it succeeds, maybe do a PAM update -+ */ -+ -+/* Stuff for PAM */ -+ -+#ifdef USE_PAM -+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, -+ struct pam_response **resp, void *data) - { -- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -- gssbuf, gssmic, NULL); -+ return (PAM_CONV_ERR); -+} -+#endif - -- return (ctx->major); -+void -+ssh_gssapi_rekey_creds(void) { -+ int ok; -+#ifdef USE_PAM -+ int ret; -+ pam_handle_t *pamh = NULL; -+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; -+ char *envstr; -+#endif -+ -+ if (gssapi_client.store.filename == NULL && -+ gssapi_client.store.envval == NULL && -+ gssapi_client.store.envvar == NULL) -+ return; -+ -+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -+ -+ if (!ok) -+ return; -+ -+ debug("Rekeyed credentials stored successfully"); -+ -+ /* Actually managing to play with the ssh pam stack from here will -+ * be next to impossible. In any case, we may want different options -+ * for rekeying. So, use our own :) -+ */ -+#ifdef USE_PAM -+ if (!use_privsep) { -+ debug("Not even going to try and do PAM with privsep disabled"); -+ return; -+ } -+ -+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, -+ &pamconv, &pamh); -+ if (ret) -+ return; -+ -+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, -+ gssapi_client.store.envval); -+ -+ ret = pam_putenv(pamh, envstr); -+ if (!ret) -+ pam_setcred(pamh, PAM_REINITIALIZE_CRED); -+ pam_end(pamh, PAM_SUCCESS); -+#endif -+} -+ -+int -+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { -+ int ok = 0; -+ -+ /* Check we've got credentials to store */ -+ if (!gssapi_client.updated) -+ return 0; -+ -+ gssapi_client.updated = 0; -+ -+ temporarily_use_uid(gssapi_client.store.owner); -+ if (gssapi_client.mech && gssapi_client.mech->updatecreds) -+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); -+ else -+ debug("No update function for this mechanism"); -+ -+ restore_uid(); -+ -+ return ok; - } - - /* Privileged */ -diff --git a/kex.c b/kex.c -index ce85f0439..574c76093 100644 ---- a/kex.c -+++ b/kex.c -@@ -57,11 +57,16 @@ - #include "misc.h" - #include "dispatch.h" - #include "monitor.h" -+#include "xmalloc.h" - - #include "ssherr.h" - #include "sshbuf.h" - #include "digest.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* prototype */ - static int kex_choose_conf(struct ssh *); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); -@@ -115,15 +120,28 @@ static const struct kexalg kexalgs[] = { - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1}, - }; -+static const struct kexalg gss_kexalgs[] = { -+#ifdef GSSAPI -+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, -+ { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, -+#endif -+ { NULL, 0, -1, -1}, -+}; - --char * --kex_alg_list(char sep) -+static char * -+kex_alg_list_internal(char sep, const struct kexalg *algs) - { - char *ret = NULL, *tmp; - size_t nlen, rlen = 0; - const struct kexalg *k; - -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = algs; k->name != NULL; k++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(k->name); -@@ -138,6 +156,18 @@ kex_alg_list(char sep) - return ret; - } - -+char * -+kex_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, kexalgs); -+} -+ -+char * -+kex_gss_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, gss_kexalgs); -+} -+ - static const struct kexalg * - kex_alg_by_name(const char *name) - { -@@ -147,6 +177,10 @@ kex_alg_by_name(const char *name) - if (strcmp(k->name, name) == 0) - return k; - } -+ for (k = gss_kexalgs; k->name != NULL; k++) { -+ if (strncmp(k->name, name, strlen(k->name)) == 0) -+ return k; -+ } - return NULL; - } - -@@ -315,6 +349,29 @@ kex_assemble_names(char **listp, const char *def, const char *all) - return r; - } - -+/* Validate GSS KEX method name list */ -+int -+kex_gss_names_valid(const char *names) -+{ -+ char *s, *cp, *p; -+ -+ if (names == NULL || *names == '\0') -+ return 0; -+ s = cp = xstrdup(names); -+ for ((p = strsep(&cp, ",")); p && *p != '\0'; -+ (p = strsep(&cp, ","))) { -+ if (strncmp(p, "gss-", 4) != 0 -+ || kex_alg_by_name(p) == NULL) { -+ error("Unsupported KEX algorithm \"%.100s\"", p); -+ free(s); -+ return 0; -+ } -+ } -+ debug3("gss kex names ok: [%s]", names); -+ free(s); -+ return 1; -+} -+ - /* put algorithm proposal into buffer */ - int - kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) -@@ -698,6 +755,9 @@ kex_free(struct kex *kex) - sshbuf_free(kex->server_version); - sshbuf_free(kex->client_pub); - free(kex->session_id); -+#ifdef GSSAPI -+ free(kex->gss_host); -+#endif /* GSSAPI */ - free(kex->failed_choice); - free(kex->hostkey_alg); - free(kex->name); -diff --git a/kex.h b/kex.h -index a5ae6ac05..fe7141414 100644 ---- a/kex.h -+++ b/kex.h -@@ -102,6 +102,15 @@ enum kex_exchange { - KEX_ECDH_SHA2, - KEX_C25519_SHA256, - KEX_KEM_SNTRUP4591761X25519_SHA512, -+#ifdef GSSAPI -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GRP14_SHA256, -+ KEX_GSS_GRP16_SHA512, -+ KEX_GSS_GEX_SHA1, -+ KEX_GSS_NISTP256_SHA256, -+ KEX_GSS_C25519_SHA256, -+#endif - KEX_MAX - }; - -@@ -153,6 +162,12 @@ struct kex { - u_int flags; - int hash_alg; - int ec_nid; -+#ifdef GSSAPI -+ int gss_deleg_creds; -+ int gss_trust_dns; -+ char *gss_host; -+ char *gss_client; -+#endif - char *failed_choice; - int (*verify_host_key)(struct sshkey *, struct ssh *); - struct sshkey *(*load_host_public_key)(int, int, struct ssh *); -@@ -174,8 +189,10 @@ struct kex { - - int kex_names_valid(const char *); - char *kex_alg_list(char); -+char *kex_gss_alg_list(char); - char *kex_names_cat(const char *, const char *); - int kex_assemble_names(char **, const char *, const char *); -+int kex_gss_names_valid(const char *); - - int kex_exchange_identification(struct ssh *, int, const char *); - -@@ -202,6 +219,12 @@ int kexgex_client(struct ssh *); - int kexgex_server(struct ssh *); - int kex_gen_client(struct ssh *); - int kex_gen_server(struct ssh *); -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+int kexgssgex_client(struct ssh *); -+int kexgssgex_server(struct ssh *); -+int kexgss_client(struct ssh *); -+int kexgss_server(struct ssh *); -+#endif - - int kex_dh_keypair(struct kex *); - int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, -@@ -234,6 +257,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, - const BIGNUM *, const u_char *, size_t, - u_char *, size_t *); - -+int kex_gen_hash(int hash_alg, const struct sshbuf *client_version, -+ const struct sshbuf *server_version, const struct sshbuf *client_kexinit, -+ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob, -+ const struct sshbuf *client_pub, const struct sshbuf *server_pub, -+ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen); -+ - void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -diff --git a/kexdh.c b/kexdh.c -index 67133e339..edaa46762 100644 ---- a/kexdh.c -+++ b/kexdh.c -@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex) - { - switch (kex->kex_type) { - case KEX_DH_GRP1_SHA1: -+#ifdef GSSAPI -+ case KEX_GSS_GRP1_SHA1: -+#endif - kex->dh = dh_new_group1(); - break; - case KEX_DH_GRP14_SHA1: - case KEX_DH_GRP14_SHA256: -+#ifdef GSSAPI -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+#endif - kex->dh = dh_new_group14(); - break; - case KEX_DH_GRP16_SHA512: -+#ifdef GSSAPI -+ case KEX_GSS_GRP16_SHA512: -+#endif - kex->dh = dh_new_group16(); - break; - case KEX_DH_GRP18_SHA512: -diff --git a/kexgen.c b/kexgen.c -index 69348b964..c0e8c2f44 100644 ---- a/kexgen.c -+++ b/kexgen.c -@@ -44,7 +44,7 @@ - static int input_kex_gen_init(int, u_int32_t, struct ssh *); - static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh); - --static int -+int - kex_gen_hash( - int hash_alg, - const struct sshbuf *client_version, -diff --git a/kexgssc.c b/kexgssc.c -new file mode 100644 -index 000000000..f6e1405eb ---- /dev/null -+++ b/kexgssc.c -@@ -0,0 +1,606 @@ -+/* -+ * Copyright (c) 2001-2009 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" -+ -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ -+#include "includes.h" -+ -+#include -+#include -+ -+#include -+ -+#include "xmalloc.h" -+#include "sshbuf.h" -+#include "ssh2.h" -+#include "sshkey.h" -+#include "cipher.h" -+#include "kex.h" -+#include "log.h" -+#include "packet.h" -+#include "dh.h" -+#include "digest.h" -+#include "ssherr.h" -+ -+#include "ssh-gss.h" -+ -+int -+kexgss_client(struct ssh *ssh) -+{ -+ struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, -+ gssbuf, msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *server_blob = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *empty = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ u_char c; -+ int r; -+ -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); -+ -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); -+ -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); -+ -+ /* Step 1 */ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_keypair(kex); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ r = kex_ecdh_keypair(kex); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ r = kex_c25519_keypair(kex); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ if (r != 0) -+ return r; -+ -+ token_ptr = GSS_C_NO_BUFFER; -+ -+ do { -+ debug("Calling gss_init_sec_context"); -+ -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); -+ -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ 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) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); -+ -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } -+ -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("failed to send packet: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ fatal("Failed to read server host key: %s", ssh_err(r)); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("Failed to read message: %s", ssh_err(r)); -+ -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ if ((r = sshpkt_get_end(ssh)) != 0) { -+ fatal("Expecting end of packet."); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt_get failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set server_blob and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* compute shared secret */ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80) -+ fatal("The received key has MSB of last octet set!"); -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ if (sshbuf_len(server_blob) != 65) -+ fatal("The received NIST-P256 key did not match" -+ "expected length (expected 65, got %zu)", sshbuf_len(server_blob)); -+ -+ if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) -+ fatal("The received NIST-P256 key does not have first octet 0x04"); -+ -+ r = kex_ecdh_dec(kex, server_blob, &shared_secret); -+ break; -+ default: -+ r = SSH_ERR_INVALID_ARGUMENT; -+ break; -+ } -+ if (r != 0) -+ goto out; -+ -+ if ((empty = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->client_pub, -+ server_blob, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) -+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); -+ -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+ -+out: -+ explicit_bzero(hash, sizeof(hash)); -+ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); -+ sshbuf_free(empty); -+ sshbuf_free(server_host_key_blob); -+ sshbuf_free(server_blob); -+ sshbuf_free(shared_secret); -+ sshbuf_free(kex->client_pub); -+ kex->client_pub = NULL; -+ return r; -+} -+ -+int -+kexgssgex_client(struct ssh *ssh) -+{ -+ struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, gssbuf, -+ msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ struct sshbuf *buf = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *server_blob = NULL; -+ BIGNUM *dh_server_pub = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ struct sshbuf *empty = NULL; -+ u_char c; -+ int r; -+ -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); -+ -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); -+ -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); -+ -+ debug("Doing group exchange"); -+ nbits = dh_estimate(kex->dh_need * 8); -+ -+ kex->min = DH_GRP_MIN; -+ kex->max = DH_GRP_MAX; -+ kex->nbits = nbits; -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_u32(ssh, nbits)) != 0 || -+ (r = sshpkt_put_u32(ssh, max)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("Failed to construct a packet: %s", ssh_err(r)); -+ -+ if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0) -+ fatal("Error: %s", ssh_err(r)); -+ -+ if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || -+ (r = sshpkt_get_bignum2(ssh, &g)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("shpkt_get_bignum2 failed: %s", ssh_err(r)); -+ -+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) -+ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ min, BN_num_bits(p), max); -+ -+ if ((kex->dh = dh_new_group(g, p)) == NULL) -+ fatal("dn_new_group() failed"); -+ p = g = NULL; /* belong to kex->dh now */ -+ -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ DH_get0_key(kex->dh, &pub_key, NULL); -+ -+ token_ptr = GSS_C_NO_BUFFER; -+ -+ do { -+ /* Step 2 - call GSS_Init_sec_context() */ -+ debug("Calling gss_init_sec_context"); -+ -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); -+ -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ 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) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); -+ -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } -+ -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh,send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt_send failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set dh_server_pub and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* 7. C verifies that the key Q_S is valid */ -+ /* 8. C computes shared secret */ -+ if ((buf = sshbuf_new()) == NULL || -+ (r = sshbuf_put_stringb(buf, server_blob)) != 0 || -+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) -+ goto out; -+ sshbuf_free(buf); -+ buf = NULL; -+ -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) -+ goto out; -+ if ((empty = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->min, kex->nbits, kex->max, -+ dh_p, dh_g, -+ pub_key, -+ dh_server_pub, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("Failed to calculate hash: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) -+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); -+ -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ /* save session id */ -+ if (kex->session_id == NULL) { -+ kex->session_id_len = hashlen; -+ kex->session_id = xmalloc(kex->session_id_len); -+ memcpy(kex->session_id, hash, kex->session_id_len); -+ } -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+out: -+ sshbuf_free(buf); -+ sshbuf_free(server_blob); -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_server_pub); -+ sshbuf_free(shared_secret); -+ sshbuf_free(server_host_key_blob); -+ return r; -+} -+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/kexgsss.c b/kexgsss.c -new file mode 100644 -index 000000000..60bc02deb ---- /dev/null -+++ b/kexgsss.c -@@ -0,0 +1,474 @@ -+/* -+ * Copyright (c) 2001-2009 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" -+ -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ -+#include -+ -+#include -+#include -+ -+#include "xmalloc.h" -+#include "sshbuf.h" -+#include "ssh2.h" -+#include "sshkey.h" -+#include "cipher.h" -+#include "kex.h" -+#include "log.h" -+#include "packet.h" -+#include "dh.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ -+#include "servconf.h" -+#include "ssh-gss.h" -+#include "digest.h" -+#include "ssherr.h" -+ -+extern ServerOptions options; -+ -+int -+kexgss_server(struct ssh *ssh) -+{ -+ struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *client_pubkey = NULL; -+ struct sshbuf *server_pubkey = NULL; -+ struct sshbuf *empty = sshbuf_new(); -+ int type = 0; -+ gss_OID oid; -+ char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ int r; -+ -+ /* Initialise GSSAPI */ -+ -+ /* If we're rekeying, privsep means that some of the private structures -+ * in the GSSAPI code are no longer available. This kludges them back -+ * into life -+ */ -+ if (!ssh_gssapi_oid_table_ok()) { -+ mechs = ssh_gssapi_server_mechanisms(); -+ free(mechs); -+ } -+ -+ debug2("%s: Identifying %s", __func__, kex->name); -+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); -+ if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); -+ -+ debug2("%s: Acquiring credentials", __func__); -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ fatal("Unable to acquire credentials for the server"); -+ -+ do { -+ debug("Wait SSH2_MSG_KEXGSS_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (client_pubkey != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ if (r != 0) -+ goto out; -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (client_pubkey == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); -+ 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)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ 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"); -+ } -+ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual Authentication flag wasn't set"); -+ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity flag wasn't set"); -+ -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ client_pubkey, -+ server_pubkey, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ goto out; -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 || -+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } else { -+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt_send failed: %s", ssh_err(r)); -+ -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ sshbuf_free(shared_secret); -+ sshbuf_free(client_pubkey); -+ sshbuf_free(server_pubkey); -+ return r; -+} -+ -+int -+kexgssgex_server(struct ssh *ssh) -+{ -+ struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ int type = 0; -+ gss_OID oid; -+ char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ BIGNUM *dh_client_pub = NULL; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int min = -1, max = -1, nbits = -1; -+ int cmin = -1, cmax = -1; /* client proposal */ -+ struct sshbuf *empty = sshbuf_new(); -+ int r; -+ -+ /* Initialise GSSAPI */ -+ -+ /* If we're rekeying, privsep means that some of the private structures -+ * in the GSSAPI code are no longer available. This kludges them back -+ * into life -+ */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ free(mechs); -+ -+ debug2("%s: Identifying %s", __func__, kex->name); -+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); -+ if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); -+ -+ debug2("%s: Acquiring credentials", __func__); -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ fatal("Unable to acquire credentials for the server"); -+ -+ /* 5. S generates an ephemeral key pair (do the allocations early) */ -+ debug("Doing group exchange"); -+ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ); -+ /* store client proposal to provide valid signature */ -+ if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 || -+ (r = sshpkt_get_u32(ssh, &nbits)) != 0 || -+ (r = sshpkt_get_u32(ssh, &cmax)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ kex->nbits = nbits; -+ kex->min = cmin; -+ kex->max = cmax; -+ min = MAX(DH_GRP_MIN, cmin); -+ max = MIN(DH_GRP_MAX, cmax); -+ nbits = MAXIMUM(DH_GRP_MIN, nbits); -+ nbits = MINIMUM(DH_GRP_MAX, nbits); -+ if (max < min || nbits < min || max < nbits) -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ kex->dh = PRIVSEP(choose_dh(min, nbits, max)); -+ if (kex->dh == NULL) { -+ sshpkt_disconnect(ssh, "Protocol error: no matching group found"); -+ fatal("Protocol error: no matching group found"); -+ } -+ -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, dh_p)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, dh_g)) != 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)); -+ -+ /* Compute our exchange value in parallel with the client */ -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ -+ do { -+ debug("Wait SSH2_MSG_GSSAPI_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (dh_client_pub != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (dh_client_pub == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); -+ 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)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ 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"); -+ } -+ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual Authentication flag wasn't set"); -+ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity flag wasn't set"); -+ -+ /* calculate shared secret */ -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0) -+ goto out; -+ -+ DH_get0_key(kex->dh, &pub_key, NULL); -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ cmin, nbits, cmax, -+ dh_p, dh_g, -+ dh_client_pub, -+ pub_key, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("kexgex_hash failed: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || -+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } else { -+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_client_pub); -+ sshbuf_free(shared_secret); -+ return r; -+} -+#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/monitor.c b/monitor.c -index 2ce89fe90..ebf76c7f9 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); - int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *); - 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_updatecreds(struct ssh *, int, struct sshbuf *); - #endif - - #ifdef SSH_AUDIT_EVENTS -@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[] = { - {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_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, - #endif - {0, 0, NULL} - }; - - struct mon_table mon_dispatch_postauth20[] = { -+#ifdef GSSAPI -+ {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_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, -+#endif - #ifdef WITH_OPENSSL - {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, - #endif -@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) - /* Permit requests for moduli and signatures */ - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - - /* The first few requests do not require asynchronous access */ - while (!authenticated) { -@@ -406,6 +419,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - - if (auth_opts->permit_pty_flag) { - monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); -@@ -1713,6 +1730,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) - # ifdef OPENSSL_HAS_ECC - kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; -+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; -+ } -+# endif - #endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kex_gen_server; - kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server; -@@ -1806,8 +1834,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) - u_char *p; - int r; - -- if (!options.gss_authentication) -- fatal("%s: GSSAPI authentication not enabled", __func__); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); - - if ((r = sshbuf_get_string(m, &p, &len)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -@@ -1839,8 +1867,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) - OM_uint32 flags = 0; /* GSI needs this */ - int r; - -- if (!options.gss_authentication) -- fatal("%s: GSSAPI authentication not enabled", __func__); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); - - if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -@@ -1860,6 +1888,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); - } - return (0); - } -@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) - OM_uint32 ret; - int r; - -- if (!options.gss_authentication) -- fatal("%s: GSSAPI authentication not enabled", __func__); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); - - if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || - (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) -@@ -1898,13 +1927,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) - int - mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) - { -- int r, authenticated; -+ int r, authenticated, kex; - const char *displayname; - -- if (!options.gss_authentication) -- fatal("%s: GSSAPI authentication not enabled", __func__); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); - -- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); -+ if ((r = sshbuf_get_u32(m, &kex)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ authenticated = authctxt->valid && -+ ssh_gssapi_userok(authctxt->user, authctxt->pw, kex); - - sshbuf_reset(m); - if ((r = sshbuf_put_u32(m, authenticated)) != 0) -@@ -1913,7 +1946,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) - debug3("%s: sending result %d", __func__, authenticated); - mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); - -- auth_method = "gssapi-with-mic"; -+ if (kex) { -+ auth_method = "gssapi-keyex"; -+ } else { -+ auth_method = "gssapi-with-mic"; -+ } - - if ((displayname = ssh_gssapi_displayname()) != NULL) - auth2_record_info(authctxt, "%s", displayname); -@@ -1921,5 +1958,85 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } -+ -+int -+mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m) -+{ -+ gss_buffer_desc data; -+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; -+ OM_uint32 major, minor; -+ size_t len; -+ u_char *p = NULL; -+ int r; -+ -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); -+ -+ if ((r = sshbuf_get_string(m, &p, &len)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ data.value = p; -+ data.length = len; -+ /* Lengths of SHA-1, SHA-256 and SHA-512 hashes that are used */ -+ if (data.length != 20 && data.length != 32 && data.length != 64) -+ fatal("%s: data length incorrect: %d", __func__, -+ (int) data.length); -+ -+ /* Save the session ID on the first time around */ -+ if (session_id2_len == 0) { -+ session_id2_len = data.length; -+ session_id2 = xmalloc(session_id2_len); -+ memcpy(session_id2, data.value, session_id2_len); -+ } -+ major = ssh_gssapi_sign(gsscontext, &data, &hash); -+ -+ free(data.value); -+ -+ sshbuf_reset(m); -+ -+ if ((r = sshbuf_put_u32(m, major)) != 0 || -+ (r = sshbuf_put_string(m, hash.value, hash.length)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSSIGN, m); -+ -+ gss_release_buffer(&minor, &hash); -+ -+ /* Turn on getpwnam permissions */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); -+ -+ /* And credential updating, for when rekeying */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSUPCREDS, 1); -+ -+ return (0); -+} -+ -+int -+mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) { -+ ssh_gssapi_ccache store; -+ int r, ok; -+ -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("%s: GSSAPI not enabled", __func__); -+ -+ if ((r = sshbuf_get_string(m, (u_char **)&store.filename, NULL)) != 0 || -+ (r = sshbuf_get_string(m, (u_char **)&store.envvar, NULL)) != 0 || -+ (r = sshbuf_get_string(m, (u_char **)&store.envval, NULL)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ ok = ssh_gssapi_update_creds(&store); -+ -+ free(store.filename); -+ free(store.envvar); -+ free(store.envval); -+ -+ sshbuf_reset(m); -+ if ((r = sshbuf_put_u32(m, ok)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); -+ -+ return(0); -+} -+ - #endif /* GSSAPI */ - -diff --git a/monitor.h b/monitor.h -index 683e5e071..2b1a2d590 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -63,6 +63,8 @@ enum monitor_reqtype { - MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, - MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, - -+ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, -+ MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, - }; - - struct ssh; -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 001a8fa1c..6edb509a3 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -993,13 +993,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) - } - - int --mm_ssh_gssapi_userok(char *user) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw, int kex) - { - struct sshbuf *m; - int r, authenticated = 0; - - if ((m = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(m, kex)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m); - mm_request_receive_expect(pmonitor->m_recvfd, -@@ -1012,4 +1014,57 @@ mm_ssh_gssapi_userok(char *user) - debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); - return (authenticated); - } -+ -+OM_uint32 -+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) -+{ -+ struct sshbuf *m; -+ OM_uint32 major; -+ int r; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_string(m, data->value, data->length)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, m); -+ -+ if ((r = sshbuf_get_u32(m, &major)) != 0 || -+ (r = ssh_gssapi_get_buffer_desc(m, hash)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ sshbuf_free(m); -+ -+ return (major); -+} -+ -+int -+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) -+{ -+ struct sshbuf *m; -+ int r, ok; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ if ((r = sshbuf_put_cstring(m, -+ store->filename ? store->filename : "")) != 0 || -+ (r = sshbuf_put_cstring(m, -+ store->envvar ? store->envvar : "")) != 0 || -+ (r = sshbuf_put_cstring(m, -+ store->envval ? store->envval : "")) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, m); -+ -+ if ((r = sshbuf_get_u32(m, &ok)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ sshbuf_free(m); -+ -+ return (ok); -+} -+ - #endif /* GSSAPI */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 23ab096aa..485590c18 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -64,8 +64,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, - OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); - OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, - gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); --int mm_ssh_gssapi_userok(char *user); -+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_update_creds(ssh_gssapi_ccache *); - #endif - - #ifdef USE_PAM -diff --git a/readconf.c b/readconf.c -index f3cac6b3a..da8022dd0 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -67,6 +67,7 @@ - #include "uidswap.h" - #include "myproposal.h" - #include "digest.h" -+#include "ssh-gss.h" - - /* Format of the configuration file: - -@@ -160,6 +161,8 @@ typedef enum { - oClearAllForwardings, oNoHostAuthenticationForLocalhost, - oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, - oAddressFamily, oGssAuthentication, oGssDelegateCreds, -+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, -+ oGssServerIdentity, oGssKexAlgorithms, - oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, - oHashKnownHosts, -@@ -204,10 +207,22 @@ static struct { - /* Sometimes-unsupported options */ - #if defined(GSSAPI) - { "gssapiauthentication", oGssAuthentication }, -+ { "gssapikeyexchange", oGssKeyEx }, - { "gssapidelegatecredentials", oGssDelegateCreds }, -+ { "gssapitrustdns", oGssTrustDns }, -+ { "gssapiclientidentity", oGssClientIdentity }, -+ { "gssapiserveridentity", oGssServerIdentity }, -+ { "gssapirenewalforcesrekey", oGssRenewalRekey }, -+ { "gssapikexalgorithms", oGssKexAlgorithms }, - # else - { "gssapiauthentication", oUnsupported }, -+ { "gssapikeyexchange", oUnsupported }, - { "gssapidelegatecredentials", oUnsupported }, -+ { "gssapitrustdns", oUnsupported }, -+ { "gssapiclientidentity", oUnsupported }, -+ { "gssapiserveridentity", oUnsupported }, -+ { "gssapirenewalforcesrekey", oUnsupported }, -+ { "gssapikexalgorithms", oUnsupported }, - #endif - #ifdef ENABLE_PKCS11 - { "pkcs11provider", oPKCS11Provider }, -@@ -1029,10 +1044,42 @@ parse_time: - intptr = &options->gss_authentication; - goto parse_flag; - -+ case oGssKeyEx: -+ intptr = &options->gss_keyex; -+ goto parse_flag; -+ - case oGssDelegateCreds: - intptr = &options->gss_deleg_creds; - goto parse_flag; - -+ case oGssTrustDns: -+ intptr = &options->gss_trust_dns; -+ goto parse_flag; -+ -+ case oGssClientIdentity: -+ charptr = &options->gss_client_identity; -+ goto parse_string; -+ -+ case oGssServerIdentity: -+ charptr = &options->gss_server_identity; -+ goto parse_string; -+ -+ case oGssRenewalRekey: -+ intptr = &options->gss_renewal_rekey; -+ goto parse_flag; -+ -+ case oGssKexAlgorithms: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", -+ filename, linenum); -+ if (!kex_gss_names_valid(arg)) -+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", -+ filename, linenum, arg ? arg : ""); -+ if (*activep && options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = xstrdup(arg); -+ break; -+ - case oBatchMode: - intptr = &options->batch_mode; - goto parse_flag; -@@ -1911,7 +1958,13 @@ initialize_options(Options * options) - options->pubkey_authentication = -1; - options->challenge_response_authentication = -1; - options->gss_authentication = -1; -+ options->gss_keyex = -1; - options->gss_deleg_creds = -1; -+ options->gss_trust_dns = -1; -+ options->gss_renewal_rekey = -1; -+ options->gss_client_identity = NULL; -+ options->gss_server_identity = NULL; -+ options->gss_kex_algorithms = NULL; - 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; - if (options->gss_authentication == -1) - options->gss_authentication = 0; -+ if (options->gss_keyex == -1) -+ options->gss_keyex = 0; - if (options->gss_deleg_creds == -1) - options->gss_deleg_creds = 0; -+ if (options->gss_trust_dns == -1) -+ options->gss_trust_dns = 0; -+ if (options->gss_renewal_rekey == -1) -+ options->gss_renewal_rekey = 0; -+#ifdef GSSAPI -+ if (options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); -+#endif - 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) - dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); - #ifdef GSSAPI - dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); -+ dump_cfg_fmtint(oGssKeyEx, o->gss_keyex); - dump_cfg_fmtint(oGssDelegateCreds, o->gss_deleg_creds); -+ dump_cfg_fmtint(oGssTrustDns, o->gss_trust_dns); -+ dump_cfg_fmtint(oGssRenewalRekey, o->gss_renewal_rekey); -+ dump_cfg_string(oGssClientIdentity, o->gss_client_identity); -+ dump_cfg_string(oGssServerIdentity, o->gss_server_identity); -+ dump_cfg_string(oGssKexAlgorithms, o->gss_kex_algorithms ? -+ o->gss_kex_algorithms : GSS_KEX_DEFAULT_KEX); - #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 feedb3d20..a8a8870d7 100644 ---- a/readconf.h -+++ b/readconf.h -@@ -41,7 +41,13 @@ typedef struct { - int challenge_response_authentication; - /* Try S/Key or TIS, authentication. */ - int gss_authentication; /* Try GSS authentication */ -+ int gss_keyex; /* Try GSS key exchange */ - int gss_deleg_creds; /* Delegate GSS credentials */ -+ int gss_trust_dns; /* Trust DNS for GSS canonicalization */ -+ int gss_renewal_rekey; /* Credential renewal forces rekey */ -+ char *gss_client_identity; /* Principal to initiate GSSAPI with */ -+ char *gss_server_identity; /* GSSAPI target principal */ -+ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ - int password_authentication; /* Try password - * authentication. */ - int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff --git a/servconf.c b/servconf.c -index 70f5f73f0..191575a16 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -69,6 +69,7 @@ - #include "auth.h" - #include "myproposal.h" - #include "digest.h" -+#include "ssh-gss.h" - - static void add_listen_addr(ServerOptions *, const char *, - const char *, int); -@@ -133,8 +134,11 @@ initialize_server_options(ServerOptions *options) - options->kerberos_ticket_cleanup = -1; - options->kerberos_get_afs_token = -1; - options->gss_authentication=-1; -+ options->gss_keyex = -1; - options->gss_cleanup_creds = -1; - options->gss_strict_acceptor = -1; -+ options->gss_store_rekey = -1; -+ 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->kerberos_get_afs_token = 0; - if (options->gss_authentication == -1) - options->gss_authentication = 0; -+ if (options->gss_keyex == -1) -+ options->gss_keyex = 0; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; - if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 1; -+ if (options->gss_store_rekey == -1) -+ options->gss_store_rekey = 0; -+#ifdef GSSAPI -+ if (options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); -+#endif - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -@@ -531,6 +543,7 @@ typedef enum { - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -+ sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, - sAcceptEnv, sSetEnv, sPermitTunnel, - sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -607,12 +620,22 @@ static struct { - #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, -+ { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, - #endif -+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, -+ { "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, - intptr = &options->gss_authentication; - goto parse_flag; - -+ case sGssKeyEx: -+ intptr = &options->gss_keyex; -+ goto parse_flag; -+ - case sGssCleanupCreds: - intptr = &options->gss_cleanup_creds; - goto parse_flag; -@@ -1556,6 +1583,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, - intptr = &options->gss_strict_acceptor; - goto parse_flag; - -+ case sGssStoreRekey: -+ intptr = &options->gss_store_rekey; -+ goto parse_flag; -+ -+ case sGssKexAlgorithms: -+ arg = strdelim(&cp); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", -+ filename, linenum); -+ if (!kex_gss_names_valid(arg)) -+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", -+ filename, linenum, arg ? arg : ""); -+ if (*activep && options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = xstrdup(arg); -+ break; -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -@@ -2777,6 +2820,10 @@ dump_config(ServerOptions *o) - #ifdef GSSAPI - dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); - dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); -+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); -+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); -+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); -+ dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); - #endif - dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); - dump_cfg_fmtint(sKbdInteractiveAuthentication, -diff --git a/servconf.h b/servconf.h -index 4202a2d02..3f47ea25e 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -132,8 +132,11 @@ typedef struct { - int kerberos_get_afs_token; /* If true, try to get AFS token if - * authenticated with Kerberos. */ - int gss_authentication; /* If true, permit GSSAPI authentication */ -+ int gss_keyex; /* If true, permit GSSAPI key exchange */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ - 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. */ - int password_authentication; /* If true, permit password - * authentication. */ - int kbd_interactive_authentication; /* If true, permit */ -diff --git a/session.c b/session.c -index 8c0e54f79..06a33442a 100644 ---- a/session.c -+++ b/session.c -@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) - - #ifdef KRB5 - if (options.kerberos_ticket_cleanup && -- authctxt->krb5_ctx) -+ authctxt->krb5_ctx) { -+ temporarily_use_uid(authctxt->pw); - krb5_cleanup_proc(authctxt); -+ restore_uid(); -+ } - #endif - - #ifdef GSSAPI -- if (options.gss_cleanup_creds) -+ if (options.gss_cleanup_creds) { -+ temporarily_use_uid(authctxt->pw); - ssh_gssapi_cleanup_creds(); -+ restore_uid(); -+ } - #endif - - /* remove agent socket */ -diff --git a/ssh-gss.h b/ssh-gss.h -index 36180d07a..70dd36658 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.14 2018/07/10 09:13:30 djm Exp $ */ - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -61,10 +61,30 @@ - - #define SSH_GSS_OIDTYPE 0x06 - -+#define SSH2_MSG_KEXGSS_INIT 30 -+#define SSH2_MSG_KEXGSS_CONTINUE 31 -+#define SSH2_MSG_KEXGSS_COMPLETE 32 -+#define SSH2_MSG_KEXGSS_HOSTKEY 33 -+#define SSH2_MSG_KEXGSS_ERROR 34 -+#define SSH2_MSG_KEXGSS_GROUPREQ 40 -+#define SSH2_MSG_KEXGSS_GROUP 41 -+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" -+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" -+#define KEX_GSS_GRP14_SHA256_ID "gss-group14-sha256-" -+#define KEX_GSS_GRP16_SHA512_ID "gss-group16-sha512-" -+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" -+#define KEX_GSS_NISTP256_SHA256_ID "gss-nistp256-sha256-" -+#define KEX_GSS_C25519_SHA256_ID "gss-curve25519-sha256-" -+ -+#define GSS_KEX_DEFAULT_KEX \ -+ KEX_GSS_GEX_SHA1_ID "," \ -+ KEX_GSS_GRP14_SHA1_ID -+ - typedef struct { - char *filename; - char *envvar; - char *envval; -+ struct passwd *owner; - void *data; - } ssh_gssapi_ccache; - -@@ -72,8 +92,11 @@ typedef struct { - gss_buffer_desc displayname; - gss_buffer_desc exportedname; - gss_cred_id_t creds; -+ gss_name_t name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ int used; -+ int updated; - } ssh_gssapi_client; - - typedef struct ssh_gssapi_mech_struct { -@@ -84,6 +107,7 @@ typedef struct ssh_gssapi_mech_struct { - int (*userok) (ssh_gssapi_client *, char *); - int (*localname) (ssh_gssapi_client *, char **); - void (*storecreds) (ssh_gssapi_client *); -+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); - } ssh_gssapi_mech; - - typedef struct { -@@ -94,10 +118,11 @@ typedef struct { - gss_OID oid; /* client */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ -- gss_cred_id_t client_creds; /* server */ -+ gss_cred_id_t client_creds; /* both */ - } Gssctxt; - - extern ssh_gssapi_mech *supported_mechs[]; -+extern Gssctxt *gss_kex_context; - - int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); - void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); -@@ -109,6 +134,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *); - - struct sshbuf; - int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *); -+int ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *, gss_buffer_desc *); - - OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *); - OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int, -@@ -123,17 +149,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); - OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_buildmic(struct sshbuf *, const char *, - const char *, const char *); --int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); -+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); -+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); -+int ssh_gssapi_credentials_updated(Gssctxt *); - - /* In the server */ -+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, -+ const char *); -+char *ssh_gssapi_client_mechanisms(const char *, const char *, const char *); -+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, -+ const char *, const char *); -+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); -+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, -+ const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); --int ssh_gssapi_userok(char *name); -+int ssh_gssapi_userok(char *name, struct passwd *, int kex); - OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_do_child(char ***, u_int *); - void ssh_gssapi_cleanup_creds(void); - void ssh_gssapi_storecreds(void); - const char *ssh_gssapi_displayname(void); - -+char *ssh_gssapi_server_mechanisms(void); -+int ssh_gssapi_oid_table_ok(void); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); -+void ssh_gssapi_rekey_creds(void); -+ - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -diff --git a/ssh.1 b/ssh.1 -index 60de6087a..db5c65bc7 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -503,7 +503,13 @@ For full details of the options listed below, and their possible values, see - .It GatewayPorts - .It GlobalKnownHostsFile - .It GSSAPIAuthentication -+.It GSSAPIKeyExchange -+.It GSSAPIClientIdentity - .It GSSAPIDelegateCredentials -+.It GSSAPIKexAlgorithms -+.It GSSAPIRenewalForcesRekey -+.It GSSAPIServerIdentity -+.It GSSAPITrustDns - .It HashKnownHosts - .It Host - .It HostbasedAuthentication -@@ -579,6 +585,8 @@ flag), - (supported message integrity codes), - .Ar kex - (key exchange algorithms), -+.Ar kex-gss -+(GSSAPI key exchange algorithms), - .Ar key - (key types), - .Ar key-cert -diff --git a/ssh.c b/ssh.c -index 15aee569e..110cf9c19 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -747,6 +747,8 @@ main(int ac, char **av) - else if (strcmp(optarg, "kex") == 0 || - strcasecmp(optarg, "KexAlgorithms") == 0) - cp = kex_alg_list('\n'); -+ else if (strcmp(optarg, "kex-gss") == 0) -+ cp = kex_gss_alg_list('\n'); - else if (strcmp(optarg, "key") == 0) - cp = sshkey_alg_list(0, 0, 0, '\n'); - else if (strcmp(optarg, "key-cert") == 0) -@@ -772,8 +774,8 @@ main(int ac, char **av) - } else if (strcmp(optarg, "help") == 0) { - cp = xstrdup( - "cipher\ncipher-auth\ncompression\nkex\n" -- "key\nkey-cert\nkey-plain\nkey-sig\nmac\n" -- "protocol-version\nsig"); -+ "kex-gss\nkey\nkey-cert\nkey-plain\n" -+ "key-sig\nmac\nprotocol-version\nsig"); - } - if (cp == NULL) - fatal("Unsupported query \"%s\"", optarg); -diff --git a/ssh_config b/ssh_config -index 5e8ef548b..1ff999b68 100644 ---- a/ssh_config -+++ b/ssh_config -@@ -24,6 +24,8 @@ - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -diff --git a/ssh_config.5 b/ssh_config.5 -index 06a32d314..3f4906972 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -766,10 +766,67 @@ The default is - Specifies whether user authentication based on GSSAPI is allowed. - The default is - .Cm no . -+.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 -+identity will be used. - .It Cm GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. - The default is - .Cm no . -+.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 . -+.It Cm GSSAPIRenewalForcesRekey -+If set to -+.Dq yes -+then renewal of the client's GSSAPI credentials will force the rekeying of the -+ssh connection. With a compatible server, this will delegate the renewed -+credentials to a session on the server. -+.Pp -+Checks are made to ensure that credentials are only propagated when the new -+credentials match the old ones on the originating client and where the -+receiving server still has the old set in its cache. -+.Pp -+The default is -+.Dq no . -+.Pp -+For this to work -+.Cm GSSAPIKeyExchange -+needs to be enabled in the server and also used by the client. -+.It Cm GSSAPIServerIdentity -+If set, specifies the GSSAPI server identity that ssh should expect when -+connecting to the server. The default is unset, which means that the -+expected GSSAPI server identity will be determined from the target -+hostname. -+.It Cm GSSAPITrustDns -+Set to -+.Dq yes -+to indicate that the DNS is trusted to securely canonicalize -+the name of the host being connected to. If -+.Dq no , -+the hostname entered on the -+command line will be passed untouched to the GSSAPI library. -+The default is -+.Dq no . -+.It Cm GSSAPIKexAlgorithms -+The list of key exchange algorithms that are offered for GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1-, -+gss-group14-sha256-, -+gss-group16-sha512-, -+gss-nistp256-sha256-, -+gss-curve25519-sha256- -+.Ed -+.Pp -+The default is -+.Dq gss-gex-sha1-,gss-group14-sha1- . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HashKnownHosts - Indicates that - .Xr ssh 1 -diff --git a/sshconnect2.c b/sshconnect2.c -index af00fb30c..03bc87eb4 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -80,8 +80,6 @@ - #endif - - /* import */ --extern char *client_version_string; --extern char *server_version_string; - extern Options options; - - /* -@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - char *s, *all_key; - int r, use_known_hosts_order = 0; - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ char *orig = NULL, *gss = NULL; -+ char *gss_host = NULL; -+#endif -+ - xxx_host = host; - xxx_hostaddr = hostaddr; - -@@ -206,6 +209,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - compat_pkalg_proposal(options.hostkeyalgorithms); - } - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ if (options.gss_keyex) { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ if (options.gss_server_identity) -+ gss_host = xstrdup(options.gss_server_identity); -+ else if (options.gss_trust_dns) -+ gss_host = remote_hostname(ssh); -+ else -+ gss_host = xstrdup(host); -+ -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ } -+ } -+#endif -+ - if (options.rekey_limit || options.rekey_interval) - ssh_packet_set_rekey_limits(ssh, options.rekey_limit, - options.rekey_interval); -@@ -224,16 +256,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - # ifdef OPENSSL_HAS_ECC - ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; - # endif --#endif -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client; -+ ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client; -+ } -+# endif -+#endif /* WITH_OPENSSL */ - ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; - ssh->kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_client; - ssh->kex->verify_host_key=&verify_host_key_callback; - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ if (options.gss_keyex) { -+ ssh->kex->gss_deleg_creds = options.gss_deleg_creds; -+ ssh->kex->gss_trust_dns = options.gss_trust_dns; -+ ssh->kex->gss_client = options.gss_client_identity; -+ ssh->kex->gss_host = gss_host; -+ } -+#endif -+ - ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); - - /* remove ext-info from the KEX proposals for rekeying */ - myproposal[PROPOSAL_KEX_ALGS] = - compat_kex_proposal(options.kex_algorithms); -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ /* repair myproposal after it was crumpled by the */ -+ /* ext-info removal above */ -+ if (gss) { -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ free(gss); -+ } -+#endif - if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) - fatal("kex_prop2buf: %s", ssh_err(r)); - -@@ -330,6 +392,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *); - static int input_gssapi_token(int type, u_int32_t, struct ssh *); - static int input_gssapi_error(int, u_int32_t, struct ssh *); - static int input_gssapi_errtok(int, u_int32_t, struct ssh *); -+static int userauth_gsskeyex(struct ssh *); - #endif - - void userauth(struct ssh *, char *); -@@ -346,6 +409,11 @@ static char *authmethods_get(void); - - Authmethod authmethods[] = { - #ifdef GSSAPI -+ {"gssapi-keyex", -+ userauth_gsskeyex, -+ NULL, -+ &options.gss_keyex, -+ NULL}, - {"gssapi-with-mic", - userauth_gssapi, - userauth_gssapi_cleanup, -@@ -716,12 +784,25 @@ userauth_gssapi(struct ssh *ssh) - OM_uint32 min; - int r, ok = 0; - gss_OID mech = NULL; -+ char *gss_host; -+ -+ if (options.gss_server_identity) -+ gss_host = xstrdup(options.gss_server_identity); -+ else if (options.gss_trust_dns) -+ gss_host = remote_hostname(ssh); -+ else -+ gss_host = xstrdup(authctxt->host); - - /* Try one GSSAPI method at a time, rather than sending them all at - * once. */ - - if (authctxt->gss_supported_mechs == NULL) -- gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); -+ if (GSS_ERROR(gss_indicate_mechs(&min, -+ &authctxt->gss_supported_mechs))) { -+ authctxt->gss_supported_mechs = NULL; -+ free(gss_host); -+ return 0; -+ } - - /* Check to see whether the mechanism is usable before we offer it */ - while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && -@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh) - elements[authctxt->mech_tried]; - /* My DER encoding requires length<128 */ - if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, -- mech, authctxt->host)) { -+ mech, gss_host, options.gss_client_identity)) { - ok = 1; /* Mechanism works */ - } else { - authctxt->mech_tried++; - } - } - -+ free(gss_host); -+ - if (!ok || mech == NULL) - return 0; - -@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) - free(lang); - return r; - } -+ -+int -+userauth_gsskeyex(struct ssh *ssh) -+{ -+ struct sshbuf *b = NULL; -+ Authctxt *authctxt = ssh->authctxt; -+ gss_buffer_desc gssbuf; -+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; -+ OM_uint32 ms; -+ int r; -+ -+ static int attempt = 0; -+ if (attempt++ >= 1) -+ return (0); -+ -+ if (gss_kex_context == NULL) { -+ debug("No valid Key exchange context"); -+ return (0); -+ } -+ -+ if ((b = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, -+ "gssapi-keyex"); -+ -+ if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) -+ fatal("%s: sshbuf_mutable_ptr failed", __func__); -+ gssbuf.length = sshbuf_len(b); -+ -+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { -+ sshbuf_free(b); -+ return (0); -+ } -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || -+ (r = sshpkt_put_cstring(ssh, 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 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("%s: %s", __func__, ssh_err(r)); -+ -+ sshbuf_free(b); -+ gss_release_buffer(&ms, &mic); -+ -+ return (1); -+} -+ - #endif /* GSSAPI */ - - static int -diff --git a/sshd.c b/sshd.c -index 60b2aaf73..d92f03aaf 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -817,8 +817,8 @@ notify_hostkeys(struct ssh *ssh) - } - debug3("%s: sent %u hostkeys", __func__, nkeys); - if (nkeys == 0) -- fatal("%s: no hostkeys", __func__); -- if ((r = sshpkt_send(ssh)) != 0) -+ debug3("%s: no hostkeys", __func__); -+ else if ((r = sshpkt_send(ssh)) != 0) - sshpkt_fatal(ssh, r, "%s: send", __func__); - sshbuf_free(buf); - } -@@ -1852,7 +1852,8 @@ main(int ac, char **av) - free(fp); - } - accumulate_host_timing_secret(cfg, NULL); -- if (!sensitive_data.have_ssh2_key) { -+ /* The GSSAPI key exchange can run without a host key */ -+ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { - logit("sshd: no hostkeys available -- exiting."); - exit(1); - } -@@ -2347,6 +2348,48 @@ do_ssh2_kex(struct ssh *ssh) - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( - list_hostkey_types()); - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ { -+ char *orig; -+ char *gss = NULL; -+ char *newstr = NULL; -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ /* -+ * If we don't have a host key, then there's no point advertising -+ * the other key exchange algorithms -+ */ -+ -+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) -+ orig = NULL; -+ -+ if (options.gss_keyex) -+ gss = ssh_gssapi_server_mechanisms(); -+ else -+ gss = NULL; -+ -+ if (gss && orig) -+ xasprintf(&newstr, "%s,%s", gss, orig); -+ else if (gss) -+ newstr = gss; -+ else if (orig) -+ newstr = orig; -+ -+ /* -+ * If we've got GSSAPI mechanisms, then we've got the 'null' host -+ * key alg, but we can't tell people about it unless its the only -+ * host key algorithm we support -+ */ -+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; -+ -+ if (newstr) -+ myproposal[PROPOSAL_KEX_ALGS] = newstr; -+ else -+ fatal("No supported key exchange algorithms"); -+ } -+#endif -+ - /* start key exchange */ - if ((r = kex_setup(ssh, myproposal)) != 0) - fatal("kex_setup: %s", ssh_err(r)); -@@ -2362,7 +2405,18 @@ do_ssh2_kex(struct ssh *ssh) - # ifdef OPENSSL_HAS_ECC - kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif --#endif -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; -+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; -+ } -+# endif -+#endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kex_gen_server; - kex->kex[KEX_KEM_SNTRUP4591761X25519_SHA512] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; -diff --git a/sshd_config b/sshd_config -index 19b7c91a1..2c48105f8 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -69,6 +69,8 @@ AuthorizedKeysFile .ssh/authorized_keys - # GSSAPI options - #GSSAPIAuthentication no - #GSSAPICleanupCredentials yes -+#GSSAPIStrictAcceptorCheck yes -+#GSSAPIKeyExchange no - - # Set this to 'yes' to enable PAM authentication, account processing, - # and session processing. If this is enabled, PAM authentication will -diff --git a/sshd_config.5 b/sshd_config.5 -index 70ccea449..f6b41a2f8 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -646,6 +646,11 @@ Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Cm yes . -+.It Cm GSSAPIKeyExchange -+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 . - .It Cm GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI acceptor - a client authenticates against. -@@ -660,6 +665,31 @@ machine's default store. - This facility is provided to assist with operation on multi homed machines. - The default is - .Cm yes . -+.It Cm GSSAPIStoreCredentialsOnRekey -+Controls whether the user's GSSAPI credentials should be updated following a -+successful connection rekeying. This option can be used to accepted renewed -+or updated credentials from a compatible client. The default is -+.Dq no . -+.Pp -+For this to work -+.Cm GSSAPIKeyExchange -+needs to be enabled in the server and also used by the client. -+.It Cm GSSAPIKexAlgorithms -+The list of key exchange algorithms that are accepted by GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1-, -+gss-group14-sha256-, -+gss-group16-sha512-, -+gss-nistp256-sha256-, -+gss-curve25519-sha256- -+.Ed -+.Pp -+The default is -+.Dq gss-gex-sha1-,gss-group14-sha1- . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HostbasedAcceptedKeyTypes - Specifies the key types that will be accepted for hostbased authentication - as a list of comma-separated patterns. -diff --git a/sshkey.c b/sshkey.c -index 57995ee68..fd5b77246 100644 ---- a/sshkey.c -+++ b/sshkey.c -@@ -154,6 +154,7 @@ static const struct keytype keytypes[] = { - KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 }, - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+ { "null", "null", NULL, KEY_NULL, 0, 0, 0 }, - { NULL, NULL, NULL, -1, -1, 0, 0 } - }; - -@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) - const struct keytype *kt; - - for (kt = keytypes; kt->type != -1; kt++) { -- if (kt->name == NULL) -+ if (kt->name == NULL || kt->type == KEY_NULL) - continue; - if (!include_sigonly && kt->sigonly) - continue; -diff --git a/sshkey.h b/sshkey.h -index 71a3fddcb..37a43a67a 100644 ---- a/sshkey.h -+++ b/sshkey.h -@@ -69,6 +69,7 @@ enum sshkey_types { - KEY_ECDSA_SK_CERT, - KEY_ED25519_SK, - KEY_ED25519_SK_CERT, -+ KEY_NULL, - KEY_UNSPEC - }; - diff --git a/debian/patches/keepalive-extensions.patch b/debian/patches/keepalive-extensions.patch deleted file mode 100644 index 734118a..0000000 --- a/debian/patches/keepalive-extensions.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 3558be2914c0127489faae40ce2eae66142c3287 Mon Sep 17 00:00:00 2001 -From: Richard Kettlewell -Date: Sun, 9 Feb 2014 16:09:52 +0000 -Subject: Various keepalive extensions - -Add compatibility aliases for ProtocolKeepAlives and SetupTimeOut, supported -in previous versions of Debian's OpenSSH package but since superseded by -ServerAliveInterval. (We're probably stuck with this bit for -compatibility.) - -In batch mode, default ServerAliveInterval to five minutes. - -Adjust documentation to match and to give some more advice on use of -keepalives. - -Author: Ian Jackson -Author: Matthew Vernon -Author: Colin Watson -Last-Update: 2020-02-21 - -Patch-Name: keepalive-extensions.patch ---- - readconf.c | 14 ++++++++++++-- - ssh_config.5 | 21 +++++++++++++++++++-- - sshd_config.5 | 3 +++ - 3 files changed, 34 insertions(+), 4 deletions(-) - -diff --git a/readconf.c b/readconf.c -index 0fc996871..2399208f8 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -176,6 +176,7 @@ typedef enum { - oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, - oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump, - oSecurityKeyProvider, -+ oProtocolKeepAlives, oSetupTimeOut, - oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported - } OpCodes; - -@@ -326,6 +327,8 @@ static struct { - { "ignoreunknown", oIgnoreUnknown }, - { "proxyjump", oProxyJump }, - { "securitykeyprovider", oSecurityKeyProvider }, -+ { "protocolkeepalives", oProtocolKeepAlives }, -+ { "setuptimeout", oSetupTimeOut }, - - { NULL, oBadOption } - }; -@@ -1495,6 +1498,8 @@ parse_keytypes: - goto parse_flag; - - case oServerAliveInterval: -+ case oProtocolKeepAlives: /* Debian-specific compatibility alias */ -+ case oSetupTimeOut: /* Debian-specific compatibility alias */ - intptr = &options->server_alive_interval; - goto parse_time; - -@@ -2198,8 +2203,13 @@ fill_default_options(Options * options) - options->rekey_interval = 0; - if (options->verify_host_key_dns == -1) - options->verify_host_key_dns = 0; -- if (options->server_alive_interval == -1) -- options->server_alive_interval = 0; -+ if (options->server_alive_interval == -1) { -+ /* in batch mode, default is 5mins */ -+ if (options->batch_mode == 1) -+ options->server_alive_interval = 300; -+ else -+ options->server_alive_interval = 0; -+ } - if (options->server_alive_count_max == -1) - options->server_alive_count_max = 3; - if (options->control_master == -1) -diff --git a/ssh_config.5 b/ssh_config.5 -index 3f4906972..3079db19b 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -266,9 +266,13 @@ If set to - .Cm yes , - user interaction such as password prompts and host key confirmation requests - will be disabled. -+In addition, the -+.Cm ServerAliveInterval -+option will be set to 300 seconds by default (Debian-specific). - This option is useful in scripts and other batch jobs where no user - is present to interact with --.Xr ssh 1 . -+.Xr ssh 1 , -+and where it is desirable to detect a broken network swiftly. - The argument must be - .Cm yes - or -@@ -1593,7 +1597,14 @@ from the server, - will send a message through the encrypted - channel to request a response from the server. - The default --is 0, indicating that these messages will not be sent to the server. -+is 0, indicating that these messages will not be sent to the server, -+or 300 if the -+.Cm BatchMode -+option is set (Debian-specific). -+.Cm ProtocolKeepAlives -+and -+.Cm SetupTimeOut -+are Debian-specific compatibility aliases for this option. - .It Cm SetEnv - Directly specify one or more environment variables and their contents to - be sent to the server. -@@ -1673,6 +1684,12 @@ Specifies whether the system should send TCP keepalive messages to the - other side. - If they are sent, death of the connection or crash of one - of the machines will be properly noticed. -+This option only uses TCP keepalives (as opposed to using ssh level -+keepalives), so takes a long time to notice when the connection dies. -+As such, you probably want -+the -+.Cm ServerAliveInterval -+option as well. - However, this means that - connections will die if the route is down temporarily, and some people - find it annoying. -diff --git a/sshd_config.5 b/sshd_config.5 -index f6b41a2f8..ebd09f891 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1668,6 +1668,9 @@ This avoids infinitely hanging sessions. - .Pp - To disable TCP keepalive messages, the value should be set to - .Cm no . -+.Pp -+This option was formerly called -+.Cm KeepAlive . - .It Cm TrustedUserCAKeys - Specifies a file containing public keys of certificate authorities that are - trusted to sign user certificates for authentication, or diff --git a/debian/patches/mention-ssh-keygen-on-keychange.patch b/debian/patches/mention-ssh-keygen-on-keychange.patch deleted file mode 100644 index 6d48d75..0000000 --- a/debian/patches/mention-ssh-keygen-on-keychange.patch +++ /dev/null @@ -1,44 +0,0 @@ -From c18e3c8125fc4553951705a1da8c86395d219bb1 Mon Sep 17 00:00:00 2001 -From: Scott Moser -Date: Sun, 9 Feb 2014 16:10:03 +0000 -Subject: Mention ssh-keygen in ssh fingerprint changed warning - -Author: Chris Lamb -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1843 -Bug-Ubuntu: https://bugs.launchpad.net/bugs/686607 -Last-Update: 2017-08-22 - -Patch-Name: mention-ssh-keygen-on-keychange.patch ---- - sshconnect.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/sshconnect.c b/sshconnect.c -index 4a5d4a003..b796d3c8a 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -991,9 +991,13 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - error("%s. This could either mean that", key_msg); - error("DNS SPOOFING is happening or the IP address for the host"); - error("and its host key have changed at the same time."); -- if (ip_status != HOST_NEW) -+ if (ip_status != HOST_NEW) { - error("Offending key for IP in %s:%lu", - ip_found->file, ip_found->line); -+ error(" remove with:"); -+ error(" ssh-keygen -f \"%s\" -R \"%s\"", -+ ip_found->file, ip); -+ } - } - /* The host key has changed. */ - warn_changed_key(host_key); -@@ -1002,6 +1006,9 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - error("Offending %s key in %s:%lu", - sshkey_type(host_found->key), - host_found->file, host_found->line); -+ error(" remove with:"); -+ error(" ssh-keygen -f \"%s\" -R \"%s\"", -+ host_found->file, host); - - /* - * If strict host key checking is in use, the user will have diff --git a/debian/patches/no-openssl-version-status.patch b/debian/patches/no-openssl-version-status.patch deleted file mode 100644 index 02a798b..0000000 --- a/debian/patches/no-openssl-version-status.patch +++ /dev/null @@ -1,62 +0,0 @@ -From ba0377ab3e6b68f7ab747f500991a0445c7f4086 Mon Sep 17 00:00:00 2001 -From: Kurt Roeckx -Date: Sun, 9 Feb 2014 16:10:14 +0000 -Subject: Don't check the status field of the OpenSSL version - -There is no reason to check the version of OpenSSL (in Debian). If it's -not compatible the soname will change. OpenSSH seems to want to do a -check for the soname based on the version number, but wants to keep the -status of the release the same. Remove that check on the status since -it doesn't tell you anything about how compatible that version is. - -Author: Colin Watson -Bug-Debian: https://bugs.debian.org/93581 -Bug-Debian: https://bugs.debian.org/664383 -Bug-Debian: https://bugs.debian.org/732940 -Forwarded: not-needed -Last-Update: 2014-10-07 - -Patch-Name: no-openssl-version-status.patch ---- - openbsd-compat/openssl-compat.c | 6 +++--- - openbsd-compat/regress/opensslvertest.c | 1 + - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c -index a37ca61bf..c1749210d 100644 ---- a/openbsd-compat/openssl-compat.c -+++ b/openbsd-compat/openssl-compat.c -@@ -34,7 +34,7 @@ - /* - * OpenSSL version numbers: MNNFFPPS: major minor fix patch status - * We match major, minor, fix and status (not patch) for <1.0.0. -- * After that, we acceptable compatible fix versions (so we -+ * After that, we accept compatible fix and status versions (so we - * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed - * within a patch series. - */ -@@ -55,10 +55,10 @@ ssh_compatible_openssl(long headerver, long libver) - } - - /* -- * For versions >= 1.0.0, major,minor,status must match and library -+ * For versions >= 1.0.0, major,minor must match and library - * fix version must be equal to or newer than the header. - */ -- mask = 0xfff0000fL; /* major,minor,status */ -+ mask = 0xfff00000L; /* major,minor */ - hfix = (headerver & 0x000ff000) >> 12; - lfix = (libver & 0x000ff000) >> 12; - if ( (headerver & mask) == (libver & mask) && lfix >= hfix) -diff --git a/openbsd-compat/regress/opensslvertest.c b/openbsd-compat/regress/opensslvertest.c -index 5d019b598..58474873d 100644 ---- a/openbsd-compat/regress/opensslvertest.c -+++ b/openbsd-compat/regress/opensslvertest.c -@@ -35,6 +35,7 @@ struct version_test { - - /* built with 1.0.1b release headers */ - { 0x1000101fL, 0x1000101fL, 1},/* exact match */ -+ { 0x1000101fL, 0x10001010L, 1}, /* different status: ok */ - { 0x1000101fL, 0x1000102fL, 1}, /* newer library patch version: ok */ - { 0x1000101fL, 0x1000100fL, 1}, /* older library patch version: ok */ - { 0x1000101fL, 0x1000201fL, 1}, /* newer library fix version: ok */ diff --git a/debian/patches/openbsd-docs.patch b/debian/patches/openbsd-docs.patch deleted file mode 100644 index 34ec870..0000000 --- a/debian/patches/openbsd-docs.patch +++ /dev/null @@ -1,148 +0,0 @@ -From 39fe318a4b572deeb3f7d03e55d319c0ab112a28 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:09 +0000 -Subject: Adjust various OpenBSD-specific references in manual pages - -No single bug reference for this patch, but history includes: - http://bugs.debian.org/154434 (login.conf(5)) - http://bugs.debian.org/513417 (/etc/rc) - http://bugs.debian.org/530692 (ssl(8)) - https://bugs.launchpad.net/bugs/456660 (ssl(8)) - -Forwarded: not-needed -Last-Update: 2017-10-04 - -Patch-Name: openbsd-docs.patch ---- - moduli.5 | 4 ++-- - ssh-keygen.1 | 12 ++++-------- - ssh.1 | 4 ++++ - sshd.8 | 5 ++--- - sshd_config.5 | 3 +-- - 5 files changed, 13 insertions(+), 15 deletions(-) - -diff --git a/moduli.5 b/moduli.5 -index ef0de0850..149846c8c 100644 ---- a/moduli.5 -+++ b/moduli.5 -@@ -21,7 +21,7 @@ - .Nd Diffie-Hellman moduli - .Sh DESCRIPTION - The --.Pa /etc/moduli -+.Pa /etc/ssh/moduli - file contains prime numbers and generators for use by - .Xr sshd 8 - in the Diffie-Hellman Group Exchange key exchange method. -@@ -110,7 +110,7 @@ first estimates the size of the modulus required to produce enough - Diffie-Hellman output to sufficiently key the selected symmetric cipher. - .Xr sshd 8 - then randomly selects a modulus from --.Fa /etc/moduli -+.Fa /etc/ssh/moduli - that best meets the size requirement. - .Sh SEE ALSO - .Xr ssh-keygen 1 , -diff --git a/ssh-keygen.1 b/ssh-keygen.1 -index 7af564297..d6a7870e0 100644 ---- a/ssh-keygen.1 -+++ b/ssh-keygen.1 -@@ -196,9 +196,7 @@ key in - .Pa ~/.ssh/id_ed25519_sk - or - .Pa ~/.ssh/id_rsa . --Additionally, the system administrator may use this to generate host keys, --as seen in --.Pa /etc/rc . -+Additionally, the system administrator may use this to generate host keys. - .Pp - Normally this program generates the key and asks for a file in which - to store the private key. -@@ -261,9 +259,7 @@ If - .Fl f - has also been specified, its argument is used as a prefix to the - default path for the resulting host key files. --This is used by --.Pa /etc/rc --to generate new host keys. -+This is used by system administration scripts to generate new host keys. - .It Fl a Ar rounds - When saving a private key, this option specifies the number of KDF - (key derivation function) rounds used. -@@ -783,7 +779,7 @@ option. - Valid generator values are 2, 3, and 5. - .Pp - Screened DH groups may be installed in --.Pa /etc/moduli . -+.Pa /etc/ssh/moduli . - It is important that this file contains moduli of a range of bit lengths and - that both ends of a connection share common moduli. - .Pp -@@ -1154,7 +1150,7 @@ on all machines - where the user wishes to log in using public key authentication. - There is no need to keep the contents of this file secret. - .Pp --.It Pa /etc/moduli -+.It Pa /etc/ssh/moduli - Contains Diffie-Hellman groups used for DH-GEX. - The file format is described in - .Xr moduli 5 . -diff --git a/ssh.1 b/ssh.1 -index cf991e4ee..17b0e984f 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -887,6 +887,10 @@ implements public key authentication protocol automatically, - using one of the DSA, ECDSA, Ed25519 or RSA algorithms. - The HISTORY section of - .Xr ssl 8 -+(on non-OpenBSD systems, see -+.nh -+http://www.openbsd.org/cgi\-bin/man.cgi?query=ssl&sektion=8#HISTORY) -+.hy - contains a brief discussion of the DSA and RSA algorithms. - .Pp - The file -diff --git a/sshd.8 b/sshd.8 -index 730520231..5ce0ea4fa 100644 ---- a/sshd.8 -+++ b/sshd.8 -@@ -65,7 +65,7 @@ over an insecure network. - .Nm - listens for connections from clients. - It is normally started at boot from --.Pa /etc/rc . -+.Pa /etc/init.d/ssh . - It forks a new - daemon for each incoming connection. - The forked daemons handle -@@ -904,7 +904,7 @@ This file is for host-based authentication (see - .Xr ssh 1 ) . - It should only be writable by root. - .Pp --.It Pa /etc/moduli -+.It Pa /etc/ssh/moduli - Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange" - key exchange method. - The file format is described in -@@ -1002,7 +1002,6 @@ The content of this file is not sensitive; it can be world-readable. - .Xr ssh-keyscan 1 , - .Xr chroot 2 , - .Xr hosts_access 5 , --.Xr login.conf 5 , - .Xr moduli 5 , - .Xr sshd_config 5 , - .Xr inetd 8 , -diff --git a/sshd_config.5 b/sshd_config.5 -index c926f584c..25f4b8117 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -387,8 +387,7 @@ Certificates signed using other algorithms will not be accepted for - public key or host-based authentication. - .It Cm ChallengeResponseAuthentication - Specifies whether challenge-response authentication is allowed (e.g. via --PAM or through authentication styles supported in --.Xr login.conf 5 ) -+PAM). - The default is - .Cm yes . - .It Cm ChrootDirectory diff --git a/debian/patches/package-versioning.patch b/debian/patches/package-versioning.patch deleted file mode 100644 index 32a7a1f..0000000 --- a/debian/patches/package-versioning.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a4f868858c3395cacb59c58786b501317b9a3d03 Mon Sep 17 00:00:00 2001 -From: Matthew Vernon -Date: Sun, 9 Feb 2014 16:10:05 +0000 -Subject: Include the Debian version in our identification - -This makes it easier to audit networks for versions patched against security -vulnerabilities. It has little detrimental effect, as attackers will -generally just try attacks rather than bothering to scan for -vulnerable-looking version strings. (However, see debian-banner.patch.) - -Forwarded: not-needed -Last-Update: 2019-06-05 - -Patch-Name: package-versioning.patch ---- - kex.c | 2 +- - version.h | 7 ++++++- - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/kex.c b/kex.c -index 574c76093..f638942d3 100644 ---- a/kex.c -+++ b/kex.c -@@ -1244,7 +1244,7 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, - 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) { - error("%s: sshbuf_putf: %s", __func__, ssh_err(r)); -diff --git a/version.h b/version.h -index c2affcb2a..d79126cc3 100644 ---- a/version.h -+++ b/version.h -@@ -3,4 +3,9 @@ - #define SSH_VERSION "OpenSSH_8.2" - - #define SSH_PORTABLE "p1" --#define SSH_RELEASE SSH_VERSION SSH_PORTABLE -+#define SSH_RELEASE_MINIMUM SSH_VERSION SSH_PORTABLE -+#ifdef SSH_EXTRAVERSION -+#define SSH_RELEASE SSH_RELEASE_MINIMUM " " SSH_EXTRAVERSION -+#else -+#define SSH_RELEASE SSH_RELEASE_MINIMUM -+#endif diff --git a/debian/patches/restore-authorized_keys2.patch b/debian/patches/restore-authorized_keys2.patch deleted file mode 100644 index aa6f4cc..0000000 --- a/debian/patches/restore-authorized_keys2.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 58390cbd5e07df92729b794beb491f7352b26993 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 5 Mar 2017 02:02:11 +0000 -Subject: Restore reading authorized_keys2 by default - -Upstream seems to intend to gradually phase this out, so don't assume -that this will remain the default forever. However, we were late in -adopting the upstream sshd_config changes, so it makes sense to extend -the grace period. - -Bug-Debian: https://bugs.debian.org/852320 -Forwarded: not-needed -Last-Update: 2017-03-05 - -Patch-Name: restore-authorized_keys2.patch ---- - sshd_config | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/sshd_config b/sshd_config -index 459c1b230..dc0db5706 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -38,9 +38,8 @@ Include /etc/ssh/sshd_config.d/*.conf - - #PubkeyAuthentication yes - --# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 --# but this is overridden so installations will only check .ssh/authorized_keys --AuthorizedKeysFile .ssh/authorized_keys -+# Expect .ssh/authorized_keys2 to be disregarded by default in future. -+#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 - - #AuthorizedPrincipalsFile none - diff --git a/debian/patches/restore-tcp-wrappers.patch b/debian/patches/restore-tcp-wrappers.patch deleted file mode 100644 index d73cc28..0000000 --- a/debian/patches/restore-tcp-wrappers.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 31d42cd8624f29508f772447e617ab043a6487d9 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Tue, 7 Oct 2014 13:22:41 +0100 -Subject: Restore TCP wrappers support - -Support for TCP wrappers was dropped in OpenSSH 6.7. See this message -and thread: - - https://lists.mindrot.org/pipermail/openssh-unix-dev/2014-April/032497.html - -It is true that this reduces preauth attack surface in sshd. On the -other hand, this support seems to be quite widely used, and abruptly -dropping it (from the perspective of users who don't read -openssh-unix-dev) could easily cause more serious problems in practice. - -It's not entirely clear what the right long-term answer for Debian is, -but it at least probably doesn't involve dropping this feature shortly -before a freeze. - -Forwarded: not-needed -Last-Update: 2019-06-05 - -Patch-Name: restore-tcp-wrappers.patch ---- - configure.ac | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ - sshd.8 | 7 +++++++ - sshd.c | 25 +++++++++++++++++++++++ - 3 files changed, 89 insertions(+) - -diff --git a/configure.ac b/configure.ac -index efafb6bd8..cee7cbc51 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1556,6 +1556,62 @@ else - AC_MSG_RESULT([no]) - fi - -+# Check whether user wants TCP wrappers support -+TCPW_MSG="no" -+AC_ARG_WITH([tcp-wrappers], -+ [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], -+ [ -+ if test "x$withval" != "xno" ; then -+ saved_LIBS="$LIBS" -+ saved_LDFLAGS="$LDFLAGS" -+ saved_CPPFLAGS="$CPPFLAGS" -+ if test -n "${withval}" && \ -+ test "x${withval}" != "xyes"; then -+ if test -d "${withval}/lib"; then -+ if test -n "${need_dash_r}"; then -+ LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" -+ else -+ LDFLAGS="-L${withval}/lib ${LDFLAGS}" -+ fi -+ else -+ if test -n "${need_dash_r}"; then -+ LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" -+ else -+ LDFLAGS="-L${withval} ${LDFLAGS}" -+ fi -+ fi -+ if test -d "${withval}/include"; then -+ CPPFLAGS="-I${withval}/include ${CPPFLAGS}" -+ else -+ CPPFLAGS="-I${withval} ${CPPFLAGS}" -+ fi -+ fi -+ LIBS="-lwrap $LIBS" -+ AC_MSG_CHECKING([for libwrap]) -+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -+#include -+#include -+#include -+#include -+int deny_severity = 0, allow_severity = 0; -+ ]], [[ -+ hosts_access(0); -+ ]])], [ -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE([LIBWRAP], [1], -+ [Define if you want -+ TCP Wrappers support]) -+ SSHDLIBS="$SSHDLIBS -lwrap" -+ TCPW_MSG="yes" -+ ], [ -+ AC_MSG_ERROR([*** libwrap missing]) -+ -+ ]) -+ LIBS="$saved_LIBS" -+ fi -+ ] -+) -+ - # Check whether user wants to use ldns - LDNS_MSG="no" - AC_ARG_WITH(ldns, -@@ -5413,6 +5469,7 @@ echo " PAM support: $PAM_MSG" - echo " OSF SIA support: $SIA_MSG" - echo " KerberosV support: $KRB5_MSG" - echo " SELinux support: $SELINUX_MSG" -+echo " TCP Wrappers support: $TCPW_MSG" - echo " MD5 password support: $MD5_MSG" - echo " libedit support: $LIBEDIT_MSG" - echo " libldns support: $LDNS_MSG" -diff --git a/sshd.8 b/sshd.8 -index c5f8987d2..730520231 100644 ---- a/sshd.8 -+++ b/sshd.8 -@@ -893,6 +893,12 @@ the user's home directory becomes accessible. - This file should be writable only by the user, and need not be - readable by anyone else. - .Pp -+.It Pa /etc/hosts.allow -+.It Pa /etc/hosts.deny -+Access controls that should be enforced by tcp-wrappers are defined here. -+Further details are described in -+.Xr hosts_access 5 . -+.Pp - .It Pa /etc/hosts.equiv - This file is for host-based authentication (see - .Xr ssh 1 ) . -@@ -995,6 +1001,7 @@ The content of this file is not sensitive; it can be world-readable. - .Xr ssh-keygen 1 , - .Xr ssh-keyscan 1 , - .Xr chroot 2 , -+.Xr hosts_access 5 , - .Xr login.conf 5 , - .Xr moduli 5 , - .Xr sshd_config 5 , -diff --git a/sshd.c b/sshd.c -index d92f03aaf..62dc55cf2 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -124,6 +124,13 @@ - #include "ssherr.h" - #include "sk-api.h" - -+#ifdef LIBWRAP -+#include -+#include -+int allow_severity; -+int deny_severity; -+#endif /* LIBWRAP */ -+ - /* Re-exec fds */ - #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) - #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) -@@ -2138,6 +2145,24 @@ main(int ac, char **av) - #ifdef SSH_AUDIT_EVENTS - audit_connection_from(remote_ip, remote_port); - #endif -+#ifdef LIBWRAP -+ allow_severity = options.log_facility|LOG_INFO; -+ deny_severity = options.log_facility|LOG_WARNING; -+ /* Check whether logins are denied from this host. */ -+ if (ssh_packet_connection_is_on_socket(ssh)) { -+ struct request_info req; -+ -+ request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); -+ fromhost(&req); -+ -+ if (!hosts_access(&req)) { -+ debug("Connection refused by tcp wrapper"); -+ refuse(&req); -+ /* NOTREACHED */ -+ fatal("libwrap refuse returns"); -+ } -+ } -+#endif /* LIBWRAP */ - - rdomain = ssh_packet_rdomain_in(ssh); - diff --git a/debian/patches/revert-ipqos-defaults.patch b/debian/patches/revert-ipqos-defaults.patch deleted file mode 100644 index 13192e3..0000000 --- a/debian/patches/revert-ipqos-defaults.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 86fe78ef4686485394b464cf9d3393ce27b33979 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Mon, 8 Apr 2019 10:46:29 +0100 -Subject: Revert "upstream: Update default IPQoS in ssh(1), sshd(8) to DSCP - AF21 for" - -This reverts commit 5ee8448ad7c306f05a9f56769f95336a8269f379. - -The IPQoS default changes have some unfortunate interactions with -iptables (see https://bugs.debian.org/923880) and VMware, so I'm -temporarily reverting them until those have been fixed. - -Bug-Debian: https://bugs.debian.org/923879 -Bug-Debian: https://bugs.debian.org/926229 -Bug-Ubuntu: https://bugs.launchpad.net/bugs/1822370 -Last-Update: 2019-04-08 - -Patch-Name: revert-ipqos-defaults.patch ---- - readconf.c | 4 ++-- - servconf.c | 4 ++-- - ssh_config.5 | 6 ++---- - sshd_config.5 | 6 ++---- - 4 files changed, 8 insertions(+), 12 deletions(-) - -diff --git a/readconf.c b/readconf.c -index e82024678..1b9494d7c 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -2230,9 +2230,9 @@ fill_default_options(Options * options) - if (options->visual_host_key == -1) - options->visual_host_key = 0; - if (options->ip_qos_interactive == -1) -- options->ip_qos_interactive = IPTOS_DSCP_AF21; -+ options->ip_qos_interactive = IPTOS_LOWDELAY; - if (options->ip_qos_bulk == -1) -- options->ip_qos_bulk = IPTOS_DSCP_CS1; -+ options->ip_qos_bulk = IPTOS_THROUGHPUT; - if (options->request_tty == -1) - options->request_tty = REQUEST_TTY_AUTO; - if (options->proxy_use_fdpass == -1) -diff --git a/servconf.c b/servconf.c -index 7bbc25c2e..470ad3619 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -452,9 +452,9 @@ fill_default_server_options(ServerOptions *options) - if (options->permit_tun == -1) - options->permit_tun = SSH_TUNMODE_NO; - if (options->ip_qos_interactive == -1) -- options->ip_qos_interactive = IPTOS_DSCP_AF21; -+ options->ip_qos_interactive = IPTOS_LOWDELAY; - if (options->ip_qos_bulk == -1) -- options->ip_qos_bulk = IPTOS_DSCP_CS1; -+ options->ip_qos_bulk = IPTOS_THROUGHPUT; - if (options->version_addendum == NULL) - options->version_addendum = xstrdup(""); - if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) -diff --git a/ssh_config.5 b/ssh_config.5 -index 34dc2d51b..91beb6f50 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -1140,11 +1140,9 @@ If one argument is specified, it is used as the packet class unconditionally. - If two values are specified, the first is automatically selected for - interactive sessions and the second for non-interactive sessions. - The default is --.Cm af21 --(Low-Latency Data) -+.Cm lowdelay - for interactive sessions and --.Cm cs1 --(Lower Effort) -+.Cm throughput - for non-interactive sessions. - .It Cm KbdInteractiveAuthentication - Specifies whether to use keyboard-interactive authentication. -diff --git a/sshd_config.5 b/sshd_config.5 -index e8271be74..d25b2f3d5 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -914,11 +914,9 @@ If one argument is specified, it is used as the packet class unconditionally. - If two values are specified, the first is automatically selected for - interactive sessions and the second for non-interactive sessions. - The default is --.Cm af21 --(Low-Latency Data) -+.Cm lowdelay - for interactive sessions and --.Cm cs1 --(Lower Effort) -+.Cm throughput - for non-interactive sessions. - .It Cm KbdInteractiveAuthentication - Specifies whether to allow keyboard-interactive authentication. diff --git a/debian/patches/scp-quoting.patch b/debian/patches/scp-quoting.patch deleted file mode 100644 index 8935b8e..0000000 --- a/debian/patches/scp-quoting.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 5166a6af68da4778c7e2c2d117bb56361c7aa361 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Nicolas=20Valc=C3=A1rcel?= -Date: Sun, 9 Feb 2014 16:09:59 +0000 -Subject: Adjust scp quoting in verbose mode - -Tweak scp's reporting of filenames in verbose mode to be a bit less -confusing with spaces. - -This should be revised to mimic real shell quoting. - -Bug-Ubuntu: https://bugs.launchpad.net/bugs/89945 -Last-Update: 2010-02-27 - -Patch-Name: scp-quoting.patch ---- - scp.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/scp.c b/scp.c -index 6901e0c94..9b64aa5f4 100644 ---- a/scp.c -+++ b/scp.c -@@ -201,8 +201,16 @@ do_local_cmd(arglist *a) - - if (verbose_mode) { - fprintf(stderr, "Executing:"); -- for (i = 0; i < a->num; i++) -- fmprintf(stderr, " %s", a->list[i]); -+ for (i = 0; i < a->num; i++) { -+ if (i == 0) -+ fmprintf(stderr, " %s", a->list[i]); -+ else -+ /* -+ * TODO: misbehaves if a->list[i] contains a -+ * single quote -+ */ -+ fmprintf(stderr, " '%s'", a->list[i]); -+ } - fprintf(stderr, "\n"); - } - if ((pid = fork()) == -1) diff --git a/debian/patches/selinux-role.patch b/debian/patches/selinux-role.patch deleted file mode 100644 index 63e44af..0000000 --- a/debian/patches/selinux-role.patch +++ /dev/null @@ -1,472 +0,0 @@ -From b108c6bbe4b3691600a272b27fa24d9080018db7 Mon Sep 17 00:00:00 2001 -From: Manoj Srivastava -Date: Sun, 9 Feb 2014 16:09:49 +0000 -Subject: Handle SELinux authorisation roles - -Rejected upstream due to discomfort with magic usernames; a better approach -will need an SSH protocol change. In the meantime, this came from Debian's -SELinux maintainer, so we'll keep it until we have something better. - -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1641 -Bug-Debian: http://bugs.debian.org/394795 -Last-Update: 2020-02-21 - -Patch-Name: selinux-role.patch ---- - auth.h | 1 + - auth2.c | 10 ++++++++-- - monitor.c | 37 +++++++++++++++++++++++++++++++++---- - monitor.h | 2 ++ - monitor_wrap.c | 27 ++++++++++++++++++++++++--- - monitor_wrap.h | 3 ++- - openbsd-compat/port-linux.c | 21 ++++++++++++++------- - openbsd-compat/port-linux.h | 4 ++-- - platform.c | 4 ++-- - platform.h | 2 +- - session.c | 10 +++++----- - session.h | 2 +- - sshd.c | 2 +- - sshpty.c | 4 ++-- - sshpty.h | 2 +- - 15 files changed, 99 insertions(+), 32 deletions(-) - -diff --git a/auth.h b/auth.h -index becc672b5..5da9fe75f 100644 ---- a/auth.h -+++ b/auth.h -@@ -63,6 +63,7 @@ struct Authctxt { - char *service; - struct passwd *pw; /* set if 'valid' */ - char *style; -+ char *role; - - /* Method lists for multiple authentication */ - char **auth_methods; /* modified from server config */ -diff --git a/auth2.c b/auth2.c -index 1c217268c..92a6bcaf4 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -265,7 +265,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - { - Authctxt *authctxt = ssh->authctxt; - Authmethod *m = NULL; -- char *user = NULL, *service = NULL, *method = NULL, *style = NULL; -+ char *user = NULL, *service = NULL, *method = NULL, *style = NULL, *role = NULL; - int r, authenticated = 0; - double tstart = monotime_double(); - -@@ -279,8 +279,13 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - debug("userauth-request for user %s service %s method %s", user, service, method); - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - -+ if ((role = strchr(user, '/')) != NULL) -+ *role++ = 0; -+ - if ((style = strchr(user, ':')) != NULL) - *style++ = 0; -+ else if (role && (style = strchr(role, ':')) != NULL) -+ *style++ = '\0'; - - if (authctxt->attempt++ == 0) { - /* setup auth context */ -@@ -307,8 +312,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - use_privsep ? " [net]" : ""); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; -+ authctxt->role = role ? xstrdup(role) : NULL; - if (use_privsep) -- mm_inform_authserv(service, style); -+ mm_inform_authserv(service, style, role); - userauth_banner(ssh); - if (auth2_setup_methods_lists(authctxt) != 0) - ssh_packet_disconnect(ssh, -diff --git a/monitor.c b/monitor.c -index ebf76c7f9..947fdfadc 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -118,6 +118,7 @@ int mm_answer_sign(struct ssh *, int, struct sshbuf *); - int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *); - int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *); - int mm_answer_authserv(struct ssh *, int, struct sshbuf *); -+int mm_answer_authrole(struct ssh *, int, struct sshbuf *); - int mm_answer_authpassword(struct ssh *, int, struct sshbuf *); - int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *); - int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *); -@@ -198,6 +199,7 @@ struct mon_table mon_dispatch_proto20[] = { - {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, - {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, - {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, -+ {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, - {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, - {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, - #ifdef USE_PAM -@@ -820,6 +822,7 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m) - - /* Allow service/style information on the auth context */ - monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); - - #ifdef USE_PAM -@@ -853,16 +856,42 @@ mm_answer_authserv(struct ssh *ssh, int sock, struct sshbuf *m) - monitor_permit_authentications(1); - - if ((r = sshbuf_get_cstring(m, &authctxt->service, NULL)) != 0 || -- (r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0) -+ (r = sshbuf_get_cstring(m, &authctxt->style, NULL)) != 0 || -+ (r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -- debug3("%s: service=%s, style=%s", -- __func__, authctxt->service, authctxt->style); -+ debug3("%s: service=%s, style=%s, role=%s", -+ __func__, authctxt->service, authctxt->style, authctxt->role); - - if (strlen(authctxt->style) == 0) { - free(authctxt->style); - authctxt->style = NULL; - } - -+ if (strlen(authctxt->role) == 0) { -+ free(authctxt->role); -+ authctxt->role = NULL; -+ } -+ -+ return (0); -+} -+ -+int -+mm_answer_authrole(struct ssh *ssh, int sock, struct sshbuf *m) -+{ -+ int r; -+ -+ monitor_permit_authentications(1); -+ -+ if ((r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ debug3("%s: role=%s", -+ __func__, authctxt->role); -+ -+ if (strlen(authctxt->role) == 0) { -+ free(authctxt->role); -+ authctxt->role = NULL; -+ } -+ - return (0); - } - -@@ -1554,7 +1583,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) - res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); - if (res == 0) - goto error; -- pty_setowner(authctxt->pw, s->tty); -+ pty_setowner(authctxt->pw, s->tty, authctxt->role); - - if ((r = sshbuf_put_u32(m, 1)) != 0 || - (r = sshbuf_put_cstring(m, s->tty)) != 0) -diff --git a/monitor.h b/monitor.h -index 2b1a2d590..4d87284aa 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -65,6 +65,8 @@ enum monitor_reqtype { - - MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, - MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, -+ -+ MONITOR_REQ_AUTHROLE = 154, - }; - - struct ssh; -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 6edb509a3..b49c268d3 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -364,10 +364,10 @@ mm_auth2_read_banner(void) - return (banner); - } - --/* Inform the privileged process about service and style */ -+/* Inform the privileged process about service, style, and role */ - - void --mm_inform_authserv(char *service, char *style) -+mm_inform_authserv(char *service, char *style, char *role) - { - struct sshbuf *m; - int r; -@@ -377,7 +377,8 @@ mm_inform_authserv(char *service, char *style) - if ((m = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new failed", __func__); - if ((r = sshbuf_put_cstring(m, service)) != 0 || -- (r = sshbuf_put_cstring(m, style ? style : "")) != 0) -+ (r = sshbuf_put_cstring(m, style ? style : "")) != 0 || -+ (r = sshbuf_put_cstring(m, role ? role : "")) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, m); -@@ -385,6 +386,26 @@ mm_inform_authserv(char *service, char *style) - sshbuf_free(m); - } - -+/* Inform the privileged process about role */ -+ -+void -+mm_inform_authrole(char *role) -+{ -+ struct sshbuf *m; -+ int r; -+ -+ debug3("%s entering", __func__); -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_cstring(m, role ? role : "")) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, m); -+ -+ sshbuf_free(m); -+} -+ - /* Do the password authentication */ - int - mm_auth_password(struct ssh *ssh, char *password) -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 485590c18..370b08e17 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -47,7 +47,8 @@ DH *mm_choose_dh(int, int, int); - #endif - int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, - const u_char *, size_t, const char *, const char *, u_int compat); --void mm_inform_authserv(char *, char *); -+void mm_inform_authserv(char *, char *, char *); -+void mm_inform_authrole(char *); - struct passwd *mm_getpwnamallow(struct ssh *, const char *); - char *mm_auth2_read_banner(void); - int mm_auth_password(struct ssh *, char *); -diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index 622988822..3e6e07670 100644 ---- a/openbsd-compat/port-linux.c -+++ b/openbsd-compat/port-linux.c -@@ -56,7 +56,7 @@ ssh_selinux_enabled(void) - - /* Return the default security context for the given username */ - static security_context_t --ssh_selinux_getctxbyname(char *pwname) -+ssh_selinux_getctxbyname(char *pwname, const char *role) - { - security_context_t sc = NULL; - char *sename = NULL, *lvl = NULL; -@@ -71,9 +71,16 @@ ssh_selinux_getctxbyname(char *pwname) - #endif - - #ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -- r = get_default_context_with_level(sename, lvl, NULL, &sc); -+ if (role != NULL && role[0]) -+ r = get_default_context_with_rolelevel(sename, role, lvl, NULL, -+ &sc); -+ else -+ r = get_default_context_with_level(sename, lvl, NULL, &sc); - #else -- r = get_default_context(sename, NULL, &sc); -+ if (role != NULL && role[0]) -+ r = get_default_context_with_role(sename, role, NULL, &sc); -+ else -+ r = get_default_context(sename, NULL, &sc); - #endif - - if (r != 0) { -@@ -103,7 +110,7 @@ ssh_selinux_getctxbyname(char *pwname) - - /* Set the execution context to the default for the specified user */ - void --ssh_selinux_setup_exec_context(char *pwname) -+ssh_selinux_setup_exec_context(char *pwname, const char *role) - { - security_context_t user_ctx = NULL; - -@@ -112,7 +119,7 @@ ssh_selinux_setup_exec_context(char *pwname) - - debug3("%s: setting execution context", __func__); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -+ user_ctx = ssh_selinux_getctxbyname(pwname, role); - if (setexeccon(user_ctx) != 0) { - switch (security_getenforce()) { - case -1: -@@ -134,7 +141,7 @@ ssh_selinux_setup_exec_context(char *pwname) - - /* Set the TTY context for the specified user */ - void --ssh_selinux_setup_pty(char *pwname, const char *tty) -+ssh_selinux_setup_pty(char *pwname, const char *tty, const char *role) - { - security_context_t new_tty_ctx = NULL; - security_context_t user_ctx = NULL; -@@ -146,7 +153,7 @@ ssh_selinux_setup_pty(char *pwname, const char *tty) - - debug3("%s: setting TTY context on %s", __func__, tty); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -+ user_ctx = ssh_selinux_getctxbyname(pwname, role); - - /* XXX: should these calls fatal() upon failure in enforcing mode? */ - -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index 3c22a854d..c88129428 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -19,8 +19,8 @@ - - #ifdef WITH_SELINUX - int ssh_selinux_enabled(void); --void ssh_selinux_setup_pty(char *, const char *); --void ssh_selinux_setup_exec_context(char *); -+void ssh_selinux_setup_pty(char *, const char *, const char *); -+void ssh_selinux_setup_exec_context(char *, const char *); - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); - #endif -diff --git a/platform.c b/platform.c -index 44ba71dc5..2defe9425 100644 ---- a/platform.c -+++ b/platform.c -@@ -143,7 +143,7 @@ platform_setusercontext(struct passwd *pw) - * called if sshd is running as root. - */ - void --platform_setusercontext_post_groups(struct passwd *pw) -+platform_setusercontext_post_groups(struct passwd *pw, const char *role) - { - #if !defined(HAVE_LOGIN_CAP) && defined(USE_PAM) - /* -@@ -184,7 +184,7 @@ platform_setusercontext_post_groups(struct passwd *pw) - } - #endif /* HAVE_SETPCRED */ - #ifdef WITH_SELINUX -- ssh_selinux_setup_exec_context(pw->pw_name); -+ ssh_selinux_setup_exec_context(pw->pw_name, role); - #endif - } - -diff --git a/platform.h b/platform.h -index ea4f9c584..60d72ffe7 100644 ---- a/platform.h -+++ b/platform.h -@@ -25,7 +25,7 @@ void platform_post_fork_parent(pid_t child_pid); - void platform_post_fork_child(void); - int platform_privileged_uidswap(void); - void platform_setusercontext(struct passwd *); --void platform_setusercontext_post_groups(struct passwd *); -+void platform_setusercontext_post_groups(struct passwd *, const char *); - char *platform_get_krb5_client(const char *); - char *platform_krb5_get_principal_name(const char *); - int platform_sys_dir_uid(uid_t); -diff --git a/session.c b/session.c -index 06a33442a..871799590 100644 ---- a/session.c -+++ b/session.c -@@ -1360,7 +1360,7 @@ safely_chroot(const char *path, uid_t uid) - - /* Set login name, uid, gid, and groups. */ - void --do_setusercontext(struct passwd *pw) -+do_setusercontext(struct passwd *pw, const char *role) - { - char uidstr[32], *chroot_path, *tmp; - -@@ -1388,7 +1388,7 @@ do_setusercontext(struct passwd *pw) - endgrent(); - #endif - -- platform_setusercontext_post_groups(pw); -+ platform_setusercontext_post_groups(pw, role); - - if (!in_chroot && options.chroot_directory != NULL && - strcasecmp(options.chroot_directory, "none") != 0) { -@@ -1529,7 +1529,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) - - /* Force a password change */ - if (s->authctxt->force_pwchange) { -- do_setusercontext(pw); -+ do_setusercontext(pw, s->authctxt->role); - child_close_fds(ssh); - do_pwchange(s); - exit(1); -@@ -1547,7 +1547,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) - /* When PAM is enabled we rely on it to do the nologin check */ - if (!options.use_pam) - do_nologin(pw); -- do_setusercontext(pw); -+ do_setusercontext(pw, s->authctxt->role); - /* - * PAM session modules in do_setusercontext may have - * generated messages, so if this in an interactive -@@ -1946,7 +1946,7 @@ session_pty_req(struct ssh *ssh, Session *s) - sshpkt_fatal(ssh, r, "%s: parse packet", __func__); - - if (!use_privsep) -- pty_setowner(s->pw, s->tty); -+ pty_setowner(s->pw, s->tty, s->authctxt->role); - - /* Set window size from the packet. */ - pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); -diff --git a/session.h b/session.h -index ce59dabd9..675c91146 100644 ---- a/session.h -+++ b/session.h -@@ -77,7 +77,7 @@ void session_pty_cleanup2(Session *); - Session *session_new(void); - Session *session_by_tty(char *); - void session_close(struct ssh *, Session *); --void do_setusercontext(struct passwd *); -+void do_setusercontext(struct passwd *, const char *); - - const char *session_get_remote_name_or_ip(struct ssh *, u_int, int); - -diff --git a/sshd.c b/sshd.c -index 62dc55cf2..65916fc6d 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -595,7 +595,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) - reseed_prngs(); - - /* Drop privileges */ -- do_setusercontext(authctxt->pw); -+ do_setusercontext(authctxt->pw, authctxt->role); - - skip: - /* It is safe now to apply the key state */ -diff --git a/sshpty.c b/sshpty.c -index bce09e255..308449b37 100644 ---- a/sshpty.c -+++ b/sshpty.c -@@ -162,7 +162,7 @@ pty_change_window_size(int ptyfd, u_int row, u_int col, - } - - void --pty_setowner(struct passwd *pw, const char *tty) -+pty_setowner(struct passwd *pw, const char *tty, const char *role) - { - struct group *grp; - gid_t gid; -@@ -186,7 +186,7 @@ pty_setowner(struct passwd *pw, const char *tty) - strerror(errno)); - - #ifdef WITH_SELINUX -- ssh_selinux_setup_pty(pw->pw_name, tty); -+ ssh_selinux_setup_pty(pw->pw_name, tty, role); - #endif - - if (st.st_uid != pw->pw_uid || st.st_gid != gid) { -diff --git a/sshpty.h b/sshpty.h -index 9ec7e9a15..de7e000ae 100644 ---- a/sshpty.h -+++ b/sshpty.h -@@ -24,5 +24,5 @@ int pty_allocate(int *, int *, char *, size_t); - void pty_release(const char *); - void pty_make_controlling_tty(int *, const char *); - void pty_change_window_size(int, u_int, u_int, u_int, u_int); --void pty_setowner(struct passwd *, const char *); -+void pty_setowner(struct passwd *, const char *, const char *); - void disconnect_controlling_tty(void); diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 8c1046a..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,25 +0,0 @@ -gssapi.patch -restore-tcp-wrappers.patch -selinux-role.patch -ssh-vulnkey-compat.patch -keepalive-extensions.patch -syslog-level-silent.patch -user-group-modes.patch -scp-quoting.patch -shell-path.patch -dnssec-sshfp.patch -mention-ssh-keygen-on-keychange.patch -package-versioning.patch -debian-banner.patch -authorized-keys-man-symlink.patch -openbsd-docs.patch -ssh-argv0.patch -doc-hash-tab-completion.patch -ssh-agent-setgid.patch -no-openssl-version-status.patch -gnome-ssh-askpass2-icon.patch -systemd-readiness.patch -debian-config.patch -restore-authorized_keys2.patch -conch-old-privkey-format.patch -revert-ipqos-defaults.patch diff --git a/debian/patches/shell-path.patch b/debian/patches/shell-path.patch deleted file mode 100644 index 43fb1d1..0000000 --- a/debian/patches/shell-path.patch +++ /dev/null @@ -1,39 +0,0 @@ -From c19bcc02b07b450d585d0fd10ccd96174aeb3b7c Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:00 +0000 -Subject: Look for $SHELL on the path for ProxyCommand/LocalCommand - -There's some debate on the upstream bug about whether POSIX requires this. -I (Colin Watson) agree with Vincent and think it does. - -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1494 -Bug-Debian: http://bugs.debian.org/492728 -Last-Update: 2020-02-21 - -Patch-Name: shell-path.patch ---- - sshconnect.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/sshconnect.c b/sshconnect.c -index 4711af782..4a5d4a003 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -260,7 +260,7 @@ ssh_proxy_connect(struct ssh *ssh, const char *host, const char *host_arg, - /* Execute the proxy command. Note that we gave up any - extra privileges above. */ - ssh_signal(SIGPIPE, SIG_DFL); -- execv(argv[0], argv); -+ execvp(argv[0], argv); - perror(argv[0]); - exit(1); - } -@@ -1388,7 +1388,7 @@ ssh_local_cmd(const char *args) - if (pid == 0) { - ssh_signal(SIGPIPE, SIG_DFL); - debug3("Executing %s -c \"%s\"", shell, args); -- execl(shell, shell, "-c", args, (char *)NULL); -+ execlp(shell, shell, "-c", args, (char *)NULL); - error("Couldn't execute %s -c \"%s\": %s", - shell, args, strerror(errno)); - _exit(1); diff --git a/debian/patches/ssh-agent-setgid.patch b/debian/patches/ssh-agent-setgid.patch deleted file mode 100644 index e7849e6..0000000 --- a/debian/patches/ssh-agent-setgid.patch +++ /dev/null @@ -1,40 +0,0 @@ -From ad09303388f0172ab6e028aaf27d87cf873d123d Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:13 +0000 -Subject: Document consequences of ssh-agent being setgid in ssh-agent(1) - -Bug-Debian: http://bugs.debian.org/711623 -Forwarded: no -Last-Update: 2020-02-21 - -Patch-Name: ssh-agent-setgid.patch ---- - ssh-agent.1 | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/ssh-agent.1 b/ssh-agent.1 -index fff0db6bc..99e4f6d2e 100644 ---- a/ssh-agent.1 -+++ b/ssh-agent.1 -@@ -201,6 +201,21 @@ socket and stores its pathname in this variable. - It is accessible only to the current user, - but is easily abused by root or another instance of the same user. - .El -+.Pp -+In Debian, -+.Nm -+is installed with the set-group-id bit set, to prevent -+.Xr ptrace 2 -+attacks retrieving private key material. -+This has the side-effect of causing the run-time linker to remove certain -+environment variables which might have security implications for set-id -+programs, including -+.Ev LD_PRELOAD , -+.Ev LD_LIBRARY_PATH , -+and -+.Ev TMPDIR . -+If you need to set any of these environment variables, you will need to do -+so in the program executed by ssh-agent. - .Sh FILES - .Bl -tag -width Ds - .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent. diff --git a/debian/patches/ssh-argv0.patch b/debian/patches/ssh-argv0.patch deleted file mode 100644 index 8f79671..0000000 --- a/debian/patches/ssh-argv0.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4b1e0000a099f988553ccc4b274e1790b5114c12 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:10:10 +0000 -Subject: ssh(1): Refer to ssh-argv0(1) - -Old versions of OpenSSH (up to 2.5 or thereabouts) allowed creating symlinks -to ssh with the name of the host you want to connect to. Debian ships an -ssh-argv0 script restoring this feature; this patch refers to its manual -page from ssh(1). - -Bug-Debian: http://bugs.debian.org/111341 -Forwarded: not-needed -Last-Update: 2013-09-14 - -Patch-Name: ssh-argv0.patch ---- - ssh.1 | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ssh.1 b/ssh.1 -index 17b0e984f..b33a8049f 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -1610,6 +1610,7 @@ if an error occurred. - .Xr sftp 1 , - .Xr ssh-add 1 , - .Xr ssh-agent 1 , -+.Xr ssh-argv0 1 , - .Xr ssh-keygen 1 , - .Xr ssh-keyscan 1 , - .Xr tun 4 , diff --git a/debian/patches/ssh-vulnkey-compat.patch b/debian/patches/ssh-vulnkey-compat.patch deleted file mode 100644 index 99116e9..0000000 --- a/debian/patches/ssh-vulnkey-compat.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 11d571f137c76d8c2e38b1c1a537b04cc279f8e3 Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:09:50 +0000 -Subject: Accept obsolete ssh-vulnkey configuration options - -These options were used as part of Debian's response to CVE-2008-0166. -Nearly six years later, we no longer need to continue carrying the bulk -of that patch, but we do need to avoid failing when the associated -configuration options are still present. - -Last-Update: 2014-02-09 - -Patch-Name: ssh-vulnkey-compat.patch ---- - readconf.c | 1 + - servconf.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/readconf.c b/readconf.c -index da8022dd0..0fc996871 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -191,6 +191,7 @@ static struct { - { "fallbacktorsh", oDeprecated }, - { "globalknownhostsfile2", oDeprecated }, - { "rhostsauthentication", oDeprecated }, -+ { "useblacklistedkeys", oDeprecated }, - { "userknownhostsfile2", oDeprecated }, - { "useroaming", oDeprecated }, - { "usersh", oDeprecated }, -diff --git a/servconf.c b/servconf.c -index 191575a16..bf3cd84a4 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -656,6 +656,7 @@ static struct { - { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, - { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, - { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, -+ { "permitblacklistedkeys", sDeprecated, SSHCFG_GLOBAL }, - { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL }, - { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL }, - { "uselogin", sDeprecated, SSHCFG_GLOBAL }, diff --git a/debian/patches/syslog-level-silent.patch b/debian/patches/syslog-level-silent.patch deleted file mode 100644 index 234d95a..0000000 --- a/debian/patches/syslog-level-silent.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 387c2c1954773733bae9fca21a92db62c31180bd Mon Sep 17 00:00:00 2001 -From: Natalie Amery -Date: Sun, 9 Feb 2014 16:09:54 +0000 -Subject: "LogLevel SILENT" compatibility - -"LogLevel SILENT" (-qq) was introduced in Debian openssh 1:3.0.1p1-1 to -match the behaviour of non-free SSH, in which -q does not suppress fatal -errors. However, this was unintentionally broken in 1:4.6p1-2 and nobody -complained, so we've dropped most of it. The parts that remain are basic -configuration file compatibility, and an adjustment to "Pseudo-terminal will -not be allocated ..." which should be split out into a separate patch. - -Author: Matthew Vernon -Author: Colin Watson -Last-Update: 2013-09-14 - -Patch-Name: syslog-level-silent.patch ---- - log.c | 1 + - ssh.c | 2 +- - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/log.c b/log.c -index d9c2d136c..1749af6d1 100644 ---- a/log.c -+++ b/log.c -@@ -93,6 +93,7 @@ static struct { - LogLevel val; - } log_levels[] = - { -+ { "SILENT", SYSLOG_LEVEL_QUIET }, /* compatibility */ - { "QUIET", SYSLOG_LEVEL_QUIET }, - { "FATAL", SYSLOG_LEVEL_FATAL }, - { "ERROR", SYSLOG_LEVEL_ERROR }, -diff --git a/ssh.c b/ssh.c -index 110cf9c19..6138fd4d3 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1305,7 +1305,7 @@ main(int ac, char **av) - /* Do not allocate a tty if stdin is not a tty. */ - if ((!isatty(fileno(stdin)) || stdin_null_flag) && - options.request_tty != REQUEST_TTY_FORCE) { -- if (tty_flag) -+ if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) - logit("Pseudo-terminal will not be allocated because " - "stdin is not a terminal."); - tty_flag = 0; diff --git a/debian/patches/systemd-readiness.patch b/debian/patches/systemd-readiness.patch deleted file mode 100644 index fdcfca3..0000000 --- a/debian/patches/systemd-readiness.patch +++ /dev/null @@ -1,84 +0,0 @@ -From a208834b2d1811dac7054d7fdcdd04672f8b19f6 Mon Sep 17 00:00:00 2001 -From: Michael Biebl -Date: Mon, 21 Dec 2015 16:08:47 +0000 -Subject: Add systemd readiness notification support - -Bug-Debian: https://bugs.debian.org/778913 -Forwarded: no -Last-Update: 2017-08-22 - -Patch-Name: systemd-readiness.patch ---- - configure.ac | 24 ++++++++++++++++++++++++ - sshd.c | 9 +++++++++ - 2 files changed, 33 insertions(+) - -diff --git a/configure.ac b/configure.ac -index cee7cbc51..5db3013de 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -4664,6 +4664,29 @@ AC_ARG_WITH([kerberos5], - AC_SUBST([GSSLIBS]) - AC_SUBST([K5LIBS]) - -+# Check whether user wants systemd support -+SYSTEMD_MSG="no" -+AC_ARG_WITH(systemd, -+ [ --with-systemd Enable systemd support], -+ [ if test "x$withval" != "xno" ; then -+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) -+ if test "$PKGCONFIG" != "no"; then -+ AC_MSG_CHECKING([for libsystemd]) -+ if $PKGCONFIG --exists libsystemd; then -+ SYSTEMD_CFLAGS=`$PKGCONFIG --cflags libsystemd` -+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` -+ CPPFLAGS="$CPPFLAGS $SYSTEMD_CFLAGS" -+ SSHDLIBS="$SSHDLIBS $SYSTEMD_LIBS" -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if you want systemd support.]) -+ SYSTEMD_MSG="yes" -+ else -+ AC_MSG_RESULT([no]) -+ fi -+ fi -+ fi ] -+) -+ - # Looking for programs, paths and files - - PRIVSEP_PATH=/var/empty -@@ -5476,6 +5499,7 @@ echo " libldns support: $LDNS_MSG" - echo " Solaris process contract support: $SPC_MSG" - echo " Solaris project support: $SP_MSG" - echo " Solaris privilege support: $SPP_MSG" -+echo " systemd support: $SYSTEMD_MSG" - echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" - echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" - echo " BSD Auth support: $BSD_AUTH_MSG" -diff --git a/sshd.c b/sshd.c -index da876a900..c069505a0 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -85,6 +85,10 @@ - #include - #endif - -+#ifdef HAVE_SYSTEMD -+#include -+#endif -+ - #include "xmalloc.h" - #include "ssh.h" - #include "ssh2.h" -@@ -2027,6 +2031,11 @@ main(int ac, char **av) - } - } - -+#ifdef HAVE_SYSTEMD -+ /* Signal systemd that we are ready to accept connections */ -+ sd_notify(0, "READY=1"); -+#endif -+ - /* Accept a connection and return in a forked child */ - server_accept_loop(&sock_in, &sock_out, - &newsock, config_s); diff --git a/debian/patches/user-group-modes.patch b/debian/patches/user-group-modes.patch deleted file mode 100644 index 8bd35ad..0000000 --- a/debian/patches/user-group-modes.patch +++ /dev/null @@ -1,210 +0,0 @@ -From 3309e464e5ae6c940ddd584eed4d2d403f4c168c Mon Sep 17 00:00:00 2001 -From: Colin Watson -Date: Sun, 9 Feb 2014 16:09:58 +0000 -Subject: Allow harmless group-writability - -Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be -group-writable, provided that the group in question contains only the file's -owner. Rejected upstream for IMO incorrect reasons (e.g. a misunderstanding -about the contents of gr->gr_mem). Given that per-user groups and umask 002 -are the default setup in Debian (for good reasons - this makes operating in -setgid directories with other groups much easier), we need to permit this by -default. - -Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060 -Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347 -Last-Update: 2019-10-09 - -Patch-Name: user-group-modes.patch ---- - auth-rhosts.c | 6 ++---- - auth.c | 3 +-- - misc.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++----- - misc.h | 2 ++ - readconf.c | 3 +-- - ssh.1 | 2 ++ - ssh_config.5 | 2 ++ - 7 files changed, 63 insertions(+), 13 deletions(-) - -diff --git a/auth-rhosts.c b/auth-rhosts.c -index 7a10210b6..587f53721 100644 ---- a/auth-rhosts.c -+++ b/auth-rhosts.c -@@ -260,8 +260,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, - return 0; - } - if (options.strict_modes && -- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || -- (st.st_mode & 022) != 0)) { -+ !secure_permissions(&st, pw->pw_uid)) { - logit("Rhosts authentication refused for %.100s: " - "bad ownership or modes for home directory.", pw->pw_name); - auth_debug_add("Rhosts authentication refused for %.100s: " -@@ -287,8 +286,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, - * allowing access to their account by anyone. - */ - if (options.strict_modes && -- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || -- (st.st_mode & 022) != 0)) { -+ !secure_permissions(&st, pw->pw_uid)) { - logit("Rhosts authentication refused for %.100s: bad modes for %.200s", - pw->pw_name, buf); - auth_debug_add("Bad file modes for %.200s", buf); -diff --git a/auth.c b/auth.c -index 687c57b42..aed3c13ac 100644 ---- a/auth.c -+++ b/auth.c -@@ -474,8 +474,7 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host, - user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); - if (options.strict_modes && - (stat(user_hostfile, &st) == 0) && -- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || -- (st.st_mode & 022) != 0)) { -+ !secure_permissions(&st, pw->pw_uid)) { - logit("Authentication refused for %.100s: " - "bad owner or modes for %.200s", - pw->pw_name, user_hostfile); -diff --git a/misc.c b/misc.c -index 3a31d5c18..073d3be19 100644 ---- a/misc.c -+++ b/misc.c -@@ -61,8 +61,9 @@ - #include - #ifdef HAVE_PATHS_H - # include --#include - #endif -+#include -+#include - #ifdef SSH_TUN_OPENBSD - #include - #endif -@@ -1124,6 +1125,55 @@ percent_expand(const char *string, ...) - #undef EXPAND_MAX_KEYS - } - -+int -+secure_permissions(struct stat *st, uid_t uid) -+{ -+ if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid) -+ return 0; -+ if ((st->st_mode & 002) != 0) -+ return 0; -+ if ((st->st_mode & 020) != 0) { -+ /* If the file is group-writable, the group in question must -+ * have exactly one member, namely the file's owner. -+ * (Zero-member groups are typically used by setgid -+ * binaries, and are unlikely to be suitable.) -+ */ -+ struct passwd *pw; -+ struct group *gr; -+ int members = 0; -+ -+ gr = getgrgid(st->st_gid); -+ if (!gr) -+ return 0; -+ -+ /* Check primary group memberships. */ -+ while ((pw = getpwent()) != NULL) { -+ if (pw->pw_gid == gr->gr_gid) { -+ ++members; -+ if (pw->pw_uid != uid) -+ return 0; -+ } -+ } -+ endpwent(); -+ -+ pw = getpwuid(st->st_uid); -+ if (!pw) -+ return 0; -+ -+ /* Check supplementary group memberships. */ -+ if (gr->gr_mem[0]) { -+ ++members; -+ if (strcmp(pw->pw_name, gr->gr_mem[0]) || -+ gr->gr_mem[1]) -+ return 0; -+ } -+ -+ if (!members) -+ return 0; -+ } -+ return 1; -+} -+ - int - tun_open(int tun, int mode, char **ifname) - { -@@ -1909,8 +1959,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir, - snprintf(err, errlen, "%s is not a regular file", buf); - return -1; - } -- if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || -- (stp->st_mode & 022) != 0) { -+ if (!secure_permissions(stp, uid)) { - snprintf(err, errlen, "bad ownership or modes for file %s", - buf); - return -1; -@@ -1925,8 +1974,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir, - strlcpy(buf, cp, sizeof(buf)); - - if (stat(buf, &st) == -1 || -- (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || -- (st.st_mode & 022) != 0) { -+ !secure_permissions(&st, uid)) { - snprintf(err, errlen, - "bad ownership or modes for directory %s", buf); - return -1; -diff --git a/misc.h b/misc.h -index 4a05db2da..5db594b91 100644 ---- a/misc.h -+++ b/misc.h -@@ -188,6 +188,8 @@ struct notifier_ctx *notify_start(int, const char *, ...) - __attribute__((format(printf, 2, 3))); - void notify_complete(struct notifier_ctx *); - -+int secure_permissions(struct stat *st, uid_t uid); -+ - #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) - #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) - #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) -diff --git a/readconf.c b/readconf.c -index 2399208f8..7f251dd4a 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -1902,8 +1902,7 @@ read_config_file_depth(const char *filename, struct passwd *pw, - - if (fstat(fileno(f), &sb) == -1) - fatal("fstat %s: %s", filename, strerror(errno)); -- if (((sb.st_uid != 0 && sb.st_uid != getuid()) || -- (sb.st_mode & 022) != 0)) -+ if (!secure_permissions(&sb, getuid())) - fatal("Bad owner or permissions on %s", filename); - } - -diff --git a/ssh.1 b/ssh.1 -index db5c65bc7..cf991e4ee 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -1506,6 +1506,8 @@ The file format and configuration options are described in - .Xr ssh_config 5 . - Because of the potential for abuse, this file must have strict permissions: - read/write for the user, and not writable by others. -+It may be group-writable provided that the group in question contains only -+the user. - .Pp - .It Pa ~/.ssh/environment - Contains additional definitions for environment variables; see -diff --git a/ssh_config.5 b/ssh_config.5 -index 3079db19b..e61a0fd43 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -1952,6 +1952,8 @@ The format of this file is described above. - This file is used by the SSH client. - Because of the potential for abuse, this file must have strict permissions: - read/write for the user, and not writable by others. -+It may be group-writable provided that the group in question contains only -+the user. - .It Pa /etc/ssh/ssh_config - Systemwide configuration file. - This file provides defaults for those diff --git a/debian/source/format b/debian/source/format index 163aaf8..89ae9db 100644 --- a/debian/source/format +++ b/debian/source/format @@ -1 +1 @@ -3.0 (quilt) +3.0 (native)