From bbf61daf970c2c84b653e0920d17d5d072ab3bb7 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Aug 24 2018 21:16:24 +0000 Subject: openssh-7.8p1-1 + 0.10.3-5 New upstream release including: * Dropping entropy patch * Remove default support for MD5 fingerprints * Porting all the downstream patches and pam_ssh_agent_auth to new sshbuf and sshkey API * pam_ssh_agent_auth is no longer using MD5 fingerprints --- diff --git a/.gitignore b/.gitignore index 09b3faa..ec4bb26 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /openssh-7.7p1.tar.gz /openssh-7.7p1.tar.gz.asc /DJM-GPG-KEY.gpg +/openssh-7.8p1.tar.gz +/openssh-7.8p1.tar.gz.asc diff --git a/openssh-5.8p1-packet.patch b/openssh-5.8p1-packet.patch deleted file mode 100644 index 2389903..0000000 --- a/openssh-5.8p1-packet.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up openssh-6.8p1/packet.c.packet openssh-6.8p1/packet.c ---- openssh-6.8p1/packet.c.packet 2015-03-18 10:56:32.286930601 +0100 -+++ openssh-6.8p1/packet.c 2015-03-18 10:58:38.535629739 +0100 -@@ -371,6 +371,8 @@ ssh_packet_connection_is_on_socket(struc - struct sockaddr_storage from, to; - socklen_t fromlen, tolen; - -+ if (!state) -+ return 0; - if (state->connection_in == -1 || state->connection_out == -1) - return 0; - diff --git a/openssh-6.1p1-gssapi-canohost.patch b/openssh-6.1p1-gssapi-canohost.patch index 124ac7f..3e6c9cc 100644 --- a/openssh-6.1p1-gssapi-canohost.patch +++ b/openssh-6.1p1-gssapi-canohost.patch @@ -4,7 +4,7 @@ diff -up openssh-6.1p1/sshconnect2.c.canohost openssh-6.1p1/sshconnect2.c @@ -699,12 +699,15 @@ userauth_gssapi(Authctxt *authctxt) static u_int mech = 0; OM_uint32 min; - int ok = 0; + int r, ok = 0; - const char *gss_host; + const char *gss_host = NULL; @@ -13,7 +13,7 @@ diff -up openssh-6.1p1/sshconnect2.c.canohost openssh-6.1p1/sshconnect2.c - else if (options.gss_trust_dns) + else if (options.gss_trust_dns) { gss_host = get_canonical_hostname(active_state, 1); -+ if ( strcmp( gss_host, "UNKNOWN" ) == 0 ) ++ if (strcmp(gss_host, "UNKNOWN") == 0) + gss_host = authctxt->host; + } else diff --git a/openssh-6.2p1-vendor.patch b/openssh-6.2p1-vendor.patch index 68abb56..1af5e9d 100644 --- a/openssh-6.2p1-vendor.patch +++ b/openssh-6.2p1-vendor.patch @@ -34,7 +34,7 @@ diff -up openssh-7.4p1/servconf.c.vendor openssh-7.4p1/servconf.c options->client_alive_interval = -1; options->client_alive_count_max = -1; @@ -325,6 +326,8 @@ fill_default_server_options(ServerOption - options->ip_qos_bulk = IPTOS_THROUGHPUT; + options->ip_qos_bulk = IPTOS_DSCP_CS1; if (options->version_addendum == NULL) options->version_addendum = xstrdup(""); + if (options->show_patchlevel == -1) @@ -71,7 +71,7 @@ diff -up openssh-7.4p1/servconf.c.vendor openssh-7.4p1/servconf.c while ((arg = strdelim(&cp)) && *arg != '\0') { if (match_user(NULL, NULL, NULL, arg) == -1) @@ -2269,6 +2277,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); + dump_cfg_fmtint(sEmptyPasswd, o->permit_empty_passwd); dump_cfg_fmtint(sCompression, o->compression); dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); + dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel); @@ -89,28 +89,13 @@ diff -up openssh-7.4p1/servconf.h.vendor openssh-7.4p1/servconf.h int use_dns; int client_alive_interval; /* * poke the client this often to -diff -up openssh-7.4p1/sshd_config.0.vendor openssh-7.4p1/sshd_config.0 ---- openssh-7.4p1/sshd_config.0.vendor 2016-12-23 13:34:51.695253847 +0100 -+++ openssh-7.4p1/sshd_config.0 2016-12-23 13:36:53.146277511 +0100 -@@ -792,6 +792,11 @@ DESCRIPTION - rdomain(4). If the routing domain is set to %D, then the domain - in which the incoming connection was received will be applied. - -+ ShowPatchLevel -+ Specifies whether sshd will display the specific patch level of -+ the binary in the server identification string. The patch level -+ is set at compile-time. The default is M-bM-^@M-^\noM-bM-^@M-^]. -+ - StreamLocalBindMask - Sets the octal file creation mode mask (umask) used when creating - a Unix-domain socket file for local or remote port forwarding. diff -up openssh-7.4p1/sshd_config.5.vendor openssh-7.4p1/sshd_config.5 --- openssh-7.4p1/sshd_config.5.vendor 2016-12-23 13:34:51.695253847 +0100 +++ openssh-7.4p1/sshd_config.5 2016-12-23 13:37:17.482282253 +0100 @@ -1334,6 +1334,13 @@ an OpenSSH Key Revocation List (KRL) as - If the routing domain is set to - .Cm \&%D , - then the domain in which the incoming connection was received will be applied. + .Cm AcceptEnv + or + .Cm PermitUserEnvironment . +.It Cm ShowPatchLevel +Specifies whether +.Nm sshd diff --git a/openssh-6.6.1p1-ip-port-config-parser.patch b/openssh-6.6.1p1-ip-port-config-parser.patch deleted file mode 100644 index 88e1ca2..0000000 --- a/openssh-6.6.1p1-ip-port-config-parser.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff --git a/misc.c b/misc.c -index 874dcc8a..7b7f7a58 100644 ---- a/misc.c -+++ b/misc.c -@@ -466,7 +466,7 @@ put_host_port(const char *host, u_short port) - * The delimiter char, if present, is stored in delim. - * If this is the last field, *cp is set to NULL. - */ --static char * -+char * - hpdelim2(char **cp, char *delim) - { - char *s, *old; -diff --git a/misc.h b/misc.h -index cdafea73..cf9c8f28 100644 ---- a/misc.h -+++ b/misc.h -@@ -54,6 +54,7 @@ int set_rdomain(int, const char *); - int a2port(const char *); - int a2tun(const char *, int *); - char *put_host_port(const char *, u_short); -+char *hpdelim2(char **, char *); - char *hpdelim(char **); - char *cleanhostname(char *); - char *colon(char *); -diff --git a/servconf.c b/servconf.c -index 0f0d0906..1679181e 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -821,7 +821,7 @@ process_permitopen(struct ssh *ssh, ServerOptions *options) - { - u_int i; - int port; -- char *host, *arg, *oarg; -+ char *host, *arg, *oarg, ch; - - channel_clear_adm_permitted_opens(ssh); - if (options->num_permitted_opens == 0) -@@ -839,8 +839,8 @@ process_permitopen(struct ssh *ssh, ServerOptions *options) - /* Otherwise treat it as a list of permitted host:port */ - for (i = 0; i < options->num_permitted_opens; i++) { - oarg = arg = xstrdup(options->permitted_opens[i]); -- host = hpdelim(&arg); -- if (host == NULL) -+ host = hpdelim2(&arg, &ch); -+ if (host == NULL || ch == '/') - fatal("%s: missing host in PermitOpen", __func__); - host = cleanhostname(host); - if (arg == NULL || ((port = permitopen_port(arg)) < 0)) -@@ -1244,8 +1244,10 @@ process_server_config_line(ServerOptions *options, char *line, - port = 0; - p = arg; - } else { -- p = hpdelim(&arg); -- if (p == NULL) -+ char ch; -+ arg2 = NULL; -+ p = hpdelim2(&arg, &ch); -+ if (p == NULL || ch == '/') - fatal("%s line %d: bad address:port usage", - filename, linenum); - p = cleanhostname(p); -@@ -1815,9 +1817,10 @@ process_server_config_line(ServerOptions *options, char *line, - break; - } - for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) { -+ char ch; - arg2 = xstrdup(arg); -- p = hpdelim(&arg); -- if (p == NULL) -+ p = hpdelim2(&arg, &ch); -+ if (p == NULL || ch == '/') - fatal("%s line %d: missing host in PermitOpen", - filename, linenum); - p = cleanhostname(p); diff --git a/openssh-6.6.1p1-log-in-chroot.patch b/openssh-6.6.1p1-log-in-chroot.patch index 99e2e03..7f822ab 100644 --- a/openssh-6.6.1p1-log-in-chroot.patch +++ b/openssh-6.6.1p1-log-in-chroot.patch @@ -34,9 +34,9 @@ diff -up openssh-7.4p1/log.h.log-in-chroot openssh-7.4p1/log.h void log_init(char *, LogLevel, SyslogFacility, int); +void log_init_handler(char *, LogLevel, SyslogFacility, int, int); + LogLevel log_level_get(void); int log_change_level(LogLevel); int log_is_on_stderr(void); - void log_redirect_stderr_to(const char *); diff -up openssh-7.4p1/monitor.c.log-in-chroot openssh-7.4p1/monitor.c --- openssh-7.4p1/monitor.c.log-in-chroot 2016-12-23 15:14:33.311168085 +0100 +++ openssh-7.4p1/monitor.c 2016-12-23 15:16:42.154193100 +0100 @@ -65,7 +65,7 @@ diff -up openssh-7.4p1/monitor.c.log-in-chroot openssh-7.4p1/monitor.c - do_log2(level, "%s [preauth]", msg); + do_log2(level, "%s [%s]", msg, pmonitor->m_state); - buffer_free(&logmsg); + sshbuf_free(logmsg); free(msg); @@ -1719,13 +1723,28 @@ monitor_init(void) mon = xcalloc(1, sizeof(*mon)); diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch index ea4cbd1..90e8627 100644 --- a/openssh-6.6.1p1-selinux-contexts.patch +++ b/openssh-6.6.1p1-selinux-contexts.patch @@ -7,7 +7,7 @@ index 8f32464..18a2ca4 100644 #include "servconf.h" #include "port-linux.h" +#include "misc.h" - #include "key.h" + #include "sshkey.h" #include "hostfile.h" #include "auth.h" @@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname) @@ -82,6 +82,14 @@ diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c index 22ea8ef..1fc963d 100644 --- a/openbsd-compat/port-linux.c +++ b/openbsd-compat/port-linux.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include "log.h" + #include "xmalloc.h" @@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) strlcpy(newctx + len, newname, newlen - len); if ((cx = index(cx + 1, ':'))) diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/openssh-6.6p1-GSSAPIEnablek5users.patch index 5dec15b..37e010d 100644 --- a/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -4,7 +4,7 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-ser @@ -279,7 +279,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri FILE *fp; char file[MAXPATHLEN]; - char line[BUFSIZ] = ""; + char *line = NULL; - char kuser[65]; /* match krb5_kuserok() */ struct stat st; struct passwd *pw = the_authctxt->pw; @@ -44,8 +44,8 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, - sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sGssKeyEx, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, @@ -497,12 +500,14 @@ static struct { { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, @@ -70,9 +70,9 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c + intptr = &options->enable_k5users; + goto parse_flag; + + case sPermitListen: case sPermitOpen: - arg = strdelim(&cp); - if (!arg || *arg == '\0') + if (opcode == sPermitListen) { @@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); diff --git a/openssh-6.6p1-ctr-cavstest.patch b/openssh-6.6p1-ctr-cavstest.patch index 08c6a35..42c399d 100644 --- a/openssh-6.6p1-ctr-cavstest.patch +++ b/openssh-6.6p1-ctr-cavstest.patch @@ -19,8 +19,8 @@ diff -up openssh-6.8p1/Makefile.in.ctr-cavs openssh-6.8p1/Makefile.in XMSS_OBJS=\ ssh-xmss.o \ @@ -194,6 +195,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) l - ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o - $(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(LIBS) + ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o uidswap.o + $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(LIBS) +ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o + $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) diff --git a/openssh-6.6p1-entropy.patch b/openssh-6.6p1-entropy.patch deleted file mode 100644 index 7f6f4d0..0000000 --- a/openssh-6.6p1-entropy.patch +++ /dev/null @@ -1,262 +0,0 @@ -diff -up openssh-7.4p1/entropy.c.entropy openssh-7.4p1/entropy.c ---- openssh-7.4p1/entropy.c.entropy 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/entropy.c 2016-12-23 18:34:27.769753570 +0100 -@@ -229,6 +229,9 @@ seed_rng(void) - memset(buf, '\0', sizeof(buf)); - - #endif /* OPENSSL_PRNG_ONLY */ -+#ifdef __linux__ -+ linux_seed(); -+#endif /* __linux__ */ - if (RAND_status() != 1) - fatal("PRNG is not seeded"); - } -diff -up openssh-7.4p1/openbsd-compat/Makefile.in.entropy openssh-7.4p1/openbsd-compat/Makefile.in ---- openssh-7.4p1/openbsd-compat/Makefile.in.entropy 2016-12-23 18:34:53.715762155 +0100 -+++ openssh-7.4p1/openbsd-compat/Makefile.in 2016-12-23 18:35:15.890769493 +0100 -@@ -20,7 +20,8 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf - port-solaris.o \ - port-net.o \ - port-uw.o \ -- port-linux-sshd.o -+ port-linux-sshd.o \ -+ port-linux-prng.o - - .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -diff -up openssh-7.4p1/openbsd-compat/port-linux.h.entropy openssh-7.4p1/openbsd-compat/port-linux.h ---- openssh-7.4p1/openbsd-compat/port-linux.h.entropy 2016-12-23 18:34:27.747753563 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 18:34:27.769753570 +0100 -@@ -34,4 +34,6 @@ void oom_adjust_restore(void); - void oom_adjust_setup(void); - #endif - -+void linux_seed(void); -+ - #endif /* ! _PORT_LINUX_H */ -diff -up openssh-7.4p1/openbsd-compat/port-linux-prng.c.entropy openssh-7.4p1/openbsd-compat/port-linux-prng.c ---- openssh-7.4p1/openbsd-compat/port-linux-prng.c.entropy 2016-12-23 18:34:27.769753570 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux-prng.c 2016-12-23 18:34:27.769753570 +0100 -@@ -0,0 +1,59 @@ -+/* $Id: port-linux.c,v 1.11.4.2 2011/02/04 00:43:08 djm Exp $ */ -+ -+/* -+ * Copyright (c) 2011 Jan F. Chadima -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+/* -+ * Linux-specific portability code - prng support -+ */ -+ -+#include "includes.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include "log.h" -+#include "xmalloc.h" -+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ -+#include "servconf.h" -+#include "port-linux.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+ -+void -+linux_seed(void) -+{ -+ char *env = getenv("SSH_USE_STRONG_RNG"); -+ char *random = "/dev/random"; -+ size_t len, ienv, randlen = 14; -+ -+ if (!env || !strcmp(env, "0")) -+ random = "/dev/urandom"; -+ else if ((ienv = atoi(env)) > randlen) -+ randlen = ienv; -+ -+ errno = 0; -+ if ((len = RAND_load_file(random, randlen)) != randlen) { -+ if (errno) -+ fatal ("cannot read from %s, %s", random, strerror(errno)); -+ else -+ fatal ("EOF reading %s", random); -+ } -+} -diff -up openssh-7.4p1/ssh.1.entropy openssh-7.4p1/ssh.1 ---- openssh-7.4p1/ssh.1.entropy 2016-12-23 18:34:27.754753565 +0100 -+++ openssh-7.4p1/ssh.1 2016-12-23 18:34:27.770753571 +0100 -@@ -1441,6 +1441,23 @@ For more information, see the - .Cm PermitUserEnvironment - option in - .Xr sshd_config 5 . -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -compact -+.It Ev SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. -+.El - .Sh FILES - .Bl -tag -width Ds -compact - .It Pa ~/.rhosts -diff -up openssh-7.4p1/ssh-add.1.entropy openssh-7.4p1/ssh-add.1 ---- openssh-7.4p1/ssh-add.1.entropy 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/ssh-add.1 2016-12-23 18:34:27.770753571 +0100 -@@ -171,6 +171,20 @@ to make this work.) - Identifies the path of a - .Ux Ns -domain - socket used to communicate with the agent. -+.It Ev SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. - .El - .Sh FILES - .Bl -tag -width Ds -diff -up openssh-7.4p1/ssh-agent.1.entropy openssh-7.4p1/ssh-agent.1 ---- openssh-7.4p1/ssh-agent.1.entropy 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/ssh-agent.1 2016-12-23 18:34:27.770753571 +0100 -@@ -214,6 +214,24 @@ sockets used to contain the connection t - These sockets should only be readable by the owner. - The sockets should get automatically removed when the agent exits. - .El -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -compact -+.Pp -+.It Pa SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. -+.El - .Sh SEE ALSO - .Xr ssh 1 , - .Xr ssh-add 1 , -diff -up openssh-7.4p1/sshd.8.entropy openssh-7.4p1/sshd.8 ---- openssh-7.4p1/sshd.8.entropy 2016-12-23 18:34:27.755753566 +0100 -+++ openssh-7.4p1/sshd.8 2016-12-23 18:34:27.770753571 +0100 -@@ -920,6 +920,24 @@ concurrently for different ports, this c - started last). - The content of this file is not sensitive; it can be world-readable. - .El -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -compact -+.Pp -+.It Pa SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. -+.El - .Sh IPV6 - IPv6 address can be used everywhere where IPv4 address. In all entries must be the IPv6 address enclosed in square brackets. Note: The square brackets are metacharacters for the shell and must be escaped in shell. - .Sh SEE ALSO -diff -up openssh-7.4p1/ssh-keygen.1.entropy openssh-7.4p1/ssh-keygen.1 ---- openssh-7.4p1/ssh-keygen.1.entropy 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/ssh-keygen.1 2016-12-23 18:34:27.770753571 +0100 -@@ -848,6 +848,24 @@ Contains Diffie-Hellman groups used for - The file format is described in - .Xr moduli 5 . - .El -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -compact -+.Pp -+.It Pa SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. -+.El - .Sh SEE ALSO - .Xr ssh 1 , - .Xr ssh-add 1 , -diff -up openssh-7.4p1/ssh-keysign.8.entropy openssh-7.4p1/ssh-keysign.8 ---- openssh-7.4p1/ssh-keysign.8.entropy 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/ssh-keysign.8 2016-12-23 18:34:27.770753571 +0100 -@@ -80,6 +80,24 @@ must be set-uid root if host-based authe - If these files exist they are assumed to contain public certificate - information corresponding with the private keys above. - .El -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -compact -+.Pp -+.It Pa SSH_USE_STRONG_RNG -+The reseeding of the OpenSSL random generator is usually done from -+.Cm /dev/urandom . -+If the -+.Cm SSH_USE_STRONG_RNG -+environment variable is set to value other than -+.Cm 0 -+the OpenSSL random generator is reseeded from -+.Cm /dev/random . -+The number of bytes read is defined by the SSH_USE_STRONG_RNG value. -+Minimum is 14 bytes. -+This setting is not recommended on the computers without the hardware -+random generator because insufficient entropy causes the connection to -+be blocked until enough entropy is available. -+.El - .Sh SEE ALSO - .Xr ssh 1 , - .Xr ssh-keygen 1 , diff --git a/openssh-6.6p1-force_krb.patch b/openssh-6.6p1-force_krb.patch index ae948f7..288963e 100644 --- a/openssh-6.6p1-force_krb.patch +++ b/openssh-6.6p1-force_krb.patch @@ -11,9 +11,9 @@ index 413b845..54dd383 100644 +#include #include "xmalloc.h" - #include "key.h" + #include "sshkey.h" @@ -45,6 +47,7 @@ - #include "buffer.h" + #include "ssh-gss.h" +extern Authctxt *the_authctxt; @@ -66,7 +66,7 @@ index 413b845..54dd383 100644 } else retval = 0; -@@ -110,6 +133,135 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -110,6 +133,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) return retval; } @@ -97,13 +97,14 @@ index 413b845..54dd383 100644 +{ + FILE *fp; + char file[MAXPATHLEN]; -+ char line[BUFSIZ] = ""; ++ char *line = NULL; + char kuser[65]; /* match krb5_kuserok() */ + struct stat st; + struct passwd *pw = the_authctxt->pw; + int found_principal = 0; + int ncommands = 0, allcommands = 0; + u_long linenum; ++ size_t linesize = 0; + + snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); + /* If both .k5login and .k5users DNE, self-login is ok. */ @@ -147,9 +148,9 @@ index 413b845..54dd383 100644 + k5users_allowed_cmds = xcalloc(++ncommands, + sizeof(*k5users_allowed_cmds)); + -+ /* Check each line. ksu allows unlimited length lines. We don't. */ -+ while (!allcommands && read_keyfile_line(fp, file, line, sizeof(line), -+ &linenum) != -1) { ++ /* Check each line. ksu allows unlimited length lines. */ ++ while (!allcommands && getline(&line, &linesize, fp) != -1) { ++ linenum++; + char *token; + + /* we parse just like ksu, even though we could do better */ @@ -182,6 +183,7 @@ index 413b845..54dd383 100644 + } + } + } ++ free(line); + if (k5users_allowed_cmds) { + /* terminate vector */ + k5users_allowed_cmds[ncommands-1] = NULL; diff --git a/openssh-6.6p1-keycat.patch b/openssh-6.6p1-keycat.patch index 108f461..e22a5f3 100644 --- a/openssh-6.6p1-keycat.patch +++ b/openssh-6.6p1-keycat.patch @@ -64,8 +64,8 @@ diff -up openssh/Makefile.in.keycat openssh/Makefile.in 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 -lfipscheck $(LIBS) $(LDAPLIBS) -+ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o -+ $(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(LIBS) ++ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o uidswap.o ++ $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(LIBS) + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) diff --git a/openssh-6.6p1-kuserok.patch b/openssh-6.6p1-kuserok.patch index 23f47ae..81ec2a4 100644 --- a/openssh-6.6p1-kuserok.patch +++ b/openssh-6.6p1-kuserok.patch @@ -224,9 +224,9 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c + intptr = &options->use_kuserok; + goto parse_flag; + + case sPermitListen: case sPermitOpen: - arg = strdelim(&cp); - if (!arg || *arg == '\0') + if (opcode == sPermitListen) { @@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(client_alive_interval); M_CP_INTOPT(ip_qos_interactive); diff --git a/openssh-6.6p1-privsep-selinux.patch b/openssh-6.6p1-privsep-selinux.patch index bc2c15d..1365506 100644 --- a/openssh-6.6p1-privsep-selinux.patch +++ b/openssh-6.6p1-privsep-selinux.patch @@ -54,9 +54,9 @@ diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c if (setusercontext(lc, pw, pw->pw_uid, (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { @@ -1361,6 +1361,9 @@ do_setusercontext(struct passwd *pw) - pw->pw_uid); - chroot_path = percent_expand(tmp, "h", pw->pw_dir, - "u", pw->pw_name, (char *)NULL); + (unsigned long long)pw->pw_uid); + chroot_path = percent_expand(tmp, "h", pw->pw_dir, + "u", pw->pw_name, "U", uidstr, (char *)NULL); +#ifdef WITH_SELINUX + sshd_selinux_copy_context(); +#endif diff --git a/openssh-6.6p1-role-mls.patch b/openssh-6.6p1-role-mls.patch deleted file mode 100644 index 37ae70d..0000000 --- a/openssh-6.6p1-role-mls.patch +++ /dev/null @@ -1,880 +0,0 @@ -diff -up openssh-7.4p1/auth2.c.role-mls openssh-7.4p1/auth2.c ---- openssh-7.4p1/auth2.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth2.c 2016-12-23 12:19:58.587459379 +0100 -@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32 - Authctxt *authctxt = ssh->authctxt; - Authmethod *m = NULL; - char *user, *service, *method, *style = NULL; -+#ifdef WITH_SELINUX -+ char *role = NULL; -+#endif - int authenticated = 0; - - if (authctxt == NULL) -@@ -226,6 +229,11 @@ input_userauth_request(int type, u_int32 - debug("userauth-request for user %s service %s method %s", user, service, method); - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - -+#ifdef WITH_SELINUX -+ if ((role = strchr(user, '/')) != NULL) -+ *role++ = 0; -+#endif -+ - if ((style = strchr(user, ':')) != NULL) - *style++ = 0; - -@@ -251,8 +259,15 @@ input_userauth_request(int type, u_int32 - use_privsep ? " [net]" : ""); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; -- if (use_privsep) -+#ifdef WITH_SELINUX -+ authctxt->role = role ? xstrdup(role) : NULL; -+#endif -+ if (use_privsep) { - mm_inform_authserv(service, style); -+#ifdef WITH_SELINUX -+ mm_inform_authrole(role); -+#endif -+ } - userauth_banner(); - if (auth2_setup_methods_lists(authctxt) != 0) - packet_disconnect("no authentication methods enabled"); -diff -up openssh-7.4p1/auth2-gss.c.role-mls openssh-7.4p1/auth2-gss.c ---- openssh-7.4p1/auth2-gss.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth2-gss.c 2016-12-23 12:19:58.586459382 +0100 -@@ -255,6 +255,7 @@ input_gssapi_mic(int type, u_int32_t ple - Authctxt *authctxt = ssh->authctxt; - Gssctxt *gssctxt; - int authenticated = 0; -+ char *micuser; - Buffer b; - gss_buffer_desc mic, gssbuf; - u_int len; -@@ -267,7 +268,13 @@ input_gssapi_mic(int type, u_int32_t ple - mic.value = packet_get_string(&len); - mic.length = len; - -- ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, -+#ifdef WITH_SELINUX -+ if (authctxt->role && (strlen(authctxt->role) > 0)) -+ xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role); -+ else -+#endif -+ micuser = authctxt->user; -+ ssh_gssapi_buildmic(&b, micuser, authctxt->service, - "gssapi-with-mic"); - - gssbuf.value = buffer_ptr(&b); -@@ -279,6 +286,8 @@ input_gssapi_mic(int type, u_int32_t ple - logit("GSSAPI MIC check failed"); - - buffer_free(&b); -+ if (micuser != authctxt->user) -+ free(micuser); - free(mic.value); - - if ((!use_privsep || mm_is_monitor()) && -diff -up openssh-7.4p1/auth2-hostbased.c.role-mls openssh-7.4p1/auth2-hostbased.c ---- openssh-7.4p1/auth2-hostbased.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth2-hostbased.c 2016-12-23 12:19:58.586459382 +0100 -@@ -121,7 +121,16 @@ userauth_hostbased(Authctxt *authctxt) - /* reconstruct packet */ - if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || - (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || -- (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || -+#ifdef WITH_SELINUX -+ (authctxt->role -+ ? ( (r = sshbuf_put_u32(b, strlen(authctxt->user)+strlen(authctxt->role)+1)) != 0 || -+ (r = sshbuf_put(b, authctxt->user, strlen(authctxt->user))) != 0 || -+ (r = sshbuf_put_u8(b, '/') != 0) || -+ (r = sshbuf_put(b, authctxt->role, strlen(authctxt->role))) != 0) -+ : (r = sshbuf_put_cstring(b, authctxt->user)) != 0) || -+#else -+ (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || -+#endif - (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || - (r = sshbuf_put_cstring(b, "hostbased")) != 0 || - (r = sshbuf_put_string(b, pkalg, alen)) != 0 || -diff -up openssh-7.4p1/auth2-pubkey.c.role-mls openssh-7.4p1/auth2-pubkey.c ---- openssh-7.4p1/auth2-pubkey.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth2-pubkey.c 2016-12-23 12:19:58.587459379 +0100 -@@ -151,9 +151,15 @@ userauth_pubkey(Authctxt *authctxt) - __func__, ssh_err(r)); - } - /* reconstruct packet */ -- xasprintf(&userstyle, "%s%s%s", authctxt->user, -+ xasprintf(&userstyle, "%s%s%s%s%s", authctxt->user, - authctxt->style ? ":" : "", -- authctxt->style ? authctxt->style : ""); -+ authctxt->style ? authctxt->style : "", -+#ifdef WITH_SELINUX -+ authctxt->role ? "/" : "", -+ authctxt->role ? authctxt->role : ""); -+#else -+ "", ""); -+#endif - if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || - (r = sshbuf_put_cstring(b, userstyle)) != 0 || - (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || -diff -up openssh-7.4p1/auth.h.role-mls openssh-7.4p1/auth.h ---- openssh-7.4p1/auth.h.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth.h 2016-12-23 12:19:43.478510375 +0100 -@@ -62,6 +62,9 @@ struct Authctxt { - char *service; - struct passwd *pw; /* set if 'valid' */ - char *style; -+#ifdef WITH_SELINUX -+ char *role; -+#endif - - /* Method lists for multiple authentication */ - char **auth_methods; /* modified from server config */ -diff -up openssh-7.4p1/auth-pam.c.role-mls openssh-7.4p1/auth-pam.c ---- openssh-7.4p1/auth-pam.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/auth-pam.c 2016-12-23 12:19:43.477510378 +0100 -@@ -1087,7 +1087,7 @@ is_pam_session_open(void) - * during the ssh authentication process. - */ - int --do_pam_putenv(char *name, char *value) -+do_pam_putenv(char *name, const char *value) - { - int ret = 1; - #ifdef HAVE_PAM_PUTENV -diff -up openssh-7.4p1/auth-pam.h.role-mls openssh-7.4p1/auth-pam.h ---- openssh-7.4p1/auth-pam.h.role-mls 2016-12-23 12:19:43.478510375 +0100 -+++ openssh-7.4p1/auth-pam.h 2016-12-23 12:21:44.698101234 +0100 -@@ -31,7 +31,7 @@ u_int do_pam_account(void); - void do_pam_session(struct ssh *); - void do_pam_setcred(int ); - void do_pam_chauthtok(void); --int do_pam_putenv(char *, char *); -+int do_pam_putenv(char *, const char *); - char ** fetch_pam_environment(void); - char ** fetch_pam_child_environment(void); - void free_pam_environment(char **); -diff -up openssh-7.4p1/misc.c.role-mls openssh-7.4p1/misc.c ---- openssh-7.4p1/misc.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/misc.c 2016-12-23 12:19:58.587459379 +0100 -@@ -432,6 +432,7 @@ char * - colon(char *cp) - { - int flag = 0; -+ int start = 1; - - if (*cp == ':') /* Leading colon is part of file name. */ - return NULL; -@@ -447,6 +448,13 @@ colon(char *cp) - return (cp); - if (*cp == '/') - return NULL; -+ if (start) { -+ /* Slash on beginning or after dots only denotes file name. */ -+ if (*cp == '/') -+ return (0); -+ if (*cp != '.') -+ start = 0; -+ } - } - return NULL; - } -diff -up openssh-7.4p1/monitor.c.role-mls openssh-7.4p1/monitor.c ---- openssh-7.4p1/monitor.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/monitor.c 2016-12-23 12:23:03.503835248 +0100 -@@ -127,6 +127,9 @@ int mm_answer_sign(int, Buffer *); - int mm_answer_pwnamallow(int, Buffer *); - int mm_answer_auth2_read_banner(int, Buffer *); - int mm_answer_authserv(int, Buffer *); -+#ifdef WITH_SELINUX -+int mm_answer_authrole(int, Buffer *); -+#endif - int mm_answer_authpassword(int, Buffer *); - int mm_answer_bsdauthquery(int, Buffer *); - int mm_answer_bsdauthrespond(int, Buffer *); -@@ -202,6 +205,9 @@ struct mon_table mon_dispatch_proto20[] - {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, - {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, - {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, -+#ifdef WITH_SELINUX -+ {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, -+#endif - {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, - {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, - #ifdef USE_PAM -@@ -769,6 +775,9 @@ mm_answer_pwnamallow(int sock, Buffer *m - - /* Allow service/style information on the auth context */ - monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); -+#ifdef WITH_SELINUX -+ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1); -+#endif - monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); - - #ifdef USE_PAM -@@ -810,6 +819,25 @@ mm_answer_authserv(int sock, Buffer *m) - return (0); - } - -+#ifdef WITH_SELINUX -+int -+mm_answer_authrole(int sock, Buffer *m) -+{ -+ monitor_permit_authentications(1); -+ -+ authctxt->role = buffer_get_string(m, NULL); -+ debug3("%s: role=%s", -+ __func__, authctxt->role); -+ -+ if (strlen(authctxt->role) == 0) { -+ free(authctxt->role); -+ authctxt->role = NULL; -+ } -+ -+ return (0); -+} -+#endif -+ - int - mm_answer_authpassword(int sock, Buffer *m) - { -@@ -1208,7 +1236,7 @@ monitor_valid_userblob(u_char *data, u_i - { - Buffer b; - u_char *p; -- char *userstyle, *cp; -+ char *userstyle, *r, *cp; - u_int len; - int fail = 0; - -@@ -1234,6 +1262,8 @@ monitor_valid_userblob(u_char *data, u_i - if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) - fail++; - cp = buffer_get_cstring(&b, NULL); -+ if ((r = strchr(cp, '/')) != NULL) -+ *r = '\0'; - xasprintf(&userstyle, "%s%s%s", authctxt->user, - authctxt->style ? ":" : "", - authctxt->style ? authctxt->style : ""); -@@ -1269,7 +1299,7 @@ monitor_valid_hostbasedblob(u_char *data - char *chost) - { - Buffer b; -- char *p, *userstyle; -+ char *p, *r, *userstyle; - u_int len; - int fail = 0; - -@@ -1286,6 +1316,8 @@ monitor_valid_hostbasedblob(u_char *data - if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) - fail++; - p = buffer_get_cstring(&b, NULL); -+ if ((r = strchr(p, '/')) != NULL) -+ *r = '\0'; - xasprintf(&userstyle, "%s%s%s", authctxt->user, - authctxt->style ? ":" : "", - authctxt->style ? authctxt->style : ""); -diff -up openssh-7.4p1/monitor.h.role-mls openssh-7.4p1/monitor.h ---- openssh-7.4p1/monitor.h.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/monitor.h 2016-12-23 12:19:58.588459376 +0100 -@@ -57,6 +57,10 @@ enum monitor_reqtype { - MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, - MONITOR_REQ_TERM = 50, - -+#ifdef WITH_SELINUX -+ MONITOR_REQ_AUTHROLE = 80, -+#endif -+ - MONITOR_REQ_PAM_START = 100, - MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, - MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105, -diff -up openssh-7.4p1/monitor_wrap.c.role-mls openssh-7.4p1/monitor_wrap.c ---- openssh-7.4p1/monitor_wrap.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/monitor_wrap.c 2016-12-23 12:19:58.588459376 +0100 -@@ -345,6 +345,25 @@ mm_inform_authserv(char *service, char * - buffer_free(&m); - } - -+/* Inform the privileged process about role */ -+ -+#ifdef WITH_SELINUX -+void -+mm_inform_authrole(char *role) -+{ -+ Buffer m; -+ -+ debug3("%s entering", __func__); -+ -+ buffer_init(&m); -+ buffer_put_cstring(&m, role ? role : ""); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, &m); -+ -+ buffer_free(&m); -+} -+#endif -+ - /* Do the password authentication */ - int - mm_auth_password(struct ssh *ssh, char *password) -diff -up openssh-7.4p1/monitor_wrap.h.role-mls openssh-7.4p1/monitor_wrap.h ---- openssh-7.4p1/monitor_wrap.h.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/monitor_wrap.h 2016-12-23 12:19:58.588459376 +0100 -@@ -42,6 +42,9 @@ int mm_is_monitor(void); - int mm_key_sign(struct sshkey *, u_char **, u_int *, const u_char *, u_int, - const char *); - void mm_inform_authserv(char *, char *); -+#ifdef WITH_SELINUX -+void mm_inform_authrole(char *); -+#endif - struct passwd *mm_getpwnamallow(const char *); - char *mm_auth2_read_banner(void); - int mm_auth_password(struct ssh *, char *); -diff -up openssh-7.4p1/openbsd-compat/Makefile.in.role-mls openssh-7.4p1/openbsd-compat/Makefile.in ---- openssh-7.4p1/openbsd-compat/Makefile.in.role-mls 2016-12-23 12:19:58.588459376 +0100 -+++ openssh-7.4p1/openbsd-compat/Makefile.in 2016-12-23 12:24:06.042643938 +0100 -@@ -20,7 +20,8 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf - port-linux.o \ - port-solaris.o \ - port-net.o \ -- port-uw.o -+ port-uw.o \ -+ port-linux-sshd.o - - .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -diff -up openssh-7.4p1/openbsd-compat/port-linux.c.role-mls openssh-7.4p1/openbsd-compat/port-linux.c ---- openssh-7.4p1/openbsd-compat/port-linux.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux.c 2016-12-23 12:19:58.590459369 +0100 -@@ -101,37 +101,6 @@ ssh_selinux_getctxbyname(char *pwname) - return sc; - } - --/* Set the execution context to the default for the specified user */ --void --ssh_selinux_setup_exec_context(char *pwname) --{ -- security_context_t user_ctx = NULL; -- -- if (!ssh_selinux_enabled()) -- return; -- -- debug3("%s: setting execution context", __func__); -- -- user_ctx = ssh_selinux_getctxbyname(pwname); -- if (setexeccon(user_ctx) != 0) { -- switch (security_getenforce()) { -- case -1: -- fatal("%s: security_getenforce() failed", __func__); -- case 0: -- error("%s: Failed to set SELinux execution " -- "context for %s", __func__, pwname); -- break; -- default: -- fatal("%s: Failed to set SELinux execution context " -- "for %s (in enforcing mode)", __func__, pwname); -- } -- } -- if (user_ctx != NULL) -- freecon(user_ctx); -- -- debug3("%s: done", __func__); --} -- - /* Set the TTY context for the specified user */ - void - ssh_selinux_setup_pty(char *pwname, const char *tty) -@@ -145,7 +114,11 @@ ssh_selinux_setup_pty(char *pwname, cons - - debug3("%s: setting TTY context on %s", __func__, tty); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -+ if (getexeccon(&user_ctx) != 0) { -+ error("%s: getexeccon: %s", __func__, strerror(errno)); -+ goto out; -+ } -+ - - /* XXX: should these calls fatal() upon failure in enforcing mode? */ - -diff -up openssh-7.4p1/openbsd-compat/port-linux.h.role-mls openssh-7.4p1/openbsd-compat/port-linux.h ---- openssh-7.4p1/openbsd-compat/port-linux.h.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 12:19:58.591459365 +0100 -@@ -20,9 +20,10 @@ - #ifdef WITH_SELINUX - int ssh_selinux_enabled(void); - void ssh_selinux_setup_pty(char *, const char *); --void ssh_selinux_setup_exec_context(char *); - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); -+ -+void sshd_selinux_setup_exec_context(char *); - #endif - - #ifdef LINUX_OOM_ADJUST -diff -up openssh-7.4p1/openbsd-compat/port-linux-sshd.c.role-mls openssh-7.4p1/openbsd-compat/port-linux-sshd.c ---- openssh-7.4p1/openbsd-compat/port-linux-sshd.c.role-mls 2016-12-23 12:19:58.590459369 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2016-12-23 12:19:58.590459369 +0100 -@@ -0,0 +1,424 @@ -+/* -+ * Copyright (c) 2005 Daniel Walsh -+ * Copyright (c) 2014 Petr Lautrbach -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+/* -+ * Linux-specific portability code - just SELinux support for sshd at present -+ */ -+ -+#include "includes.h" -+ -+#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST) -+#include -+#include -+#include -+#include -+ -+#include "log.h" -+#include "xmalloc.h" -+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ -+#include "servconf.h" -+#include "port-linux.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+ -+#ifdef WITH_SELINUX -+#include -+#include -+#include -+#include -+ -+#ifdef HAVE_LINUX_AUDIT -+#include -+#include -+#endif -+ -+extern ServerOptions options; -+extern Authctxt *the_authctxt; -+extern int inetd_flag; -+extern int rexeced_flag; -+ -+/* Send audit message */ -+static int -+sshd_selinux_send_audit_message(int success, security_context_t default_context, -+ security_context_t selected_context) -+{ -+ int rc=0; -+#ifdef HAVE_LINUX_AUDIT -+ char *msg = NULL; -+ int audit_fd = audit_open(); -+ security_context_t default_raw=NULL; -+ security_context_t selected_raw=NULL; -+ rc = -1; -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return 0; /* No audit support in kernel */ -+ error("Error connecting to audit system."); -+ return rc; -+ } -+ if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) { -+ error("Error translating default context."); -+ default_raw = NULL; -+ } -+ if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) { -+ error("Error translating selected context."); -+ selected_raw = NULL; -+ } -+ if (asprintf(&msg, "sshd: default-context=%s selected-context=%s", -+ default_raw ? default_raw : (default_context ? default_context: "?"), -+ selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) { -+ error("Error allocating memory."); -+ goto out; -+ } -+ if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE, -+ msg, NULL, NULL, NULL, success) <= 0) { -+ error("Error sending audit message."); -+ goto out; -+ } -+ rc = 0; -+ out: -+ free(msg); -+ freecon(default_raw); -+ freecon(selected_raw); -+ close(audit_fd); -+#endif -+ return rc; -+} -+ -+static int -+mls_range_allowed(security_context_t src, security_context_t dst) -+{ -+ struct av_decision avd; -+ int retval; -+ access_vector_t bit; -+ security_class_t class; -+ -+ debug("%s: src:%s dst:%s", __func__, src, dst); -+ class = string_to_security_class("context"); -+ if (!class) { -+ error("string_to_security_class failed to translate security class context"); -+ return 1; -+ } -+ bit = string_to_av_perm(class, "contains"); -+ if (!bit) { -+ error("string_to_av_perm failed to translate av perm contains"); -+ return 1; -+ } -+ retval = security_compute_av(src, dst, class, bit, &avd); -+ if (retval || ((bit & avd.allowed) != bit)) -+ return 0; -+ -+ return 1; -+} -+ -+static int -+get_user_context(const char *sename, const char *role, const char *lvl, -+ security_context_t *sc) { -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) { -+ /* User may have requested a level completely outside of his -+ allowed range. We get a context just for auditing as the -+ range check below will certainly fail for default context. */ -+#endif -+ if (get_default_context(sename, NULL, sc) != 0) { -+ *sc = NULL; -+ return -1; -+ } -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ } -+#endif -+ if (role != NULL && role[0]) { -+ context_t con; -+ char *type=NULL; -+ if (get_default_type(role, &type) != 0) { -+ error("get_default_type: failed to get default type for '%s'", -+ role); -+ goto out; -+ } -+ con = context_new(*sc); -+ if (!con) { -+ goto out; -+ } -+ context_role_set(con, role); -+ context_type_set(con, type); -+ freecon(*sc); -+ *sc = strdup(context_str(con)); -+ context_free(con); -+ if (!*sc) -+ return -1; -+ } -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ if (lvl != NULL && lvl[0]) { -+ /* verify that the requested range is obtained */ -+ context_t con; -+ security_context_t obtained_raw; -+ security_context_t requested_raw; -+ con = context_new(*sc); -+ if (!con) { -+ goto out; -+ } -+ context_range_set(con, lvl); -+ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) { -+ context_free(con); -+ goto out; -+ } -+ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) { -+ freecon(obtained_raw); -+ context_free(con); -+ goto out; -+ } -+ -+ debug("get_user_context: obtained context '%s' requested context '%s'", -+ obtained_raw, requested_raw); -+ if (strcmp(obtained_raw, requested_raw)) { -+ /* set the context to the real requested one but fail */ -+ freecon(requested_raw); -+ freecon(obtained_raw); -+ freecon(*sc); -+ *sc = strdup(context_str(con)); -+ context_free(con); -+ return -1; -+ } -+ freecon(requested_raw); -+ freecon(obtained_raw); -+ context_free(con); -+ } -+#endif -+ return 0; -+ out: -+ freecon(*sc); -+ *sc = NULL; -+ return -1; -+} -+ -+static void -+ssh_selinux_get_role_level(char **role, const char **level) -+{ -+ *role = NULL; -+ *level = NULL; -+ if (the_authctxt) { -+ if (the_authctxt->role != NULL) { -+ char *slash; -+ *role = xstrdup(the_authctxt->role); -+ if ((slash = strchr(*role, '/')) != NULL) { -+ *slash = '\0'; -+ *level = slash + 1; -+ } -+ } -+ } -+} -+ -+/* Return the default security context for the given username */ -+static int -+sshd_selinux_getctxbyname(char *pwname, -+ security_context_t *default_sc, security_context_t *user_sc) -+{ -+ char *sename, *lvl; -+ char *role; -+ const char *reqlvl; -+ int r = 0; -+ context_t con = NULL; -+ -+ ssh_selinux_get_role_level(&role, &reqlvl); -+ -+#ifdef HAVE_GETSEUSERBYNAME -+ if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { -+ sename = NULL; -+ lvl = NULL; -+ } -+#else -+ sename = pwname; -+ lvl = ""; -+#endif -+ -+ if (r == 0) { -+#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL -+ r = get_default_context_with_level(sename, lvl, NULL, default_sc); -+#else -+ r = get_default_context(sename, NULL, default_sc); -+#endif -+ } -+ -+ if (r == 0) { -+ /* If launched from xinetd, we must use current level */ -+ if (inetd_flag && !rexeced_flag) { -+ security_context_t sshdsc=NULL; -+ -+ if (getcon_raw(&sshdsc) < 0) -+ fatal("failed to allocate security context"); -+ -+ if ((con=context_new(sshdsc)) == NULL) -+ fatal("failed to allocate selinux context"); -+ reqlvl = context_range_get(con); -+ freecon(sshdsc); -+ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) -+ /* we actually don't change level */ -+ reqlvl = ""; -+ -+ debug("%s: current connection level '%s'", __func__, reqlvl); -+ -+ } -+ -+ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) { -+ r = get_user_context(sename, role, reqlvl, user_sc); -+ -+ if (r == 0 && reqlvl != NULL && reqlvl[0]) { -+ security_context_t default_level_sc = *default_sc; -+ if (role != NULL && role[0]) { -+ if (get_user_context(sename, role, lvl, &default_level_sc) < 0) -+ default_level_sc = *default_sc; -+ } -+ /* verify that the requested range is contained in the user range */ -+ if (mls_range_allowed(default_level_sc, *user_sc)) { -+ logit("permit MLS level %s (user range %s)", reqlvl, lvl); -+ } else { -+ r = -1; -+ error("deny MLS level %s (user range %s)", reqlvl, lvl); -+ } -+ if (default_level_sc != *default_sc) -+ freecon(default_level_sc); -+ } -+ } else { -+ *user_sc = *default_sc; -+ } -+ } -+ if (r != 0) { -+ error("%s: Failed to get default SELinux security " -+ "context for %s", __func__, pwname); -+ } -+ -+#ifdef HAVE_GETSEUSERBYNAME -+ free(sename); -+ free(lvl); -+#endif -+ -+ if (role != NULL) -+ free(role); -+ if (con) -+ context_free(con); -+ -+ return (r); -+} -+ -+/* Setup environment variables for pam_selinux */ -+static int -+sshd_selinux_setup_pam_variables(void) -+{ -+ const char *reqlvl; -+ char *role; -+ char *use_current; -+ int rv; -+ -+ debug3("%s: setting execution context", __func__); -+ -+ ssh_selinux_get_role_level(&role, &reqlvl); -+ -+ rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); -+ -+ if (inetd_flag && !rexeced_flag) { -+ use_current = "1"; -+ } else { -+ use_current = ""; -+ rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: ""); -+ } -+ -+ rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current); -+ -+ if (role != NULL) -+ free(role); -+ -+ return rv; -+} -+ -+/* Set the execution context to the default for the specified user */ -+void -+sshd_selinux_setup_exec_context(char *pwname) -+{ -+ security_context_t user_ctx = NULL; -+ int r = 0; -+ security_context_t default_ctx = NULL; -+ -+ if (!ssh_selinux_enabled()) -+ return; -+ -+ if (options.use_pam) { -+ /* do not compute context, just setup environment for pam_selinux */ -+ if (sshd_selinux_setup_pam_variables()) { -+ switch (security_getenforce()) { -+ case -1: -+ fatal("%s: security_getenforce() failed", __func__); -+ case 0: -+ error("%s: SELinux PAM variable setup failure. Continuing in permissive mode.", -+ __func__); -+ break; -+ default: -+ fatal("%s: SELinux PAM variable setup failure. Aborting connection.", -+ __func__); -+ } -+ } -+ return; -+ } -+ -+ debug3("%s: setting execution context", __func__); -+ -+ r = sshd_selinux_getctxbyname(pwname, &default_ctx, &user_ctx); -+ if (r >= 0) { -+ r = setexeccon(user_ctx); -+ if (r < 0) { -+ error("%s: Failed to set SELinux execution context %s for %s", -+ __func__, user_ctx, pwname); -+ } -+#ifdef HAVE_SETKEYCREATECON -+ else if (setkeycreatecon(user_ctx) < 0) { -+ error("%s: Failed to set SELinux keyring creation context %s for %s", -+ __func__, user_ctx, pwname); -+ } -+#endif -+ } -+ if (user_ctx == NULL) { -+ user_ctx = default_ctx; -+ } -+ if (r < 0 || user_ctx != default_ctx) { -+ /* audit just the case when user changed a role or there was -+ a failure */ -+ sshd_selinux_send_audit_message(r >= 0, default_ctx, user_ctx); -+ } -+ if (r < 0) { -+ switch (security_getenforce()) { -+ case -1: -+ fatal("%s: security_getenforce() failed", __func__); -+ case 0: -+ error("%s: SELinux failure. Continuing in permissive mode.", -+ __func__); -+ break; -+ default: -+ fatal("%s: SELinux failure. Aborting connection.", -+ __func__); -+ } -+ } -+ if (user_ctx != NULL && user_ctx != default_ctx) -+ freecon(user_ctx); -+ if (default_ctx != NULL) -+ freecon(default_ctx); -+ -+ debug3("%s: done", __func__); -+} -+ -+#endif -+#endif -+ -diff -up openssh-7.4p1/platform.c.role-mls openssh-7.4p1/platform.c ---- openssh-7.4p1/platform.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/platform.c 2016-12-23 12:19:58.591459365 +0100 -@@ -184,7 +184,7 @@ platform_setusercontext_post_groups(stru - } - #endif /* HAVE_SETPCRED */ - #ifdef WITH_SELINUX -- ssh_selinux_setup_exec_context(pw->pw_name); -+ sshd_selinux_setup_exec_context(pw->pw_name); - #endif - } - -diff -up openssh-7.4p1/sshd.c.role-mls openssh-7.4p1/sshd.c ---- openssh-7.4p1/sshd.c.role-mls 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/sshd.c 2016-12-23 12:19:58.591459365 +0100 -@@ -2053,6 +2053,9 @@ main(int ac, char **av) - restore_uid(); - } - #endif -+#ifdef WITH_SELINUX -+ sshd_selinux_setup_exec_context(authctxt->pw->pw_name); -+#endif - #ifdef USE_PAM - if (options.use_pam) { - do_pam_setcred(1); ---- openssh/configure.ac.role-mls 2017-09-27 12:54:52.926425979 +0200 -+++ openssh/configure.ac 2017-09-27 12:57:06.854224956 +0200 -@@ -4158,10 +4158,7 @@ - LIBS="$LIBS -lselinux" - ], - AC_MSG_ERROR([SELinux support requires libselinux library])) -- SSHLIBS="$SSHLIBS $LIBSELINUX" -- SSHDLIBS="$SSHDLIBS $LIBSELINUX" - AC_CHECK_FUNCS([getseuserbyname get_default_context_with_level]) -- LIBS="$save_LIBS" - fi ] - ) - AC_SUBST([SSHLIBS]) diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch index 253e0ee..0d238dd 100644 --- a/openssh-6.7p1-coverity.patch +++ b/openssh-6.7p1-coverity.patch @@ -120,7 +120,7 @@ diff -up openssh-7.4p1/serverloop.c.coverity openssh-7.4p1/serverloop.c - while (read(notify_pipe[0], &c, 1) != -1) + if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) + while (read(notify_pipe[0], &c, 1) >= 0) - debug2("notify_done: reading"); + debug2("%s: reading", __func__); } @@ -518,7 +518,7 @@ server_request_tun(void) diff --git a/openssh-6.7p1-kdf-cavs.patch b/openssh-6.7p1-kdf-cavs.patch index 4e5c7a5..f92cb50 100644 --- a/openssh-6.7p1-kdf-cavs.patch +++ b/openssh-6.7p1-kdf-cavs.patch @@ -88,8 +88,8 @@ diff -up openssh-6.8p1/ssh-cavs.c.kdf-cavs openssh-6.8p1/ssh-cavs.c +#include + +#include "xmalloc.h" -+#include "buffer.h" -+#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" +#include "cipher.h" +#include "kex.h" +#include "packet.h" diff --git a/openssh-6.7p1-ldap.patch b/openssh-6.7p1-ldap.patch index ddb3974..328b95e 100644 --- a/openssh-6.7p1-ldap.patch +++ b/openssh-6.7p1-ldap.patch @@ -157,7 +157,7 @@ diff -up openssh-6.8p1/Makefile.in.ldap openssh-6.8p1/Makefile.in ssh-xmss.o \ @@ -112,8 +115,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ - sandbox-solaris.o + sandbox-solaris.o uidswap.o -MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out -MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 @@ -356,7 +356,7 @@ diff -up openssh-6.8p1/configure.ac.ldap openssh-6.8p1/configure.ac diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c --- openssh-6.8p1/ldap-helper.c.ldap 2015-03-18 11:11:29.030801464 +0100 +++ openssh-6.8p1/ldap-helper.c 2015-03-18 11:11:29.030801464 +0100 -@@ -0,0 +1,155 @@ +@@ -0,0 +1,151 @@ +/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* + * Copyright (c) 2009 Jan F. Chadima. All rights reserved. @@ -390,6 +390,7 @@ diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c +#include "ldapbody.h" +#include +#include ++#include + +static int config_debug = 0; +int config_exclusive_config_file = 0; @@ -507,11 +508,6 @@ diff -up openssh-6.8p1/ldap-helper.c.ldap openssh-6.8p1/ldap-helper.c + ldap_do_close(); + return 0; +} -+ -+/* Ugly hack */ -+void *buffer_get_string(Buffer *b, u_int *l) { return NULL; } -+void buffer_put_string(Buffer *b, const void *f, u_int l) {} -+ diff -up openssh-6.8p1/ldap-helper.h.ldap openssh-6.8p1/ldap-helper.h --- openssh-6.8p1/ldap-helper.h.ldap 2015-03-18 11:11:29.031801462 +0100 +++ openssh-6.8p1/ldap-helper.h 2015-03-18 11:11:29.031801462 +0100 @@ -684,6 +680,7 @@ diff -up openssh-6.8p1/ldapbody.c.ldap openssh-6.8p1/ldapbody.c +#include "ldapbody.h" +#include +#include ++#include +#include "misc.h" + +#define LDAPSEARCH_FORMAT "(&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f)" @@ -1188,7 +1185,7 @@ diff -up openssh-6.8p1/ldapbody.h.ldap openssh-6.8p1/ldapbody.h diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c --- openssh-6.8p1/ldapconf.c.ldap 2015-03-18 11:11:29.032801460 +0100 +++ openssh-6.8p1/ldapconf.c 2015-03-18 11:11:29.032801460 +0100 -@@ -0,0 +1,728 @@ +@@ -0,0 +1,729 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* + * Copyright (c) 2009 Jan F. Chadima. All rights reserved. @@ -1222,6 +1219,7 @@ diff -up openssh-6.8p1/ldapconf.c.ldap openssh-6.8p1/ldapconf.c +#include "ldapconf.h" +#include +#include ++#include + +/* Keyword tokens. */ + diff --git a/openssh-7.0p1-gssKexAlgorithms.patch b/openssh-7.0p1-gssKexAlgorithms.patch index d2453d5..2ba360e 100644 --- a/openssh-7.0p1-gssKexAlgorithms.patch +++ b/openssh-7.0p1-gssKexAlgorithms.patch @@ -23,9 +23,9 @@ diff -up openssh-7.0p1/gss-genr.c.gsskexalg openssh-7.0p1/gss-genr.c ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, - const char *host, const char *client) { + const char *host, const char *client, const char *kex) { - Buffer buf; + struct sshbuf *buf; size_t i; - int oidpos, enclen; + int oidpos, enclen, r; @@ -100,6 +101,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup char deroid[2]; const EVP_MD *evp_md = EVP_md5(); @@ -35,39 +35,44 @@ diff -up openssh-7.0p1/gss-genr.c.gsskexalg openssh-7.0p1/gss-genr.c if (gss_enc2oid != NULL) { for (i = 0; gss_enc2oid[i].encoded != NULL; i++) @@ -113,6 +115,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - buffer_init(&buf); + 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)) { -@@ -131,26 +134,22 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup +@@ -131,28 +134,25 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup enclen = __b64_ntop(digest, EVP_MD_size(evp_md), encoded, EVP_MD_size(evp_md) * 2); - if (oidpos != 0) -- buffer_put_char(&buf, ','); +- if ((r = sshbuf_put_u8(buf, ',')) != 0) +- fatal("%s: buffer error: %s", __func__, ssh_err(r)); - -- buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, -- sizeof(KEX_GSS_GEX_SHA1_ID) - 1); -- buffer_append(&buf, encoded, enclen); -- buffer_put_char(&buf, ','); -- buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, -- sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); -- buffer_append(&buf, encoded, enclen); -- buffer_put_char(&buf, ','); -- buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, -- sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); -- buffer_append(&buf, encoded, enclen); +- 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)); + cp = strncpy(s, kex, strlen(kex)); + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { -+ if (buffer_len(&buf) != 0) -+ buffer_put_char(&buf, ','); -+ buffer_append(&buf, p, -+ strlen(p)); -+ buffer_append(&buf, encoded, enclen); ++ if (sshbuf_len(buf) != 0) ++ if ((r = sshbuf_put_u8(buf, ',')) != 0) ++ fatal("%s: buffer error: %s", ++ __func__, ssh_err(r)); ++ if ((r = sshbuf_put(buf, p, strlen(p))) != 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]); @@ -104,7 +109,7 @@ diff -up openssh-7.0p1/kex.c.gsskexalg openssh-7.0p1/kex.c #include "ssherr.h" #include "sshbuf.h" @@ -232,6 +232,29 @@ kex_assemble_names(const char *def, char - return 0; + return r; } +/* Validate GSS KEX method name list */ @@ -139,7 +144,7 @@ diff -up openssh-7.0p1/kex.h.gsskexalg openssh-7.0p1/kex.h @@ -173,6 +173,7 @@ int kex_names_valid(const char *); char *kex_alg_list(char); char *kex_names_cat(const char *, const char *); - int kex_assemble_names(const char *, char **); + int kex_assemble_names(char **, const char *, const char *); +int gss_kex_names_valid(const char *); int kex_new(struct ssh *, char *[PROPOSAL_MAX], struct kex **); @@ -162,7 +167,7 @@ diff -up openssh-7.0p1/readconf.c.gsskexalg openssh-7.0p1/readconf.c - oGssServerIdentity, + oGssServerIdentity, oGssKexAlgorithms, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oControlPersist, + oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, @@ -200,6 +201,7 @@ static struct { { "gssapiclientidentity", oGssClientIdentity }, @@ -263,9 +268,9 @@ diff -up openssh-7.0p1/servconf.c.gsskexalg openssh-7.0p1/servconf.c sHostKeyAlgorithms, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, -- sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, -+ sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, +- sGssKeyEx, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, ++ sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sHostCertificate, @@ -506,6 +510,7 @@ static struct { @@ -388,7 +393,7 @@ diff -up openssh-7.0p1/sshconnect2.c.gsskexalg openssh-7.0p1/sshconnect2.c +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 comma-separated pattern list. + as a list of comma-separated patterns. diff -up openssh-7.0p1/ssh-gss.h.gsskexalg openssh-7.0p1/ssh-gss.h --- openssh-7.0p1/ssh-gss.h.gsskexalg 2015-08-19 12:28:38.031518944 +0200 +++ openssh-7.0p1/ssh-gss.h 2015-08-19 12:28:38.081518832 +0200 diff --git a/openssh-7.0p1-show-more-fingerprints.patch b/openssh-7.0p1-show-more-fingerprints.patch deleted file mode 100644 index aeb3daa..0000000 --- a/openssh-7.0p1-show-more-fingerprints.patch +++ /dev/null @@ -1,324 +0,0 @@ -diff -up openssh/clientloop.c.fingerprint openssh/clientloop.c ---- openssh/clientloop.c.fingerprint 2017-09-26 15:21:22.582477729 +0200 -+++ openssh/clientloop.c 2017-09-26 15:21:22.620477932 +0200 -@@ -1854,7 +1854,7 @@ update_known_hosts(struct hostkeys_updat - if (ctx->keys_seen[i] != 2) - continue; - if ((fp = sshkey_fingerprint(ctx->keys[i], -- options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) -+ options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) - fatal("%s: sshkey_fingerprint failed", __func__); - do_log2(loglevel, "Learned new hostkey: %s %s", - sshkey_type(ctx->keys[i]), fp); -@@ -1862,7 +1862,7 @@ update_known_hosts(struct hostkeys_updat - } - for (i = 0; i < ctx->nold; i++) { - if ((fp = sshkey_fingerprint(ctx->old_keys[i], -- options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) -+ options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) - fatal("%s: sshkey_fingerprint failed", __func__); - do_log2(loglevel, "Deprecating obsolete hostkey: %s %s", - sshkey_type(ctx->old_keys[i]), fp); -@@ -1905,7 +1905,7 @@ update_known_hosts(struct hostkeys_updat - (r = hostfile_replace_entries(options.user_hostfiles[0], - ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys, - options.hash_known_hosts, 0, -- options.fingerprint_hash)) != 0) -+ options.fingerprint_hash[0])) != 0) - error("%s: hostfile_replace_entries failed: %s", - __func__, ssh_err(r)); - } -@@ -2038,7 +2038,7 @@ client_input_hostkeys(void) - error("%s: parse key: %s", __func__, ssh_err(r)); - goto out; - } -- fp = sshkey_fingerprint(key, options.fingerprint_hash, -+ fp = sshkey_fingerprint(key, options.fingerprint_hash[0], - SSH_FP_DEFAULT); - debug3("%s: received %s key %s", __func__, - sshkey_type(key), fp); -diff -up openssh/readconf.c.fingerprint openssh/readconf.c ---- openssh/readconf.c.fingerprint 2017-09-26 15:21:22.618477921 +0200 -+++ openssh/readconf.c 2017-09-26 15:21:22.621477937 +0200 -@@ -1681,16 +1681,18 @@ parse_keytypes: - goto parse_string; - - case oFingerprintHash: -- intptr = &options->fingerprint_hash; -- arg = strdelim(&s); -- if (!arg || *arg == '\0') -- fatal("%.200s line %d: Missing argument.", -- filename, linenum); -- if ((value = ssh_digest_alg_by_name(arg)) == -1) -- fatal("%.200s line %d: Invalid hash algorithm \"%s\".", -- filename, linenum, arg); -- if (*activep && *intptr == -1) -- *intptr = value; -+ if (*activep && options->num_fingerprint_hash == 0) -+ while ((arg = strdelim(&s)) != NULL && *arg != '\0') { -+ value = ssh_digest_alg_by_name(arg); -+ if (value == -1) -+ fatal("%s line %d: unknown fingerprints algorithm specs: %s.", -+ filename, linenum, arg); -+ if (options->num_fingerprint_hash >= SSH_DIGEST_MAX) -+ fatal("%s line %d: too many fingerprints algorithm specs.", -+ filename, linenum); -+ options->fingerprint_hash[ -+ options->num_fingerprint_hash++] = value; -+ } - break; - - case oUpdateHostkeys: -@@ -1917,7 +1919,7 @@ initialize_options(Options * options) - options->canonicalize_fallback_local = -1; - options->canonicalize_hostname = -1; - options->revoked_host_keys = NULL; -- options->fingerprint_hash = -1; -+ options->num_fingerprint_hash = 0; - options->update_hostkeys = -1; - options->hostbased_key_types = NULL; - options->pubkey_key_types = NULL; -@@ -2096,8 +2098,10 @@ fill_default_options(Options * options) - options->canonicalize_fallback_local = 1; - if (options->canonicalize_hostname == -1) - options->canonicalize_hostname = SSH_CANONICALISE_NO; -- if (options->fingerprint_hash == -1) -- options->fingerprint_hash = SSH_FP_HASH_DEFAULT; -+ if (options->num_fingerprint_hash == 0) { -+ options->fingerprint_hash[options->num_fingerprint_hash++] = SSH_DIGEST_SHA256; -+ options->fingerprint_hash[options->num_fingerprint_hash++] = SSH_DIGEST_MD5; -+ } - if (options->update_hostkeys == -1) - options->update_hostkeys = 0; - if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || -@@ -2474,6 +2478,17 @@ dump_cfg_strarray(OpCodes code, u_int co - } - - static void -+dump_cfg_fmtarray(OpCodes code, u_int count, int *vals) -+{ -+ u_int i; -+ -+ printf("%s", lookup_opcode_name(code)); -+ for (i = 0; i < count; i++) -+ printf(" %s", fmt_intarg(code, vals[i])); -+ printf("\n"); -+} -+ -+static void - dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals) - { - u_int i; -@@ -2549,7 +2564,6 @@ dump_client_config(Options *o, const cha - dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign); - dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings); - dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure); -- dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash); - dump_cfg_fmtint(oForwardAgent, o->forward_agent); - dump_cfg_fmtint(oForwardX11, o->forward_x11); - dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted); -@@ -2618,6 +2632,7 @@ dump_client_config(Options *o, const cha - dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles); - dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles); - dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env); -+ dump_cfg_fmtarray(oFingerprintHash, o->num_fingerprint_hash, o->fingerprint_hash); - - /* Special cases */ - -diff -up openssh/readconf.h.fingerprint openssh/readconf.h ---- openssh/readconf.h.fingerprint 2017-09-26 15:21:22.618477921 +0200 -+++ openssh/readconf.h 2017-09-26 15:21:22.621477937 +0200 -@@ -21,6 +21,7 @@ - #define MAX_SEND_ENV 256 - #define SSH_MAX_HOSTS_FILES 32 - #define MAX_CANON_DOMAINS 32 -+#define MAX_SSH_DIGESTS 32 - #define PATH_MAX_SUN (sizeof((struct sockaddr_un *)0)->sun_path) - - struct allowed_cname { -@@ -157,7 +158,8 @@ typedef struct { - - char *revoked_host_keys; - -- int fingerprint_hash; -+ int num_fingerprint_hash; -+ int fingerprint_hash[MAX_SSH_DIGESTS]; - - int update_hostkeys; /* one of SSH_UPDATE_HOSTKEYS_* */ - -diff -up openssh/ssh_config.5.fingerprint openssh/ssh_config.5 ---- openssh/ssh_config.5.fingerprint 2017-09-26 15:21:22.618477921 +0200 -+++ openssh/ssh_config.5 2017-09-26 15:21:22.621477937 +0200 -@@ -624,12 +624,13 @@ or - .Cm no - (the default). - .It Cm FingerprintHash --Specifies the hash algorithm used when displaying key fingerprints. -+Specifies the hash algorithms used when displaying key fingerprints. - Valid options are: - .Cm md5 - and --.Cm sha256 --(the default). -+.Cm sha256 . -+The default is -+.Cm "sha256 md5". - .It Cm ForwardAgent - Specifies whether the connection to the authentication agent (if any) - will be forwarded to the remote machine. -diff -up openssh/sshconnect2.c.fingerprint openssh/sshconnect2.c ---- openssh/sshconnect2.c.fingerprint 2017-09-26 15:21:22.619477926 +0200 -+++ openssh/sshconnect2.c 2017-09-26 15:21:50.677628003 +0200 -@@ -679,7 +679,7 @@ input_userauth_pk_ok(int type, u_int32_t - key->type, pktype); - goto done; - } -- if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, -+ if ((fp = sshkey_fingerprint(key, options.fingerprint_hash[0], - SSH_FP_DEFAULT)) == NULL) - goto done; - debug2("input_userauth_pk_ok: fp %s", fp); -@@ -1198,7 +1198,7 @@ sign_and_send_pubkey(Authctxt *authctxt, - int matched, ret = -1, have_sig = 1; - char *fp; - -- if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash, -+ if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash[0], - SSH_FP_DEFAULT)) == NULL) - return 0; - debug3("%s: %s %s", __func__, key_type(id->key), fp); -@@ -1620,7 +1620,7 @@ userauth_pubkey(Authctxt *authctxt) - if (id->key != NULL) { - if (try_identity(id)) { - if ((fp = sshkey_fingerprint(id->key, -- options.fingerprint_hash, -+ options.fingerprint_hash[0], - SSH_FP_DEFAULT)) == NULL) { - error("%s: sshkey_fingerprint failed", - __func__); -@@ -1914,7 +1914,7 @@ userauth_hostbased(Authctxt *authctxt) - goto out; - } - -- if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, -+ if ((fp = sshkey_fingerprint(private, options.fingerprint_hash[0], - SSH_FP_DEFAULT)) == NULL) { - error("%s: sshkey_fingerprint failed", __func__); - goto out; -diff -up openssh/sshconnect.c.fingerprint openssh/sshconnect.c ---- openssh/sshconnect.c.fingerprint 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/sshconnect.c 2017-09-26 15:21:22.622477943 +0200 -@@ -861,9 +861,9 @@ check_host_key(char *hostname, struct so - "of known hosts.", type, ip); - } else if (options.visual_host_key) { - fp = sshkey_fingerprint(host_key, -- options.fingerprint_hash, SSH_FP_DEFAULT); -+ options.fingerprint_hash[0], SSH_FP_DEFAULT); - ra = sshkey_fingerprint(host_key, -- options.fingerprint_hash, SSH_FP_RANDOMART); -+ options.fingerprint_hash[0], SSH_FP_RANDOMART); - if (fp == NULL || ra == NULL) - fatal("%s: sshkey_fingerprint fail", __func__); - logit("Host key fingerprint is %s\n%s", fp, ra); -@@ -907,12 +907,6 @@ check_host_key(char *hostname, struct so - else - snprintf(msg1, sizeof(msg1), "."); - /* The default */ -- fp = sshkey_fingerprint(host_key, -- options.fingerprint_hash, SSH_FP_DEFAULT); -- ra = sshkey_fingerprint(host_key, -- options.fingerprint_hash, SSH_FP_RANDOMART); -- if (fp == NULL || ra == NULL) -- fatal("%s: sshkey_fingerprint fail", __func__); - msg2[0] = '\0'; - if (options.verify_host_key_dns) { - if (matching_host_key_dns) -@@ -926,16 +920,28 @@ check_host_key(char *hostname, struct so - } - snprintf(msg, sizeof(msg), - "The authenticity of host '%.200s (%s)' can't be " -- "established%s\n" -- "%s key fingerprint is %s.%s%s\n%s" -+ "established%s\n", host, ip, msg1); -+ for (i = 0; i < (u_int) options.num_fingerprint_hash; i++) { -+ fp = sshkey_fingerprint(host_key, -+ options.fingerprint_hash[i], SSH_FP_DEFAULT); -+ ra = sshkey_fingerprint(host_key, -+ options.fingerprint_hash[i], SSH_FP_RANDOMART); -+ if (fp == NULL || ra == NULL) -+ fatal("%s: sshkey_fingerprint fail", __func__); -+ len = strlen(msg); -+ snprintf(msg+len, sizeof(msg)-len, -+ "%s key fingerprint is %s.%s%s\n%s", -+ type, fp, -+ options.visual_host_key ? "\n" : "", -+ options.visual_host_key ? ra : "", -+ msg2); -+ free(ra); -+ free(fp); -+ } -+ len = strlen(msg); -+ snprintf(msg+len, sizeof(msg)-len, - "Are you sure you want to continue connecting " -- "(yes/no)? ", -- host, ip, msg1, type, fp, -- options.visual_host_key ? "\n" : "", -- options.visual_host_key ? ra : "", -- msg2); -- free(ra); -- free(fp); -+ "(yes/no)? "); - if (!confirm(msg)) - goto fail; - hostkey_trusted = 1; /* user explicitly confirmed */ -@@ -1192,7 +1198,7 @@ verify_host_key(char *host, struct socka - struct sshkey *plain = NULL; - - if ((fp = sshkey_fingerprint(host_key, -- options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { -+ options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) { - error("%s: fingerprint host key: %s", __func__, ssh_err(r)); - r = -1; - goto out; -@@ -1200,7 +1206,7 @@ verify_host_key(char *host, struct socka - - if (sshkey_is_cert(host_key)) { - if ((cafp = sshkey_fingerprint(host_key->cert->signature_key, -- options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { -+ options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) { - error("%s: fingerprint CA key: %s", - __func__, ssh_err(r)); - r = -1; -@@ -1369,9 +1375,9 @@ show_other_keys(struct hostkeys *hostkey - if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) - continue; - fp = sshkey_fingerprint(found->key, -- options.fingerprint_hash, SSH_FP_DEFAULT); -+ options.fingerprint_hash[0], SSH_FP_DEFAULT); - ra = sshkey_fingerprint(found->key, -- options.fingerprint_hash, SSH_FP_RANDOMART); -+ options.fingerprint_hash[0], SSH_FP_RANDOMART); - if (fp == NULL || ra == NULL) - fatal("%s: sshkey_fingerprint fail", __func__); - logit("WARNING: %s key found for host %s\n" -@@ -1394,7 +1400,7 @@ warn_changed_key(struct sshkey *host_key - { - char *fp; - -- fp = sshkey_fingerprint(host_key, options.fingerprint_hash, -+ fp = sshkey_fingerprint(host_key, options.fingerprint_hash[0], - SSH_FP_DEFAULT); - if (fp == NULL) - fatal("%s: sshkey_fingerprint fail", __func__); -diff -up openssh/ssh-keysign.c.fingerprint openssh/ssh-keysign.c ---- openssh/ssh-keysign.c.fingerprint 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/ssh-keysign.c 2017-09-26 15:21:22.622477943 +0200 -@@ -285,7 +285,7 @@ main(int argc, char **argv) - } - } - if (!found) { -- if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, -+ if ((fp = sshkey_fingerprint(key, options.fingerprint_hash[0], - SSH_FP_DEFAULT)) == NULL) - fatal("%s: sshkey_fingerprint failed", __progname); - fatal("no matching hostkey found for key %s %s", diff --git a/openssh-7.1p1-gssapi-documentation.patch b/openssh-7.1p1-gssapi-documentation.patch index a97cbc4..db689d4 100644 --- a/openssh-7.1p1-gssapi-documentation.patch +++ b/openssh-7.1p1-gssapi-documentation.patch @@ -49,4 +49,4 @@ diff -up openssh-7.4p1/sshd_config.5.gss-docs openssh-7.4p1/sshd_config.5 +needs to be enabled in the server and also used by the client. .It Cm HostbasedAcceptedKeyTypes Specifies the key types that will be accepted for hostbased authentication - as a comma-separated pattern list. + as a list of comma-separated patterns. diff --git a/openssh-7.1p2-audit-race-condition.patch b/openssh-7.1p2-audit-race-condition.patch index d390f63..9a0d917 100644 --- a/openssh-7.1p2-audit-race-condition.patch +++ b/openssh-7.1p2-audit-race-condition.patch @@ -1,20 +1,21 @@ diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c --- openssh-7.4p1/monitor_wrap.c.audit-race 2016-12-23 16:35:52.694685771 +0100 +++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:35:52.697685772 +0100 -@@ -1107,4 +1107,48 @@ mm_audit_destroy_sensitive_data(const ch - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); - buffer_free(&m); +@@ -1107,4 +1107,50 @@ mm_audit_destroy_sensitive_data(const ch + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); + sshbuf_free(m); } + +int mm_forward_audit_messages(int fdin) +{ + u_char buf[4]; + u_int blen, msg_len; -+ Buffer m; -+ int ret = 0; ++ struct sshbuf *m; ++ int r, ret = 0; + + debug3("%s: entering", __func__); -+ buffer_init(&m); ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); + do { + blen = atomicio(read, fdin, buf, sizeof(buf)); + if (blen == 0) /* closed pipe */ @@ -28,21 +29,22 @@ diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c + msg_len = get_u32(buf); + if (msg_len > 256 * 1024) + fatal("%s: read: bad msg_len %d", __func__, msg_len); -+ buffer_clear(&m); -+ buffer_append_space(&m, msg_len); -+ if (atomicio(read, fdin, buffer_ptr(&m), msg_len) != msg_len) { ++ sshbuf_reset(m); ++ if ((r = sshbuf_reserve(m, msg_len, NULL)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if (atomicio(read, fdin, sshbuf_mutable_ptr(m), msg_len) != msg_len) { + error("%s: Failed to read the the buffer content from the child", __func__); + ret = -1; + break; + } + if (atomicio(vwrite, pmonitor->m_recvfd, buf, blen) != blen || -+ atomicio(vwrite, pmonitor->m_recvfd, buffer_ptr(&m), msg_len) != msg_len) { ++ atomicio(vwrite, pmonitor->m_recvfd, sshbuf_mutable_ptr(m), msg_len) != msg_len) { + error("%s: Failed to write the message to the monitor", __func__); + ret = -1; + break; + } + } while (1); -+ buffer_free(&m); ++ sshbuf_free(m); + return ret; +} +void mm_set_monitor_pipe(int fd) @@ -115,7 +117,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c ret = do_exec_pty(ssh, s, command); @@ -732,6 +745,20 @@ do_exec(Session *s, const char *command) */ - buffer_clear(&loginmsg); + sshbuf_reset(loginmsg); +#ifdef SSH_AUDIT_EVENTS + close(paudit[1]); diff --git a/openssh-7.2p1-gsskex.patch b/openssh-7.2p1-gsskex.patch deleted file mode 100644 index c9034e8..0000000 --- a/openssh-7.2p1-gsskex.patch +++ /dev/null @@ -1,2867 +0,0 @@ -diff -up openssh/auth2.c.gsskex openssh/auth2.c ---- openssh/auth2.c.gsskex 2017-09-27 13:54:53.539534068 +0200 -+++ openssh/auth2.c 2017-09-27 13:54:53.590534348 +0200 -@@ -72,6 +72,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -79,6 +80,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - &method_passwd, -diff -up openssh/auth2-gss.c.gsskex openssh/auth2-gss.c ---- openssh/auth2-gss.c.gsskex 2017-09-27 13:54:53.539534068 +0200 -+++ openssh/auth2-gss.c 2017-09-27 13:54:53.590534348 +0200 -@@ -31,6 +31,7 @@ - #include - - #include -+#include - - #include "xmalloc.h" - #include "key.h" -@@ -53,6 +54,41 @@ static int input_gssapi_mic(int type, u_ - 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 authenticated = 0; -+ Buffer b; -+ gss_buffer_desc mic, gssbuf; -+ u_int len; -+ -+ mic.value = packet_get_string(&len); -+ mic.length = len; -+ -+ packet_check_eom(); -+ -+ ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, -+ "gssapi-keyex"); -+ -+ gssbuf.value = buffer_ptr(&b); -+ gssbuf.length = buffer_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)); -+ -+ buffer_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) -@@ -240,7 +275,8 @@ input_gssapi_exchange_complete(int type, - - packet_check_eom(); - -- 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) -@@ -288,7 +324,8 @@ input_gssapi_mic(int type, u_int32_t ple - gssbuf.length = buffer_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"); - -@@ -310,6 +347,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, -diff -up openssh/auth.c.gsskex openssh/auth.c ---- openssh/auth.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/auth.c 2017-09-27 13:54:53.591534353 +0200 -@@ -395,6 +395,7 @@ auth_root_allowed(const char *method) - 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; -diff -up openssh/clientloop.c.gsskex openssh/clientloop.c ---- openssh/clientloop.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/clientloop.c 2017-09-27 13:54:53.591534353 +0200 -@@ -112,6 +112,10 @@ - #include "ssherr.h" - #include "hostfile.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* import options */ - extern Options options; - -@@ -1349,9 +1353,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(NULL)) { -+ debug("credentials updated - forcing rekey"); -+ need_rekeying = 1; -+ } -+#endif -+ } -+ - /* Buffer input from the connection. */ - client_process_net_input(readset); - -diff -up openssh/configure.ac.gsskex openssh/configure.ac ---- openssh/configure.ac.gsskex 2017-09-27 13:54:53.581534298 +0200 -+++ openssh/configure.ac 2017-09-27 13:54:53.592534359 +0200 -@@ -621,6 +621,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]) -diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c ---- openssh/gss-genr.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/gss-genr.c 2017-09-27 13:54:53.592534359 +0200 -@@ -40,12 +40,167 @@ - #include "buffer.h" - #include "log.h" - #include "ssh2.h" -+#include "cipher.h" -+#include "key.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) { -+ 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) { -+ Buffer buf; -+ size_t i; -+ int oidpos, enclen; -+ 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)); -+ -+ buffer_init(&buf); -+ -+ 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) -+ buffer_put_char(&buf, ','); -+ -+ buffer_append(&buf, KEX_GSS_GEX_SHA1_ID, -+ sizeof(KEX_GSS_GEX_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ buffer_put_char(&buf, ','); -+ buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, -+ sizeof(KEX_GSS_GRP1_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ buffer_put_char(&buf, ','); -+ buffer_append(&buf, KEX_GSS_GRP14_SHA1_ID, -+ sizeof(KEX_GSS_GRP14_SHA1_ID) - 1); -+ buffer_append(&buf, encoded, enclen); -+ -+ gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); -+ gss_enc2oid[oidpos].encoded = encoded; -+ oidpos++; -+ } -+ } -+ gss_enc2oid[oidpos].oid = NULL; -+ gss_enc2oid[oidpos].encoded = NULL; -+ -+ buffer_put_char(&buf, '\0'); -+ -+ mechs = xmalloc(buffer_len(&buf)); -+ buffer_get(&buf, mechs, buffer_len(&buf)); -+ buffer_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; -+} -+ - /* 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) -@@ -198,7 +353,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); - -@@ -228,8 +383,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); -@@ -237,6 +426,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(Buffer *b, const char *user, const char *service, - const char *context) -@@ -250,11 +452,16 @@ ssh_gssapi_buildmic(Buffer *b, const cha - } - - 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 && -@@ -264,6 +471,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx - 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); -@@ -273,10 +484,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 */ -diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c ---- openssh/gss-serv.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/gss-serv.c 2017-09-27 13:54:53.592534359 +0200 -@@ -45,17 +45,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}, 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; -@@ -142,6 +144,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) - { -@@ -151,7 +175,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, -@@ -277,8 +303,48 @@ OM_uint32 - ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - { - int i = 0; -+ int equal = 0; -+ gss_name_t new_name = GSS_C_NO_NAME; -+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; -+ -+ if (options.gss_store_rekey && client->used && ctx->client_creds) { -+ if (client->mech->oid.length != ctx->oid->length || -+ (memcmp(client->mech->oid.elements, -+ ctx->oid->elements, ctx->oid->length) !=0)) { -+ debug("Rekeyed credentials have different mechanism"); -+ return GSS_S_COMPLETE; -+ } -+ -+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &new_name, -+ NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ ctx->major = gss_compare_name(&ctx->minor, client->name, -+ new_name, &equal); -+ -+ if (GSS_ERROR(ctx->major)) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ if (!equal) { -+ debug("Rekeyed credentials have different name"); -+ return GSS_S_COMPLETE; -+ } -+ -+ debug("Marking rekeyed credentials for export"); - -- gss_buffer_desc ename; -+ 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; - -@@ -293,6 +359,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); -@@ -310,6 +383,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; -@@ -320,11 +395,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; -+ } - } - } - -@@ -357,7 +441,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; - -@@ -367,9 +451,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); -@@ -383,14 +469,89 @@ 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.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 -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c ---- openssh/gss-serv-krb5.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/gss-serv-krb5.c 2017-09-27 13:54:53.593534364 +0200 -@@ -121,7 +121,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) { -@@ -181,11 +181,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) -@@ -194,9 +209,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", -@@ -204,7 +286,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 -up openssh/kex.c.gsskex openssh/kex.c ---- openssh/kex.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/kex.c 2017-09-27 13:54:53.593534364 +0200 -@@ -54,6 +54,10 @@ - #include "sshbuf.h" - #include "digest.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* prototype */ - static int kex_choose_conf(struct ssh *); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); -@@ -103,6 +107,11 @@ static const struct kexalg kexalgs[] = { - { 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}, - }; - -@@ -136,6 +145,12 @@ kex_alg_by_name(const char *name) - for (k = 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; - } -diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c ---- openssh/kexgssc.c.gsskex 2017-09-27 13:54:53.593534364 +0200 -+++ openssh/kexgssc.c 2017-09-27 13:54:53.593534364 +0200 -@@ -0,0 +1,338 @@ -+/* -+ * 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 "buffer.h" -+#include "ssh2.h" -+#include "key.h" -+#include "cipher.h" -+#include "kex.h" -+#include "log.h" -+#include "packet.h" -+#include "dh.h" -+#include "digest.h" -+ -+#include "ssh-gss.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; -+ 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 dh->pub_key */ -+ dh_gen_key(dh, ssh->kex->we_need * 8); -+ -+ /* 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(dh->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 ((int)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, -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ dh->pub_key, /* e */ -+ dh_server_pub, /* f */ -+ shared_secret, /* K */ -+ hash, &hashlen -+ ); -+ break; -+ case KEX_GSS_GEX_SHA1: -+ kexgex_hash( -+ ssh->kex->hash_alg, -+ ssh->kex->client_version_string, -+ ssh->kex->server_version_string, -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ (serverhostkey ? serverhostkey : empty), slen, -+ min, nbits, max, -+ dh->p, dh->g, -+ dh->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 */ -diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c ---- openssh/kexgsss.c.gsskex 2017-09-27 13:54:53.593534364 +0200 -+++ openssh/kexgsss.c 2017-09-27 13:54:53.593534364 +0200 -@@ -0,0 +1,297 @@ -+/* -+ * 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 "buffer.h" -+#include "ssh2.h" -+#include "key.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" -+ -+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; -+ -+ /* 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"); -+ -+ packet_start(SSH2_MSG_KEXGSS_GROUP); -+ packet_put_bignum2(dh->p); -+ packet_put_bignum2(dh->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(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); -+ -+ 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, -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ NULL, 0, /* Change this if we start sending host keys */ -+ dh_client_pub, dh->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, -+ buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), -+ buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), -+ NULL, 0, -+ cmin, nbits, cmax, -+ dh->p, dh->g, -+ dh_client_pub, -+ dh->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(dh->pub_key); -+ packet_put_string(msg_tok.value,msg_tok.length); -+ -+ if (send_tok.length != 0) { -+ packet_put_char(1); /* true */ -+ packet_put_string(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 */ -diff -up openssh/kex.h.gsskex openssh/kex.h ---- openssh/kex.h.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/kex.h 2017-09-27 13:54:53.593534364 +0200 -@@ -99,6 +99,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 - }; - -@@ -147,6 +152,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; -@@ -196,6 +207,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, -diff -up openssh/Makefile.in.gsskex openssh/Makefile.in ---- openssh/Makefile.in.gsskex 2017-09-27 13:54:53.588534337 +0200 -+++ openssh/Makefile.in 2017-09-27 13:54:53.594534370 +0200 -@@ -91,6 +91,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - readpass.o ttymodes.o xmalloc.o addrmatch.o \ - atomicio.o key.o dispatch.o mac.o uidswap.o uuencode.o misc.o utf8.o \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ -+ kexgssc.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ - ssh-pkcs11.o smult_curve25519_ref.o \ - poly1305.o chacha.o cipher-chachapoly.o \ -@@ -112,7 +113,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw - auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor.o monitor_wrap.o auth-krb5.o \ -- auth2-gss.o gss-serv.o gss-serv-krb5.o \ -+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff -up openssh/monitor.c.gsskex openssh/monitor.c ---- openssh/monitor.c.gsskex 2017-09-27 13:54:53.541534079 +0200 -+++ openssh/monitor.c 2017-09-27 13:54:53.594534370 +0200 -@@ -160,6 +160,8 @@ int mm_answer_gss_setup_ctx(int, Buffer - int mm_answer_gss_accept_ctx(int, Buffer *); - int mm_answer_gss_userok(int, Buffer *); - int mm_answer_gss_checkmic(int, Buffer *); -+int mm_answer_gss_sign(int, Buffer *); -+int mm_answer_gss_updatecreds(int, Buffer *); - #endif - - #ifdef SSH_AUDIT_EVENTS -@@ -236,11 +238,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 -@@ -308,6 +317,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) { -@@ -414,6 +427,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); -@@ -1656,6 +1673,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; -@@ -1744,7 +1768,7 @@ mm_answer_gss_setup_ctx(int sock, Buffer - OM_uint32 major; - u_int len; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - - goid.elements = buffer_get_string(m, &len); -@@ -1774,7 +1798,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe - OM_uint32 flags = 0; /* GSI needs this */ - u_int len; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - - in.value = buffer_get_string(m, &len); -@@ -1794,6 +1818,7 @@ mm_answer_gss_accept_ctx(int sock, Buffe - 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); - } -@@ -1805,7 +1830,7 @@ mm_answer_gss_checkmic(int sock, Buffer - OM_uint32 ret; - u_int len; - -- if (!options.gss_authentication) -+ if (!options.gss_authentication && !options.gss_keyex) - fatal("%s: GSSAPI authentication not enabled", __func__); - - gssbuf.value = buffer_get_string(m, &len); -@@ -1835,10 +1860,11 @@ mm_answer_gss_userok(int sock, Buffer *m - int 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); - - buffer_clear(m); - buffer_put_int(m, authenticated); -@@ -1854,5 +1880,71 @@ mm_answer_gss_userok(int sock, Buffer *m - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } -+ -+int -+mm_answer_gss_sign(int socket, Buffer *m) -+{ -+ gss_buffer_desc data; -+ gss_buffer_desc hash = GSS_C_EMPTY_BUFFER; -+ OM_uint32 major, minor; -+ u_int len; -+ -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ -+ data.value = buffer_get_string(m, &len); -+ data.length = len; -+ 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); -+ -+ buffer_clear(m); -+ buffer_put_int(m, major); -+ buffer_put_string(m, hash.value, hash.length); -+ -+ 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, Buffer *m) { -+ ssh_gssapi_ccache store; -+ int ok; -+ -+ store.envvar = buffer_get_string(m, NULL); -+ store.envval = buffer_get_string(m, NULL); -+ -+ ok = ssh_gssapi_update_creds(&store); -+ -+ free(store.envvar); -+ free(store.envval); -+ -+ buffer_clear(m); -+ buffer_put_int(m, ok); -+ -+ mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); -+ -+ return(0); -+} -+ - #endif /* GSSAPI */ - -diff -up openssh/monitor.h.gsskex openssh/monitor.h ---- openssh/monitor.h.gsskex 2017-09-27 13:54:53.541534079 +0200 -+++ openssh/monitor.h 2017-09-27 13:54:53.594534370 +0200 -@@ -60,6 +60,8 @@ enum monitor_reqtype { - #ifdef WITH_SELINUX - MONITOR_REQ_AUTHROLE = 80, - #endif -+ MONITOR_REQ_GSSSIGN = 82, MONITOR_ANS_GSSSIGN = 83, -+ MONITOR_REQ_GSSUPCREDS = 84, MONITOR_ANS_GSSUPCREDS = 85, - - MONITOR_REQ_PAM_START = 100, - MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, -diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c ---- openssh/monitor_wrap.c.gsskex 2017-09-27 13:54:53.542534084 +0200 -+++ openssh/monitor_wrap.c 2017-09-27 13:54:53.595534375 +0200 -@@ -950,7 +950,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss - } - - int --mm_ssh_gssapi_userok(char *user) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw) - { - Buffer m; - int authenticated = 0; -@@ -967,5 +967,49 @@ 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) -+{ -+ Buffer m; -+ OM_uint32 major; -+ u_int len; -+ -+ buffer_init(&m); -+ buffer_put_string(&m, data->value, data->length); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m); -+ -+ major = buffer_get_int(&m); -+ hash->value = buffer_get_string(&m, &len); -+ hash->length = len; -+ -+ buffer_free(&m); -+ -+ return(major); -+} -+ -+int -+mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) -+{ -+ Buffer m; -+ int ok; -+ -+ buffer_init(&m); -+ -+ buffer_put_cstring(&m, store->envvar ? store->envvar : ""); -+ buffer_put_cstring(&m, store->envval ? store->envval : ""); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUPCREDS, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUPCREDS, &m); -+ -+ ok = buffer_get_int(&m); -+ -+ buffer_free(&m); -+ -+ return (ok); -+} -+ - #endif /* GSSAPI */ - -diff -up openssh/monitor_wrap.h.gsskex openssh/monitor_wrap.h ---- openssh/monitor_wrap.h.gsskex 2017-09-27 13:54:53.542534084 +0200 -+++ openssh/monitor_wrap.h 2017-09-27 13:54:53.595534375 +0200 -@@ -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 -diff -up openssh/readconf.c.gsskex openssh/readconf.c ---- openssh/readconf.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/readconf.c 2017-09-27 13:54:53.596534381 +0200 -@@ -160,6 +160,8 @@ typedef enum { - oClearAllForwardings, oNoHostAuthenticationForLocalhost, - oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, - oAddressFamily, oGssAuthentication, oGssDelegateCreds, -+ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, -+ oGssServerIdentity, - oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oControlPersist, - oHashKnownHosts, -@@ -199,10 +201,19 @@ 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 }, -+ { "gssapirenewalforcesrekey", oUnsupported }, - #endif - #ifdef ENABLE_PKCS11 - { "smartcarddevice", oPKCS11Provider }, -@@ -976,10 +987,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; -@@ -1790,7 +1821,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; -@@ -1930,8 +1966,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) -diff -up openssh/readconf.h.gsskex openssh/readconf.h ---- openssh/readconf.h.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/readconf.h 2017-09-27 13:54:53.596534381 +0200 -@@ -42,7 +42,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. */ -diff -up openssh/regress/cert-hostkey.sh.gsskex openssh/regress/cert-hostkey.sh ---- openssh/regress/cert-hostkey.sh.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/regress/cert-hostkey.sh 2017-09-27 13:54:53.596534381 +0200 -@@ -59,7 +59,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" -diff -up openssh/regress/cert-userkey.sh.gsskex openssh/regress/cert-userkey.sh ---- openssh/regress/cert-userkey.sh.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/regress/cert-userkey.sh 2017-09-27 13:54:53.596534381 +0200 -@@ -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 - PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512" -diff -up openssh/regress/kextype.sh.gsskex openssh/regress/kextype.sh ---- openssh/regress/kextype.sh.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/regress/kextype.sh 2017-09-27 13:54:53.596534381 +0200 -@@ -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 -diff -up openssh/regress/rekey.sh.gsskex openssh/regress/rekey.sh ---- openssh/regress/rekey.sh.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/regress/rekey.sh 2017-09-27 13:54:53.596534381 +0200 -@@ -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 -diff -up openssh/servconf.c.gsskex openssh/servconf.c ---- openssh/servconf.c.gsskex 2017-09-27 13:54:53.581534298 +0200 -+++ openssh/servconf.c 2017-09-27 13:54:53.597534386 +0200 -@@ -113,8 +113,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; -@@ -269,10 +271,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) -@@ -413,7 +419,7 @@ typedef enum { - sHostKeyAlgorithms, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -- sAcceptEnv, sPermitTunnel, -+ sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, - sHostCertificate, -@@ -488,11 +494,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 }, -@@ -1257,6 +1269,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; -@@ -1265,6 +1281,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; -@@ -2302,6 +2322,9 @@ 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); - #endif - dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); - dump_cfg_fmtint(sKbdInteractiveAuthentication, -diff -up openssh/servconf.h.gsskex openssh/servconf.h ---- openssh/servconf.h.gsskex 2017-09-27 13:54:53.582534304 +0200 -+++ openssh/servconf.h 2017-09-27 13:54:53.597534386 +0200 -@@ -119,8 +119,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 */ -diff -up openssh/ssh_config.5.gsskex openssh/ssh_config.5 ---- openssh/ssh_config.5.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/ssh_config.5 2017-09-27 13:54:53.597534386 +0200 -@@ -720,10 +720,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 -diff -up openssh/ssh_config.gsskex openssh/ssh_config ---- openssh/ssh_config.gsskex 2017-09-27 13:54:53.571534243 +0200 -+++ openssh/ssh_config 2017-09-27 13:54:53.597534386 +0200 -@@ -24,6 +24,8 @@ - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -diff -up openssh/sshconnect2.c.gsskex openssh/sshconnect2.c ---- openssh/sshconnect2.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/sshconnect2.c 2017-09-27 13:57:23.418358207 +0200 -@@ -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,34 @@ 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 -+ 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); -+ 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); -@@ -192,6 +335,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); -@@ -212,11 +366,31 @@ ssh_kex2(char *host, struct sockaddr *ho - kex->kex[KEX_ECDH_SHA2] = kexecdh_client; - # endif - #endif -+#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->kex[KEX_C25519_SHA256] = kexc25519_client; - 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 */ -@@ -311,6 +485,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 *); -@@ -327,6 +502,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, -@@ -654,19 +834,31 @@ userauth_gssapi(Authctxt *authctxt) - static u_int mech = 0; - OM_uint32 min; - int 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++; -@@ -763,8 +955,8 @@ input_gssapi_response(int type, u_int32_ - { - Authctxt *authctxt = ssh->authctxt; - Gssctxt *gssctxt; -- int oidlen; -- char *oidv; -+ u_int oidlen; -+ u_char *oidv; - - if (authctxt == NULL) - fatal("input_gssapi_response: no authentication context"); -@@ -877,6 +1069,48 @@ input_gssapi_error(int type, u_int32_t p - free(lang); - return 0; - } -+ -+int -+userauth_gsskeyex(Authctxt *authctxt) -+{ -+ Buffer b; -+ 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); -+ } -+ -+ ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service, -+ "gssapi-keyex"); -+ -+ gssbuf.value = buffer_ptr(&b); -+ gssbuf.length = buffer_len(&b); -+ -+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { -+ buffer_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(); -+ -+ buffer_free(&b); -+ gss_release_buffer(&ms, &mic); -+ -+ return (1); -+} -+ - #endif /* GSSAPI */ - - int -diff -up openssh/sshd.c.gsskex openssh/sshd.c ---- openssh/sshd.c.gsskex 2017-09-27 13:54:53.584534315 +0200 -+++ openssh/sshd.c 2017-09-27 13:54:53.600534403 +0200 -@@ -530,7 +530,7 @@ privsep_preauth_child(void) - - #ifdef GSSAPI - /* Cache supported mechanism OIDs for later use */ -- if (options.gss_authentication) -+ if (options.gss_authentication || options.gss_keyex) - ssh_gssapi_prepare_supported_oids(); - #endif - -@@ -871,8 +871,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); - } - -@@ -1738,7 +1739,8 @@ main(int ac, char **av) - key ? "private" : "agent", i, sshkey_ssh_name(pubkey), fp); - free(fp); - } -- 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); - } -@@ -2203,6 +2205,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)); -@@ -2220,6 +2264,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; -diff -up openssh/sshd_config.5.gsskex openssh/sshd_config.5 ---- openssh/sshd_config.5.gsskex 2017-09-27 13:54:53.582534304 +0200 -+++ openssh/sshd_config.5 2017-09-27 13:54:53.600534403 +0200 -@@ -638,6 +638,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. -@@ -652,6 +657,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 comma-separated pattern list. -diff -up openssh/sshd_config.gsskex openssh/sshd_config ---- openssh/sshd_config.gsskex 2017-09-27 13:54:53.585534320 +0200 -+++ openssh/sshd_config 2017-09-27 13:54:53.601534408 +0200 -@@ -86,6 +86,8 @@ ChallengeResponseAuthentication no - # GSSAPI options - GSSAPIAuthentication yes - GSSAPICleanupCredentials no -+#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 -up openssh/ssh-gss.h.gsskex openssh/ssh-gss.h ---- openssh/ssh-gss.h.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/ssh-gss.h 2017-09-27 13:54:53.601534408 +0200 -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.12 2017/06/24 06:34:38 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,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); -@@ -119,17 +136,33 @@ void ssh_gssapi_build_ctx(Gssctxt **); - void ssh_gssapi_delete_ctx(Gssctxt **); - OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_buildmic(Buffer *, 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 *); -+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 */ -diff -up openssh/sshkey.c.gsskex openssh/sshkey.c ---- openssh/sshkey.c.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/sshkey.c 2017-09-27 13:54:53.601534408 +0200 -@@ -112,6 +112,7 @@ static const struct keytype keytypes[] = - # endif /* OPENSSL_HAS_NISTP521 */ - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+ { "null", "null", KEY_NULL, 0, 0, 1 }, - { NULL, NULL, -1, -1, 0, 0 } - }; - -diff -up openssh/sshkey.h.gsskex openssh/sshkey.h ---- openssh/sshkey.h.gsskex 2017-09-25 01:48:10.000000000 +0200 -+++ openssh/sshkey.h 2017-09-27 13:54:53.602534414 +0200 -@@ -61,6 +61,7 @@ enum sshkey_types { - KEY_ED25519_CERT, - KEY_XMSS, - KEY_XMSS_CERT, -+ KEY_NULL, - KEY_UNSPEC - }; - diff --git a/openssh-7.2p2-UsePAM-UseLogin-warning.patch b/openssh-7.2p2-UsePAM-UseLogin-warning.patch deleted file mode 100644 index b3038ea..0000000 --- a/openssh-7.2p2-UsePAM-UseLogin-warning.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/sshd.c b/sshd.c ---- a/sshd.c -+++ b/sshd.c -@@ -1701,6 +1701,10 @@ main(int ac, char **av) - parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, - &cfg, NULL); - -+ /* 'UsePAM no' is not supported in Fedora */ -+ if (! options.use_pam) -+ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems."); -+ - seed_rng(); - - /* Fill in default values for those options not explicitly set. */ -diff --git a/sshd_config b/sshd_config ---- a/sshd_config -+++ b/sshd_config -@@ -101,6 +101,8 @@ GSSAPICleanupCredentials no - # If you just want the PAM account and session checks to run without - # PAM authentication, then enable this but set PasswordAuthentication - # and ChallengeResponseAuthentication to 'no'. -+# WARNING: 'UsePAM no' is not supported in Fedora and may cause several -+# problems. - UsePAM yes - - #AllowAgentForwarding yes diff --git a/openssh-7.3p1-openssl-1.1.0.patch b/openssh-7.3p1-openssl-1.1.0.patch index dadde28..42ede48 100644 --- a/openssh-7.3p1-openssl-1.1.0.patch +++ b/openssh-7.3p1-openssl-1.1.0.patch @@ -136,7 +136,7 @@ diff -up openssh/dh.c.openssl openssh/dh.c need > INT_MAX / 2 || 2 * need > pbits) return SSH_ERR_INVALID_ARGUMENT; if (need < 256) -@@ -271,10 +275,11 @@ dh_gen_key(DH *dh, int need) +@@ -271,11 +275,11 @@ dh_gen_key(DH *dh, int need) * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), * so double requested need here. */ @@ -144,6 +144,7 @@ diff -up openssh/dh.c.openssl openssh/dh.c - if (DH_generate_key(dh) == 0 || - !dh_pub_is_valid(dh, dh->pub_key)) { - BN_clear_free(dh->priv_key); +- dh->priv_key = NULL; + DH_set_length(dh, MINIMUM(need * 2, pbits - 1)); + if (DH_generate_key(dh) == 0) + return SSH_ERR_LIBCRYPTO_ERROR; @@ -300,8 +301,8 @@ diff -up openssh/gss-genr.c.openssl openssh/gss-genr.c if (gss_enc2oid != NULL) { @@ -113,6 +113,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - - buffer_init(&buf); + if ((buf = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + md = EVP_MD_CTX_new(); oidpos = 0; @@ -452,7 +453,7 @@ diff -up openssh/kexdhs.c.openssl openssh/kexdhs.c hash, &hashlen)) != 0) goto out; @@ -197,7 +203,7 @@ input_kex_dh_init(int type, u_int32_t se - /* send server hostkey, DH pubkey 'f' and singed H */ + /* send server hostkey, DH pubkey 'f' and signed H */ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 || (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || - (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ @@ -599,7 +600,7 @@ diff -up openssh/kexgexs.c.openssl openssh/kexgexs.c hash, &hashlen)) != 0) goto out; @@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_ - /* send server hostkey, DH pubkey 'f' and singed H */ + /* send server hostkey, DH pubkey 'f' and signed H */ if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || - (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ @@ -636,8 +637,8 @@ diff -up openssh/kexgssc.c.openssl openssh/kexgssc.c } else { packet_start(SSH2_MSG_KEXGSS_CONTINUE); @@ -282,13 +284,14 @@ kexgss_client(struct ssh *ssh) { - buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), - buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), (serverhostkey ? serverhostkey : empty), slen, - dh->pub_key, /* e */ + pub_key, /* e */ @@ -652,7 +653,7 @@ diff -up openssh/kexgssc.c.openssl openssh/kexgssc.c ssh->kex->hash_alg, ssh->kex->client_version_string, @@ -297,8 +300,8 @@ kexgss_client(struct ssh *ssh) { - buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), (serverhostkey ? serverhostkey : empty), slen, min, nbits, max, - dh->p, dh->g, @@ -695,8 +696,8 @@ diff -up openssh/kexgsss.c.openssl openssh/kexgsss.c switch (ssh->kex->kex_type) { case KEX_GSS_GRP1_SHA1: @@ -232,7 +235,7 @@ kexgss_server(struct ssh *ssh) - buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), - buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), + 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, dh->pub_key, shared_secret, + dh_client_pub, pub_key, shared_secret, @@ -704,7 +705,7 @@ diff -up openssh/kexgsss.c.openssl openssh/kexgsss.c ); break; @@ -244,9 +247,9 @@ kexgss_server(struct ssh *ssh) - buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), NULL, 0, cmin, nbits, cmax, - dh->p, dh->g, @@ -1241,14 +1242,14 @@ diff -up openssh/monitor.c.openssl openssh/monitor.c + const BIGNUM *p, *g; + + DH_get0_pqg(dh, &p, NULL, &g); - buffer_put_char(m, 1); -- buffer_put_bignum2(m, dh->p); -- buffer_put_bignum2(m, dh->g); -+ buffer_put_bignum2(m, p); -+ buffer_put_bignum2(m, g); + if ((r = sshbuf_put_u8(m, 1)) != 0 || +- (r = sshbuf_put_bignum2(m, dh->p)) != 0 || +- (r = sshbuf_put_bignum2(m, dh->g)) != 0) ++ (r = sshbuf_put_bignum2(m, p)) != 0 || ++ (r = sshbuf_put_bignum2(m, g)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); DH_free(dh); - } diff -up openssh/openbsd-compat/openssl-compat.c.openssl openssh/openbsd-compat/openssl-compat.c --- openssh/openbsd-compat/openssl-compat.c.openssl 2017-09-19 06:26:43.000000000 +0200 +++ openssh/openbsd-compat/openssl-compat.c 2017-09-26 13:19:31.799249709 +0200 @@ -1404,17 +1405,6 @@ diff -up openssh/regress/unittests/sshkey/test_sshkey.c.openssl openssh/regress/ TEST_DONE(); TEST_START("equal KEY_DSA/demoted KEY_DSA"); -diff -up openssh/sshconnect2.c.openssl openssh/sshconnect2.c ---- openssh/sshconnect2.c.openssl 2017-09-26 13:19:31.786249629 +0200 -+++ openssh/sshconnect2.c 2017-09-26 13:19:31.800249715 +0200 -@@ -306,6 +306,7 @@ ssh_kex2(char *host, struct sockaddr *ho - packet_send(); - packet_write_wait(); - #endif -+ /* XXX free myproposal ?? */ - } - - /* diff -up openssh/ssh.c.openssl openssh/ssh.c --- openssh/ssh.c.openssl 2017-09-26 13:19:31.786249629 +0200 +++ openssh/ssh.c 2017-09-26 13:19:31.800249715 +0200 diff --git a/openssh-7.3p1-x11-max-displays.patch b/openssh-7.3p1-x11-max-displays.patch index b36671d..94dac8f 100644 --- a/openssh-7.3p1-x11-max-displays.patch +++ b/openssh-7.3p1-x11-max-displays.patch @@ -10,8 +10,8 @@ diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c +/* Minimum port number for X11 forwarding */ +#define X11_PORT_MIN 6000 - /* - * Data structure for storing which hosts are permitted for forward requests. + /* Per-channel callback for pre/post select() actions */ + typedef void chan_fn(struct ssh *, Channel *c, @@ -4228,7 +4228,7 @@ channel_send_window_changes(void) */ int diff --git a/openssh-7.5p1-gssapi-kex-with-ec.patch b/openssh-7.5p1-gssapi-kex-with-ec.patch index 437cce6..1e2d650 100644 --- a/openssh-7.5p1-gssapi-kex-with-ec.patch +++ b/openssh-7.5p1-gssapi-kex-with-ec.patch @@ -91,7 +91,7 @@ index 132df8b5..ed23f06d 100644 + case KEX_GSS_GRP16_SHA512: kex_dh_hash(ssh->kex->hash_alg, ssh->kex->client_version_string, ssh->kex->server_version_string, - buffer_ptr(ssh->kex->my), buffer_len(ssh->kex->my), + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), diff --git a/kexgsss.c b/kexgsss.c index 82a715cc..b7da8823 100644 --- a/kexgsss.c @@ -117,7 +117,7 @@ index 82a715cc..b7da8823 100644 + case KEX_GSS_GRP16_SHA512: kex_dh_hash(ssh->kex->hash_alg, ssh->kex->client_version_string, ssh->kex->server_version_string, - buffer_ptr(ssh->kex->peer), buffer_len(ssh->kex->peer), + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), diff --git a/monitor.c b/monitor.c index 17046936..d6bc7ac7 100644 --- a/monitor.c @@ -674,8 +674,8 @@ index ed23f06d..bdb3109a 100644 + kex_c25519_hash( + kex->hash_alg, + kex->client_version_string, kex->server_version_string, -+ buffer_ptr(kex->my), buffer_len(kex->my), -+ buffer_ptr(kex->peer), buffer_len(kex->peer), ++ sshbuf_ptr(kex->my), sshbuf_len(kex->my), ++ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + kex->c25519_client_pubkey, server_pub, + sshbuf_ptr(c25519_shared_secret), sshbuf_len(c25519_shared_secret), @@ -1008,8 +1008,8 @@ index b7da8823..a7c42803 100644 + kex_c25519_hash( + kex->hash_alg, + kex->client_version_string, kex->server_version_string, -+ buffer_ptr(kex->peer), buffer_len(kex->peer), -+ buffer_ptr(kex->my), buffer_len(kex->my), ++ sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), ++ sshbuf_ptr(kex->my), sshbuf_len(kex->my), + NULL, 0, + client_pub, c25519_server_pubkey, + sshbuf_ptr(c25519_shared_secret), sshbuf_len(c25519_shared_secret), @@ -1117,8 +1117,8 @@ index d6bc7ac7..b11616c8 100644 kex->load_host_public_key=&get_hostkey_public_by_type; @@ -1867,7 +1869,8 @@ mm_answer_gss_sign(int socket, Buffer *m) - data.value = buffer_get_string(m, &len); - data.length = len; + 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) + /* Lengths of SHA-1, SHA-256 and SHA-512 hashes that are used */ + if (data.length != 20 && data.length != 32 && data.length != 64) diff --git a/openssh-7.5p1-sandbox.patch b/openssh-7.5p1-sandbox.patch index 7cdb0aa..b761962 100644 --- a/openssh-7.5p1-sandbox.patch +++ b/openssh-7.5p1-sandbox.patch @@ -20,8 +20,8 @@ index ca75cc7..6e7de31 100644 +#if defined(__NR_flock) && defined(__s390__) + SC_ALLOW(__NR_flock), +#endif - #ifdef __NR_getpgid - SC_ALLOW(__NR_getpgid), + #ifdef __NR_geteuid + SC_ALLOW(__NR_geteuid), #endif @@ -178,6 +181,9 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_gettimeofday @@ -30,8 +30,8 @@ index ca75cc7..6e7de31 100644 +#if defined(__NR_ipc) && defined(__s390__) + SC_ALLOW(__NR_ipc), +#endif - #ifdef __NR_madvise - SC_ALLOW(__NR_madvise), + #ifdef __NR_getuid + SC_ALLOW(__NR_getuid), #endif -- 1.9.1 diff --git a/openssh-7.6p1-audit.patch b/openssh-7.6p1-audit.patch index c6e30a4..e184894 100644 --- a/openssh-7.6p1-audit.patch +++ b/openssh-7.6p1-audit.patch @@ -77,16 +77,8 @@ diff -up openssh-7.6p1/audit-bsm.c.audit openssh-7.6p1/audit-bsm.c diff -up openssh-7.6p1/audit.c.audit openssh-7.6p1/audit.c --- openssh-7.6p1/audit.c.audit 2017-10-02 21:34:26.000000000 +0200 +++ openssh-7.6p1/audit.c 2017-10-04 17:18:32.834505048 +0200 -@@ -26,6 +26,7 @@ - - #include - #include -+#include - - #ifdef SSH_AUDIT_EVENTS - @@ -34,6 +35,12 @@ - #include "key.h" + #include "log.h" #include "hostfile.h" #include "auth.h" +#include "ssh-gss.h" @@ -127,7 +119,7 @@ diff -up openssh-7.6p1/audit.c.audit openssh-7.6p1/audit.c } +void -+audit_key(int host_user, int *rv, const Key *key) ++audit_key(int host_user, int *rv, const struct sshkey *key) +{ + char *fp; + @@ -268,7 +260,7 @@ diff -up openssh-7.6p1/audit.h.audit openssh-7.6p1/audit.h # define _SSH_AUDIT_H #include "loginrec.h" -+#include "key.h" ++#include "sshkey.h" enum ssh_audit_event_type { SSH_LOGIN_EXCEED_MAXTRIES, @@ -296,7 +288,7 @@ diff -up openssh-7.6p1/audit.h.audit openssh-7.6p1/audit.h +void audit_end_command(int, const char *); ssh_audit_event_t audit_classify_auth(const char *); +int audit_keyusage(int, char *, int); -+void audit_key(int, int *, const Key *); ++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); @@ -313,7 +305,7 @@ diff -up openssh-7.6p1/audit-linux.c.audit openssh-7.6p1/audit-linux.c #include "log.h" #include "audit.h" -+#include "key.h" ++#include "sshkey.h" +#include "hostfile.h" +#include "auth.h" +#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ @@ -596,8 +588,8 @@ diff -up openssh-7.6p1/audit-linux.c.audit openssh-7.6p1/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(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]; @@ -786,11 +778,11 @@ diff -up openssh-7.6p1/auth2-pubkey.c.audit openssh-7.6p1/auth2-pubkey.c /* test for correct signature */ authenticated = 0; if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && -- PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), -+ PRIVSEP(user_key_verify(key, sig, slen, sshbuf_ptr(b), - sshbuf_len(b), NULL, ssh->compat)) == 0) { - authenticated = 1; - } +- PRIVSEP(sshkey_verify(key, sig, slen, ++ PRIVSEP(user_key_verify(key, sig, slen, + sshbuf_ptr(b), sshbuf_len(b), + (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, + ssh->compat)) == 0) { @@ -250,6 +250,19 @@ done: return authenticated; } @@ -882,7 +874,7 @@ diff -up openssh-7.6p1/cipher.c.audit openssh-7.6p1/cipher.c - static const struct sshcipher ciphers[] = { #ifdef WITH_OPENSSL - { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, + #ifndef OPENSSL_NO_DES @@ -409,7 +409,7 @@ cipher_get_length(struct sshcipher_ctx * void cipher_free(struct sshcipher_ctx *cc) @@ -1032,17 +1024,6 @@ diff -up openssh-7.6p1/kex.h.audit openssh-7.6p1/kex.h 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 *); -diff -up openssh-7.6p1/key.h.audit openssh-7.6p1/key.h ---- openssh-7.6p1/key.h.audit 2017-10-02 21:34:26.000000000 +0200 -+++ openssh-7.6p1/key.h 2017-10-04 17:18:32.836505059 +0200 -@@ -43,6 +43,7 @@ typedef struct sshkey Key; - #define key_ssh_name_plain sshkey_ssh_name_plain - #define key_type_from_name sshkey_type_from_name - #define key_is_cert sshkey_is_cert -+#define key_is_private sshkey_is_private - #define key_type_plain sshkey_type_plain - #endif - diff -up openssh-7.6p1/mac.c.audit openssh-7.6p1/mac.c --- openssh-7.6p1/mac.c.audit 2017-10-02 21:34:26.000000000 +0200 +++ openssh-7.6p1/mac.c 2017-10-04 17:18:32.836505059 +0200 @@ -1102,7 +1083,7 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c #include "ssherr.h" @@ -117,6 +118,8 @@ extern Buffer auth_debug; - extern Buffer loginmsg; + extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ +extern void destroy_sensitive_data(int); @@ -1112,13 +1093,13 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c @@ -167,6 +170,11 @@ int mm_answer_gss_updatecreds(int, Buffe #ifdef SSH_AUDIT_EVENTS - int mm_answer_audit_event(int, Buffer *); - int mm_answer_audit_command(int, Buffer *); -+int mm_answer_audit_end_command(int, Buffer *); -+int mm_answer_audit_unsupported_body(int, Buffer *); -+int mm_answer_audit_kex_body(int, Buffer *); -+int mm_answer_audit_session_key_free_body(int, Buffer *); -+int mm_answer_audit_server_key_free(int, Buffer *); + 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 *); #endif static int monitor_read_log(struct monitor *); @@ -1145,16 +1126,18 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c #endif {0, 0, NULL} }; -@@ -1396,7 +1413,9 @@ mm_answer_keyverify(int sock, struct ssh +@@ -1396,8 +1413,10 @@ mm_answer_keyverify(int sock, struct ssh char *sigalg; size_t signaturelen, datalen, bloblen; int r, ret, valid_data = 0, encoded_ret; + int type = 0; -+ type = buffer_get_int(m); - if ((r = sshbuf_get_string(m, &blob, &bloblen)) != 0 || +- if ((r = sshbuf_get_string(m, &blob, &bloblen)) != 0 || ++ if ((r = sshbuf_get_u32(m, &type)) != 0 || ++ (r = sshbuf_get_string(m, &blob, &bloblen)) != 0 || (r = sshbuf_get_string(m, &signature, &signaturelen)) != 0 || (r = sshbuf_get_string(m, &data, &datalen)) != 0 || + (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) @@ -1405,6 +1424,8 @@ mm_answer_keyverify(int sock, struct ssh if (hostbased_cuser == NULL || hostbased_chost == NULL || !monitor_allowed_key(blob, bloblen)) @@ -1213,14 +1196,15 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) exit(1); -@@ -1630,11 +1662,45 @@ mm_answer_audit_command(int socket, Buff +@@ -1630,12 +1662,47 @@ mm_answer_audit_command(int socket, Buff { - u_int len; char *cmd; + int r; + Session *s; debug3("%s entering", __func__); - cmd = buffer_get_string(m, &len); + if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + /* sanity check command, if so how? */ - audit_run_command(cmd); @@ -1232,8 +1216,8 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c + s->command_handle = audit_run_command(cmd); +#endif + -+ buffer_clear(m); -+ buffer_put_int(m, s->self); ++ sshbuf_reset(m); ++ sshbuf_put_u32(m, s->self); + + mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); + @@ -1241,16 +1225,17 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c +} + +int -+mm_answer_audit_end_command(int socket, Buffer *m) ++mm_answer_audit_end_command(int socket, struct sshbuf *m) +{ -+ int handle; -+ u_int len; -+ char *cmd; ++ int handle, r; ++ size_t len; ++ u_char *cmd = NULL; + Session *s; + + debug3("%s entering", __func__); -+ handle = buffer_get_int(m); -+ cmd = buffer_get_string(m, &len); ++ 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 || @@ -1264,7 +1249,7 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c void mm_get_keystate(struct monitor *pmonitor) { -+ Buffer m; ++ struct sshbuf *m; debug3("%s: Waiting for new keys", __func__); if ((child_state = sshbuf_new()) == NULL) @@ -1274,11 +1259,11 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c debug3("%s: GOT new keys", __func__); + +#ifdef SSH_AUDIT_EVENTS -+ buffer_init(&m); ++ 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); -+ buffer_free(&m); ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m); ++ mm_answer_audit_session_key_free_body(pmonitor->m_sendfd, m); ++ sshbuf_free(m); +#endif + + /* Drain any buffered messages from the child */ @@ -1288,41 +1273,47 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c } -@@ -1976,3 +2056,86 @@ mm_answer_gss_updatecreds(int socket, Bu +@@ -1976,3 +2056,102 @@ mm_answer_gss_updatecreds(int socket, Bu #endif /* GSSAPI */ +#ifdef SSH_AUDIT_EVENTS +int -+mm_answer_audit_unsupported_body(int sock, Buffer *m) ++mm_answer_audit_unsupported_body(int sock, struct sshbuf *m) +{ -+ int what; ++ int what, r; + -+ what = buffer_get_int(m); ++ if ((r = sshbuf_get_u32(m, &what)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + audit_unsupported_body(what); + -+ buffer_clear(m); ++ sshbuf_reset(m); + + mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); + return 0; +} + +int -+mm_answer_audit_kex_body(int sock, Buffer *m) ++mm_answer_audit_kex_body(int sock, struct sshbuf *m) +{ -+ int ctos, len; ++ int ctos, r; + char *cipher, *mac, *compress, *pfs; ++ u_int64_t tmp; + pid_t pid; + uid_t uid; + -+ ctos = buffer_get_int(m); -+ cipher = buffer_get_string(m, &len); -+ mac = buffer_get_string(m, &len); -+ compress = buffer_get_string(m, &len); -+ pfs = buffer_get_string(m, &len); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); ++ 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); + @@ -1330,47 +1321,57 @@ diff -up openssh-7.6p1/monitor.c.audit openssh-7.6p1/monitor.c + free(mac); + free(compress); + free(pfs); -+ buffer_clear(m); ++ sshbuf_reset(m); + + mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); + return 0; +} + +int -+mm_answer_audit_session_key_free_body(int sock, Buffer *m) ++mm_answer_audit_session_key_free_body(int sock, struct sshbuf *m) +{ -+ int ctos; ++ int ctos, r; ++ u_int64_t tmp; + pid_t pid; + uid_t uid; + -+ ctos = buffer_get_int(m); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); ++ 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); + -+ buffer_clear(m); ++ 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, Buffer *m) ++mm_answer_audit_server_key_free(int sock, struct sshbuf *m) +{ -+ int len; ++ size_t len, r; + char *fp; ++ u_int64_t tmp; + pid_t pid; + uid_t uid; + -+ fp = buffer_get_string(m, &len); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); ++ 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); + + free(fp); -+ buffer_clear(m); ++ sshbuf_reset(m); + + return 0; +} @@ -1404,15 +1405,17 @@ diff -up openssh-7.6p1/monitor_wrap.c.audit openssh-7.6p1/monitor_wrap.c +mm_sshkey_verify(enum mm_keytype type, const struct sshkey *key, const u_char *sig, size_t siglen, const u_char *data, size_t datalen, const char *sigalg, u_int compat) { - Buffer m; -@@ -478,6 +478,7 @@ mm_sshkey_verify(const struct sshkey *ke - return (0); - - buffer_init(&m); -+ buffer_put_int(&m, type); - buffer_put_string(&m, blob, len); - buffer_put_string(&m, sig, siglen); - buffer_put_string(&m, data, datalen); + struct sshbuf *m; +@@ -478,7 +478,8 @@ mm_sshkey_verify(const struct sshkey *ke + + if ((m = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); +- if ((r = sshkey_puts(key, m)) != 0 || ++ if ((r = sshbuf_put_u32(m, type)) != 0 || ++ (r = sshkey_puts(key, m)) != 0 || + (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) @@ -497,6 +498,20 @@ mm_sshkey_verify(const struct sshkey *ke return 0; } @@ -1434,27 +1437,29 @@ diff -up openssh-7.6p1/monitor_wrap.c.audit openssh-7.6p1/monitor_wrap.c void mm_send_keystate(struct monitor *monitor) { -@@ -874,10 +889,11 @@ mm_audit_event(ssh_audit_event_t event) - buffer_free(&m); +@@ -874,11 +889,12 @@ mm_audit_event(ssh_audit_event_t event) + sshbuf_free(m); } -void +int mm_audit_run_command(const char *command) { - Buffer m; + struct sshbuf *m; + int r; + int handle; debug3("%s entering command %s", __func__, command); -@@ -885,6 +901,26 @@ mm_audit_run_command(const char *command - buffer_put_cstring(&m, command); +@@ -885,6 +901,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); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, &m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m); + -+ handle = buffer_get_int(&m); -+ buffer_free(&m); ++ if ((r = sshbuf_get_u32(m, &handle)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ sshbuf_free(m); + + return (handle); +} @@ -1462,87 +1467,103 @@ diff -up openssh-7.6p1/monitor_wrap.c.audit openssh-7.6p1/monitor_wrap.c +void +mm_audit_end_command(int handle, const char *command) +{ -+ Buffer m; ++ int r; ++ struct sshbuf *m; + + debug3("%s entering command %s", __func__, command); + -+ buffer_init(&m); -+ buffer_put_int(&m, handle); -+ buffer_put_cstring(&m, 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)); + -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); - buffer_free(&m); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, m); + sshbuf_free(m); } #endif /* SSH_AUDIT_EVENTS */ -@@ -1020,3 +1056,70 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc - +@@ -1020,3 +1056,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc + return (ok); + } #endif /* GSSAPI */ - +#ifdef SSH_AUDIT_EVENTS +void +mm_audit_unsupported_body(int what) +{ -+ Buffer m; ++ int r; ++ struct sshbuf *m; + -+ buffer_init(&m); -+ buffer_put_int(&m, what); ++ 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_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, -+ &m); ++ m); + -+ buffer_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) +{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_cstring(&m, cipher); -+ buffer_put_cstring(&m, (mac ? mac : "")); -+ buffer_put_cstring(&m, compress); -+ buffer_put_cstring(&m, fps); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &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)); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, -+ &m); ++ m); + -+ buffer_free(&m); ++ sshbuf_free(m); +} + +void +mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) +{ -+ Buffer m; ++ int r; ++ struct sshbuf *m; + -+ buffer_init(&m); -+ buffer_put_int(&m, ctos); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, &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)); ++ ++ 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); -+ buffer_free(&m); ++ m); ++ sshbuf_free(m); +} + +void +mm_audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) +{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_cstring(&m, fp); -+ buffer_put_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, &m); -+ buffer_free(&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)); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); ++ sshbuf_free(m); +} +#endif /* SSH_AUDIT_EVENTS */ diff -up openssh-7.6p1/monitor_wrap.h.audit openssh-7.6p1/monitor_wrap.h @@ -1577,7 +1598,7 @@ diff -up openssh-7.6p1/packet.c.audit openssh-7.6p1/packet.c --- openssh-7.6p1/packet.c.audit 2017-10-04 17:18:32.672504220 +0200 +++ openssh-7.6p1/packet.c 2017-10-04 17:25:48.141741390 +0200 @@ -67,6 +67,7 @@ - #include "key.h" /* typedefs XXX */ + #include #include "xmalloc.h" +#include "audit.h" @@ -1642,9 +1663,9 @@ diff -up openssh-7.6p1/packet.c.audit openssh-7.6p1/packet.c + close(state->connection_in); + close(state->connection_out); + } + free(ssh->local_ipaddr); + ssh->local_ipaddr = NULL; free(ssh->remote_ipaddr); - ssh->remote_ipaddr = NULL; - free(ssh->state); @@ -854,6 +863,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod (unsigned long long)state->p_read.blocks, (unsigned long long)state->p_send.bytes, @@ -1685,16 +1706,16 @@ diff -up openssh-7.6p1/packet.c.audit openssh-7.6p1/packet.c + cipher_free(state->receive_context); + cipher_free(state->send_context); + -+ buffer_free(state->input); ++ sshbuf_free(state->input); + state->input = NULL; -+ buffer_free(state->output); ++ sshbuf_free(state->output); + state->output = NULL; -+ buffer_free(state->outgoing_packet); ++ sshbuf_free(state->outgoing_packet); + state->outgoing_packet = NULL; -+ buffer_free(state->incoming_packet); ++ sshbuf_free(state->incoming_packet); + state->incoming_packet = NULL; -+ if( state->compression_buffer ) { -+ buffer_free(state->compression_buffer); ++ if (state->compression_buffer) { ++ sshbuf_free(state->compression_buffer); + state->compression_buffer = NULL; + } + newkeys_destroy_and_free(state->newkeys[MODE_IN]); @@ -1744,7 +1765,7 @@ diff -up openssh-7.6p1/session.c.audit openssh-7.6p1/session.c extern int startup_pipe; -extern void destroy_sensitive_data(void); +extern void destroy_sensitive_data(int); - extern Buffer loginmsg; + extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; char *tun_fwd_ifnames; /* serverloop.c */ @@ -605,6 +605,14 @@ do_exec_pty(struct ssh *ssh, Session *s, @@ -1984,11 +2005,11 @@ diff -up openssh-7.6p1/sshd.c.audit openssh-7.6p1/sshd.c if (sensitive_data.host_keys[i]) { + char *fp; + -+ if (key_is_private(sensitive_data.host_keys[i])) ++ 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; - key_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 @@ -2005,13 +2026,13 @@ diff -up openssh-7.6p1/sshd.c.audit openssh-7.6p1/sshd.c - if (sensitive_data.host_certificates[i]) { + if (sensitive_data.host_certificates + && sensitive_data.host_certificates[i]) { - key_free(sensitive_data.host_certificates[i]); + sshkey_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } -@@ -499,12 +536,30 @@ demote_sensitive_data(void) - { +@@ -499,16 +536,34 @@ demote_sensitive_data(void) struct sshkey *tmp; u_int i; + int r; +#ifdef SSH_AUDIT_EVENTS + pid_t pid; + uid_t uid; @@ -2023,12 +2044,16 @@ diff -up openssh-7.6p1/sshd.c.audit openssh-7.6p1/sshd.c if (sensitive_data.host_keys[i]) { + char *fp; + -+ if (key_is_private(sensitive_data.host_keys[i])) ++ 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; - tmp = key_demote(sensitive_data.host_keys[i]); - key_free(sensitive_data.host_keys[i]); + if ((r = sshkey_demote(sensitive_data.host_keys[i], + &tmp)) != 0) + fatal("could not demote host %s key: %s", + sshkey_type(sensitive_data.host_keys[i]), + ssh_err(r)); + sshkey_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = tmp; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS diff --git a/openssh-7.6p1-pkcs11-ecdsa.patch b/openssh-7.6p1-pkcs11-ecdsa.patch index b7fd2cf..9b19b68 100644 --- a/openssh-7.6p1-pkcs11-ecdsa.patch +++ b/openssh-7.6p1-pkcs11-ecdsa.patch @@ -29,7 +29,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 { static RSA_METHOD helper_rsa; -@@ -152,6 +160,81 @@ wrap_key(RSA *rsa) +@@ -152,6 +160,85 @@ wrap_key(RSA *rsa) return (0); } @@ -38,30 +38,34 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 +pkcs11_ecdsa_private_sign(const unsigned char *from, int flen, + const BIGNUM *inv, const BIGNUM *rp, EC_KEY * ecdsa) +{ -+ Key key; ++ struct sshkey *key; + u_char *blob, *signature = NULL; -+ u_int blen, slen = 0; -+ Buffer msg; ++ size_t blen, slen = 0; ++ struct sshbuf *msg; + ECDSA_SIG *ret = NULL; + BIGNUM *r = NULL, *s = NULL; ++ int rv; + -+ key.type = KEY_ECDSA; -+ key.ecdsa = ecdsa; -+ key.ecdsa_nid = sshkey_ecdsa_key_to_nid(ecdsa); -+ if (key_to_blob(&key, &blob, &blen) == 0) ++ key = sshkey_new(KEY_ECDSA); ++ key->ecdsa = ecdsa; ++ key->ecdsa_nid = sshkey_ecdsa_key_to_nid(ecdsa); ++ if (sshkey_to_blob(key, &blob, &blen) == 0) + return NULL; -+ buffer_init(&msg); -+ buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); -+ buffer_put_string(&msg, blob, blen); -+ buffer_put_string(&msg, from, flen); -+ buffer_put_int(&msg, 0); ++ if ((msg = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((rv = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || ++ (rv = sshbuf_put_string(msg, blob, blen)) != 0 || ++ (rv = sshbuf_put_string(msg, from, flen)) != 0 || ++ (rv = sshbuf_put_u32(msg, 0)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(rv)); + free(blob); -+ send_msg(&msg); -+ buffer_clear(&msg); ++ send_msg(msg); ++ sshbuf_reset(msg); + -+ if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { -+ signature = buffer_get_string(&msg, &slen); -+ if (slen <= (u_int)ECDSA_size(ecdsa)) { ++ if (recv_msg(msg) == SSH2_AGENT_SIGN_RESPONSE) { ++ if ((rv = sshbuf_get_string(msg, &signature, &slen)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(rv)); ++ if (slen <= (size_t)ECDSA_size(ecdsa)) { + int nlen = slen / 2; + ret = ECDSA_SIG_new(); + r = BN_new(); @@ -72,7 +76,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 + } + free(signature); + } -+ buffer_free(&msg); ++ sshbuf_free(msg); + return (ret); +} + @@ -112,9 +116,9 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 pkcs11_start_helper(void) { @@ -212,7 +281,15 @@ pkcs11_add_provider(char *name, char *pi - blob = buffer_get_string(&msg, &blen); - free(buffer_get_string(&msg, NULL)); - k = key_from_blob(blob, blen); + __func__, ssh_err(r)); + if ((r = sshkey_from_blob(blob, blen, &k)) != 0) + fatal("%s: bad key: %s", __func__, ssh_err(r)); - wrap_key(k->rsa); + if(k->type == KEY_RSA) { + wrap_rsa_key(k->rsa); diff --git a/openssh-7.6p1-pkcs11-uri.patch b/openssh-7.6p1-pkcs11-uri.patch index 79c6a00..c032ed5 100644 --- a/openssh-7.6p1-pkcs11-uri.patch +++ b/openssh-7.6p1-pkcs11-uri.patch @@ -17,18 +17,18 @@ index ac959c1f..f8ed1781 100644 rm -f regress/unittests/utf8/test_utf8$(EXEEXT) + rm -f regress/unittests/pkcs11/*.o + rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) - rm -f regress/misc/kexfuzz/*.o - rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT) - (cd openbsd-compat && $(MAKE) clean) + rm -f regress/misc/kexfuzz/*.o + rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT) + (cd openbsd-compat && $(MAKE) clean) @@ -276,6 +278,8 @@ distclean: regressclean rm -f regress/unittests/match/test_match rm -f regress/unittests/utf8/*.o rm -f regress/unittests/utf8/test_utf8 + rm -f regress/unittests/pkcs11/*.o + rm -f regress/unittests/pkcs11/test_pkcs11 - rm -f regress/unittests/misc/kexfuzz - (cd openbsd-compat && $(MAKE) distclean) - if test -d pkg ; then \ + rm -f regress/misc/kexfuzz/*.o + rm -f regress/misc/kexfuzz + (cd openbsd-compat && $(MAKE) distclean) @@ -437,6 +441,7 @@ regress-prep: $(MKDIR_P) `pwd`/regress/unittests/kex $(MKDIR_P) `pwd`/regress/unittests/match @@ -72,8 +72,8 @@ index ac959c1f..f8ed1781 100644 regress/netcat$(EXEEXT) \ + regress/soft-pkcs11.so \ regress/check-perm$(EXEEXT) \ + regress/mkdtemp$(EXEEXT) \ regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ - regress/unittests/sshkey/test_sshkey$(EXEEXT) \ @@ -575,6 +596,7 @@ regress-binaries: regress/modpipe$(EXEEXT) \ regress/unittests/kex/test_kex$(EXEEXT) \ regress/unittests/match/test_match$(EXEEXT) \ @@ -81,7 +81,7 @@ index ac959c1f..f8ed1781 100644 + regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ regress/misc/kexfuzz/kexfuzz$(EXEEXT) - REGRESSTMP = "$(PWD)/regress" + tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) diff --git a/authfd.c b/authfd.c index 1eff7ba9..35153f47 100644 --- a/authfd.c @@ -2717,7 +2717,7 @@ new file mode 100644 index 00000000..e83aca54 --- /dev/null +++ b/regress/unittests/pkcs11/tests.c -@@ -0,0 +1,329 @@ +@@ -0,0 +1,330 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -2743,6 +2743,7 @@ index 00000000..e83aca54 + +#include "../test_helper/test_helper.h" + ++#include "sshbuf.h" +#include "ssh-pkcs11-uri.h" + +#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL) @@ -3288,12 +3289,12 @@ index a023f5f4..882e8381 100644 key.type = KEY_RSA; key.rsa = rsa; + key.ecdsa_nid = 0; - if (key_to_blob(&key, &blob, &blen) == 0) + if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) { + error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); return -1; - buffer_init(&msg); @@ -195,6 +196,8 @@ pkcs11_add_provider(char *name, char *pin, Key ***keysp) - u_int blen; - Buffer msg; + u_int nkeys, i; + struct sshbuf *msg; + debug("%s: called, name = %s", __func__, name); + @@ -3301,19 +3302,19 @@ index a023f5f4..882e8381 100644 return (-1); @@ -208,6 +211,7 @@ pkcs11_add_provider(char *name, char *pin, Key ***keysp) - if (recv_msg(&msg) == SSH2_AGENT_IDENTITIES_ANSWER) { - nkeys = buffer_get_int(&msg); - *keysp = xcalloc(nkeys, sizeof(Key *)); -+ debug("%s: nkeys = %d", __func__, nkeys); + if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); ++ debug("%s: nkeys = %u", __func__, nkeys); for (i = 0; i < nkeys; i++) { - blob = buffer_get_string(&msg, &blen); - free(buffer_get_string(&msg, NULL)); + /* XXX clean up properly instead of fatal() */ + if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c new file mode 100644 index 00000000..da15c164 --- /dev/null +++ b/ssh-pkcs11-uri.c -@@ -0,0 +1,400 @@ +@@ -0,0 +1,401 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -3340,6 +3341,7 @@ index 00000000..da15c164 +#include + +#include "sshkey.h" ++#include "sshbuf.h" +#include "log.h" + +#define CRYPTOKI_COMPAT @@ -4624,7 +4626,7 @@ index d3619fe2..180eb2e0 100644 + break; + } +#endif - p = tilde_expand_filename(optarg, original_real_uid); + p = tilde_expand_filename(optarg, getuid()); if (stat(p, &st) < 0) fprintf(stderr, "Warning: Identity file %s " @@ -1999,6 +2007,45 @@ ssh_session2(struct ssh *ssh, struct passwd *pw) @@ -4656,7 +4658,7 @@ index d3619fe2..180eb2e0 100644 + (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) { + for (i = 0; i < nkeys; i++) { + if (*n_ids >= SSH_MAX_IDENTITY_FILES) { -+ key_free(keys[i]); ++ sshkey_free(keys[i]); + continue; + } + identity_keys[*n_ids] = keys[i]; @@ -4674,9 +4676,9 @@ index d3619fe2..180eb2e0 100644 static void load_public_identity_files(struct passwd *pw) @@ -2011,10 +2058,6 @@ load_public_identity_files(struct passwd *pw) - struct sshkey *identity_keys[SSH_MAX_IDENTITY_FILES]; char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; + int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; -#ifdef ENABLE_PKCS11 - struct sshkey **keys; - int nkeys; @@ -4684,8 +4686,8 @@ index d3619fe2..180eb2e0 100644 n_ids = n_certs = 0; memset(identity_files, 0, sizeof(identity_files)); -@@ -2023,35 +2066,48 @@ load_public_identity_files(struct passwd *pw) - memset(certificates, 0, sizeof(certificates)); +@@ -2023,32 +2066,46 @@ load_public_identity_files(struct passwd *pw) + sizeof(certificate_file_userprovided)); #ifdef ENABLE_PKCS11 - if (options.pkcs11_provider != NULL && @@ -4695,7 +4697,7 @@ index d3619fe2..180eb2e0 100644 - &keys)) > 0) { - for (i = 0; i < nkeys; i++) { - if (n_ids >= SSH_MAX_IDENTITY_FILES) { -- key_free(keys[i]); +- sshkey_free(keys[i]); - continue; - } - identity_keys[n_ids] = keys[i]; @@ -4725,8 +4727,6 @@ index d3619fe2..180eb2e0 100644 + pkcs11_uri_cleanup(uri); } #endif /* ENABLE_PKCS11 */ - if ((pw = getpwuid(original_real_uid)) == NULL) - fatal("load_public_identity_files: getpwuid failed"); for (i = 0; i < options.num_identity_files; i++) { + char *name = options.identity_files[i]; if (n_ids >= SSH_MAX_IDENTITY_FILES || @@ -4736,8 +4736,7 @@ index d3619fe2..180eb2e0 100644 options.identity_files[i] = NULL; continue; } -- cp = tilde_expand_filename(options.identity_files[i], -- original_real_uid); +- cp = tilde_expand_filename(options.identity_files[i], getuid()); +#ifdef ENABLE_PKCS11 + if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && + strncmp(name, PKCS11_URI_SCHEME, @@ -4748,7 +4747,7 @@ index d3619fe2..180eb2e0 100644 + continue; + } +#endif /* ENABLE_PKCS11 */ -+ cp = tilde_expand_filename(name, original_real_uid); ++ cp = tilde_expand_filename(name, getuid()); filename = percent_expand(cp, "d", pw->pw_dir, "u", pw->pw_name, "l", thishost, "h", host, "r", options.user, (char *)NULL); diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch index 6ce05ab..084c903 100644 --- a/openssh-7.7p1-fips.patch +++ b/openssh-7.7p1-fips.patch @@ -294,7 +294,7 @@ diff -up openssh-7.7p1/Makefile.in.fips openssh-7.7p1/Makefile.in + $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) scp$(EXEEXT): $(LIBCOMPAT) libssh.a scp.o progressmeter.o - $(LD) -o $@ scp.o progressmeter.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + $(LD) -o $@ scp.o progressmeter.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o - $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) @@ -308,9 +308,9 @@ diff -up openssh-7.7p1/Makefile.in.fips openssh-7.7p1/Makefile.in - $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + $(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o -- $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o readconf.o uidswap.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 -lfipscheck $(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) @@ -380,53 +380,35 @@ diff -up openssh-7.7p1/myproposal.h.fips openssh-7.7p1/myproposal.h #else /* WITH_OPENSSL */ #define KEX_SERVER_KEX \ -diff -up openssh-7.7p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.fips openssh-7.7p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c ---- openssh-7.7p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.fips 2018-08-08 10:08:40.649718516 +0200 -+++ openssh-7.7p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2018-08-08 10:08:40.823719982 +0200 -@@ -55,6 +55,7 @@ - #include "secure_filename.h" - #include "uidswap.h" - #include -+#include - - #include "identity.h" - -@@ -104,7 +105,8 @@ pamsshagentauth_check_authkeys_file(FILE - found_key = 1; - logit("matching key found: file/command %s, line %lu", file, - linenum); -- fp = sshkey_fingerprint(found, SSH_DIGEST_MD5, SSH_FP_HEX); -+ fp = sshkey_fingerprint(found, FIPS_mode() ? SSH_DIGEST_SHA1 : SSH_DIGEST_MD5, -+ SSH_FP_HEX); - logit("Found matching %s key: %s", - sshkey_type(found), fp); - free(fp); diff -up openssh-7.7p1/readconf.c.fips openssh-7.7p1/readconf.c --- openssh-7.7p1/readconf.c.fips 2018-08-08 10:08:40.769719527 +0200 +++ openssh-7.7p1/readconf.c 2018-08-08 10:08:40.824719990 +0200 -@@ -2081,12 +2081,17 @@ fill_default_options(Options * options) - } - if (options->update_hostkeys == -1) - options->update_hostkeys = 0; -- if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || -- kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 || -- kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 || -- kex_assemble_names(KEX_DEFAULT_PK_ALG, -+ if (kex_assemble_names((FIPS_mode() ? KEX_FIPS_ENCRYPT -+ : KEX_CLIENT_ENCRYPT), &options->ciphers) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_MAC -+ : KEX_CLIENT_MAC), &options->macs) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_DEFAULT_KEX_FIPS -+ : KEX_CLIENT_KEX), &options->kex_algorithms) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), - &options->hostbased_key_types) != 0 || -- kex_assemble_names(KEX_DEFAULT_PK_ALG, -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), - &options->pubkey_key_types) != 0) - fatal("%s: kex_assemble_names failed", __func__); - +@@ -2081,17 +2081,18 @@ fill_default_options(Options * options) + all_mac = mac_alg_list(','); + all_kex = kex_alg_list(','); + all_key = sshkey_alg_list(0, 0, 1, ','); +-#define ASSEMBLE(what, defaults, all) \ ++#define ASSEMBLE(what, defaults, fips_defaults, all) \ + do { \ + if ((r = kex_assemble_names(&options->what, \ +- defaults, all)) != 0) \ ++ (FIPS_mode() ? fips_defaults : defaults), \ ++ all)) != 0) \ + fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \ + } while (0) +- ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, all_cipher); +- ASSEMBLE(macs, KEX_SERVER_MAC, all_mac); +- ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex); +- ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); +- ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); ++ ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, KEX_FIPS_ENCRYPT, all_cipher); ++ ASSEMBLE(macs, KEX_SERVER_MAC, KEX_FIPS_MAC, all_mac); ++ ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, KEX_DEFAULT_KEX_FIPS, all_kex); ++ ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); ++ ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); + #undef ASSEMBLE + free(all_cipher); + free(all_mac); diff -up openssh-7.7p1/sandbox-seccomp-filter.c.fips openssh-7.7p1/sandbox-seccomp-filter.c --- openssh-7.7p1/sandbox-seccomp-filter.c.fips 2018-08-08 10:08:40.794719737 +0200 +++ openssh-7.7p1/sandbox-seccomp-filter.c 2018-08-08 10:08:40.824719990 +0200 @@ -443,33 +425,33 @@ diff -up openssh-7.7p1/sandbox-seccomp-filter.c.fips openssh-7.7p1/sandbox-secco diff -up openssh-7.7p1/servconf.c.fips openssh-7.7p1/servconf.c --- openssh-7.7p1/servconf.c.fips 2018-08-08 10:08:40.778719603 +0200 +++ openssh-7.7p1/servconf.c 2018-08-08 10:08:40.824719990 +0200 -@@ -196,14 +196,20 @@ option_clear_or_none(const char *o) - static void - assemble_algorithms(ServerOptions *o) - { -- if (kex_assemble_names(KEX_SERVER_ENCRYPT, &o->ciphers) != 0 || -- kex_assemble_names(KEX_SERVER_MAC, &o->macs) != 0 || -- kex_assemble_names(KEX_SERVER_KEX, &o->kex_algorithms) != 0 || -- kex_assemble_names(KEX_DEFAULT_PK_ALG, -+ if (kex_assemble_names((FIPS_mode() ? KEX_FIPS_ENCRYPT -+ : KEX_SERVER_ENCRYPT), &o->ciphers) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_MAC -+ : KEX_SERVER_MAC), &o->macs) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_DEFAULT_KEX_FIPS -+ : KEX_SERVER_KEX), &o->kex_algorithms) != 0 || -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), - &o->hostkeyalgorithms) != 0 || -- kex_assemble_names(KEX_DEFAULT_PK_ALG, -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), - &o->hostbased_key_types) != 0 || -- kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->pubkey_key_types) != 0) -+ kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), &o->pubkey_key_types) != 0) - fatal("kex_assemble_names failed"); - } - +@@ -196,17 +196,18 @@ option_clear_or_none(const char *o) + all_mac = mac_alg_list(','); + all_kex = kex_alg_list(','); + all_key = sshkey_alg_list(0, 0, 1, ','); +-#define ASSEMBLE(what, defaults, all) \ ++#define ASSEMBLE(what, defaults, fips_defaults, all) \ + do { \ +- if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ ++ if ((r = kex_assemble_names(&o->what, (FIPS_mode() \ ++ ? fips_defaults : defaults), all)) != 0) \ + fatal("%s: %s: %s", __func__, #what, ssh_err(r)); \ + } while (0) +- ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, all_cipher); +- ASSEMBLE(macs, KEX_SERVER_MAC, all_mac); +- ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex); +- ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, all_key); +- ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); +- ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); ++ ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, KEX_FIPS_ENCRYPT, all_cipher); ++ ASSEMBLE(macs, KEX_SERVER_MAC, KEX_FIPS_MAC, all_mac); ++ ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, KEX_DEFAULT_KEX_FIPS, all_kex); ++ ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); ++ ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); ++ ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); + #undef ASSEMBLE + free(all_cipher); + free(all_mac); diff -up openssh-7.7p1/ssh.c.fips openssh-7.7p1/ssh.c --- openssh-7.7p1/ssh.c.fips 2018-08-08 10:08:40.811719881 +0200 +++ openssh-7.7p1/ssh.c 2018-08-08 10:08:40.825719999 +0200 @@ -581,14 +563,14 @@ diff -up openssh-7.7p1/sshconnect2.c.fips openssh-7.7p1/sshconnect2.c } #endif @@ -322,14 +330,16 @@ ssh_kex2(char *host, struct sockaddr *ho - myproposal[PROPOSAL_MAC_ALGS_CTOS] = - myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; if (options.hostkeyalgorithms != NULL) { -- if (kex_assemble_names(KEX_DEFAULT_PK_ALG, -+ if (kex_assemble_names((FIPS_mode() ? KEX_FIPS_PK_ALG -+ : KEX_DEFAULT_PK_ALG), - &options.hostkeyalgorithms) != 0) + all_key = sshkey_alg_list(0, 0, 1, ','); + if (kex_assemble_names(&options.hostkeyalgorithms, +- KEX_DEFAULT_PK_ALG, all_key) != 0) ++ (FIPS_mode() ? KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), ++ all_key) != 0) fatal("%s: kex_assemble_namelist", __func__); + free(all_key); myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(options.hostkeyalgorithms); } else { diff --git a/openssh-7.7p1-redhat.patch b/openssh-7.7p1-redhat.patch index dc38d65..99a4411 100644 --- a/openssh-7.7p1-redhat.patch +++ b/openssh-7.7p1-redhat.patch @@ -148,7 +148,7 @@ diff -up openssh-7.7p1/sshd_config.redhat openssh-7.7p1/sshd_config + #PrintLastLog yes #TCPKeepAlive yes - #UseLogin no + #PermitUserEnvironment no @@ -106,6 +126,12 @@ AuthorizedKeysFile .ssh/authorized_keys # no default banner path #Banner none diff --git a/openssh-7.7p1-tun-devices.patch b/openssh-7.7p1-tun-devices.patch deleted file mode 100644 index efd82c3..0000000 --- a/openssh-7.7p1-tun-devices.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 4f60e4f66b5880c9f50ef758e8b7f7a9ae786d21 Mon Sep 17 00:00:00 2001 -From: Darren Tucker -Date: Fri, 13 Apr 2018 13:13:33 +1000 -Subject: [PATCH 1/5] Revert $REGRESSTMP changes. - -Revert 3fd2d229 and subsequent changes as they turned out to be a -portability hassle. ---- - Makefile.in | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/Makefile.in b/Makefile.in -index 04e1c8e53..dd942ee7b 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -577,8 +577,6 @@ regress-binaries: regress/modpipe$(EXEEXT) \ - regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ - regress/misc/kexfuzz/kexfuzz$(EXEEXT) - --REGRESSTMP = "$(PWD)/regress" -- - tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) - BUILDDIR=`pwd`; \ - TEST_SSH_SCP="$${BUILDDIR}/scp"; \ -@@ -602,7 +600,7 @@ tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) - .OBJDIR="$${BUILDDIR}/regress" \ - .CURDIR="`pwd`" \ - BUILDDIR="$${BUILDDIR}" \ -- OBJ="$(REGRESSTMP)" \ -+ OBJ="$${BUILDDIR}/regress/" \ - PATH="$${BUILDDIR}:$${PATH}" \ - TEST_ENV=MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ - TEST_MALLOC_OPTIONS="@TEST_MALLOC_OPTIONS@" \ - -From b81b2d120e9c8a83489e241620843687758925ad Mon Sep 17 00:00:00 2001 -From: Damien Miller -Date: Fri, 13 Apr 2018 13:38:06 +1000 -Subject: [PATCH 2/5] Fix tunnel forwarding broken in 7.7p1 - -bz2855, ok dtucker@ ---- - openbsd-compat/port-net.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/openbsd-compat/port-net.c b/openbsd-compat/port-net.c -index 7050629c3..bb535626f 100644 ---- a/openbsd-compat/port-net.c -+++ b/openbsd-compat/port-net.c -@@ -185,7 +185,7 @@ sys_tun_open(int tun, int mode, char **ifname) - else - debug("%s: %s mode %d fd %d", __func__, ifr.ifr_name, mode, fd); - -- if (ifname != NULL && (*ifname = strdup(ifr.ifr_name))) -+ if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL) - goto failed; - - return (fd); -@@ -272,7 +272,7 @@ sys_tun_open(int tun, int mode, char **ifname) - goto failed; - } - -- if (ifname != NULL && (*ifname = strdup(ifr.ifr_name))) -+ if (ifname != NULL && (*ifname = strdup(ifr.ifr_name)) == NULL) - goto failed; - - close(sock); - -From 341727df910e12e26ef161508ed76d91c40a61eb Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Mon, 9 Apr 2018 23:54:49 +0000 -Subject: [PATCH 3/5] upstream: don't kill ssh-agent's listening socket - entriely if we - -fail to accept a connection; bz#2837, patch from Lukas Kuster - -OpenBSD-Commit-ID: 52413f5069179bebf30d38f524afe1a2133c738f ---- - ssh-agent.c | 7 +++---- - 1 file changed, 3 insertions(+), 4 deletions(-) - -diff --git a/ssh-agent.c b/ssh-agent.c -index 2a4578b03..68de56ce6 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: ssh-agent.c,v 1.228 2018/02/23 15:58:37 markus Exp $ */ -+/* $OpenBSD: ssh-agent.c,v 1.229 2018/04/09 23:54:49 djm Exp $ */ - /* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland -@@ -909,9 +909,8 @@ after_poll(struct pollfd *pfd, size_t npfd) - /* Process events */ - switch (sockets[socknum].type) { - case AUTH_SOCKET: -- if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 && -- handle_socket_read(socknum) != 0) -- close_socket(&sockets[socknum]); -+ if ((pfd[i].revents & (POLLIN|POLLERR)) != 0) -+ handle_socket_read(socknum); - break; - case AUTH_CONNECTION: - if ((pfd[i].revents & (POLLIN|POLLERR)) != 0 && - -From 3402cc607049ac900f6d8574bc2ce657a8cdf4fe Mon Sep 17 00:00:00 2001 -From: Darren Tucker -Date: Fri, 13 Apr 2018 13:43:55 +1000 -Subject: [PATCH 4/5] Using "==" in shell tests is not portable. - -Patch from rsbecker at nexbridge.com. ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 663062bef..2e84d90b7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1398,7 +1398,7 @@ AC_RUN_IFELSE( - ) - AC_MSG_RESULT([$func_calloc_0_nonnull]) - --if test "x$func_calloc_0_nonnull" == "xyes"; then -+if test "x$func_calloc_0_nonnull" = "xyes"; then - AC_DEFINE(HAVE_CALLOC, 1, [calloc(0, x) returns non-null]) - else - AC_DEFINE(HAVE_CALLOC, 0, [calloc(0, x) returns NULL]) - -From 85fe48fd49f2e81fa30902841b362cfbb7f1933b Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Sat, 14 Apr 2018 21:50:41 +0000 -Subject: [PATCH 5/5] upstream: don't free the %C expansion, it's used later - for - -LocalCommand - -OpenBSD-Commit-ID: 857b5cb37b2d856bfdfce61289a415257a487fb1 ---- - ssh.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ssh.c b/ssh.c -index d3619fe29..9c011dd7e 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1323,7 +1323,6 @@ main(int ac, char **av) - (char *)NULL); - free(cp); - } -- free(conn_hash_hex); - - if (config_test) { - dump_client_config(&options, host); diff --git a/openssh-7.8p1-UsePAM-warning.patch b/openssh-7.8p1-UsePAM-warning.patch new file mode 100644 index 0000000..da39361 --- /dev/null +++ b/openssh-7.8p1-UsePAM-warning.patch @@ -0,0 +1,26 @@ +diff --git a/sshd.c b/sshd.c +--- a/sshd.c ++++ b/sshd.c +@@ -1701,6 +1701,10 @@ main(int ac, char **av) + parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, + cfg, NULL); + ++ /* 'UsePAM no' is not supported in Fedora */ ++ if (! options.use_pam) ++ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems."); ++ + seed_rng(); + + /* Fill in default values for those options not explicitly set. */ +diff --git a/sshd_config b/sshd_config +--- a/sshd_config ++++ b/sshd_config +@@ -101,6 +101,8 @@ GSSAPICleanupCredentials no + # If you just want the PAM account and session checks to run without + # PAM authentication, then enable this but set PasswordAuthentication + # and ChallengeResponseAuthentication to 'no'. ++# WARNING: 'UsePAM no' is not supported in Fedora and may cause several ++# problems. + UsePAM yes + + #AllowAgentForwarding yes diff --git a/openssh-7.8p1-gsskex.patch b/openssh-7.8p1-gsskex.patch new file mode 100644 index 0000000..dd10d4d --- /dev/null +++ b/openssh-7.8p1-gsskex.patch @@ -0,0 +1,2871 @@ +diff -up openssh/auth2.c.gsskex openssh/auth2.c +--- openssh/auth2.c.gsskex 2018-08-22 11:47:33.260216045 +0200 ++++ openssh/auth2.c 2018-08-22 11:47:33.307216424 +0200 +@@ -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, +diff -up openssh/auth2-gss.c.gsskex openssh/auth2-gss.c +--- openssh/auth2-gss.c.gsskex 2018-08-22 11:47:33.260216045 +0200 ++++ openssh/auth2-gss.c 2018-08-22 13:00:48.722680124 +0200 +@@ -31,6 +31,7 @@ + #include + + #include ++#include + + #include "xmalloc.h" + #include "sshkey.h" +@@ -54,6 +55,41 @@ static int input_gssapi_mic(int type, u_ + 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 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(); ++ ++ 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 +296,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) +@@ -313,7 +350,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"); + +@@ -335,6 +373,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, +diff -up openssh/auth.c.gsskex openssh/auth.c +--- openssh/auth.c.gsskex 2018-08-22 11:47:33.274216158 +0200 ++++ openssh/auth.c 2018-08-22 11:47:33.308216432 +0200 +@@ -395,6 +395,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; +diff -up openssh/clientloop.c.gsskex openssh/clientloop.c +--- openssh/clientloop.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/clientloop.c 2018-08-22 11:47:33.309216441 +0200 +@@ -112,6 +112,10 @@ + #include "ssherr.h" + #include "hostfile.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* import options */ + extern Options options; + +@@ -1357,9 +1361,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(NULL)) { ++ debug("credentials updated - forcing rekey"); ++ need_rekeying = 1; ++ } ++#endif ++ } ++ + /* Buffer input from the connection. */ + client_process_net_input(readset); + +diff -up openssh/configure.ac.gsskex openssh/configure.ac +--- openssh/configure.ac.gsskex 2018-08-22 11:47:33.296216335 +0200 ++++ openssh/configure.ac 2018-08-22 11:47:33.309216441 +0200 +@@ -673,6 +673,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]) +diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c +--- openssh/gss-genr.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/gss-genr.c 2018-08-22 13:18:47.444383602 +0200 +@@ -35,18 +35,177 @@ + #include + #include + #include ++#include + + #include "xmalloc.h" + #include "ssherr.h" + #include "sshbuf.h" + #include "log.h" + #include "ssh2.h" ++#include "cipher.h" ++#include "sshkey.h" ++#include "kex.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() { ++ 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) { ++ 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__); ++ ++ 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++; ++ } ++ } ++ 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 +373,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 +403,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 +446,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,11 +475,16 @@ 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 && +@@ -287,6 +494,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx + 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 +507,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 */ +diff -up openssh/gss-serv.c.gsskex openssh/gss-serv.c +--- openssh/gss-serv.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/gss-serv.c 2018-08-22 11:47:33.310216448 +0200 +@@ -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}, 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; ++ } ++ ++ 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_buffer_desc ename; ++ 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,89 @@ 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.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 -up openssh/gss-serv-krb5.c.gsskex openssh/gss-serv-krb5.c +--- openssh/gss-serv-krb5.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/gss-serv-krb5.c 2018-08-22 11:47:33.311216457 +0200 +@@ -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 */ +diff -up openssh/kex.c.gsskex openssh/kex.c +--- openssh/kex.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/kex.c 2018-08-22 11:47:33.311216457 +0200 +@@ -54,6 +54,10 @@ + #include "sshbuf.h" + #include "digest.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* prototype */ + static int kex_choose_conf(struct ssh *); + static int kex_input_newkeys(int, u_int32_t, struct ssh *); +@@ -103,6 +107,11 @@ static const struct kexalg kexalgs[] = { + { 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}, + }; + +@@ -136,6 +145,12 @@ kex_alg_by_name(const char *name) + for (k = 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; + } +diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c +--- openssh/kexgssc.c.gsskex 2018-08-22 11:47:33.311216457 +0200 ++++ openssh/kexgssc.c 2018-08-22 11:47:33.311216457 +0200 +@@ -0,0 +1,338 @@ ++/* ++ * 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" ++ ++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; ++ 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 dh->pub_key */ ++ dh_gen_key(dh, ssh->kex->we_need * 8); ++ ++ /* 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(dh->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 ((int)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, ++ dh->pub_key, /* e */ ++ dh_server_pub, /* f */ ++ shared_secret, /* K */ ++ 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->my), sshbuf_len(ssh->kex->my), ++ sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), ++ (serverhostkey ? serverhostkey : empty), slen, ++ min, nbits, max, ++ dh->p, dh->g, ++ dh->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 */ +diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c +--- openssh/kexgsss.c.gsskex 2018-08-22 11:47:33.311216457 +0200 ++++ openssh/kexgsss.c 2018-08-22 11:47:33.311216457 +0200 +@@ -0,0 +1,297 @@ ++/* ++ * 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 "ssh-gss.h" ++#include "digest.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; ++ ++ /* 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"); ++ ++ packet_start(SSH2_MSG_KEXGSS_GROUP); ++ packet_put_bignum2(dh->p); ++ packet_put_bignum2(dh->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(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); ++ ++ 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, dh->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, ++ dh->p, dh->g, ++ dh_client_pub, ++ dh->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(dh->pub_key); ++ packet_put_string(msg_tok.value,msg_tok.length); ++ ++ if (send_tok.length != 0) { ++ packet_put_char(1); /* true */ ++ packet_put_string(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 */ +diff -up openssh/kex.h.gsskex openssh/kex.h +--- openssh/kex.h.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/kex.h 2018-08-22 11:47:33.311216457 +0200 +@@ -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, +diff -up openssh/Makefile.in.gsskex openssh/Makefile.in +--- openssh/Makefile.in.gsskex 2018-08-22 11:47:33.312216465 +0200 ++++ openssh/Makefile.in 2018-08-22 13:19:54.955928277 +0200 +@@ -100,6 +100,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + readpass.o ttymodes.o xmalloc.o addrmatch.o \ + atomicio.o dispatch.o mac.o uuencode.o misc.o utf8.o \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ ++ kexgssc.o \ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + ssh-pkcs11.o smult_curve25519_ref.o \ + poly1305.o chacha.o cipher-chachapoly.o \ +@@ -121,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 \ +diff -up openssh/monitor.c.gsskex openssh/monitor.c +--- openssh/monitor.c.gsskex 2018-08-22 11:47:33.263216069 +0200 ++++ openssh/monitor.c 2018-08-22 13:22:19.589095240 +0200 +@@ -146,6 +146,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 +@@ -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 +@@ -293,6 +302,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) { +@@ -405,6 +418,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); +@@ -1695,6 +1712,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; +@@ -1785,7 +1809,7 @@ mm_answer_gss_setup_ctx(int sock, struct + u_char *p; + int r; + +- if (!options.gss_authentication) ++ if (!options.gss_authentication && !options.gss_keyex) + fatal("%s: GSSAPI authentication not enabled", __func__); + + if ((r = sshbuf_get_string(m, &p, &len)) != 0) +@@ -1818,7 +1842,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) +@@ -1839,6 +1863,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); + } +@@ -1850,7 +1875,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 || +@@ -1880,10 +1905,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) +@@ -1900,5 +1926,74 @@ mm_answer_gss_userok(int sock, struct ss + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } ++ ++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 */ + +diff -up openssh/monitor.h.gsskex openssh/monitor.h +--- openssh/monitor.h.gsskex 2018-08-22 11:47:33.263216069 +0200 ++++ openssh/monitor.h 2018-08-22 11:47:33.313216473 +0200 +@@ -58,6 +58,8 @@ enum monitor_reqtype { + #ifdef WITH_SELINUX + MONITOR_REQ_AUTHROLE = 80, + #endif ++ MONITOR_REQ_GSSSIGN = 82, MONITOR_ANS_GSSSIGN = 83, ++ MONITOR_REQ_GSSUPCREDS = 84, MONITOR_ANS_GSSUPCREDS = 85, + + MONITOR_REQ_PAM_START = 100, + MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, +diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c +--- openssh/monitor_wrap.c.gsskex 2018-08-22 11:47:33.313216473 +0200 ++++ openssh/monitor_wrap.c 2018-08-22 13:27:38.665669643 +0200 +@@ -1004,7 +1004,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; +@@ -1023,4 +1023,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 */ +diff -up openssh/monitor_wrap.h.gsskex openssh/monitor_wrap.h +--- openssh/monitor_wrap.h.gsskex 2018-08-22 11:47:33.263216069 +0200 ++++ openssh/monitor_wrap.h 2018-08-22 11:47:33.313216473 +0200 +@@ -63,8 +63,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 +diff -up openssh/readconf.c.gsskex openssh/readconf.c +--- openssh/readconf.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/readconf.c 2018-08-22 13:28:17.487982869 +0200 +@@ -161,6 +161,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, +@@ -201,10 +203,19 @@ 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 }, ++ { "gssapirenewalforcesrekey", oUnsupported }, + #endif + #ifdef ENABLE_PKCS11 + { "smartcarddevice", oPKCS11Provider }, +@@ -973,10 +984,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; +@@ -1817,7 +1848,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; +@@ -1962,8 +1998,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) +diff -up openssh/readconf.h.gsskex openssh/readconf.h +--- openssh/readconf.h.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/readconf.h 2018-08-22 11:47:33.314216481 +0200 +@@ -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. */ +diff -up openssh/regress/cert-hostkey.sh.gsskex openssh/regress/cert-hostkey.sh +--- openssh/regress/cert-hostkey.sh.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/regress/cert-hostkey.sh 2018-08-22 11:47:33.314216481 +0200 +@@ -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" +diff -up openssh/regress/cert-userkey.sh.gsskex openssh/regress/cert-userkey.sh +--- openssh/regress/cert-userkey.sh.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/regress/cert-userkey.sh 2018-08-22 11:47:33.314216481 +0200 +@@ -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 +diff -up openssh/regress/kextype.sh.gsskex openssh/regress/kextype.sh +--- openssh/regress/kextype.sh.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/regress/kextype.sh 2018-08-22 11:47:33.315216489 +0200 +@@ -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 +diff -up openssh/regress/rekey.sh.gsskex openssh/regress/rekey.sh +--- openssh/regress/rekey.sh.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/regress/rekey.sh 2018-08-22 11:47:33.315216489 +0200 +@@ -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 +diff -up openssh/servconf.c.gsskex openssh/servconf.c +--- openssh/servconf.c.gsskex 2018-08-22 11:47:33.296216335 +0200 ++++ openssh/servconf.c 2018-08-22 13:28:41.905179879 +0200 +@@ -124,8 +124,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; +@@ -334,10 +336,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) +@@ -484,7 +490,7 @@ typedef enum { + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, +- sAcceptEnv, sSetEnv, sPermitTunnel, ++ sGssKeyEx, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sHostCertificate, +@@ -559,11 +565,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 }, +@@ -1463,6 +1475,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; +@@ -1471,6 +1487,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; +@@ -2560,6 +2580,9 @@ 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); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, +diff -up openssh/servconf.h.gsskex openssh/servconf.h +--- openssh/servconf.h.gsskex 2018-08-22 11:47:33.296216335 +0200 ++++ openssh/servconf.h 2018-08-22 11:47:33.316216497 +0200 +@@ -124,8 +124,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 */ +diff -up openssh/ssh_config.5.gsskex openssh/ssh_config.5 +--- openssh/ssh_config.5.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/ssh_config.5 2018-08-22 11:47:33.316216497 +0200 +@@ -718,10 +718,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 +diff -up openssh/ssh_config.gsskex openssh/ssh_config +--- openssh/ssh_config.gsskex 2018-08-22 11:47:33.289216279 +0200 ++++ openssh/ssh_config 2018-08-22 11:47:33.316216497 +0200 +@@ -24,6 +24,8 @@ + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes + # AddressFamily any +diff -up openssh/sshconnect2.c.gsskex openssh/sshconnect2.c +--- openssh/sshconnect2.c.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/sshconnect2.c 2018-08-22 13:33:01.674275795 +0200 +@@ -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,34 @@ 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 ++ 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); ++ 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 +337,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); +@@ -214,11 +368,31 @@ ssh_kex2(char *host, struct sockaddr *ho + kex->kex[KEX_ECDH_SHA2] = kexecdh_client; + # endif + #endif ++#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->kex[KEX_C25519_SHA256] = kexc25519_client; + 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 +488,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 +505,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, +@@ -657,19 +837,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++; +@@ -906,6 +1098,48 @@ 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); ++ } ++ ++ 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 +diff -up openssh/sshd.c.gsskex openssh/sshd.c +--- openssh/sshd.c.gsskex 2018-08-22 11:47:33.299216360 +0200 ++++ openssh/sshd.c 2018-08-22 13:34:28.455975954 +0200 +@@ -537,7 +537,7 @@ privsep_preauth_child(void) + + #ifdef GSSAPI + /* Cache supported mechanism OIDs for later use */ +- if (options.gss_authentication) ++ if (options.gss_authentication || options.gss_keyex) + ssh_gssapi_prepare_supported_oids(); + #endif + +@@ -887,8 +887,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); + } + +@@ -1841,7 +1842,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); + } +@@ -2321,6 +2323,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)); +@@ -2338,6 +2382,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; +diff -up openssh/sshd_config.5.gsskex openssh/sshd_config.5 +--- openssh/sshd_config.5.gsskex 2018-08-22 11:47:33.297216344 +0200 ++++ openssh/sshd_config.5 2018-08-22 13:35:05.531275099 +0200 +@@ -642,6 +642,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. +@@ -656,6 +661,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. +diff -up openssh/sshd_config.gsskex openssh/sshd_config +--- openssh/sshd_config.gsskex 2018-08-22 11:47:33.299216360 +0200 ++++ openssh/sshd_config 2018-08-22 11:47:33.318216513 +0200 +@@ -85,6 +85,8 @@ ChallengeResponseAuthentication no + # GSSAPI options + GSSAPIAuthentication yes + GSSAPICleanupCredentials no ++#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 -up openssh/ssh-gss.h.gsskex openssh/ssh-gss.h +--- openssh/ssh-gss.h.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/ssh-gss.h 2018-08-22 13:36:44.773075793 +0200 +@@ -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,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,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 *); ++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 */ +diff -up openssh/sshkey.c.gsskex openssh/sshkey.c +--- openssh/sshkey.c.gsskex 2018-08-22 11:47:33.319216521 +0200 ++++ openssh/sshkey.c 2018-08-22 13:37:18.979351804 +0200 +@@ -140,6 +140,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 } + }; + +diff -up openssh/sshkey.h.gsskex openssh/sshkey.h +--- openssh/sshkey.h.gsskex 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/sshkey.h 2018-08-22 11:47:33.320216529 +0200 +@@ -63,6 +63,7 @@ enum sshkey_types { + KEY_ED25519_CERT, + KEY_XMSS, + KEY_XMSS_CERT, ++ KEY_NULL, + KEY_UNSPEC + }; + diff --git a/openssh-7.8p1-ip-port-config-parser.patch b/openssh-7.8p1-ip-port-config-parser.patch new file mode 100644 index 0000000..6ca0cf5 --- /dev/null +++ b/openssh-7.8p1-ip-port-config-parser.patch @@ -0,0 +1,72 @@ +diff -up openssh/misc.c.config openssh/misc.c +--- openssh/misc.c.config 2018-08-22 13:58:54.922807799 +0200 ++++ openssh/misc.c 2018-08-22 13:58:55.000808428 +0200 +@@ -485,7 +485,7 @@ put_host_port(const char *host, u_short + * The delimiter char, if present, is stored in delim. + * If this is the last field, *cp is set to NULL. + */ +-static char * ++char * + hpdelim2(char **cp, char *delim) + { + char *s, *old; +diff -up openssh/misc.h.config openssh/misc.h +--- openssh/misc.h.config 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/misc.h 2018-08-22 13:58:55.001808436 +0200 +@@ -54,6 +54,7 @@ int set_rdomain(int, const char *); + int a2port(const char *); + int a2tun(const char *, int *); + char *put_host_port(const char *, u_short); ++char *hpdelim2(char **, char *); + char *hpdelim(char **); + char *cleanhostname(char *); + char *colon(char *); +diff -up openssh/servconf.c.config openssh/servconf.c +--- openssh/servconf.c.config 2018-08-22 13:58:54.989808340 +0200 ++++ openssh/servconf.c 2018-08-22 14:18:49.235443937 +0200 +@@ -886,7 +886,7 @@ process_permitopen_list(struct ssh *ssh, + { + u_int i; + int port; +- char *host, *arg, *oarg; ++ char *host, *arg, *oarg, ch; + int where = opcode == sPermitOpen ? FORWARD_LOCAL : FORWARD_REMOTE; + const char *what = lookup_opcode_name(opcode); + +@@ -904,8 +904,8 @@ process_permitopen_list(struct ssh *ssh, + /* Otherwise treat it as a list of permitted host:port */ + for (i = 0; i < num_opens; i++) { + oarg = arg = xstrdup(opens[i]); +- host = hpdelim(&arg); +- if (host == NULL) ++ host = hpdelim2(&arg, &ch); ++ if (host == NULL || ch == '/') + fatal("%s: missing host in %s", __func__, what); + host = cleanhostname(host); + if (arg == NULL || ((port = permitopen_port(arg)) < 0)) +@@ -1323,8 +1323,10 @@ process_server_config_line(ServerOptions + port = 0; + p = arg; + } else { +- p = hpdelim(&arg); +- if (p == NULL) ++ char ch; ++ arg2 = NULL; ++ p = hpdelim2(&arg, &ch); ++ if (p == NULL || ch == '/') + fatal("%s line %d: bad address:port usage", + filename, linenum); + p = cleanhostname(p); +@@ -1965,9 +1967,10 @@ process_server_config_line(ServerOptions + */ + xasprintf(&arg2, "*:%s", arg); + } else { ++ char ch; + arg2 = xstrdup(arg); +- p = hpdelim(&arg); +- if (p == NULL) { ++ p = hpdelim2(&arg, &ch); ++ if (p == NULL || ch == '/') { + fatal("%s line %d: missing host in %s", + filename, linenum, + lookup_opcode_name(opcode)); diff --git a/openssh-7.8p1-role-mls.patch b/openssh-7.8p1-role-mls.patch new file mode 100644 index 0000000..4c58d71 --- /dev/null +++ b/openssh-7.8p1-role-mls.patch @@ -0,0 +1,885 @@ +diff -up openssh/auth2.c.role-mls openssh/auth2.c +--- openssh/auth2.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth2.c 2018-08-22 11:14:56.815430916 +0200 +@@ -256,6 +256,9 @@ input_userauth_request(int type, u_int32 + Authctxt *authctxt = ssh->authctxt; + Authmethod *m = NULL; + char *user, *service, *method, *style = NULL; ++#ifdef WITH_SELINUX ++ char *role = NULL; ++#endif + int authenticated = 0; + double tstart = monotime_double(); + +@@ -268,6 +271,11 @@ input_userauth_request(int type, u_int32 + debug("userauth-request for user %s service %s method %s", user, service, method); + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + ++#ifdef WITH_SELINUX ++ if ((role = strchr(user, '/')) != NULL) ++ *role++ = 0; ++#endif ++ + if ((style = strchr(user, ':')) != NULL) + *style++ = 0; + +@@ -296,8 +304,15 @@ input_userauth_request(int type, u_int32 + use_privsep ? " [net]" : ""); + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; +- if (use_privsep) ++#ifdef WITH_SELINUX ++ authctxt->role = role ? xstrdup(role) : NULL; ++#endif ++ if (use_privsep) { + mm_inform_authserv(service, style); ++#ifdef WITH_SELINUX ++ mm_inform_authrole(role); ++#endif ++ } + userauth_banner(); + if (auth2_setup_methods_lists(authctxt) != 0) + packet_disconnect("no authentication methods enabled"); +diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c +--- openssh/auth2-gss.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth2-gss.c 2018-08-22 11:15:42.459799171 +0200 +@@ -281,6 +281,7 @@ input_gssapi_mic(int type, u_int32_t ple + Authctxt *authctxt = ssh->authctxt; + Gssctxt *gssctxt; + int r, authenticated = 0; ++ char *micuser; + struct sshbuf *b; + gss_buffer_desc mic, gssbuf; + const char *displayname; +@@ -298,7 +299,13 @@ input_gssapi_mic(int type, u_int32_t ple + fatal("%s: sshbuf_new failed", __func__); + mic.value = p; + mic.length = len; +- ssh_gssapi_buildmic(b, authctxt->user, authctxt->service, ++#ifdef WITH_SELINUX ++ if (authctxt->role && (strlen(authctxt->role) > 0)) ++ xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role); ++ else ++#endif ++ micuser = authctxt->user; ++ ssh_gssapi_buildmic(b, micuser, authctxt->service, + "gssapi-with-mic"); + + if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) +@@ -311,6 +318,8 @@ input_gssapi_mic(int type, u_int32_t ple + logit("GSSAPI MIC check failed"); + + sshbuf_free(b); ++ if (micuser != authctxt->user) ++ free(micuser); + free(mic.value); + + if ((!use_privsep || mm_is_monitor()) && +diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c +--- openssh/auth2-hostbased.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth2-hostbased.c 2018-08-22 11:14:56.816430924 +0200 +@@ -123,7 +123,16 @@ userauth_hostbased(struct ssh *ssh) + /* reconstruct packet */ + if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || + (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || ++#ifdef WITH_SELINUX ++ (authctxt->role ++ ? ( (r = sshbuf_put_u32(b, strlen(authctxt->user)+strlen(authctxt->role)+1)) != 0 || ++ (r = sshbuf_put(b, authctxt->user, strlen(authctxt->user))) != 0 || ++ (r = sshbuf_put_u8(b, '/') != 0) || ++ (r = sshbuf_put(b, authctxt->role, strlen(authctxt->role))) != 0) ++ : (r = sshbuf_put_cstring(b, authctxt->user)) != 0) || ++#else + (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || ++#endif + (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || + (r = sshbuf_put_cstring(b, "hostbased")) != 0 || + (r = sshbuf_put_string(b, pkalg, alen)) != 0 || +diff -up openssh/auth2-pubkey.c.role-mls openssh/auth2-pubkey.c +--- openssh/auth2-pubkey.c.role-mls 2018-08-22 11:14:56.816430924 +0200 ++++ openssh/auth2-pubkey.c 2018-08-22 11:17:07.331483958 +0200 +@@ -169,9 +169,16 @@ userauth_pubkey(struct ssh *ssh) + goto done; + } + /* reconstruct packet */ +- xasprintf(&userstyle, "%s%s%s", authctxt->user, ++ xasprintf(&userstyle, "%s%s%s%s%s", authctxt->user, + authctxt->style ? ":" : "", +- authctxt->style ? authctxt->style : ""); ++ authctxt->style ? authctxt->style : "", ++#ifdef WITH_SELINUX ++ authctxt->role ? "/" : "", ++ authctxt->role ? authctxt->role : "" ++#else ++ "", "" ++#endif ++ ); + if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || + (r = sshbuf_put_cstring(b, userstyle)) != 0 || + (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || +diff -up openssh/auth.h.role-mls openssh/auth.h +--- openssh/auth.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth.h 2018-08-22 11:14:56.816430924 +0200 +@@ -65,6 +65,9 @@ struct Authctxt { + char *service; + struct passwd *pw; /* set if 'valid' */ + char *style; ++#ifdef WITH_SELINUX ++ char *role; ++#endif + + /* Method lists for multiple authentication */ + char **auth_methods; /* modified from server config */ +diff -up openssh/auth-pam.c.role-mls openssh/auth-pam.c +--- openssh/auth-pam.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth-pam.c 2018-08-22 11:14:56.816430924 +0200 +@@ -1172,7 +1172,7 @@ is_pam_session_open(void) + * during the ssh authentication process. + */ + int +-do_pam_putenv(char *name, char *value) ++do_pam_putenv(char *name, const char *value) + { + int ret = 1; + #ifdef HAVE_PAM_PUTENV +diff -up openssh/auth-pam.h.role-mls openssh/auth-pam.h +--- openssh/auth-pam.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth-pam.h 2018-08-22 11:14:56.817430932 +0200 +@@ -33,7 +33,7 @@ u_int do_pam_account(void); + void do_pam_session(struct ssh *); + void do_pam_setcred(int ); + void do_pam_chauthtok(void); +-int do_pam_putenv(char *, char *); ++int do_pam_putenv(char *, const char *); + char ** fetch_pam_environment(void); + char ** fetch_pam_child_environment(void); + void free_pam_environment(char **); +diff -up openssh/configure.ac.role-mls openssh/configure.ac +--- openssh/configure.ac.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/configure.ac 2018-08-22 11:14:56.820430957 +0200 +@@ -4241,10 +4241,7 @@ AC_ARG_WITH([selinux], + LIBS="$LIBS -lselinux" + ], + AC_MSG_ERROR([SELinux support requires libselinux library])) +- SSHLIBS="$SSHLIBS $LIBSELINUX" +- SSHDLIBS="$SSHDLIBS $LIBSELINUX" + AC_CHECK_FUNCS([getseuserbyname get_default_context_with_level]) +- LIBS="$save_LIBS" + fi ] + ) + AC_SUBST([SSHLIBS]) +diff -up openssh/misc.c.role-mls openssh/misc.c +--- openssh/misc.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/misc.c 2018-08-22 11:14:56.817430932 +0200 +@@ -542,6 +542,7 @@ char * + colon(char *cp) + { + int flag = 0; ++ int start = 1; + + if (*cp == ':') /* Leading colon is part of file name. */ + return NULL; +@@ -557,6 +558,13 @@ colon(char *cp) + return (cp); + if (*cp == '/') + return NULL; ++ if (start) { ++ /* Slash on beginning or after dots only denotes file name. */ ++ if (*cp == '/') ++ return (0); ++ if (*cp != '.') ++ start = 0; ++ } + } + return NULL; + } +diff -up openssh/monitor.c.role-mls openssh/monitor.c +--- openssh/monitor.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/monitor.c 2018-08-22 11:19:56.006844867 +0200 +@@ -115,6 +115,9 @@ int mm_answer_sign(int, struct sshbuf *) + int mm_answer_pwnamallow(int, struct sshbuf *); + int mm_answer_auth2_read_banner(int, struct sshbuf *); + int mm_answer_authserv(int, struct sshbuf *); ++#ifdef WITH_SELINUX ++int mm_answer_authrole(int, struct sshbuf *); ++#endif + int mm_answer_authpassword(int, struct sshbuf *); + int mm_answer_bsdauthquery(int, struct sshbuf *); + int mm_answer_bsdauthrespond(int, struct sshbuf *); +@@ -189,6 +192,9 @@ struct mon_table mon_dispatch_proto20[] + {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, ++#ifdef WITH_SELINUX ++ {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, ++#endif + {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, + #ifdef USE_PAM +@@ -796,6 +802,9 @@ mm_answer_pwnamallow(int sock, struct ss + + /* Allow service/style information on the auth context */ + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); ++#ifdef WITH_SELINUX ++ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHROLE, 1); ++#endif + monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); + + #ifdef USE_PAM +@@ -842,6 +851,26 @@ mm_answer_authserv(int sock, struct sshb + return (0); + } + ++#ifdef WITH_SELINUX ++int ++mm_answer_authrole(int sock, struct sshbuf *m) ++{ ++ int r; ++ monitor_permit_authentications(1); ++ ++ if ((r = sshbuf_get_cstring(m, &authctxt->role, NULL)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ debug3("%s: role=%s", __func__, authctxt->role); ++ ++ if (strlen(authctxt->role) == 0) { ++ free(authctxt->role); ++ authctxt->role = NULL; ++ } ++ ++ return (0); ++} ++#endif ++ + int + mm_answer_authpassword(int sock, struct sshbuf *m) + { +@@ -1218,7 +1247,7 @@ monitor_valid_userblob(u_char *data, u_i + { + struct sshbuf *b; + const u_char *p; +- char *userstyle, *cp; ++ char *userstyle, *s, *cp; + size_t len; + u_char type; + int r, fail = 0; +@@ -1251,6 +1280,8 @@ monitor_valid_userblob(u_char *data, u_i + fail++; + if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((s = strchr(cp, '/')) != NULL) ++ *s = '\0'; + xasprintf(&userstyle, "%s%s%s", authctxt->user, + authctxt->style ? ":" : "", + authctxt->style ? authctxt->style : ""); +@@ -1286,7 +1317,7 @@ monitor_valid_hostbasedblob(u_char *data + { + struct sshbuf *b; + const u_char *p; +- char *cp, *userstyle; ++ char *cp, *s, *userstyle; + size_t len; + int r, fail = 0; + u_char type; +@@ -1308,6 +1339,8 @@ monitor_valid_hostbasedblob(u_char *data + fail++; + if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if ((s = strchr(p, '/')) != NULL) ++ *s = '\0'; + xasprintf(&userstyle, "%s%s%s", authctxt->user, + authctxt->style ? ":" : "", + authctxt->style ? authctxt->style : ""); +diff -up openssh/monitor.h.role-mls openssh/monitor.h +--- openssh/monitor.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/monitor.h 2018-08-22 11:14:56.818430941 +0200 +@@ -55,6 +55,10 @@ enum monitor_reqtype { + MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, + MONITOR_REQ_TERM = 50, + ++#ifdef WITH_SELINUX ++ MONITOR_REQ_AUTHROLE = 80, ++#endif ++ + MONITOR_REQ_PAM_START = 100, + MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, + MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105, +diff -up openssh/monitor_wrap.c.role-mls openssh/monitor_wrap.c +--- openssh/monitor_wrap.c.role-mls 2018-08-22 11:14:56.818430941 +0200 ++++ openssh/monitor_wrap.c 2018-08-22 11:21:47.938747968 +0200 +@@ -390,6 +390,27 @@ mm_inform_authserv(char *service, char * + sshbuf_free(m); + } + ++/* Inform the privileged process about role */ ++ ++#ifdef WITH_SELINUX ++void ++mm_inform_authrole(char *role) ++{ ++ int r; ++ struct sshbuf *m; ++ ++ debug3("%s entering", __func__); ++ ++ if ((m = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_cstring(m, role ? role : "")) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHROLE, m); ++ ++ sshbuf_free(m); ++} ++#endif ++ + /* Do the password authentication */ + int + mm_auth_password(struct ssh *ssh, char *password) +diff -up openssh/monitor_wrap.h.role-mls openssh/monitor_wrap.h +--- openssh/monitor_wrap.h.role-mls 2018-08-22 11:14:56.818430941 +0200 ++++ openssh/monitor_wrap.h 2018-08-22 11:22:10.439929513 +0200 +@@ -44,6 +44,9 @@ DH *mm_choose_dh(int, int, int); + int mm_sshkey_sign(struct sshkey *, u_char **, size_t *, const u_char *, size_t, + const char *, u_int compat); + void mm_inform_authserv(char *, char *); ++#ifdef WITH_SELINUX ++void mm_inform_authrole(char *); ++#endif + struct passwd *mm_getpwnamallow(const char *); + char *mm_auth2_read_banner(void); + int mm_auth_password(struct ssh *, char *); +diff -up openssh/openbsd-compat/Makefile.in.role-mls openssh/openbsd-compat/Makefile.in +--- openssh/openbsd-compat/Makefile.in.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/Makefile.in 2018-08-22 11:14:56.819430949 +0200 +@@ -92,7 +92,8 @@ PORTS= port-aix.o \ + port-linux.o \ + port-solaris.o \ + port-net.o \ +- port-uw.o ++ port-uw.o \ ++ port-linux-sshd.o + + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< +diff -up openssh/openbsd-compat/port-linux.c.role-mls openssh/openbsd-compat/port-linux.c +--- openssh/openbsd-compat/port-linux.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/port-linux.c 2018-08-22 11:14:56.819430949 +0200 +@@ -100,37 +100,6 @@ ssh_selinux_getctxbyname(char *pwname) + return sc; + } + +-/* Set the execution context to the default for the specified user */ +-void +-ssh_selinux_setup_exec_context(char *pwname) +-{ +- security_context_t user_ctx = NULL; +- +- if (!ssh_selinux_enabled()) +- return; +- +- debug3("%s: setting execution context", __func__); +- +- user_ctx = ssh_selinux_getctxbyname(pwname); +- if (setexeccon(user_ctx) != 0) { +- switch (security_getenforce()) { +- case -1: +- fatal("%s: security_getenforce() failed", __func__); +- case 0: +- error("%s: Failed to set SELinux execution " +- "context for %s", __func__, pwname); +- break; +- default: +- fatal("%s: Failed to set SELinux execution context " +- "for %s (in enforcing mode)", __func__, pwname); +- } +- } +- if (user_ctx != NULL) +- freecon(user_ctx); +- +- debug3("%s: done", __func__); +-} +- + /* Set the TTY context for the specified user */ + void + ssh_selinux_setup_pty(char *pwname, const char *tty) +@@ -145,7 +114,11 @@ ssh_selinux_setup_pty(char *pwname, cons + + debug3("%s: setting TTY context on %s", __func__, tty); + +- user_ctx = ssh_selinux_getctxbyname(pwname); ++ if (getexeccon(&user_ctx) != 0) { ++ error("%s: getexeccon: %s", __func__, strerror(errno)); ++ goto out; ++ } ++ + + /* XXX: should these calls fatal() upon failure in enforcing mode? */ + +diff -up openssh/openbsd-compat/port-linux.h.role-mls openssh/openbsd-compat/port-linux.h +--- openssh/openbsd-compat/port-linux.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/port-linux.h 2018-08-22 11:14:56.819430949 +0200 +@@ -20,9 +20,10 @@ + #ifdef WITH_SELINUX + int ssh_selinux_enabled(void); + void ssh_selinux_setup_pty(char *, const char *); +-void ssh_selinux_setup_exec_context(char *); + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); ++ ++void sshd_selinux_setup_exec_context(char *); + #endif + + #ifdef LINUX_OOM_ADJUST +diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compat/port-linux-sshd.c +--- openssh/openbsd-compat/port-linux-sshd.c.role-mls 2018-08-22 11:14:56.819430949 +0200 ++++ openssh/openbsd-compat/port-linux-sshd.c 2018-08-22 11:14:56.819430949 +0200 +@@ -0,0 +1,425 @@ ++/* ++ * Copyright (c) 2005 Daniel Walsh ++ * Copyright (c) 2014 Petr Lautrbach ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Linux-specific portability code - just SELinux support for sshd at present ++ */ ++ ++#include "includes.h" ++ ++#if defined(WITH_SELINUX) || defined(LINUX_OOM_ADJUST) ++#include ++#include ++#include ++#include ++#include ++ ++#include "log.h" ++#include "xmalloc.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ ++#include "servconf.h" ++#include "port-linux.h" ++#include "sshkey.h" ++#include "hostfile.h" ++#include "auth.h" ++ ++#ifdef WITH_SELINUX ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_LINUX_AUDIT ++#include ++#include ++#endif ++ ++extern ServerOptions options; ++extern Authctxt *the_authctxt; ++extern int inetd_flag; ++extern int rexeced_flag; ++ ++/* Send audit message */ ++static int ++sshd_selinux_send_audit_message(int success, security_context_t default_context, ++ security_context_t selected_context) ++{ ++ int rc=0; ++#ifdef HAVE_LINUX_AUDIT ++ char *msg = NULL; ++ int audit_fd = audit_open(); ++ security_context_t default_raw=NULL; ++ security_context_t selected_raw=NULL; ++ rc = -1; ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return 0; /* No audit support in kernel */ ++ error("Error connecting to audit system."); ++ return rc; ++ } ++ if (selinux_trans_to_raw_context(default_context, &default_raw) < 0) { ++ error("Error translating default context."); ++ default_raw = NULL; ++ } ++ if (selinux_trans_to_raw_context(selected_context, &selected_raw) < 0) { ++ error("Error translating selected context."); ++ selected_raw = NULL; ++ } ++ if (asprintf(&msg, "sshd: default-context=%s selected-context=%s", ++ default_raw ? default_raw : (default_context ? default_context: "?"), ++ selected_context ? selected_raw : (selected_context ? selected_context :"?")) < 0) { ++ error("Error allocating memory."); ++ goto out; ++ } ++ if (audit_log_user_message(audit_fd, AUDIT_USER_ROLE_CHANGE, ++ msg, NULL, NULL, NULL, success) <= 0) { ++ error("Error sending audit message."); ++ goto out; ++ } ++ rc = 0; ++ out: ++ free(msg); ++ freecon(default_raw); ++ freecon(selected_raw); ++ close(audit_fd); ++#endif ++ return rc; ++} ++ ++static int ++mls_range_allowed(security_context_t src, security_context_t dst) ++{ ++ struct av_decision avd; ++ int retval; ++ access_vector_t bit; ++ security_class_t class; ++ ++ debug("%s: src:%s dst:%s", __func__, src, dst); ++ class = string_to_security_class("context"); ++ if (!class) { ++ error("string_to_security_class failed to translate security class context"); ++ return 1; ++ } ++ bit = string_to_av_perm(class, "contains"); ++ if (!bit) { ++ error("string_to_av_perm failed to translate av perm contains"); ++ return 1; ++ } ++ retval = security_compute_av(src, dst, class, bit, &avd); ++ if (retval || ((bit & avd.allowed) != bit)) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++get_user_context(const char *sename, const char *role, const char *lvl, ++ security_context_t *sc) { ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ if (lvl == NULL || lvl[0] == '\0' || get_default_context_with_level(sename, lvl, NULL, sc) != 0) { ++ /* User may have requested a level completely outside of his ++ allowed range. We get a context just for auditing as the ++ range check below will certainly fail for default context. */ ++#endif ++ if (get_default_context(sename, NULL, sc) != 0) { ++ *sc = NULL; ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ } ++#endif ++ if (role != NULL && role[0]) { ++ context_t con; ++ char *type=NULL; ++ if (get_default_type(role, &type) != 0) { ++ error("get_default_type: failed to get default type for '%s'", ++ role); ++ goto out; ++ } ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_role_set(con, role); ++ context_type_set(con, type); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ if (!*sc) ++ return -1; ++ } ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ if (lvl != NULL && lvl[0]) { ++ /* verify that the requested range is obtained */ ++ context_t con; ++ security_context_t obtained_raw; ++ security_context_t requested_raw; ++ con = context_new(*sc); ++ if (!con) { ++ goto out; ++ } ++ context_range_set(con, lvl); ++ if (selinux_trans_to_raw_context(*sc, &obtained_raw) < 0) { ++ context_free(con); ++ goto out; ++ } ++ if (selinux_trans_to_raw_context(context_str(con), &requested_raw) < 0) { ++ freecon(obtained_raw); ++ context_free(con); ++ goto out; ++ } ++ ++ debug("get_user_context: obtained context '%s' requested context '%s'", ++ obtained_raw, requested_raw); ++ if (strcmp(obtained_raw, requested_raw)) { ++ /* set the context to the real requested one but fail */ ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ freecon(*sc); ++ *sc = strdup(context_str(con)); ++ context_free(con); ++ return -1; ++ } ++ freecon(requested_raw); ++ freecon(obtained_raw); ++ context_free(con); ++ } ++#endif ++ return 0; ++ out: ++ freecon(*sc); ++ *sc = NULL; ++ return -1; ++} ++ ++static void ++ssh_selinux_get_role_level(char **role, const char **level) ++{ ++ *role = NULL; ++ *level = NULL; ++ if (the_authctxt) { ++ if (the_authctxt->role != NULL) { ++ char *slash; ++ *role = xstrdup(the_authctxt->role); ++ if ((slash = strchr(*role, '/')) != NULL) { ++ *slash = '\0'; ++ *level = slash + 1; ++ } ++ } ++ } ++} ++ ++/* Return the default security context for the given username */ ++static int ++sshd_selinux_getctxbyname(char *pwname, ++ security_context_t *default_sc, security_context_t *user_sc) ++{ ++ char *sename, *lvl; ++ char *role; ++ const char *reqlvl; ++ int r = 0; ++ context_t con = NULL; ++ ++ ssh_selinux_get_role_level(&role, &reqlvl); ++ ++#ifdef HAVE_GETSEUSERBYNAME ++ if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { ++ sename = NULL; ++ lvl = NULL; ++ } ++#else ++ sename = pwname; ++ lvl = ""; ++#endif ++ ++ if (r == 0) { ++#ifdef HAVE_GET_DEFAULT_CONTEXT_WITH_LEVEL ++ r = get_default_context_with_level(sename, lvl, NULL, default_sc); ++#else ++ r = get_default_context(sename, NULL, default_sc); ++#endif ++ } ++ ++ if (r == 0) { ++ /* If launched from xinetd, we must use current level */ ++ if (inetd_flag && !rexeced_flag) { ++ security_context_t sshdsc=NULL; ++ ++ if (getcon_raw(&sshdsc) < 0) ++ fatal("failed to allocate security context"); ++ ++ if ((con=context_new(sshdsc)) == NULL) ++ fatal("failed to allocate selinux context"); ++ reqlvl = context_range_get(con); ++ freecon(sshdsc); ++ if (reqlvl !=NULL && lvl != NULL && strcmp(reqlvl, lvl) == 0) ++ /* we actually don't change level */ ++ reqlvl = ""; ++ ++ debug("%s: current connection level '%s'", __func__, reqlvl); ++ ++ } ++ ++ if ((reqlvl != NULL && reqlvl[0]) || (role != NULL && role[0])) { ++ r = get_user_context(sename, role, reqlvl, user_sc); ++ ++ if (r == 0 && reqlvl != NULL && reqlvl[0]) { ++ security_context_t default_level_sc = *default_sc; ++ if (role != NULL && role[0]) { ++ if (get_user_context(sename, role, lvl, &default_level_sc) < 0) ++ default_level_sc = *default_sc; ++ } ++ /* verify that the requested range is contained in the user range */ ++ if (mls_range_allowed(default_level_sc, *user_sc)) { ++ logit("permit MLS level %s (user range %s)", reqlvl, lvl); ++ } else { ++ r = -1; ++ error("deny MLS level %s (user range %s)", reqlvl, lvl); ++ } ++ if (default_level_sc != *default_sc) ++ freecon(default_level_sc); ++ } ++ } else { ++ *user_sc = *default_sc; ++ } ++ } ++ if (r != 0) { ++ error("%s: Failed to get default SELinux security " ++ "context for %s", __func__, pwname); ++ } ++ ++#ifdef HAVE_GETSEUSERBYNAME ++ free(sename); ++ free(lvl); ++#endif ++ ++ if (role != NULL) ++ free(role); ++ if (con) ++ context_free(con); ++ ++ return (r); ++} ++ ++/* Setup environment variables for pam_selinux */ ++static int ++sshd_selinux_setup_pam_variables(void) ++{ ++ const char *reqlvl; ++ char *role; ++ char *use_current; ++ int rv; ++ ++ debug3("%s: setting execution context", __func__); ++ ++ ssh_selinux_get_role_level(&role, &reqlvl); ++ ++ rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); ++ ++ if (inetd_flag && !rexeced_flag) { ++ use_current = "1"; ++ } else { ++ use_current = ""; ++ rv = rv || do_pam_putenv("SELINUX_LEVEL_REQUESTED", reqlvl ? reqlvl: ""); ++ } ++ ++ rv = rv || do_pam_putenv("SELINUX_USE_CURRENT_RANGE", use_current); ++ ++ if (role != NULL) ++ free(role); ++ ++ return rv; ++} ++ ++/* Set the execution context to the default for the specified user */ ++void ++sshd_selinux_setup_exec_context(char *pwname) ++{ ++ security_context_t user_ctx = NULL; ++ int r = 0; ++ security_context_t default_ctx = NULL; ++ ++ if (!ssh_selinux_enabled()) ++ return; ++ ++ if (options.use_pam) { ++ /* do not compute context, just setup environment for pam_selinux */ ++ if (sshd_selinux_setup_pam_variables()) { ++ switch (security_getenforce()) { ++ case -1: ++ fatal("%s: security_getenforce() failed", __func__); ++ case 0: ++ error("%s: SELinux PAM variable setup failure. Continuing in permissive mode.", ++ __func__); ++ break; ++ default: ++ fatal("%s: SELinux PAM variable setup failure. Aborting connection.", ++ __func__); ++ } ++ } ++ return; ++ } ++ ++ debug3("%s: setting execution context", __func__); ++ ++ r = sshd_selinux_getctxbyname(pwname, &default_ctx, &user_ctx); ++ if (r >= 0) { ++ r = setexeccon(user_ctx); ++ if (r < 0) { ++ error("%s: Failed to set SELinux execution context %s for %s", ++ __func__, user_ctx, pwname); ++ } ++#ifdef HAVE_SETKEYCREATECON ++ else if (setkeycreatecon(user_ctx) < 0) { ++ error("%s: Failed to set SELinux keyring creation context %s for %s", ++ __func__, user_ctx, pwname); ++ } ++#endif ++ } ++ if (user_ctx == NULL) { ++ user_ctx = default_ctx; ++ } ++ if (r < 0 || user_ctx != default_ctx) { ++ /* audit just the case when user changed a role or there was ++ a failure */ ++ sshd_selinux_send_audit_message(r >= 0, default_ctx, user_ctx); ++ } ++ if (r < 0) { ++ switch (security_getenforce()) { ++ case -1: ++ fatal("%s: security_getenforce() failed", __func__); ++ case 0: ++ error("%s: SELinux failure. Continuing in permissive mode.", ++ __func__); ++ break; ++ default: ++ fatal("%s: SELinux failure. Aborting connection.", ++ __func__); ++ } ++ } ++ if (user_ctx != NULL && user_ctx != default_ctx) ++ freecon(user_ctx); ++ if (default_ctx != NULL) ++ freecon(default_ctx); ++ ++ debug3("%s: done", __func__); ++} ++ ++#endif ++#endif ++ +diff -up openssh/platform.c.role-mls openssh/platform.c +--- openssh/platform.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/platform.c 2018-08-22 11:14:56.819430949 +0200 +@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(stru + } + #endif /* HAVE_SETPCRED */ + #ifdef WITH_SELINUX +- ssh_selinux_setup_exec_context(pw->pw_name); ++ sshd_selinux_setup_exec_context(pw->pw_name); + #endif + } + +diff -up openssh/sshd.c.role-mls openssh/sshd.c +--- openssh/sshd.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/sshd.c 2018-08-22 11:14:56.820430957 +0200 +@@ -2186,6 +2186,9 @@ main(int ac, char **av) + restore_uid(); + } + #endif ++#ifdef WITH_SELINUX ++ sshd_selinux_setup_exec_context(authctxt->pw->pw_name); ++#endif + #ifdef USE_PAM + if (options.use_pam) { + do_pam_setcred(1); diff --git a/openssh.spec b/openssh.spec index 0beae40..a4fb7ad 100644 --- a/openssh.spec +++ b/openssh.spec @@ -65,10 +65,10 @@ %endif # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%global openssh_ver 7.7p1 -%global openssh_rel 6 +%global openssh_ver 7.8p1 +%global openssh_rel 1 %global pam_ssh_agent_ver 0.10.3 -%global pam_ssh_agent_rel 4 +%global pam_ssh_agent_rel 5 Summary: An open source implementation of SSH protocol version 2 Name: openssh @@ -100,8 +100,6 @@ Patch100: openssh-6.7p1-coverity.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1894 #https://bugzilla.redhat.com/show_bug.cgi?id=735889 #Patch102: openssh-5.8p1-getaddrinfo.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1889 -Patch103: openssh-5.8p1-packet.patch # OpenSSL 1.1.0 compatibility Patch104: openssh-7.3p1-openssl-1.1.0.patch @@ -129,7 +127,7 @@ Patch306: pam_ssh_agent_auth-0.10.2-compat.patch Patch307: pam_ssh_agent_auth-0.10.2-dereference.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) -Patch400: openssh-6.6p1-role-mls.patch +Patch400: openssh-7.8p1-role-mls.patch #https://bugzilla.redhat.com/show_bug.cgi?id=781634 Patch404: openssh-6.6p1-privsep-selinux.patch @@ -157,12 +155,10 @@ Patch702: openssh-5.1p1-askpass-progress.patch Patch703: openssh-4.3p2-askpass-grab-info.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX) Patch707: openssh-7.7p1-redhat.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1890 (WONTFIX) need integration to prng helper which is discontinued :) -Patch708: openssh-6.6p1-entropy.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1640 (WONTFIX) Patch709: openssh-6.2p1-vendor.patch # warn users for unsupported UsePAM=no (#757545) -Patch711: openssh-7.2p2-UsePAM-UseLogin-warning.patch +Patch711: openssh-7.8p1-UsePAM-warning.patch # make aes-ctr ciphers use EVP engines such as AES-NI from OpenSSL Patch712: openssh-6.3p1-ctr-evp-fast.patch # add cavs test binary for the aes-ctr @@ -173,7 +169,7 @@ Patch714: openssh-6.7p1-kdf-cavs.patch #http://www.sxw.org.uk/computing/patches/openssh.html #changed cache storage type - #848228 -Patch800: openssh-7.2p1-gsskex.patch +Patch800: openssh-7.8p1-gsskex.patch #http://www.mail-archive.com/kerberos@mit.edu/msg17591.html Patch801: openssh-6.6p1-force_krb.patch # add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) @@ -204,7 +200,7 @@ Patch918: openssh-6.6.1p1-log-in-chroot.patch # scp file into non-existing directory (#1142223) Patch919: openssh-6.6.1p1-scp-non-existing-directory.patch # Config parser shouldn't accept ip/port syntax (#1130733) -Patch920: openssh-6.6.1p1-ip-port-config-parser.patch +Patch920: openssh-7.8p1-ip-port-config-parser.patch # apply upstream patch and make sshd -T more consistent (#1187521) Patch922: openssh-6.8p1-sshdT-output.patch # Add sftp option to force mode of created files (#1191055) @@ -213,8 +209,6 @@ Patch926: openssh-6.7p1-sftp-force-permission.patch Patch929: openssh-6.9p1-permit-root-login.patch # Add GSSAPIKexAlgorithms option for server and client application Patch932: openssh-7.0p1-gssKexAlgorithms.patch -# Possibility to validate legacy systems by more fingerprints (#1249626)(#2439) -Patch933: openssh-7.0p1-show-more-fingerprints.patch # make s390 use /dev/ crypto devices -- ignore closefrom Patch939: openssh-7.2p2-s390-closefrom.patch # Move MAX_DISPLAYS to a configuration option (#1341302) @@ -229,8 +223,6 @@ Patch950: openssh-7.5p1-sandbox.patch Patch951: openssh-7.6p1-pkcs11-uri.patch # PKCS#11 ECDSA keys (upstream #2474, 8th iteration) Patch952: openssh-7.6p1-pkcs11-ecdsa.patch -# Opening tun devices fails + other regressions in OpenSSH v7.7 (#2855, #1567775) -Patch953: openssh-7.7p1-tun-devices.patch License: BSD Group: Applications/Internet @@ -326,7 +318,7 @@ Requires: openssh = %{version}-%{release} Summary: PAM module for authentication with ssh-agent Group: System Environment/Base Version: %{pam_ssh_agent_ver} -Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel}.1 +Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel} License: BSD %description @@ -390,7 +382,6 @@ gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} %endif # investigate %patch102 -p1 -b .getaddrinfo -%patch103 -p1 -b .packet %if %{pam_ssh_agent} pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} @@ -421,7 +412,6 @@ popd %patch702 -p1 -b .progress %patch703 -p1 -b .grab-info %patch707 -p1 -b .redhat -%patch708 -p1 -b .entropy %patch709 -p1 -b .vendor %patch711 -p1 -b .log-usepam-no %patch712 -p1 -b .evp-ctr @@ -447,7 +437,6 @@ popd %patch926 -p1 -b .sftp-force-mode %patch929 -p1 -b .root-login %patch932 -p1 -b .gsskexalg -%patch933 -p1 -b .fingerprint %patch939 -p1 -b .s390-dev %patch944 -p1 -b .x11max %patch948 -p1 -b .systemd @@ -456,7 +445,6 @@ popd %patch950 -p1 -b .sandbox %patch951 -p1 -b .pkcs11-uri %patch952 -p1 -b .pkcs11-ecdsa -%patch953 -p1 -b .tun-devices %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race diff --git a/pam_ssh_agent_auth-0.10.2-compat.patch b/pam_ssh_agent_auth-0.10.2-compat.patch index da5c38c..a7fda5b 100644 --- a/pam_ssh_agent_auth-0.10.2-compat.patch +++ b/pam_ssh_agent_auth-0.10.2-compat.patch @@ -1,7 +1,15 @@ -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c 2017-02-07 14:41:20.483509205 +0100 -@@ -65,8 +65,8 @@ proc_pid_cmdline(char *** inargv) +diff -up openssh/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/get_command_line.c +--- openssh/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/get_command_line.c 2018-08-24 10:22:56.281930322 +0200 +@@ -27,6 +27,7 @@ + * or implied, of Jamie Beverly. + */ + ++#include + #include + #include + #include +@@ -65,8 +66,8 @@ proc_pid_cmdline(char *** inargv) case EOF: case '\0': if (len > 0) { @@ -12,7 +20,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat strncpy(argv[count++], argbuf, len); memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); len = 0; -@@ -105,9 +105,9 @@ pamsshagentauth_free_command_line(char * +@@ -105,9 +106,9 @@ pamsshagentauth_free_command_line(char * { size_t i; for (i = 0; i < n_args; i++) @@ -24,9 +32,43 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-compat return; } -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-compat 2017-02-07 14:41:20.479509208 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 14:41:20.481509206 +0100 +diff -up openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/identity.h +--- openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/identity.h 2018-08-24 10:18:05.009393312 +0200 +@@ -30,8 +30,8 @@ + #include "openbsd-compat/sys-queue.h" + #include "xmalloc.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "authfd.h" + #include + +@@ -41,7 +41,7 @@ typedef struct idlist Idlist; + struct identity { + TAILQ_ENTRY(identity) next; + AuthenticationConnection *ac; /* set if agent supports key */ +- Key *key; /* public/private key */ ++ struct sshkey *key; /* public/private key */ + char *filename; /* comment for agent-only keys */ + int tried; + int isprivate; /* key points to the private key */ +diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c +--- openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-compat 2018-08-24 10:18:05.007393297 +0200 ++++ openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2018-08-24 10:18:32.937612513 +0200 +@@ -36,8 +36,8 @@ + #include "openbsd-compat/sys-queue.h" + #include "xmalloc.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "authfd.h" + #include + #include @@ -58,6 +58,8 @@ #include "get_command_line.h" extern char **environ; @@ -45,25 +87,48 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c for (i = 0; i < count; i++) { strcat(buf, (i > 0) ? " '" : "'"); strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); -@@ -90,12 +92,12 @@ void - agent_action(Buffer *buf, char ** action, size_t count) +@@ -87,21 +89,25 @@ log_action(char ** action, size_t count) + } + + void +-agent_action(Buffer *buf, char ** action, size_t count) ++agent_action(struct sshbuf *buf, char ** action, size_t count) { size_t i; - pamsshagentauth_buffer_init(buf); -+ buffer_init(buf); ++ int r; - pamsshagentauth_buffer_put_int(buf, count); -+ buffer_put_int(buf, count); ++ if ((buf = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(buf, count)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); for (i = 0; i < count; i++) { - pamsshagentauth_buffer_put_cstring(buf, action[i]); -+ buffer_put_cstring(buf, action[i]); ++ if ((r = sshbuf_put_cstring(buf, action[i])) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); } } -@@ -119,17 +121,17 @@ pamsshagentauth_session_id2_gen(Buffer * + +-void +-pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, ++static void ++pamsshagentauth_session_id2_gen(struct sshbuf ** session_id2, const char * user, + const char * ruser, const char * servicename) + { + u_char *cookie = NULL; +@@ -114,22 +116,23 @@ pamsshagentauth_session_id2_gen(Buffer * + char ** reported_argv = NULL; + size_t count = 0; + char * action_logbuf = NULL; +- Buffer action_agentbuf; ++ struct sshbuf *action_agentbuf = NULL; + uint8_t free_logbuf = 0; char * retc; int32_t reti; ++ int r; - rnd = pamsshagentauth_arc4random(); + rnd = arc4random(); @@ -73,7 +138,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c } - cookie = pamsshagentauth_xcalloc(1,cookie_len); -+ cookie = xcalloc(1,cookie_len); ++ cookie = xcalloc(1, cookie_len); for (i = 0; i < cookie_len; i++) { if (i % 4 == 0) { @@ -82,21 +147,29 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c } cookie[i] = (u_char) rnd; rnd >>= 8; -@@ -144,7 +146,7 @@ pamsshagentauth_session_id2_gen(Buffer * +@@ -139,12 +141,13 @@ pamsshagentauth_session_id2_gen(Buffer * + if (count > 0) { + free_logbuf = 1; + action_logbuf = log_action(reported_argv, count); +- agent_action(&action_agentbuf, reported_argv, count); ++ agent_action(action_agentbuf, reported_argv, count); + pamsshagentauth_free_command_line(reported_argv, count); } else { action_logbuf = "unknown on this platform"; - pamsshagentauth_buffer_init(&action_agentbuf); /* stays empty, means unavailable */ -+ buffer_init(&action_agentbuf); /* stays empty, means unavailable */ ++ if ((action_agentbuf = sshbuf_new()) == NULL) /* stays empty, means unavailable */ ++ fatal("%s: sshbuf_new failed", __func__); } /* -@@ -161,35 +163,35 @@ pamsshagentauth_session_id2_gen(Buffer * +@@ -161,35 +163,39 @@ pamsshagentauth_session_id2_gen(Buffer * retc = getcwd(pwd, sizeof(pwd) - 1); time(&ts); - pamsshagentauth_buffer_init(session_id2); -+ buffer_init(session_id2); ++ if ((*session_id2 = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); - pamsshagentauth_buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); - /* pamsshagentauth_debug3("cookie: %s", pamsshagentauth_tohex(cookie, cookie_len)); */ @@ -108,49 +181,81 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c - /* pamsshagentauth_debug3("servicename: %s", servicename); */ - pamsshagentauth_buffer_put_cstring(session_id2, servicename); - /* pamsshagentauth_debug3("pwd: %s", pwd); */ -+ buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); -+ /* debug3("cookie: %s", tohex(cookie, cookie_len)); */ -+ buffer_put_string(session_id2, cookie, cookie_len); -+ /* debug3("user: %s", user); */ -+ buffer_put_cstring(session_id2, user); -+ /* debug3("ruser: %s", ruser); */ -+ buffer_put_cstring(session_id2, ruser); -+ /* debug3("servicename: %s", servicename); */ -+ buffer_put_cstring(session_id2, servicename); -+ /* debug3("pwd: %s", pwd); */ - if(retc) +- if(retc) - pamsshagentauth_buffer_put_cstring(session_id2, pwd); -+ buffer_put_cstring(session_id2, pwd); - else +- else - pamsshagentauth_buffer_put_cstring(session_id2, ""); - /* pamsshagentauth_debug3("action: %s", action_logbuf); */ - pamsshagentauth_buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); -+ buffer_put_cstring(session_id2, ""); -+ /* debug3("action: %s", action_logbuf); */ -+ buffer_put_string(session_id2, sshbuf_ptr(&action_agentbuf), sshbuf_len(&action_agentbuf)); ++ if ((r = sshbuf_put_u32(*session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1)) != 0 || ++ (r = sshbuf_put_string(*session_id2, cookie, cookie_len)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, user)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, ruser)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, servicename)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if (retc) { ++ if ((r = sshbuf_put_cstring(*session_id2, pwd)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } else { ++ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } ++ if ((r = sshbuf_put_stringb(*session_id2, action_agentbuf)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (free_logbuf) { - pamsshagentauth_xfree(action_logbuf); - pamsshagentauth_buffer_free(&action_agentbuf); + free(action_logbuf); -+ buffer_free(&action_agentbuf); ++ sshbuf_free(action_agentbuf); } - /* pamsshagentauth_debug3("hostname: %s", hostname); */ -+ /* debug3("hostname: %s", hostname); */ - if(reti >= 0) +- if(reti >= 0) - pamsshagentauth_buffer_put_cstring(session_id2, hostname); -+ buffer_put_cstring(session_id2, hostname); - else +- else - pamsshagentauth_buffer_put_cstring(session_id2, ""); - /* pamsshagentauth_debug3("ts: %ld", ts); */ - pamsshagentauth_buffer_put_int64(session_id2, (uint64_t) ts); -+ buffer_put_cstring(session_id2, ""); ++ /* debug3("hostname: %s", hostname); */ ++ if (reti >= 0) { ++ if ((r = sshbuf_put_cstring(*session_id2, hostname)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } else { ++ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } + /* debug3("ts: %ld", ts); */ -+ buffer_put_int64(session_id2, (uint64_t) ts); ++ if ((r = sshbuf_put_u64(*session_id2, (uint64_t) ts)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); free(cookie); return; -@@ -295,29 +297,29 @@ pamsshagentauth_find_authorized_keys(con - pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); +@@ -278,7 +280,8 @@ ssh_get_authentication_connection_for_ui + + auth = xmalloc(sizeof(*auth)); + auth->fd = sock; +- buffer_init(&auth->identities); ++ if ((auth->identities = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); + auth->howmany = 0; + + return auth; +@@ -287,43 +289,42 @@ ssh_get_authentication_connection_for_ui + int + pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) + { +- Buffer session_id2 = { 0 }; ++ struct sshbuf *session_id2 = NULL; + Identity *id; +- Key *key; ++ struct sshkey *key; + AuthenticationConnection *ac; + char *comment; + uint8_t retval = 0; + uid_t uid = getpwnam(ruser)->pw_uid; + + OpenSSL_add_all_digests(); +- pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); ++ pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); if ((ac = ssh_get_authentication_connection_for_uid(uid))) { - pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); @@ -163,7 +268,8 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c id->key = key; id->filename = comment; id->ac = ac; - if(userauth_pubkey_from_id(ruser, id, &session_id2)) { +- if(userauth_pubkey_from_id(ruser, id, &session_id2)) { ++ if(userauth_pubkey_from_id(ruser, id, session_id2)) { retval = 1; } - pamsshagentauth_xfree(id->filename); @@ -177,18 +283,20 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-c } } - pamsshagentauth_buffer_free(&session_id2); -+ buffer_free(&session_id2); ++ sshbuf_free(session_id2); ssh_close_authentication_connection(ac); } else { - pamsshagentauth_verbose("No ssh-agent could be contacted"); + verbose("No ssh-agent could be contacted"); } - /* pamsshagentauth_xfree(session_id2); */ +- /* pamsshagentauth_xfree(session_id2); */ EVP_cleanup(); -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-compat 2017-02-07 14:41:20.480509207 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c 2017-02-07 14:44:20.549369019 +0100 + return retval; + } +diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c +--- openssh/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-compat 2018-08-24 10:18:05.008393305 +0200 ++++ openssh/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c 2018-08-24 10:18:05.009393312 +0200 @@ -104,7 +104,7 @@ pam_sm_authenticate(pam_handle_t * pamh, * a patch 8-) */ @@ -276,10 +384,29 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-compa } cleanexit: -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c 2017-02-07 14:41:20.484509204 +0100 -@@ -117,12 +117,12 @@ parse_authorized_key_file(const char *us +diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c +--- openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c 2018-08-24 10:18:05.009393312 +0200 +@@ -66,8 +66,8 @@ + #include "xmalloc.h" + #include "match.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "misc.h" + + #include "xmalloc.h" +@@ -77,7 +77,6 @@ + #include "pathnames.h" + #include "secure_filename.h" + +-#include "identity.h" + #include "pam_user_key_allowed2.h" + + extern char *authorized_keys_file; +@@ -117,12 +116,12 @@ parse_authorized_key_file(const char *us } else { slash_ptr = strchr(auth_keys_file_buf, '/'); if(!slash_ptr) @@ -294,7 +421,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); if(!authorized_keys_file_allowed_owner_uid) -@@ -130,11 +130,11 @@ parse_authorized_key_file(const char *us +@@ -130,11 +129,11 @@ parse_authorized_key_file(const char *us getpwnam(owner_uname)->pw_uid; } authorized_keys_file = @@ -308,7 +435,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa percent_expand later, we'd step on this, so free -@@ -150,7 +150,7 @@ parse_authorized_key_file(const char *us +@@ -150,13 +149,13 @@ parse_authorized_key_file(const char *us strncat(hostname, fqdn, strcspn(fqdn, ".")); #endif authorized_keys_file = @@ -317,38 +444,78 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa getpwnam(user)->pw_dir, "H", hostname, "f", fqdn, "u", user, NULL); } -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2017-02-07 14:41:20.484509204 +0100 -@@ -48,11 +48,13 @@ - #include "buffer.h" + + int +-pam_user_key_allowed(const char *ruser, Key * key) ++pam_user_key_allowed(const char *ruser, struct sshkey * key) + { + return + pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), +diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.h.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.h +--- openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.h.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.h 2018-08-24 10:18:05.010393320 +0200 +@@ -32,7 +32,7 @@ + #define _PAM_USER_KEY_ALLOWED_H + + #include "identity.h" +-int pam_user_key_allowed(const char *, Key *); ++int pam_user_key_allowed(const char *, struct sshkey *); + void parse_authorized_key_file(const char *, const char *); + + #endif +diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c +--- openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2018-08-24 10:18:05.010393320 +0200 +@@ -45,44 +45,46 @@ + #include "xmalloc.h" + #include "ssh.h" + #include "ssh2.h" +-#include "buffer.h" ++#include "sshbuf.h" #include "log.h" #include "compat.h" +-#include "key.h" +#include "digest.h" - #include "key.h" ++#include "sshkey.h" #include "pathnames.h" #include "misc.h" #include "secure_filename.h" #include "uidswap.h" +- +-#include "identity.h" +#include - #include "identity.h" - -@@ -68,7 +70,7 @@ pamsshagentauth_check_authkeys_file(FILE + /* return 1 if user allows given key */ + /* Modified slightly from original found in auth2-pubkey.c */ + static int +-pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key) ++pamsshagentauth_check_authkeys_file(FILE * f, char *file, struct sshkey * key) + { +- char line[SSH_MAX_PUBKEY_BYTES]; ++ char *line = NULL; + int found_key = 0; + u_long linenum = 0; +- Key *found; ++ struct sshkey *found; char *fp; ++ size_t linesize = 0; found_key = 0; - found = pamsshagentauth_key_new(key->type); -+ found = key_new(key->type); ++ found = sshkey_new(key->type); - while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { +- while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { ++ while ((getline(&line, &linesize, f)) != -1) { char *cp = NULL; /* *key_options = NULL; */ -@@ -78,11 +80,11 @@ pamsshagentauth_check_authkeys_file(FILE + ++ linenum++; + /* Skip leading whitespace, empty and comment lines. */ + for(cp = line; *cp == ' ' || *cp == '\t'; cp++); if(!*cp || *cp == '\n' || *cp == '#') continue; - if(pamsshagentauth_key_read(found, &cp) != 1) { -+ if(key_read(found, &cp) != 1) { ++ if (sshkey_read(found, &cp) != 0) { /* no key? check if there are options for this key */ int quoted = 0; @@ -357,20 +524,20 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co /* key_options = cp; */ for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if(*cp == '\\' && cp[1] == '"') -@@ -92,26 +94,26 @@ pamsshagentauth_check_authkeys_file(FILE +@@ -92,26 +94,27 @@ pamsshagentauth_check_authkeys_file(FILE } /* Skip remaining whitespace. */ for(; *cp == ' ' || *cp == '\t'; cp++); - if(pamsshagentauth_key_read(found, &cp) != 1) { - pamsshagentauth_verbose("user_key_allowed: advance: '%s'", cp); -+ if(key_read(found, &cp) != 1) { ++ if(sshkey_read(found, &cp) != 0) { + verbose("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line */ continue; } } - if(pamsshagentauth_key_equal(found, key)) { -+ if(key_equal(found, key)) { ++ if(sshkey_equal(found, key)) { found_key = 1; - pamsshagentauth_logit("matching key found: file/command %s, line %lu", file, + logit("matching key found: file/command %s, line %lu", file, @@ -379,23 +546,34 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co - pamsshagentauth_logit("Found matching %s key: %s", - pamsshagentauth_key_type(found), fp); - pamsshagentauth_xfree(fp); -+ fp = sshkey_fingerprint(found, SSH_DIGEST_MD5, SSH_FP_HEX); ++ fp = sshkey_fingerprint(found, SSH_DIGEST_SHA256, SSH_FP_BASE64); + logit("Found matching %s key: %s", -+ key_type(found), fp); ++ sshkey_type(found), fp); + free(fp); break; } } - pamsshagentauth_key_free(found); -+ key_free(found); ++ free(line); ++ sshkey_free(found); if(!found_key) - pamsshagentauth_verbose("key not found"); + verbose("key not found"); return found_key; } -@@ -128,11 +130,11 @@ pamsshagentauth_user_key_allowed2(struct - char buf[SSH_MAX_PUBKEY_BYTES]; +@@ -120,19 +123,19 @@ pamsshagentauth_check_authkeys_file(FILE + * returns 1 if the key is allowed or 0 otherwise. + */ + int +-pamsshagentauth_user_key_allowed2(struct passwd *pw, Key * key, char *file) ++pamsshagentauth_user_key_allowed2(struct passwd *pw, struct sshkey * key, char *file) + { + FILE *f; + int found_key = 0; + struct stat st; +- char buf[SSH_MAX_PUBKEY_BYTES]; ++ char buf[256]; /* Temporarily use the user's uid. */ - pamsshagentauth_verbose("trying public key file %s", file); @@ -408,7 +586,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co return 0; } -@@ -144,7 +146,7 @@ pamsshagentauth_user_key_allowed2(struct +@@ -144,7 +147,7 @@ pamsshagentauth_user_key_allowed2(struct if(pamsshagentauth_secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { fclose(f); @@ -417,7 +595,16 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co return 0; } -@@ -187,44 +189,44 @@ pamsshagentauth_user_key_command_allowed +@@ -160,7 +163,7 @@ pamsshagentauth_user_key_allowed2(struct + int + pamsshagentauth_user_key_command_allowed2(char *authorized_keys_command, + char *authorized_keys_command_user, +- struct passwd *user_pw, Key * key) ++ struct passwd *user_pw, struct sshkey * key) + { + FILE *f; + int ok, found_key = 0; +@@ -187,44 +190,44 @@ pamsshagentauth_user_key_command_allowed else { pw = getpwnam(authorized_keys_command_user); if(pw == NULL) { @@ -470,7 +657,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co close(p[0]); close(p[1]); return 0; -@@ -234,13 +236,13 @@ pamsshagentauth_user_key_command_allowed +@@ -234,13 +237,13 @@ pamsshagentauth_user_key_command_allowed /* do this before the setresuid so thta they can be logged */ if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { @@ -486,7 +673,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co _exit(1); } #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) -@@ -248,7 +250,7 @@ pamsshagentauth_user_key_command_allowed +@@ -248,7 +251,7 @@ pamsshagentauth_user_key_command_allowed #else if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { #endif @@ -495,7 +682,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co strerror(errno)); _exit(1); } -@@ -258,7 +260,7 @@ pamsshagentauth_user_key_command_allowed +@@ -258,7 +261,7 @@ pamsshagentauth_user_key_command_allowed #else if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { #endif @@ -504,7 +691,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co strerror(errno)); _exit(1); } -@@ -270,18 +272,18 @@ pamsshagentauth_user_key_command_allowed +@@ -270,18 +273,18 @@ pamsshagentauth_user_key_command_allowed /* pretty sure this will barf because we are now suid, but since we should't reach this anyway, I'll leave it here */ @@ -526,7 +713,7 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co close(p[0]); /* Don't leave zombie child */ while(waitpid(pid, NULL, 0) == -1 && errno == EINTR); -@@ -292,22 +294,22 @@ pamsshagentauth_user_key_command_allowed +@@ -292,22 +295,22 @@ pamsshagentauth_user_key_command_allowed while(waitpid(pid, &status, 0) == -1) { if(errno != EINTR) { @@ -553,9 +740,33 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-co + restore_uid(); return found_key; } -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c 2017-02-07 14:41:20.481509206 +0100 +diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.h.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.h +--- openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.h.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.h 2018-08-24 10:18:05.010393320 +0200 +@@ -32,7 +32,7 @@ + #define _PAM_USER_KEY_ALLOWED_H + + #include "identity.h" +-int pamsshagentauth_user_key_allowed2(struct passwd *, Key *, char *); +-int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, Key *); ++int pamsshagentauth_user_key_allowed2(struct passwd *, struct sshkey *, char *); ++int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, struct sshkey *); + + #endif +diff -up openssh/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/secure_filename.c +--- openssh/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/secure_filename.c 2018-08-24 10:18:05.010393320 +0200 +@@ -53,8 +53,8 @@ + #include "xmalloc.h" + #include "match.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "misc.h" + + @@ -80,7 +80,7 @@ pamsshagentauth_auth_secure_path(const c int comparehome = 0; struct stat st; @@ -586,10 +797,24 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-compat o buf); break; } -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-02-07 14:41:20.484509204 +0100 -@@ -48,6 +48,8 @@ +diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c +--- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2018-08-24 10:22:13.202657025 +0200 +@@ -37,10 +37,11 @@ + #include "xmalloc.h" + #include "ssh.h" + #include "ssh2.h" +-#include "buffer.h" ++#include "sshbuf.h" + #include "log.h" + #include "compat.h" +-#include "key.h" ++#include "sshkey.h" ++#include "ssherr.h" + #include "pathnames.h" + #include "misc.h" + #include "secure_filename.h" +@@ -48,54 +48,59 @@ #include "identity.h" #include "pam_user_authorized_keys.h" @@ -598,7 +823,22 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa- /* extern u_char *session_id2; extern uint8_t session_id_len; */ -@@ -65,37 +67,38 @@ userauth_pubkey_from_id(const char *ruse + + int +-userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) ++userauth_pubkey_from_id(const char *ruser, Identity * id, struct sshbuf * session_id2) + { +- Buffer b = { 0 }; ++ struct sshbuf *b = NULL; + char *pkalg = NULL; + u_char *pkblob = NULL, *sig = NULL; +- u_int blen = 0, slen = 0; ++ size_t blen = 0, slen = 0; +- int authenticated = 0; ++ int r, authenticated = 0; + +- pkalg = (char *) key_ssh_name(id->key); ++ pkalg = (char *) sshkey_ssh_name(id->key); /* first test if this key is even allowed */ if(! pam_user_key_allowed(ruser, id->key)) @@ -607,12 +847,13 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa- - if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) - goto user_auth_clean_exit; -+ if(key_to_blob(id->key, &pkblob, &blen) == 0) ++ if(sshkey_to_blob(id->key, &pkblob, &blen) != 0) + goto user_auth_clean_exit_without_buffer; /* construct packet to sign and test */ - pamsshagentauth_buffer_init(&b); -+ buffer_init(&b); ++ if ((b = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); - pamsshagentauth_buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset); - pamsshagentauth_buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); @@ -622,28 +863,29 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa- - pamsshagentauth_buffer_put_char(&b, 1); - pamsshagentauth_buffer_put_cstring(&b, pkalg); - pamsshagentauth_buffer_put_string(&b, pkblob, blen); -+ buffer_put_string(&b, sshbuf_ptr(session_id2), sshbuf_len(session_id2)); -+ buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); -+ buffer_put_cstring(&b, ruser); -+ buffer_put_cstring(&b, "pam_ssh_agent_auth"); -+ buffer_put_cstring(&b, "publickey"); -+ buffer_put_char(&b, 1); -+ buffer_put_cstring(&b, pkalg); -+ buffer_put_string(&b, pkblob, blen); ++ if ((r = sshbuf_put_string(b, sshbuf_ptr(session_id2), sshbuf_len(session_id2))) != 0 || ++ (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_TRUST_REQUEST)) != 0 || ++ (r = sshbuf_put_cstring(b, ruser)) != 0 || ++ (r = sshbuf_put_cstring(b, "pam_ssh_agent_auth")) != 0 || ++ (r = sshbuf_put_cstring(b, "publickey")) != 0 || ++ (r = sshbuf_put_u8(b, 1)) != 0 || ++ (r = sshbuf_put_cstring(b, pkalg)) != 0 || ++ (r = sshbuf_put_string(b, pkblob, blen)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); - if(ssh_agent_sign(id->ac, id->key, &sig, &slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) != 0) -+ if(ssh_agent_sign(id->ac, id->key, &sig, &slen, buffer_ptr(&b), buffer_len(&b)) != 0) ++ if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) goto user_auth_clean_exit; /* test for correct signature */ - if(pamsshagentauth_key_verify(id->key, sig, slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) == 1) -+ if(key_verify(id->key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) ++ if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) == 0) authenticated = 1; user_auth_clean_exit: /* if(&b != NULL) */ - pamsshagentauth_buffer_free(&b); -+ buffer_free(&b); ++ sshbuf_free(b); + user_auth_clean_exit_without_buffer: if(sig != NULL) - pamsshagentauth_xfree(sig); @@ -654,9 +896,22 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa- CRYPTO_cleanup_all_ex_data(); return authenticated; } -diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/uuencode.c.psaa-compat openssh-7.4p1/pam_ssh_agent_auth-0.10.3/uuencode.c ---- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/uuencode.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 -+++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/uuencode.c 2017-02-07 14:41:20.484509204 +0100 +diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.h.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.h +--- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.h.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.h 2018-08-24 10:18:05.010393320 +0200 +@@ -31,7 +31,7 @@ + #ifndef _USERAUTH_PUBKEY_FROM_ID_H + #define _USERAUTH_PUBKEY_FROM_ID_H + +-#include +-int userauth_pubkey_from_id(const char *, Identity *, Buffer *); ++#include "identity.h" ++int userauth_pubkey_from_id(const char *, Identity *, struct sshbuf *); + + #endif +diff -up openssh/pam_ssh_agent_auth-0.10.3/uuencode.c.psaa-compat openssh/pam_ssh_agent_auth-0.10.3/uuencode.c +--- openssh/pam_ssh_agent_auth-0.10.3/uuencode.c.psaa-compat 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/uuencode.c 2018-08-24 10:18:05.010393320 +0200 @@ -56,7 +56,7 @@ pamsshagentauth_uudecode(const char *src /* and remove trailing whitespace because __b64_pton needs this */ *p = '\0'; diff --git a/pam_ssh_agent_auth-0.10.2-dereference.patch b/pam_ssh_agent_auth-0.10.2-dereference.patch index 351aea8..bf49c37 100644 --- a/pam_ssh_agent_auth-0.10.2-dereference.patch +++ b/pam_ssh_agent_auth-0.10.2-dereference.patch @@ -3,7 +3,7 @@ diff --git a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c b/pam_ssh_agen +++ b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c @@ -158,11 +158,12 @@ parse_authorized_key_file(const char *user, int - pam_user_key_allowed(const char *ruser, Key * key) + pam_user_key_allowed(const char *ruser, struct sshkey * key) { + struct passwd *pw; return diff --git a/pam_ssh_agent_auth-0.9.3-agent_structure.patch b/pam_ssh_agent_auth-0.9.3-agent_structure.patch index 6ff49d7..26ae902 100644 --- a/pam_ssh_agent_auth-0.9.3-agent_structure.patch +++ b/pam_ssh_agent_auth-0.9.3-agent_structure.patch @@ -7,7 +7,7 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent openssh/pam_ssh +typedef struct { + int fd; -+ Buffer identities; ++ struct sshbuf *identities; + int howmany; +} AuthenticationConnection; + @@ -18,8 +18,8 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent o --- openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 +++ openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-09-27 14:25:49.421739027 +0200 @@ -39,6 +39,7 @@ - #include "buffer.h" - #include "key.h" + #include "sshbuf.h" + #include "sshkey.h" #include "authfd.h" +#include "ssherr.h" #include @@ -27,9 +27,9 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent o #include "ssh2.h" @@ -291,36 +292,43 @@ pamsshagentauth_find_authorized_keys(con { - Buffer session_id2 = { 0 }; + struct sshbuf *session_id2 = NULL; Identity *id; -- Key *key; +- struct sshkey *key; AuthenticationConnection *ac; - char *comment; uint8_t retval = 0; @@ -59,7 +59,7 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent o + id->key = idlist->keys[i]; + id->filename = idlist->comments[i]; id->ac = ac; - if(userauth_pubkey_from_id(ruser, id, &session_id2)) { + if(userauth_pubkey_from_id(ruser, id, session_id2)) { retval = 1; } - free(id->filename); @@ -69,7 +69,7 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent o break; } } - buffer_free(&session_id2); + sshbuf_free(session_id2); - ssh_close_authentication_connection(ac); + ssh_free_identitylist(idlist); + ssh_close_authentication_socket(ac->fd); @@ -78,91 +78,15 @@ diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent o } else { verbose("No ssh-agent could be contacted"); -diff -up openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c ---- openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-agent 2017-09-27 14:26:04.277820716 +0200 -+++ openssh/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2017-09-27 14:26:34.426986497 +0200 -@@ -70,7 +70,7 @@ pamsshagentauth_check_authkeys_file(FILE - char *fp; - - found_key = 0; -- found = key_new(key->type); -+ found = sshkey_new(key->type); - - while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { - char *cp = NULL; /* *key_options = NULL; */ -@@ -80,7 +80,7 @@ pamsshagentauth_check_authkeys_file(FILE - if(!*cp || *cp == '\n' || *cp == '#') - continue; - -- if(key_read(found, &cp) != 1) { -+ if(sshkey_read(found, &cp) != 0) { - /* no key? check if there are options for this key */ - int quoted = 0; - -@@ -94,24 +94,24 @@ pamsshagentauth_check_authkeys_file(FILE - } - /* Skip remaining whitespace. */ - for(; *cp == ' ' || *cp == '\t'; cp++); -- if(key_read(found, &cp) != 1) { -+ if(sshkey_read(found, &cp) != 0) { - verbose("user_key_allowed: advance: '%s'", cp); - /* still no key? advance to next line */ - continue; - } - } -- if(key_equal(found, key)) { -+ if(sshkey_equal(found, key)) { - found_key = 1; - logit("matching key found: file/command %s, line %lu", file, - linenum); - fp = sshkey_fingerprint(found, SSH_DIGEST_MD5, SSH_FP_HEX); - logit("Found matching %s key: %s", -- key_type(found), fp); -+ sshkey_type(found), fp); - free(fp); - break; - } - } -- key_free(found); -+ sshkey_free(found); - if(!found_key) - verbose("key not found"); - return found_key; diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c --- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 +++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-09-27 14:25:49.422739032 +0200 -@@ -57,10 +57,11 @@ extern uint8_t session_id_len; - int - userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) - { -- Buffer b = { 0 }; -+ Buffer b; - char *pkalg = NULL; - u_char *pkblob = NULL, *sig = NULL; -- u_int blen = 0, slen = 0; -+ u_int blen = 0; -+ size_t slen = 0; - int authenticated = 0; - - pkalg = (char *) key_ssh_name(id->key); @@ -84,7 +85,7 @@ userauth_pubkey_from_id(const char *ruse - buffer_put_cstring(&b, pkalg); - buffer_put_string(&b, pkblob, blen); + (r = sshbuf_put_string(b, pkblob, blen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); -- if(ssh_agent_sign(id->ac, id->key, &sig, &slen, buffer_ptr(&b), buffer_len(&b)) != 0) -+ if(ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, buffer_ptr(&b), buffer_len(&b), NULL, 0) != 0) +- if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) ++ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) goto user_auth_clean_exit; /* test for correct signature */ -diff -up openssh-7.7p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-sshkey openssh-7.7p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c ---- openssh-7.7p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-sshkey 2018-04-04 13:55:02.383899631 +0200 -+++ openssh-7.7p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2018-04-04 13:58:36.759339845 +0200 -@@ -89,7 +89,7 @@ userauth_pubkey_from_id(const char *ruse - goto user_auth_clean_exit; - - /* test for correct signature */ -- if(key_verify(id->key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) -+ if(sshkey_verify(id->key, sig, slen, buffer_ptr(&b), buffer_len(&b), NULL, 0) == 0) - authenticated = 1; - - user_auth_clean_exit: diff --git a/pam_ssh_agent_auth-0.9.3-build.patch b/pam_ssh_agent_auth-0.9.3-build.patch index 1a32bf1..f269b97 100644 --- a/pam_ssh_agent_auth-0.9.3-build.patch +++ b/pam_ssh_agent_auth-0.9.3-build.patch @@ -189,8 +189,8 @@ diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build openssh- -pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o - $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam -+pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o -+ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam ++pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o ../uidswap.o ++ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o ../uidswap.o $(LIBS) -lpam $(MANPAGES): $(MANPAGES_IN) pod2man --section=8 --release=v0.10.3 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 diff --git a/sources b/sources index b591052..c3723f0 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ -SHA512 (openssh-7.7p1.tar.gz) = 597252cb48209a0cb98ca1928a67e8d63e4275252f25bc37269204c108f034baade6ba0634e32ae63422fddd280f73096a6b31ad2f2e7a848dde75ca30e14261 -SHA512 (openssh-7.7p1.tar.gz.asc) = 9445a589a84538fb0b4eae0f7bf6ce46def51b09254d6fffcc6ed64472f10ccf9e4d5d200387725043039d77ca886e2c8e8f3128e7969c582156fafb0783988d +SHA512 (openssh-7.8p1.tar.gz) = 8e5b0c8682a9243e4e8b7c374ec989dccd1a752eb6f84e593b67141e8b23dcc8b9a7322b1f7525d18e2ce8830a767d0d9793f997486339db201a57986b910705 +SHA512 (openssh-7.8p1.tar.gz.asc) = 3a7bef84df3c07aa78965a11a6bbd6ca6e5d1e9265ac08871b3e5d304646be651b74f5302a195e86a56e6a83b19d79292e5599c9a9cf6f003a513d4354e8ad2f SHA512 (DJM-GPG-KEY.gpg) = db1191ed9b6495999e05eed2ef863fb5179bdb63e94850f192dad68eed8579836f88fbcfffd9f28524fe1457aff8cd248ee3e0afc112c8f609b99a34b80ecc0d SHA512 (pam_ssh_agent_auth-0.10.3.tar.bz2) = d75062c4e46b0b011f46aed9704a99049995fea8b5115ff7ee26dad7e93cbcf54a8af7efc6b521109d77dc03c6f5284574d2e1b84c6829cec25610f24fb4bd66