From 318211936ae894df772bef2437501b6e61e73a9b7c54c40098a9f0c69d557e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Chv=C3=A1tal?= Date: Thu, 10 Oct 2019 13:32:50 +0000 Subject: [PATCH 1/3] Accepting request 737034 from home:hpjansson:branches:network Version update to 8.1p1: * ssh-keygen(1): when acting as a CA and signing certificates with an RSA key, default to using the rsa-sha2-512 signature algorithm. Certificates signed by RSA keys will therefore be incompatible with OpenSSH versions prior to 7.2 unless the default is overridden (using "ssh-keygen -t ssh-rsa -s ..."). * ssh(1): Allow %n to be expanded in ProxyCommand strings * ssh(1), sshd(8): Allow prepending a list of algorithms to the default set by starting the list with the '^' character, E.g. "HostKeyAlgorithms ^ssh-ed25519" * ssh-keygen(1): add an experimental lightweight signature and verification ability. Signatures may be made using regular ssh keys held on disk or stored in a ssh-agent and verified against an authorized_keys-like list of allowed keys. Signatures embed a namespace that prevents confusion and attacks between different usage domains (e.g. files vs email). * ssh-keygen(1): print key comment when extracting public key from a private key. * ssh-keygen(1): accept the verbose flag when searching for host keys in known hosts (i.e. "ssh-keygen -vF host") to print the matching host's random-art signature too. * All: support PKCS8 as an optional format for storage of private keys to disk. The OpenSSH native key format remains the default, but PKCS8 is a superior format to PEM if interoperability with non-OpenSSH software is required, as it may use a less insecure key derivation function than PEM's. - Additional changes from 8.0p1 release: * scp(1): Add "-T" flag to disable client-side filtering of server file list. * sshd(8): Remove support for obsolete "host/port" syntax. OBS-URL: https://build.opensuse.org/request/show/737034 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=197 --- ...-race-conditions-in-sshd-relating-to.patch | 252 -- ...h-7.7p1-X_forward_with_disabled_ipv6.patch | 21 +- openssh-7.7p1-cavstest-ctr.patch | 45 +- openssh-7.7p1-cavstest-kdf.patch | 41 +- openssh-7.7p1-disable_openssl_abi_check.patch | 50 +- openssh-7.7p1-fips.patch | 255 +- openssh-7.7p1-fips_checks.patch | 86 +- openssh-7.7p1-gssapi_key_exchange.patch | 3313 -------------- ...1-hostname_changes_when_forwarding_X.patch | 32 +- openssh-7.7p1-ldap.patch | 170 +- openssh-7.7p1-seccomp_ioctl_s390_EP11.patch | 36 - openssh-7.7p1-seed-prng.patch | 161 +- ...7.7p1-sftp_print_diagnostic_messages.patch | 45 +- openssh-7.9p1-CVE-2018-20685.patch | 33 - openssh-7.9p1-brace-expansion.patch | 348 -- openssh-7.9p1.tar.gz | 3 - openssh-7.9p1.tar.gz.asc | 14 - openssh-8.0p1-gssapi-keyex.patch | 3922 +++++++++++++++++ ...1-audit.patch => openssh-8.1p1-audit.patch | 1575 +++---- openssh-8.1p1.tar.gz | 3 + openssh-8.1p1.tar.gz.asc | 14 + ...2019-6109-force-progressmeter-update.patch | 110 - ...CVE-2019-6109-sanitize-scp-filenames.patch | 262 -- ...sh-CVE-2019-6111-scp-client-wildcard.patch | 186 - openssh-askpass-gnome.spec | 2 +- openssh-openssl-1_0_0-compatibility.patch | 41 - openssh.changes | 108 + openssh.spec | 14 +- 28 files changed, 5336 insertions(+), 5806 deletions(-) delete mode 100644 0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch delete mode 100644 openssh-7.7p1-gssapi_key_exchange.patch delete mode 100644 openssh-7.7p1-seccomp_ioctl_s390_EP11.patch delete mode 100644 openssh-7.9p1-CVE-2018-20685.patch delete mode 100644 openssh-7.9p1-brace-expansion.patch delete mode 100644 openssh-7.9p1.tar.gz delete mode 100644 openssh-7.9p1.tar.gz.asc create mode 100644 openssh-8.0p1-gssapi-keyex.patch rename openssh-7.7p1-audit.patch => openssh-8.1p1-audit.patch (53%) create mode 100644 openssh-8.1p1.tar.gz create mode 100644 openssh-8.1p1.tar.gz.asc delete mode 100644 openssh-CVE-2019-6109-force-progressmeter-update.patch delete mode 100644 openssh-CVE-2019-6109-sanitize-scp-filenames.patch delete mode 100644 openssh-CVE-2019-6111-scp-client-wildcard.patch delete mode 100644 openssh-openssl-1_0_0-compatibility.patch diff --git a/0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch b/0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch deleted file mode 100644 index 20f87a2..0000000 --- a/0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch +++ /dev/null @@ -1,252 +0,0 @@ -From 76a24b3fa193a9ca3e47a8779d497cb06500798b Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Fri, 1 Mar 2019 02:32:39 +0000 -Subject: upstream: Fix two race conditions in sshd relating to SIGHUP: -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -1. Recently-forked child processes will briefly remain listening to - listen_socks. If the main server sshd process completes its restart - via execv() before these sockets are closed by the child processes - then it can fail to listen at the desired addresses/ports and/or - fail to restart. - -2. When a SIGHUP is received, there may be forked child processes that - are awaiting their reexecution state. If the main server sshd - process restarts before passing this state, these child processes - will yield errors and use a fallback path of reading the current - sshd_config from the filesystem rather than use the one that sshd - was started with. - -To fix both of these cases, we reuse the startup_pipes that are shared -between the main server sshd and forked children. Previously this was -used solely to implement tracking of pre-auth child processes for -MaxStartups, but this extends the messaging over these pipes to include -a child->parent message that the parent process is safe to restart. This -message is sent from the child after it has completed its preliminaries: -closing listen_socks and receiving its reexec state. - -bz#2953, reported by Michal Koutný; ok markus@ dtucker@ - -OpenBSD-Commit-ID: 7df09eacfa3ce13e9a7b1e9f17276ecc924d65ab ---- - sshd.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 86 insertions(+), 28 deletions(-) - -Index: openssh-7.9p1/sshd.c -=================================================================== ---- openssh-7.9p1.orig/sshd.c 2019-03-11 15:26:34.532966127 +0100 -+++ openssh-7.9p1/sshd.c 2019-03-11 16:05:21.242748303 +0100 -@@ -240,9 +240,26 @@ u_int session_id2_len = 0; - /* record remote hostname or ip */ - u_int utmp_len = HOST_NAME_MAX+1; - --/* options.max_startup sized array of fd ints */ -+/* -+ * startup_pipes/flags are used for tracking children of the listening sshd -+ * process early in their lifespans. This tracking is needed for three things: -+ * -+ * 1) Implementing the MaxStartups limit of concurrent unauthenticated -+ * connections. -+ * 2) Avoiding a race condition for SIGHUP processing, where child processes -+ * may have listen_socks open that could collide with main listener process -+ * after it restarts. -+ * 3) Ensuring that rexec'd sshd processes have received their initial state -+ * from the parent listen process before handling SIGHUP. -+ * -+ * Child processes signal that they have completed closure of the listen_socks -+ * and (if applicable) received their rexec state by sending a char over their -+ * sock. Child processes signal that authentication has completed by closing -+ * the sock (or by exiting). -+ */ - int *startup_pipes = NULL; --int startup_pipe; /* in child */ -+static int *startup_flags = NULL; /* Indicates child closed listener */ -+static int startup_pipe = -1; /* in child */ - - /* variables used for privilege separation */ - int use_privsep = -1; -@@ -1081,14 +1098,9 @@ server_accept_inetd(int *sock_in, int *s - { - int fd; - -- startup_pipe = -1; - if (rexeced_flag) { - close(REEXEC_CONFIG_PASS_FD); - *sock_in = *sock_out = dup(STDIN_FILENO); -- if (!debug_flag) { -- startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); -- close(REEXEC_STARTUP_PIPE_FD); -- } - } else { - *sock_in = dup(STDIN_FILENO); - *sock_out = dup(STDOUT_FILENO); -@@ -1213,8 +1225,9 @@ server_accept_loop(int *sock_in, int *so - { - fd_set *fdset; - int i, j, ret, maxfd; -- int startups = 0; -+ int startups = 0, listening = 0, lameduck = 0; - int startup_p[2] = { -1 , -1 }; -+ char c = 0; - struct sockaddr_storage from; - socklen_t fromlen; - pid_t pid; -@@ -1228,6 +1241,7 @@ server_accept_loop(int *sock_in, int *so - maxfd = listen_socks[i]; - /* pipes connected to unauthenticated childs */ - startup_pipes = xcalloc(options.max_startups, sizeof(int)); -+ startup_flags = xcalloc(options.max_startups, sizeof(int)); - for (i = 0; i < options.max_startups; i++) - startup_pipes[i] = -1; - -@@ -1236,8 +1250,15 @@ server_accept_loop(int *sock_in, int *so - * the daemon is killed with a signal. - */ - for (;;) { -- if (received_sighup) -- sighup_restart(); -+ if (received_sighup) { -+ if (!lameduck) { -+ debug("Received SIGHUP; waiting for children"); -+ close_listen_socks(); -+ lameduck = 1; -+ } -+ if (listening <= 0) -+ sighup_restart(); -+ } - free(fdset); - fdset = xcalloc(howmany(maxfd + 1, NFDBITS), - sizeof(fd_mask)); -@@ -1264,19 +1285,37 @@ server_accept_loop(int *sock_in, int *so - if (ret < 0) - continue; - -- for (i = 0; i < options.max_startups; i++) -- if (startup_pipes[i] != -1 && -- FD_ISSET(startup_pipes[i], fdset)) { -- /* -- * the read end of the pipe is ready -- * if the child has closed the pipe -- * after successful authentication -- * or if the child has died -- */ -+ for (i = 0; i < options.max_startups; i++) { -+ if (startup_pipes[i] == -1 || -+ !FD_ISSET(startup_pipes[i], fdset)) -+ continue; -+ switch (read(startup_pipes[i], &c, sizeof(c))) { -+ case -1: -+ if (errno == EINTR || errno == EAGAIN) -+ continue; -+ if (errno != EPIPE) { -+ error("%s: startup pipe %d (fd=%d): " -+ "read %s", __func__, i, -+ startup_pipes[i], strerror(errno)); -+ } -+ /* FALLTHROUGH */ -+ case 0: -+ /* child exited or completed auth */ - close(startup_pipes[i]); - startup_pipes[i] = -1; - startups--; -+ if (startup_flags[i]) -+ listening--; -+ break; -+ case 1: -+ /* child has finished preliminaries */ -+ if (startup_flags[i]) { -+ listening--; -+ startup_flags[i] = 0; -+ } -+ break; - } -+ } - for (i = 0; i < num_listen_socks; i++) { - if (!FD_ISSET(listen_socks[i], fdset)) - continue; -@@ -1330,6 +1369,7 @@ server_accept_loop(int *sock_in, int *so - if (maxfd < startup_p[0]) - maxfd = startup_p[0]; - startups++; -+ startup_flags[j] = 1; - break; - } - if(!(--re_seeding_counter)) { -@@ -1359,7 +1399,7 @@ server_accept_loop(int *sock_in, int *so - send_rexec_state(config_s[0], cfg); - close(config_s[0]); - } -- break; -+ return; - } - - /* -@@ -1368,13 +1408,14 @@ server_accept_loop(int *sock_in, int *so - * parent continues listening. - */ - platform_pre_fork(); -+ listening++; - if ((pid = fork()) == 0) { - /* - * Child. Close the listening and - * max_startup sockets. Start using - * the accepted socket. Reinitialize - * logging (since our pid has changed). -- * We break out of the loop to handle -+ * We return from this function to handle - * the connection. - */ - platform_post_fork_child(); -@@ -1389,7 +1430,18 @@ server_accept_loop(int *sock_in, int *so - log_stderr); - if (rexec_flag) - close(config_s[0]); -- break; -+ else { -+ /* -+ * Signal parent that the preliminaries -+ * for this child are complete. For the -+ * re-exec case, this happens after the -+ * child has received the rexec state -+ * from the server. -+ */ -+ (void)atomicio(vwrite, startup_pipe, -+ "\0", 1); -+ } -+ return; - } - - /* Parent. Stay in the loop. */ -@@ -1421,10 +1473,6 @@ server_accept_loop(int *sock_in, int *so - #endif - explicit_bzero(rnd, sizeof(rnd)); - } -- -- /* child process check (or debug mode) */ -- if (num_listen_socks < 0) -- break; - } - } - -@@ -1760,8 +1808,18 @@ main(int ac, char **av) - /* Fetch our configuration */ - if ((cfg = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new failed", __func__); -- if (rexeced_flag) -+ if (rexeced_flag) { - recv_rexec_state(REEXEC_CONFIG_PASS_FD, cfg); -+ if (!debug_flag) { -+ startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); -+ close(REEXEC_STARTUP_PIPE_FD); -+ /* -+ * Signal parent that this child is at a point where -+ * they can go away if they have a SIGHUP pending. -+ */ -+ (void)atomicio(vwrite, startup_pipe, "\0", 1); -+ } -+ } - else if (strcasecmp(config_file_name, "none") != 0) - load_server_config(config_file_name, cfg); - diff --git a/openssh-7.7p1-X_forward_with_disabled_ipv6.patch b/openssh-7.7p1-X_forward_with_disabled_ipv6.patch index 5b4983a..5ab2d56 100644 --- a/openssh-7.7p1-X_forward_with_disabled_ipv6.patch +++ b/openssh-7.7p1-X_forward_with_disabled_ipv6.patch @@ -3,15 +3,11 @@ Do not throw away already open sockets for X11 forwarding if another socket family is not available for bind() -diff --git a/openssh-7.7p1/channels.c b/openssh-7.7p1/channels.c ---- openssh-7.7p1/channels.c -+++ openssh-7.7p1/channels.c -@@ -4421,16 +4421,23 @@ x11_create_display_inet(struct ssh *ssh, - if (ai->ai_family == AF_INET6) - sock_set_v6only(sock); - if (x11_use_localhost) - set_reuseaddr(sock); - if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { +diff --git a/channels.c b/channels.c +index f51b7e3..95af47e 100644 +--- a/channels.c ++++ b/channels.c +@@ -4637,6 +4637,13 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, debug2("%s: bind port %d: %.100s", __func__, port, strerror(errno)); close(sock); @@ -21,12 +17,7 @@ diff --git a/openssh-7.7p1/channels.c b/openssh-7.7p1/channels.c + * disabled while being supported) + */ + if (EADDRNOTAVAIL == errno) -+ continue; ++ continue; for (n = 0; n < num_socks; n++) close(socks[n]); num_socks = 0; - break; - } - socks[num_socks++] = sock; - if (num_socks == NUM_SOCKS) - break; diff --git a/openssh-7.7p1-cavstest-ctr.patch b/openssh-7.7p1-cavstest-ctr.patch index 5a2f363..7d3dda6 100644 --- a/openssh-7.7p1-cavstest-ctr.patch +++ b/openssh-7.7p1-cavstest-ctr.patch @@ -2,11 +2,11 @@ # Parent cc1022edba2c5eeb0facba08468f65afc2466b63 CAVS test for OpenSSH's own CTR encryption mode implementation -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in -+++ openssh-7.9p1/Makefile.in -@@ -24,6 +24,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpas +diff --git a/Makefile.in b/Makefile.in +index 7488595..d426006 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -24,6 +24,7 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper @@ -23,7 +23,7 @@ Index: openssh-7.9p1/Makefile.in XMSS_OBJS=\ ssh-xmss.o \ sshkey-xmss.o \ -@@ -204,6 +207,10 @@ sftp-server$(EXEEXT): $(LIBCOMPAT) libss +@@ -210,6 +213,10 @@ sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o s sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) @@ -34,7 +34,7 @@ Index: openssh-7.9p1/Makefile.in # test driver for the loginrec code - not built by default logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) -@@ -348,6 +355,7 @@ install-files: +@@ -354,6 +361,7 @@ install-files: $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) @@ -42,10 +42,11 @@ Index: openssh-7.9p1/Makefile.in $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -Index: openssh-7.9p1/cavstest-ctr.c -=================================================================== +diff --git a/cavstest-ctr.c b/cavstest-ctr.c +new file mode 100644 +index 0000000..f81cb72 --- /dev/null -+++ openssh-7.9p1/cavstest-ctr.c ++++ b/cavstest-ctr.c @@ -0,0 +1,214 @@ +/* + * @@ -261,13 +262,13 @@ Index: openssh-7.9p1/cavstest-ctr.c + printf("\n"); + return 0; +} -Index: openssh-7.9p1/cipher.c -=================================================================== ---- openssh-7.9p1.orig/cipher.c -+++ openssh-7.9p1/cipher.c -@@ -54,15 +54,6 @@ - #include "fips.h" - #include "log.h" +diff --git a/cipher.c b/cipher.c +index acca752..b67a4ff 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -58,15 +58,6 @@ + #define EVP_CIPHER_CTX void + #endif -struct sshcipher_ctx { - int plaintext; @@ -281,11 +282,11 @@ Index: openssh-7.9p1/cipher.c struct sshcipher { char *name; u_int block_size; -Index: openssh-7.9p1/cipher.h -=================================================================== ---- openssh-7.9p1.orig/cipher.h -+++ openssh-7.9p1/cipher.h -@@ -46,7 +46,15 @@ +diff --git a/cipher.h b/cipher.h +index 5843aab..d7d8c89 100644 +--- a/cipher.h ++++ b/cipher.h +@@ -48,7 +48,15 @@ #define CIPHER_DECRYPT 0 struct sshcipher; diff --git a/openssh-7.7p1-cavstest-kdf.patch b/openssh-7.7p1-cavstest-kdf.patch index bca6c3b..26280d4 100644 --- a/openssh-7.7p1-cavstest-kdf.patch +++ b/openssh-7.7p1-cavstest-kdf.patch @@ -2,10 +2,10 @@ # Parent 1e1d5a2ab8bddfc800f570755f9ea1addcc878c1 CAVS test for KDF implementation in OpenSSH -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in 2019-03-12 16:12:42.213142294 +0100 -+++ openssh-7.9p1/Makefile.in 2019-03-28 13:49:37.150166231 +0100 +diff --git a/Makefile.in b/Makefile.in +index d426006..85818f4 100644 +--- a/Makefile.in ++++ b/Makefile.in @@ -25,6 +25,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper @@ -23,7 +23,7 @@ Index: openssh-7.9p1/Makefile.in XMSS_OBJS=\ ssh-xmss.o \ -@@ -211,6 +212,9 @@ sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sft +@@ -217,6 +218,9 @@ sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glo cavstest-ctr$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-ctr.o $(LD) -o $@ cavstest-ctr.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) @@ -33,7 +33,7 @@ Index: openssh-7.9p1/Makefile.in # test driver for the loginrec code - not built by default logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) -@@ -356,6 +360,7 @@ install-files: +@@ -362,6 +366,7 @@ install-files: $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) @@ -41,11 +41,12 @@ Index: openssh-7.9p1/Makefile.in $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -Index: openssh-7.9p1/cavstest-kdf.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/cavstest-kdf.c 2019-03-28 13:54:20.047709759 +0100 -@@ -0,0 +1,384 @@ +diff --git a/cavstest-kdf.c b/cavstest-kdf.c +new file mode 100644 +index 0000000..a6ecf45 +--- /dev/null ++++ b/cavstest-kdf.c +@@ -0,0 +1,402 @@ +/* + * Copyright (C) 2015, Stephan Mueller + * @@ -93,6 +94,7 @@ Index: openssh-7.9p1/cavstest-kdf.c +#include + +#include "xmalloc.h" ++#include "ssherr.h" +#include "sshbuf.h" +#include "sshkey.h" +#include "cipher.h" @@ -208,6 +210,23 @@ Index: openssh-7.9p1/cavstest-kdf.c + unsigned int ik_len; +}; + ++#ifdef WITH_OPENSSL ++static int ++kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, ++ const BIGNUM *secret) ++{ ++ struct sshbuf *shared_secret; ++ int r; ++ ++ if ((shared_secret = sshbuf_new()) == NULL) ++ return SSH_ERR_ALLOC_FAIL; ++ if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) ++ r = kex_derive_keys(ssh, hash, hashlen, shared_secret); ++ sshbuf_free(shared_secret); ++ return r; ++} ++#endif ++ +static int sshkdf_cavs(struct kdf_cavs *test) +{ + int ret = 0; diff --git a/openssh-7.7p1-disable_openssl_abi_check.patch b/openssh-7.7p1-disable_openssl_abi_check.patch index 3d032ef..8e33f62 100644 --- a/openssh-7.7p1-disable_openssl_abi_check.patch +++ b/openssh-7.7p1-disable_openssl_abi_check.patch @@ -4,15 +4,11 @@ disable run-time check for OpenSSL ABI by version number as that is not a reliable indicator of ABI changes and doesn't make much sense in a distribution package -diff --git a/openssh-7.7p1/configure.ac b/openssh-7.7p1/configure.ac ---- openssh-7.7p1/configure.ac -+++ openssh-7.7p1/configure.ac -@@ -4895,16 +4895,29 @@ AC_ARG_WITH([bsd-auth], - if test "x$withval" != "xno" ; then - AC_DEFINE([BSD_AUTH], [1], - [Define if you have BSD auth support]) - BSD_AUTH_MSG=yes - fi +diff --git a/configure.ac b/configure.ac +index 42ffd95..20a1884 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -4878,6 +4878,19 @@ AC_ARG_WITH([bsd-auth], ] ) @@ -32,33 +28,21 @@ diff --git a/openssh-7.7p1/configure.ac b/openssh-7.7p1/configure.ac # Where to place sshd.pid piddir=/var/run # make sure the directory exists - if test ! -d $piddir ; then - piddir=`eval echo ${sysconfdir}` - case $piddir in - NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;; - esac -diff --git a/openssh-7.7p1/entropy.c b/openssh-7.7p1/entropy.c ---- openssh-7.7p1/entropy.c -+++ openssh-7.7p1/entropy.c -@@ -209,19 +209,21 @@ rexec_recv_rng_seed(Buffer *m) - #endif /* OPENSSL_PRNG_ONLY */ +diff --git a/entropy.c b/entropy.c +index f8b9f42..4957b23 100644 +--- a/entropy.c ++++ b/entropy.c +@@ -223,11 +223,13 @@ seed_rng(void) + /* Initialise libcrypto */ + ssh_libcrypto_init(); - void - seed_rng(void) - { - #ifndef OPENSSL_PRNG_ONLY - unsigned char buf[RANDOM_SEED_SIZE]; - #endif +#ifndef DISTRO_SSL - if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, SSLeay())) + if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, + OpenSSL_version_num())) fatal("OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + "have %lx", (u_long)OPENSSL_VERSION_NUMBER, + OpenSSL_version_num()); +#endif #ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - debug3("RNG is ready, skipping seeding"); - return; - } - - if (seed_from_prngd(buf, sizeof(buf)) == -1) + if (RAND_status() == 1) diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch index 0b3ba6c..41d2379 100644 --- a/openssh-7.7p1-fips.patch +++ b/openssh-7.7p1-fips.patch @@ -3,23 +3,23 @@ FIPS 140-2 compliance. Perform selftests on start and use only FIPS approved algorithms. -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in 2019-02-28 17:20:15.767164591 +0100 -+++ openssh-7.9p1/Makefile.in 2019-03-12 11:41:49.662894934 +0100 -@@ -102,6 +102,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ +diff --git a/Makefile.in b/Makefile.in +index 1d2b2d9..7488595 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -103,6 +103,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ platform-pledge.o platform-tracing.o platform-misc.o + +LIBSSH_OBJS += fips.o + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ sshconnect.o sshconnect2.o mux.o -Index: openssh-7.9p1/cipher-ctr.c -=================================================================== ---- openssh-7.9p1.orig/cipher-ctr.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/cipher-ctr.c 2019-02-28 17:20:15.919165544 +0100 +diff --git a/cipher-ctr.c b/cipher-ctr.c +index 32771f2..b66f92f 100644 +--- a/cipher-ctr.c ++++ b/cipher-ctr.c @@ -27,6 +27,8 @@ #include "xmalloc.h" #include "log.h" @@ -38,20 +38,21 @@ Index: openssh-7.9p1/cipher-ctr.c #endif return (&aes_ctr); } -Index: openssh-7.9p1/cipher.c -=================================================================== ---- openssh-7.9p1.orig/cipher.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/cipher.c 2019-03-12 11:41:49.662894934 +0100 -@@ -51,6 +51,8 @@ +diff --git a/cipher.c b/cipher.c +index 25f98ba..acca752 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -51,6 +51,9 @@ #include "openbsd-compat/openssl-compat.h" +#include "fips.h" +#include "log.h" - - struct sshcipher_ctx { - int plaintext; -@@ -80,7 +82,7 @@ struct sshcipher { ++ + #ifndef WITH_OPENSSL + #define EVP_CIPHER_CTX void + #endif +@@ -83,7 +86,7 @@ struct sshcipher { #endif }; @@ -60,7 +61,7 @@ Index: openssh-7.9p1/cipher.c #ifdef WITH_OPENSSL #ifndef OPENSSL_NO_DES { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, -@@ -111,8 +113,52 @@ static const struct sshcipher ciphers[] +@@ -114,8 +117,52 @@ static const struct sshcipher ciphers[] = { { NULL, 0, 0, 0, 0, 0, NULL } }; @@ -113,7 +114,7 @@ Index: openssh-7.9p1/cipher.c /* Returns a comma-separated list of supported ciphers. */ char * cipher_alg_list(char sep, int auth_only) -@@ -121,7 +167,7 @@ cipher_alg_list(char sep, int auth_only) +@@ -124,7 +171,7 @@ cipher_alg_list(char sep, int auth_only) size_t nlen, rlen = 0; const struct sshcipher *c; @@ -122,7 +123,7 @@ Index: openssh-7.9p1/cipher.c if ((c->flags & CFLAG_INTERNAL) != 0) continue; if (auth_only && c->auth_len == 0) -@@ -193,7 +239,7 @@ const struct sshcipher * +@@ -196,7 +243,7 @@ const struct sshcipher * cipher_by_name(const char *name) { const struct sshcipher *c; @@ -131,10 +132,11 @@ Index: openssh-7.9p1/cipher.c if (strcmp(c->name, name) == 0) return c; return NULL; -Index: openssh-7.9p1/fips.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/fips.c 2019-03-12 11:42:10.971006569 +0100 +diff --git a/fips.c b/fips.c +new file mode 100644 +index 0000000..23e3876 +--- /dev/null ++++ b/fips.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012 Petr Cerny. All rights reserved. @@ -348,10 +350,11 @@ Index: openssh-7.9p1/fips.c + return dgst; +} + -Index: openssh-7.9p1/fips.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/fips.h 2019-03-12 11:41:49.514894158 +0100 +diff --git a/fips.h b/fips.h +new file mode 100644 +index 0000000..a115a61 +--- /dev/null ++++ b/fips.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012 Petr Cerny. All rights reserved. @@ -397,11 +400,11 @@ Index: openssh-7.9p1/fips.h + +#endif + -Index: openssh-7.9p1/hmac.c -=================================================================== ---- openssh-7.9p1.orig/hmac.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/hmac.c 2019-02-28 17:20:15.919165544 +0100 -@@ -144,7 +144,7 @@ hmac_test(void *key, size_t klen, void * +diff --git a/hmac.c b/hmac.c +index 3268887..b905a1e 100644 +--- a/hmac.c ++++ b/hmac.c +@@ -146,7 +146,7 @@ hmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen) size_t i; u_char digest[16]; @@ -410,11 +413,11 @@ Index: openssh-7.9p1/hmac.c printf("ssh_hmac_start failed"); if (ssh_hmac_init(ctx, key, klen) < 0 || ssh_hmac_update(ctx, m, mlen) < 0 || -Index: openssh-7.9p1/kex.c -=================================================================== ---- openssh-7.9p1.orig/kex.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/kex.c 2019-02-28 17:20:15.919165544 +0100 -@@ -54,6 +54,8 @@ +diff --git a/kex.c b/kex.c +index 49d7015..1f82c2e 100644 +--- a/kex.c ++++ b/kex.c +@@ -60,6 +60,8 @@ #include "sshbuf.h" #include "digest.h" @@ -423,7 +426,7 @@ Index: openssh-7.9p1/kex.c /* prototype */ static int kex_choose_conf(struct ssh *); static int kex_input_newkeys(int, u_int32_t, struct ssh *); -@@ -77,7 +79,7 @@ struct kexalg { +@@ -83,7 +85,7 @@ struct kexalg { int ec_nid; int hash_alg; }; @@ -432,8 +435,8 @@ Index: openssh-7.9p1/kex.c #ifdef WITH_OPENSSL { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -@@ -106,6 +108,47 @@ static const struct kexalg kexalgs[] = { - { NULL, -1, -1, -1}, +@@ -114,6 +116,47 @@ static const struct kexalg kexalgs[] = { + { NULL, 0, -1, -1}, }; +static const struct kexalg kexalgs_fips140_2[] = { @@ -480,7 +483,7 @@ Index: openssh-7.9p1/kex.c char * kex_alg_list(char sep) { -@@ -113,7 +156,7 @@ kex_alg_list(char sep) +@@ -121,7 +164,7 @@ kex_alg_list(char sep) size_t nlen, rlen = 0; const struct kexalg *k; @@ -489,7 +492,7 @@ Index: openssh-7.9p1/kex.c if (ret != NULL) ret[rlen++] = sep; nlen = strlen(k->name); -@@ -133,7 +176,7 @@ kex_alg_by_name(const char *name) +@@ -141,7 +184,7 @@ kex_alg_by_name(const char *name) { const struct kexalg *k; @@ -498,7 +501,7 @@ Index: openssh-7.9p1/kex.c if (strcmp(k->name, name) == 0) return k; } -@@ -153,7 +196,10 @@ kex_names_valid(const char *names) +@@ -161,7 +204,10 @@ kex_names_valid(const char *names) for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (kex_alg_by_name(p) == NULL) { @@ -509,11 +512,11 @@ Index: openssh-7.9p1/kex.c free(s); return 0; } -Index: openssh-7.9p1/mac.c -=================================================================== ---- openssh-7.9p1.orig/mac.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/mac.c 2019-02-28 17:20:15.923165569 +0100 -@@ -40,6 +40,9 @@ +diff --git a/mac.c b/mac.c +index f3dda66..90d71c8 100644 +--- a/mac.c ++++ b/mac.c +@@ -41,6 +41,9 @@ #include "openbsd-compat/openssl-compat.h" @@ -523,7 +526,7 @@ Index: openssh-7.9p1/mac.c #define SSH_DIGEST 1 /* SSH_DIGEST_XXX */ #define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ #define SSH_UMAC128 3 -@@ -54,7 +57,7 @@ struct macalg { +@@ -55,7 +58,7 @@ struct macalg { int etm; /* Encrypt-then-MAC */ }; @@ -532,7 +535,7 @@ Index: openssh-7.9p1/mac.c /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, -@@ -82,6 +85,41 @@ static const struct macalg macs[] = { +@@ -79,6 +82,41 @@ static const struct macalg macs[] = { { NULL, 0, 0, 0, 0, 0, 0 } }; @@ -574,7 +577,7 @@ Index: openssh-7.9p1/mac.c /* Returns a list of supported MACs separated by the specified char. */ char * mac_alg_list(char sep) -@@ -90,7 +128,7 @@ mac_alg_list(char sep) +@@ -87,7 +125,7 @@ mac_alg_list(char sep) size_t nlen, rlen = 0; const struct macalg *m; @@ -583,7 +586,7 @@ Index: openssh-7.9p1/mac.c if (ret != NULL) ret[rlen++] = sep; nlen = strlen(m->name); -@@ -129,7 +167,7 @@ mac_setup(struct sshmac *mac, char *name +@@ -126,7 +164,7 @@ mac_setup(struct sshmac *mac, char *name) { const struct macalg *m; @@ -592,11 +595,11 @@ Index: openssh-7.9p1/mac.c if (strcmp(name, m->name) != 0) continue; if (mac != NULL) -Index: openssh-7.9p1/myproposal.h -=================================================================== ---- openssh-7.9p1.orig/myproposal.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/myproposal.h 2019-02-28 17:20:15.923165569 +0100 -@@ -151,6 +151,8 @@ +diff --git a/myproposal.h b/myproposal.h +index 34bd10c..e6be484 100644 +--- a/myproposal.h ++++ b/myproposal.h +@@ -144,6 +144,8 @@ #else /* WITH_OPENSSL */ @@ -605,10 +608,10 @@ Index: openssh-7.9p1/myproposal.h #define KEX_SERVER_KEX \ "curve25519-sha256," \ "curve25519-sha256@libssh.org" -Index: openssh-7.9p1/readconf.c -=================================================================== ---- openssh-7.9p1.orig/readconf.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/readconf.c 2019-02-28 20:20:19.619112418 +0100 +diff --git a/readconf.c b/readconf.c +index f78b4d6..228f481 100644 +--- a/readconf.c ++++ b/readconf.c @@ -68,6 +68,8 @@ #include "myproposal.h" #include "digest.h" @@ -618,7 +621,7 @@ Index: openssh-7.9p1/readconf.c /* Format of the configuration file: # Configuration data is parsed as follows: -@@ -1816,6 +1818,23 @@ option_clear_or_none(const char *o) +@@ -1837,6 +1839,23 @@ option_clear_or_none(const char *o) return o == NULL || strcasecmp(o, "none") == 0; } @@ -642,7 +645,7 @@ Index: openssh-7.9p1/readconf.c /* * Initializes options to special values that indicate that they have not yet * been set. Read_config_file will only set options with this value. Options -@@ -2095,6 +2114,8 @@ fill_default_options(Options * options) +@@ -2116,6 +2135,8 @@ fill_default_options(Options * options) options->canonicalize_hostname = SSH_CANONICALISE_NO; if (options->fingerprint_hash == -1) options->fingerprint_hash = SSH_FP_HASH_DEFAULT; @@ -651,7 +654,7 @@ Index: openssh-7.9p1/readconf.c if (options->update_hostkeys == -1) options->update_hostkeys = 0; -@@ -2122,6 +2143,7 @@ fill_default_options(Options * options) +@@ -2143,6 +2164,7 @@ fill_default_options(Options * options) free(all_kex); free(all_key); free(all_sig); @@ -659,10 +662,10 @@ Index: openssh-7.9p1/readconf.c #define CLEAR_ON_NONE(v) \ do { \ -Index: openssh-7.9p1/readconf.h -=================================================================== ---- openssh-7.9p1.orig/readconf.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/readconf.h 2019-02-28 17:20:15.923165569 +0100 +diff --git a/readconf.h b/readconf.h +index 8e36bf3..67111e9 100644 +--- a/readconf.h ++++ b/readconf.h @@ -197,6 +197,7 @@ typedef struct { #define SSH_STRICT_HOSTKEY_YES 2 #define SSH_STRICT_HOSTKEY_ASK 3 @@ -671,10 +674,10 @@ Index: openssh-7.9p1/readconf.h void initialize_options(Options *); void fill_default_options(Options *); void fill_default_options_for_canonicalization(Options *); -Index: openssh-7.9p1/servconf.c -=================================================================== ---- openssh-7.9p1.orig/servconf.c 2019-02-28 17:20:15.851165117 +0100 -+++ openssh-7.9p1/servconf.c 2019-02-28 17:20:15.923165569 +0100 +diff --git a/servconf.c b/servconf.c +index f58fecb..a8833a9 100644 +--- a/servconf.c ++++ b/servconf.c @@ -64,6 +64,7 @@ #include "auth.h" #include "myproposal.h" @@ -716,7 +719,7 @@ Index: openssh-7.9p1/servconf.c } static void -@@ -410,6 +430,8 @@ fill_default_server_options(ServerOption +@@ -424,6 +444,8 @@ fill_default_server_options(ServerOptions *options) options->fwd_opts.streamlocal_bind_unlink = 0; if (options->fingerprint_hash == -1) options->fingerprint_hash = SSH_FP_HASH_DEFAULT; @@ -725,20 +728,20 @@ Index: openssh-7.9p1/servconf.c if (options->disable_forwarding == -1) options->disable_forwarding = 0; if (options->expose_userauth_info == -1) -Index: openssh-7.9p1/ssh-keygen.c -=================================================================== ---- openssh-7.9p1.orig/ssh-keygen.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/ssh-keygen.c 2019-02-28 17:20:15.923165569 +0100 -@@ -61,6 +61,8 @@ - #include "utf8.h" +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 8c829ca..da63fb0 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -64,6 +64,8 @@ #include "authfd.h" + #include "sshsig.h" +#include "fips.h" + #ifdef WITH_OPENSSL # define DEFAULT_KEY_TYPE_NAME "rsa" #else -@@ -996,11 +998,13 @@ do_fingerprint(struct passwd *pw) +@@ -1002,11 +1004,13 @@ do_fingerprint(struct passwd *pw) static void do_gen_all_hostkeys(struct passwd *pw) { @@ -754,7 +757,7 @@ Index: openssh-7.9p1/ssh-keygen.c #ifdef WITH_OPENSSL { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, -@@ -1015,6 +1019,17 @@ do_gen_all_hostkeys(struct passwd *pw) +@@ -1021,6 +1025,17 @@ do_gen_all_hostkeys(struct passwd *pw) { NULL, NULL, NULL } }; @@ -769,10 +772,10 @@ Index: openssh-7.9p1/ssh-keygen.c + }; + + struct Key_types *key_types; + u_int32_t bits = 0; int first = 0; struct stat st; - struct sshkey *private, *public; -@@ -1022,6 +1037,12 @@ do_gen_all_hostkeys(struct passwd *pw) +@@ -1029,6 +1044,12 @@ do_gen_all_hostkeys(struct passwd *pw) int i, type, fd, r; FILE *f; @@ -785,7 +788,7 @@ Index: openssh-7.9p1/ssh-keygen.c for (i = 0; key_types[i].key_type; i++) { public = private = NULL; prv_tmp = pub_tmp = prv_file = pub_file = NULL; -@@ -2817,6 +2838,15 @@ main(int argc, char **argv) +@@ -3215,6 +3236,15 @@ main(int argc, char **argv) key_type_name = DEFAULT_KEY_TYPE_NAME; type = sshkey_type_from_name(key_type_name); @@ -801,35 +804,11 @@ Index: openssh-7.9p1/ssh-keygen.c type_bits_valid(type, key_type_name, &bits); if (!quiet) -Index: openssh-7.9p1/ssh_config.0 -=================================================================== ---- openssh-7.9p1.orig/ssh_config.0 2018-10-19 03:06:19.000000000 +0200 -+++ openssh-7.9p1/ssh_config.0 2019-02-28 17:20:15.923165569 +0100 -@@ -353,6 +353,9 @@ DESCRIPTION - Specifies the hash algorithm used when displaying key - fingerprints. Valid options are: md5 and sha256 (the default). - -+ In the FIPS mode the minimum of SHA-1 is enforced (which means -+ sha256). -+ - ForwardAgent - Specifies whether the connection to the authentication agent (if - any) will be forwarded to the remote machine. The argument must -@@ -610,6 +613,9 @@ DESCRIPTION - The list of available key exchange algorithms may also be - obtained using "ssh -Q kex". - -+ In the FIPS mode the FIPS standard takes precedence over RFC and -+ forces the minimum to a higher value, currently 2048 bits. -+ - LocalCommand - Specifies a command to execute on the local machine after - successfully connecting to the server. The command string -Index: openssh-7.9p1/ssh_config.5 -=================================================================== ---- openssh-7.9p1.orig/ssh_config.5 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/ssh_config.5 2019-02-28 17:20:15.923165569 +0100 -@@ -642,6 +642,8 @@ Valid options are: +diff --git a/ssh_config.5 b/ssh_config.5 +index 02a8789..f0cb291 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -664,6 +664,8 @@ Valid options are: and .Cm sha256 (the default). @@ -838,11 +817,11 @@ Index: openssh-7.9p1/ssh_config.5 .It Cm ForwardAgent Specifies whether the connection to the authentication agent (if any) will be forwarded to the remote machine. -Index: openssh-7.9p1/sshd.c -=================================================================== ---- openssh-7.9p1.orig/sshd.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/sshd.c 2019-03-12 11:41:49.514894158 +0100 -@@ -123,6 +123,8 @@ +diff --git a/sshd.c b/sshd.c +index 6b55ef7..c8086cd 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -127,6 +127,8 @@ #include "version.h" #include "ssherr.h" @@ -851,35 +830,11 @@ Index: openssh-7.9p1/sshd.c /* Re-exec fds */ #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) -Index: openssh-7.9p1/sshd_config.0 -=================================================================== ---- openssh-7.9p1.orig/sshd_config.0 2019-02-28 17:20:15.851165117 +0100 -+++ openssh-7.9p1/sshd_config.0 2019-02-28 17:20:15.927165594 +0100 -@@ -348,6 +348,9 @@ DESCRIPTION - Specifies the hash algorithm used when logging key fingerprints. - Valid options are: md5 and sha256. The default is sha256. - -+ In the FIPS mode the minimum of SHA-1 is enforced (which means -+ sha256). -+ - ForceCommand - Forces the execution of the command specified by ForceCommand, - ignoring any command supplied by the client and ~/.ssh/rc if -@@ -555,6 +558,9 @@ DESCRIPTION - The list of available key exchange algorithms may also be - obtained using "ssh -Q kex". - -+ In the FIPS mode the FIPS standard takes precedence over RFC and -+ forces the minimum to a higher value, currently 2048 bits. -+ - ListenAddress - Specifies the local addresses sshd(8) should listen on. The - following forms may be used: -Index: openssh-7.9p1/sshd_config.5 -=================================================================== ---- openssh-7.9p1.orig/sshd_config.5 2019-02-28 17:20:15.851165117 +0100 -+++ openssh-7.9p1/sshd_config.5 2019-02-28 17:20:15.927165594 +0100 -@@ -603,6 +603,8 @@ and +diff --git a/sshd_config.5 b/sshd_config.5 +index 0707b47..8818ea5 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -605,6 +605,8 @@ and .Cm sha256 . The default is .Cm sha256 . diff --git a/openssh-7.7p1-fips_checks.patch b/openssh-7.7p1-fips_checks.patch index 548574f..fc931bc 100644 --- a/openssh-7.7p1-fips_checks.patch +++ b/openssh-7.7p1-fips_checks.patch @@ -14,10 +14,11 @@ # file is not found (or the hash matches), proceed in non-FIPS mode and abort # otherwise. -Index: openssh-7.9p1/fips-check.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/fips-check.c 2019-03-12 11:42:19.299050200 +0100 +diff --git a/fips-check.c b/fips-check.c +new file mode 100644 +index 0000000..eceb031 +--- /dev/null ++++ b/fips-check.c @@ -0,0 +1,34 @@ +#include "includes.h" +#include @@ -53,10 +54,10 @@ Index: openssh-7.9p1/fips-check.c + fips_ssh_init(); + return 0; +} -Index: openssh-7.9p1/fips.c -=================================================================== ---- openssh-7.9p1.orig/fips.c 2019-03-12 11:42:19.299050200 +0100 -+++ openssh-7.9p1/fips.c 2019-03-12 11:43:02.363275819 +0100 +diff --git a/fips.c b/fips.c +index 23e3876..297ae99 100644 +--- a/fips.c ++++ b/fips.c @@ -35,30 +35,293 @@ #include "log.h" #include "xmalloc.h" @@ -245,9 +246,7 @@ Index: openssh-7.9p1/fips.c { int fips_required = 0; - char *env = getenv(SSH_FORCE_FIPS_ENV); -+ int fips_fd; -+ char fips_sys = 0; - +- - if (env) { - errno = 0; - fips_required = strtol(env, NULL, 10); @@ -257,6 +256,9 @@ Index: openssh-7.9p1/fips.c - fips_required = 0; - } else - fips_required = 1; ++ int fips_fd; ++ char fips_sys = 0; ++ + struct stat dummy; + if (-1 == stat(FIPS_PROC_PATH, &dummy)) { + switch (errno) { @@ -362,10 +364,10 @@ Index: openssh-7.9p1/fips.c int fips_mode(void) { -Index: openssh-7.9p1/fips.h -=================================================================== ---- openssh-7.9p1.orig/fips.h 2019-03-12 11:42:13.819021490 +0100 -+++ openssh-7.9p1/fips.h 2019-03-12 11:42:19.303050221 +0100 +diff --git a/fips.h b/fips.h +index a115a61..3404684 100644 +--- a/fips.h ++++ b/fips.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Petr Cerny. All rights reserved. @@ -402,38 +404,38 @@ Index: openssh-7.9p1/fips.h int fips_mode(void); int fips_correct_dgst(int); int fips_dgst_min(void); -@@ -41,4 +56,3 @@ enum fp_type fips_correct_fp_type(enum +@@ -41,4 +56,3 @@ enum fp_type fips_correct_fp_type(enum fp_type); int fips_filter_crypto(char **, fips_filters); #endif - -Index: openssh-7.9p1/sftp-server.c -=================================================================== ---- openssh-7.9p1.orig/sftp-server.c 2019-03-12 11:42:13.819021490 +0100 -+++ openssh-7.9p1/sftp-server.c 2019-03-12 11:42:19.303050221 +0100 -@@ -51,6 +51,8 @@ - #include "sftp.h" - #include "sftp-common.h" +diff --git a/sftp-server.c b/sftp-server.c +index b133cbc..c3086b6 100644 +--- a/sftp-server.c ++++ b/sftp-server.c +@@ -53,6 +53,8 @@ + + char *sftp_realpath(const char *, char *); /* sftp-realpath.c */ +#include "fips.h" + /* Our verbosity */ static LogLevel log_level = SYSLOG_LEVEL_ERROR; -@@ -1509,6 +1511,9 @@ sftp_server_main(int argc, char **argv, +@@ -1595,6 +1597,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) extern char *optarg; extern char *__progname; + /* initialize fips */ + fips_ssh_init(); + - ssh_malloc_init(); /* must be called before any mallocs */ __progname = ssh_get_progname(argv[0]); log_init(__progname, log_level, log_facility, log_stderr); -Index: openssh-7.9p1/ssh.c -=================================================================== ---- openssh-7.9p1.orig/ssh.c 2019-03-12 11:42:13.823021511 +0100 -+++ openssh-7.9p1/ssh.c 2019-03-12 11:42:19.303050221 +0100 + +diff --git a/ssh.c b/ssh.c +index ee51823..882d1da 100644 +--- a/ssh.c ++++ b/ssh.c @@ -113,6 +113,8 @@ #include "ssh-pkcs11.h" #endif @@ -443,29 +445,29 @@ Index: openssh-7.9p1/ssh.c extern char *__progname; /* Saves a copy of argv for setproctitle emulation */ -@@ -593,6 +595,10 @@ main(int ac, char **av) +@@ -596,6 +598,10 @@ main(int ac, char **av) struct ssh_digest_ctx *md; u_char conn_hash[SSH_DIGEST_MAX_LENGTH]; -+ /* initialize fips - can go before ssh_malloc_init(), since that is a -+ * OpenBSD-only thing (as of OpenSSH 7.6p1) */ ++ /* initialize fips - can go before ssh_malloc_init(), since that is a ++ * OpenBSD-only thing (as of OpenSSH 7.6p1) */ + fips_ssh_init(); + - ssh_malloc_init(); /* must be called before any mallocs */ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ sanitise_stdfd(); -Index: openssh-7.9p1/sshd.c -=================================================================== ---- openssh-7.9p1.orig/sshd.c 2019-03-12 11:42:13.823021511 +0100 -+++ openssh-7.9p1/sshd.c 2019-03-12 11:42:19.303050221 +0100 -@@ -1485,6 +1485,10 @@ main(int ac, char **av) + +diff --git a/sshd.c b/sshd.c +index c8086cd..bb20eec 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -1443,6 +1443,10 @@ main(int ac, char **av) Authctxt *authctxt; struct connection_info *connection_info = NULL; -+ /* initialize fips - can go before ssh_malloc_init(), since that is a -+ * OpenBSD-only thing (as of OpenSSH 7.6p1) */ ++ /* initialize fips - can go before ssh_malloc_init(), since that is a ++ * OpenBSD-only thing (as of OpenSSH 7.6p1) */ + fips_ssh_init(); + - ssh_malloc_init(); /* must be called before any mallocs */ - #ifdef HAVE_SECUREWARE + (void)set_auth_parameters(ac, av); + #endif diff --git a/openssh-7.7p1-gssapi_key_exchange.patch b/openssh-7.7p1-gssapi_key_exchange.patch deleted file mode 100644 index 5b764d9..0000000 --- a/openssh-7.7p1-gssapi_key_exchange.patch +++ /dev/null @@ -1,3313 +0,0 @@ -# HG changeset patch -# Parent 6a2300496d25e85647e718287d4d9f37170f492a - -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in 2019-02-27 15:43:51.360515721 +0100 -+++ openssh-7.9p1/Makefile.in 2019-02-27 15:43:55.360539487 +0100 -@@ -104,10 +104,13 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ - kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ - kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ -+ kexgssc.o \ - platform-pledge.o platform-tracing.o platform-misc.o - - LIBSSH_OBJS += fips.o - -+LIBSSH_OBJS += kexgssc.o kexgsss.o -+ - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect2.o mux.o - -@@ -119,7 +122,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw - 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 \ -Index: openssh-7.9p1/auth-krb5.c -=================================================================== ---- openssh-7.9p1.orig/auth-krb5.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/auth-krb5.c 2019-02-27 15:43:51.428516125 +0100 -@@ -182,8 +182,13 @@ auth_krb5_password(Authctxt *authctxt, c - - len = strlen(authctxt->krb5_ticket_file) + 6; - authctxt->krb5_ccname = xmalloc(len); -+#ifdef USE_CCAPI -+ snprintf(authctxt->krb5_ccname, len, "API:%s", -+ authctxt->krb5_ticket_file); -+#else - snprintf(authctxt->krb5_ccname, len, "FILE:%s", - authctxt->krb5_ticket_file); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -243,12 +248,18 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c - int tmpfd, ret, oerrno; - char ccname[40]; - mode_t old_umask; -+#ifdef USE_CCAPI -+ char cctemplate[] = "API:krb5cc_%d"; -+#else -+ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; -+#endif - - ret = snprintf(ccname, sizeof(ccname), -- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); -+ cctemplate, geteuid()); - if (ret < 0 || (size_t)ret >= sizeof(ccname)) - return ENOMEM; - -+#ifndef USE_CCAPI - old_umask = umask(0177); - tmpfd = mkstemp(ccname + strlen("FILE:")); - oerrno = errno; -@@ -265,6 +276,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_c - return oerrno; - } - close(tmpfd); -+#endif - - return (krb5_cc_resolve(ctx, ccname, ccache)); - } -Index: openssh-7.9p1/auth.c -=================================================================== ---- openssh-7.9p1.orig/auth.c 2019-02-27 15:43:51.228514936 +0100 -+++ openssh-7.9p1/auth.c 2019-02-27 15:43:55.360539487 +0100 -@@ -399,6 +399,7 @@ auth_root_allowed(struct ssh *ssh, const - case PERMIT_NO_PASSWD: - if (strcmp(method, "publickey") == 0 || - strcmp(method, "hostbased") == 0 || -+ strcmp(method, "gssapi-keyex") == 0 || - strcmp(method, "gssapi-with-mic") == 0) - return 1; - break; -Index: openssh-7.9p1/auth2-gss.c -=================================================================== ---- openssh-7.9p1.orig/auth2-gss.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/auth2-gss.c 2019-02-27 15:43:51.428516125 +0100 -@@ -31,6 +31,7 @@ - #include - - #include -+#include - - #include "xmalloc.h" - #include "sshkey.h" -@@ -55,6 +56,44 @@ static int input_gssapi_exchange_complet - 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 authenticated = 0; -+ struct sshbuf *b = NULL; -+ gss_buffer_desc mic, gssbuf; -+ u_int len; -+ -+ mic.value = packet_get_string(&len); -+ mic.length = len; -+ -+ packet_check_eom(); -+ -+ if ((b = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ ssh_gssapi_buildmic(b, authctxt->user, authctxt->service, -+ "gssapi-keyex"); -+ -+ gssbuf.value = sshbuf_mutable_ptr(b); -+ 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)); -+ -+ 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 +299,8 @@ input_gssapi_exchange_complete(int type, - 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)); - - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -306,7 +346,8 @@ input_gssapi_mic(int type, u_int32_t ple - 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)); - else - logit("GSSAPI MIC check failed"); - -@@ -326,6 +367,12 @@ input_gssapi_mic(int type, u_int32_t ple - return 0; - } - -+Authmethod method_gsskeyex = { -+ "gssapi-keyex", -+ userauth_gsskeyex, -+ &options.gss_authentication -+}; -+ - Authmethod method_gssapi = { - "gssapi-with-mic", - userauth_gssapi, -Index: openssh-7.9p1/auth2.c -=================================================================== ---- openssh-7.9p1.orig/auth2.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/auth2.c 2019-02-27 15:43:55.360539487 +0100 -@@ -74,6 +74,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -81,6 +82,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - &method_passwd, -Index: openssh-7.9p1/clientloop.c -=================================================================== ---- openssh-7.9p1.orig/clientloop.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/clientloop.c 2019-02-27 15:43:51.428516125 +0100 -@@ -112,6 +112,10 @@ - #include "ssherr.h" - #include "hostfile.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* import options */ - extern Options options; - -@@ -1370,9 +1374,18 @@ client_loop(struct ssh *ssh, int have_pt - 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((Gssctxt *)NULL)) { -+ debug("credentials updated - forcing rekey"); -+ need_rekeying = 1; -+ } -+#endif -+ } -+ - /* Buffer input from the connection. */ - client_process_net_input(readset); - -Index: openssh-7.9p1/configure.ac -=================================================================== ---- openssh-7.9p1.orig/configure.ac 2019-02-27 15:43:51.412516029 +0100 -+++ openssh-7.9p1/configure.ac 2019-02-27 15:43:55.192538489 +0100 -@@ -664,6 +664,30 @@ main() { if (NSVersionOfRunTimeLibrary(" - [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]) -@@ -1844,9 +1868,9 @@ AC_RUN_IFELSE( - ) - - AC_LINK_IFELSE( -- [AC_LANG_PROGRAM( -- [[ #include ]], -- [[ return (isblank('a')); ]])], -+ [AC_LANG_PROGRAM( -+ [[ #include ]], -+ [[ return (isblank('a')); ]])], - [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) - ]) - -@@ -2175,7 +2199,7 @@ int snprintf(char *a, size_t b, const ch - ]])], - [AC_MSG_RESULT([yes]) - AC_DEFINE([SNPRINTF_CONST], [const], -- [Define as const if snprintf() can declare const char *fmt])], -+ [Define as const if snprintf() can declare const char *fmt])], - [AC_MSG_RESULT([no]) - AC_DEFINE([SNPRINTF_CONST], [/* not const */])]) - -@@ -2190,7 +2214,7 @@ if test "x$ac_cv_func_getpeereid" != "xy - AC_DEFINE([HAVE_SO_PEERCRED], [1], [Have PEERCRED socket option]) - ], [AC_MSG_RESULT([no]) - NO_PEERCHECK=1 -- ]) -+ ]) - fi - - dnl see whether mkstemp() requires XXXXXX -@@ -4601,7 +4625,7 @@ AC_ARG_WITH([maildir], - if test "X$withval" != X && test "x$withval" != xno && \ - test "x${withval}" != xyes; then - AC_DEFINE_UNQUOTED([MAIL_DIRECTORY], ["$withval"], -- [Set this to your mail directory if you do not have _PATH_MAILDIR]) -+ [Set this to your mail directory if you do not have _PATH_MAILDIR]) - fi - ],[ - if test "X$maildir" != "X"; then -Index: openssh-7.9p1/gss-genr.c -=================================================================== ---- openssh-7.9p1.orig/gss-genr.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/gss-genr.c 2019-02-27 15:43:54.528534543 +0100 -@@ -41,12 +41,174 @@ - #include "sshbuf.h" - #include "log.h" - #include "ssh2.h" -+#include "cipher.h" -+#include "sshkey.h" -+#include "kex.h" -+#include - - #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() { -+ return (gss_enc2oid != NULL); -+} -+ -+/* -+ * 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; -+ 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)); -+} -+ -+char * -+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, -+ const char *host, const char *client) { -+ struct sshbuf *buf; -+ size_t i; -+ int oidpos, enclen, r; -+ char *mechs, *encoded; -+ u_char digest[EVP_MAX_MD_SIZE]; -+ char deroid[2]; -+ const EVP_MD *evp_md = EVP_md5(); -+ EVP_MD_CTX *md; -+ -+ 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__); -+ -+ md = EVP_MD_CTX_new(); -+ oidpos = 0; -+ 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; -+ -+ EVP_DigestInit(md, evp_md); -+ EVP_DigestUpdate(md, deroid, 2); -+ EVP_DigestUpdate(md, -+ gss_supported->elements[i].elements, -+ gss_supported->elements[i].length); -+ EVP_DigestFinal(md, digest, NULL); -+ -+ encoded = xmalloc(EVP_MD_size(evp_md) * 2); -+ enclen = __b64_ntop(digest, EVP_MD_size(evp_md), -+ encoded, EVP_MD_size(evp_md) * 2); -+ -+ if (oidpos != 0) -+ if ((r = sshbuf_put_u8(buf, ',')) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ if ((r = sshbuf_put(buf, KEX_GSS_GEX_SHA1_ID, -+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1)) != 0 || -+ (r = sshbuf_put(buf, encoded, enclen)) != 0 || -+ (r = sshbuf_put_u8(buf, ',')) != 0 || -+ (r = sshbuf_put(buf, KEX_GSS_GRP1_SHA1_ID, -+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1)) != 0 || -+ (r = sshbuf_put(buf, encoded, enclen)) != 0 || -+ (r = sshbuf_put_u8(buf, ',')) != 0 || -+ (r = sshbuf_put(buf, KEX_GSS_GRP14_SHA1_ID, -+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1)) != 0 || -+ (r = sshbuf_put(buf, encoded, enclen)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); -+ gss_enc2oid[oidpos].encoded = encoded; -+ oidpos++; -+ } -+ } -+ EVP_MD_CTX_free(md); -+ gss_enc2oid[oidpos].oid = NULL; -+ gss_enc2oid[oidpos].encoded = NULL; -+ -+ if ((r = sshbuf_put_u8(buf, '\0')) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ mechs = xmalloc(sshbuf_len(buf)); -+ sshbuf_get(buf, mechs, sshbuf_len(buf)); -+ 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; -+ -+ switch (kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GRP1_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GRP1_SHA1_ID) - 1; -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GRP14_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GRP14_SHA1_ID) - 1; -+ break; -+ case KEX_GSS_GEX_SHA1: -+ if (strlen(name) < sizeof(KEX_GSS_GEX_SHA1_ID)) -+ return GSS_C_NO_OID; -+ name += sizeof(KEX_GSS_GEX_SHA1_ID) - 1; -+ break; -+ default: -+ return GSS_C_NO_OID; -+ } -+ -+ 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; -+} -+ - /* sshbuf_get for gss_buffer_desc */ - int - ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) -@@ -218,7 +380,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de - } - - 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); - -@@ -248,8 +410,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con - } - - 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 +453,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer - 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,22 +482,31 @@ ssh_gssapi_buildmic(struct sshbuf *b, co - } - - 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 && -+ if (oid->length == spnego_oid.length && - (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0)) - return 0; /* false */ - - 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, -+ major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, - NULL); - gss_release_buffer(&minor, &token); - if ((*ctx)->context != GSS_C_NO_CONTEXT) -@@ -296,10 +514,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx - 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 */ -Index: openssh-7.9p1/gss-serv-krb5.c -=================================================================== ---- openssh-7.9p1.orig/gss-serv-krb5.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/gss-serv-krb5.c 2019-02-27 15:43:51.432516148 +0100 -@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - krb5_error_code problem; - krb5_principal princ; - OM_uint32 maj_status, min_status; -- int len; -+ const char *new_ccname, *new_cctype; - const char *errmsg; - - if (client->creds == NULL) { -@@ -180,11 +180,23 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_cctype = krb5_cc_get_type(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); -+#else -+ if (new_ccname[0] == ':') -+ new_ccname++; -+ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); -+ if (strcmp(new_cctype, "DIR") == 0) { -+ char *p; -+ p = strrchr(client->store.envval, '/'); -+ if (p) -+ *p = '\0'; -+ } -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -193,9 +205,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl - - krb5_cc_close(krb_context, ccache); - -+ client->store.data = krb_context; -+ - 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 +282,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 */ -Index: openssh-7.9p1/gss-serv.c -=================================================================== ---- openssh-7.9p1.orig/gss-serv.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/gss-serv.c 2019-02-27 15:43:51.432516148 +0100 -@@ -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_NO_CREDENTIAL, GSS_C_NO_NAME, 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; -@@ -141,6 +143,28 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss - } - - /* Unprivileged */ -+char * -+ssh_gssapi_server_mechanisms() { -+ if (supported_oids == NULL) -+ ssh_gssapi_prepare_supported_oids(); -+ return (ssh_gssapi_kex_mechs(supported_oids, -+ &ssh_gssapi_server_check_mech, NULL, NULL)); -+} -+ -+/* 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 +174,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o - 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 +302,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; -+ } - -- gss_buffer_desc ename; -+ 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; -+ } -+ -+ 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 +358,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - 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 +382,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - 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; -@@ -319,11 +394,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g - void - ssh_gssapi_cleanup_creds(void) - { -- if (gssapi_client.store.filename != NULL) { -- /* Unlink probably isn't sufficient */ -- debug("removing gssapi cred file\"%s\"", -- gssapi_client.store.filename); -- unlink(gssapi_client.store.filename); -+ krb5_ccache ccache = NULL; -+ krb5_error_code problem; -+ -+ if (gssapi_client.store.data != NULL) { -+ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { -+ debug("%s: krb5_cc_resolve(): %.100s", __func__, -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { -+ debug("%s: krb5_cc_resolve(): %.100s", __func__, -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else { -+ krb5_free_context(gssapi_client.store.data); -+ gssapi_client.store.data = NULL; -+ } - } - } - -@@ -356,7 +440,7 @@ ssh_gssapi_do_child(char ***envp, u_int - - /* Privileged */ - int --ssh_gssapi_userok(char *user) -+ssh_gssapi_userok(char *user, struct passwd *pw) - { - OM_uint32 lmin; - -@@ -366,9 +450,11 @@ ssh_gssapi_userok(char *user) - 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 +468,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() { -+ int ok; -+ int ret; -+#ifdef USE_PAM -+ 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 */ -Index: openssh-7.9p1/kex.c -=================================================================== ---- openssh-7.9p1.orig/kex.c 2019-02-27 15:43:51.296515340 +0100 -+++ openssh-7.9p1/kex.c 2019-02-27 15:43:55.360539487 +0100 -@@ -56,6 +56,10 @@ - - #include "fips.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 *); -@@ -105,6 +109,11 @@ static const struct kexalg kexalgs_all[] - { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ -+#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 }, -+#endif - { NULL, -1, -1, -1}, - }; - -@@ -129,6 +138,10 @@ static const struct kexalg kexalgs_fips1 - # endif /* OPENSSL_HAS_NISTP521 */ - #endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+#ifdef GSSAPI -+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+#endif - { NULL, -1, -1, -1}, - }; - -@@ -179,6 +192,12 @@ kex_alg_by_name(const char *name) - for (k = fips_select_kexalgs(); k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) - return k; -+#ifdef GSSAPI -+ if (strncmp(name, "gss-", 4) == 0) { -+ if (strncmp(k->name, name, strlen(k->name)) == 0) -+ return k; -+ } -+#endif - } - return NULL; - } -Index: openssh-7.9p1/kex.h -=================================================================== ---- openssh-7.9p1.orig/kex.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/kex.h 2019-02-27 15:43:55.360539487 +0100 -@@ -100,6 +100,11 @@ enum kex_exchange { - KEX_DH_GEX_SHA256, - KEX_ECDH_SHA2, - KEX_C25519_SHA256, -+#ifdef GSSAPI -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GEX_SHA1, -+#endif - KEX_MAX - }; - -@@ -148,6 +153,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 *client_version_string; - char *server_version_string; - char *failed_choice; -@@ -197,6 +208,10 @@ int kexecdh_client(struct ssh *); - int kexecdh_server(struct ssh *); - int kexc25519_client(struct ssh *); - int kexc25519_server(struct ssh *); -+#ifdef GSSAPI -+int kexgss_client(struct ssh *); -+int kexgss_server(struct ssh *); -+#endif - - int kex_dh_hash(int, const char *, const char *, - const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, -Index: openssh-7.9p1/kexgssc.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/kexgssc.c 2019-02-27 15:44:14.792654941 +0100 -@@ -0,0 +1,346 @@ -+/* -+ * 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" -+ -+#ifdef GSSAPI -+ -+#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 "ssh-gss.h" -+ -+#include "fips.h" -+ -+int -+kexgss_client(struct ssh *ssh) -+{ -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ u_int klen, kout, slen = 0, strlen; -+ DH *dh; -+ BIGNUM *dh_server_pub = NULL; -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ const BIGNUM *pub_key, *p1, *g1; -+ u_char *kbuf; -+ u_char *serverhostkey = NULL; -+ u_char *empty = ""; -+ char *msg; -+ char *lang; -+ int type = 0; -+ int first = 1; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, ssh->kex->name, ssh->kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); -+ -+ if (ssh_gssapi_import_name(ctxt, ssh->kex->gss_host)) -+ fatal("Couldn't import hostname"); -+ -+ if (ssh->kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, ssh->kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); -+ -+ switch (ssh->kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ dh = dh_new_group1(); -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ dh = dh_new_group14(); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ debug("Doing group exchange\n"); -+ nbits = dh_estimate(ssh->kex->we_need * 8); -+ packet_start(SSH2_MSG_KEXGSS_GROUPREQ); -+ packet_put_int(min); -+ packet_put_int(nbits); -+ packet_put_int(max); -+ -+ packet_send(); -+ -+ packet_read_expect(SSH2_MSG_KEXGSS_GROUP); -+ -+ if ((p = BN_new()) == NULL) -+ fatal("BN_new() failed"); -+ packet_get_bignum2(p); -+ if ((g = BN_new()) == NULL) -+ fatal("BN_new() failed"); -+ packet_get_bignum2(g); -+ packet_check_eom(); -+ -+ 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); -+ -+ dh = dh_new_group(g, p); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); -+ } -+ -+ /* Step 1 - e is pub_key */ -+ dh_gen_key(dh, ssh->kex->we_need * 8); -+ DH_get0_key(dh, &pub_key, NULL); -+ -+ /* This is f, we initialise it now to make life easier */ -+ dh_server_pub = BN_new(); -+ if (dh_server_pub == NULL) -+ fatal("dh_server_pub == NULL"); -+ -+ token_ptr = GSS_C_NO_BUFFER; -+ -+ do { -+ debug("Calling gss_init_sec_context"); -+ -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ ssh->kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length != 0) { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ free(recv_tok.value); -+ -+ 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) { -+ packet_start(SSH2_MSG_KEXGSS_INIT); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ packet_put_bignum2((BIGNUM *)pub_key); -+ first = 0; -+ } else { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, -+ send_tok.length); -+ } -+ packet_send(); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = packet_read(); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (serverhostkey) -+ fatal("Server host key received more than once"); -+ serverhostkey = -+ packet_get_string(&slen); -+ } -+ } 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"); -+ recv_tok.value = packet_get_string(&strlen); -+ recv_tok.length = strlen; -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ packet_get_bignum2(dh_server_pub); -+ msg_tok.value = packet_get_string(&strlen); -+ msg_tok.length = strlen; -+ -+ /* Is there a token included? */ -+ if (packet_get_char()) { -+ recv_tok.value= -+ packet_get_string(&strlen); -+ recv_tok.length = strlen; -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ packet_disconnect("Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ packet_disconnect("Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ maj_status = packet_get_int(); -+ min_status = packet_get_int(); -+ msg = packet_get_string(NULL); -+ lang = packet_get_string(NULL); -+ fatal("GSSAPI Error: \n%.400s",msg); -+ default: -+ packet_disconnect("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"); -+ -+ /* Check f in range [1, p-1] */ -+ if (!dh_pub_is_valid(dh, dh_server_pub)) -+ packet_disconnect("bad server public DH value"); -+ -+ /* compute K=f^x mod p */ -+ klen = DH_size(dh); -+ kbuf = xmalloc(klen); -+ kout = DH_compute_key(kbuf, dh_server_pub, dh); -+ if (kout < 0) -+ fatal("DH_compute_key: failed"); -+ -+ shared_secret = BN_new(); -+ if (shared_secret == NULL) -+ fatal("kexgss_client: BN_new failed"); -+ -+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) -+ fatal("kexdh_client: BN_bin2bn failed"); -+ -+ memset(kbuf, 0, klen); -+ free(kbuf); -+ -+ hashlen = sizeof(hash); -+ switch (ssh->kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, -+ ssh->kex->server_version_string, -+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), -+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ pub_key, /* e */ -+ dh_server_pub, /* f */ -+ shared_secret, /* K */ -+ hash, &hashlen -+ ); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ DH_get0_pqg(dh, &p1, NULL, &g1); -+ kexgex_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, -+ ssh->kex->server_version_string, -+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), -+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ min, nbits, max, -+ p, g, -+ pub_key, -+ dh_server_pub, -+ shared_secret, -+ hash, &hashlen -+ ); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->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))) -+ packet_disconnect("Hash's MIC didn't verify"); -+ -+ free(msg_tok.value); -+ -+ DH_free(dh); -+ if (serverhostkey) -+ free(serverhostkey); -+ BN_clear_free(dh_server_pub); -+ -+ /* save session id */ -+ if (ssh->kex->session_id == NULL) { -+ ssh->kex->session_id_len = hashlen; -+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); -+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); -+ } -+ -+ if (ssh->kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ return kex_send_newkeys(ssh); -+} -+ -+#endif /* GSSAPI */ -Index: openssh-7.9p1/kexgsss.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ openssh-7.9p1/kexgsss.c 2019-02-27 15:43:51.432516148 +0100 -@@ -0,0 +1,302 @@ -+/* -+ * 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" -+ -+#ifdef GSSAPI -+ -+#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 "digest.h" -+ -+#include "fips.h" -+ -+extern ServerOptions options; -+ -+int -+kexgss_server(struct ssh *ssh) -+{ -+ 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; -+ u_int slen, klen, kout; -+ u_char *kbuf; -+ DH *dh; -+ int min = -1, max = -1, nbits = -1; -+ int cmin = -1, cmax = -1; /* client proposal */ -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *dh_client_pub = NULL; -+ int type = 0; -+ gss_OID oid; -+ char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ const BIGNUM *p, *g, *pub_key; -+ -+ /* 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__, ssh->kex->name); -+ oid = ssh_gssapi_id_kex(NULL, ssh->kex->name, ssh->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"); -+ -+ switch (ssh->kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ dh = dh_new_group1(); -+ break; -+ case KEX_GSS_GRP14_SHA1: -+ dh = dh_new_group14(); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ debug("Doing group exchange"); -+ packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ); -+ /* store client proposal to provide valid signature */ -+ cmin = packet_get_int(); -+ nbits = packet_get_int(); -+ cmax = packet_get_int(); -+ min = MAX(DH_GRP_MIN, cmin); -+ max = MIN(DH_GRP_MAX, cmax); -+ packet_check_eom(); -+ if (max < min || nbits < min || max < nbits) { -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ } -+ dh = PRIVSEP(choose_dh(min, nbits, max)); -+ if (dh == NULL) -+ packet_disconnect("Protocol error: no matching group found"); -+ -+ DH_get0_pqg(dh, &p, NULL, &g); -+ packet_start(SSH2_MSG_KEXGSS_GROUP); -+ packet_put_bignum2((BIGNUM *)p); -+ packet_put_bignum2((BIGNUM *)g); -+ packet_send(); -+ -+ packet_write_wait(); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); -+ } -+ -+ dh_gen_key(dh, ssh->kex->we_need * 8); -+ -+ do { -+ debug("Wait SSH2_MSG_GSSAPI_INIT"); -+ type = packet_read(); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (dh_client_pub != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ recv_tok.value = packet_get_string(&slen); -+ recv_tok.length = slen; -+ -+ if ((dh_client_pub = BN_new()) == NULL) -+ fatal("dh_client_pub == NULL"); -+ -+ packet_get_bignum2(dh_client_pub); -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ recv_tok.value = packet_get_string(&slen); -+ recv_tok.length = slen; -+ break; -+ default: -+ packet_disconnect( -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ free(recv_tok.value); -+ -+ 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"); -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string(send_tok.value, send_tok.length); -+ packet_send(); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ packet_start(SSH2_MSG_KEXGSS_CONTINUE); -+ packet_put_string((char *)send_tok.value, send_tok.length); -+ packet_send(); -+ } -+ 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"); -+ -+ if (!dh_pub_is_valid(dh, dh_client_pub)) -+ packet_disconnect("bad client public DH value"); -+ -+ klen = DH_size(dh); -+ kbuf = xmalloc(klen); -+ kout = DH_compute_key(kbuf, dh_client_pub, dh); -+ if ((int)kout < 0) -+ fatal("DH_compute_key: failed"); -+ -+ shared_secret = BN_new(); -+ if (shared_secret == NULL) -+ fatal("kexgss_server: BN_new failed"); -+ -+ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) -+ fatal("kexgss_server: BN_bin2bn failed"); -+ -+ memset(kbuf, 0, klen); -+ free(kbuf); -+ -+ DH_get0_key(dh, &pub_key, NULL); -+ hashlen = sizeof(hash); -+ switch (ssh->kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash(ssh->kex->hash_alg, -+ ssh->kex->client_version_string, ssh->kex->server_version_string, -+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), -+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), -+ NULL, 0, /* Change this if we start sending host keys */ -+ dh_client_pub, pub_key, shared_secret, -+ hash, &hashlen -+ ); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ kexgex_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, ssh->kex->server_version_string, -+ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), -+ sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), -+ NULL, 0, -+ cmin, nbits, cmax, -+ p, g, -+ dh_client_pub, -+ pub_key, -+ shared_secret, -+ hash, &hashlen -+ ); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); -+ } -+ -+ BN_clear_free(dh_client_pub); -+ -+ if (ssh->kex->session_id == NULL) { -+ ssh->kex->session_id_len = hashlen; -+ ssh->kex->session_id = xmalloc(ssh->kex->session_id_len); -+ memcpy(ssh->kex->session_id, hash, ssh->kex->session_id_len); -+ } -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ packet_start(SSH2_MSG_KEXGSS_COMPLETE); -+ packet_put_bignum2(pub_key); -+ packet_put_string(msg_tok.value,msg_tok.length); -+ -+ if (send_tok.length != 0) { -+ packet_put_char(1); /* true */ -+ packet_put_string((char *)send_tok.value, send_tok.length); -+ } else { -+ packet_put_char(0); /* false */ -+ } -+ packet_send(); -+ -+ 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); -+ -+ DH_free(dh); -+ -+ kex_derive_keys_bn(ssh, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ 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(); -+ return 0; -+} -+#endif /* GSSAPI */ -Index: openssh-7.9p1/monitor.c -=================================================================== ---- openssh-7.9p1.orig/monitor.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/monitor.c 2019-02-27 15:43:55.360539487 +0100 -@@ -145,6 +145,8 @@ int mm_answer_gss_setup_ctx(int, struct - int mm_answer_gss_accept_ctx(int, struct sshbuf *); - int mm_answer_gss_userok(int, struct sshbuf *); - int mm_answer_gss_checkmic(int, struct sshbuf *); -+int mm_answer_gss_sign(int, struct sshbuf *); -+int mm_answer_gss_updatecreds(int, struct sshbuf *); - #endif - - #ifdef SSH_AUDIT_EVENTS -@@ -215,6 +217,7 @@ 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} - }; -@@ -231,6 +234,12 @@ struct mon_table mon_dispatch_postauth20 - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, - #endif -+#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 - {0, 0, NULL} - }; - -@@ -289,7 +298,10 @@ monitor_child_preauth(Authctxt *_authctx - /* 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) { - partial = 0; -@@ -401,6 +413,10 @@ monitor_child_postauth(struct monitor *p - 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); -@@ -609,7 +625,7 @@ mm_answer_moduli(int sock, struct sshbuf - int - mm_answer_sign(int sock, struct sshbuf *m) - { -- struct ssh *ssh = active_state; /* XXX */ -+ struct ssh *ssh = active_state; /* XXX */ - extern int auth_sock; /* XXX move to state struct? */ - struct sshkey *key; - struct sshbuf *sigbuf = NULL; -@@ -1647,7 +1663,7 @@ monitor_apply_keystate(struct monitor *p - - debug3("%s: packet_set_state", __func__); - if ((r = ssh_packet_set_state(ssh, child_state)) != 0) -- fatal("%s: packet_set_state: %s", __func__, ssh_err(r)); -+ fatal("%s: packet_set_state: %s", __func__, ssh_err(r)); - sshbuf_free(child_state); - child_state = NULL; - -@@ -1666,6 +1682,13 @@ monitor_apply_keystate(struct monitor *p - # endif - #endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kexc25519_server; -+#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_GEX_SHA1] = kexgss_server; -+ } -+#endif - kex->load_host_public_key=&get_hostkey_public_by_type; - kex->load_host_private_key=&get_hostkey_private_by_type; - kex->host_key_index=&get_hostkey_index; -@@ -1756,8 +1779,8 @@ mm_answer_gss_setup_ctx(int sock, struct - 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 authentication not enabled", __func__); - - if ((r = sshbuf_get_string(m, &p, &len)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -@@ -1789,7 +1812,7 @@ mm_answer_gss_accept_ctx(int sock, struc - OM_uint32 flags = 0; /* GSI needs this */ - int r; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - - if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) -@@ -1810,6 +1833,7 @@ mm_answer_gss_accept_ctx(int sock, struc - 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); - } -@@ -1821,7 +1845,7 @@ mm_answer_gss_checkmic(int sock, struct - OM_uint32 ret; - int r; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - - if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || -@@ -1851,10 +1875,11 @@ mm_answer_gss_userok(int sock, struct ss - int r, authenticated; - const char *displayname; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - -- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); -+ authenticated = authctxt->valid && -+ ssh_gssapi_userok(authctxt->user, authctxt->pw); - - sshbuf_reset(m); - if ((r = sshbuf_put_u32(m, authenticated)) != 0) -@@ -1871,5 +1896,73 @@ mm_answer_gss_userok(int sock, struct ss - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } --#endif /* GSSAPI */ - -+int -+mm_answer_gss_sign(int socket, struct sshbuf *m) -+{ -+ gss_buffer_desc data; -+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; -+ OM_uint32 major, minor; -+ int r; -+ -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ -+ if ((r = sshbuf_get_string(m, (u_char **)&data.value, &data.length)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ if (data.length != 20) -+ 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(int socket, struct sshbuf *m) { -+ ssh_gssapi_ccache store; -+ int ok, r; -+ -+ if ((r = sshbuf_get_cstring(m, &store.envvar, NULL)) != 0 || -+ (r = sshbuf_get_cstring(m, &store.envval, NULL)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ -+ ok = ssh_gssapi_update_creds(&store); -+ -+ 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 */ -Index: openssh-7.9p1/monitor.h -=================================================================== ---- openssh-7.9p1.orig/monitor.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/monitor.h 2019-02-27 15:43:55.360539487 +0100 -@@ -63,6 +63,9 @@ 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 = 201, MONITOR_ANS_GSSSIGN = 202, -+ MONITOR_REQ_GSSUPCREDS = 203, MONITOR_ANS_GSSUPCREDS = 204, -+ - }; - - struct monitor { -Index: openssh-7.9p1/monitor_wrap.c -=================================================================== ---- openssh-7.9p1.orig/monitor_wrap.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/monitor_wrap.c 2019-02-27 15:43:55.360539487 +0100 -@@ -984,7 +984,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss - } - - int --mm_ssh_gssapi_userok(char *user) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw) - { - struct sshbuf *m; - int r, authenticated = 0; -@@ -1003,4 +1003,52 @@ 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 = sshbuf_get_string(m, (u_char **)&hash->value, &hash->length)) != 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 ok, r; -+ -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ -+ if ((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 */ -Index: openssh-7.9p1/monitor_wrap.h -=================================================================== ---- openssh-7.9p1.orig/monitor_wrap.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/monitor_wrap.h 2019-02-27 15:43:55.360539487 +0100 -@@ -60,8 +60,10 @@ int mm_sshkey_verify(const struct sshkey - 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 *); - 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 -Index: openssh-7.9p1/readconf.c -=================================================================== ---- openssh-7.9p1.orig/readconf.c 2019-02-27 15:43:51.296515340 +0100 -+++ openssh-7.9p1/readconf.c 2019-02-27 15:43:51.432516148 +0100 -@@ -163,6 +163,8 @@ typedef enum { - oClearAllForwardings, oNoHostAuthenticationForLocalhost, - oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, - oAddressFamily, oGssAuthentication, oGssDelegateCreds, -+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, -+ oGssServerIdentity, - oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, - oHashKnownHosts, -@@ -203,10 +205,20 @@ static struct { - /* Sometimes-unsupported options */ - #if defined(GSSAPI) - { "gssapiauthentication", oGssAuthentication }, -+ { "gssapikeyexchange", oGssKeyEx }, - { "gssapidelegatecredentials", oGssDelegateCreds }, -+ { "gssapitrustdns", oGssTrustDns }, -+ { "gssapiclientidentity", oGssClientIdentity }, -+ { "gssapiserveridentity", oGssServerIdentity }, -+ { "gssapirenewalforcesrekey", oGssRenewalRekey }, - # else - { "gssapiauthentication", oUnsupported }, -+ { "gssapikeyexchange", oUnsupported }, - { "gssapidelegatecredentials", oUnsupported }, -+ { "gssapitrustdns", oUnsupported }, -+ { "gssapiclientidentity", oUnsupported }, -+ { "gssapiserveridentity", oUnsupported }, -+ { "gssapirenewalforcesrekey", oUnsupported }, - #endif - #ifdef ENABLE_PKCS11 - { "smartcarddevice", oPKCS11Provider }, -@@ -976,10 +988,30 @@ 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 oBatchMode: - intptr = &options->batch_mode; - goto parse_flag; -@@ -1861,7 +1893,12 @@ 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->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->kbd_interactive_devices = NULL; -@@ -2007,8 +2044,14 @@ 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; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -Index: openssh-7.9p1/readconf.h -=================================================================== ---- openssh-7.9p1.orig/readconf.h 2019-02-27 15:43:51.296515340 +0100 -+++ openssh-7.9p1/readconf.h 2019-02-27 15:43:51.432516148 +0100 -@@ -40,7 +40,12 @@ 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 */ - int password_authentication; /* Try password - * authentication. */ - int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -Index: openssh-7.9p1/regress/cert-hostkey.sh -=================================================================== ---- openssh-7.9p1.orig/regress/cert-hostkey.sh 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/regress/cert-hostkey.sh 2019-02-27 15:43:51.432516148 +0100 -@@ -66,7 +66,7 @@ touch $OBJ/host_revoked_plain - touch $OBJ/host_revoked_cert - cat $OBJ/host_ca_key.pub $OBJ/host_ca_key2.pub > $OBJ/host_revoked_ca - --PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'` -+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/g;s/^ssh-//'` - - if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then - PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512" -Index: openssh-7.9p1/regress/cert-userkey.sh -=================================================================== ---- openssh-7.9p1.orig/regress/cert-userkey.sh 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/regress/cert-userkey.sh 2019-02-27 15:43:51.432516148 +0100 -@@ -7,7 +7,7 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us - cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak - cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak - --PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` -+PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` - EXTRA_TYPES="" - - if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then -Index: openssh-7.9p1/regress/kextype.sh -=================================================================== ---- openssh-7.9p1.orig/regress/kextype.sh 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/regress/kextype.sh 2019-02-27 15:43:51.432516148 +0100 -@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/ssh - - tries="1 2 3 4" - for k in `${SSH} -Q kex`; do -+ if [ $k = "gss-gex-sha1-" -o $k = "gss-group1-sha1-" -o $k = "gss-group14-sha1-" ]; then -+ continue -+ fi - verbose "kex $k" - for i in $tries; do - ${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true -Index: openssh-7.9p1/regress/rekey.sh -=================================================================== ---- openssh-7.9p1.orig/regress/rekey.sh 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/regress/rekey.sh 2019-02-27 15:43:51.436516173 +0100 -@@ -38,6 +38,9 @@ increase_datafile_size 300 - - opts="" - for i in `${SSH} -Q kex`; do -+ if [ $i = "gss-gex-sha1-" -o $i = "gss-group1-sha1-" -o $i = "gss-group14-sha1-" ]; then -+ continue -+ fi - opts="$opts KexAlgorithms=$i" - done - for i in `${SSH} -Q cipher`; do -@@ -56,6 +59,9 @@ done - if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then - for c in `${SSH} -Q cipher-auth`; do - for kex in `${SSH} -Q kex`; do -+ if [ $kex = "gss-gex-sha1-" -o $kex = "gss-group1-sha1-" -o $kex = "gss-group14-sha1-" ]; then -+ continue -+ fi - verbose "client rekey $c $kex" - ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c - done -Index: openssh-7.9p1/servconf.c -=================================================================== ---- openssh-7.9p1.orig/servconf.c 2019-02-27 15:43:51.296515340 +0100 -+++ openssh-7.9p1/servconf.c 2019-02-27 15:43:51.436516173 +0100 -@@ -126,8 +126,10 @@ initialize_server_options(ServerOptions - 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->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; -@@ -360,10 +362,14 @@ fill_default_server_options(ServerOption - 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; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -@@ -510,6 +516,7 @@ typedef enum { - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -+ sGssKeyEx, sGssStoreRekey, - sAcceptEnv, sSetEnv, sPermitTunnel, - sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -587,11 +594,17 @@ static struct { - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, - #endif -+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, - { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, - { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, - { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, -@@ -1498,6 +1511,10 @@ process_server_config_line(ServerOptions - 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; -@@ -1506,6 +1523,10 @@ process_server_config_line(ServerOptions - intptr = &options->gss_strict_acceptor; - goto parse_flag; - -+ case sGssStoreRekey: -+ intptr = &options->gss_store_rekey; -+ goto parse_flag; -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -@@ -2295,6 +2316,10 @@ copy_set_server_options(ServerOptions *d - - M_CP_INTOPT(password_authentication); - M_CP_INTOPT(gss_authentication); -+ M_CP_INTOPT(gss_keyex); -+ M_CP_INTOPT(gss_cleanup_creds); -+ M_CP_INTOPT(gss_strict_acceptor); -+ M_CP_INTOPT(gss_store_rekey); - M_CP_INTOPT(pubkey_authentication); - M_CP_INTOPT(kerberos_authentication); - M_CP_INTOPT(hostbased_authentication); -@@ -2590,7 +2615,10 @@ dump_config(ServerOptions *o) - #endif - #ifdef GSSAPI - dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -+ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); - dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); -+ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); -+ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); - #endif - dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); - dump_cfg_fmtint(sKbdInteractiveAuthentication, -Index: openssh-7.9p1/servconf.h -=================================================================== ---- openssh-7.9p1.orig/servconf.h 2019-02-27 15:43:51.232514961 +0100 -+++ openssh-7.9p1/servconf.h 2019-02-27 15:43:51.436516173 +0100 -@@ -16,6 +16,8 @@ - #ifndef SERVCONF_H - #define SERVCONF_H - -+#include "misc.h" -+ - #define MAX_PORTS 256 /* Max # ports. */ - - #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ -@@ -125,8 +127,10 @@ 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; - int password_authentication; /* If true, permit password - * authentication. */ - int kbd_interactive_authentication; /* If true, permit */ -Index: openssh-7.9p1/ssh-gss.h -=================================================================== ---- openssh-7.9p1.orig/ssh-gss.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/ssh-gss.h 2019-02-27 15:43:51.436516173 +0100 -@@ -61,10 +61,22 @@ - - #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_GEX_SHA1_ID "gss-gex-sha1-" -+ - typedef struct { - char *filename; - char *envvar; - char *envval; -+ struct passwd *owner; - void *data; - } ssh_gssapi_ccache; - -@@ -72,8 +84,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 +99,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 +110,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); -@@ -123,17 +140,31 @@ 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 *); -+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 *); - 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(); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); -+ -+void ssh_gssapi_rekey_creds(void); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -Index: openssh-7.9p1/ssh_config -=================================================================== ---- openssh-7.9p1.orig/ssh_config 2019-02-27 15:43:51.172514604 +0100 -+++ openssh-7.9p1/ssh_config 2019-02-27 15:43:51.436516173 +0100 -@@ -40,6 +40,8 @@ Host * - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -Index: openssh-7.9p1/ssh_config.0 -=================================================================== ---- openssh-7.9p1.orig/ssh_config.0 2019-02-27 15:43:51.300515365 +0100 -+++ openssh-7.9p1/ssh_config.0 2019-02-27 15:43:51.436516173 +0100 -@@ -422,9 +422,40 @@ DESCRIPTION - Specifies whether user authentication based on GSSAPI is allowed. - The default is no. - -+ 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 no. -+ Note that this option applies to protocol version 2 only. -+ -+ 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. -+ -+ 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. -+ - GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. The default is no. - -+ GSSAPIRenewalForcesRekey -+ If set to yes then renewal of the client's GSSAPI credentials will -+ force the rekeying of the ssh connection. With a compatible server, -+ this can delegate the renewed credentials to a session on the -+ server. The default is no. -+ -+ GSSAPITrustDns -+ Set to yes to indicate that the DNS is trusted to securely -+ canonicalize the name of the host being connected to. If no, the -+ hostname entered on the command line will be passed untouched to -+ the GSSAPI library. The default is no. -+ This option only applies to protocol version 2 connections using -+ GSSAPI. -+ - HashKnownHosts - Indicates that ssh(1) should hash host names and addresses when - they are added to ~/.ssh/known_hosts. These hashed names may be -Index: openssh-7.9p1/ssh_config.5 -=================================================================== ---- openssh-7.9p1.orig/ssh_config.5 2019-02-27 15:43:51.300515365 +0100 -+++ openssh-7.9p1/ssh_config.5 2019-02-27 15:43:51.436516173 +0100 -@@ -738,10 +738,40 @@ 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 can delegate the renewed -+credentials to a session on the server. -+The default is -+.Dq no . -+.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 HashKnownHosts - Indicates that - .Xr ssh 1 -Index: openssh-7.9p1/sshconnect2.c -=================================================================== ---- openssh-7.9p1.orig/sshconnect2.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/sshconnect2.c 2019-02-27 15:43:51.436516173 +0100 -@@ -82,6 +82,124 @@ extern char *client_version_string; - extern char *server_version_string; - extern Options options; - -+/* XXX from auth.h -- refactoring move these useful functions away of client context*/ -+ -+/* -+ * 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) < 0) { -+ debug("getpeername failed: %.100s", strerror(errno)); -+ return strdup(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 strdup(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 strdup(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 strdup(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 strdup(ntop); -+ } -+ return strdup(name); -+} -+ -+/* -+ * Return the canonical name of the host in the other side of the current -+ * connection. The host name is cached, so it is efficient to call this -+ * several times. -+ */ -+ -+const char * -+get_canonical_hostname(struct ssh *ssh, int use_dns) -+{ -+ static char *dnsname; -+ -+ if (!use_dns) -+ return ssh_remote_ipaddr(ssh); -+ else if (dnsname != NULL) -+ return dnsname; -+ else { -+ dnsname = remote_hostname(ssh); -+ return dnsname; -+ } -+} -+ -+ -+ - /* - * SSH2 key exchange - */ -@@ -162,9 +280,37 @@ ssh_kex2(char *host, struct sockaddr *ho - struct kex *kex; - int r; - -+#ifdef GSSAPI -+ char *orig = NULL, *gss = NULL; -+ char *gss_host = NULL; -+#endif -+ - xxx_host = host; - xxx_hostaddr = hostaddr; - -+#ifdef GSSAPI -+ /* TODO: should we use myproposal[PROPOSAL_KEX_ALGS] -+ * instead of options.kex_algorithms? */ -+ if (options.gss_keyex) { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = options.kex_algorithms; -+ -+ if (options.gss_trust_dns) -+ gss_host = (char *)get_canonical_hostname(active_state, 1); -+ else -+ gss_host = host; -+ -+ gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity, -+ options.kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&options.kex_algorithms, -+ "%s,%s", gss, orig); -+ } -+ } -+#endif -+ - if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) - fatal("%s: kex_names_cat", __func__); - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); -@@ -194,6 +340,17 @@ ssh_kex2(char *host, struct sockaddr *ho - order_hostkeyalgs(host, hostaddr, port)); - } - -+#ifdef GSSAPI -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ if (options.gss_keyex && gss) { -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ free(gss); -+ } -+#endif -+ - if (options.rekey_limit || options.rekey_interval) - packet_set_rekey_limits(options.rekey_limit, - options.rekey_interval); -@@ -215,10 +372,30 @@ ssh_kex2(char *host, struct sockaddr *ho - # endif - #endif - kex->kex[KEX_C25519_SHA256] = kexc25519_client; -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; -+ } -+#endif - kex->client_version_string=client_version_string; - kex->server_version_string=server_version_string; - kex->verify_host_key=&verify_host_key_callback; - -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->gss_deleg_creds = options.gss_deleg_creds; -+ kex->gss_trust_dns = options.gss_trust_dns; -+ kex->gss_client = options.gss_client_identity; -+ if (options.gss_server_identity) { -+ kex->gss_host = options.gss_server_identity; -+ } else { -+ kex->gss_host = gss_host; -+ } -+ } -+#endif -+ - ssh_dispatch_run_fatal(active_state, DISPATCH_BLOCK, &kex->done); - - /* remove ext-info from the KEX proposals for rekeying */ -@@ -314,6 +491,7 @@ int input_gssapi_token(int type, u_int32 - int input_gssapi_hash(int type, u_int32_t, struct ssh *); - int input_gssapi_error(int, u_int32_t, struct ssh *); - int input_gssapi_errtok(int, u_int32_t, struct ssh *); -+int userauth_gsskeyex(Authctxt *authctxt); - #endif - - void userauth(Authctxt *, char *); -@@ -330,6 +508,11 @@ static char *authmethods_get(void); - - Authmethod authmethods[] = { - #ifdef GSSAPI -+ {"gssapi-keyex", -+ userauth_gsskeyex, -+ NULL, -+ &options.gss_authentication, -+ NULL}, - {"gssapi-with-mic", - userauth_gssapi, - NULL, -@@ -686,19 +869,31 @@ userauth_gssapi(Authctxt *authctxt) - static u_int mech = 0; - OM_uint32 min; - int r, ok = 0; -+ const char *gss_host; -+ -+if (options.gss_server_identity) -+ gss_host = options.gss_server_identity; -+ else if (options.gss_trust_dns) -+ gss_host = get_canonical_hostname(active_state, 1); -+ else -+ gss_host = authctxt->host; - - /* Try one GSSAPI method at a time, rather than sending them all at - * once. */ - - if (gss_supported == NULL) -- gss_indicate_mechs(&min, &gss_supported); -+ if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) { -+ gss_supported = NULL; -+ return 0; -+ } - - /* Check to see if the mechanism is usable before we offer it */ - while (mech < gss_supported->count && !ok) { - /* My DER encoding requires length<128 */ - if (gss_supported->elements[mech].length < 128 && - ssh_gssapi_check_mechanism(&gssctxt, -- &gss_supported->elements[mech], authctxt->host)) { -+ &gss_supported->elements[mech], gss_host, -+ options.gss_client_identity)) { - ok = 1; /* Mechanism works */ - } else { - mech++; -@@ -935,6 +1130,51 @@ input_gssapi_error(int type, u_int32_t p - free(lang); - return r; - } -+ -+int -+userauth_gsskeyex(Authctxt *authctxt) -+{ -+ struct sshbuf *b = NULL; -+ gss_buffer_desc gssbuf; -+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; -+ OM_uint32 ms; -+ -+ 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"); -+ -+ gssbuf.value = sshbuf_mutable_ptr(b); -+ gssbuf.length = sshbuf_len(b); -+ -+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { -+ sshbuf_free(b); -+ return (0); -+ } -+ -+ packet_start(SSH2_MSG_USERAUTH_REQUEST); -+ packet_put_cstring(authctxt->server_user); -+ packet_put_cstring(authctxt->service); -+ packet_put_cstring(authctxt->method->name); -+ packet_put_string(mic.value, mic.length); -+ packet_send(); -+ -+ sshbuf_free(b); -+ gss_release_buffer(&ms, &mic); -+ -+ return (1); -+} -+ - #endif /* GSSAPI */ - - int -@@ -1473,8 +1713,8 @@ key_type_allowed_by_config(struct sshkey - - /* - * try keys in the following order: -- * 1. certificates listed in the config file -- * 2. other input certificates -+ * 1. certificates listed in the config file -+ * 2. other input certificates - * 3. agent keys that are found in the config file - * 4. other agent keys - * 5. keys that are only listed in the config file -Index: openssh-7.9p1/sshd.c -=================================================================== ---- openssh-7.9p1.orig/sshd.c 2019-02-27 15:43:51.412516029 +0100 -+++ openssh-7.9p1/sshd.c 2019-02-27 15:43:55.360539487 +0100 -@@ -131,6 +131,10 @@ - - #include "fips.h" - -+#ifdef USE_SECURITY_SESSION_API -+#include -+#endif -+ - /* Re-exec fds */ - #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) - #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) -@@ -555,7 +559,8 @@ privsep_preauth_child(void) - - #ifdef GSSAPI - /* Cache supported mechanism OIDs for later use */ -- ssh_gssapi_prepare_supported_oids(); -+ if (options.gss_authentication || options.gss_keyex) -+ ssh_gssapi_prepare_supported_oids(); - #endif - - reseed_prngs(); -@@ -897,8 +902,9 @@ notify_hostkeys(struct ssh *ssh) - } - debug3("%s: sent %u hostkeys", __func__, nkeys); - if (nkeys == 0) -- fatal("%s: no hostkeys", __func__); -- packet_send(); -+ debug3("%s: no hostkeys", __func__); -+ else -+ packet_send(); - sshbuf_free(buf); - } - -@@ -1837,7 +1843,12 @@ main(int ac, char **av) - free(fp); - } - accumulate_host_timing_secret(cfg, NULL); -+#ifndef GSSAPI - if (!sensitive_data.have_ssh2_key) { -+#else -+ /* The GSSAPI key exchange can run without a host key */ -+ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { -+#endif - logit("sshd: no hostkeys available -- exiting."); - exit(1); - } -@@ -2015,6 +2026,60 @@ main(int ac, char **av) - /* This is the child processing a new connection. */ - setproctitle("%s", "[accepted]"); - -+#ifdef USE_SECURITY_SESSION_API -+ /* -+ * Create a new security session for use by the new user login if -+ * the current session is the root session or we are not launched -+ * by inetd (eg: debugging mode or server mode). We do not -+ * necessarily need to create a session if we are launched from -+ * inetd because Panther xinetd will create a session for us. -+ * -+ * The only case where this logic will fail is if there is an -+ * inetd running in a non-root session which is not creating -+ * new sessions for us. Then all the users will end up in the -+ * same session (bad). -+ * -+ * When the client exits, the session will be destroyed for us -+ * automatically. -+ * -+ * We must create the session before any credentials are stored -+ * (including AFS pags, which happens a few lines below). -+ */ -+ { -+ OSStatus err = 0; -+ SecuritySessionId sid = 0; -+ SessionAttributeBits sattrs = 0; -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("Current Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ -+ if (inetd_flag && !(sattrs & sessionIsRoot)) -+ debug("Running in inetd mode in a non-root session... " -+ "assuming inetd created the session for us."); -+ else { -+ debug("Creating new security session..."); -+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); -+ if (err) -+ error("SessionCreate() failed with error %.8X", -+ (unsigned) err); -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, -+ &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("New Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ } -+ } -+#endif -+ - /* - * Create a new session and process group since the 4.4BSD - * setlogin() affects the entire process group. We don't -@@ -2136,6 +2201,60 @@ main(int ac, char **av) - rdomain == NULL ? "" : "\""); - free(laddr); - -+#ifdef USE_SECURITY_SESSION_API -+ /* -+ * Create a new security session for use by the new user login if -+ * the current session is the root session or we are not launched -+ * by inetd (eg: debugging mode or server mode). We do not -+ * necessarily need to create a session if we are launched from -+ * inetd because Panther xinetd will create a session for us. -+ * -+ * The only case where this logic will fail is if there is an -+ * inetd running in a non-root session which is not creating -+ * new sessions for us. Then all the users will end up in the -+ * same session (bad). -+ * -+ * When the client exits, the session will be destroyed for us -+ * automatically. -+ * -+ * We must create the session before any credentials are stored -+ * (including AFS pags, which happens a few lines below). -+ */ -+ { -+ OSStatus err = 0; -+ SecuritySessionId sid = 0; -+ SessionAttributeBits sattrs = 0; -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("Current Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ -+ if (inetd_flag && !(sattrs & sessionIsRoot)) -+ debug("Running in inetd mode in a non-root session... " -+ "assuming inetd created the session for us."); -+ else { -+ debug("Creating new security session..."); -+ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); -+ if (err) -+ error("SessionCreate() failed with error %.8X", -+ (unsigned) err); -+ -+ err = SessionGetInfo(callerSecuritySession, &sid, -+ &sattrs); -+ if (err) -+ error("SessionGetInfo() failed with error %.8X", -+ (unsigned) err); -+ else -+ debug("New Session ID is %.8X / Session Attributes are %.8X", -+ (unsigned) sid, (unsigned) sattrs); -+ } -+ } -+#endif -+ - /* - * We don't want to listen forever unless the other side - * successfully authenticates itself. So we set up an alarm which is -@@ -2319,6 +2438,48 @@ do_ssh2_kex(void) - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( - list_hostkey_types()); - -+#ifdef GSSAPI -+ { -+ 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(active_state, myproposal)) != 0) - fatal("kex_setup: %s", ssh_err(r)); -@@ -2336,6 +2497,13 @@ do_ssh2_kex(void) - # endif - #endif - kex->kex[KEX_C25519_SHA256] = kexc25519_server; -+#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_GEX_SHA1] = kexgss_server; -+ } -+#endif - kex->server = 1; - kex->client_version_string=client_version_string; - kex->server_version_string=server_version_string; -Index: openssh-7.9p1/sshd_config -=================================================================== ---- openssh-7.9p1.orig/sshd_config 2019-02-27 15:43:51.172514604 +0100 -+++ openssh-7.9p1/sshd_config 2019-02-27 15:43:51.436516173 +0100 -@@ -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 -Index: openssh-7.9p1/sshd_config.5 -=================================================================== ---- openssh-7.9p1.orig/sshd_config.5 2019-02-27 15:43:51.300515365 +0100 -+++ openssh-7.9p1/sshd_config.5 2019-02-27 15:43:51.436516173 +0100 -@@ -655,6 +655,11 @@ Specifies whether to automatically destr - 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 -+.Dq no . - .It Cm GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI acceptor - a client authenticates against. -@@ -669,6 +674,11 @@ 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 . - .It Cm HostbasedAcceptedKeyTypes - Specifies the key types that will be accepted for hostbased authentication - as a list of comma-separated patterns. -@@ -1627,16 +1637,16 @@ as a non-root user. - The default is - .Cm no . - .It Cm UsePAMCheckLocks --When set to -+When set to - .Dq yes - , the checks whether the account has been locked with - .Pa passwd -l --are performed even when PAM authentication is enabled via -+are performed even when PAM authentication is enabled via - .Cm UsePAM . - This is to ensure that it is not possible to log in with e.g. a - public key (in such a case PAM is used only to set up the session and some PAM - modules will not check whether the account is locked in this scenario). The --default is -+default is - .Dq no . - .It Cm VersionAddendum - Optionally specifies additional text to append to the SSH protocol banner -Index: openssh-7.9p1/sshkey.c -=================================================================== ---- openssh-7.9p1.orig/sshkey.c 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/sshkey.c 2019-02-27 15:43:55.360539487 +0100 -@@ -135,6 +135,7 @@ static const struct keytype keytypes[] = - # endif /* OPENSSL_HAS_NISTP521 */ - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+ { "null", "null", NULL, KEY_NULL, 0, 0, 1 }, - { NULL, NULL, NULL, -1, -1, 0, 0 } - }; - -Index: openssh-7.9p1/sshkey.h -=================================================================== ---- openssh-7.9p1.orig/sshkey.h 2018-10-17 02:01:20.000000000 +0200 -+++ openssh-7.9p1/sshkey.h 2019-02-27 15:43:55.360539487 +0100 -@@ -64,6 +64,7 @@ enum sshkey_types { - KEY_ED25519_CERT, - KEY_XMSS, - KEY_XMSS_CERT, -+ KEY_NULL, - KEY_UNSPEC - }; - -Index: openssh-7.9p1/sshd_config.0 -=================================================================== ---- openssh-7.9p1.orig/sshd_config.0 2019-02-27 15:43:51.300515365 +0100 -+++ openssh-7.9p1/sshd_config.0 2019-02-27 15:43:51.436516173 +0100 -@@ -380,6 +380,12 @@ DESCRIPTION - Specifies whether user authentication based on GSSAPI is allowed. - The default is no. - -+ 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 no. -+ Note that this option applies to protocol version 2 only. -+ - GSSAPICleanupCredentials - Specifies whether to automatically destroy the user's credentials - cache on logout. The default is yes. -@@ -393,6 +399,12 @@ DESCRIPTION - facility is provided to assist with operation on multi homed - machines. The default is yes. - -+ 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 no. -+ - HostbasedAcceptedKeyTypes - Specifies the key types that will be accepted for hostbased - authentication as a list of comma-separated patterns. diff --git a/openssh-7.7p1-hostname_changes_when_forwarding_X.patch b/openssh-7.7p1-hostname_changes_when_forwarding_X.patch index c7daaf1..bb58140 100644 --- a/openssh-7.7p1-hostname_changes_when_forwarding_X.patch +++ b/openssh-7.7p1-hostname_changes_when_forwarding_X.patch @@ -5,11 +5,11 @@ handle hostname changes when forwarding X bnc#98627 -Index: openssh-7.8p1/session.c -=================================================================== ---- openssh-7.8p1.orig/session.c -+++ openssh-7.8p1/session.c -@@ -1009,7 +1009,7 @@ copy_environment(char **source, char *** +diff --git a/session.c b/session.c +index 94d7438..d81060c 100644 +--- a/session.c ++++ b/session.c +@@ -981,7 +981,7 @@ copy_environment(char **source, char ***env, u_int *envsize) } static char ** @@ -18,7 +18,7 @@ Index: openssh-7.8p1/session.c { char buf[256]; size_t n; -@@ -1213,6 +1213,8 @@ do_setup_env(struct ssh *ssh, Session *s +@@ -1191,6 +1191,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) for (i = 0; env[i]; i++) fprintf(stderr, " %.200s\n", env[i]); } @@ -27,7 +27,7 @@ Index: openssh-7.8p1/session.c return env; } -@@ -1221,7 +1223,7 @@ do_setup_env(struct ssh *ssh, Session *s +@@ -1199,7 +1201,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) * first in this order). */ static void @@ -36,7 +36,7 @@ Index: openssh-7.8p1/session.c { FILE *f = NULL; char cmd[1024]; -@@ -1276,12 +1278,20 @@ do_rc_files(struct ssh *ssh, Session *s, +@@ -1254,12 +1256,20 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell) options.xauth_location); f = popen(cmd, "w"); if (f) { @@ -57,15 +57,15 @@ Index: openssh-7.8p1/session.c } else { fprintf(stderr, "Could not run %s\n", cmd); -@@ -1534,6 +1544,7 @@ do_child(struct ssh *ssh, Session *s, co - { - extern char **environ; - char **env; -+ int env_size; - char *argv[ARGV_MAX]; +@@ -1515,6 +1525,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) + char **env, *argv[ARGV_MAX], remote_id[512]; const char *shell, *shell0; struct passwd *pw = s->pw; -@@ -1591,7 +1602,7 @@ do_child(struct ssh *ssh, Session *s, co ++ int env_size; + int r = 0; + + sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); +@@ -1571,7 +1582,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) * Make sure $SHELL points to the shell from the password file, * even if shell is overridden from login.conf */ @@ -74,7 +74,7 @@ Index: openssh-7.8p1/session.c #ifdef HAVE_LOGIN_CAP shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); -@@ -1655,7 +1666,7 @@ do_child(struct ssh *ssh, Session *s, co +@@ -1635,7 +1646,7 @@ do_child(struct ssh *ssh, Session *s, const char *command) closefrom(STDERR_FILENO + 1); diff --git a/openssh-7.7p1-ldap.patch b/openssh-7.7p1-ldap.patch index 7e8a79d..550bfc3 100644 --- a/openssh-7.7p1-ldap.patch +++ b/openssh-7.7p1-ldap.patch @@ -10,10 +10,11 @@ # internal versions. ssh-keyconverter consequently fails to link as it lacks # the proper flags, and libopenbsd-compat doesn't contain the b64_* functions) -Index: openssh-7.9p1/HOWTO.ldap-keys -=================================================================== +diff --git a/HOWTO.ldap-keys b/HOWTO.ldap-keys +new file mode 100644 +index 0000000..831d399 --- /dev/null -+++ openssh-7.9p1/HOWTO.ldap-keys ++++ b/HOWTO.ldap-keys @@ -0,0 +1,108 @@ + +HOW TO START @@ -123,11 +124,11 @@ Index: openssh-7.9p1/HOWTO.ldap-keys + - frederic peters. + - Finlay dobbie. + - Stefan Fisher. -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in -+++ openssh-7.9p1/Makefile.in -@@ -24,6 +24,8 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpas +diff --git a/Makefile.in b/Makefile.in +index 750aada..1baf5c6 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -24,6 +24,8 @@ ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper @@ -136,7 +137,7 @@ Index: openssh-7.9p1/Makefile.in CAVSTEST_CTR=$(libexecdir)/cavstest-ctr CAVSTEST_KDF=$(libexecdir)/cavstest-kdf PRIVSEP_PATH=@PRIVSEP_PATH@ -@@ -66,6 +68,9 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-a +@@ -66,6 +68,9 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keys TARGETS += cavstest-ctr$(EXEEXT) cavstest-kdf$(EXEEXT) @@ -146,7 +147,7 @@ Index: openssh-7.9p1/Makefile.in XMSS_OBJS=\ ssh-xmss.o \ sshkey-xmss.o \ -@@ -130,8 +135,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw +@@ -127,8 +132,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ sandbox-solaris.o uidswap.o @@ -157,17 +158,17 @@ Index: openssh-7.9p1/Makefile.in MANTYPE = @MANTYPE@ CONFIGFILES=sshd_config.out ssh_config.out moduli.out -@@ -206,6 +211,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) +@@ -208,6 +213,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11 ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) +ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o + $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + - sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o - $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-realpath.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-realpath.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) -@@ -361,6 +369,10 @@ install-files: +@@ -363,6 +371,10 @@ install-files: $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) @@ -178,7 +179,7 @@ Index: openssh-7.9p1/Makefile.in $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) -@@ -379,6 +391,10 @@ install-files: +@@ -381,6 +393,10 @@ install-files: $(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 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 @@ -189,7 +190,7 @@ Index: openssh-7.9p1/Makefile.in install-sysconf: $(MKDIR_P) $(DESTDIR)$(sysconfdir) -@@ -402,6 +418,13 @@ install-sysconf: +@@ -404,6 +420,13 @@ install-sysconf: else \ echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ fi @@ -203,7 +204,7 @@ Index: openssh-7.9p1/Makefile.in host-key: ssh-keygen$(EXEEXT) @if [ -z "$(DESTDIR)" ] ; then \ -@@ -439,6 +462,8 @@ uninstall: +@@ -441,6 +464,8 @@ uninstall: -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) @@ -212,7 +213,7 @@ Index: openssh-7.9p1/Makefile.in -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -@@ -450,6 +475,7 @@ uninstall: +@@ -452,6 +477,7 @@ uninstall: -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 @@ -220,11 +221,11 @@ Index: openssh-7.9p1/Makefile.in regress-prep: $(MKDIR_P) `pwd`/regress/unittests/test_helper -Index: openssh-7.9p1/configure.ac -=================================================================== ---- openssh-7.9p1.orig/configure.ac -+++ openssh-7.9p1/configure.ac -@@ -1671,6 +1671,106 @@ AC_ARG_WITH([audit], +diff --git a/configure.ac b/configure.ac +index 20a1884..ff9c11a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1651,6 +1651,106 @@ AC_ARG_WITH([audit], esac ] ) @@ -331,10 +332,11 @@ Index: openssh-7.9p1/configure.ac AC_ARG_WITH([pie], [ --with-pie Build Position Independent Executables if possible], [ if test "x$withval" = "xno"; then -Index: openssh-7.9p1/ldap-helper.c -=================================================================== +diff --git a/ldap-helper.c b/ldap-helper.c +new file mode 100644 +index 0000000..0efff1f --- /dev/null -+++ openssh-7.9p1/ldap-helper.c ++++ b/ldap-helper.c @@ -0,0 +1,155 @@ +/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -491,10 +493,11 @@ Index: openssh-7.9p1/ldap-helper.c +void *buffer_get_string(struct sshbuf *b, u_int *l) { return NULL; } +void buffer_put_string(struct sshbuf *b, const void *f, u_int l) {} + -Index: openssh-7.9p1/ldap-helper.h -=================================================================== +diff --git a/ldap-helper.h b/ldap-helper.h +new file mode 100644 +index 0000000..14cb29a --- /dev/null -+++ openssh-7.9p1/ldap-helper.h ++++ b/ldap-helper.h @@ -0,0 +1,32 @@ +/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -528,10 +531,11 @@ Index: openssh-7.9p1/ldap-helper.h +extern int config_warning_config_file; + +#endif /* LDAP_HELPER_H */ -Index: openssh-7.9p1/ldap.conf -=================================================================== +diff --git a/ldap.conf b/ldap.conf +new file mode 100644 +index 0000000..42e38d3 --- /dev/null -+++ openssh-7.9p1/ldap.conf ++++ b/ldap.conf @@ -0,0 +1,88 @@ +# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $ +# @@ -621,10 +625,11 @@ Index: openssh-7.9p1/ldap.conf +#tls_cert +#tls_key + -Index: openssh-7.9p1/ldapbody.c -=================================================================== +diff --git a/ldapbody.c b/ldapbody.c +new file mode 100644 +index 0000000..032cc89 --- /dev/null -+++ openssh-7.9p1/ldapbody.c ++++ b/ldapbody.c @@ -0,0 +1,494 @@ +/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1120,10 +1125,11 @@ Index: openssh-7.9p1/ldapbody.c + return; +} + -Index: openssh-7.9p1/ldapbody.h -=================================================================== +diff --git a/ldapbody.h b/ldapbody.h +new file mode 100644 +index 0000000..665dca2 --- /dev/null -+++ openssh-7.9p1/ldapbody.h ++++ b/ldapbody.h @@ -0,0 +1,37 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1162,10 +1168,11 @@ Index: openssh-7.9p1/ldapbody.h + +#endif /* LDAPBODY_H */ + -Index: openssh-7.9p1/ldapconf.c -=================================================================== +diff --git a/ldapconf.c b/ldapconf.c +new file mode 100644 +index 0000000..2e22438 --- /dev/null -+++ openssh-7.9p1/ldapconf.c ++++ b/ldapconf.c @@ -0,0 +1,711 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1878,10 +1885,11 @@ Index: openssh-7.9p1/ldapconf.c + dump_cfg_string(lSSH_Filter, options.ssh_filter); +} + -Index: openssh-7.9p1/ldapconf.h -=================================================================== +diff --git a/ldapconf.h b/ldapconf.h +new file mode 100644 +index 0000000..c2aa704 --- /dev/null -+++ openssh-7.9p1/ldapconf.h ++++ b/ldapconf.h @@ -0,0 +1,71 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1954,10 +1962,11 @@ Index: openssh-7.9p1/ldapconf.h +void dump_config(void); + +#endif /* LDAPCONF_H */ -Index: openssh-7.9p1/ldapincludes.h -=================================================================== +diff --git a/ldapincludes.h b/ldapincludes.h +new file mode 100644 +index 0000000..8539bdc --- /dev/null -+++ openssh-7.9p1/ldapincludes.h ++++ b/ldapincludes.h @@ -0,0 +1,41 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2000,10 +2009,11 @@ Index: openssh-7.9p1/ldapincludes.h +#endif + +#endif /* LDAPINCLUDES_H */ -Index: openssh-7.9p1/ldapmisc.c -=================================================================== +diff --git a/ldapmisc.c b/ldapmisc.c +new file mode 100644 +index 0000000..de23c0c --- /dev/null -+++ openssh-7.9p1/ldapmisc.c ++++ b/ldapmisc.c @@ -0,0 +1,79 @@ + +#include "ldapincludes.h" @@ -2084,10 +2094,11 @@ Index: openssh-7.9p1/ldapmisc.c +} +#endif + -Index: openssh-7.9p1/ldapmisc.h -=================================================================== +diff --git a/ldapmisc.h b/ldapmisc.h +new file mode 100644 +index 0000000..4c271df --- /dev/null -+++ openssh-7.9p1/ldapmisc.h ++++ b/ldapmisc.h @@ -0,0 +1,35 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2124,10 +2135,10 @@ Index: openssh-7.9p1/ldapmisc.h + +#endif /* LDAPMISC_H */ + -Index: openssh-7.9p1/openbsd-compat/base64.c -=================================================================== ---- openssh-7.9p1.orig/openbsd-compat/base64.c -+++ openssh-7.9p1/openbsd-compat/base64.c +diff --git a/openbsd-compat/base64.c b/openbsd-compat/base64.c +index 9e74667..14824be 100644 +--- a/openbsd-compat/base64.c ++++ b/openbsd-compat/base64.c @@ -46,7 +46,7 @@ #include "includes.h" @@ -2146,7 +2157,7 @@ Index: openssh-7.9p1/openbsd-compat/base64.c int b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) { -@@ -185,7 +185,7 @@ b64_ntop(u_char const *src, size_t srcle +@@ -185,7 +185,7 @@ b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) } #endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ @@ -2155,10 +2166,10 @@ Index: openssh-7.9p1/openbsd-compat/base64.c /* skips all whitespace anywhere. converts characters, four at a time, starting at (or after) -Index: openssh-7.9p1/openbsd-compat/base64.h -=================================================================== ---- openssh-7.9p1.orig/openbsd-compat/base64.h -+++ openssh-7.9p1/openbsd-compat/base64.h +diff --git a/openbsd-compat/base64.h b/openbsd-compat/base64.h +index bd77293..e27df9a 100644 +--- a/openbsd-compat/base64.h ++++ b/openbsd-compat/base64.h @@ -45,16 +45,16 @@ #include "includes.h" @@ -2180,10 +2191,11 @@ Index: openssh-7.9p1/openbsd-compat/base64.h int b64_pton(char const *src, u_char *target, size_t targsize); # endif /* !HAVE_B64_PTON */ # define __b64_pton(a,b,c) b64_pton(a,b,c) -Index: openssh-7.9p1/openssh-lpk-openldap.schema -=================================================================== +diff --git a/openssh-lpk-openldap.schema b/openssh-lpk-openldap.schema +new file mode 100644 +index 0000000..c84f90f --- /dev/null -+++ openssh-7.9p1/openssh-lpk-openldap.schema ++++ b/openssh-lpk-openldap.schema @@ -0,0 +1,21 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2206,10 +2218,11 @@ Index: openssh-7.9p1/openssh-lpk-openldap.schema + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -Index: openssh-7.9p1/openssh-lpk-sun.schema -=================================================================== +diff --git a/openssh-lpk-sun.schema b/openssh-lpk-sun.schema +new file mode 100644 +index 0000000..3136673 --- /dev/null -+++ openssh-7.9p1/openssh-lpk-sun.schema ++++ b/openssh-lpk-sun.schema @@ -0,0 +1,23 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2234,10 +2247,11 @@ Index: openssh-7.9p1/openssh-lpk-sun.schema + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -Index: openssh-7.9p1/ssh-ldap-helper.8 -=================================================================== +diff --git a/ssh-ldap-helper.8 b/ssh-ldap-helper.8 +new file mode 100644 +index 0000000..f8440e4 --- /dev/null -+++ openssh-7.9p1/ssh-ldap-helper.8 ++++ b/ssh-ldap-helper.8 @@ -0,0 +1,79 @@ +.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ +.\" @@ -2318,19 +2332,21 @@ Index: openssh-7.9p1/ssh-ldap-helper.8 +OpenSSH 5.5 + PKA-LDAP . +.Sh AUTHORS +.An Jan F. Chadima Aq jchadima@redhat.com -Index: openssh-7.9p1/ssh-ldap-wrapper -=================================================================== +diff --git a/ssh-ldap-wrapper b/ssh-ldap-wrapper +new file mode 100644 +index 0000000..9fdfc37 --- /dev/null -+++ openssh-7.9p1/ssh-ldap-wrapper ++++ b/ssh-ldap-wrapper @@ -0,0 +1,4 @@ +#!/bin/sh + +exec @LIBEXECDIR@/ssh-ldap-helper -s "$1" + -Index: openssh-7.9p1/ssh-ldap.conf.5 -=================================================================== +diff --git a/ssh-ldap.conf.5 b/ssh-ldap.conf.5 +new file mode 100644 +index 0000000..15eb03d --- /dev/null -+++ openssh-7.9p1/ssh-ldap.conf.5 ++++ b/ssh-ldap.conf.5 @@ -0,0 +1,376 @@ +.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $ +.\" diff --git a/openssh-7.7p1-seccomp_ioctl_s390_EP11.patch b/openssh-7.7p1-seccomp_ioctl_s390_EP11.patch deleted file mode 100644 index c6290a0..0000000 --- a/openssh-7.7p1-seccomp_ioctl_s390_EP11.patch +++ /dev/null @@ -1,36 +0,0 @@ -# HG changeset patch -# Parent a7b18fdd68dba10349e59a9085fd822343311f45 -Patch from IBM enabling use of EP11 hw crypto accelerator, submitted upstreams: - -From: Eduardo Barretto -To: openssh-unix-dev@mindrot.org -Subject: [PATCH 3/3] Enable specific ioctl call for EP11 crypto card (s390) -Date: Tue, 9 May 2017 14:27:15 -0300 - -The EP11 crypto card needs to make an ioctl call, which receives an -specific argument. This crypto card is for s390 only. - -Signed-off-by: Eduardo Barretto - -diff --git a/openssh-7.7p1/sandbox-seccomp-filter.c b/openssh-7.7p1/sandbox-seccomp-filter.c ---- openssh-7.7p1/sandbox-seccomp-filter.c -+++ openssh-7.7p1/sandbox-seccomp-filter.c -@@ -248,16 +248,18 @@ static const struct sock_filter preauth_ - SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN), - SC_DENY(__NR_socketcall, EACCES), - #endif - #if defined(__NR_ioctl) && defined(__s390__) - /* Allow ioctls for ICA crypto card on s390 */ - SC_ALLOW_ARG(__NR_ioctl, 1, Z90STAT_STATUS_MASK), - SC_ALLOW_ARG(__NR_ioctl, 1, ICARSAMODEXPO), - SC_ALLOW_ARG(__NR_ioctl, 1, ICARSACRT), -+ /* Allow ioctls for EP11 crypto card on s390 */ -+ SC_ALLOW_ARG(__NR_ioctl, 1, ZSENDEP11CPRB), - #endif - #if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT) - /* - * On Linux x32, the clock_gettime VDSO falls back to the - * x86-64 syscall under some circumstances, e.g. - * https://bugs.debian.org/849923 - */ - SC_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT), diff --git a/openssh-7.7p1-seed-prng.patch b/openssh-7.7p1-seed-prng.patch index e9b7f60..deb38cf 100644 --- a/openssh-7.7p1-seed-prng.patch +++ b/openssh-7.7p1-seed-prng.patch @@ -3,25 +3,71 @@ # extended support for (re-)seeding the OpenSSL PRNG from /dev/random # bnc#703221, FATE#312172 -Index: openssh-7.8p1/entropy.c -=================================================================== ---- openssh-7.8p1.orig/entropy.c -+++ openssh-7.8p1/entropy.c -@@ -235,6 +235,9 @@ seed_rng(void) - memset(buf, '\0', sizeof(buf)); +diff --git a/Makefile.in b/Makefile.in +index 85818f4..750aada 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -182,13 +182,13 @@ libssh.a: $(LIBSSH_OBJS) + $(RANLIB) $@ + ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) +- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) ++ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(SSHLIBS) $(LIBS) $(GSSLIBS) + + sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) +- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) ++ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) + + scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o +- $(LD) -o $@ scp.o progressmeter.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ scp.o progressmeter.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + + ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o + $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +@@ -197,10 +197,10 @@ ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o + $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + + ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o sshsig.o +- $(LD) -o $@ ssh-keygen.o sshsig.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-keygen.o sshsig.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + + ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o uidswap.o compat.o +- $(LD) -o $@ ssh-keysign.o readconf.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-keysign.o readconf.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + + ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11.o + $(LD) -o $@ ssh-pkcs11-helper.o ssh-pkcs11.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +@@ -209,10 +209,10 @@ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-realpath.o sftp-server-main.o +- $(LD) -o $@ sftp-server.o sftp-common.o sftp-realpath.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ sftp-server.o sftp-common.o sftp-realpath.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + + sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o +- $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) ++ $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) + + # FIPS tests + cavstest-ctr$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-ctr.o +diff --git a/entropy.c b/entropy.c +index 5de6801..f8b9f42 100644 +--- a/entropy.c ++++ b/entropy.c +@@ -239,6 +239,8 @@ seed_rng(void) + } #endif /* OPENSSL_PRNG_ONLY */ -+ + + linux_seed(); + if (RAND_status() != 1) fatal("PRNG is not seeded"); - } -Index: openssh-7.8p1/openbsd-compat/Makefile.in -=================================================================== ---- openssh-7.8p1.orig/openbsd-compat/Makefile.in -+++ openssh-7.8p1/openbsd-compat/Makefile.in -@@ -90,6 +90,7 @@ COMPAT= arc4random.o \ + +diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in +index 1162dc5..80fd688 100644 +--- a/openbsd-compat/Makefile.in ++++ b/openbsd-compat/Makefile.in +@@ -91,6 +91,7 @@ COMPAT= arc4random.o \ PORTS= port-aix.o \ port-irix.o \ port-linux.o \ @@ -29,10 +75,11 @@ Index: openssh-7.8p1/openbsd-compat/Makefile.in port-solaris.o \ port-net.o \ port-uw.o -Index: openssh-7.8p1/openbsd-compat/port-linux-prng.c -=================================================================== +diff --git a/openbsd-compat/port-linux-prng.c b/openbsd-compat/port-linux-prng.c +new file mode 100644 +index 0000000..dfc4bdb --- /dev/null -+++ openssh-7.8p1/openbsd-compat/port-linux-prng.c ++++ b/openbsd-compat/port-linux-prng.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Jan F. Chadima @@ -115,10 +162,10 @@ Index: openssh-7.8p1/openbsd-compat/port-linux-prng.c + fatal ("EOF reading %s", rand_file); + } +} -Index: openssh-7.8p1/openbsd-compat/port-linux.h -=================================================================== ---- openssh-7.8p1.orig/openbsd-compat/port-linux.h -+++ openssh-7.8p1/openbsd-compat/port-linux.h +diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 3c22a85..2dc1fd0 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h @@ -17,6 +17,10 @@ #ifndef _PORT_LINUX_H #define _PORT_LINUX_H @@ -130,11 +177,11 @@ Index: openssh-7.8p1/openbsd-compat/port-linux.h #ifdef WITH_SELINUX int ssh_selinux_enabled(void); void ssh_selinux_setup_pty(char *, const char *); -Index: openssh-7.8p1/ssh-add.1 -=================================================================== ---- openssh-7.8p1.orig/ssh-add.1 -+++ openssh-7.8p1/ssh-add.1 -@@ -172,6 +172,20 @@ to make this work.) +diff --git a/ssh-add.1 b/ssh-add.1 +index d4e1c60..6f76900 100644 +--- a/ssh-add.1 ++++ b/ssh-add.1 +@@ -189,6 +189,20 @@ to make this work.) Identifies the path of a .Ux Ns -domain socket used to communicate with the agent. @@ -155,11 +202,11 @@ Index: openssh-7.8p1/ssh-add.1 .El .Sh FILES .Bl -tag -width Ds -Index: openssh-7.8p1/ssh-agent.1 -=================================================================== ---- openssh-7.8p1.orig/ssh-agent.1 -+++ openssh-7.8p1/ssh-agent.1 -@@ -214,6 +214,23 @@ sockets used to contain the connection t +diff --git a/ssh-agent.1 b/ssh-agent.1 +index 83b2b41..9e187f2 100644 +--- a/ssh-agent.1 ++++ b/ssh-agent.1 +@@ -214,6 +214,23 @@ sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El @@ -183,11 +230,11 @@ Index: openssh-7.8p1/ssh-agent.1 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , -Index: openssh-7.8p1/ssh-keygen.1 -=================================================================== ---- openssh-7.8p1.orig/ssh-keygen.1 -+++ openssh-7.8p1/ssh-keygen.1 -@@ -869,6 +869,23 @@ Contains Diffie-Hellman groups used for +diff --git a/ssh-keygen.1 b/ssh-keygen.1 +index 957d2f0..70c4a28 100644 +--- a/ssh-keygen.1 ++++ b/ssh-keygen.1 +@@ -1054,6 +1054,23 @@ Contains Diffie-Hellman groups used for DH-GEX. The file format is described in .Xr moduli 5 . .El @@ -211,11 +258,11 @@ Index: openssh-7.8p1/ssh-keygen.1 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , -Index: openssh-7.8p1/ssh-keysign.8 -=================================================================== ---- openssh-7.8p1.orig/ssh-keysign.8 -+++ openssh-7.8p1/ssh-keysign.8 -@@ -80,6 +80,23 @@ must be set-uid root if host-based authe +diff --git a/ssh-keysign.8 b/ssh-keysign.8 +index 19b0dbc..639b56e 100644 +--- a/ssh-keysign.8 ++++ b/ssh-keysign.8 +@@ -80,6 +80,23 @@ must be set-uid root if host-based authentication is used. If these files exist they are assumed to contain public certificate information corresponding with the private keys above. .El @@ -239,11 +286,11 @@ Index: openssh-7.8p1/ssh-keysign.8 .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-keygen 1 , -Index: openssh-7.8p1/ssh.1 -=================================================================== ---- openssh-7.8p1.orig/ssh.1 -+++ openssh-7.8p1/ssh.1 -@@ -1432,6 +1432,20 @@ For more information, see the +diff --git a/ssh.1 b/ssh.1 +index 424d6c3..899a339 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -1433,6 +1433,20 @@ For more information, see the .Cm PermitUserEnvironment option in .Xr sshd_config 5 . @@ -264,11 +311,11 @@ Index: openssh-7.8p1/ssh.1 .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.rhosts -Index: openssh-7.8p1/sshd.8 -=================================================================== ---- openssh-7.8p1.orig/sshd.8 -+++ openssh-7.8p1/sshd.8 -@@ -966,6 +966,23 @@ concurrently for different ports, this c +diff --git a/sshd.8 b/sshd.8 +index fb133c1..2f1d3ab 100644 +--- a/sshd.8 ++++ b/sshd.8 +@@ -966,6 +966,23 @@ concurrently for different ports, this contains the process ID of the one started last). The content of this file is not sensitive; it can be world-readable. .El @@ -292,10 +339,10 @@ Index: openssh-7.8p1/sshd.8 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , -Index: openssh-7.8p1/sshd.c -=================================================================== ---- openssh-7.8p1.orig/sshd.c -+++ openssh-7.8p1/sshd.c +diff --git a/sshd.c b/sshd.c +index bb20eec..c562094 100644 +--- a/sshd.c ++++ b/sshd.c @@ -55,6 +55,8 @@ #endif #include "openbsd-compat/sys-tree.h" @@ -305,7 +352,7 @@ Index: openssh-7.8p1/sshd.c #include #include -@@ -208,6 +210,13 @@ struct { +@@ -205,6 +207,13 @@ struct { int have_ssh2_key; } sensitive_data; @@ -319,8 +366,8 @@ Index: openssh-7.8p1/sshd.c /* This is set to true when a signal is received. */ static volatile sig_atomic_t received_sighup = 0; static volatile sig_atomic_t received_sigterm = 0; -@@ -1252,6 +1261,10 @@ server_accept_loop(int *sock_in, int *so - startups++; +@@ -1201,6 +1210,10 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) + startup_flags[j] = 1; break; } + if(!(--re_seeding_counter)) { diff --git a/openssh-7.7p1-sftp_print_diagnostic_messages.patch b/openssh-7.7p1-sftp_print_diagnostic_messages.patch index ad61a2d..4c4c8de 100644 --- a/openssh-7.7p1-sftp_print_diagnostic_messages.patch +++ b/openssh-7.7p1-sftp_print_diagnostic_messages.patch @@ -3,26 +3,11 @@ Put back sftp client diagnostic messages in batch mode bsc#1023275 - -Index: openssh-7.8p1/sftp.0 -=================================================================== ---- openssh-7.8p1.orig/sftp.0 -+++ openssh-7.8p1/sftp.0 -@@ -160,6 +160,9 @@ DESCRIPTION - -p Preserves modification times, access times, and modes from the - original files transferred. - -+ -Q Not-so-quiet batch mode: forces printing of diagnostic messages -+ in batch mode. -+ - -q Quiet mode: disables the progress meter as well as warning and - diagnostic messages from ssh(1). - -Index: openssh-7.8p1/sftp.1 -=================================================================== ---- openssh-7.8p1.orig/sftp.1 -+++ openssh-7.8p1/sftp.1 -@@ -256,6 +256,9 @@ Specifies the port to connect to on the +diff --git a/sftp.1 b/sftp.1 +index a52c1cf..7333de8 100644 +--- a/sftp.1 ++++ b/sftp.1 +@@ -278,6 +278,9 @@ Specifies the port to connect to on the remote host. .It Fl p Preserves modification times, access times, and modes from the original files transferred. @@ -32,11 +17,11 @@ Index: openssh-7.8p1/sftp.1 .It Fl q Quiet mode: disables the progress meter as well as warning and diagnostic messages from -Index: openssh-7.8p1/sftp.c -=================================================================== ---- openssh-7.8p1.orig/sftp.c -+++ openssh-7.8p1/sftp.c -@@ -86,6 +86,9 @@ static volatile pid_t sshpid = -1; +diff --git a/sftp.c b/sftp.c +index b66037f..6c94a38 100644 +--- a/sftp.c ++++ b/sftp.c +@@ -85,6 +85,9 @@ static volatile pid_t sshpid = -1; /* Suppress diagnositic messages */ int quiet = 0; @@ -46,16 +31,16 @@ Index: openssh-7.8p1/sftp.c /* This is set to 0 if the progressmeter is not desired. */ int showprogress = 1; -@@ -2373,7 +2376,7 @@ main(int argc, char **argv) +@@ -2406,7 +2409,7 @@ main(int argc, char **argv) infile = stdin; while ((ch = getopt(argc, argv, -- "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { -+ "1246afhpQqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { +- "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { ++ "1246afhpQqrvCc:D:i:l:o:s:S:b:B:F:J:P:R:")) != -1) { switch (ch) { /* Passed through to ssh(1) */ case '4': -@@ -2389,6 +2392,9 @@ main(int argc, char **argv) +@@ -2423,6 +2426,9 @@ main(int argc, char **argv) addargs(&args, "-%c", ch); addargs(&args, "%s", optarg); break; @@ -65,7 +50,7 @@ Index: openssh-7.8p1/sftp.c case 'q': ll = SYSLOG_LEVEL_ERROR; quiet = 1; -@@ -2472,6 +2478,8 @@ main(int argc, char **argv) +@@ -2506,6 +2512,8 @@ main(int argc, char **argv) usage(); } } diff --git a/openssh-7.9p1-CVE-2018-20685.patch b/openssh-7.9p1-CVE-2018-20685.patch deleted file mode 100644 index ac539dc..0000000 --- a/openssh-7.9p1-CVE-2018-20685.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 6010c0303a422a9c5fa8860c061bf7105eb7f8b2 Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Fri, 16 Nov 2018 03:03:10 +0000 -Subject: [PATCH] upstream: disallow empty incoming filename or ones that refer - to the - -current directory; based on report/patch from Harry Sintonen - -OpenBSD-Commit-ID: f27651b30eaee2df49540ab68d030865c04f6de9 ---- - scp.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/scp.c b/scp.c -index 60682c687..4f3fdcd3d 100644 ---- a/scp.c -+++ b/scp.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: scp.c,v 1.197 2018/06/01 04:31:48 dtucker Exp $ */ -+/* $OpenBSD: scp.c,v 1.198 2018/11/16 03:03:10 djm Exp $ */ - /* - * scp - secure remote copy. This is basically patched BSD rcp which - * uses ssh to do the data transfer (instead of using rcmd). -@@ -1106,7 +1106,8 @@ sink(int argc, char **argv) - SCREWUP("size out of range"); - size = (off_t)ull; - -- if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) { -+ if (*cp == '\0' || strchr(cp, '/') != NULL || -+ strcmp(cp, ".") == 0 || strcmp(cp, "..") == 0) { - run_err("error: unexpected filename: %s", cp); - exit(1); - } diff --git a/openssh-7.9p1-brace-expansion.patch b/openssh-7.9p1-brace-expansion.patch deleted file mode 100644 index ab0aa32..0000000 --- a/openssh-7.9p1-brace-expansion.patch +++ /dev/null @@ -1,348 +0,0 @@ -From 3d896c157c722bc47adca51a58dca859225b5874 Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Sun, 10 Feb 2019 11:15:52 +0000 -Subject: [PATCH] upstream: when checking that filenames sent by the server - side - -match what the client requested, be prepared to handle shell-style brace -alternations, e.g. "{foo,bar}". - -"looks good to me" millert@ + in snaps for the last week courtesy -deraadt@ - -OpenBSD-Commit-ID: 3b1ce7639b0b25b2248e3a30f561a548f6815f3e ---- - scp.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 270 insertions(+), 12 deletions(-) - -Index: openssh-7.9p1/scp.c -=================================================================== ---- openssh-7.9p1.orig/scp.c -+++ openssh-7.9p1/scp.c -@@ -627,6 +627,253 @@ parse_scp_uri(const char *uri, char **us - return r; - } - -+/* Appends a string to an array; returns 0 on success, -1 on alloc failure */ -+static int -+append(char *cp, char ***ap, size_t *np) -+{ -+ char **tmp; -+ -+ if ((tmp = reallocarray(*ap, *np + 1, sizeof(*tmp))) == NULL) -+ return -1; -+ tmp[(*np)] = cp; -+ (*np)++; -+ *ap = tmp; -+ return 0; -+} -+ -+/* -+ * Finds the start and end of the first brace pair in the pattern. -+ * returns 0 on success or -1 for invalid patterns. -+ */ -+static int -+find_brace(const char *pattern, int *startp, int *endp) -+{ -+ int i; -+ int in_bracket, brace_level; -+ -+ *startp = *endp = -1; -+ in_bracket = brace_level = 0; -+ for (i = 0; i < INT_MAX && *endp < 0 && pattern[i] != '\0'; i++) { -+ switch (pattern[i]) { -+ case '\\': -+ /* skip next character */ -+ if (pattern[i + 1] != '\0') -+ i++; -+ break; -+ case '[': -+ in_bracket = 1; -+ break; -+ case ']': -+ in_bracket = 0; -+ break; -+ case '{': -+ if (in_bracket) -+ break; -+ if (pattern[i + 1] == '}') { -+ /* Protect a single {}, for find(1), like csh */ -+ i++; /* skip */ -+ break; -+ } -+ if (*startp == -1) -+ *startp = i; -+ brace_level++; -+ break; -+ case '}': -+ if (in_bracket) -+ break; -+ if (*startp < 0) { -+ /* Unbalanced brace */ -+ return -1; -+ } -+ if (--brace_level <= 0) -+ *endp = i; -+ break; -+ } -+ } -+ /* unbalanced brackets/braces */ -+ if (*endp < 0 && (*startp >= 0 || in_bracket)) -+ return -1; -+ return 0; -+} -+ -+/* -+ * Assembles and records a successfully-expanded pattern, returns -1 on -+ * alloc failure. -+ */ -+static int -+emit_expansion(const char *pattern, int brace_start, int brace_end, -+ int sel_start, int sel_end, char ***patternsp, size_t *npatternsp) -+{ -+ char *cp; -+ int o = 0, tail_len = strlen(pattern + brace_end + 1); -+ -+ if ((cp = malloc(brace_start + (sel_end - sel_start) + -+ tail_len + 1)) == NULL) -+ return -1; -+ -+ /* Pattern before initial brace */ -+ if (brace_start > 0) { -+ memcpy(cp, pattern, brace_start); -+ o = brace_start; -+ } -+ /* Current braced selection */ -+ if (sel_end - sel_start > 0) { -+ memcpy(cp + o, pattern + sel_start, -+ sel_end - sel_start); -+ o += sel_end - sel_start; -+ } -+ /* Remainder of pattern after closing brace */ -+ if (tail_len > 0) { -+ memcpy(cp + o, pattern + brace_end + 1, tail_len); -+ o += tail_len; -+ } -+ cp[o] = '\0'; -+ if (append(cp, patternsp, npatternsp) != 0) { -+ free(cp); -+ return -1; -+ } -+ return 0; -+} -+ -+/* -+ * Expand the first encountered brace in pattern, appending the expanded -+ * patterns it yielded to the *patternsp array. -+ * -+ * Returns 0 on success or -1 on allocation failure. -+ * -+ * Signals whether expansion was performed via *expanded and whether -+ * pattern was invalid via *invalid. -+ */ -+static int -+brace_expand_one(const char *pattern, char ***patternsp, size_t *npatternsp, -+ int *expanded, int *invalid) -+{ -+ int i; -+ int in_bracket, brace_start, brace_end, brace_level; -+ int sel_start, sel_end; -+ -+ *invalid = *expanded = 0; -+ -+ if (find_brace(pattern, &brace_start, &brace_end) != 0) { -+ *invalid = 1; -+ return 0; -+ } else if (brace_start == -1) -+ return 0; -+ -+ in_bracket = brace_level = 0; -+ for (i = sel_start = brace_start + 1; i < brace_end; i++) { -+ switch (pattern[i]) { -+ case '{': -+ if (in_bracket) -+ break; -+ brace_level++; -+ break; -+ case '}': -+ if (in_bracket) -+ break; -+ brace_level--; -+ break; -+ case '[': -+ in_bracket = 1; -+ break; -+ case ']': -+ in_bracket = 0; -+ break; -+ case '\\': -+ if (i < brace_end - 1) -+ i++; /* skip */ -+ break; -+ } -+ if (pattern[i] == ',' || i == brace_end - 1) { -+ if (in_bracket || brace_level > 0) -+ continue; -+ /* End of a selection, emit an expanded pattern */ -+ -+ /* Adjust end index for last selection */ -+ sel_end = (i == brace_end - 1) ? brace_end : i; -+ if (emit_expansion(pattern, brace_start, brace_end, -+ sel_start, sel_end, patternsp, npatternsp) != 0) -+ return -1; -+ /* move on to the next selection */ -+ sel_start = i + 1; -+ continue; -+ } -+ } -+ if (in_bracket || brace_level > 0) { -+ *invalid = 1; -+ return 0; -+ } -+ /* success */ -+ *expanded = 1; -+ return 0; -+} -+ -+/* Expand braces from pattern. Returns 0 on success, -1 on failure */ -+static int -+brace_expand(const char *pattern, char ***patternsp, size_t *npatternsp) -+{ -+ char *cp, *cp2, **active = NULL, **done = NULL; -+ size_t i, nactive = 0, ndone = 0; -+ int ret = -1, invalid = 0, expanded = 0; -+ -+ *patternsp = NULL; -+ *npatternsp = 0; -+ -+ /* Start the worklist with the original pattern */ -+ if ((cp = strdup(pattern)) == NULL) -+ return -1; -+ if (append(cp, &active, &nactive) != 0) { -+ free(cp); -+ return -1; -+ } -+ while (nactive > 0) { -+ cp = active[nactive - 1]; -+ nactive--; -+ if (brace_expand_one(cp, &active, &nactive, -+ &expanded, &invalid) == -1) { -+ free(cp); -+ goto fail; -+ } -+ if (invalid) -+ fatal("%s: invalid brace pattern \"%s\"", __func__, cp); -+ if (expanded) { -+ /* -+ * Current entry expanded to new entries on the -+ * active list; discard the progenitor pattern. -+ */ -+ free(cp); -+ continue; -+ } -+ /* -+ * Pattern did not expand; append the finename component to -+ * the completed list -+ */ -+ if ((cp2 = strrchr(cp, '/')) != NULL) -+ *cp2++ = '\0'; -+ else -+ cp2 = cp; -+ if (append(xstrdup(cp2), &done, &ndone) != 0) { -+ free(cp); -+ goto fail; -+ } -+ free(cp); -+ } -+ /* success */ -+ *patternsp = done; -+ *npatternsp = ndone; -+ done = NULL; -+ ndone = 0; -+ ret = 0; -+ fail: -+ for (i = 0; i < nactive; i++) -+ free(active[i]); -+ free(active); -+ for (i = 0; i < ndone; i++) -+ free(done[i]); -+ free(done); -+ return ret; -+} -+ - void - toremote(int argc, char **argv) - { -@@ -990,7 +1237,8 @@ sink(int argc, char **argv, const char * - unsigned long long ull; - int setimes, targisdir, wrerrno = 0; - char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; -- char *src_copy = NULL, *restrict_pattern = NULL; -+ char **patterns = NULL; -+ size_t n, npatterns = 0; - struct timeval tv[2]; - - #define atime tv[0] -@@ -1020,16 +1268,13 @@ sink(int argc, char **argv, const char * - * Prepare to try to restrict incoming filenames to match - * the requested destination file glob. - */ -- if ((src_copy = strdup(src)) == NULL) -- fatal("strdup failed"); -- if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) { -- *restrict_pattern++ = '\0'; -- } -+ if (brace_expand(src, &patterns, &npatterns) != 0) -+ fatal("%s: could not expand pattern", __func__); - } - for (first = 1;; first = 0) { - cp = buf; - if (atomicio(read, remin, cp, 1) != 1) -- return; -+ goto done; - if (*cp++ == '\n') - SCREWUP("unexpected "); - do { -@@ -1055,7 +1300,7 @@ sink(int argc, char **argv, const char * - } - if (buf[0] == 'E') { - (void) atomicio(vwrite, remout, "", 1); -- return; -+ goto done; - } - if (ch == '\n') - *--cp = 0; -@@ -1130,9 +1375,14 @@ sink(int argc, char **argv, const char * - run_err("error: unexpected filename: %s", cp); - exit(1); - } -- if (restrict_pattern != NULL && -- fnmatch(restrict_pattern, cp, 0) != 0) -- SCREWUP("filename does not match request"); -+ if (npatterns > 0) { -+ for (n = 0; n < npatterns; n++) { -+ if (fnmatch(patterns[n], cp, 0) == 0) -+ break; -+ } -+ if (n >= npatterns) -+ SCREWUP("filename does not match request"); -+ } - if (targisdir) { - static char *namebuf; - static size_t cursize; -@@ -1291,7 +1541,15 @@ bad: run_err("%s: %s", np, strerror(er - break; - } - } -+done: -+ for (n = 0; n < npatterns; n++) -+ free(patterns[n]); -+ free(patterns); -+ return; - screwup: -+ for (n = 0; n < npatterns; n++) -+ free(patterns[n]); -+ free(patterns); - run_err("protocol error: %s", why); - exit(1); - } diff --git a/openssh-7.9p1.tar.gz b/openssh-7.9p1.tar.gz deleted file mode 100644 index c60cf36..0000000 --- a/openssh-7.9p1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6b4b3ba2253d84ed3771c8050728d597c91cfce898713beb7b64a305b6f11aad -size 1565384 diff --git a/openssh-7.9p1.tar.gz.asc b/openssh-7.9p1.tar.gz.asc deleted file mode 100644 index ced7989..0000000 --- a/openssh-7.9p1.tar.gz.asc +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQHDBAABCgAdFiEEWcIRjtIG2SfmZ+vj0+X1a22SDTAFAlvJLhsACgkQ0+X1a22S -DTBjHwx/T3EX3EtCzB9I6zHFUgF2/0hEKVYZw2Yl4UbUvgjy/KdEdlJzdH3Hc/yU -jJZzraDY7nJMrCly734FbFGKsKoRkxWMkeuQGOhvpzgTYg+fOa1J0a14xK/ub9Y0 -9Z/4zP0Zs7mn+8MApMS3XOZ+AJgdRiXN9i3PXmbYO9Gcg+QthtgE1DeG0d0vVTP/ -ipCBBg8mMlAANdlu9IUCv4CJPwJjQt2aYsvCiuUQuzrKYsV5noCOBaGRbmPcN9SM -3cvSTZgDbK3kHdL1RnBgWpcO+o+D8sqSW2rm8xpCQv/ILo86/BLBjXDCYLEt0nSn -+dONPytwhwwJWPPYe7+RSYWHS2cKwVTDk7lr2E636SwU1fM1NiNYle9hB6cUT0nU -sypfHOIARAMSqepnaT3WgffM0jlEWrSB0PuDLTLTO5ZPmUijqqT6xGwWSUc4GQZY -WNyGg1w0Ryj2pRd7DlXDDivTCneXFqV7JZiR3R4ZXJJV0uVQOUitCS/DnwSDpIfp -HlVEWeRAszQFKLKttu0/4SY2NVrRBA== -=4Z9x ------END PGP SIGNATURE----- diff --git a/openssh-8.0p1-gssapi-keyex.patch b/openssh-8.0p1-gssapi-keyex.patch new file mode 100644 index 0000000..a849032 --- /dev/null +++ b/openssh-8.0p1-gssapi-keyex.patch @@ -0,0 +1,3922 @@ +diff --git a/Makefile.in b/Makefile.in +index 1baf5c6..02bafbc 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 \ + platform-pledge.o platform-tracing.o platform-misc.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 sftp-realpath.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ +diff --git a/auth.c b/auth.c +index 5c58dd1..ab43955 100644 +--- a/auth.c ++++ b/auth.c +@@ -399,7 +399,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: +@@ -723,99 +724,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 strdup(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 strdup(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 strdup(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 strdup(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 strdup(ntop); +- } +- return strdup(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 9351e04..d6446c0 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 0e77622..1c21726 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 abea9c6..9a00fc2 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 strdup(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 strdup(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 strdup(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 strdup(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 strdup(ntop); ++ } ++ return strdup(name); ++} ++ + void + ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) + { +diff --git a/canohost.h b/canohost.h +index 26d6285..0cadc9f 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 b5a1f70..9def2a1 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; + +@@ -1373,9 +1377,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 ff9c11a..c0db779 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -666,6 +666,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 d56257b..3eaa5fa 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,161 @@ 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, 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 +397,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 +426,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 +470,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 +499,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 +518,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 +531,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 a151bc1..8d2b677 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,7 +120,7 @@ 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 *new_ccname, *new_cctype; + const char *errmsg; + + if (client->creds == NULL) { +@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) + return; + } + +- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); ++ new_cctype = krb5_cc_get_type(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 ++ if (new_ccname[0] == ':') ++ new_ccname++; ++ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); ++ if (strcmp(new_cctype, "DIR") == 0) { ++ char *p; ++ p = strrchr(client->store.envval, '/'); ++ if (p) ++ *p = '\0'; ++ } ++ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) ++ client->store.filename = xstrdup(new_ccname); ++#endif + + #ifdef USE_PAM + if (options.use_pam) +@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) + + krb5_cc_close(krb_context, ccache); + ++ client->store.data = krb_context; ++ + 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 +285,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 ab3a15f..6ce56e9 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); ++ } + +- gss_buffer_desc ename; ++ 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; ++ } ++ ++ 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; +@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + void + ssh_gssapi_cleanup_creds(void) + { +- if (gssapi_client.store.filename != NULL) { +- /* Unlink probably isn't sufficient */ +- debug("removing gssapi cred file\"%s\"", +- gssapi_client.store.filename); +- unlink(gssapi_client.store.filename); ++ krb5_ccache ccache = NULL; ++ krb5_error_code problem; ++ ++ if (gssapi_client.store.data != NULL) { ++ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { ++ debug("%s: krb5_cc_resolve(): %.100s", __func__, ++ krb5_get_err_text(gssapi_client.store.data, problem)); ++ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { ++ debug("%s: krb5_cc_destroy(): %.100s", __func__, ++ krb5_get_err_text(gssapi_client.store.data, problem)); ++ } else { ++ krb5_free_context(gssapi_client.store.data); ++ gssapi_client.store.data = NULL; ++ } + } + } + +@@ -356,19 +441,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 +471,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 1f82c2e..92d8ee0 100644 +--- a/kex.c ++++ b/kex.c +@@ -55,11 +55,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 ++ + #include "fips.h" + + /* prototype */ +@@ -115,6 +120,19 @@ static const struct kexalg kexalgs_all[] = { + #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 }, ++}; + + static const struct kexalg kexalgs_fips140_2[] = { + #ifdef WITH_OPENSSL +@@ -142,12 +160,12 @@ static const struct kexalg kexalgs_fips140_2[] = { + + /* Returns array of macs available depending on selected FIPS mode */ + static const struct kexalg * +-fips_select_kexalgs(void) ++fips_select_kexalgs(const struct kexalg *algs) + { + int fips = fips_mode(); + switch (fips) { + case 0: +- return kexalgs_all; ++ return algs; + case 1: + return kexalgs_fips140_2; + default: +@@ -158,13 +176,13 @@ fips_select_kexalgs(void) + } + + char * +-kex_alg_list(char sep) ++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 = fips_select_kexalgs(); k->name != NULL; k++) { ++ for (k = fips_select_kexalgs(algs); k->name != NULL; k++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); +@@ -179,15 +197,31 @@ kex_alg_list(char sep) + return ret; + } + ++char * ++kex_alg_list(char sep) ++{ ++ return kex_alg_list_internal(sep, kexalgs_all); ++} ++ ++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) + { + const struct kexalg *k; + +- for (k = fips_select_kexalgs(); k->name != NULL; k++) { ++ for (k = fips_select_kexalgs(kexalgs_all); k->name != NULL; k++) { + 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; + } + +@@ -359,6 +393,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]) +@@ -742,6 +799,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 a5ae6ac..4dc48fd 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 *); ++#ifdef GSSAPI ++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 67133e3..edaa467 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 bb996b5..d353ed8 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 0000000..0b2f6a5 +--- /dev/null ++++ b/kexgssc.c +@@ -0,0 +1,595 @@ ++/* ++ * 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 = sshbuf_new(); ++ 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; ++ ++ 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 = sshbuf_new(); ++ 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); ++ ++ 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; ++ ++ 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(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 0000000..60bc02d +--- /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 00af44f..20812fa 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -147,6 +147,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 +@@ -219,11 +221,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 +@@ -292,6 +301,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) { +@@ -405,6 +418,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); +@@ -1687,6 +1704,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; +@@ -1780,8 +1808,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)); +@@ -1813,8 +1841,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)); +@@ -1834,6 +1862,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); + } +@@ -1845,8 +1874,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) +@@ -1872,13 +1901,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) +@@ -1887,7 +1920,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); +@@ -1895,5 +1932,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 683e5e0..2b1a2d5 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 4169b76..fdca39a 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -978,13 +978,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, +@@ -997,4 +999,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 191277f..92dda57 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -63,8 +63,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 228f481..24f2cb1 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -67,6 +67,7 @@ + #include "uidswap.h" + #include "myproposal.h" + #include "digest.h" ++#include "ssh-gss.h" + + #include "fips.h" + +@@ -164,6 +165,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 }, +@@ -990,10 +1005,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; +@@ -1882,7 +1929,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; +@@ -2028,8 +2081,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) +@@ -2647,7 +2710,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 67111e9..2617764 100644 +--- a/readconf.h ++++ b/readconf.h +@@ -40,7 +40,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 a8833a9..13cf154 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -64,6 +64,7 @@ + #include "auth.h" + #include "myproposal.h" + #include "digest.h" ++#include "ssh-gss.h" + #include "fips.h" + + static void add_listen_addr(ServerOptions *, const char *, +@@ -126,8 +127,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; +@@ -374,10 +378,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) +@@ -523,6 +535,7 @@ typedef enum { + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, ++ sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, +@@ -599,12 +612,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 }, +@@ -1518,6 +1541,10 @@ process_server_config_line(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; +@@ -1526,6 +1553,22 @@ process_server_config_line(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; +@@ -2615,6 +2658,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 4670a5a..56373e5 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -126,8 +126,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 d81060c..89f9539 100644 +--- a/session.c ++++ b/session.c +@@ -2713,13 +2713,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 36180d0..70dd366 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 899a339..70d3017 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -497,7 +497,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 +@@ -573,6 +579,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 882d1da..5f3ca8d 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -742,6 +742,8 @@ main(int ac, char **av) + cp = mac_alg_list('\n'); + else if (strcmp(optarg, "kex") == 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) +@@ -754,7 +756,7 @@ main(int ac, char **av) + cp = xstrdup("2"); + else if (strcmp(optarg, "help") == 0) { + cp = xstrdup( +- "cipher\ncipher-auth\nkex\nkey\n" ++ "cipher\ncipher-auth\nkex\nkex-gss\nkey\n" + "key-cert\nkey-plain\nmac\n" + "protocol-version\nsig"); + } +diff --git a/ssh_config b/ssh_config +index 3a00f4d..a798a43 100644 +--- a/ssh_config ++++ b/ssh_config +@@ -40,6 +40,8 @@ Host * + # 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 f0cb291..3bf0502 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -760,10 +760,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 87fa70a..9e8c3e5 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -78,8 +78,6 @@ + #endif + + /* import */ +-extern char *client_version_string; +-extern char *server_version_string; + extern Options options; + + /* +@@ -161,6 +159,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) + char *s, *all_key; + int r; + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ char *orig = NULL, *gss = NULL; ++ char *gss_host = NULL; ++#endif ++ + xxx_host = host; + xxx_hostaddr = hostaddr; + +@@ -193,6 +196,35 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) + order_hostkeyalgs(host, hostaddr, port)); + } + ++#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); +@@ -211,16 +243,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)); + +@@ -317,6 +379,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 *); +@@ -333,6 +396,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, +@@ -697,12 +765,23 @@ 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))) { ++ 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 && +@@ -711,13 +790,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; + +@@ -957,6 +1038,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 c562094..0d5c4c4 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -815,8 +815,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); + } +@@ -1800,7 +1800,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); + } +@@ -2297,6 +2298,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)); +@@ -2312,7 +2355,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 9ae8b05..8c1d1e5 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 8818ea5..50a4917 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -657,6 +657,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. +@@ -671,6 +676,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 ef90563..4d2048b 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -145,6 +145,7 @@ static const struct keytype keytypes[] = { + # endif /* OPENSSL_HAS_NISTP521 */ + # endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ ++ { "null", "null", NULL, KEY_NULL, 0, 0, 0 }, + { NULL, NULL, NULL, -1, -1, 0, 0 } + }; + +@@ -233,7 +234,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 1119a7b..1bf30d0 100644 +--- a/sshkey.h ++++ b/sshkey.h +@@ -65,6 +65,7 @@ enum sshkey_types { + KEY_ED25519_CERT, + KEY_XMSS, + KEY_XMSS_CERT, ++ KEY_NULL, + KEY_UNSPEC + }; + diff --git a/openssh-7.7p1-audit.patch b/openssh-8.1p1-audit.patch similarity index 53% rename from openssh-7.7p1-audit.patch rename to openssh-8.1p1-audit.patch index 506c82d..fb1980b 100644 --- a/openssh-7.7p1-audit.patch +++ b/openssh-8.1p1-audit.patch @@ -1,103 +1,95 @@ -# HG changeset patch -# Parent 8f6ff259bbb7a7f173004e8cb11a16e7a9a29c7f -Extended auditing through the Linux Auditing subsystem -RH patch from git://pkgs.fedoraproject.org/openssh.git - -Index: openssh-7.9p1/Makefile.in -=================================================================== ---- openssh-7.9p1.orig/Makefile.in -+++ openssh-7.9p1/Makefile.in -@@ -111,6 +111,8 @@ LIBSSH_OBJS += fips.o +diff --git a/Makefile.in b/Makefile.in +index 02bafbc..4ee4ab2 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -110,7 +110,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kexgexc.o kexgexs.o \ + sntrup4591761.o kexsntrup4591761x25519.o kexgen.o \ + kexgssc.o \ +- platform-pledge.o platform-tracing.o platform-misc.o ++ platform-pledge.o platform-tracing.o platform-misc.o \ ++ auditstub.o - LIBSSH_OBJS += kexgssc.o kexgsss.o -+LIBSSH_OBJS += auditstub.o -+ - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect2.o mux.o - -Index: openssh-7.9p1/audit-bsm.c -=================================================================== ---- openssh-7.9p1.orig/audit-bsm.c -+++ openssh-7.9p1/audit-bsm.c -@@ -372,10 +372,23 @@ audit_connection_from(const char *host, + LIBSSH_OBJS += fips.o +diff --git a/audit-bsm.c b/audit-bsm.c +index 0ba16c7..d5e9cda 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -372,12 +372,25 @@ audit_connection_from(const char *host, int port) #endif } --void +int - audit_run_command(const char *command) - { - /* not implemented */ ++audit_run_command(struct ssh *ssh, const char *command) ++{ ++ /* not implemented */ + return 0; +} + -+void -+audit_end_command(int handle, const char *command) -+{ -+ /* not implemented */ -+} -+ + void +-audit_run_command(const char *command) ++audit_end_command(struct ssh *ssh, int handle, const char *command) + { + /* not implemented */ + } + +void +audit_count_session_open(void) +{ + /* not necessary */ - } - ++} ++ void -@@ -390,6 +403,12 @@ audit_session_close(struct logininfo *li + audit_session_open(struct logininfo *li) + { +@@ -390,6 +403,12 @@ audit_session_close(struct logininfo *li) /* not implemented */ } +int -+audit_keyusage(int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) +{ + /* not implemented */ +} + void - audit_event(ssh_audit_event_t event) + audit_event(struct ssh *ssh, ssh_audit_event_t event) { -@@ -451,4 +470,34 @@ audit_event(ssh_audit_event_t event) +@@ -451,4 +470,28 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) debug("%s: unhandled event %d", __func__, event); } } + +void -+audit_unsupported_body(int what) ++audit_unsupported_body(struct ssh *ssh, int what) +{ + /* not implemented */ +} + +void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) +{ + /* not implemented */ +} + +void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++audit_session_key_free_body(struct ssh * ssh, int ctos, pid_t pid, uid_t uid) +{ + /* not implemented */ +} + +void -+audit_destroy_sensitive_data(const char *fp) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) +{ + /* not implemented */ +} #endif /* BSM */ -Index: openssh-7.9p1/audit-linux.c -=================================================================== ---- openssh-7.9p1.orig/audit-linux.c -+++ openssh-7.9p1/audit-linux.c -@@ -33,27 +33,41 @@ +diff --git a/audit-linux.c b/audit-linux.c +index 3fcbe5c..a823c30 100644 +--- a/audit-linux.c ++++ b/audit-linux.c +@@ -33,27 +33,40 @@ #include "log.h" #include "audit.h" @@ -106,14 +98,12 @@ Index: openssh-7.9p1/audit-linux.c +#include "auth.h" +#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ +#include "servconf.h" -+#include "ssherr.h" #include "canohost.h" #include "packet.h" -- +#include "cipher.h" +#include "channels.h" +#include "session.h" -+ + +#define AUDIT_LOG_SIZE 256 + +extern ServerOptions options; @@ -147,7 +137,7 @@ Index: openssh-7.9p1/audit-linux.c saved_errno = errno; close(audit_fd); -@@ -65,9 +79,96 @@ linux_audit_record_event(int uid, const +@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const char *username, const char *hostname, rc = 0; errno = saved_errno; @@ -156,8 +146,8 @@ Index: openssh-7.9p1/audit-linux.c +fatal_report: + fatal("linux_audit_write_entry failed: %s", strerror(errno)); + } - } - ++} ++ +static void +linux_audit_user_auth(int uid, const char *username, + const char *ip, const char *ttyn, int success, int event) @@ -211,7 +201,7 @@ Index: openssh-7.9p1/audit-linux.c +} + +int -+audit_keyusage(int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, rc, saved_errno; @@ -226,53 +216,53 @@ Index: openssh-7.9p1/audit-linux.c + } + snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(active_state), NULL, rv); ++ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) + goto out; + snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); + rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, -+ ssh_remote_ipaddr(active_state), NULL, rv); ++ ssh_remote_ipaddr(ssh), NULL, rv); +out: + saved_errno = errno; + audit_close(audit_fd); + errno = saved_errno; + /* do not report error if the error is EPERM and sshd is run as non root user */ + return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); -+} -+ + } + +static int user_login_count = 0; + /* Below is the sshd audit API code */ void -@@ -76,24 +177,55 @@ audit_connection_from(const char *host, +@@ -76,49 +176,210 @@ audit_connection_from(const char *host, int port) /* not implemented */ } --void +int - audit_run_command(const char *command) - { -- /* not implemented */ ++audit_run_command(struct ssh *ssh, const char *command) ++{ + if (!user_login_count++) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ ssh_remote_ipaddr(active_state), ++ ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ ssh_remote_ipaddr(active_state), ++ ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_START); + return 0; +} + -+void -+audit_end_command(int handle, const char *command) -+{ + void +-audit_run_command(const char *command) ++audit_end_command(struct ssh *ssh, int handle, const char *command) + { +- /* not implemented */ + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ ssh_remote_ipaddr(active_state), ++ ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ ssh_remote_ipaddr(active_state), ++ ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGOUT); +} + @@ -307,9 +297,8 @@ Index: openssh-7.9p1/audit-linux.c } void -@@ -102,25 +234,155 @@ audit_event(ssh_audit_event_t event) - struct ssh *ssh = active_state; /* XXX */ - + audit_event(struct ssh *ssh, ssh_audit_event_t event) + { switch(event) { - case SSH_AUTH_SUCCESS: - case SSH_CONNECTION_CLOSE: @@ -360,7 +349,7 @@ Index: openssh-7.9p1/audit-linux.c } + +void -+audit_unsupported_body(int what) ++audit_unsupported_body(struct ssh *ssh, int what) +{ +#ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; @@ -369,15 +358,15 @@ Index: openssh-7.9p1/audit-linux.c + int audit_fd; + + snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", -+ name[what], ssh_remote_port(active_state), (s = get_local_ipaddr(packet_get_connection_in())), -+ ssh_local_port(active_state)); ++ name[what], ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ++ ssh_local_port(ssh)); + free(s); + audit_fd = audit_open(); + if (audit_fd < 0) + /* no problem, the next instruction will be fatal() */ + return; + audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 0); ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 0); + audit_close(audit_fd); +#endif +} @@ -385,8 +374,8 @@ Index: openssh-7.9p1/audit-linux.c +const static char *direction[] = { "from-server", "from-client", "both" }; + +void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, -+ uid_t uid) ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, ++ char *pfs, pid_t pid, uid_t uid) +{ +#ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; @@ -397,7 +386,7 @@ Index: openssh-7.9p1/audit-linux.c + snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", + direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, + (intmax_t)pid, (intmax_t)uid, -+ ssh_remote_port(active_state), (s = get_local_ipaddr(packet_get_connection_in())), ssh_local_port(active_state)); ++ ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ssh_local_port(ssh)); + free(s); + audit_fd = audit_open(); + if (audit_fd < 0) { @@ -408,7 +397,7 @@ Index: openssh-7.9p1/audit-linux.c + fatal("cannot open audit"); /* Must prevent login */ + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 1); ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) @@ -417,7 +406,7 @@ Index: openssh-7.9p1/audit-linux.c +} + +void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; @@ -425,9 +414,9 @@ Index: openssh-7.9p1/audit-linux.c + + snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", + direction[ctos], (intmax_t)pid, (intmax_t)uid, -+ ssh_remote_port(active_state), -+ (s = get_local_ipaddr(packet_get_connection_in())), -+ ssh_local_port(active_state)); ++ ssh_remote_port(ssh), ++ (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ++ ssh_local_port(ssh)); + free(s); + audit_fd = audit_open(); + if (audit_fd < 0) { @@ -437,7 +426,7 @@ Index: openssh-7.9p1/audit-linux.c + return; + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 1); ++ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) @@ -445,7 +434,7 @@ Index: openssh-7.9p1/audit-linux.c +} + +void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; @@ -461,7 +450,7 @@ Index: openssh-7.9p1/audit-linux.c + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, -+ listening_for_clients() ? NULL : ssh_remote_ipaddr(active_state), ++ listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh), + NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ @@ -469,24 +458,24 @@ Index: openssh-7.9p1/audit-linux.c + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ -Index: openssh-7.9p1/audit.c -=================================================================== ---- openssh-7.9p1.orig/audit.c -+++ openssh-7.9p1/audit.c -@@ -34,13 +34,19 @@ +diff --git a/audit.c b/audit.c +index dd2f035..c8d54b1 100644 +--- a/audit.c ++++ b/audit.c +@@ -34,6 +34,12 @@ #include "log.h" #include "hostfile.h" #include "auth.h" -- +#include "ssh-gss.h" +#include "monitor_wrap.h" +#include "xmalloc.h" +#include "misc.h" +#include "servconf.h" +#include "ssherr.h" + /* * Care must be taken when using this since it WILL NOT be initialized when - * audit_connection_from() is called and MAY NOT be initialized when +@@ -41,6 +47,7 @@ * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. */ extern Authctxt *the_authctxt; @@ -494,7 +483,7 @@ Index: openssh-7.9p1/audit.c /* Maybe add the audit class to struct Authmethod? */ ssh_audit_event_t -@@ -69,13 +75,10 @@ audit_classify_auth(const char *method) +@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) const char * audit_username(void) { @@ -510,46 +499,47 @@ Index: openssh-7.9p1/audit.c return (the_authctxt->user); } -@@ -109,6 +112,35 @@ audit_event_lookup(ssh_audit_event_t ev) +@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) return(event_lookup[i].name); } +void -+audit_key(int host_user, int *rv, const struct sshkey *key) ++audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) +{ + char *fp; + + fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (audit_keyusage(host_user, fp, (*rv == 0)) == 0) ++ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) + *rv = -SSH_ERR_INTERNAL_ERROR; + free(fp); +} + +void -+audit_unsupported(int what) ++audit_unsupported(struct ssh *ssh, int what) +{ -+ PRIVSEP(audit_unsupported_body(what)); ++ PRIVSEP(audit_unsupported_body(ssh, what)); +} + +void -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) +{ -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); ++ PRIVSEP(audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid())); +} + +void -+audit_session_key_free(int ctos) ++audit_session_key_free(struct ssh *ssh, int ctos) +{ -+ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); ++ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid())); +} + # ifndef CUSTOM_SSH_AUDIT_EVENTS /* * Null implementations of audit functions. -@@ -138,6 +170,17 @@ audit_event(ssh_audit_event_t event) +@@ -137,6 +170,17 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + audit_username(), event, audit_event_lookup(event)); } - /* ++/* + * Called when a child process has called, or will soon call, + * audit_session_open. + */ @@ -560,11 +550,10 @@ Index: openssh-7.9p1/audit.c + audit_username()); +} + -+/* + /* * Called when a user session is started. Argument is the tty allocated to * the session, or NULL if no tty was allocated. - * -@@ -172,13 +215,82 @@ audit_session_close(struct logininfo *li +@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li) /* * This will be called when a user runs a non-interactive command. Note that * it may be called multiple times for a single connection since SSH2 allows @@ -573,8 +562,9 @@ Index: openssh-7.9p1/audit.c + * audit_end_command. */ -void +-audit_run_command(const char *command) +int - audit_run_command(const char *command) ++audit_run_command(struct ssh *ssh, const char *command) { debug("audit run command euid %d user %s command '%.200s'", geteuid(), audit_username(), command); @@ -588,7 +578,7 @@ Index: openssh-7.9p1/audit.c + * the corresponding audit_run_command. + */ +void -+audit_end_command(int handle, const char *command) ++audit_end_command(struct ssh *ssh, int handle, const char *command) +{ + debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); @@ -600,7 +590,7 @@ Index: openssh-7.9p1/audit.c + * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. + */ +int -+audit_keyusage(int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) +{ + debug("audit %s key usage euid %d user %s fingerprint %s, result %d", + host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), @@ -611,7 +601,7 @@ Index: openssh-7.9p1/audit.c + * This will be called when the protocol negotiation fails. + */ +void -+audit_unsupported_body(int what) ++audit_unsupported_body(struct ssh *ssh, int what) +{ + debug("audit unsupported protocol euid %d type %d", geteuid(), what); +} @@ -620,19 +610,19 @@ Index: openssh-7.9p1/audit.c + * This will be called on succesfull protocol negotiation. + */ +void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, + uid_t uid) +{ + debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", + (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, -+ (unsigned)uid); ++ (unsigned)uid); +} + +/* + * This will be called on succesfull session key discard + */ +void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) +{ + debug("audit session key discard euid %u direction %d from pid %ld uid %u", + (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); @@ -642,26 +632,26 @@ Index: openssh-7.9p1/audit.c + * This will be called on destroy private part of the server key + */ +void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) +{ + debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", + geteuid(), fp, (long)pid, (unsigned)uid); } # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ #endif /* SSH_AUDIT_EVENTS */ -Index: openssh-7.9p1/audit.h -=================================================================== ---- openssh-7.9p1.orig/audit.h -+++ openssh-7.9p1/audit.h +diff --git a/audit.h b/audit.h +index 38cb5ad..45d66cc 100644 +--- a/audit.h ++++ b/audit.h @@ -26,6 +26,7 @@ # define _SSH_AUDIT_H #include "loginrec.h" +#include "sshkey.h" - enum ssh_audit_event_type { - SSH_LOGIN_EXCEED_MAXTRIES, -@@ -43,13 +44,32 @@ enum ssh_audit_event_type { + struct ssh; + +@@ -45,13 +46,32 @@ enum ssh_audit_event_type { SSH_CONNECTION_ABANDON, /* closed without completing auth */ SSH_AUDIT_UNKNOWN }; @@ -676,30 +666,31 @@ Index: openssh-7.9p1/audit.h +int listening_for_clients(void); + void audit_connection_from(const char *, int); - void audit_event(ssh_audit_event_t); + void audit_event(struct ssh *, ssh_audit_event_t); +void audit_count_session_open(void); void audit_session_open(struct logininfo *); void audit_session_close(struct logininfo *); -void audit_run_command(const char *); -+int audit_run_command(const char *); -+void audit_end_command(int, const char *); ++int audit_run_command(struct ssh *, const char *); ++void audit_end_command(struct ssh *, int, const char *); ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(int, char *, int); -+void audit_key(int, int *, const struct sshkey *); -+void audit_unsupported(int); -+void audit_kex(int, char *, char *, char *, char *); -+void audit_unsupported_body(int); -+void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); -+void audit_session_key_free(int ctos); -+void audit_session_key_free_body(int ctos, pid_t, uid_t); -+void audit_destroy_sensitive_data(const char *, pid_t, uid_t); ++int audit_keyusage(struct ssh *, int, char *, int); ++void audit_key(struct ssh *, int, int *, const struct sshkey *); ++void audit_unsupported(struct ssh *, int); ++void audit_kex(struct ssh *, int, char *, char *, char *, char *); ++void audit_unsupported_body(struct ssh *, int); ++void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(struct ssh *, int ctos); ++void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); #endif /* _SSH_AUDIT_H */ -Index: openssh-7.9p1/auditstub.c -=================================================================== +diff --git a/auditstub.c b/auditstub.c +new file mode 100644 +index 0000000..639a798 --- /dev/null -+++ openssh-7.9p1/auditstub.c -@@ -0,0 +1,50 @@ ++++ b/auditstub.c +@@ -0,0 +1,52 @@ +/* $Id: auditstub.c,v 1.1 jfch Exp $ */ + +/* @@ -731,166 +722,159 @@ Index: openssh-7.9p1/auditstub.c + +#include + ++struct ssh; ++ +void -+audit_unsupported(int n) ++audit_unsupported(struct ssh *ssh, int n) +{ +} + +void -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) +{ +} + +void -+audit_session_key_free(int ctos) ++audit_session_key_free(struct ssh *ssh, int ctos) +{ +} + +void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) +{ +} -Index: openssh-7.9p1/auth.c -=================================================================== ---- openssh-7.9p1.orig/auth.c -+++ openssh-7.9p1/auth.c -@@ -366,7 +366,7 @@ auth_log(Authctxt *authctxt, int authent +diff --git a/auth.c b/auth.c +index ab43955..5a4d11a 100644 +--- a/auth.c ++++ b/auth.c +@@ -366,7 +366,7 @@ auth_log(struct ssh *ssh, int authenticated, int partial, # endif #endif #ifdef SSH_AUDIT_EVENTS - if (authenticated == 0 && !authctxt->postponed) + if (authenticated == 0 && !authctxt->postponed && !partial) - audit_event(audit_classify_auth(method)); + audit_event(ssh, audit_classify_auth(method)); #endif } -@@ -605,9 +605,6 @@ getpwnamallow(const char *user) - record_failed_login(user, +@@ -592,9 +592,6 @@ getpwnamallow(struct ssh *ssh, const char *user) + record_failed_login(ssh, user, auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); #endif -#ifdef SSH_AUDIT_EVENTS -- audit_event(SSH_INVALID_USER); +- audit_event(ssh, SSH_INVALID_USER); -#endif /* SSH_AUDIT_EVENTS */ return (NULL); } - if (!allowed_user(pw)) -Index: openssh-7.9p1/auth.h -=================================================================== ---- openssh-7.9p1.orig/auth.h -+++ openssh-7.9p1/auth.h -@@ -193,6 +193,8 @@ struct passwd * getpwnamallow(const char + if (!allowed_user(ssh, pw)) +diff --git a/auth.h b/auth.h +index becc672..84532d0 100644 +--- a/auth.h ++++ b/auth.h +@@ -189,6 +189,8 @@ struct passwd * getpwnamallow(struct ssh *, const char *user); char *expand_authorized_keys(const char *, struct passwd *pw); char *authorized_principals_file(struct passwd *); -+int user_key_verify(const struct sshkey *, const u_char *, size_t, -+ const u_char *, size_t, const char *, u_int); ++int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int); FILE *auth_openkeyfile(const char *, struct passwd *, int); FILE *auth_openprincipals(const char *, struct passwd *, int); -@@ -212,6 +214,8 @@ struct sshkey *get_hostkey_private_by_ty +@@ -208,6 +210,8 @@ struct sshkey *get_hostkey_private_by_type(int, int, struct ssh *); int get_hostkey_index(struct sshkey *, int, struct ssh *); - int sshd_hostkey_sign(struct sshkey *, struct sshkey *, u_char **, - size_t *, const u_char *, size_t, const char *, u_int); -+int hostbased_key_verify(const struct sshkey *, const u_char *, size_t, -+ const u_char *, size_t, const char *, u_int); + int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, + u_char **, size_t *, const u_char *, size_t, const char *); ++int hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int); /* Key / cert options linkage to auth layer */ const struct sshauthopt *auth_options(struct ssh *); -Index: openssh-7.9p1/auth2-hostbased.c -=================================================================== ---- openssh-7.9p1.orig/auth2-hostbased.c -+++ openssh-7.9p1/auth2-hostbased.c -@@ -148,7 +148,7 @@ userauth_hostbased(struct ssh *ssh) - /* test for allowed key and correct signature */ +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index d460470..de26444 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -150,7 +150,7 @@ userauth_hostbased(struct ssh *ssh) authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && + if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser, + chost, key)) && - PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(hostbased_key_verify(key, sig, slen, ++ PRIVSEP(hostbased_key_verify(ssh, key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0) authenticated = 1; -@@ -165,6 +165,19 @@ done: +@@ -167,6 +167,19 @@ done: return authenticated; } +int -+hostbased_key_verify(const struct sshkey *key, const u_char *sig, size_t slen, -+ const u_char *data, size_t datalen, const char *alg, u_int compat) ++hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, ++ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat) +{ + int rv; + -+ rv = sshkey_verify(key, sig, slen, data, datalen, alg, compat); ++ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat); +#ifdef SSH_AUDIT_EVENTS -+ audit_key(0, &rv, key); ++ audit_key(ssh, 0, &rv, key); +#endif + return rv; +} + /* return 1 if given hostkey is allowed */ int - hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, -Index: openssh-7.9p1/auth2-pubkey.c -=================================================================== ---- openssh-7.9p1.orig/auth2-pubkey.c -+++ openssh-7.9p1/auth2-pubkey.c -@@ -193,7 +193,7 @@ userauth_pubkey(struct ssh *ssh) + hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index df12c2c..6062b8b 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -210,7 +210,7 @@ userauth_pubkey(struct ssh *ssh) /* test for correct signature */ authenticated = 0; if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && - PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(user_key_verify(key, sig, slen, ++ PRIVSEP(user_key_verify(ssh, key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, ssh->compat)) == 0) { -@@ -252,6 +252,19 @@ done: +@@ -269,6 +269,19 @@ done: return authenticated; } +int -+user_key_verify(const struct sshkey *key, const u_char *sig, size_t slen, -+ const u_char *data, size_t datalen, const char *alg, u_int compat) ++user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, ++ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat) +{ -+ int rv; ++ int rv; + -+ rv = sshkey_verify(key, sig, slen, data, datalen, alg, compat); ++ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat); +#ifdef SSH_AUDIT_EVENTS -+ audit_key(1, &rv, key); ++ audit_key(ssh, 1, &rv, key); +#endif -+ return rv; ++ return rv; +} + static int match_principals_option(const char *principal_list, struct sshkey_cert *cert) { -@@ -773,7 +786,7 @@ user_cert_trusted_ca(struct ssh *ssh, st - found_principal = 1; - /* If principals file or command is specified, then require a match */ - use_authorized_principals = principals_file != NULL || -- options.authorized_principals_command != NULL; -+ options.authorized_principals_command != NULL; - if (!found_principal && use_authorized_principals) { - reason = "Certificate does not contain an authorized principal"; - goto fail_reason; -Index: openssh-7.9p1/auth2.c -=================================================================== ---- openssh-7.9p1.orig/auth2.c -+++ openssh-7.9p1/auth2.c -@@ -284,9 +284,6 @@ input_userauth_request(int type, u_int32 +diff --git a/auth2.c b/auth2.c +index 1c21726..e54509a 100644 +--- a/auth2.c ++++ b/auth2.c +@@ -293,9 +293,6 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) } else { /* Invalid user, fake password information */ authctxt->pw = fakepw(); -#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(SSH_INVALID_USER)); +- PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); -#endif } #ifdef USE_PAM if (options.use_pam) -Index: openssh-7.9p1/cipher.c -=================================================================== ---- openssh-7.9p1.orig/cipher.c -+++ openssh-7.9p1/cipher.c -@@ -54,25 +54,6 @@ - #include "fips.h" - #include "log.h" +diff --git a/cipher.c b/cipher.c +index b67a4ff..e0d23a5 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -58,25 +58,6 @@ + #define EVP_CIPHER_CTX void + #endif -struct sshcipher { - char *name; @@ -914,7 +898,7 @@ Index: openssh-7.9p1/cipher.c static const struct sshcipher ciphers_all[] = { #ifdef WITH_OPENSSL #ifndef OPENSSL_NO_DES -@@ -447,7 +428,7 @@ cipher_get_length(struct sshcipher_ctx * +@@ -451,7 +432,7 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, void cipher_free(struct sshcipher_ctx *cc) { @@ -923,11 +907,11 @@ Index: openssh-7.9p1/cipher.c return; if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) explicit_bzero(&cc->cp_ctx, sizeof(cc->cp_ctx)); -Index: openssh-7.9p1/cipher.h -=================================================================== ---- openssh-7.9p1.orig/cipher.h -+++ openssh-7.9p1/cipher.h -@@ -45,7 +45,25 @@ +diff --git a/cipher.h b/cipher.h +index d7d8c89..2341068 100644 +--- a/cipher.h ++++ b/cipher.h +@@ -47,7 +47,25 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 @@ -954,77 +938,103 @@ Index: openssh-7.9p1/cipher.h struct sshcipher_ctx { int plaintext; int encrypt; -Index: openssh-7.9p1/kex.c -=================================================================== ---- openssh-7.9p1.orig/kex.c -+++ openssh-7.9p1/kex.c -@@ -53,6 +53,7 @@ +diff --git a/kex.c b/kex.c +index 92d8ee0..96e44a5 100644 +--- a/kex.c ++++ b/kex.c +@@ -60,6 +60,7 @@ #include "ssherr.h" #include "sshbuf.h" #include "digest.h" +#include "audit.h" - #include "fips.h" + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -856,12 +857,16 @@ kex_start_rekex(struct ssh *ssh) + } -@@ -765,8 +766,12 @@ choose_enc(struct sshenc *enc, char *cli + static int +-choose_enc(struct sshenc *enc, char *client, char *server) ++choose_enc(struct ssh *ssh, struct sshenc *enc, char *client, char *server) { char *name = match_list(client, server, NULL); - if (name == NULL) + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_CIPHER); ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_CIPHER); +#endif return SSH_ERR_NO_CIPHER_ALG_MATCH; + } if ((enc->cipher = cipher_by_name(name)) == NULL) { + error("%s: unsupported cipher %s", __func__, name); free(name); - return SSH_ERR_INTERNAL_ERROR; -@@ -786,8 +791,12 @@ choose_mac(struct ssh *ssh, struct sshma +@@ -882,8 +887,12 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) { char *name = match_list(client, server, NULL); - if (name == NULL) -- return SSH_ERR_NO_MAC_ALG_MATCH; + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_MAC); ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_MAC); +#endif -+ return SSH_ERR_NO_MAC_ALG_MATCH; + return SSH_ERR_NO_MAC_ALG_MATCH; + } if (mac_setup(mac, name) < 0) { + error("%s: unsupported MAC %s", __func__, name); free(name); - return SSH_ERR_INTERNAL_ERROR; -@@ -803,8 +812,12 @@ choose_comp(struct sshcomp *comp, char * +@@ -896,12 +905,16 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) + } + + static int +-choose_comp(struct sshcomp *comp, char *client, char *server) ++choose_comp(struct ssh *ssh, struct sshcomp *comp, char *client, char *server) { char *name = match_list(client, server, NULL); - if (name == NULL) + if (name == NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(SSH_AUDIT_UNSUPPORTED_COMPRESSION); ++ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_COMPRESSION); +#endif return SSH_ERR_NO_COMPRESS_ALG_MATCH; + } if (strcmp(name, "zlib@openssh.com") == 0) { comp->type = COMP_DELAYED; } else if (strcmp(name, "zlib") == 0) { -@@ -974,6 +987,10 @@ kex_choose_conf(struct ssh *ssh) +@@ -1039,7 +1052,7 @@ kex_choose_conf(struct ssh *ssh) + nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; + nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; + ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; +- if ((r = choose_enc(&newkeys->enc, cprop[nenc], ++ if ((r = choose_enc(ssh, &newkeys->enc, cprop[nenc], + sprop[nenc])) != 0) { + kex->failed_choice = peer[nenc]; + peer[nenc] = NULL; +@@ -1054,7 +1067,7 @@ kex_choose_conf(struct ssh *ssh) + peer[nmac] = NULL; + goto out; + } +- if ((r = choose_comp(&newkeys->comp, cprop[ncomp], ++ if ((r = choose_comp(ssh, &newkeys->comp, cprop[ncomp], + sprop[ncomp])) != 0) { + kex->failed_choice = peer[ncomp]; + peer[ncomp] = NULL; +@@ -1077,6 +1090,10 @@ kex_choose_conf(struct ssh *ssh) dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); + debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); +#ifdef SSH_AUDIT_EVENTS -+ audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); ++ audit_kex(ssh, mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); +#endif } /* XXX need runden? */ kex->we_need = need; -@@ -1106,3 +1123,33 @@ dump_digest(char *msg, u_char *digest, i - sshbuf_dump_data(digest, len, stderr); +@@ -1241,6 +1258,36 @@ dump_digest(const char *msg, const u_char *digest, int len) } #endif -+ + +static void +enc_destroy(struct sshenc *enc) +{ @@ -1054,24 +1064,28 @@ Index: openssh-7.9p1/kex.c + mac_destroy(&newkeys->mac); + memset(&newkeys->comp, 0, sizeof(newkeys->comp)); +} -Index: openssh-7.9p1/kex.h -=================================================================== ---- openssh-7.9p1.orig/kex.h -+++ openssh-7.9p1/kex.h -@@ -213,6 +213,8 @@ int kexgss_client(struct ssh *); ++ + /* + * Send a plaintext error message to the peer, suffixed by \r\n. + * Only used during banner exchange, and there only for the server. +diff --git a/kex.h b/kex.h +index 4dc48fd..fdf0cf6 100644 +--- a/kex.h ++++ b/kex.h +@@ -226,6 +226,8 @@ int kexgss_client(struct ssh *); int kexgss_server(struct ssh *); #endif +void newkeys_destroy(struct newkeys *newkeys); + - int kex_dh_hash(int, const char *, const char *, - const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, - const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); -Index: openssh-7.9p1/mac.c -=================================================================== ---- openssh-7.9p1.orig/mac.c -+++ openssh-7.9p1/mac.c -@@ -280,6 +280,20 @@ mac_clear(struct sshmac *mac) + int kex_dh_keypair(struct kex *); + int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, + struct sshbuf **); +diff --git a/mac.c b/mac.c +index 90d71c8..6d87a80 100644 +--- a/mac.c ++++ b/mac.c +@@ -277,6 +277,20 @@ mac_clear(struct sshmac *mac) mac->umac_ctx = NULL; } @@ -1092,21 +1106,21 @@ Index: openssh-7.9p1/mac.c /* XXX copied from ciphers_valid */ #define MAC_SEP "," int -Index: openssh-7.9p1/mac.h -=================================================================== ---- openssh-7.9p1.orig/mac.h -+++ openssh-7.9p1/mac.h -@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int3 +diff --git a/mac.h b/mac.h +index 0b119d7..5fb593b 100644 +--- a/mac.h ++++ b/mac.h +@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t, const u_char *, size_t); void mac_clear(struct sshmac *); +void mac_destroy(struct sshmac *); #endif /* SSHMAC_H */ -Index: openssh-7.9p1/monitor.c -=================================================================== ---- openssh-7.9p1.orig/monitor.c -+++ openssh-7.9p1/monitor.c +diff --git a/monitor.c b/monitor.c +index 20812fa..2e421cf 100644 +--- a/monitor.c ++++ b/monitor.c @@ -93,6 +93,7 @@ #include "compat.h" #include "ssh2.h" @@ -1119,36 +1133,35 @@ Index: openssh-7.9p1/monitor.c extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ -+extern void destroy_sensitive_data(int); ++extern void destroy_sensitive_data(struct ssh *, int); + /* State exported from the child */ static struct sshbuf *child_state; -@@ -152,6 +155,11 @@ int mm_answer_gss_updatecreds(int, struc +@@ -154,6 +157,11 @@ int mm_answer_gss_updatecreds(struct ssh*, int, struct sshbuf *); #ifdef SSH_AUDIT_EVENTS - int mm_answer_audit_event(int, struct sshbuf *); - int mm_answer_audit_command(int, struct sshbuf *); -+int mm_answer_audit_end_command(int, struct sshbuf *); -+int mm_answer_audit_unsupported_body(int, struct sshbuf *); -+int mm_answer_audit_kex_body(int, struct sshbuf *); -+int mm_answer_audit_session_key_free_body(int, struct sshbuf *); -+int mm_answer_audit_server_key_free(int, struct sshbuf *); + int mm_answer_audit_event(struct ssh *, int, struct sshbuf *); + int mm_answer_audit_command(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_end_command(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_unsupported_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_kex_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_session_key_free_body(struct ssh *, int, struct sshbuf *); ++int mm_answer_audit_server_key_free(struct ssh *, int, struct sshbuf *); #endif - static int monitor_read_log(struct monitor *); -@@ -205,6 +213,11 @@ struct mon_table mon_dispatch_proto20[] + static Authctxt *authctxt; +@@ -209,6 +217,10 @@ struct mon_table mon_dispatch_proto20[] = { #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}\ -+, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, + {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif #ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -233,6 +246,11 @@ struct mon_table mon_dispatch_postauth20 +@@ -243,6 +255,11 @@ struct mon_table mon_dispatch_postauth20[] = { #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, @@ -1158,9 +1171,9 @@ Index: openssh-7.9p1/monitor.c + {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, + {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, #endif - #ifdef GSSAPI - {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, -@@ -1379,8 +1397,10 @@ mm_answer_keyverify(int sock, struct ssh + {0, 0, NULL} + }; +@@ -1408,8 +1425,10 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) char *sigalg; size_t signaturelen, datalen, bloblen; int r, ret, valid_data = 0, encoded_ret; @@ -1172,7 +1185,7 @@ Index: openssh-7.9p1/monitor.c (r = sshbuf_get_string(m, &signature, &signaturelen)) != 0 || (r = sshbuf_get_string(m, &data, &datalen)) != 0 || (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) -@@ -1389,6 +1409,8 @@ mm_answer_keyverify(int sock, struct ssh +@@ -1418,6 +1437,8 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) if (hostbased_cuser == NULL || hostbased_chost == NULL || !monitor_allowed_key(blob, bloblen)) fatal("%s: bad key, not previously allowed", __func__); @@ -1181,19 +1194,18 @@ Index: openssh-7.9p1/monitor.c /* Empty signature algorithm means NULL. */ if (*sigalg == '\0') { -@@ -1403,22 +1425,25 @@ mm_answer_keyverify(int sock, struct ssh - switch (key_blobtype) { +@@ -1433,21 +1454,24 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) case MM_USERKEY: valid_data = monitor_valid_userblob(data, datalen); -+ ret = user_key_verify(key, signature, signaturelen, data, -+ datalen, sigalg, active_state->compat); auth_method = "publickey"; ++ ret = user_key_verify(ssh, key, signature, signaturelen, data, ++ datalen, sigalg, ssh->compat); break; case MM_HOSTKEY: valid_data = monitor_valid_hostbasedblob(data, datalen, hostbased_cuser, hostbased_chost); -+ ret = hostbased_key_verify(key, signature, signaturelen, data, -+ datalen, sigalg, active_state->compat); ++ ret = hostbased_key_verify(ssh, key, signature, signaturelen, data, ++ datalen, sigalg, ssh->compat); auth_method = "hostbased"; break; default: @@ -1205,33 +1217,59 @@ Index: openssh-7.9p1/monitor.c fatal("%s: bad signature data blob", __func__); - ret = sshkey_verify(key, signature, signaturelen, data, datalen, -- sigalg, active_state->compat); +- sigalg, ssh->compat); debug3("%s: %s %p signature %s", __func__, auth_method, key, (ret == 0) ? "verified" : "unverified"); auth2_record_key(authctxt, ret == 0, key); -@@ -1478,6 +1503,12 @@ mm_session_close(Session *s) +@@ -1499,13 +1523,19 @@ mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw) + } + + static void +-mm_session_close(Session *s) ++mm_session_close(struct ssh *ssh, Session *s) + { + debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid); + if (s->ttyfd != -1) { debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); session_pty_cleanup2(s); } +#ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL) { -+ debug3("%s: command %d", __func__, s->command_handle); -+ session_end_command2(s); -+ } ++ if (s->command != NULL) { ++ debug3("%s: command %d", __func__, s->command_handle); ++ session_end_command2(ssh, s); ++ } +#endif session_unused(s->self); } -@@ -1586,6 +1617,8 @@ mm_answer_term(int sock, struct sshbuf * +@@ -1572,7 +1602,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) + + error: + if (s != NULL) +- mm_session_close(s); ++ mm_session_close(ssh, s); + if ((r = sshbuf_put_u32(m, 0)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + mm_request_send(sock, MONITOR_ANS_PTY, m); +@@ -1591,7 +1621,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, int sock, struct sshbuf *m) + if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if ((s = session_by_tty(tty)) != NULL) +- mm_session_close(s); ++ mm_session_close(ssh, s); + sshbuf_reset(m); + free(tty); + return (0); +@@ -1613,6 +1643,8 @@ mm_answer_term(struct ssh *ssh, int sock, struct sshbuf *req) sshpam_cleanup(); #endif -+ destroy_sensitive_data(0); ++ destroy_sensitive_data(ssh, 0); + while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) exit(1); -@@ -1632,14 +1665,50 @@ mm_answer_audit_command(int socket, stru +@@ -1659,12 +1691,47 @@ mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m) { char *cmd; int r; @@ -1243,57 +1281,52 @@ Index: openssh-7.9p1/monitor.c + /* sanity check command, if so how? */ - audit_run_command(cmd); -- free(cmd); -- return (0); + s = session_new(); + if (s == NULL) -+ fatal("%s: error allocating a session", __func__); ++ fatal("%s: error allocating a session", __func__); + s->command = cmd; +#ifdef SSH_AUDIT_EVENTS -+ s->command_handle = audit_run_command(cmd); ++ s->command_handle = audit_run_command(ssh, cmd); +#endif + -+ sshbuf_reset(m); -+ sshbuf_put_u32(m, s->self); ++ sshbuf_reset(m); ++ sshbuf_put_u32(m, s->self); + -+ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); ++ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); + -+ return (0); ++ return (0); +} + +int -+mm_answer_audit_end_command(int socket, struct sshbuf *m) ++mm_answer_audit_end_command(struct ssh *ssh, int socket, struct sshbuf *m) +{ -+ int handle, r; -+ size_t len; -+ u_char *cmd = NULL; -+ Session *s; ++ int handle, r; ++ size_t len; ++ u_char *cmd = NULL; ++ Session *s; + -+ debug3("%s entering", __func__); -+ if ((r = sshbuf_get_u32(m, &handle)) != 0 || -+ (r = sshbuf_get_string(m, &cmd, &len)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ debug3("%s entering", __func__); ++ if ((r = sshbuf_get_u32(m, &handle)) != 0 || ++ (r = sshbuf_get_string(m, &cmd, &len)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ s = session_by_id(handle); -+ if (s == NULL || s->ttyfd != -1 || s->command == NULL || -+ strcmp(s->command, cmd) != 0) -+ fatal("%s: invalid handle", __func__); -+ mm_session_close(s); -+ -+ free(cmd); -+ return (0); ++ s = session_by_id(handle); ++ if (s == NULL || s->ttyfd != -1 || s->command == NULL || ++ strcmp(s->command, cmd) != 0) ++ fatal("%s: invalid handle", __func__); ++ mm_session_close(ssh, s); + free(cmd); + return (0); } - #endif /* SSH_AUDIT_EVENTS */ - -@@ -1701,6 +1770,7 @@ monitor_apply_keystate(struct monitor *p +@@ -1730,6 +1797,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) void - mm_get_keystate(struct monitor *pmonitor) + mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) { + struct sshbuf *m; debug3("%s: Waiting for new keys", __func__); if ((child_state = sshbuf_new()) == NULL) -@@ -1708,6 +1778,19 @@ mm_get_keystate(struct monitor *pmonitor +@@ -1737,6 +1805,19 @@ mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, child_state); debug3("%s: GOT new keys", __func__); @@ -1302,7 +1335,7 @@ Index: openssh-7.9p1/monitor.c + m = sshbuf_new(); + mm_request_receive_expect(pmonitor->m_sendfd, + MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); -+ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, m); ++ mm_answer_audit_session_key_free_body(ssh, pmonitor->m_sendfd, m); + sshbuf_free(m); +#endif + @@ -1313,122 +1346,113 @@ Index: openssh-7.9p1/monitor.c } -@@ -1909,7 +1992,7 @@ mm_answer_gss_sign(int socket, struct ss - fatal("In GSSAPI monitor when GSSAPI is disabled"); - - if ((r = sshbuf_get_string(m, (u_char **)&data.value, &data.length)) != 0) -- fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - if (data.length != 20) - fatal("%s: data length incorrect: %d", __func__, - (int) data.length); -@@ -1966,3 +2049,102 @@ mm_answer_gss_updatecreds(int socket, st - } +@@ -2014,3 +2095,102 @@ mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) { #endif /* GSSAPI */ -+ + +#ifdef SSH_AUDIT_EVENTS +int -+mm_answer_audit_unsupported_body(int sock, struct sshbuf *m) ++mm_answer_audit_unsupported_body(struct ssh *ssh, int sock, struct sshbuf *m) +{ -+ int what, r; ++ int what, r; + -+ if ((r = sshbuf_get_u32(m, &what)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((r = sshbuf_get_u32(m, &what)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ audit_unsupported_body(what); ++ audit_unsupported_body(ssh, what); + -+ sshbuf_reset(m); ++ sshbuf_reset(m); + -+ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); -+ return 0; ++ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); ++ return 0; +} + +int -+mm_answer_audit_kex_body(int sock, struct sshbuf *m) ++mm_answer_audit_kex_body(struct ssh *ssh, int sock, struct sshbuf *m) +{ -+ int ctos, r; -+ char *cipher, *mac, *compress, *pfs; -+ u_int64_t tmp; -+ pid_t pid; -+ uid_t uid; ++ int ctos, r; ++ char *cipher, *mac, *compress, *pfs; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; + -+ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || -+ (r = sshbuf_get_cstring(m, &cipher, NULL)) != 0 || -+ (r = sshbuf_get_cstring(m, &mac, NULL)) != 0 || -+ (r = sshbuf_get_cstring(m, &compress, NULL)) != 0 || -+ (r = sshbuf_get_cstring(m, &pfs, NULL)) != 0 || -+ (r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ pid = (pid_t) tmp; -+ if ((r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ uid = (pid_t) tmp; ++ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || ++ (r = sshbuf_get_cstring(m, &cipher, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &mac, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &compress, NULL)) != 0 || ++ (r = sshbuf_get_cstring(m, &pfs, NULL)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ uid = (pid_t) tmp; + -+ audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); ++ audit_kex_body(ssh, ctos, cipher, mac, compress, pfs, pid, uid); + -+ free(cipher); -+ free(mac); -+ free(compress); -+ free(pfs); -+ sshbuf_reset(m); ++ free(cipher); ++ free(mac); ++ free(compress); ++ free(pfs); ++ sshbuf_reset(m); + -+ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); -+ return 0; ++ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); ++ return 0; +} + +int -+mm_answer_audit_session_key_free_body(int sock, struct sshbuf *m) ++mm_answer_audit_session_key_free_body(struct ssh *ssh, int sock, struct sshbuf *m) +{ -+ int ctos, r; -+ u_int64_t tmp; -+ pid_t pid; -+ uid_t uid; ++ int ctos, r; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; + -+ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || -+ (r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ pid = (pid_t) tmp; -+ if ((r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ uid = (uid_t) tmp; ++ if ((r = sshbuf_get_u32(m, &ctos)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ uid = (uid_t) tmp; + -+ audit_session_key_free_body(ctos, pid, uid); -+ sshbuf_reset(m); ++ audit_session_key_free_body(ssh, ctos, pid, uid); + -+ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); -+ return 0; ++ sshbuf_reset(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m); ++ return 0; +} + +int -+mm_answer_audit_server_key_free(int sock, struct sshbuf *m) ++mm_answer_audit_server_key_free(struct ssh *ssh, int sock, struct sshbuf *m) +{ -+ size_t len, r; -+ char *fp; -+ u_int64_t tmp; -+ pid_t pid; -+ uid_t uid; ++ size_t len, r; ++ char *fp; ++ u_int64_t tmp; ++ pid_t pid; ++ uid_t uid; + -+ if ((r = sshbuf_get_cstring(m, &fp, &len)) != 0 || -+ (r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ pid = (pid_t) tmp; -+ if ((r = sshbuf_get_u64(m, &tmp)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ uid = (uid_t) tmp; ++ if ((r = sshbuf_get_cstring(m, &fp, &len)) != 0 || ++ (r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ pid = (pid_t) tmp; ++ if ((r = sshbuf_get_u64(m, &tmp)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ uid = (uid_t) tmp; + -+ audit_destroy_sensitive_data(fp, pid, uid); ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); + -+ free(fp); -+ sshbuf_reset(m); ++ free(fp); ++ sshbuf_reset(m); + -+ return 0; ++ return 0; +} +#endif /* SSH_AUDIT_EVENTS */ -Index: openssh-7.9p1/monitor.h -=================================================================== ---- openssh-7.9p1.orig/monitor.h -+++ openssh-7.9p1/monitor.h +diff --git a/monitor.h b/monitor.h +index 2b1a2d5..7817990 100644 +--- a/monitor.h ++++ b/monitor.h @@ -61,7 +61,13 @@ enum monitor_reqtype { MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, @@ -1442,13 +1466,13 @@ Index: openssh-7.9p1/monitor.h + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, + MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, - MONITOR_REQ_GSSSIGN = 201, MONITOR_ANS_GSSSIGN = 202, - MONITOR_REQ_GSSUPCREDS = 203, MONITOR_ANS_GSSUPCREDS = 204, -Index: openssh-7.9p1/monitor_wrap.c -=================================================================== ---- openssh-7.9p1.orig/monitor_wrap.c -+++ openssh-7.9p1/monitor_wrap.c -@@ -497,7 +497,7 @@ mm_key_allowed(enum mm_keytype type, con + MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, + MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, +diff --git a/monitor_wrap.c b/monitor_wrap.c +index fdca39a..b427dd6 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -492,7 +492,7 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, */ int @@ -1457,11 +1481,8 @@ Index: openssh-7.9p1/monitor_wrap.c const u_char *data, size_t datalen, const char *sigalg, u_int compat) { struct sshbuf *m; -@@ -506,10 +506,10 @@ mm_sshkey_verify(const struct sshkey *ke +@@ -504,7 +504,8 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, - debug3("%s entering", __func__); - -- if ((m = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); - if ((r = sshkey_puts(key, m)) != 0 || @@ -1470,36 +1491,35 @@ Index: openssh-7.9p1/monitor_wrap.c (r = sshbuf_put_string(m, sig, siglen)) != 0 || (r = sshbuf_put_string(m, data, datalen)) != 0 || (r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0) -@@ -531,6 +531,22 @@ mm_sshkey_verify(const struct sshkey *ke +@@ -526,6 +527,20 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, return 0; } +int -+mm_hostbased_key_verify(const struct sshkey *key, const u_char *sig, size_t siglen, -+ const u_char *data, size_t datalen, const char *alg, u_int compat) ++mm_hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen, ++ const u_char *data, size_t datalen, const char *pkalg, u_int compat) +{ -+ return mm_sshkey_verify(MM_HOSTKEY, key, sig, siglen, data, datalen, -+ alg, compat); ++ return mm_sshkey_verify(MM_HOSTKEY, key, sig, siglen, data, datalen, pkalg, compat); +} + +int -+mm_user_key_verify(const struct sshkey *key, const u_char *sig, size_t siglen, -+ const u_char *data, size_t datalen, const char *alg, u_int compat) ++mm_user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen, ++ const u_char *data, size_t datalen, const char *pkalg, u_int compat) +{ -+ return mm_sshkey_verify(MM_USERKEY, key, sig, siglen, data, datalen, -+ alg, compat); ++ return mm_sshkey_verify(MM_USERKEY, key, sig, siglen, data, datalen, pkalg, compat); +} + void - mm_send_keystate(struct monitor *monitor) + mm_send_keystate(struct ssh *ssh, struct monitor *monitor) { -@@ -885,11 +901,12 @@ mm_audit_event(ssh_audit_event_t event) +@@ -879,11 +894,12 @@ mm_audit_event(struct ssh *ssh, ssh_audit_event_t event) sshbuf_free(m); } -void +-mm_audit_run_command(const char *command) +int - mm_audit_run_command(const char *command) ++mm_audit_run_command(struct ssh *ssh, const char *command) { struct sshbuf *m; int r; @@ -1507,166 +1527,163 @@ Index: openssh-7.9p1/monitor_wrap.c debug3("%s entering command %s", __func__, command); -@@ -899,7 +916,31 @@ mm_audit_run_command(const char *command +@@ -893,6 +909,30 @@ mm_audit_run_command(const char *command) fatal("%s: buffer error: %s", __func__, ssh_err(r)); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m); -- sshbuf_free(m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m); + -+ if ((r = sshbuf_get_u32(m, &handle)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ sshbuf_free(m); ++ if ((r = sshbuf_get_u32(m, &handle)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ sshbuf_free(m); + -+ return (handle); ++ return (handle); +} + +void -+mm_audit_end_command(int handle, const char *command) ++mm_audit_end_command(struct ssh *ssh, int handle, const char *command) +{ -+ int r; -+ struct sshbuf *m; ++ int r; ++ struct sshbuf *m; + -+ debug3("%s entering command %s", __func__, command); ++ debug3("%s entering command %s", __func__, command); + -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(m, handle)) != 0 || -+ (r = sshbuf_put_cstring(m, command)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(m, handle)) != 0 || ++ (r = sshbuf_put_cstring(m, command)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, m); -+ sshbuf_free(m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, m); + sshbuf_free(m); } #endif /* SSH_AUDIT_EVENTS */ - -@@ -1052,3 +1093,84 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc - return (ok); +@@ -1053,3 +1093,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) } + #endif /* GSSAPI */ -+ +#ifdef SSH_AUDIT_EVENTS +void -+mm_audit_unsupported_body(int what) ++mm_audit_unsupported_body(struct ssh *ssh, int what) +{ -+ int r; -+ struct sshbuf *m; ++ int r; ++ struct sshbuf *m; + -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(m, what)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(m, what)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, -+ m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, ++ m); + -+ sshbuf_free(m); ++ sshbuf_free(m); +} + +void -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, -+ uid_t uid) ++mm_audit_kex_body(struct ssh *ssh, int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, ++ uid_t uid) +{ -+ int r; -+ struct sshbuf *m; ++ int r; ++ struct sshbuf *m; + -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(m, ctos)) != 0 || -+ (r = sshbuf_put_cstring(m, cipher)) != 0 || -+ (r = sshbuf_put_cstring(m, (mac ? mac : ""))) != 0 || -+ (r = sshbuf_put_cstring(m, compress)) != 0 || -+ (r = sshbuf_put_cstring(m, fps)) != 0 || -+ (r = sshbuf_put_u64(m, pid)) != 0 || -+ (r = sshbuf_put_u64(m, uid)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(m, ctos)) != 0 || ++ (r = sshbuf_put_cstring(m, cipher)) != 0 || ++ (r = sshbuf_put_cstring(m, (mac ? mac : ""))) != 0 || ++ (r = sshbuf_put_cstring(m, compress)) != 0 || ++ (r = sshbuf_put_cstring(m, fps)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, -+ m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, ++ m); + -+ sshbuf_free(m); ++ sshbuf_free(m); +} + +void -+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++mm_audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) +{ -+ int r; -+ struct sshbuf *m; ++ int r; ++ struct sshbuf *m; + -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_u32(m, ctos)) != 0 || -+ (r = sshbuf_put_u64(m, pid)) != 0 || -+ (r = sshbuf_put_u64(m, uid)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(m, ctos)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, -+ m); -+ sshbuf_free(m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, ++ m); ++ sshbuf_free(m); +} + +void -+mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) +{ -+ int r; -+ struct sshbuf *m; ++ int r; ++ struct sshbuf *m; + -+ if ((m = sshbuf_new()) == NULL) -+ fatal("%s: sshbuf_new failed", __func__); -+ if ((r = sshbuf_put_cstring(m, fp)) != 0 || -+ (r = sshbuf_put_u64(m, pid)) != 0 || -+ (r = sshbuf_put_u64(m, uid)) != 0) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_cstring(m, fp)) != 0 || ++ (r = sshbuf_put_u64(m, pid)) != 0 || ++ (r = sshbuf_put_u64(m, uid)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); -+ sshbuf_free(m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); ++ sshbuf_free(m); +} +#endif /* SSH_AUDIT_EVENTS */ -Index: openssh-7.9p1/monitor_wrap.h -=================================================================== ---- openssh-7.9p1.orig/monitor_wrap.h -+++ openssh-7.9p1/monitor_wrap.h -@@ -53,7 +53,9 @@ int mm_user_key_allowed(struct ssh *, st +diff --git a/monitor_wrap.h b/monitor_wrap.h +index 92dda57..d413dac 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -56,7 +56,9 @@ int mm_user_key_allowed(struct ssh *, struct passwd *, struct sshkey *, int, struct sshauthopt **); - int mm_hostbased_key_allowed(struct passwd *, const char *, + int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *, const char *, struct sshkey *); -int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, -+int mm_hostbased_key_verify(const struct sshkey *, const u_char *, size_t, ++int mm_hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, + const u_char *, size_t, const char *, u_int); -+int mm_user_key_verify(const struct sshkey *, const u_char *, size_t, ++int mm_user_key_verify(struct ssh*, const struct sshkey *, const u_char *, size_t, const u_char *, size_t, const char *, u_int); #ifdef GSSAPI -@@ -78,7 +80,12 @@ void mm_sshpam_free_ctx(void *); +@@ -81,7 +83,12 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" - void mm_audit_event(ssh_audit_event_t); + void mm_audit_event(struct ssh *, ssh_audit_event_t); -void mm_audit_run_command(const char *); -+int mm_audit_run_command(const char *); -+void mm_audit_end_command(int, const char *); -+void mm_audit_unsupported_body(int); -+void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); -+void mm_audit_session_key_free_body(int, pid_t, uid_t); -+void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); ++int mm_audit_run_command(struct ssh *ssh, const char *); ++void mm_audit_end_command(struct ssh *ssh, int, const char *); ++void mm_audit_unsupported_body(struct ssh *, int); ++void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t); ++void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); #endif struct Session; -Index: openssh-7.9p1/packet.c -=================================================================== ---- openssh-7.9p1.orig/packet.c -+++ openssh-7.9p1/packet.c -@@ -76,6 +76,7 @@ +diff --git a/packet.c b/packet.c +index 817da43..aec02e4 100644 +--- a/packet.c ++++ b/packet.c +@@ -77,6 +77,7 @@ #include #include "xmalloc.h" +#include "audit.h" - #include "crc32.h" #include "compat.h" #include "ssh2.h" -@@ -506,6 +507,13 @@ ssh_packet_get_connection_out(struct ssh + #include "cipher.h" +@@ -509,6 +510,13 @@ ssh_packet_get_connection_out(struct ssh *ssh) return ssh->state->connection_out; } @@ -1680,7 +1697,7 @@ Index: openssh-7.9p1/packet.c /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. -@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss +@@ -586,22 +594,19 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) { struct session_state *state = ssh->state; u_int mode; @@ -1708,14 +1725,14 @@ Index: openssh-7.9p1/packet.c for (mode = 0; mode < MODE_MAX; mode++) { kex_free_newkeys(state->newkeys[mode]); /* current keys */ state->newkeys[mode] = NULL; -@@ -632,8 +637,18 @@ ssh_packet_close_internal(struct ssh *ss +@@ -635,8 +640,18 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) } cipher_free(state->send_context); cipher_free(state->receive_context); + if (had_keys && state->server_side) { -+ /* Assuming this is called only from privsep child */ -+ audit_session_key_free(MODE_MAX); -+ } ++ /* Assuming this is called only from privsep child */ ++ audit_session_key_free(ssh, MODE_MAX); ++ } state->send_context = state->receive_context = NULL; if (do_close) { + if (state->connection_in == state->connection_out) { @@ -1727,24 +1744,15 @@ Index: openssh-7.9p1/packet.c free(ssh->local_ipaddr); ssh->local_ipaddr = NULL; free(ssh->remote_ipaddr); -@@ -858,6 +873,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod - (unsigned long long)state->p_read.blocks, +@@ -863,6 +878,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode) (unsigned long long)state->p_send.bytes, (unsigned long long)state->p_send.blocks); -+ audit_session_key_free(mode); - cipher_free(*ccp); - *ccp = NULL; kex_free_newkeys(state->newkeys[mode]); -@@ -952,7 +968,7 @@ ssh_packet_need_rekeying(struct ssh *ssh - return 1; - - /* -- * Always rekey when MAX_PACKETS sent in either direction -+ * Always rekey when MAX_PACKETS sent in either direction - * As per RFC4344 section 3.1 we do this after 2^31 packets. - */ - if (state->p_send.packets > MAX_PACKETS || -@@ -2143,6 +2159,72 @@ ssh_packet_get_output(struct ssh *ssh) ++ audit_session_key_free(ssh, mode); + state->newkeys[mode] = NULL; + } + /* note that both bytes and the seqnr are not reset */ +@@ -2166,6 +2182,71 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1770,77 +1778,76 @@ Index: openssh-7.9p1/packet.c +static void +packet_destroy_state(struct session_state *state) +{ -+ if (state == NULL) -+ return; ++ if (state == NULL) ++ return; + -+ cipher_free(state->receive_context); -+ cipher_free(state->send_context); ++ cipher_free(state->receive_context); ++ cipher_free(state->send_context); + -+ sshbuf_free(state->input); -+ state->input = NULL; -+ sshbuf_free(state->output); -+ state->output = NULL; -+ sshbuf_free(state->outgoing_packet); -+ state->outgoing_packet = NULL; -+ sshbuf_free(state->incoming_packet); -+ state->incoming_packet = NULL; -+ if (state->compression_buffer) { -+ sshbuf_free(state->compression_buffer); -+ state->compression_buffer = NULL; -+ } -+ newkeys_destroy_and_free(state->newkeys[MODE_IN]); -+ state->newkeys[MODE_IN] = NULL; -+ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); -+ state->newkeys[MODE_OUT] = NULL; -+ mac_destroy(state->packet_discard_mac); -+// TAILQ_HEAD(, packet) outgoing; -+// memset(state, 0, sizeof(state)); ++ sshbuf_free(state->input); ++ state->input = NULL; ++ sshbuf_free(state->output); ++ state->output = NULL; ++ sshbuf_free(state->outgoing_packet); ++ state->outgoing_packet = NULL; ++ sshbuf_free(state->incoming_packet); ++ state->incoming_packet = NULL; ++ if (state->compression_buffer) { ++ sshbuf_free(state->compression_buffer); ++ state->compression_buffer = NULL; ++ } ++ newkeys_destroy_and_free(state->newkeys[MODE_IN]); ++ state->newkeys[MODE_IN] = NULL; ++ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); ++ state->newkeys[MODE_OUT] = NULL; ++ mac_destroy(state->packet_discard_mac); ++// TAILQ_HEAD(, packet) outgoing; ++// memset(state, 0, sizeof(state)); +} + +void -+packet_destroy_all(int audit_it, int privsep) ++packet_destroy_all(struct ssh *ssh, int audit_it, int privsep) +{ -+ if (audit_it) -+ audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)); -+ if (active_state != NULL) -+ packet_destroy_state(active_state->state); -+ if (audit_it) { ++ if (audit_it) ++ audit_it = packet_state_has_keys(ssh->state); ++ packet_destroy_state(ssh->state); ++ if (audit_it) { +#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ audit_session_key_free(MODE_MAX); -+ else -+ audit_session_key_free_body(MODE_MAX, getpid(), getuid()); ++ if (privsep) ++ audit_session_key_free(ssh, MODE_MAX); ++ else ++ audit_session_key_free_body(ssh, MODE_MAX, getpid(), getuid()); +#endif -+ } ++ } +} + /* Reset after_authentication and reset compression in post-auth privsep */ static int ssh_packet_set_postauth(struct ssh *ssh) -Index: openssh-7.9p1/packet.h -=================================================================== ---- openssh-7.9p1.orig/packet.h -+++ openssh-7.9p1/packet.h -@@ -219,4 +219,5 @@ extern struct ssh *active_state; +diff --git a/packet.h b/packet.h +index 8ccfd2e..cfd9ebe 100644 +--- a/packet.h ++++ b/packet.h +@@ -217,4 +217,5 @@ const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); # undef EC_POINT #endif -+void packet_destroy_all(int, int); ++void packet_destroy_all(struct ssh *, int, int); #endif /* PACKET_H */ -Index: openssh-7.9p1/session.c -=================================================================== ---- openssh-7.9p1.orig/session.c -+++ openssh-7.9p1/session.c -@@ -139,7 +139,7 @@ extern char *__progname; +diff --git a/session.c b/session.c +index 89f9539..07411f3 100644 +--- a/session.c ++++ b/session.c +@@ -136,7 +136,7 @@ extern char *__progname; extern int debug_flag; extern u_int utmp_len; extern int startup_pipe; -extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(int); ++extern void destroy_sensitive_data(struct ssh *, int); extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; - char *tun_fwd_ifnames; /* serverloop.c */ -@@ -648,6 +648,14 @@ do_exec_pty(struct ssh *ssh, Session *s, + extern char *tun_fwd_ifnames; /* serverloop.c */ +@@ -647,6 +647,14 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); @@ -1854,8 +1861,8 @@ Index: openssh-7.9p1/session.c + /* Enter interactive session. */ s->ptymaster = ptymaster; - packet_set_interactive(1, -@@ -741,15 +749,19 @@ do_exec(struct ssh *ssh, Session *s, con + ssh_packet_set_interactive(ssh, 1, +@@ -711,15 +719,19 @@ do_exec(struct ssh *ssh, Session *s, const char *command) s->self); #ifdef SSH_AUDIT_EVENTS @@ -1873,24 +1880,24 @@ Index: openssh-7.9p1/session.c + s->command = xstrdup(shell); } + if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = PRIVSEP(audit_run_command(s->command)); ++ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -1553,8 +1565,11 @@ do_child(struct ssh *ssh, Session *s, co - int r = 0; +@@ -1531,8 +1543,11 @@ do_child(struct ssh *ssh, Session *s, const char *command) + sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); /* remove hostkey from the child's memory */ - destroy_sensitive_data(); -+ destroy_sensitive_data(1); - packet_clear_keys(); ++ destroy_sensitive_data(ssh, 1); + ssh_packet_clear_keys(ssh); + /* Don't audit this - both us and the parent would be talking to the + monitor over a single socket, with no synchronization. */ -+ packet_destroy_all(0, 1); ++ packet_destroy_all(ssh, 0, 1); /* Force a password change */ if (s->authctxt->force_pwchange) { -@@ -1761,6 +1776,9 @@ session_unused(int id) +@@ -1741,6 +1756,9 @@ session_unused(int id) sessions[id].ttyfd = -1; sessions[id].ptymaster = -1; sessions[id].x11_chanids = NULL; @@ -1900,10 +1907,11 @@ Index: openssh-7.9p1/session.c sessions[id].next_unused = sessions_first_unused; sessions_first_unused = id; } -@@ -1843,6 +1861,19 @@ session_open(Authctxt *authctxt, int cha +@@ -1822,6 +1840,19 @@ session_open(Authctxt *authctxt, int chanid) + return 1; } - Session * ++Session * +session_by_id(int id) +{ + if (id >= 0 && id < sessions_nalloc) { @@ -1916,21 +1924,20 @@ Index: openssh-7.9p1/session.c + return NULL; +} + -+Session * + Session * session_by_tty(char *tty) { - int i; -@@ -2428,6 +2459,32 @@ session_exit_message(struct ssh *ssh, Se +@@ -2433,6 +2464,32 @@ session_exit_message(struct ssh *ssh, Session *s, int status) chan_write_failed(ssh, c); } +#ifdef SSH_AUDIT_EVENTS +void -+session_end_command2(Session *s) ++session_end_command2(struct ssh *ssh, Session *s) +{ + if (s->command != NULL) { + if (s->command_handle != -1) -+ audit_end_command(s->command_handle, s->command); ++ audit_end_command(ssh, s->command_handle, s->command); + free(s->command); + s->command = NULL; + s->command_handle = -1; @@ -1938,11 +1945,11 @@ Index: openssh-7.9p1/session.c +} + +static void -+session_end_command(Session *s) ++session_end_command(struct ssh *ssh, Session *s) +{ + if (s->command != NULL) { + if (s->command_handle != -1) -+ PRIVSEP(audit_end_command(s->command_handle, s->command)); ++ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command)); + free(s->command); + s->command = NULL; + s->command_handle = -1; @@ -1953,34 +1960,51 @@ Index: openssh-7.9p1/session.c void session_close(struct ssh *ssh, Session *s) { -@@ -2469,6 +2526,10 @@ session_close(struct ssh *ssh, Session * +@@ -2474,6 +2531,10 @@ session_close(struct ssh *ssh, Session *s) if (s->ttyfd != -1) session_pty_cleanup(s); +#ifdef SSH_AUDIT_EVENTS + if (s->command) -+ session_end_command(s); ++ session_end_command(ssh, s); +#endif free(s->term); free(s->display); free(s->x11_chanids); -@@ -2677,6 +2738,15 @@ do_authenticated2(struct ssh *ssh, Authc +@@ -2549,14 +2610,14 @@ session_close_by_channel(struct ssh *ssh, int id, void *arg) + } + + void +-session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *)) ++session_destroy_all(struct ssh *ssh, void (*closefunc)(struct ssh *ssh, Session *)) + { + int i; + for (i = 0; i < sessions_nalloc; i++) { + Session *s = &sessions[i]; + if (s->used) { + if (closefunc != NULL) +- closefunc(s); ++ closefunc(ssh, s); + else + session_close(ssh, s); + } +@@ -2682,6 +2743,15 @@ do_authenticated2(struct ssh *ssh, Authctxt *authctxt) server_loop2(ssh, authctxt); } +static void -+do_cleanup_one_session(Session *s) ++do_cleanup_one_session(struct ssh *ssh, Session *s) +{ + session_pty_cleanup2(s); +#ifdef SSH_AUDIT_EVENTS -+ session_end_command2(s); ++ session_end_command2(ssh, s); +#endif +} + void do_cleanup(struct ssh *ssh, Authctxt *authctxt) { -@@ -2734,7 +2804,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au +@@ -2745,7 +2815,7 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) * or if running in monitor. */ if (!use_privsep || mm_is_monitor()) @@ -1989,10 +2013,10 @@ Index: openssh-7.9p1/session.c } /* Return a name for the remote host that fits inside utmp_size */ -Index: openssh-7.9p1/session.h -=================================================================== ---- openssh-7.9p1.orig/session.h -+++ openssh-7.9p1/session.h +diff --git a/session.h b/session.h +index ce59dab..bcd4b1d 100644 +--- a/session.h ++++ b/session.h @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2006,21 +2030,24 @@ Index: openssh-7.9p1/session.h }; void do_authenticated(struct ssh *, Authctxt *); -@@ -73,8 +79,10 @@ void session_close_by_pid(struct ssh *s +@@ -71,10 +77,12 @@ void session_unused(int); + int session_input_channel_req(struct ssh *, Channel *, const char *); + void session_close_by_pid(struct ssh *ssh, pid_t, int); void session_close_by_channel(struct ssh *, int, void *); - void session_destroy_all(struct ssh *, void (*)(Session *)); +-void session_destroy_all(struct ssh *, void (*)(Session *)); ++void session_destroy_all(struct ssh *, void (*)(struct ssh*, Session *)); void session_pty_cleanup2(Session *); -+void session_end_command2(Session *); ++void session_end_command2(struct ssh *ssh, Session *); Session *session_new(void); +Session *session_by_id(int); Session *session_by_tty(char *); void session_close(struct ssh *, Session *); void do_setusercontext(struct passwd *); -Index: openssh-7.9p1/sshd.c -=================================================================== ---- openssh-7.9p1.orig/sshd.c -+++ openssh-7.9p1/sshd.c +diff --git a/sshd.c b/sshd.c +index 0d5c4c4..dca7b1e 100644 +--- a/sshd.c ++++ b/sshd.c @@ -124,6 +124,7 @@ #include "ssh-gss.h" #endif @@ -2029,16 +2056,18 @@ Index: openssh-7.9p1/sshd.c #include "ssh-sandbox.h" #include "auth-options.h" #include "version.h" -@@ -265,7 +266,7 @@ struct sshbuf *loginmsg; +@@ -272,8 +273,8 @@ struct sshbuf *loginmsg; struct passwd *privsep_pw = NULL; /* Prototypes for various functions defined later in this file. */ -void destroy_sensitive_data(void); -+void destroy_sensitive_data(int); - void demote_sensitive_data(void); - static void do_ssh2_kex(void); +-void demote_sensitive_data(void); ++void destroy_sensitive_data(struct ssh *, int); ++void demote_sensitive_data(struct ssh *); + static void do_ssh2_kex(struct ssh *); -@@ -282,6 +283,15 @@ close_listen_socks(void) + /* +@@ -289,6 +290,15 @@ close_listen_socks(void) num_listen_socks = -1; } @@ -2048,14 +2077,14 @@ Index: openssh-7.9p1/sshd.c + */ +int listening_for_clients(void) +{ -+ return num_listen_socks >= 0; ++ return num_listen_socks >= 0; +} + static void close_startup_pipes(void) { -@@ -488,18 +498,46 @@ sshd_exchange_identification(struct ssh - } +@@ -395,18 +405,45 @@ grace_alarm_handler(int sig) + ssh_remote_port(the_active_state)); } -/* Destroy the host and server keys. They will no longer be needed. */ @@ -2065,36 +2094,34 @@ Index: openssh-7.9p1/sshd.c + */ void -destroy_sensitive_data(void) -+destroy_sensitive_data(int privsep) ++destroy_sensitive_data(struct ssh *ssh, int privsep) { u_int i; +#ifdef SSH_AUDIT_EVENTS -+ pid_t pid; -+ uid_t uid; -+ -+ pid = getpid(); -+ uid = getuid(); -+#endif ++ pid_t pid; ++ uid_t uid; ++ pid = getpid(); ++ uid = getuid(); ++#endif for (i = 0; i < options.num_host_key_files; i++) { if (sensitive_data.host_keys[i]) { -- sshkey_free(sensitive_data.host_keys[i]); + char *fp; + + if (sshkey_is_private(sensitive_data.host_keys[i])) + fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); -+ else ++ else + fp = NULL; -+ sshkey_free(sensitive_data.host_keys[i]); + sshkey_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS + if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(fp, -+ pid, uid)); ++ PRIVSEP(audit_destroy_sensitive_data(ssh, fp, ++ pid, uid)); + else -+ audit_destroy_sensitive_data(fp, -+ pid, uid); ++ audit_destroy_sensitive_data(ssh, fp, ++ pid, uid); +#endif + free(fp); + } @@ -2105,42 +2132,66 @@ Index: openssh-7.9p1/sshd.c sshkey_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } -@@ -513,8 +551,21 @@ demote_sensitive_data(void) +@@ -415,14 +452,26 @@ destroy_sensitive_data(void) + + /* Demote private to public keys for network child */ + void +-demote_sensitive_data(void) ++demote_sensitive_data(struct ssh *ssh) + { struct sshkey *tmp; u_int i; int r; +#ifdef SSH_AUDIT_EVENTS + pid_t pid; + uid_t uid; -+ + + pid = getpid(); + uid = getuid(); +#endif - for (i = 0; i < options.num_host_key_files; i++) { -+ char *fp; -+ -+ if (sshkey_is_private(sensitive_data.host_keys[i])) -+ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); -+ else -+ fp = NULL; if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (sshkey_is_private(sensitive_data.host_keys[i])) ++ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); ++ else ++ fp = NULL; if ((r = sshkey_from_private( sensitive_data.host_keys[i], &tmp)) != 0) -@@ -523,6 +574,12 @@ demote_sensitive_data(void) + fatal("could not demote host %s key: %s", +@@ -430,6 +479,12 @@ demote_sensitive_data(void) ssh_err(r)); sshkey_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = tmp; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_destroy_sensitive_data(fp, pid, uid); ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); +#endif -+ free(fp); -+ } ++ free(fp); ++ } } /* Certs do not need demotion */ } -@@ -601,7 +658,7 @@ privsep_preauth(Authctxt *authctxt) +@@ -457,7 +512,7 @@ reseed_prngs(void) + } + + static void +-privsep_preauth_child(void) ++privsep_preauth_child(struct ssh *ssh) + { + gid_t gidset[1]; + +@@ -472,7 +527,7 @@ privsep_preauth_child(void) + reseed_prngs(); + + /* Demote the private keys to public keys. */ +- demote_sensitive_data(); ++ demote_sensitive_data(ssh); + + /* Demote the child */ + if (privsep_chroot) { +@@ -507,7 +562,7 @@ privsep_preauth(struct ssh *ssh) if (use_privsep == PRIVSEP_ON) box = ssh_sandbox_init(pmonitor); @@ -2149,28 +2200,64 @@ Index: openssh-7.9p1/sshd.c if (pid == -1) { fatal("fork of unprivileged child failed"); } else if (pid != 0) { -@@ -1198,6 +1255,7 @@ server_accept_loop(int *sock_in, int *so +@@ -553,7 +608,7 @@ privsep_preauth(struct ssh *ssh) + /* Arrange for logging to be sent to the monitor */ + set_log_handler(mm_log_handler, pmonitor); + +- privsep_preauth_child(); ++ privsep_preauth_child(ssh); + setproctitle("%s", "[net]"); + if (box != NULL) + ssh_sandbox_child(box); +@@ -597,7 +652,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) + pmonitor->m_sendfd = -1; + + /* Demote the private keys to public keys. */ +- demote_sensitive_data(); ++ demote_sensitive_data(ssh); + + reseed_prngs(); + +@@ -1060,7 +1115,7 @@ server_listen(void) + * from this function are in a forked subprocess. + */ + static void +-server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) ++server_accept_loop(struct ssh *ssh, int *sock_in, int *sock_out, int *newsock, int *config_s) + { + fd_set *fdset; + int i, j, ret, maxfd; +@@ -1115,6 +1170,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) if (received_sigterm) { logit("Received signal %d; terminating.", (int) received_sigterm); -+ destroy_sensitive_data(0); ++ destroy_sensitive_data(ssh, 0); close_listen_socks(); if (options.pid_file != NULL) unlink(options.pid_file); -@@ -2362,6 +2420,9 @@ main(int ac, char **av) +@@ -1973,7 +2029,7 @@ main(int ac, char **av) + #endif + + /* Accept a connection and return in a forked child */ +- server_accept_loop(&sock_in, &sock_out, ++ server_accept_loop(ssh, &sock_in, &sock_out, + &newsock, config_s); + } + +@@ -2212,6 +2268,9 @@ main(int ac, char **av) do_authenticated(ssh, authctxt); /* The connection has been terminated. */ -+ packet_destroy_all(1, 1); -+ destroy_sensitive_data(1); ++ packet_destroy_all(ssh, 1, 1); ++ destroy_sensitive_data(ssh, 1); + - packet_get_bytes(&ibytes, &obytes); + ssh_packet_get_bytes(ssh, &ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); -@@ -2532,6 +2593,15 @@ void +@@ -2393,6 +2452,15 @@ do_ssh2_kex(struct ssh *ssh) + void cleanup_exit(int i) { - struct ssh *ssh = active_state; /* XXX */ + static int in_cleanup = 0; + int is_privsep_child; + @@ -2180,77 +2267,79 @@ Index: openssh-7.9p1/sshd.c + if (in_cleanup) + _exit(i); + in_cleanup = 1; - - if (the_authctxt) { - do_cleanup(ssh, the_authctxt); -@@ -2544,9 +2614,14 @@ cleanup_exit(int i) + if (the_active_state != NULL && the_authctxt != NULL) { + do_cleanup(the_active_state, the_authctxt); + if (use_privsep && privsep_is_preauth && +@@ -2404,9 +2472,16 @@ cleanup_exit(int i) pmonitor->m_pid, strerror(errno)); } } + is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL) -+ destroy_sensitive_data(is_privsep_child); -+ packet_destroy_all(1, is_privsep_child); ++ if (sensitive_data.host_keys != NULL && the_active_state != NULL) ++ destroy_sensitive_data(the_active_state, is_privsep_child); ++ if (the_active_state != NULL) ++ packet_destroy_all(the_active_state, 1, is_privsep_child); #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (!use_privsep || mm_is_monitor()) -+ if ((the_authctxt == NULL || !the_authctxt->authenticated) && +- if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) ++ if (the_active_state != NULL && ++ (the_authctxt == NULL || !the_authctxt->authenticated) && + (!use_privsep || mm_is_monitor())) - audit_event(SSH_CONNECTION_ABANDON); + audit_event(the_active_state, SSH_CONNECTION_ABANDON); #endif _exit(i); -Index: openssh-7.9p1/sshkey.h -=================================================================== ---- openssh-7.9p1.orig/sshkey.h -+++ openssh-7.9p1/sshkey.h -@@ -147,6 +147,7 @@ u_int sshkey_size(const struct sshkey - int sshkey_generate(int type, u_int bits, struct sshkey **keyp); - int sshkey_from_private(const struct sshkey *, struct sshkey **); +diff --git a/sshkey.c b/sshkey.c +index 4d2048b..142dc09 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -340,6 +340,38 @@ sshkey_type_is_valid_ca(int type) + } + } + ++int ++sshkey_is_private(const struct sshkey *k) ++{ ++ switch (k->type) { ++#ifdef WITH_OPENSSL ++ case KEY_RSA_CERT: ++ case KEY_RSA: { ++ const BIGNUM *d; ++ RSA_get0_key(k->rsa, NULL, NULL, &d); ++ return d != NULL; ++ } ++ case KEY_DSA_CERT: ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: ++ return EC_KEY_get0_private_key(k->ecdsa) != NULL; ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } ++} ++ + int + sshkey_is_cert(const struct sshkey *k) + { +diff --git a/sshkey.h b/sshkey.h +index 1bf30d0..065ef0b 100644 +--- a/sshkey.h ++++ b/sshkey.h +@@ -164,6 +164,7 @@ int sshkey_shield_private(struct sshkey *); + int sshkey_unshield_private(struct sshkey *); + int sshkey_type_from_name(const char *); +int sshkey_is_private(const struct sshkey *); int sshkey_is_cert(const struct sshkey *); int sshkey_type_is_cert(int); int sshkey_type_plain(int); -Index: openssh-7.9p1/sshkey.c -=================================================================== ---- openssh-7.9p1.orig/sshkey.c -+++ openssh-7.9p1/sshkey.c -@@ -331,6 +331,38 @@ sshkey_type_is_valid_ca(int type) - } - - int -+sshkey_is_private(const struct sshkey *k) -+{ -+ switch (k->type) { -+#ifdef WITH_OPENSSL -+ case KEY_RSA_CERT: -+ case KEY_RSA: { -+ const BIGNUM *d; -+ RSA_get0_key(k->rsa, NULL, NULL, &d); -+ return d != NULL; -+ } -+ case KEY_DSA_CERT: -+ case KEY_DSA: { -+ const BIGNUM *priv_key; -+ DSA_get0_key(k->dsa, NULL, &priv_key); -+ return priv_key != NULL; -+ } -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif /* OPENSSL_HAS_ECC */ -+#endif /* WITH_OPENSSL */ -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ /* fatal("key_is_private: bad key type %d", k->type); */ -+ return 0; -+ } -+} -+ -+int - sshkey_is_cert(const struct sshkey *k) - { - if (k == NULL) diff --git a/openssh-8.1p1.tar.gz b/openssh-8.1p1.tar.gz new file mode 100644 index 0000000..4bb509b --- /dev/null +++ b/openssh-8.1p1.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02f5dbef3835d0753556f973cd57b4c19b6b1f6cd24c03445e23ac77ca1b93ff +size 1625894 diff --git a/openssh-8.1p1.tar.gz.asc b/openssh-8.1p1.tar.gz.asc new file mode 100644 index 0000000..e70fa8a --- /dev/null +++ b/openssh-8.1p1.tar.gz.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNATURE----- + +iQHDBAABCgAdFiEEWcIRjtIG2SfmZ+vj0+X1a22SDTAFAl2dLEgACgkQ0+X1a22S +DTAcUgx7BcRCaH7fb0AeQGvIrxXlyeN3uL6HOyo8MKkryN+y9zpvpcU6T8FBjtoh +zgjonewzodGj+C1ma0O9TgIfnUxdOVL+eQsPYgOWLJt2MzSnY/Ru+20J5ZGwGc+5 +pJcuV+xlAuwae/EL+Pk86CdQ0D6zaf9NBHGTNmrswwhT9B3UWSCbEmmc8jm0DChm +F5+dW1nK0n6YSQ9dVUH17/ujvego5WQkOiaSxjaK29/xS39BD6jrbwfFpL3/iKru +mWVzcNJaX5WL3ZUnyZRcIHzVpBdr2n0pLCnmqIT8LGPwI3razEbZKIDXf+q0ZA88 +wRfCL9aEVWjhG+v56c/NiM/wD3h3A4uh8fZeeeyP3hmgEv8Wp8g7fFxf5MaEJlGL +Oy6LeH0+x/uPySxaEvy4kuo/hapX2ClM16EMCUXHPwGIYRWdbTL7rzMTaoG3thyz +VO04LulI9Xmvadn6k3JR5mFPpIsV+LNwt3g+c+4rBWspOdTHnFqo+OO7Uk8Ee3E0 +/MeuPBtqQq9o7RkoY8wtVOqT8q9/6g== +=mpF6 +-----END PGP SIGNATURE----- diff --git a/openssh-CVE-2019-6109-force-progressmeter-update.patch b/openssh-CVE-2019-6109-force-progressmeter-update.patch deleted file mode 100644 index 0a67d30..0000000 --- a/openssh-CVE-2019-6109-force-progressmeter-update.patch +++ /dev/null @@ -1,110 +0,0 @@ -commit bdc6c63c80b55bcbaa66b5fde31c1cb1d09a41eb -Author: dtucker@openbsd.org -Date: Thu Jan 24 16:52:17 2019 +0000 - - upstream: Have progressmeter force an update at the beginning and - - end of each transfer. Fixes the problem recently introduces where very quick - transfers do not display the progressmeter at all. Spotted by naddy@ - - OpenBSD-Commit-ID: 68dc46c259e8fdd4f5db3ec2a130f8e4590a7a9a - -Index: openssh-7.9p1/progressmeter.c -=================================================================== ---- openssh-7.9p1.orig/progressmeter.c -+++ openssh-7.9p1/progressmeter.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */ -+/* $OpenBSD: progressmeter.c,v 1.47 2019/01/24 16:52:17 dtucker Exp $ */ - /* - * Copyright (c) 2003 Nils Nordman. All rights reserved. - * -@@ -59,9 +59,6 @@ static void format_rate(char *, int, off - static void sig_winch(int); - static void setscreensize(void); - --/* updates the progressmeter to reflect the current state of the transfer */ --void refresh_progress_meter(void); -- - /* signal handler for updating the progress meter */ - static void sig_alarm(int); - -@@ -120,7 +117,7 @@ format_size(char *buf, int size, off_t b - } - - void --refresh_progress_meter(void) -+refresh_progress_meter(int force_update) - { - char buf[MAX_WINSIZE + 1]; - off_t transferred; -@@ -131,7 +128,7 @@ refresh_progress_meter(void) - int hours, minutes, seconds; - int file_len; - -- if ((!alarm_fired && !win_resized) || !can_output()) -+ if ((!force_update && !alarm_fired && !win_resized) || !can_output()) - return; - alarm_fired = 0; - -@@ -254,7 +251,7 @@ start_progress_meter(const char *f, off_ - bytes_per_second = 0; - - setscreensize(); -- refresh_progress_meter(); -+ refresh_progress_meter(1); - - signal(SIGALRM, sig_alarm); - signal(SIGWINCH, sig_winch); -@@ -271,7 +268,7 @@ stop_progress_meter(void) - - /* Ensure we complete the progress */ - if (cur_pos != end_pos) -- refresh_progress_meter(); -+ refresh_progress_meter(1); - - atomicio(vwrite, STDOUT_FILENO, "\n", 1); - } -Index: openssh-7.9p1/progressmeter.h -=================================================================== ---- openssh-7.9p1.orig/progressmeter.h -+++ openssh-7.9p1/progressmeter.h -@@ -1,4 +1,4 @@ --/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */ -+/* $OpenBSD: progressmeter.h,v 1.5 2019/01/24 16:52:17 dtucker Exp $ */ - /* - * Copyright (c) 2002 Nils Nordman. All rights reserved. - * -@@ -24,5 +24,5 @@ - */ - - void start_progress_meter(const char *, off_t, off_t *); --void refresh_progress_meter(void); -+void refresh_progress_meter(int); - void stop_progress_meter(void); -Index: openssh-7.9p1/scp.c -=================================================================== ---- openssh-7.9p1.orig/scp.c -+++ openssh-7.9p1/scp.c -@@ -585,7 +585,7 @@ scpio(void *_cnt, size_t s) - off_t *cnt = (off_t *)_cnt; - - *cnt += s; -- refresh_progress_meter(); -+ refresh_progress_meter(0); - if (limit_kbps > 0) - bandwidth_limit(&bwlimit, s); - return 0; -Index: openssh-7.9p1/sftp-client.c -=================================================================== ---- openssh-7.9p1.orig/sftp-client.c -+++ openssh-7.9p1/sftp-client.c -@@ -101,7 +101,7 @@ sftpio(void *_bwlimit, size_t amount) - { - struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; - -- refresh_progress_meter(); -+ refresh_progress_meter(0); - if (bwlimit != NULL) - bandwidth_limit(bwlimit, amount); - return 0; diff --git a/openssh-CVE-2019-6109-sanitize-scp-filenames.patch b/openssh-CVE-2019-6109-sanitize-scp-filenames.patch deleted file mode 100644 index e2554dd..0000000 --- a/openssh-CVE-2019-6109-sanitize-scp-filenames.patch +++ /dev/null @@ -1,262 +0,0 @@ -commit 8976f1c4b2721c26e878151f52bdf346dfe2d54c -Author: dtucker@openbsd.org -Date: Wed Jan 23 08:01:46 2019 +0000 - - upstream: Sanitize scp filenames via snmprintf. To do this we move - - the progressmeter formatting outside of signal handler context and have the - atomicio callback called for EINTR too. bz#2434 with contributions from djm - and jjelen at redhat.com, ok djm@ - - OpenBSD-Commit-ID: 1af61c1f70e4f3bd8ab140b9f1fa699481db57d8 - -Index: openssh-7.9p1/atomicio.c -=================================================================== ---- openssh-7.9p1.orig/atomicio.c -+++ openssh-7.9p1/atomicio.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */ -+/* $OpenBSD: atomicio.c,v 1.29 2019/01/23 08:01:46 dtucker Exp $ */ - /* - * Copyright (c) 2006 Damien Miller. All rights reserved. - * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. -@@ -65,9 +65,14 @@ atomicio6(ssize_t (*f) (int, void *, siz - res = (f) (fd, s + pos, n - pos); - switch (res) { - case -1: -- if (errno == EINTR) -+ if (errno == EINTR) { -+ /* possible SIGALARM, update callback */ -+ if (cb != NULL && cb(cb_arg, 0) == -1) { -+ errno = EINTR; -+ return pos; -+ } - continue; -- if (errno == EAGAIN || errno == EWOULDBLOCK) { -+ } else if (errno == EAGAIN || errno == EWOULDBLOCK) { - #ifndef BROKEN_READ_COMPARISON - (void)poll(&pfd, 1, -1); - #endif -@@ -122,9 +127,14 @@ atomiciov6(ssize_t (*f) (int, const stru - res = (f) (fd, iov, iovcnt); - switch (res) { - case -1: -- if (errno == EINTR) -+ if (errno == EINTR) { -+ /* possible SIGALARM, update callback */ -+ if (cb != NULL && cb(cb_arg, 0) == -1) { -+ errno = EINTR; -+ return pos; -+ } - continue; -- if (errno == EAGAIN || errno == EWOULDBLOCK) { -+ } else if (errno == EAGAIN || errno == EWOULDBLOCK) { - #ifndef BROKEN_READV_COMPARISON - (void)poll(&pfd, 1, -1); - #endif -Index: openssh-7.9p1/progressmeter.c -=================================================================== ---- openssh-7.9p1.orig/progressmeter.c -+++ openssh-7.9p1/progressmeter.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: progressmeter.c,v 1.45 2016/06/30 05:17:05 dtucker Exp $ */ -+/* $OpenBSD: progressmeter.c,v 1.46 2019/01/23 08:01:46 dtucker Exp $ */ - /* - * Copyright (c) 2003 Nils Nordman. All rights reserved. - * -@@ -31,6 +31,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -39,6 +40,7 @@ - #include "progressmeter.h" - #include "atomicio.h" - #include "misc.h" -+#include "utf8.h" - - #define DEFAULT_WINSIZE 80 - #define MAX_WINSIZE 512 -@@ -61,7 +63,7 @@ static void setscreensize(void); - void refresh_progress_meter(void); - - /* signal handler for updating the progress meter */ --static void update_progress_meter(int); -+static void sig_alarm(int); - - static double start; /* start progress */ - static double last_update; /* last progress update */ -@@ -74,6 +76,7 @@ static long stalled; /* how long we hav - static int bytes_per_second; /* current speed in bytes per second */ - static int win_size; /* terminal window size */ - static volatile sig_atomic_t win_resized; /* for window resizing */ -+static volatile sig_atomic_t alarm_fired; - - /* units for format_size */ - static const char unit[] = " KMGT"; -@@ -126,9 +129,17 @@ refresh_progress_meter(void) - off_t bytes_left; - int cur_speed; - int hours, minutes, seconds; -- int i, len; - int file_len; - -+ if ((!alarm_fired && !win_resized) || !can_output()) -+ return; -+ alarm_fired = 0; -+ -+ if (win_resized) { -+ setscreensize(); -+ win_resized = 0; -+ } -+ - transferred = *counter - (cur_pos ? cur_pos : start_pos); - cur_pos = *counter; - now = monotime_double(); -@@ -158,16 +169,11 @@ refresh_progress_meter(void) - - /* filename */ - buf[0] = '\0'; -- file_len = win_size - 35; -+ file_len = win_size - 36; - if (file_len > 0) { -- len = snprintf(buf, file_len + 1, "\r%s", file); -- if (len < 0) -- len = 0; -- if (len >= file_len + 1) -- len = file_len; -- for (i = len; i < file_len; i++) -- buf[i] = ' '; -- buf[file_len] = '\0'; -+ buf[0] = '\r'; -+ snmprintf(buf+1, sizeof(buf)-1 , &file_len, "%*s", -+ file_len * -1, file); - } - - /* percent of transfer done */ -@@ -228,22 +234,11 @@ refresh_progress_meter(void) - - /*ARGSUSED*/ - static void --update_progress_meter(int ignore) -+sig_alarm(int ignore) - { -- int save_errno; -- -- save_errno = errno; -- -- if (win_resized) { -- setscreensize(); -- win_resized = 0; -- } -- if (can_output()) -- refresh_progress_meter(); -- -- signal(SIGALRM, update_progress_meter); -+ signal(SIGALRM, sig_alarm); -+ alarm_fired = 1; - alarm(UPDATE_INTERVAL); -- errno = save_errno; - } - - void -@@ -259,10 +254,9 @@ start_progress_meter(const char *f, off_ - bytes_per_second = 0; - - setscreensize(); -- if (can_output()) -- refresh_progress_meter(); -+ refresh_progress_meter(); - -- signal(SIGALRM, update_progress_meter); -+ signal(SIGALRM, sig_alarm); - signal(SIGWINCH, sig_winch); - alarm(UPDATE_INTERVAL); - } -@@ -286,6 +280,7 @@ stop_progress_meter(void) - static void - sig_winch(int sig) - { -+ signal(SIGWINCH, sig_winch); - win_resized = 1; - } - -Index: openssh-7.9p1/progressmeter.h -=================================================================== ---- openssh-7.9p1.orig/progressmeter.h -+++ openssh-7.9p1/progressmeter.h -@@ -1,4 +1,4 @@ --/* $OpenBSD: progressmeter.h,v 1.3 2015/01/14 13:54:13 djm Exp $ */ -+/* $OpenBSD: progressmeter.h,v 1.4 2019/01/23 08:01:46 dtucker Exp $ */ - /* - * Copyright (c) 2002 Nils Nordman. All rights reserved. - * -@@ -24,4 +24,5 @@ - */ - - void start_progress_meter(const char *, off_t, off_t *); -+void refresh_progress_meter(void); - void stop_progress_meter(void); -Index: openssh-7.9p1/scp.c -=================================================================== ---- openssh-7.9p1.orig/scp.c -+++ openssh-7.9p1/scp.c -@@ -585,6 +585,7 @@ scpio(void *_cnt, size_t s) - off_t *cnt = (off_t *)_cnt; - - *cnt += s; -+ refresh_progress_meter(); - if (limit_kbps > 0) - bandwidth_limit(&bwlimit, s); - return 0; -Index: openssh-7.9p1/sftp-client.c -=================================================================== ---- openssh-7.9p1.orig/sftp-client.c -+++ openssh-7.9p1/sftp-client.c -@@ -101,7 +101,9 @@ sftpio(void *_bwlimit, size_t amount) - { - struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; - -- bandwidth_limit(bwlimit, amount); -+ refresh_progress_meter(); -+ if (bwlimit != NULL) -+ bandwidth_limit(bwlimit, amount); - return 0; - } - -@@ -121,8 +123,8 @@ send_msg(struct sftp_conn *conn, struct - iov[1].iov_base = (u_char *)sshbuf_ptr(m); - iov[1].iov_len = sshbuf_len(m); - -- if (atomiciov6(writev, conn->fd_out, iov, 2, -- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != -+ if (atomiciov6(writev, conn->fd_out, iov, 2, sftpio, -+ conn->limit_kbps > 0 ? &conn->bwlimit_out : NULL) != - sshbuf_len(m) + sizeof(mlen)) - fatal("Couldn't send packet: %s", strerror(errno)); - -@@ -138,8 +140,8 @@ get_msg_extended(struct sftp_conn *conn, - - if ((r = sshbuf_reserve(m, 4, &p)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -- if (atomicio6(read, conn->fd_in, p, 4, -- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { -+ if (atomicio6(read, conn->fd_in, p, 4, sftpio, -+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) != 4) { - if (errno == EPIPE || errno == ECONNRESET) - fatal("Connection closed"); - else -@@ -157,8 +159,8 @@ get_msg_extended(struct sftp_conn *conn, - - if ((r = sshbuf_reserve(m, msg_len, &p)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); -- if (atomicio6(read, conn->fd_in, p, msg_len, -- conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) -+ if (atomicio6(read, conn->fd_in, p, msg_len, sftpio, -+ conn->limit_kbps > 0 ? &conn->bwlimit_in : NULL) - != msg_len) { - if (errno == EPIPE) - fatal("Connection closed"); diff --git a/openssh-CVE-2019-6111-scp-client-wildcard.patch b/openssh-CVE-2019-6111-scp-client-wildcard.patch deleted file mode 100644 index 00247d1..0000000 --- a/openssh-CVE-2019-6111-scp-client-wildcard.patch +++ /dev/null @@ -1,186 +0,0 @@ -commit 391ffc4b9d31fa1f4ad566499fef9176ff8a07dc -Author: djm@openbsd.org -Date: Sat Jan 26 22:41:28 2019 +0000 - - upstream: check in scp client that filenames sent during - - remote->local directory copies satisfy the wildcard specified by the user. - - This checking provides some protection against a malicious server - sending unexpected filenames, but it comes at a risk of rejecting wanted - files due to differences between client and server wildcard expansion rules. - - For this reason, this also adds a new -T flag to disable the check. - - reported by Harry Sintonen - fix approach suggested by markus@; - has been in snaps for ~1wk courtesy deraadt@ - - OpenBSD-Commit-ID: 00f44b50d2be8e321973f3c6d014260f8f7a8eda - -Index: openssh-7.9p1/scp.1 -=================================================================== ---- openssh-7.9p1.orig/scp.1 -+++ openssh-7.9p1/scp.1 -@@ -18,7 +18,7 @@ - .Nd secure copy (remote file copy program) - .Sh SYNOPSIS - .Nm scp --.Op Fl 346BCpqrv -+.Op Fl 346BCpqrTv - .Op Fl c Ar cipher - .Op Fl F Ar ssh_config - .Op Fl i Ar identity_file -@@ -208,6 +208,16 @@ to use for the encrypted connection. - The program must understand - .Xr ssh 1 - options. -+.It Fl T -+Disable strict filename checking. -+By default when copying files from a remote host to a local directory -+.Nm -+checks that the received filenames match those requested on the command-line -+to prevent the remote end from sending unexpected or unwanted files. -+Because of differences in how various operating systems and shells interpret -+filename wildcards, these checks may cause wanted files to be rejected. -+This option disables these checks at the expense of fully trusting that -+the server will not send unexpected filenames. - .It Fl v - Verbose mode. - Causes -Index: openssh-7.9p1/scp.c -=================================================================== ---- openssh-7.9p1.orig/scp.c -+++ openssh-7.9p1/scp.c -@@ -94,6 +94,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -375,14 +376,14 @@ void verifydir(char *); - struct passwd *pwd; - uid_t userid; - int errs, remin, remout; --int pflag, iamremote, iamrecursive, targetshouldbedirectory; -+int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; - - #define CMDNEEDS 64 - char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ - - int response(void); - void rsource(char *, struct stat *); --void sink(int, char *[]); -+void sink(int, char *[], const char *); - void source(int, char *[]); - void tolocal(int, char *[]); - void toremote(int, char *[]); -@@ -421,8 +422,9 @@ main(int argc, char **argv) - addargs(&args, "-oRemoteCommand=none"); - addargs(&args, "-oRequestTTY=no"); - -- fflag = tflag = 0; -- while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1) -+ fflag = Tflag = tflag = 0; -+ while ((ch = getopt(argc, argv, -+ "dfl:prtTvBCc:i:P:q12346S:o:F:J:")) != -1) { - switch (ch) { - /* User-visible flags. */ - case '1': -@@ -501,9 +503,13 @@ main(int argc, char **argv) - setmode(0, O_BINARY); - #endif - break; -+ case 'T': -+ Tflag = 1; -+ break; - default: - usage(); - } -+ } - argc -= optind; - argv += optind; - -@@ -534,7 +540,7 @@ main(int argc, char **argv) - } - if (tflag) { - /* Receive data. */ -- sink(argc, argv); -+ sink(argc, argv, NULL); - exit(errs != 0); - } - if (argc < 2) -@@ -792,7 +798,7 @@ tolocal(int argc, char **argv) - continue; - } - free(bp); -- sink(1, argv + argc - 1); -+ sink(1, argv + argc - 1, src); - (void) close(remin); - remin = remout = -1; - } -@@ -968,7 +974,7 @@ rsource(char *name, struct stat *statp) - (sizeof(type) != 4 && sizeof(type) != 8)) - - void --sink(int argc, char **argv) -+sink(int argc, char **argv, const char *src) - { - static BUF buffer; - struct stat stb; -@@ -984,6 +990,7 @@ sink(int argc, char **argv) - unsigned long long ull; - int setimes, targisdir, wrerrno = 0; - char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; -+ char *src_copy = NULL, *restrict_pattern = NULL; - struct timeval tv[2]; - - #define atime tv[0] -@@ -1008,6 +1015,17 @@ sink(int argc, char **argv) - (void) atomicio(vwrite, remout, "", 1); - if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) - targisdir = 1; -+ if (src != NULL && !iamrecursive && !Tflag) { -+ /* -+ * Prepare to try to restrict incoming filenames to match -+ * the requested destination file glob. -+ */ -+ if ((src_copy = strdup(src)) == NULL) -+ fatal("strdup failed"); -+ if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) { -+ *restrict_pattern++ = '\0'; -+ } -+ } - for (first = 1;; first = 0) { - cp = buf; - if (atomicio(read, remin, cp, 1) != 1) -@@ -1112,6 +1130,9 @@ sink(int argc, char **argv) - run_err("error: unexpected filename: %s", cp); - exit(1); - } -+ if (restrict_pattern != NULL && -+ fnmatch(restrict_pattern, cp, 0) != 0) -+ SCREWUP("filename does not match request"); - if (targisdir) { - static char *namebuf; - static size_t cursize; -@@ -1149,7 +1170,7 @@ sink(int argc, char **argv) - goto bad; - } - vect[0] = xstrdup(np); -- sink(1, vect); -+ sink(1, vect, src); - if (setimes) { - setimes = 0; - if (utimes(vect[0], tv) < 0) -@@ -1317,7 +1338,7 @@ void - usage(void) - { - (void) fprintf(stderr, -- "usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" -+ "usage: scp [-346BCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n" - " [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n"); - exit(1); - } diff --git a/openssh-askpass-gnome.spec b/openssh-askpass-gnome.spec index 64062f9..eaa041b 100644 --- a/openssh-askpass-gnome.spec +++ b/openssh-askpass-gnome.spec @@ -18,7 +18,7 @@ %define _name openssh Name: openssh-askpass-gnome -Version: 7.9p1 +Version: 8.1p1 Release: 0 Summary: A GNOME-Based Passphrase Dialog for OpenSSH License: BSD-2-Clause diff --git a/openssh-openssl-1_0_0-compatibility.patch b/openssh-openssl-1_0_0-compatibility.patch deleted file mode 100644 index d715312..0000000 --- a/openssh-openssl-1_0_0-compatibility.patch +++ /dev/null @@ -1,41 +0,0 @@ -Index: openssh-7.9p1/openbsd-compat/openssl-compat.c -=================================================================== ---- openssh-7.9p1.orig/openbsd-compat/openssl-compat.c 2018-11-26 11:47:17.417925053 +0100 -+++ openssh-7.9p1/openbsd-compat/openssl-compat.c 2018-11-26 11:52:47.127727580 +0100 -@@ -76,7 +76,7 @@ ssh_OpenSSL_add_all_algorithms(void) - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - --#if OPENSSL_VERSION_NUMBER < 0x10001000L -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - OPENSSL_config(NULL); - #else - OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | -Index: openssh-7.9p1/gss-genr.c -=================================================================== ---- openssh-7.9p1.orig/gss-genr.c 2018-11-26 11:47:17.417925053 +0100 -+++ openssh-7.9p1/gss-genr.c 2018-11-26 12:01:40.354642746 +0100 -@@ -114,7 +114,11 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - if ((buf = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new failed", __func__); - -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+ md = EVP_MD_CTX_create(); -+#else - md = EVP_MD_CTX_new(); -+#endif - oidpos = 0; - for (i = 0; i < gss_supported->count; i++) { - if (gss_supported->elements[i].length < 128 && -@@ -156,7 +160,11 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - oidpos++; - } - } -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+ EVP_MD_CTX_destroy(md); -+#else - EVP_MD_CTX_free(md); -+#endif - gss_enc2oid[oidpos].oid = NULL; - gss_enc2oid[oidpos].encoded = NULL; - diff --git a/openssh.changes b/openssh.changes index 68b6177..74ace9d 100644 --- a/openssh.changes +++ b/openssh.changes @@ -1,3 +1,111 @@ +------------------------------------------------------------------- +Thu Oct 10 00:41:18 UTC 2019 - Hans Petter Jansson + +- Version update to 8.1p1: + * ssh-keygen(1): when acting as a CA and signing certificates with + an RSA key, default to using the rsa-sha2-512 signature algorithm. + Certificates signed by RSA keys will therefore be incompatible + with OpenSSH versions prior to 7.2 unless the default is + overridden (using "ssh-keygen -t ssh-rsa -s ..."). + * ssh(1): Allow %n to be expanded in ProxyCommand strings + * ssh(1), sshd(8): Allow prepending a list of algorithms to the + default set by starting the list with the '^' character, E.g. + "HostKeyAlgorithms ^ssh-ed25519" + * ssh-keygen(1): add an experimental lightweight signature and + verification ability. Signatures may be made using regular ssh keys + held on disk or stored in a ssh-agent and verified against an + authorized_keys-like list of allowed keys. Signatures embed a + namespace that prevents confusion and attacks between different + usage domains (e.g. files vs email). + * ssh-keygen(1): print key comment when extracting public key from a + private key. + * ssh-keygen(1): accept the verbose flag when searching for host keys + in known hosts (i.e. "ssh-keygen -vF host") to print the matching + host's random-art signature too. + * All: support PKCS8 as an optional format for storage of private + keys to disk. The OpenSSH native key format remains the default, + but PKCS8 is a superior format to PEM if interoperability with + non-OpenSSH software is required, as it may use a less insecure + key derivation function than PEM's. + +- Additional changes from 8.0p1 release: + * scp(1): Add "-T" flag to disable client-side filtering of + server file list. + * sshd(8): Remove support for obsolete "host/port" syntax. + * ssh(1), ssh-agent(1), ssh-add(1): Add support for ECDSA keys in + PKCS#11 tokens. + * ssh(1), sshd(8): Add experimental quantum-computing resistant + key exchange method, based on a combination of Streamlined NTRU + Prime 4591^761 and X25519. + * ssh-keygen(1): Increase the default RSA key size to 3072 bits, + following NIST Special Publication 800-57's guidance for a + 128-bit equivalent symmetric security level. + * ssh(1): Allow "PKCS11Provider=none" to override later instances of + the PKCS11Provider directive in ssh_config, + * sshd(8): Add a log message for situations where a connection is + dropped for attempting to run a command but a sshd_config + ForceCommand=internal-sftp restriction is in effect. + * ssh(1): When prompting whether to record a new host key, accept + the key fingerprint as a synonym for "yes". This allows the user + to paste a fingerprint obtained out of band at the prompt and + have the client do the comparison for you. + * ssh-keygen(1): When signing multiple certificates on a single + command-line invocation, allow automatically incrementing the + certificate serial number. + * scp(1), sftp(1): Accept -J option as an alias to ProxyJump on + the scp and sftp command-lines. + * ssh-agent(1), ssh-pkcs11-helper(8), ssh-add(1): Accept "-v" + command-line flags to increase the verbosity of output; pass + verbose flags though to subprocesses, such as ssh-pkcs11-helper + started from ssh-agent. + * ssh-add(1): Add a "-T" option to allowing testing whether keys in + an agent are usable by performing a signature and a verification. + * sftp-server(8): Add a "lsetstat@openssh.com" protocol extension + that replicates the functionality of the existing SSH2_FXP_SETSTAT + operation but does not follow symlinks. + * sftp(1): Add "-h" flag to chown/chgrp/chmod commands to request + they do not follow symlinks. + * sshd(8): Expose $SSH_CONNECTION in the PAM environment. This makes + the connection 4-tuple available to PAM modules that wish to use + it in decision-making. + * sshd(8): Add a ssh_config "Match final" predicate Matches in same + pass as "Match canonical" but doesn't require hostname + canonicalisation be enabled. + * sftp(1): Support a prefix of '@' to suppress echo of sftp batch + commands. + * ssh-keygen(1): When printing certificate contents using + "ssh-keygen -Lf /path/certificate", include the algorithm that + the CA used to sign the cert. + +- Rebased patches: + * openssh-7.7p1-IPv6_X_forwarding.patch + * openssh-7.7p1-X_forward_with_disabled_ipv6.patch + * openssh-7.7p1-cavstest-ctr.patch + * openssh-7.7p1-cavstest-kdf.patch + * openssh-7.7p1-disable_openssl_abi_check.patch + * openssh-7.7p1-fips.patch + * openssh-7.7p1-fips_checks.patch + * openssh-7.7p1-hostname_changes_when_forwarding_X.patch + * openssh-7.7p1-ldap.patch + * openssh-7.7p1-seed-prng.patch + * openssh-7.7p1-sftp_force_permissions.patch + * openssh-7.7p1-sftp_print_diagnostic_messages.patch + * openssh-8.0p1-gssapi-keyex.patch (formerly + openssh-7.7p1-gssapi_key_exchange.patch) + * openssh-8.1p1-audit.patch (formerly openssh-7.7p1-audit.patch) + +- Removed patches (integrated upstream): + * 0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch + * openssh-7.7p1-seccomp_ioctl_s390_EP11.patch + * openssh-7.9p1-CVE-2018-20685.patch + * openssh-7.9p1-brace-expansion.patch + * openssh-CVE-2019-6109-force-progressmeter-update.patch + * openssh-CVE-2019-6109-sanitize-scp-filenames.patch + * openssh-CVE-2019-6111-scp-client-wildcard.patch + +- Removed patches (obsolete): + * openssh-openssl-1_0_0-compatibility.patch + ------------------------------------------------------------------- Mon Aug 19 11:24:36 CEST 2019 - kukuk@suse.de diff --git a/openssh.spec b/openssh.spec index 8a9a995..fd660d0 100644 --- a/openssh.spec +++ b/openssh.spec @@ -37,7 +37,7 @@ %define _fillupdir %{_localstatedir}/adm/fillup-templates %endif Name: openssh -Version: 7.9p1 +Version: 8.1p1 Release: 0 Summary: Secure Shell Client and Server (Remote Login Program) License: BSD-2-Clause AND MIT @@ -70,7 +70,6 @@ Patch14: openssh-7.7p1-seccomp_stat.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2752 Patch15: openssh-7.7p1-seccomp_ipc_flock.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2752 -Patch16: openssh-7.7p1-seccomp_ioctl_s390_EP11.patch # Local FIPS patchset Patch17: openssh-7.7p1-fips.patch # Local cavs patchset @@ -82,9 +81,9 @@ Patch20: openssh-7.7p1-fips_checks.patch Patch21: openssh-7.7p1-seed-prng.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2641 Patch22: openssh-7.7p1-systemd-notify.patch -Patch23: openssh-7.7p1-gssapi_key_exchange.patch +Patch23: openssh-8.0p1-gssapi-keyex.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=1402 -Patch24: openssh-7.7p1-audit.patch +Patch24: openssh-8.1p1-audit.patch # Local patch to disable runtime abi SSL checks, quite pointless for us Patch26: openssh-7.7p1-disable_openssl_abi_check.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2641 @@ -98,13 +97,6 @@ Patch31: openssh-7.7p1-ldap.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2213 Patch32: openssh-7.7p1-IPv6_X_forwarding.patch Patch33: openssh-7.7p1-sftp_print_diagnostic_messages.patch -Patch34: openssh-openssl-1_0_0-compatibility.patch -Patch35: openssh-7.9p1-CVE-2018-20685.patch -Patch36: openssh-CVE-2019-6109-sanitize-scp-filenames.patch -Patch37: openssh-CVE-2019-6109-force-progressmeter-update.patch -Patch38: openssh-CVE-2019-6111-scp-client-wildcard.patch -Patch39: openssh-7.9p1-brace-expansion.patch -Patch40: 0001-upstream-Fix-two-race-conditions-in-sshd-relating-to.patch BuildRequires: audit-devel BuildRequires: autoconf BuildRequires: groff From fbcab3da0ed89545f8da4ff4fcccbec8747c764f15ca8696859789d82b626924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Chv=C3=A1tal?= Date: Tue, 15 Oct 2019 07:47:08 +0000 Subject: [PATCH 2/3] Accepting request 738490 from home:hpjansson:branches:network Add openssh-7.9p1-keygen-preserve-perms.patch (bsc#1150574). This attempts to preserve the permissions of any existing known_hosts file when modified by ssh-keygen (for instance, with -R). Run 'ssh-keygen -A' on startup only if SSHD_AUTO_KEYGEN="yes" in /etc/sysconfig/ssh. This is set to "yes" by default, but can be changed by the system administrator (bsc#1139089). Add openssh-7.9p1-keygen-preserve-perms.patch (bsc#1150574). This attempts to preserve the permissions of any existing known_hosts file when modified by ssh-keygen (for instance, with -R). OBS-URL: https://build.opensuse.org/request/show/738490 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=198 --- openssh-7.9p1-keygen-preserve-perms.patch | 39 +++++++++++ openssh-7.9p1-revert-new-qos-defaults.patch | 76 +++++++++++++++++++++ openssh.changes | 23 +++++++ openssh.spec | 2 + sshd-gen-keys-start | 5 +- sysconfig.ssh | 5 ++ 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 openssh-7.9p1-keygen-preserve-perms.patch create mode 100644 openssh-7.9p1-revert-new-qos-defaults.patch diff --git a/openssh-7.9p1-keygen-preserve-perms.patch b/openssh-7.9p1-keygen-preserve-perms.patch new file mode 100644 index 0000000..a32eff9 --- /dev/null +++ b/openssh-7.9p1-keygen-preserve-perms.patch @@ -0,0 +1,39 @@ +commit 07ffb49749c310b82e44278ae05e081d6f4a82bf +Author: Hans Petter Jansson +Date: Fri Sep 27 01:57:16 2019 +0200 + + ssh-keygen: Preserve known_hosts permissions on rewrite + + Transfer the permissions of the old known_hosts file instead of + just going with what mkstemp() gives us. This is useful in corner + cases where known_hosts is shared between users. + +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 03a7fe5..ca8a309 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -1338,6 +1338,11 @@ do_known_hosts(struct passwd *pw, const char *name) + if (inplace) + unlink(tmp); + } else if (inplace) { ++ struct stat st; ++ ++ /* Get metadata for existing file */ ++ r = stat(identity_file, &st); ++ + /* Backup existing file */ + if (unlink(old) == -1 && errno != ENOENT) + fatal("unlink %.100s: %s", old, strerror(errno)); +@@ -1352,6 +1357,12 @@ do_known_hosts(struct passwd *pw, const char *name) + unlink(old); + exit(1); + } ++ /* Preserve permissions; non-critical */ ++ if (r != -1) ++ r = chown(identity_file, st.st_uid, st.st_gid); ++ if (r != -1) ++ chmod(identity_file, ++ st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + + printf("%s updated.\n", identity_file); + printf("Original contents retained as %s\n", old); diff --git a/openssh-7.9p1-revert-new-qos-defaults.patch b/openssh-7.9p1-revert-new-qos-defaults.patch new file mode 100644 index 0000000..db6ca6c --- /dev/null +++ b/openssh-7.9p1-revert-new-qos-defaults.patch @@ -0,0 +1,76 @@ +commit 101aa2f70c937abb428c9433c39ba0fd9a91fe6b +Author: Hans Petter Jansson +Date: Thu Jun 20 23:54:11 2019 +0200 + + Revert IPQoS DSCP AF21/CS1 from upstream due to bugs in other software + + Reverts OpenBSD-Commit-ID: d11d2a4484f461524ef0c20870523dfcdeb52181 + +diff --git a/readconf.c b/readconf.c +index 24f2cb1..bbdea0d 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -2183,9 +2183,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 13cf154..766ac6b 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -445,9 +445,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 3bf0502..10246f8 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -1088,11 +1088,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 50a4917..a276fcb 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -868,11 +868,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/openssh.changes b/openssh.changes index 74ace9d..427d1bc 100644 --- a/openssh.changes +++ b/openssh.changes @@ -1,3 +1,26 @@ +------------------------------------------------------------------- +Mon Oct 14 23:58:39 UTC 2019 - Hans Petter Jansson + +- Add openssh-7.9p1-keygen-preserve-perms.patch (bsc#1150574). + This attempts to preserve the permissions of any existing + known_hosts file when modified by ssh-keygen (for instance, + with -R). + +------------------------------------------------------------------- +Mon Oct 14 23:56:42 UTC 2019 - Hans Petter Jansson + +- Run 'ssh-keygen -A' on startup only if SSHD_AUTO_KEYGEN="yes" + in /etc/sysconfig/ssh. This is set to "yes" by default, but + can be changed by the system administrator (bsc#1139089). + +------------------------------------------------------------------- +Mon Oct 14 23:50:04 UTC 2019 - Hans Petter Jansson + +- Add openssh-7.9p1-keygen-preserve-perms.patch (bsc#1150574). + This attempts to preserve the permissions of any existing + known_hosts file when modified by ssh-keygen (for instance, + with -R). + ------------------------------------------------------------------- Thu Oct 10 00:41:18 UTC 2019 - Hans Petter Jansson diff --git a/openssh.spec b/openssh.spec index fd660d0..64dc598 100644 --- a/openssh.spec +++ b/openssh.spec @@ -97,6 +97,8 @@ Patch31: openssh-7.7p1-ldap.patch # https://bugzilla.mindrot.org/show_bug.cgi?id=2213 Patch32: openssh-7.7p1-IPv6_X_forwarding.patch Patch33: openssh-7.7p1-sftp_print_diagnostic_messages.patch +Patch34: openssh-7.9p1-keygen-preserve-perms.patch +Patch35: openssh-7.9p1-revert-new-qos-defaults.patch BuildRequires: audit-devel BuildRequires: autoconf BuildRequires: groff diff --git a/sshd-gen-keys-start b/sshd-gen-keys-start index a4f8535..7f5226c 100644 --- a/sshd-gen-keys-start +++ b/sshd-gen-keys-start @@ -1,5 +1,8 @@ #!/bin/sh -if ! grep -q '^[[:space:]]*HostKey[[:space:]]' /etc/ssh/sshd_config; then + +. /etc/sysconfig/ssh + +if [ "$SSHD_AUTO_KEYGEN" = "yes" ]; then echo "Checking for missing server keys in /etc/ssh" ssh-keygen -A fi diff --git a/sysconfig.ssh b/sysconfig.ssh index 81c642a..248449b 100644 --- a/sysconfig.ssh +++ b/sysconfig.ssh @@ -7,3 +7,8 @@ # Options for sshd # SSHD_OPTS="" + +# +# Whether to run ssh-keygen -A +# +SSHD_AUTO_KEYGEN="yes" From 5c5997059ed98d2ca05642067cdadc7266cd7f6226a07148f6e69ecdecc57625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Chv=C3=A1tal?= Date: Tue, 15 Oct 2019 08:09:16 +0000 Subject: [PATCH 3/3] - Add patch from upstream openssh-7.9p1-revert-new-qos-defaults.patch OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=199 --- openssh.changes | 1 + 1 file changed, 1 insertion(+) diff --git a/openssh.changes b/openssh.changes index 427d1bc..9b014e4 100644 --- a/openssh.changes +++ b/openssh.changes @@ -5,6 +5,7 @@ Mon Oct 14 23:58:39 UTC 2019 - Hans Petter Jansson This attempts to preserve the permissions of any existing known_hosts file when modified by ssh-keygen (for instance, with -R). +- Add patch from upstream openssh-7.9p1-revert-new-qos-defaults.patch ------------------------------------------------------------------- Mon Oct 14 23:56:42 UTC 2019 - Hans Petter Jansson