From 1d31ef596787b74ddd13a12c15cb7f526f92688c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 01 2017 03:22:06 +0000 Subject: import openssh-7.4p1-11.el7 --- diff --git a/.gitignore b/.gitignore index 5dd3f0b..9614d59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/openssh-6.6p1.tar.gz -SOURCES/pam_ssh_agent_auth-0.9.3.tar.bz2 +SOURCES/openssh-7.4p1.tar.gz +SOURCES/pam_ssh_agent_auth-0.10.3.tar.bz2 diff --git a/.openssh.metadata b/.openssh.metadata index a78a9c0..35bfd8e 100644 --- a/.openssh.metadata +++ b/.openssh.metadata @@ -1,2 +1,2 @@ -b850fd1af704942d9b3c2eff7ef6b3a59b6a6b6e SOURCES/openssh-6.6p1.tar.gz -5761a2d5e3ea29e0b415424338d27deaabdd75f4 SOURCES/pam_ssh_agent_auth-0.9.3.tar.bz2 +2330bbf82ed08cf3ac70e0acf00186ef3eeb97e0 SOURCES/openssh-7.4p1.tar.gz +a4482a050fdad1d012427e45799564136708cf6b SOURCES/pam_ssh_agent_auth-0.10.3.tar.bz2 diff --git a/SOURCES/openssh-4.3p2-askpass-grab-info.patch b/SOURCES/openssh-4.3p2-askpass-grab-info.patch index e9dc835..e9a0b0d 100644 --- a/SOURCES/openssh-4.3p2-askpass-grab-info.patch +++ b/SOURCES/openssh-4.3p2-askpass-grab-info.patch @@ -1,7 +1,8 @@ ---- openssh-4.3p2/contrib/gnome-ssh-askpass2.c.grab-info 2006-07-17 15:10:11.000000000 +0200 -+++ openssh-4.3p2/contrib/gnome-ssh-askpass2.c 2006-07-17 15:25:04.000000000 +0200 -@@ -65,9 +65,12 @@ - err = gtk_message_dialog_new(NULL, 0, +diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.grab-info openssh-7.4p1/contrib/gnome-ssh-askpass2.c +--- openssh-7.4p1/contrib/gnome-ssh-askpass2.c.grab-info 2016-12-23 13:31:22.645213115 +0100 ++++ openssh-7.4p1/contrib/gnome-ssh-askpass2.c 2016-12-23 13:31:40.997216691 +0100 +@@ -65,9 +65,12 @@ report_failed_grab (GtkWidget *parent_wi + err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - "Could not grab %s. " @@ -14,5 +15,5 @@ + "Either close the application which grabs the %s or " + "log out and log in again to prevent this from happening.", what, what); gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); - gtk_label_set_line_wrap(GTK_LABEL((GTK_MESSAGE_DIALOG(err))->label), - TRUE); + + gtk_dialog_run(GTK_DIALOG(err)); diff --git a/SOURCES/openssh-5.1p1-askpass-progress.patch b/SOURCES/openssh-5.1p1-askpass-progress.patch index ec93b87..6601fbf 100644 --- a/SOURCES/openssh-5.1p1-askpass-progress.patch +++ b/SOURCES/openssh-5.1p1-askpass-progress.patch @@ -1,6 +1,6 @@ -diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contrib/gnome-ssh-askpass2.c ---- openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress 2008-07-23 19:05:26.000000000 +0200 -+++ openssh-5.1p1/contrib/gnome-ssh-askpass2.c 2008-07-23 19:05:26.000000000 +0200 +diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contrib/gnome-ssh-askpass2.c +--- openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/contrib/gnome-ssh-askpass2.c 2016-12-23 13:31:16.545211926 +0100 @@ -53,6 +53,7 @@ #include #include @@ -9,7 +9,7 @@ diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contr #include #include -@@ -83,13 +84,24 @@ ok_dialog(GtkWidget *entry, gpointer dia +@@ -81,13 +82,24 @@ ok_dialog(GtkWidget *entry, gpointer dia gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); } @@ -30,12 +30,12 @@ diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contr const char *failed; char *passphrase, *local; int result, grab_tries, grab_server, grab_pointer; -- GtkWidget *dialog, *entry; -+ GtkWidget *dialog, *entry, *progress, *hbox; +- GtkWidget *parent_window, *dialog, *entry; ++ GtkWidget *parent_window, *dialog, *entry, *progress, *hbox; GdkGrabStatus status; grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL); -@@ -102,13 +114,31 @@ passphrase_dialog(char *message) +@@ -104,14 +116,32 @@ passphrase_dialog(char *message) "%s", message); @@ -45,9 +45,11 @@ diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contr + gtk_widget_show(hbox); + entry = gtk_entry_new(); -- gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE, -+ gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, - FALSE, 0); + gtk_box_pack_start( +- GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry, +- FALSE, FALSE, 0); ++ GTK_BOX(hbox), entry, ++ TRUE, FALSE, 0); + gtk_entry_set_width_chars(GTK_ENTRY(entry), 2); gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); gtk_widget_grab_focus(entry); @@ -68,7 +70,7 @@ diff -up openssh-5.1p1/contrib/gnome-ssh-askpass2.c.progress openssh-5.1p1/contr gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH"); gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); -@@ -119,6 +149,8 @@ passphrase_dialog(char *message) +@@ -120,6 +150,8 @@ passphrase_dialog(char *message) gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(ok_dialog), dialog); diff --git a/SOURCES/openssh-5.5p1-x11.patch b/SOURCES/openssh-5.5p1-x11.patch index 70a3c85..91e82ef 100644 --- a/SOURCES/openssh-5.5p1-x11.patch +++ b/SOURCES/openssh-5.5p1-x11.patch @@ -1,7 +1,7 @@ diff -up openssh-5.3p1/channels.c.bz595935 openssh-5.3p1/channels.c --- openssh-5.3p1/channels.c.bz595935 2010-08-12 14:19:28.000000000 +0200 +++ openssh-5.3p1/channels.c 2010-08-12 14:33:51.000000000 +0200 -@@ -3185,7 +3185,7 @@ x11_create_display_inet(int x11_display_ +@@ -3990,21 +3990,24 @@ x11_create_display_inet(int x11_display_ } static int @@ -10,14 +10,16 @@ diff -up openssh-5.3p1/channels.c.bz595935 openssh-5.3p1/channels.c { int sock; struct sockaddr_un addr; -@@ -3195,11 +3195,14 @@ connect_local_xsocket_path(const char *p + ++ if (len <= 0) ++ return -1; + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) error("socket: %.100s", strerror(errno)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) -+ if (len <= 0) -+ return -1; + if (len > sizeof addr.sun_path) + len = sizeof addr.sun_path; + memcpy(addr.sun_path, pathname, len); diff --git a/SOURCES/openssh-5.8p1-packet.patch b/SOURCES/openssh-5.8p1-packet.patch index 4951af6..7b1a985 100644 --- a/SOURCES/openssh-5.8p1-packet.patch +++ b/SOURCES/openssh-5.8p1-packet.patch @@ -5,8 +5,8 @@ diff -up openssh-5.8p1/packet.c.packet openssh-5.8p1/packet.c struct sockaddr_storage from, to; socklen_t fromlen, tolen; -+ if (!active_state) ++ if (!state) + return 0; - /* filedescriptors in and out are the same, so it's a socket */ - if (active_state->connection_in == active_state->connection_out) - return 1; + if (state->connection_in == -1 || state->connection_out == -1) + return 0; + diff --git a/SOURCES/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch b/SOURCES/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch deleted file mode 100644 index 44da114..0000000 --- a/SOURCES/openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch +++ /dev/null @@ -1,177 +0,0 @@ -From 5618210618256bbf5f4f71b2887ff186fd451736 Mon Sep 17 00:00:00 2001 -From: Damien Miller -Date: Sun, 20 Apr 2014 13:44:47 +1000 -Subject: [PATCH] - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c - version.h] OpenSSH 6.5 and 6.6 sometimes encode a value used in the - curve25519 key exchange incorrectly, causing connection failures about - 0.2% of the time when this method is used against a peer that implements - the method properly. - - Fix the problem and disable the curve25519 KEX when speaking to - OpenSSH 6.5 or 6.6. This version will identify itself as 6.6.1 - to enable the compatability code. ---- - ChangeLog | 11 +++++++++++ - bufaux.c | 5 ++++- - compat.c | 17 ++++++++++++++++- - compat.h | 2 ++ - sshconnect2.c | 2 ++ - sshd.c | 3 +++ - version.h | 2 +- - 7 files changed, 39 insertions(+), 3 deletions(-) - -diff --git a/ChangeLog b/ChangeLog -index 1603a07..928999d 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,13 +1,23 @@ - 20140420 -- - djm@cvs.openbsd.org 2014/04/01 03:34:10 -- [sshconnect.c] -- When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any -- certificate keys to plain keys and attempt SSHFP resolution. -- -- Prevents a server from skipping SSHFP lookup and forcing a new-hostkey -- dialog by offering only certificate keys. -- -- Reported by mcv21 AT cam.ac.uk -+ - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c version.h] -+ OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519 -+ key exchange incorrectly, causing connection failures about 0.2% of -+ the time when this method is used against a peer that implements -+ the method properly. -+ -+ Fix the problem and disable the curve25519 KEX when speaking to -+ OpenSSH 6.5 or 6.6. This version will identify itself as 6.6.1 -+ to enable the compatability code. -+ -+ - djm@cvs.openbsd.org 2014/04/01 03:34:10 -+ [sshconnect.c] -+ When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any -+ certificate keys to plain keys and attempt SSHFP resolution. -+ -+ Prevents a server from skipping SSHFP lookup and forcing a new-hostkey -+ dialog by offering only certificate keys. -+ -+ Reported by mcv21 AT cam.ac.uk - - 20140313 - - (djm) Release OpenSSH 6.6 -diff --git a/bufaux.c b/bufaux.c -index e24b5fc..f6a6f2a 100644 ---- a/bufaux.c -+++ b/bufaux.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: bufaux.c,v 1.56 2014/02/02 03:44:31 djm Exp $ */ -+/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */ - /* - * Author: Tatu Ylonen - * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland -@@ -372,6 +372,9 @@ buffer_put_bignum2_from_string(Buffer *buffer, const u_char *s, u_int l) - - if (l > 8 * 1024) - fatal("%s: length %u too long", __func__, l); -+ /* Skip leading zero bytes */ -+ for (; l > 0 && *s == 0; l--, s++) -+ ; - p = buf = xmalloc(l + 1); - /* - * If most significant bit is set then prepend a zero byte to -diff --git a/compat.c b/compat.c -index 9d9fabe..2709dc5 100644 ---- a/compat.c -+++ b/compat.c -@@ -95,6 +95,9 @@ compat_datafellows(const char *version) - { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, - { "OpenSSH_4*", 0 }, - { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, -+ { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, -+ { "OpenSSH_6.5*," -+ "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, - { "OpenSSH*", SSH_NEW_OPENSSH }, - { "*MindTerm*", 0 }, - { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| -@@ -251,7 +254,6 @@ compat_cipher_proposal(char *cipher_prop) - return cipher_prop; - } - -- - char * - compat_pkalg_proposal(char *pkalg_prop) - { -@@ -265,3 +267,16 @@ compat_pkalg_proposal(char *pkalg_prop) - return pkalg_prop; - } - -+char * -+compat_kex_proposal(char *kex_prop) -+{ -+ if (!(datafellows & SSH_BUG_CURVE25519PAD)) -+ return kex_prop; -+ debug2("%s: original KEX proposal: %s", __func__, kex_prop); -+ kex_prop = filter_proposal(kex_prop, "curve25519-sha256@libssh.org"); -+ debug2("%s: compat KEX proposal: %s", __func__, kex_prop); -+ if (*kex_prop == '\0') -+ fatal("No supported key exchange algorithms found"); -+ return kex_prop; -+} -+ -diff --git a/compat.h b/compat.h -index b174fa1..a6c3f3d 100644 ---- a/compat.h -+++ b/compat.h -@@ -59,6 +59,7 @@ - #define SSH_BUG_RFWD_ADDR 0x02000000 - #define SSH_NEW_OPENSSH 0x04000000 - #define SSH_BUG_DYNAMIC_RPORT 0x08000000 -+#define SSH_BUG_CURVE25519PAD 0x10000000 - - void enable_compat13(void); - void enable_compat20(void); -@@ -66,6 +67,7 @@ void compat_datafellows(const char *); - int proto_spec(const char *); - char *compat_cipher_proposal(char *); - char *compat_pkalg_proposal(char *); -+char *compat_kex_proposal(char *); - - extern int compat13; - extern int compat20; -diff --git a/sshconnect2.c b/sshconnect2.c -index bb9292f..b00658b 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -220,6 +220,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - } - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; -+ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( -+ myproposal[PROPOSAL_KEX_ALGS]); - - #ifdef GSSAPI - /* If we've got GSSAPI algorithms, then we also support the -diff --git a/sshd.c b/sshd.c -index e4e406e..512c7ed 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2488,6 +2488,9 @@ do_ssh2_kex(void) - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; - -+ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( -+ myproposal[PROPOSAL_KEX_ALGS]); -+ - if (options.rekey_limit || options.rekey_interval) - packet_set_rekey_limits((u_int32_t)options.rekey_limit, - (time_t)options.rekey_interval); -diff --git a/version.h b/version.h -index a1579ac..a33e77c 100644 ---- a/version.h -+++ b/version.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */ - --#define SSH_VERSION "OpenSSH_6.6" -+#define SSH_VERSION "OpenSSH_6.6.1" - - #define SSH_PORTABLE "p1" - #define SSH_RELEASE SSH_VERSION SSH_PORTABLE diff --git a/SOURCES/openssh-6.1p1-askpass-ld.patch b/SOURCES/openssh-6.1p1-askpass-ld.patch deleted file mode 100644 index f7a7fac..0000000 --- a/SOURCES/openssh-6.1p1-askpass-ld.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff -up openssh-6.1p1/contrib/Makefile.askpass-ld openssh-6.1p1/contrib/Makefile ---- openssh-6.1p1/contrib/Makefile.askpass-ld 2012-05-19 07:24:37.000000000 +0200 -+++ openssh-6.1p1/contrib/Makefile 2012-09-14 20:35:47.565704718 +0200 -@@ -4,12 +4,12 @@ all: - @echo "Valid targets: gnome-ssh-askpass1 gnome-ssh-askpass2" - - gnome-ssh-askpass1: gnome-ssh-askpass1.c -- $(CC) `gnome-config --cflags gnome gnomeui` \ -+ $(CC) ${CFLAGS} `gnome-config --cflags gnome gnomeui` \ - gnome-ssh-askpass1.c -o gnome-ssh-askpass1 \ - `gnome-config --libs gnome gnomeui` - - gnome-ssh-askpass2: gnome-ssh-askpass2.c -- $(CC) `$(PKG_CONFIG) --cflags gtk+-2.0` \ -+ $(CC) ${CFLAGS} `$(PKG_CONFIG) --cflags gtk+-2.0` \ - gnome-ssh-askpass2.c -o gnome-ssh-askpass2 \ - `$(PKG_CONFIG) --libs gtk+-2.0 x11` - diff --git a/SOURCES/openssh-6.1p1-gssapi-canohost.patch b/SOURCES/openssh-6.1p1-gssapi-canohost.patch index eb5c2e6..124ac7f 100644 --- a/SOURCES/openssh-6.1p1-gssapi-canohost.patch +++ b/SOURCES/openssh-6.1p1-gssapi-canohost.patch @@ -12,7 +12,7 @@ diff -up openssh-6.1p1/sshconnect2.c.canohost openssh-6.1p1/sshconnect2.c gss_host = options.gss_server_identity; - else if (options.gss_trust_dns) + else if (options.gss_trust_dns) { - gss_host = get_canonical_hostname(1); + gss_host = get_canonical_hostname(active_state, 1); + if ( strcmp( gss_host, "UNKNOWN" ) == 0 ) + gss_host = authctxt->host; + } diff --git a/SOURCES/openssh-6.2p1-vendor.patch b/SOURCES/openssh-6.2p1-vendor.patch index ddccd2c..54d08f0 100644 --- a/SOURCES/openssh-6.2p1-vendor.patch +++ b/SOURCES/openssh-6.2p1-vendor.patch @@ -1,7 +1,7 @@ -diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac ---- openssh-6.2p1/configure.ac.vendor 2013-03-25 19:34:01.277495179 +0100 -+++ openssh-6.2p1/configure.ac 2013-03-25 19:34:01.377495818 +0100 -@@ -4420,6 +4420,12 @@ AC_ARG_WITH([lastlog], +diff -up openssh-7.4p1/configure.ac.vendor openssh-7.4p1/configure.ac +--- openssh-7.4p1/configure.ac.vendor 2017-02-10 10:45:54.977836854 +0100 ++++ openssh-7.4p1/configure.ac 2017-02-10 10:45:54.995836725 +0100 +@@ -4930,6 +4930,12 @@ AC_ARG_WITH([lastlog], fi ] ) @@ -14,7 +14,7 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac dnl lastlog, [uw]tmpx? detection dnl NOTE: set the paths in the platform section to avoid the -@@ -4681,6 +4687,7 @@ echo " Translate v4 in v6 hack +@@ -5194,6 +5200,7 @@ echo " Translate v4 in v6 hack echo " BSD Auth support: $BSD_AUTH_MSG" echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" @@ -22,10 +22,10 @@ diff -up openssh-6.2p1/configure.ac.vendor openssh-6.2p1/configure.ac echo "" -diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c ---- openssh-6.2p1/servconf.c.vendor 2013-03-25 19:34:01.197494668 +0100 -+++ openssh-6.2p1/servconf.c 2013-03-25 19:34:01.379495831 +0100 -@@ -128,6 +128,7 @@ initialize_server_options(ServerOptions +diff -up openssh-7.4p1/servconf.c.vendor openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.vendor 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-10 10:45:54.995836725 +0100 +@@ -143,6 +143,7 @@ initialize_server_options(ServerOptions options->max_authtries = -1; options->max_sessions = -1; options->banner = NULL; @@ -33,26 +33,25 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c options->use_dns = -1; options->client_alive_interval = -1; options->client_alive_count_max = -1; -@@ -287,6 +288,9 @@ fill_default_server_options(ServerOption +@@ -325,6 +326,8 @@ fill_default_server_options(ServerOption options->ip_qos_bulk = IPTOS_THROUGHPUT; if (options->version_addendum == NULL) options->version_addendum = xstrdup(""); + if (options->show_patchlevel == -1) + options->show_patchlevel = 0; -+ - /* Turn privilege separation on by default */ - if (use_privsep == -1) - use_privsep = PRIVSEP_NOSANDBOX; -@@ -324,7 +328,7 @@ typedef enum { - sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, - sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, - sMaxStartups, sMaxAuthTries, sMaxSessions, + if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) + options->fwd_opts.streamlocal_bind_mask = 0177; + if (options->fwd_opts.streamlocal_bind_unlink == -1) +@@ -402,7 +405,7 @@ typedef enum { + sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes, + sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, - sBanner, sUseDNS, sHostbasedAuthentication, + sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, -@@ -439,6 +443,7 @@ static struct { + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, +@@ -528,6 +531,7 @@ static struct { { "maxauthtries", sMaxAuthTries, SSHCFG_ALL }, { "maxsessions", sMaxSessions, SSHCFG_ALL }, { "banner", sBanner, SSHCFG_ALL }, @@ -60,7 +59,7 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c { "usedns", sUseDNS, SSHCFG_GLOBAL }, { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, -@@ -1163,6 +1168,10 @@ process_server_config_line(ServerOptions +@@ -1369,6 +1373,10 @@ process_server_config_line(ServerOptions multistate_ptr = multistate_privsep; goto parse_multistate; @@ -71,18 +70,18 @@ diff -up openssh-6.2p1/servconf.c.vendor openssh-6.2p1/servconf.c case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (options->num_allow_users >= MAX_ALLOW_USERS) -@@ -1950,6 +1959,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sUseLogin, o->use_login); +@@ -2269,6 +2277,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sPermitUserEnvironment, o->permit_user_env); dump_cfg_fmtint(sCompression, o->compression); - dump_cfg_fmtint(sGatewayPorts, o->gateway_ports); + dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); + dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel); dump_cfg_fmtint(sUseDNS, o->use_dns); dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); -diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h ---- openssh-6.2p1/servconf.h.vendor 2013-01-09 05:56:45.000000000 +0100 -+++ openssh-6.2p1/servconf.h 2013-03-25 19:34:01.379495831 +0100 -@@ -147,6 +147,7 @@ typedef struct { + dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding); +diff -up openssh-7.4p1/servconf.h.vendor openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.vendor 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/servconf.h 2017-02-10 10:45:54.995836725 +0100 +@@ -149,6 +149,7 @@ typedef struct { int max_authtries; int max_sessions; char *banner; /* SSH-2 banner message */ @@ -90,39 +89,13 @@ diff -up openssh-6.2p1/servconf.h.vendor openssh-6.2p1/servconf.h int use_dns; int client_alive_interval; /* * poke the client this often to -diff -up openssh-6.2p1/sshd_config.vendor openssh-6.2p1/sshd_config ---- openssh-6.2p1/sshd_config.vendor 2013-03-25 19:34:01.380495837 +0100 -+++ openssh-6.2p1/sshd_config 2013-03-25 19:44:43.471296362 +0100 -@@ -118,6 +118,7 @@ UsePrivilegeSeparation sandbox # Defaul - #Compression delayed - #ClientAliveInterval 0 - #ClientAliveCountMax 3 -+#ShowPatchLevel no - #UseDNS yes - #PidFile /var/run/sshd.pid - #MaxStartups 10:30:100 -diff -up openssh-6.2p1/sshd_config.0.vendor openssh-6.2p1/sshd_config.0 ---- openssh-6.2p1/sshd_config.0.vendor 2013-03-25 19:34:01.361495716 +0100 -+++ openssh-6.2p1/sshd_config.0 2013-03-25 19:34:01.381495844 +0100 -@@ -595,6 +595,11 @@ DESCRIPTION - Defines the number of bits in the ephemeral protocol version 1 - server key. The minimum value is 512, and the default is 1024. - -+ 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-^]. -+ - StrictModes - Specifies whether sshd(8) should check file modes and ownership - of the user's files and home directory before accepting login. -diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5 ---- openssh-6.2p1/sshd_config.5.vendor 2013-03-25 19:34:01.362495722 +0100 -+++ openssh-6.2p1/sshd_config.5 2013-03-25 19:34:01.382495850 +0100 -@@ -1019,6 +1019,14 @@ This option applies to protocol version - .It Cm ServerKeyBits - Defines the number of bits in the ephemeral protocol version 1 server key. - The minimum value is 512, and the default is 1024. +diff -up openssh-7.4p1/sshd_config.5.vendor openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.vendor 2017-02-10 10:45:54.990836761 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-10 10:45:54.996836718 +0100 +@@ -1334,6 +1334,14 @@ an OpenSSH Key Revocation List (KRL) as + .Xr ssh-keygen 1 . + For more information on KRLs, see the KEY REVOCATION LISTS section in + .Xr ssh-keygen 1 . +.It Cm ShowPatchLevel +Specifies whether +.Nm sshd @@ -131,28 +104,40 @@ diff -up openssh-6.2p1/sshd_config.5.vendor openssh-6.2p1/sshd_config.5 +The default is +.Dq no . +This option applies to protocol version 1 only. - .It Cm StrictModes - Specifies whether - .Xr sshd 8 -diff -up openssh-6.2p1/sshd.c.vendor openssh-6.2p1/sshd.c ---- openssh-6.2p1/sshd.c.vendor 2013-03-25 19:34:01.332495531 +0100 -+++ openssh-6.2p1/sshd.c 2013-03-25 19:44:11.864112092 +0100 -@@ -442,7 +442,7 @@ sshd_exchange_identification(int sock_in - } + .It Cm StreamLocalBindMask + Sets the octal file creation mode mask + .Pq umask +diff -up openssh-7.4p1/sshd_config.vendor openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.vendor 2017-02-10 10:45:54.990836761 +0100 ++++ openssh-7.4p1/sshd_config 2017-02-10 10:45:54.996836718 +0100 +@@ -105,6 +105,7 @@ X11Forwarding yes + #Compression delayed + #ClientAliveInterval 0 + #ClientAliveCountMax 3 ++#ShowPatchLevel no + #UseDNS no + #PidFile /var/run/sshd.pid + #MaxStartups 10:30:100 +diff -up openssh-7.4p1/sshd.c.vendor openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.vendor 2017-02-10 10:45:54.996836718 +0100 ++++ openssh-7.4p1/sshd.c 2017-02-10 10:48:41.633648667 +0100 +@@ -367,7 +367,8 @@ sshd_exchange_identification(struct ssh + char remote_version[256]; /* Must be at least as big as buf. */ xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", -- major, minor, SSH_VERSION, -+ major, minor, (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, +- PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, ++ PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, ++ (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, *options.version_addendum == '\0' ? "" : " ", options.version_addendum, newline); -@@ -1675,7 +1675,8 @@ main(int ac, char **av) +@@ -1654,7 +1655,8 @@ main(int ac, char **av) exit(1); } - debug("sshd version %s, %s", SSH_VERSION, + debug("sshd version %s, %s", + (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, - SSLeay_version(SSLEAY_VERSION)); - - /* Store privilege separation user for later use if required. */ + #ifdef WITH_OPENSSL + SSLeay_version(SSLEAY_VERSION) + #else diff --git a/SOURCES/openssh-6.4p1-CLOCK_BOOTTIME.patch b/SOURCES/openssh-6.4p1-CLOCK_BOOTTIME.patch deleted file mode 100644 index 1073a77..0000000 --- a/SOURCES/openssh-6.4p1-CLOCK_BOOTTIME.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/misc.c -+++ b/misc.c -@@ -865,17 +865,24 @@ ms_to_timeval(struct timeval *tv, int ms - time_t - monotime(void) - { --#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) -+#if defined(HAVE_CLOCK_GETTIME) && \ -+ (defined(CLOCK_MONOTONIC) || defined(CLOCK_BOOTTIME)) - struct timespec ts; - static int gettime_failed = 0; - - if (!gettime_failed) { -+#if defined(CLOCK_BOOTTIME) -+ if (clock_gettime(CLOCK_BOOTTIME, &ts) == 0) -+ return (ts.tv_sec); -+#endif -+#if defined(CLOCK_MONOTONIC) - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) - return (ts.tv_sec); -+#endif - debug3("clock_gettime: %s", strerror(errno)); - gettime_failed = 1; - } --#endif -+#endif /* HAVE_CLOCK_GETTIME && (CLOCK_MONOTONIC || CLOCK_BOOTTIME */ - - return time(NULL); - } diff --git a/SOURCES/openssh-6.4p1-legacy-ssh-copy-id.patch b/SOURCES/openssh-6.4p1-legacy-ssh-copy-id.patch deleted file mode 100644 index ba8d949..0000000 --- a/SOURCES/openssh-6.4p1-legacy-ssh-copy-id.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff -up openssh-6.4p1/contrib/ssh-copy-id.1.legacy-ssh-copy-id openssh-6.4p1/contrib/ssh-copy-id.1 ---- openssh-6.4p1/contrib/ssh-copy-id.1.legacy-ssh-copy-id 2013-03-22 00:17:37.000000000 +0100 -+++ openssh-6.4p1/contrib/ssh-copy-id.1 2014-01-28 17:12:49.197542425 +0100 -@@ -180,6 +180,19 @@ should prove enlightening (N.B. the mode - .Fl W - option, rather than - .Xr nc 1 ) . -+.Sh ENVIRONMENT -+.Bl -tag -width Ds -+.Pp -+.It Pa SSH_COPY_ID_LEGACY -+If the -+.Cm SSH_COPY_ID_LEGACY -+environment variable is set, the -+.Nm -+is run in a legacy mode. In this mode, the -+.Nm -+doesn't check an existence of a private key and doesn't do remote checks -+of the remote server versions or if public keys are already installed. -+.El - .Sh "SEE ALSO" - .Xr ssh 1 , - .Xr ssh-agent 1 , -diff -up openssh-6.4p1/contrib/ssh-copy-id.legacy-ssh-copy-id openssh-6.4p1/contrib/ssh-copy-id ---- openssh-6.4p1/contrib/ssh-copy-id.legacy-ssh-copy-id 2013-06-05 14:48:45.000000000 +0200 -+++ openssh-6.4p1/contrib/ssh-copy-id 2014-01-28 17:11:51.538833032 +0100 -@@ -77,7 +77,7 @@ use_id_file() { - PUB_ID_FILE="$L_ID_FILE.pub" - fi - -- PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) -+ [ "x$SSH_COPY_ID_LEGACY" != "x" ] || PRIV_ID_FILE=$(dirname "$PUB_ID_FILE")/$(basename "$PUB_ID_FILE" .pub) - - # check that the files are readable - for f in $PUB_ID_FILE $PRIV_ID_FILE ; do -@@ -243,7 +243,7 @@ populate_new_ids() { - printf '%s: INFO: %d key(s) remain to be installed -- if you are prompted now it is to install the new keys\n' "$0" "$(printf '%s\n' "$NEW_IDS" | wc -l)" >&2 - } - --REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' "$@" 2>&1 | -+[ "x$SSH_COPY_ID_LEGACY" != "x" ] || REMOTE_VERSION=$(ssh -v -o PreferredAuthentications=',' "$@" 2>&1 | - sed -ne 's/.*remote software version //p') - - case "$REMOTE_VERSION" in -@@ -268,7 +268,11 @@ case "$REMOTE_VERSION" in - ;; - *) - # Assuming that the remote host treats ~/.ssh/authorized_keys as one might expect -- populate_new_ids 0 -+ if [ "x$SSH_COPY_ID_LEGACY" != "x" ]; then -+ NEW_IDS=`eval "$GET_ID"` -+ else -+ populate_new_ids 0 -+ fi - [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | ssh "$@" " - umask 077 ; - mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; diff --git a/SOURCES/openssh-6.6.1p1-NI_MAXHOST.patch b/SOURCES/openssh-6.6.1p1-NI_MAXHOST.patch deleted file mode 100644 index 7eeee50..0000000 --- a/SOURCES/openssh-6.6.1p1-NI_MAXHOST.patch +++ /dev/null @@ -1,76 +0,0 @@ -diff --git a/ChangeLog b/ChangeLog -index 928999d..3887495 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,3 +1,10 @@ -+20140703 -+ - OpenBSD CVS Sync -+ - djm@cvs.openbsd.org 2014/07/03 03:34:09 -+ [gss-serv.c session.c ssh-keygen.c] -+ standardise on NI_MAXHOST for gethostname() string lengths; about -+ 1/2 the cases were using it already. Fixes bz#2239 en passant -+ - 20140420 - - (djm) [bufaux.c compat.c compat.h sshconnect2.c sshd.c version.h] - OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519 -diff --git a/gss-serv.c b/gss-serv.c -index 14f540e..29916d3 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: gss-serv.c,v 1.26 2014/02/26 20:28:44 djm Exp $ */ -+/* $OpenBSD: gss-serv.c,v 1.27 2014/07/03 03:34:09 djm Exp $ */ - - /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -@@ -102,14 +102,14 @@ static OM_uint32 - ssh_gssapi_acquire_cred(Gssctxt *ctx) - { - OM_uint32 status; -- char lname[MAXHOSTNAMELEN]; -+ char lname[NI_MAXHOST]; - gss_OID_set oidset; - - if (options.gss_strict_acceptor) { - gss_create_empty_oid_set(&status, &oidset); - gss_add_oid_set_member(&status, ctx->oid, &oidset); - -- if (gethostname(lname, MAXHOSTNAMELEN)) { -+ if (gethostname(lname, sizeof(lname))) { - gss_release_oid_set(&status, &oidset); - return (-1); - } -diff --git a/session.c b/session.c -index ba4589b..e4add93 100644 ---- a/session.c -+++ b/session.c -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - #ifdef HAVE_PATHS_H - #include - #endif -@@ -2669,7 +2670,7 @@ session_setup_x11fwd(Session *s) - { - struct stat st; - char display[512], auth_display[512]; -- char hostname[MAXHOSTNAMELEN]; -+ char hostname[NI_MAXHOST]; - u_int i; - - if (no_x11_forwarding_flag) { -diff --git a/ssh-keygen.c b/ssh-keygen.c -index 482dc1c..66198e6 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -165,7 +165,7 @@ int rounds = 0; - /* argv0 */ - extern char *__progname; - --char hostname[MAXHOSTNAMELEN]; -+char hostname[NI_MAXHOST]; - - /* moduli.c */ - int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *); diff --git a/SOURCES/openssh-6.6.1p1-audit-pfs.patch b/SOURCES/openssh-6.6.1p1-audit-pfs.patch deleted file mode 100644 index 35be907..0000000 --- a/SOURCES/openssh-6.6.1p1-audit-pfs.patch +++ /dev/null @@ -1,212 +0,0 @@ -diff --git a/audit-bsm.c b/audit-bsm.c -index 5160869..c7a1b47 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -481,7 +481,7 @@ audit_unsupported_body(int what) - } - - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, 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) - { - /* not implemented */ - } -diff --git a/audit-linux.c b/audit-linux.c -index 6954fc1..6686f6a 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -297,7 +297,7 @@ audit_unsupported_body(int what) - const static char *direction[] = { "from-server", "from-client", "both" }; - - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, - uid_t uid) - { - #ifdef AUDIT_CRYPTO_SESSION -@@ -306,8 +306,8 @@ audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, - Cipher *cipher = cipher_by_name(enc); - char *s; - -- snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -- direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, -+ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, - (intmax_t)pid, (intmax_t)uid, - get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); - free(s); -diff --git a/audit.c b/audit.c -index 13c6849..5b49434 100644 ---- a/audit.c -+++ b/audit.c -@@ -135,9 +135,9 @@ audit_unsupported(int what) - } - - void --audit_kex(int ctos, char *enc, char *mac, char *comp) -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) - { -- PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); - } - - void -@@ -270,11 +270,11 @@ audit_unsupported_body(int what) - * This will be called on succesfull protocol negotiation. - */ - void --audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, - uid_t uid) - { -- debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", -- (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, - (unsigned)uid); - } - -diff --git a/audit.h b/audit.h -index a2dc3ff..903df66 100644 ---- a/audit.h -+++ b/audit.h -@@ -61,9 +61,9 @@ ssh_audit_event_t audit_classify_auth(const char *); - int audit_keyusage(int, const char *, unsigned, char *, int); - void audit_key(int, int *, const Key *); - void audit_unsupported(int); --void audit_kex(int, char *, char *, char *); -+void audit_kex(int, char *, char *, char *, char *); - void audit_unsupported_body(int); --void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); - void audit_session_key_free(int ctos); - void audit_session_key_free_body(int ctos, pid_t, uid_t); - void audit_destroy_sensitive_data(const char *, pid_t, uid_t); -diff --git a/auditstub.c b/auditstub.c -index 45817e0..116f460 100644 ---- a/auditstub.c -+++ b/auditstub.c -@@ -35,7 +35,7 @@ audit_unsupported(int n) - } - - void --audit_kex(int ctos, char *enc, char *mac, char *comp) -+audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) - { - } - -diff --git a/kex.c b/kex.c -index ede7b67..eb5f333 100644 ---- a/kex.c -+++ b/kex.c -@@ -553,13 +553,12 @@ kex_choose_conf(Kex *kex) - newkeys->enc.name, - authlen == 0 ? newkeys->mac.name : "", - newkeys->comp.name); --#ifdef SSH_AUDIT_EVENTS -- audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); --#endif - } -+ - choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], - sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); -+ - need = dh_need = 0; - for (mode = 0; mode < MODE_MAX; mode++) { - newkeys = kex->newkeys[mode]; -@@ -571,11 +570,16 @@ kex_choose_conf(Kex *kex) - dh_need = MAX(dh_need, newkeys->enc.block_size); - dh_need = MAX(dh_need, newkeys->enc.iv_len); - dh_need = MAX(dh_need, newkeys->mac.key_len); -+ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); -+#endif - } - /* XXX need runden? */ - kex->we_need = need; - kex->dh_need = dh_need; - -+ - /* ignore the next message if the proposals do not match */ - if (first_kex_follows && !proposals_match(my, peer) && - !(datafellows & SSH_BUG_FIRSTKEX)) { -diff --git a/monitor.c b/monitor.c -index 70b9b4c..81bc9c1 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2396,7 +2396,7 @@ int - mm_answer_audit_kex_body(int sock, Buffer *m) - { - int ctos, len; -- char *cipher, *mac, *compress; -+ char *cipher, *mac, *compress, *pfs; - pid_t pid; - uid_t uid; - -@@ -2404,14 +2404,16 @@ mm_answer_audit_kex_body(int sock, Buffer *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); - -- audit_kex_body(ctos, cipher, mac, compress, pid, uid); -+ audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); - - free(cipher); - free(mac); - free(compress); -+ free(pfs); - buffer_clear(m); - - mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 93f6535..69b29d8 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -1408,7 +1408,7 @@ mm_audit_unsupported_body(int what) - } - - void --mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid, - uid_t uid) - { - Buffer m; -@@ -1418,6 +1418,7 @@ mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, pid_t pid, - 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); - -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 4cf0c78..e43109f 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -83,7 +83,7 @@ void mm_audit_event(ssh_audit_event_t); - int mm_audit_run_command(const char *); - void mm_audit_end_command(int, const char *); - void mm_audit_unsupported_body(int); --void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); - void mm_audit_session_key_free_body(int, pid_t, uid_t); - void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); - #endif -diff --git a/sshd.c b/sshd.c -index ee94825..41a94a7 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2430,7 +2430,7 @@ do_ssh1_kex(void) - packet_disconnect("IP Spoofing check bytes do not match."); - - #ifdef SSH_AUDIT_EVENTS -- audit_kex(2, cipher_name(cipher_type), "crc", "none"); -+ audit_kex(2, cipher_name(cipher_type), "crc", "none", "none"); - #endif - - debug("Encryption type: %.200s", cipher_name(cipher_type)); diff --git a/SOURCES/openssh-6.6.1p1-coverity.patch b/SOURCES/openssh-6.6.1p1-coverity.patch deleted file mode 100644 index 9f71f9c..0000000 --- a/SOURCES/openssh-6.6.1p1-coverity.patch +++ /dev/null @@ -1,844 +0,0 @@ -diff --git a/auth-pam.c b/auth-pam.c -index cd1a775..690711e 100644 ---- a/auth-pam.c -+++ b/auth-pam.c -@@ -216,7 +216,12 @@ pthread_join(sp_pthread_t thread, void **value) - if (sshpam_thread_status != -1) - return (sshpam_thread_status); - signal(SIGCHLD, sshpam_oldsig); -- waitpid(thread, &status, 0); -+ while (waitpid(thread, &status, 0) < 0) { -+ if (errno == EINTR) -+ continue; -+ fatal("%s: waitpid: %s", __func__, -+ strerror(errno)); -+ } - return (status); - } - #endif -diff --git a/channels.c b/channels.c -index af3fdc2..39c9f89 100644 ---- a/channels.c -+++ b/channels.c -@@ -233,11 +233,11 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, - channel_max_fd = MAX(channel_max_fd, wfd); - channel_max_fd = MAX(channel_max_fd, efd); - -- if (rfd != -1) -+ if (rfd >= 0) - fcntl(rfd, F_SETFD, FD_CLOEXEC); -- if (wfd != -1 && wfd != rfd) -+ if (wfd >= 0 && wfd != rfd) - fcntl(wfd, F_SETFD, FD_CLOEXEC); -- if (efd != -1 && efd != rfd && efd != wfd) -+ if (efd >= 0 && efd != rfd && efd != wfd) - fcntl(efd, F_SETFD, FD_CLOEXEC); - - c->rfd = rfd; -@@ -255,11 +255,11 @@ channel_register_fds(Channel *c, int rfd, int wfd, int efd, - - /* enable nonblocking mode */ - if (nonblock) { -- if (rfd != -1) -+ if (rfd >= 0) - set_nonblock(rfd); -- if (wfd != -1) -+ if (wfd >= 0) - set_nonblock(wfd); -- if (efd != -1) -+ if (efd >= 0) - set_nonblock(efd); - } - } -diff --git a/clientloop.c b/clientloop.c -index 9c60108..d372b53 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -2081,14 +2081,15 @@ client_input_global_request(int type, u_int32_t seq, void *ctxt) - char *rtype; - int want_reply; - int success = 0; -+/* success is still 0 the packet is allways SSH2_MSG_REQUEST_FAILURE, isn't it? */ - - rtype = packet_get_string(NULL); - want_reply = packet_get_char(); - debug("client_input_global_request: rtype %s want_reply %d", - rtype, want_reply); - if (want_reply) { -- packet_start(success ? -- SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); -+ packet_start(/*success ? -+ SSH2_MSG_REQUEST_SUCCESS :*/ SSH2_MSG_REQUEST_FAILURE); - packet_send(); - packet_write_wait(); - } -diff --git a/key.c b/key.c -index a2050f6..6487d81 100644 ---- a/key.c -+++ b/key.c -@@ -880,8 +880,10 @@ key_read(Key *ret, char **cpp) - success = 1; - /*XXXX*/ - key_free(k); -+/*XXXX - if (success != 1) - break; -+XXXX*/ - /* advance cp: skip whitespace and data */ - while (*cp == ' ' || *cp == '\t') - cp++; -diff --git a/monitor.c b/monitor.c -index 3ff62b0..70b9b4c 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -472,7 +472,7 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) - mm_get_keystate(pmonitor); - - /* Drain any buffered messages from the child */ -- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) - ; - - close(pmonitor->m_sendfd); -@@ -1254,6 +1254,10 @@ mm_answer_keyallowed(int sock, Buffer *m) - break; - } - } -+ -+ debug3("%s: key %p is %s", -+ __func__, key, allowed ? "allowed" : "not allowed"); -+ - if (key != NULL) - key_free(key); - -@@ -1275,9 +1279,6 @@ mm_answer_keyallowed(int sock, Buffer *m) - free(chost); - } - -- debug3("%s: key %p is %s", -- __func__, key, allowed ? "allowed" : "not allowed"); -- - buffer_clear(m); - buffer_put_int(m, allowed); - buffer_put_int(m, forced_command != NULL); -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 6df236a..93f6535 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -743,10 +743,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) - if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || - (tmp2 = dup(pmonitor->m_recvfd)) == -1) { - error("%s: cannot allocate fds for pty", __func__); -- if (tmp1 > 0) -+ if (tmp1 >= 0) - close(tmp1); -- if (tmp2 > 0) -- close(tmp2); -+ /*DEAD CODE if (tmp2 >= 0) -+ close(tmp2);*/ - return 0; - } - close(tmp1); -diff --git a/openbsd-compat/bindresvport.c b/openbsd-compat/bindresvport.c -index c89f214..80115c2 100644 ---- a/openbsd-compat/bindresvport.c -+++ b/openbsd-compat/bindresvport.c -@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr *sa) - struct sockaddr_in6 *in6; - u_int16_t *portp; - u_int16_t port; -- socklen_t salen; -+ socklen_t salen = sizeof(struct sockaddr_storage); - int i; - - if (sa == NULL) { -diff --git a/packet.c b/packet.c -index f5b122b..1305e87 100644 ---- a/packet.c -+++ b/packet.c -@@ -1234,6 +1234,7 @@ packet_read_poll1(void) - case DEATTACK_DETECTED: - packet_disconnect("crc32 compensation attack: " - "network attack detected"); -+ break; - case DEATTACK_DOS_DETECTED: - packet_disconnect("deattack denial of " - "service detected"); -diff --git a/progressmeter.c b/progressmeter.c -index bbbc706..ae6d1aa 100644 ---- a/progressmeter.c -+++ b/progressmeter.c -@@ -65,7 +65,7 @@ static void update_progress_meter(int); - - static time_t start; /* start progress */ - static time_t last_update; /* last progress update */ --static char *file; /* name of the file being transferred */ -+static const char *file; /* name of the file being transferred */ - static off_t start_pos; /* initial position of transfer */ - static off_t end_pos; /* ending position of transfer */ - static off_t cur_pos; /* transfer position as of last refresh */ -@@ -248,7 +248,7 @@ update_progress_meter(int ignore) - } - - void --start_progress_meter(char *f, off_t filesize, off_t *ctr) -+start_progress_meter(const char *f, off_t filesize, off_t *ctr) - { - start = last_update = monotime(); - file = f; -diff --git a/progressmeter.h b/progressmeter.h -index 10bab99..e9ca8f0 100644 ---- a/progressmeter.h -+++ b/progressmeter.h -@@ -23,5 +23,5 @@ - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - --void start_progress_meter(char *, off_t, off_t *); -+void start_progress_meter(const char *, off_t, off_t *); - void stop_progress_meter(void); -diff --git a/scp.c b/scp.c -index 1178a07..d9bc016 100644 ---- a/scp.c -+++ b/scp.c -@@ -155,7 +155,7 @@ killchild(int signo) - { - if (do_cmd_pid > 1) { - kill(do_cmd_pid, signo ? signo : SIGTERM); -- waitpid(do_cmd_pid, NULL, 0); -+ (void) waitpid(do_cmd_pid, NULL, 0); - } - - if (signo) -diff --git a/servconf.c b/servconf.c -index 3839928..d482e79 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -1382,7 +1382,7 @@ process_server_config_line(ServerOptions *options, char *line, - fatal("%s line %d: Missing subsystem name.", - filename, linenum); - if (!*activep) { -- arg = strdelim(&cp); -+ /*arg =*/ (void) strdelim(&cp); - break; - } - for (i = 0; i < options->num_subsystems; i++) -@@ -1473,8 +1473,9 @@ process_server_config_line(ServerOptions *options, char *line, - if (*activep && *charptr == NULL) { - *charptr = tilde_expand_filename(arg, getuid()); - /* increase optional counter */ -- if (intptr != NULL) -- *intptr = *intptr + 1; -+ /* DEAD CODE intptr is still NULL ;) -+ if (intptr != NULL) -+ *intptr = *intptr + 1; */ - } - break; - -diff --git a/serverloop.c b/serverloop.c -index 2f8e3a0..e03bc6c 100644 ---- a/serverloop.c -+++ b/serverloop.c -@@ -147,13 +147,13 @@ notify_setup(void) - static void - notify_parent(void) - { -- if (notify_pipe[1] != -1) -+ if (notify_pipe[1] >= 0) - (void)write(notify_pipe[1], "", 1); - } - static void - notify_prepare(fd_set *readset) - { -- if (notify_pipe[0] != -1) -+ if (notify_pipe[0] >= 0) - FD_SET(notify_pipe[0], readset); - } - static void -@@ -161,8 +161,8 @@ notify_done(fd_set *readset) - { - char c; - -- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) -- while (read(notify_pipe[0], &c, 1) != -1) -+ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) -+ while (read(notify_pipe[0], &c, 1) >= 0) - debug2("notify_done: reading"); - } - -@@ -337,7 +337,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, - * If we have buffered data, try to write some of that data - * to the program. - */ -- if (fdin != -1 && buffer_len(&stdin_buffer) > 0) -+ if (fdin >= 0 && buffer_len(&stdin_buffer) > 0) - FD_SET(fdin, *writesetp); - } - notify_prepare(*readsetp); -@@ -477,7 +477,7 @@ process_output(fd_set *writeset) - int len; - - /* Write buffered data to program stdin. */ -- if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { -+ if (!compat20 && fdin >= 0 && FD_ISSET(fdin, writeset)) { - data = buffer_ptr(&stdin_buffer); - dlen = buffer_len(&stdin_buffer); - len = write(fdin, data, dlen); -@@ -590,7 +590,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) - set_nonblock(fdin); - set_nonblock(fdout); - /* we don't have stderr for interactive terminal sessions, see below */ -- if (fderr != -1) -+ if (fderr >= 0) - set_nonblock(fderr); - - if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) -@@ -614,7 +614,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) - max_fd = MAX(connection_in, connection_out); - max_fd = MAX(max_fd, fdin); - max_fd = MAX(max_fd, fdout); -- if (fderr != -1) -+ if (fderr >= 0) - max_fd = MAX(max_fd, fderr); - #endif - -@@ -644,7 +644,7 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) - * If we have received eof, and there is no more pending - * input data, cause a real eof by closing fdin. - */ -- if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) { -+ if (stdin_eof && fdin >= 0 && buffer_len(&stdin_buffer) == 0) { - if (fdin != fdout) - close(fdin); - else -@@ -740,15 +740,15 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) - buffer_free(&stderr_buffer); - - /* Close the file descriptors. */ -- if (fdout != -1) -+ if (fdout >= 0) - close(fdout); - fdout = -1; - fdout_eof = 1; -- if (fderr != -1) -+ if (fderr >= 0) - close(fderr); - fderr = -1; - fderr_eof = 1; -- if (fdin != -1) -+ if (fdin >= 0) - close(fdin); - fdin = -1; - -@@ -947,7 +947,7 @@ server_input_window_size(int type, u_int32_t seq, void *ctxt) - - debug("Window change received."); - packet_check_eom(); -- if (fdin != -1) -+ if (fdin >= 0) - pty_change_window_size(fdin, row, col, xpixel, ypixel); - } - -@@ -1007,7 +1007,7 @@ server_request_tun(void) - } - - tun = packet_get_int(); -- if (forced_tun_device != -1) { -+ if (forced_tun_device >= 0) { - if (tun != SSH_TUNID_ANY && forced_tun_device != tun) - goto done; - tun = forced_tun_device; -diff --git a/sftp-client.c b/sftp-client.c -index 2f5907c..3a2affd 100644 ---- a/sftp-client.c -+++ b/sftp-client.c -@@ -151,7 +151,7 @@ get_msg(struct sftp_conn *conn, Buffer *m) - } - - static void --send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, -+send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s, - u_int len) - { - Buffer msg; -@@ -167,7 +167,7 @@ send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, - - static void - send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, -- char *s, u_int len, Attrib *a) -+ const char *s, u_int len, Attrib *a) - { - Buffer msg; - -@@ -429,7 +429,7 @@ sftp_proto_version(struct sftp_conn *conn) - } - - int --do_close(struct sftp_conn *conn, char *handle, u_int handle_len) -+do_close(struct sftp_conn *conn, const char *handle, u_int handle_len) - { - u_int id, status; - Buffer msg; -@@ -454,7 +454,7 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len) - - - static int --do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, -+do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, - SFTP_DIRENT ***dir) - { - Buffer msg; -@@ -577,7 +577,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, - } - - int --do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) -+do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) - { - return(do_lsreaddir(conn, path, 0, dir)); - } -@@ -597,7 +597,7 @@ void free_sftp_dirents(SFTP_DIRENT **s) - } - - int --do_rm(struct sftp_conn *conn, char *path) -+do_rm(struct sftp_conn *conn, const char *path) - { - u_int status, id; - -@@ -612,7 +612,7 @@ do_rm(struct sftp_conn *conn, char *path) - } - - int --do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) -+do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) - { - u_int status, id; - -@@ -628,7 +628,7 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) - } - - int --do_rmdir(struct sftp_conn *conn, char *path) -+do_rmdir(struct sftp_conn *conn, const char *path) - { - u_int status, id; - -@@ -644,7 +644,7 @@ do_rmdir(struct sftp_conn *conn, char *path) - } - - Attrib * --do_stat(struct sftp_conn *conn, char *path, int quiet) -+do_stat(struct sftp_conn *conn, const char *path, int quiet) - { - u_int id; - -@@ -658,7 +658,7 @@ do_stat(struct sftp_conn *conn, char *path, int quiet) - } - - Attrib * --do_lstat(struct sftp_conn *conn, char *path, int quiet) -+do_lstat(struct sftp_conn *conn, const char *path, int quiet) - { - u_int id; - -@@ -679,7 +679,7 @@ do_lstat(struct sftp_conn *conn, char *path, int quiet) - - #ifdef notyet - Attrib * --do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) -+do_fstat(struct sftp_conn *conn, const char *handle, u_int handle_len, int quiet) - { - u_int id; - -@@ -692,7 +692,7 @@ do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) - #endif - - int --do_setstat(struct sftp_conn *conn, char *path, Attrib *a) -+do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) - { - u_int status, id; - -@@ -709,7 +709,7 @@ do_setstat(struct sftp_conn *conn, char *path, Attrib *a) - } - - int --do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, -+do_fsetstat(struct sftp_conn *conn, const char *handle, u_int handle_len, - Attrib *a) - { - u_int status, id; -@@ -726,7 +726,7 @@ do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, - } - - char * --do_realpath(struct sftp_conn *conn, char *path) -+do_realpath(struct sftp_conn *conn, const char *path) - { - Buffer msg; - u_int type, expected_id, count, id; -@@ -775,7 +775,7 @@ do_realpath(struct sftp_conn *conn, char *path) - } - - int --do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, -+do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, - int force_legacy) - { - Buffer msg; -@@ -811,7 +811,7 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, - } - - int --do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) -+do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) - { - Buffer msg; - u_int status, id; -@@ -844,7 +844,7 @@ do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) - } - - int --do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) -+do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) - { - Buffer msg; - u_int status, id; -@@ -876,7 +876,7 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) - } - - int --do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) -+do_fsync(struct sftp_conn *conn, const char *handle, u_int handle_len) - { - Buffer msg; - u_int status, id; -@@ -907,7 +907,7 @@ do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) - - #ifdef notyet - char * --do_readlink(struct sftp_conn *conn, char *path) -+do_readlink(struct sftp_conn *conn, const char *path) - { - Buffer msg; - u_int type, expected_id, count, id; -@@ -1010,7 +1010,7 @@ do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, - - static void - send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, -- u_int len, char *handle, u_int handle_len) -+ u_int len, const char *handle, u_int handle_len) - { - Buffer msg; - -@@ -1026,7 +1026,7 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, - } - - int --do_download(struct sftp_conn *conn, char *remote_path, char *local_path, -+do_download(struct sftp_conn *conn, const char *remote_path, const char *local_path, - Attrib *a, int preserve_flag, int resume_flag, int fsync_flag) - { - Attrib junk; -@@ -1308,7 +1308,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, - } - - static int --download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, -+download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int depth, - Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, - int fsync_flag) - { -@@ -1400,7 +1400,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, - } - - int --download_dir(struct sftp_conn *conn, char *src, char *dst, -+download_dir(struct sftp_conn *conn, const char *src, const char *dst, - Attrib *dirattrib, int preserve_flag, int print_flag, - int resume_flag, int fsync_flag) - { -@@ -1419,7 +1419,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst, - } - - int --do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, -+do_upload(struct sftp_conn *conn, const char *local_path, const char *remote_path, - int preserve_flag, int fsync_flag) - { - int local_fd; -@@ -1607,7 +1607,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, - } - - static int --upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, -+upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, int depth, - int preserve_flag, int print_flag, int fsync_flag) - { - int ret = 0, status; -@@ -1700,7 +1700,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, - } - - int --upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, -+upload_dir(struct sftp_conn *conn, const char *src, const char *dst, int preserve_flag, - int print_flag, int fsync_flag) - { - char *dst_canon; -@@ -1719,7 +1719,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, - } - - char * --path_append(char *p1, char *p2) -+path_append(const char *p1, const char *p2) - { - char *ret; - size_t len = strlen(p1) + strlen(p2) + 2; -diff --git a/sftp-client.h b/sftp-client.h -index ba92ad0..c085423 100644 ---- a/sftp-client.h -+++ b/sftp-client.h -@@ -56,79 +56,79 @@ struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t); - u_int sftp_proto_version(struct sftp_conn *); - - /* Close file referred to by 'handle' */ --int do_close(struct sftp_conn *, char *, u_int); -+int do_close(struct sftp_conn *, const char *, u_int); - - /* Read contents of 'path' to NULL-terminated array 'dir' */ --int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); -+int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***); - - /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ - void free_sftp_dirents(SFTP_DIRENT **); - - /* Delete file 'path' */ --int do_rm(struct sftp_conn *, char *); -+int do_rm(struct sftp_conn *, const char *); - - /* Create directory 'path' */ --int do_mkdir(struct sftp_conn *, char *, Attrib *, int); -+int do_mkdir(struct sftp_conn *, const char *, Attrib *, int); - - /* Remove directory 'path' */ --int do_rmdir(struct sftp_conn *, char *); -+int do_rmdir(struct sftp_conn *, const char *); - - /* Get file attributes of 'path' (follows symlinks) */ --Attrib *do_stat(struct sftp_conn *, char *, int); -+Attrib *do_stat(struct sftp_conn *, const char *, int); - - /* Get file attributes of 'path' (does not follow symlinks) */ --Attrib *do_lstat(struct sftp_conn *, char *, int); -+Attrib *do_lstat(struct sftp_conn *, const char *, int); - - /* Set file attributes of 'path' */ --int do_setstat(struct sftp_conn *, char *, Attrib *); -+int do_setstat(struct sftp_conn *, const char *, Attrib *); - - /* Set file attributes of open file 'handle' */ --int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *); -+int do_fsetstat(struct sftp_conn *, const char *, u_int, Attrib *); - - /* Canonicalise 'path' - caller must free result */ --char *do_realpath(struct sftp_conn *, char *); -+char *do_realpath(struct sftp_conn *, const char *); - - /* Get statistics for filesystem hosting file at "path" */ - int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); - - /* Rename 'oldpath' to 'newpath' */ --int do_rename(struct sftp_conn *, char *, char *m, int force_legacy); -+int do_rename(struct sftp_conn *, const char *, const char *m, int force_legacy); - - /* Link 'oldpath' to 'newpath' */ --int do_hardlink(struct sftp_conn *, char *, char *); -+int do_hardlink(struct sftp_conn *, const char *, const char *); - - /* Rename 'oldpath' to 'newpath' */ --int do_symlink(struct sftp_conn *, char *, char *); -+int do_symlink(struct sftp_conn *, const char *, const char *); - - /* Call fsync() on open file 'handle' */ --int do_fsync(struct sftp_conn *conn, char *, u_int); -+int do_fsync(struct sftp_conn *conn, const char *, u_int); - - /* - * Download 'remote_path' to 'local_path'. Preserve permissions and times - * if 'pflag' is set - */ --int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int, int); -+int do_download(struct sftp_conn *, const char *, const char *, Attrib *, int, int, int); - - /* - * Recursively download 'remote_directory' to 'local_directory'. Preserve - * times if 'pflag' is set - */ --int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, -+int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, int, - int, int, int); - - /* - * Upload 'local_path' to 'remote_path'. Preserve permissions and times - * if 'pflag' is set - */ --int do_upload(struct sftp_conn *, char *, char *, int, int); -+int do_upload(struct sftp_conn *, const char *, const char *, int, int); - - /* - * Recursively upload 'local_directory' to 'remote_directory'. Preserve - * times if 'pflag' is set - */ --int upload_dir(struct sftp_conn *, char *, char *, int, int, int); -+int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int); - - /* Concatenate paths, taking care of slashes. Caller must free result. */ --char *path_append(char *, char *); -+char *path_append(const char *, const char *); - - #endif -diff --git a/sftp.c b/sftp.c -index ad1f8c8..3987117 100644 ---- a/sftp.c -+++ b/sftp.c -@@ -218,7 +218,7 @@ killchild(int signo) - { - if (sshpid > 1) { - kill(sshpid, SIGTERM); -- waitpid(sshpid, NULL, 0); -+ (void) waitpid(sshpid, NULL, 0); - } - - _exit(1); -@@ -329,7 +329,7 @@ local_do_ls(const char *args) - - /* Strip one path (usually the pwd) from the start of another */ - static char * --path_strip(char *path, char *strip) -+path_strip(const char *path, const char *strip) - { - size_t len; - -@@ -347,7 +347,7 @@ path_strip(char *path, char *strip) - } - - static char * --make_absolute(char *p, char *pwd) -+make_absolute(char *p, const char *pwd) - { - char *abs_str; - -@@ -545,7 +545,7 @@ parse_no_flags(const char *cmd, char **argv, int argc) - } - - static int --is_dir(char *path) -+is_dir(const char *path) - { - struct stat sb; - -@@ -557,7 +557,7 @@ is_dir(char *path) - } - - static int --remote_is_dir(struct sftp_conn *conn, char *path) -+remote_is_dir(struct sftp_conn *conn, const char *path) - { - Attrib *a; - -@@ -571,7 +571,7 @@ remote_is_dir(struct sftp_conn *conn, char *path) - - /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ - static int --pathname_is_dir(char *pathname) -+pathname_is_dir(const char *pathname) - { - size_t l = strlen(pathname); - -@@ -579,7 +579,7 @@ pathname_is_dir(char *pathname) - } - - static int --process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, -+process_get(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, - int pflag, int rflag, int resume, int fflag) - { - char *abs_src = NULL; -@@ -659,7 +659,7 @@ out: - } - - static int --process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, -+process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, - int pflag, int rflag, int fflag) - { - char *tmp_dst = NULL; -@@ -765,7 +765,7 @@ sdirent_comp(const void *aa, const void *bb) - - /* sftp ls.1 replacement for directories */ - static int --do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) -+do_ls_dir(struct sftp_conn *conn, const char *path, const char *strip_path, int lflag) - { - int n; - u_int c = 1, colspace = 0, columns = 1; -@@ -850,7 +850,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) - - /* sftp ls.1 replacement which handles path globs */ - static int --do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, -+do_globbed_ls(struct sftp_conn *conn, const char *path, const char *strip_path, - int lflag) - { - char *fname, *lname; -@@ -931,7 +931,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, - } - - static int --do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) -+do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag) - { - struct sftp_statvfs st; - char s_used[FMT_SCALED_STRSIZE]; -diff --git a/ssh-agent.c b/ssh-agent.c -index 117fdde..2b50132 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -1037,8 +1037,8 @@ main(int ac, char **av) - sanitise_stdfd(); - - /* drop */ -- setegid(getgid()); -- setgid(getgid()); -+ (void) setegid(getgid()); -+ (void) setgid(getgid()); - - #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) - /* Disable ptrace on Linux without sgid bit */ -diff --git a/sshd.c b/sshd.c -index 773bb02..1eaa9f7 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -771,8 +771,10 @@ privsep_preauth(Authctxt *authctxt) - if (getuid() == 0 || geteuid() == 0) - privsep_preauth_child(); - setproctitle("%s", "[net]"); -- if (box != NULL) -+ if (box != NULL) { - ssh_sandbox_child(box); -+ free(box); -+ } - - return 0; - } -@@ -1439,6 +1441,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) - if (num_listen_socks < 0) - break; - } -+ -+ if (fdset != NULL) -+ free(fdset); - } - - diff --git a/SOURCES/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch b/SOURCES/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch deleted file mode 100644 index 87434ce..0000000 --- a/SOURCES/openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/ChangeLog b/ChangeLog -index 3887495..a4dc72f 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,3 +1,9 @@ -+20140823 -+ - (djm) [sshd.c] Ignore SIGXFSZ in preauth monitor child; can explode on -+ lastlog writing on platforms with high UIDs; bz#2263 -+ - (djm) [monitor.c sshd.c] SIGXFSZ needs to be ignored in postauth -+ monitor, not preauth; bz#2263 -+ - 20140703 - - OpenBSD CVS Sync - - djm@cvs.openbsd.org 2014/07/03 03:34:09 -diff --git a/monitor.c b/monitor.c -index bdabe21..5a65114 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -501,6 +501,9 @@ monitor_child_postauth(struct monitor *pmonitor) - signal(SIGHUP, &monitor_child_handler); - signal(SIGTERM, &monitor_child_handler); - signal(SIGINT, &monitor_child_handler); -+#ifdef SIGXFSZ -+ signal(SIGXFSZ, SIG_IGN); -+#endif - - if (compat20) { - mon_dispatch = mon_dispatch_postauth20; diff --git a/SOURCES/openssh-6.6.1p1-log-in-chroot.patch b/SOURCES/openssh-6.6.1p1-log-in-chroot.patch deleted file mode 100644 index bccf39b..0000000 --- a/SOURCES/openssh-6.6.1p1-log-in-chroot.patch +++ /dev/null @@ -1,295 +0,0 @@ -diff --git a/log.c b/log.c -index 32e1d2e..d4caeb5 100644 ---- a/log.c -+++ b/log.c -@@ -241,6 +241,11 @@ debug3(const char *fmt,...) - void - log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) - { -+ log_init_handler(av0, level, facility, on_stderr, 1); -+} -+ -+void -+log_init_handler(char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int reset_handler) { - #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) - struct syslog_data sdata = SYSLOG_DATA_INIT; - #endif -@@ -264,8 +269,10 @@ log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) - exit(1); - } - -- log_handler = NULL; -- log_handler_ctx = NULL; -+ if (reset_handler) { -+ log_handler = NULL; -+ log_handler_ctx = NULL; -+ } - - log_on_stderr = on_stderr; - if (on_stderr) -diff --git a/log.h b/log.h -index ae7df25..30c3310 100644 ---- a/log.h -+++ b/log.h -@@ -49,6 +49,7 @@ typedef enum { - typedef void (log_handler_fn)(LogLevel, const char *, void *); - - void log_init(char *, LogLevel, SyslogFacility, int); -+void log_init_handler(char *, LogLevel, SyslogFacility, int, int); - void log_change_level(LogLevel); - int log_is_on_stderr(void); - void log_redirect_stderr_to(const char *); -diff --git a/monitor.c b/monitor.c -index 7461fae..da2f766 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -364,6 +364,8 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) - close(pmonitor->m_log_sendfd); - pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; - -+ pmonitor->m_state = "preauth"; -+ - authctxt = _authctxt; - memset(authctxt, 0, sizeof(*authctxt)); - -@@ -472,6 +474,8 @@ monitor_child_postauth(struct monitor *pmonitor) - close(pmonitor->m_recvfd); - pmonitor->m_recvfd = -1; - -+ pmonitor->m_state = "postauth"; -+ - monitor_set_child_handler(pmonitor->m_pid); - signal(SIGHUP, &monitor_child_handler); - signal(SIGTERM, &monitor_child_handler); -@@ -552,7 +556,7 @@ monitor_read_log(struct monitor *pmonitor) - if (log_level_name(level) == NULL) - fatal("%s: invalid log level %u (corrupted message?)", - __func__, level); -- do_log2(level, "%s [preauth]", msg); -+ do_log2(level, "%s [%s]", msg, pmonitor->m_state); - - buffer_free(&logmsg); - free(msg); -@@ -2083,13 +2087,28 @@ monitor_init(void) - mm_init_compression(mon->m_zlib); - } - -+ mon->m_state = ""; -+ - return mon; - } - - void --monitor_reinit(struct monitor *mon) -+monitor_reinit(struct monitor *mon, const char *chroot_dir) - { -- monitor_openfds(mon, 0); -+ struct stat dev_log_stat; -+ char *dev_log_path; -+ int do_logfds = 0; -+ -+ if (chroot_dir != NULL) { -+ xasprintf(&dev_log_path, "%s/dev/log", chroot_dir); -+ -+ if (stat(dev_log_path, &dev_log_stat) != 0) { -+ debug("%s: /dev/log doesn't exist in %s chroot - will try to log via monitor using [postauth] suffix", __func__, chroot_dir); -+ do_logfds = 1; -+ } -+ free(dev_log_path); -+ } -+ monitor_openfds(mon, do_logfds); - } - - #ifdef GSSAPI -diff --git a/monitor.h b/monitor.h -index ff79fbb..00c2028 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -83,10 +83,11 @@ struct monitor { - struct mm_master *m_zlib; - struct Kex **m_pkex; - pid_t m_pid; -+ char *m_state; - }; - - struct monitor *monitor_init(void); --void monitor_reinit(struct monitor *); -+void monitor_reinit(struct monitor *, const char *); - void monitor_sync(struct monitor *); - - struct Authctxt; -diff --git a/session.c b/session.c -index e4add93..bc4a8dd 100644 ---- a/session.c -+++ b/session.c -@@ -160,6 +160,8 @@ login_cap_t *lc; - - static int is_child = 0; - -+static int have_dev_log = 1; -+ - /* Name and directory of socket for authentication agent forwarding. */ - static char *auth_sock_name = NULL; - static char *auth_sock_dir = NULL; -@@ -523,8 +525,8 @@ do_exec_no_pty(Session *s, const char *command) - is_child = 1; - - /* Child. Reinitialize the log since the pid has changed. */ -- log_init(__progname, options.log_level, -- options.log_facility, log_stderr); -+ log_init_handler(__progname, options.log_level, -+ options.log_facility, log_stderr, have_dev_log); - - /* - * Create a new session and process group since the 4.4BSD -@@ -692,8 +694,8 @@ do_exec_pty(Session *s, const char *command) - close(ptymaster); - - /* Child. Reinitialize the log because the pid has changed. */ -- log_init(__progname, options.log_level, -- options.log_facility, log_stderr); -+ log_init_handler(__progname, options.log_level, -+ options.log_facility, log_stderr, have_dev_log); - /* Close the master side of the pseudo tty. */ - close(ptyfd); - -@@ -797,6 +799,7 @@ do_exec(Session *s, const char *command) - int ret; - const char *forced = NULL; - char session_type[1024], *tty = NULL; -+ struct stat dev_log_stat; - - if (options.adm_forced_command) { - original_command = command; -@@ -854,6 +857,10 @@ do_exec(Session *s, const char *command) - tty += 5; - } - -+ if (lstat("/dev/log", &dev_log_stat) != 0) { -+ have_dev_log = 0; -+ } -+ - verbose("Starting session: %s%s%s for %s from %.200s port %d", - session_type, - tty == NULL ? "" : " on ", -@@ -1681,14 +1688,6 @@ child_close_fds(void) - * descriptors left by system functions. They will be closed later. - */ - endpwent(); -- -- /* -- * Close any extra open file descriptors so that we don't have them -- * hanging around in clients. Note that we want to do this after -- * initgroups, because at least on Solaris 2.3 it leaves file -- * descriptors open. -- */ -- closefrom(STDERR_FILENO + 1); - } - - /* -@@ -1834,8 +1833,6 @@ do_child(Session *s, const char *command) - exit(1); - } - -- closefrom(STDERR_FILENO + 1); -- - if (!options.use_login) - do_rc_files(s, shell); - -@@ -1859,9 +1856,17 @@ do_child(Session *s, const char *command) - argv[i] = NULL; - optind = optreset = 1; - __progname = argv[0]; -- exit(sftp_server_main(i, argv, s->pw)); -+ exit(sftp_server_main(i, argv, s->pw, have_dev_log)); - } - -+ /* -+ * Close any extra open file descriptors so that we don't have them -+ * hanging around in clients. Note that we want to do this after -+ * initgroups, because at least on Solaris 2.3 it leaves file -+ * descriptors open. -+ */ -+ closefrom(STDERR_FILENO + 1); -+ - fflush(NULL); - - if (options.use_login) { -diff --git a/sftp-server-main.c b/sftp-server-main.c -index 7e644ab..e162b7a 100644 ---- a/sftp-server-main.c -+++ b/sftp-server-main.c -@@ -47,5 +47,5 @@ main(int argc, char **argv) - return 1; - } - -- return (sftp_server_main(argc, argv, user_pw)); -+ return (sftp_server_main(argc, argv, user_pw, 0)); - } -diff --git a/sftp-server.c b/sftp-server.c -index b8eb59c..a0e644c 100644 ---- a/sftp-server.c -+++ b/sftp-server.c -@@ -1437,7 +1437,7 @@ sftp_server_usage(void) - } - - int --sftp_server_main(int argc, char **argv, struct passwd *user_pw) -+sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler) - { - fd_set *rset, *wset; - int i, in, out, max, ch, skipargs = 0, log_stderr = 0; -@@ -1450,7 +1450,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) - extern char *__progname; - - __progname = ssh_get_progname(argv[0]); -- log_init(__progname, log_level, log_facility, log_stderr); -+ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); - - pw = pwcopy(user_pw); - -@@ -1521,7 +1521,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) - } - } - -- log_init(__progname, log_level, log_facility, log_stderr); -+ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); - - if ((cp = getenv("SSH_CONNECTION")) != NULL) { - client_addr = xstrdup(cp); -diff --git a/sftp.h b/sftp.h -index 2bde8bb..ddf1a39 100644 ---- a/sftp.h -+++ b/sftp.h -@@ -97,5 +97,5 @@ - - struct passwd; - --int sftp_server_main(int, char **, struct passwd *); -+int sftp_server_main(int, char **, struct passwd *, int); - void sftp_server_cleanup_exit(int) __attribute__((noreturn)); -diff --git a/sshd.c b/sshd.c -index 3eee75a..9c00bcb 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -745,7 +745,7 @@ privsep_postauth(Authctxt *authctxt) - } - - /* New socket pair */ -- monitor_reinit(pmonitor); -+ monitor_reinit(pmonitor, options.chroot_directory); - - pmonitor->m_pid = fork(); - if (pmonitor->m_pid == -1) -@@ -763,6 +763,11 @@ privsep_postauth(Authctxt *authctxt) - - close(pmonitor->m_sendfd); - pmonitor->m_sendfd = -1; -+ close(pmonitor->m_log_recvfd); -+ pmonitor->m_log_recvfd = -1; -+ -+ if (pmonitor->m_log_sendfd != -1) -+ set_log_handler(mm_log_handler, pmonitor); - - /* Demote the private keys to public keys. */ - demote_sensitive_data(); diff --git a/SOURCES/openssh-6.6.1p1-partial-success.patch b/SOURCES/openssh-6.6.1p1-partial-success.patch deleted file mode 100644 index b5c61cf..0000000 --- a/SOURCES/openssh-6.6.1p1-partial-success.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/auth2.c b/auth2.c -index d9b440a..ec0bf12 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -355,8 +355,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, const char *method, - authctxt->success = 1; - } else { - -- /* Allow initial try of "none" auth without failure penalty */ -- if (!authctxt->server_caused_failure && -+ /* Allow initial try of "none" auth without failure penalty -+ * Partial succes is not failure */ -+ if (!authctxt->server_caused_failure && !partial && - (authctxt->attempt > 1 || strcmp(method, "none") != 0)) - authctxt->failures++; - if (authctxt->failures >= options.max_authtries) { diff --git a/SOURCES/openssh-6.6.1p1-servconf-parser.patch b/SOURCES/openssh-6.6.1p1-servconf-parser.patch deleted file mode 100644 index b93f6f3..0000000 --- a/SOURCES/openssh-6.6.1p1-servconf-parser.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/servconf.c b/servconf.c -index b7f3294..bc1e909 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -1550,7 +1550,7 @@ process_server_config_line(ServerOptions *options, char *line, - break; - - case sForceCommand: -- if (cp == NULL) -+ if (cp == NULL || *cp == '\0') - fatal("%.200s line %d: Missing argument.", filename, - linenum); - len = strspn(cp, WHITESPACE); -@@ -1595,7 +1595,7 @@ process_server_config_line(ServerOptions *options, char *line, - break; - - case sVersionAddendum: -- if (cp == NULL) -+ if (cp == NULL || *cp == '\0') - fatal("%.200s line %d: Missing argument.", filename, - linenum); - len = strspn(cp, WHITESPACE); -@@ -1630,6 +1630,8 @@ process_server_config_line(ServerOptions *options, char *line, - break; - - case sAuthenticationMethods: -+ if (cp == NULL || *cp == '\0') -+ fatal("%.200s line %d: Missing argument.", filename, linenum); - if (*activep && options->num_auth_methods == 0) { - while ((arg = strdelim(&cp)) && *arg != '\0') { - if (options->num_auth_methods >= diff --git a/SOURCES/openssh-6.6.1p1-utf8-banner.patch b/SOURCES/openssh-6.6.1p1-utf8-banner.patch deleted file mode 100644 index 1ab8ade..0000000 --- a/SOURCES/openssh-6.6.1p1-utf8-banner.patch +++ /dev/null @@ -1,994 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 2ad26ff..0f0d39f 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -81,7 +81,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ - ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ -- ssh-ed25519.o digest-openssl.o hmac.o \ -+ ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \ - sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ -diff --git a/misc.h b/misc.h -index d4df619..d98b83d 100644 ---- a/misc.h -+++ b/misc.h -@@ -106,4 +106,7 @@ char *read_passphrase(const char *, int); - int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); - int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); - -+/* utf8_stringprep.c */ -+int utf8_stringprep(const char *, char *, size_t); -+ - #endif /* _MISC_H */ -diff --git a/sshconnect2.c b/sshconnect2.c -index b00658b..08064f4 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -33,6 +33,8 @@ - - #include - #include -+#include -+#include - #include - #include - #include -@@ -519,21 +521,51 @@ input_userauth_error(int type, u_int32_t seq, void *ctxt) - "type %d", type); - } - -+/* Check whether we can display UTF-8 safely */ -+static int -+utf8_ok(void) -+{ -+ static int ret = -1; -+ char *cp; -+ -+ if (ret == -1) { -+ setlocale(LC_CTYPE, ""); -+ cp = nl_langinfo(CODESET); -+ ret = strcmp(cp, "UTF-8") == 0; -+ } -+ return ret; -+} -+ - /* ARGSUSED */ - void - input_userauth_banner(int type, u_int32_t seq, void *ctxt) - { - char *msg, *raw, *lang; -- u_int len; -+ u_int done, len; - - debug3("input_userauth_banner"); -+ - raw = packet_get_string(&len); - lang = packet_get_string(NULL); - if (len > 0 && options.log_level >= SYSLOG_LEVEL_INFO) { - if (len > 65536) - len = 65536; - msg = xmalloc(len * 4 + 1); /* max expansion from strnvis() */ -- strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH); -+ done = 0; -+ if (utf8_ok()) { -+ if (utf8_stringprep(raw, msg, len * 4 + 1) == 0) -+ done = 1; -+ else -+ debug2("%s: UTF8 stringprep failed", __func__); -+ } -+ /* -+ * Fallback to strnvis if UTF8 display not supported or -+ * conversion failed. -+ */ -+ if (!done) { -+ strnvis(msg, raw, len * 4 + 1, -+ VIS_SAFE|VIS_OCTAL|VIS_NOSLASH); -+ } - fprintf(stderr, "%s", msg); - free(msg); - } -diff --git a/stringprep-tables.c b/stringprep-tables.c -new file mode 100644 -index 0000000..49f4d9d ---- /dev/null -+++ b/stringprep-tables.c -@@ -0,0 +1,661 @@ -+/* Public domain. */ -+ -+/* $OpenBSD$ */ -+ -+/* -+ * Tables for RFC3454 stringprep algorithm, updated with a table of allocated -+ * characters generated from Unicode.6.2's UnicodeData.txt -+ * -+ * Intended to be included directly from utf8_stringprep.c -+ */ -+ -+/* Unassigned characters in Unicode 6.2 */ -+static const struct u32_range unassigned[] = { -+ { 0x0378, 0x0379 }, -+ { 0x037F, 0x0383 }, -+ { 0x038B, 0x038B }, -+ { 0x038D, 0x038D }, -+ { 0x03A2, 0x03A2 }, -+ { 0x0528, 0x0530 }, -+ { 0x0557, 0x0558 }, -+ { 0x0560, 0x0560 }, -+ { 0x0588, 0x0588 }, -+ { 0x058B, 0x058E }, -+ { 0x0590, 0x0590 }, -+ { 0x05C8, 0x05CF }, -+ { 0x05EB, 0x05EF }, -+ { 0x05F5, 0x05FF }, -+ { 0x0605, 0x0605 }, -+ { 0x061C, 0x061D }, -+ { 0x070E, 0x070E }, -+ { 0x074B, 0x074C }, -+ { 0x07B2, 0x07BF }, -+ { 0x07FB, 0x07FF }, -+ { 0x082E, 0x082F }, -+ { 0x083F, 0x083F }, -+ { 0x085C, 0x085D }, -+ { 0x085F, 0x089F }, -+ { 0x08A1, 0x08A1 }, -+ { 0x08AD, 0x08E3 }, -+ { 0x08FF, 0x08FF }, -+ { 0x0978, 0x0978 }, -+ { 0x0980, 0x0980 }, -+ { 0x0984, 0x0984 }, -+ { 0x098D, 0x098E }, -+ { 0x0991, 0x0992 }, -+ { 0x09A9, 0x09A9 }, -+ { 0x09B1, 0x09B1 }, -+ { 0x09B3, 0x09B5 }, -+ { 0x09BA, 0x09BB }, -+ { 0x09C5, 0x09C6 }, -+ { 0x09C9, 0x09CA }, -+ { 0x09CF, 0x09D6 }, -+ { 0x09D8, 0x09DB }, -+ { 0x09DE, 0x09DE }, -+ { 0x09E4, 0x09E5 }, -+ { 0x09FC, 0x0A00 }, -+ { 0x0A04, 0x0A04 }, -+ { 0x0A0B, 0x0A0E }, -+ { 0x0A11, 0x0A12 }, -+ { 0x0A29, 0x0A29 }, -+ { 0x0A31, 0x0A31 }, -+ { 0x0A34, 0x0A34 }, -+ { 0x0A37, 0x0A37 }, -+ { 0x0A3A, 0x0A3B }, -+ { 0x0A3D, 0x0A3D }, -+ { 0x0A43, 0x0A46 }, -+ { 0x0A49, 0x0A4A }, -+ { 0x0A4E, 0x0A50 }, -+ { 0x0A52, 0x0A58 }, -+ { 0x0A5D, 0x0A5D }, -+ { 0x0A5F, 0x0A65 }, -+ { 0x0A76, 0x0A80 }, -+ { 0x0A84, 0x0A84 }, -+ { 0x0A8E, 0x0A8E }, -+ { 0x0A92, 0x0A92 }, -+ { 0x0AA9, 0x0AA9 }, -+ { 0x0AB1, 0x0AB1 }, -+ { 0x0AB4, 0x0AB4 }, -+ { 0x0ABA, 0x0ABB }, -+ { 0x0AC6, 0x0AC6 }, -+ { 0x0ACA, 0x0ACA }, -+ { 0x0ACE, 0x0ACF }, -+ { 0x0AD1, 0x0ADF }, -+ { 0x0AE4, 0x0AE5 }, -+ { 0x0AF2, 0x0B00 }, -+ { 0x0B04, 0x0B04 }, -+ { 0x0B0D, 0x0B0E }, -+ { 0x0B11, 0x0B12 }, -+ { 0x0B29, 0x0B29 }, -+ { 0x0B31, 0x0B31 }, -+ { 0x0B34, 0x0B34 }, -+ { 0x0B3A, 0x0B3B }, -+ { 0x0B45, 0x0B46 }, -+ { 0x0B49, 0x0B4A }, -+ { 0x0B4E, 0x0B55 }, -+ { 0x0B58, 0x0B5B }, -+ { 0x0B5E, 0x0B5E }, -+ { 0x0B64, 0x0B65 }, -+ { 0x0B78, 0x0B81 }, -+ { 0x0B84, 0x0B84 }, -+ { 0x0B8B, 0x0B8D }, -+ { 0x0B91, 0x0B91 }, -+ { 0x0B96, 0x0B98 }, -+ { 0x0B9B, 0x0B9B }, -+ { 0x0B9D, 0x0B9D }, -+ { 0x0BA0, 0x0BA2 }, -+ { 0x0BA5, 0x0BA7 }, -+ { 0x0BAB, 0x0BAD }, -+ { 0x0BBA, 0x0BBD }, -+ { 0x0BC3, 0x0BC5 }, -+ { 0x0BC9, 0x0BC9 }, -+ { 0x0BCE, 0x0BCF }, -+ { 0x0BD1, 0x0BD6 }, -+ { 0x0BD8, 0x0BE5 }, -+ { 0x0BFB, 0x0C00 }, -+ { 0x0C04, 0x0C04 }, -+ { 0x0C0D, 0x0C0D }, -+ { 0x0C11, 0x0C11 }, -+ { 0x0C29, 0x0C29 }, -+ { 0x0C34, 0x0C34 }, -+ { 0x0C3A, 0x0C3C }, -+ { 0x0C45, 0x0C45 }, -+ { 0x0C49, 0x0C49 }, -+ { 0x0C4E, 0x0C54 }, -+ { 0x0C57, 0x0C57 }, -+ { 0x0C5A, 0x0C5F }, -+ { 0x0C64, 0x0C65 }, -+ { 0x0C70, 0x0C77 }, -+ { 0x0C80, 0x0C81 }, -+ { 0x0C84, 0x0C84 }, -+ { 0x0C8D, 0x0C8D }, -+ { 0x0C91, 0x0C91 }, -+ { 0x0CA9, 0x0CA9 }, -+ { 0x0CB4, 0x0CB4 }, -+ { 0x0CBA, 0x0CBB }, -+ { 0x0CC5, 0x0CC5 }, -+ { 0x0CC9, 0x0CC9 }, -+ { 0x0CCE, 0x0CD4 }, -+ { 0x0CD7, 0x0CDD }, -+ { 0x0CDF, 0x0CDF }, -+ { 0x0CE4, 0x0CE5 }, -+ { 0x0CF0, 0x0CF0 }, -+ { 0x0CF3, 0x0D01 }, -+ { 0x0D04, 0x0D04 }, -+ { 0x0D0D, 0x0D0D }, -+ { 0x0D11, 0x0D11 }, -+ { 0x0D3B, 0x0D3C }, -+ { 0x0D45, 0x0D45 }, -+ { 0x0D49, 0x0D49 }, -+ { 0x0D4F, 0x0D56 }, -+ { 0x0D58, 0x0D5F }, -+ { 0x0D64, 0x0D65 }, -+ { 0x0D76, 0x0D78 }, -+ { 0x0D80, 0x0D81 }, -+ { 0x0D84, 0x0D84 }, -+ { 0x0D97, 0x0D99 }, -+ { 0x0DB2, 0x0DB2 }, -+ { 0x0DBC, 0x0DBC }, -+ { 0x0DBE, 0x0DBF }, -+ { 0x0DC7, 0x0DC9 }, -+ { 0x0DCB, 0x0DCE }, -+ { 0x0DD5, 0x0DD5 }, -+ { 0x0DD7, 0x0DD7 }, -+ { 0x0DE0, 0x0DF1 }, -+ { 0x0DF5, 0x0E00 }, -+ { 0x0E3B, 0x0E3E }, -+ { 0x0E5C, 0x0E80 }, -+ { 0x0E83, 0x0E83 }, -+ { 0x0E85, 0x0E86 }, -+ { 0x0E89, 0x0E89 }, -+ { 0x0E8B, 0x0E8C }, -+ { 0x0E8E, 0x0E93 }, -+ { 0x0E98, 0x0E98 }, -+ { 0x0EA0, 0x0EA0 }, -+ { 0x0EA4, 0x0EA4 }, -+ { 0x0EA6, 0x0EA6 }, -+ { 0x0EA8, 0x0EA9 }, -+ { 0x0EAC, 0x0EAC }, -+ { 0x0EBA, 0x0EBA }, -+ { 0x0EBE, 0x0EBF }, -+ { 0x0EC5, 0x0EC5 }, -+ { 0x0EC7, 0x0EC7 }, -+ { 0x0ECE, 0x0ECF }, -+ { 0x0EDA, 0x0EDB }, -+ { 0x0EE0, 0x0EFF }, -+ { 0x0F48, 0x0F48 }, -+ { 0x0F6D, 0x0F70 }, -+ { 0x0F98, 0x0F98 }, -+ { 0x0FBD, 0x0FBD }, -+ { 0x0FCD, 0x0FCD }, -+ { 0x0FDB, 0x0FFF }, -+ { 0x10C6, 0x10C6 }, -+ { 0x10C8, 0x10CC }, -+ { 0x10CE, 0x10CF }, -+ { 0x1249, 0x1249 }, -+ { 0x124E, 0x124F }, -+ { 0x1257, 0x1257 }, -+ { 0x1259, 0x1259 }, -+ { 0x125E, 0x125F }, -+ { 0x1289, 0x1289 }, -+ { 0x128E, 0x128F }, -+ { 0x12B1, 0x12B1 }, -+ { 0x12B6, 0x12B7 }, -+ { 0x12BF, 0x12BF }, -+ { 0x12C1, 0x12C1 }, -+ { 0x12C6, 0x12C7 }, -+ { 0x12D7, 0x12D7 }, -+ { 0x1311, 0x1311 }, -+ { 0x1316, 0x1317 }, -+ { 0x135B, 0x135C }, -+ { 0x137D, 0x137F }, -+ { 0x139A, 0x139F }, -+ { 0x13F5, 0x13FF }, -+ { 0x169D, 0x169F }, -+ { 0x16F1, 0x16FF }, -+ { 0x170D, 0x170D }, -+ { 0x1715, 0x171F }, -+ { 0x1737, 0x173F }, -+ { 0x1754, 0x175F }, -+ { 0x176D, 0x176D }, -+ { 0x1771, 0x1771 }, -+ { 0x1774, 0x177F }, -+ { 0x17DE, 0x17DF }, -+ { 0x17EA, 0x17EF }, -+ { 0x17FA, 0x17FF }, -+ { 0x180F, 0x180F }, -+ { 0x181A, 0x181F }, -+ { 0x1878, 0x187F }, -+ { 0x18AB, 0x18AF }, -+ { 0x18F6, 0x18FF }, -+ { 0x191D, 0x191F }, -+ { 0x192C, 0x192F }, -+ { 0x193C, 0x193F }, -+ { 0x1941, 0x1943 }, -+ { 0x196E, 0x196F }, -+ { 0x1975, 0x197F }, -+ { 0x19AC, 0x19AF }, -+ { 0x19CA, 0x19CF }, -+ { 0x19DB, 0x19DD }, -+ { 0x1A1C, 0x1A1D }, -+ { 0x1A5F, 0x1A5F }, -+ { 0x1A7D, 0x1A7E }, -+ { 0x1A8A, 0x1A8F }, -+ { 0x1A9A, 0x1A9F }, -+ { 0x1AAE, 0x1AFF }, -+ { 0x1B4C, 0x1B4F }, -+ { 0x1B7D, 0x1B7F }, -+ { 0x1BF4, 0x1BFB }, -+ { 0x1C38, 0x1C3A }, -+ { 0x1C4A, 0x1C4C }, -+ { 0x1C80, 0x1CBF }, -+ { 0x1CC8, 0x1CCF }, -+ { 0x1CF7, 0x1CFF }, -+ { 0x1DE7, 0x1DFB }, -+ { 0x1F16, 0x1F17 }, -+ { 0x1F1E, 0x1F1F }, -+ { 0x1F46, 0x1F47 }, -+ { 0x1F4E, 0x1F4F }, -+ { 0x1F58, 0x1F58 }, -+ { 0x1F5A, 0x1F5A }, -+ { 0x1F5C, 0x1F5C }, -+ { 0x1F5E, 0x1F5E }, -+ { 0x1F7E, 0x1F7F }, -+ { 0x1FB5, 0x1FB5 }, -+ { 0x1FC5, 0x1FC5 }, -+ { 0x1FD4, 0x1FD5 }, -+ { 0x1FDC, 0x1FDC }, -+ { 0x1FF0, 0x1FF1 }, -+ { 0x1FF5, 0x1FF5 }, -+ { 0x1FFF, 0x1FFF }, -+ { 0x2065, 0x2069 }, -+ { 0x2072, 0x2073 }, -+ { 0x208F, 0x208F }, -+ { 0x209D, 0x209F }, -+ { 0x20BB, 0x20CF }, -+ { 0x20F1, 0x20FF }, -+ { 0x218A, 0x218F }, -+ { 0x23F4, 0x23FF }, -+ { 0x2427, 0x243F }, -+ { 0x244B, 0x245F }, -+ { 0x2700, 0x2700 }, -+ { 0x2B4D, 0x2B4F }, -+ { 0x2B5A, 0x2BFF }, -+ { 0x2C2F, 0x2C2F }, -+ { 0x2C5F, 0x2C5F }, -+ { 0x2CF4, 0x2CF8 }, -+ { 0x2D26, 0x2D26 }, -+ { 0x2D28, 0x2D2C }, -+ { 0x2D2E, 0x2D2F }, -+ { 0x2D68, 0x2D6E }, -+ { 0x2D71, 0x2D7E }, -+ { 0x2D97, 0x2D9F }, -+ { 0x2DA7, 0x2DA7 }, -+ { 0x2DAF, 0x2DAF }, -+ { 0x2DB7, 0x2DB7 }, -+ { 0x2DBF, 0x2DBF }, -+ { 0x2DC7, 0x2DC7 }, -+ { 0x2DCF, 0x2DCF }, -+ { 0x2DD7, 0x2DD7 }, -+ { 0x2DDF, 0x2DDF }, -+ { 0x2E3C, 0x2E7F }, -+ { 0x2E9A, 0x2E9A }, -+ { 0x2EF4, 0x2EFF }, -+ { 0x2FD6, 0x2FEF }, -+ { 0x2FFC, 0x2FFF }, -+ { 0x3040, 0x3040 }, -+ { 0x3097, 0x3098 }, -+ { 0x3100, 0x3104 }, -+ { 0x312E, 0x3130 }, -+ { 0x318F, 0x318F }, -+ { 0x31BB, 0x31BF }, -+ { 0x31E4, 0x31EF }, -+ { 0x321F, 0x321F }, -+ { 0x32FF, 0x32FF }, -+ { 0x4DB6, 0x4DBF }, -+ { 0x9FA6, 0x9FCB }, -+ { 0x9FCD, 0x9FFF }, -+ { 0xA48D, 0xA48F }, -+ { 0xA4C7, 0xA4CF }, -+ { 0xA62C, 0xA63F }, -+ { 0xA698, 0xA69E }, -+ { 0xA6F8, 0xA6FF }, -+ { 0xA78F, 0xA78F }, -+ { 0xA794, 0xA79F }, -+ { 0xA7AB, 0xA7F7 }, -+ { 0xA82C, 0xA82F }, -+ { 0xA83A, 0xA83F }, -+ { 0xA878, 0xA87F }, -+ { 0xA8C5, 0xA8CD }, -+ { 0xA8DA, 0xA8DF }, -+ { 0xA8FC, 0xA8FF }, -+ { 0xA954, 0xA95E }, -+ { 0xA97D, 0xA97F }, -+ { 0xA9CE, 0xA9CE }, -+ { 0xA9DA, 0xA9DD }, -+ { 0xA9E0, 0xA9FF }, -+ { 0xAA37, 0xAA3F }, -+ { 0xAA4E, 0xAA4F }, -+ { 0xAA5A, 0xAA5B }, -+ { 0xAA7C, 0xAA7F }, -+ { 0xAAC3, 0xAADA }, -+ { 0xAAF7, 0xAB00 }, -+ { 0xAB07, 0xAB08 }, -+ { 0xAB0F, 0xAB10 }, -+ { 0xAB17, 0xAB1F }, -+ { 0xAB27, 0xAB27 }, -+ { 0xAB2F, 0xABBF }, -+ { 0xABEE, 0xABEF }, -+ { 0xABFA, 0xABFF }, -+ { 0xD7A4, 0xD7AF }, -+ { 0xD7C7, 0xD7CA }, -+ { 0xD7FC, 0xD7FF }, -+ { 0xFA6E, 0xFA6F }, -+ { 0xFADA, 0xFAFF }, -+ { 0xFB07, 0xFB12 }, -+ { 0xFB18, 0xFB1C }, -+ { 0xFB37, 0xFB37 }, -+ { 0xFB3D, 0xFB3D }, -+ { 0xFB3F, 0xFB3F }, -+ { 0xFB42, 0xFB42 }, -+ { 0xFB45, 0xFB45 }, -+ { 0xFBC2, 0xFBD2 }, -+ { 0xFD40, 0xFD4F }, -+ { 0xFD90, 0xFD91 }, -+ { 0xFDC8, 0xFDCF }, -+ { 0xFDFE, 0xFDFF }, -+ { 0xFE1A, 0xFE1F }, -+ { 0xFE27, 0xFE2F }, -+ { 0xFE53, 0xFE53 }, -+ { 0xFE67, 0xFE67 }, -+ { 0xFE6C, 0xFE6F }, -+ { 0xFE75, 0xFE75 }, -+ { 0xFEFD, 0xFEFE }, -+ { 0xFF00, 0xFF00 }, -+ { 0xFFBF, 0xFFC1 }, -+ { 0xFFC8, 0xFFC9 }, -+ { 0xFFD0, 0xFFD1 }, -+ { 0xFFD8, 0xFFD9 }, -+ { 0xFFDD, 0xFFDF }, -+ { 0xFFE7, 0xFFE7 }, -+ { 0xFFEF, 0xFFF8 }, -+ { 0x1000C, 0x1000C }, -+ { 0x10027, 0x10027 }, -+ { 0x1003B, 0x1003B }, -+ { 0x1003E, 0x1003E }, -+ { 0x1004E, 0x1004F }, -+ { 0x1005E, 0x1007F }, -+ { 0x100FB, 0x100FF }, -+ { 0x10103, 0x10106 }, -+ { 0x10134, 0x10136 }, -+ { 0x1018B, 0x1018F }, -+ { 0x1019C, 0x101CF }, -+ { 0x101FE, 0x1027F }, -+ { 0x1029D, 0x1029F }, -+ { 0x102D1, 0x102FF }, -+ { 0x1031F, 0x1031F }, -+ { 0x10324, 0x1032F }, -+ { 0x1034B, 0x1037F }, -+ { 0x1039E, 0x1039E }, -+ { 0x103C4, 0x103C7 }, -+ { 0x103D6, 0x103FF }, -+ { 0x1049E, 0x1049F }, -+ { 0x104AA, 0x107FF }, -+ { 0x10806, 0x10807 }, -+ { 0x10809, 0x10809 }, -+ { 0x10836, 0x10836 }, -+ { 0x10839, 0x1083B }, -+ { 0x1083D, 0x1083E }, -+ { 0x10856, 0x10856 }, -+ { 0x10860, 0x108FF }, -+ { 0x1091C, 0x1091E }, -+ { 0x1093A, 0x1093E }, -+ { 0x10940, 0x1097F }, -+ { 0x109B8, 0x109BD }, -+ { 0x109C0, 0x109FF }, -+ { 0x10A04, 0x10A04 }, -+ { 0x10A07, 0x10A0B }, -+ { 0x10A14, 0x10A14 }, -+ { 0x10A18, 0x10A18 }, -+ { 0x10A34, 0x10A37 }, -+ { 0x10A3B, 0x10A3E }, -+ { 0x10A48, 0x10A4F }, -+ { 0x10A59, 0x10A5F }, -+ { 0x10A80, 0x10AFF }, -+ { 0x10B36, 0x10B38 }, -+ { 0x10B56, 0x10B57 }, -+ { 0x10B73, 0x10B77 }, -+ { 0x10B80, 0x10BFF }, -+ { 0x10C49, 0x10E5F }, -+ { 0x10E7F, 0x10FFF }, -+ { 0x1104E, 0x11051 }, -+ { 0x11070, 0x1107F }, -+ { 0x110C2, 0x110CF }, -+ { 0x110E9, 0x110EF }, -+ { 0x110FA, 0x110FF }, -+ { 0x11135, 0x11135 }, -+ { 0x11144, 0x1117F }, -+ { 0x111C9, 0x111CF }, -+ { 0x111DA, 0x1167F }, -+ { 0x116B8, 0x116BF }, -+ { 0x116CA, 0x11FFF }, -+ { 0x1236F, 0x123FF }, -+ { 0x12463, 0x1246F }, -+ { 0x12474, 0x12FFF }, -+ { 0x1342F, 0x167FF }, -+ { 0x16A39, 0x16EFF }, -+ { 0x16F45, 0x16F4F }, -+ { 0x16F7F, 0x16F8E }, -+ { 0x16FA0, 0x1AFFF }, -+ { 0x1B002, 0x1CFFF }, -+ { 0x1D0F6, 0x1D0FF }, -+ { 0x1D127, 0x1D128 }, -+ { 0x1D1DE, 0x1D1FF }, -+ { 0x1D246, 0x1D2FF }, -+ { 0x1D357, 0x1D35F }, -+ { 0x1D372, 0x1D3FF }, -+ { 0x1D455, 0x1D455 }, -+ { 0x1D49D, 0x1D49D }, -+ { 0x1D4A0, 0x1D4A1 }, -+ { 0x1D4A3, 0x1D4A4 }, -+ { 0x1D4A7, 0x1D4A8 }, -+ { 0x1D4AD, 0x1D4AD }, -+ { 0x1D4BA, 0x1D4BA }, -+ { 0x1D4BC, 0x1D4BC }, -+ { 0x1D4C4, 0x1D4C4 }, -+ { 0x1D506, 0x1D506 }, -+ { 0x1D50B, 0x1D50C }, -+ { 0x1D515, 0x1D515 }, -+ { 0x1D51D, 0x1D51D }, -+ { 0x1D53A, 0x1D53A }, -+ { 0x1D53F, 0x1D53F }, -+ { 0x1D545, 0x1D545 }, -+ { 0x1D547, 0x1D549 }, -+ { 0x1D551, 0x1D551 }, -+ { 0x1D6A6, 0x1D6A7 }, -+ { 0x1D7CC, 0x1D7CD }, -+ { 0x1D800, 0x1EDFF }, -+ { 0x1EE04, 0x1EE04 }, -+ { 0x1EE20, 0x1EE20 }, -+ { 0x1EE23, 0x1EE23 }, -+ { 0x1EE25, 0x1EE26 }, -+ { 0x1EE28, 0x1EE28 }, -+ { 0x1EE33, 0x1EE33 }, -+ { 0x1EE38, 0x1EE38 }, -+ { 0x1EE3A, 0x1EE3A }, -+ { 0x1EE3C, 0x1EE41 }, -+ { 0x1EE43, 0x1EE46 }, -+ { 0x1EE48, 0x1EE48 }, -+ { 0x1EE4A, 0x1EE4A }, -+ { 0x1EE4C, 0x1EE4C }, -+ { 0x1EE50, 0x1EE50 }, -+ { 0x1EE53, 0x1EE53 }, -+ { 0x1EE55, 0x1EE56 }, -+ { 0x1EE58, 0x1EE58 }, -+ { 0x1EE5A, 0x1EE5A }, -+ { 0x1EE5C, 0x1EE5C }, -+ { 0x1EE5E, 0x1EE5E }, -+ { 0x1EE60, 0x1EE60 }, -+ { 0x1EE63, 0x1EE63 }, -+ { 0x1EE65, 0x1EE66 }, -+ { 0x1EE6B, 0x1EE6B }, -+ { 0x1EE73, 0x1EE73 }, -+ { 0x1EE78, 0x1EE78 }, -+ { 0x1EE7D, 0x1EE7D }, -+ { 0x1EE7F, 0x1EE7F }, -+ { 0x1EE8A, 0x1EE8A }, -+ { 0x1EE9C, 0x1EEA0 }, -+ { 0x1EEA4, 0x1EEA4 }, -+ { 0x1EEAA, 0x1EEAA }, -+ { 0x1EEBC, 0x1EEEF }, -+ { 0x1EEF2, 0x1EFFF }, -+ { 0x1F02C, 0x1F02F }, -+ { 0x1F094, 0x1F09F }, -+ { 0x1F0AF, 0x1F0B0 }, -+ { 0x1F0BF, 0x1F0C0 }, -+ { 0x1F0D0, 0x1F0D0 }, -+ { 0x1F0E0, 0x1F0FF }, -+ { 0x1F10B, 0x1F10F }, -+ { 0x1F12F, 0x1F12F }, -+ { 0x1F16C, 0x1F16F }, -+ { 0x1F19B, 0x1F1E5 }, -+ { 0x1F203, 0x1F20F }, -+ { 0x1F23B, 0x1F23F }, -+ { 0x1F249, 0x1F24F }, -+ { 0x1F252, 0x1F2FF }, -+ { 0x1F321, 0x1F32F }, -+ { 0x1F336, 0x1F336 }, -+ { 0x1F37D, 0x1F37F }, -+ { 0x1F394, 0x1F39F }, -+ { 0x1F3C5, 0x1F3C5 }, -+ { 0x1F3CB, 0x1F3DF }, -+ { 0x1F3F1, 0x1F3FF }, -+ { 0x1F43F, 0x1F43F }, -+ { 0x1F441, 0x1F441 }, -+ { 0x1F4F8, 0x1F4F8 }, -+ { 0x1F4FD, 0x1F4FF }, -+ { 0x1F53E, 0x1F53F }, -+ { 0x1F544, 0x1F54F }, -+ { 0x1F568, 0x1F5FA }, -+ { 0x1F641, 0x1F644 }, -+ { 0x1F650, 0x1F67F }, -+ { 0x1F6C6, 0x1F6FF }, -+ { 0x1F774, 0x1FFFD }, -+ { 0x2A6D7, 0x2A6FF }, -+ { 0x2A701, 0x2B733 }, -+ { 0x2B735, 0x2B73F }, -+ { 0x2B741, 0x2B81C }, -+ { 0x2B81E, 0x2F7FF }, -+ { 0x2FA1E, 0x2FFFD }, -+ { 0x30000, 0x3FFFD }, -+ { 0x40000, 0x4FFFD }, -+ { 0x50000, 0x5FFFD }, -+ { 0x60000, 0x6FFFD }, -+ { 0x70000, 0x7FFFD }, -+ { 0x80000, 0x8FFFD }, -+ { 0x90000, 0x9FFFD }, -+ { 0xA0000, 0xAFFFD }, -+ { 0xB0000, 0xBFFFD }, -+ { 0xC0000, 0xCFFFD }, -+ { 0xD0000, 0xDFFFD }, -+ { 0xE0000, 0xE0000 }, -+ { 0xE0002, 0xE001F }, -+ { 0xE0080, 0xE00FF }, -+ { 0xE01F0, 0xEFFFD }, -+}; -+ -+/* RFC3454 Table B.1 */ -+static const struct u32_range map_to_nothing[] = { -+ { 0x00AD, 0x00AD }, -+ { 0x034F, 0x034F }, -+ { 0x1806, 0x1806 }, -+ { 0x180B, 0x180D }, -+ { 0x200B, 0x200D }, -+ { 0x2060, 0x2060 }, -+ { 0xFE00, 0xFE0F }, -+ { 0xFEFF, 0xFEFF }, -+}; -+ -+/* Local: allow tab, CR and LF */ -+static const struct u32_range whitelist[] = { -+ { 0x09, 0x09 }, -+ { 0x0a, 0x0a }, -+ { 0x0d, 0x0d }, -+}; -+ -+/* RFC3454 Tables in appendix C */ -+static const struct u32_range prohibited[] = { -+ /* C.2.1 ASCII control characters */ -+ { 0x0000, 0x001F }, -+ { 0x007F, 0x007F }, -+ /* C.2.2 Non-ASCII control characters */ -+ { 0x0080, 0x009F }, -+ { 0x06DD, 0x06DD }, -+ { 0x070F, 0x070F }, -+ { 0x180E, 0x180E }, -+ { 0x200C, 0x200C }, -+ { 0x200D, 0x200D }, -+ { 0x2028, 0x2028 }, -+ { 0x2029, 0x2029 }, -+ { 0x2060, 0x2060 }, -+ { 0x2061, 0x2061 }, -+ { 0x2062, 0x2062 }, -+ { 0x2063, 0x2063 }, -+ { 0x206A, 0x206F }, -+ { 0xFEFF, 0xFEFF }, -+ { 0xFFF9, 0xFFFC }, -+ { 0x1D173, 0x1D17A }, -+ /* C.3 Private use */ -+ { 0xE000, 0xF8FF }, -+ { 0xF0000, 0xFFFFD }, -+ { 0x100000, 0x10FFFD }, -+ /* C.4 Non-character code points */ -+ { 0xFDD0, 0xFDEF }, -+ { 0xFFFE, 0xFFFF }, -+ { 0x1FFFE, 0x1FFFF }, -+ { 0x2FFFE, 0x2FFFF }, -+ { 0x3FFFE, 0x3FFFF }, -+ { 0x4FFFE, 0x4FFFF }, -+ { 0x5FFFE, 0x5FFFF }, -+ { 0x6FFFE, 0x6FFFF }, -+ { 0x7FFFE, 0x7FFFF }, -+ { 0x8FFFE, 0x8FFFF }, -+ { 0x9FFFE, 0x9FFFF }, -+ { 0xAFFFE, 0xAFFFF }, -+ { 0xBFFFE, 0xBFFFF }, -+ { 0xCFFFE, 0xCFFFF }, -+ { 0xDFFFE, 0xDFFFF }, -+ { 0xEFFFE, 0xEFFFF }, -+ { 0xFFFFE, 0xFFFFF }, -+ { 0x10FFFE, 0x10FFFF }, -+ /* C.5 Surrogate codes */ -+ { 0xD800, 0xDFFF }, -+ /* C.6 Inappropriate for plain text */ -+ { 0xFFF9, 0xFFF9 }, -+ { 0xFFFA, 0xFFFA }, -+ { 0xFFFB, 0xFFFB }, -+ { 0xFFFC, 0xFFFC }, -+ { 0xFFFD, 0xFFFD }, -+ /* C.7 Inappropriate for canonical representation */ -+ { 0x2FF0, 0x2FFB }, -+ /* C.8 Change display properties or are deprecated */ -+ { 0x0340, 0x0340 }, -+ { 0x0341, 0x0341 }, -+ { 0x200E, 0x200E }, -+ { 0x200F, 0x200F }, -+ { 0x202A, 0x202A }, -+ { 0x202B, 0x202B }, -+ { 0x202C, 0x202C }, -+ { 0x202D, 0x202D }, -+ { 0x202E, 0x202E }, -+ { 0x206A, 0x206A }, -+ { 0x206B, 0x206B }, -+ { 0x206C, 0x206C }, -+ { 0x206D, 0x206D }, -+ { 0x206E, 0x206E }, -+ { 0x206F, 0x206F }, -+ /* C.9 Tagging characters */ -+ { 0xE0001, 0xE0001 }, -+ { 0xE0020, 0xE007F }, -+}; -+ -diff --git a/utf8_stringprep.c b/utf8_stringprep.c -new file mode 100644 -index 0000000..bcafae7 ---- /dev/null -+++ b/utf8_stringprep.c -@@ -0,0 +1,229 @@ -+/* -+ * Copyright (c) 2013 Damien Miller -+ * -+ * 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. -+ */ -+ -+/* -+ * This is a simple RFC3454 stringprep profile to sanitise UTF-8 strings -+ * from untrusted sources. -+ * -+ * It is intended to be used prior to display of untrusted strings only. -+ * It should not be used for logging because of bi-di ambiguity. It -+ * should also not be used in any case where lack of normalisation may -+ * cause problems. -+ * -+ * This profile uses the prohibition and mapping tables from RFC3454 -+ * (listed below) but the unassigned character table has been updated to -+ * Unicode 6.2. It uses a local whitelist of whitespace characters (\n, -+ * \a and \t). Unicode normalisation and bi-di testing are not used. -+ * -+ * XXX: implement bi-di handling (needed for logs) -+ * XXX: implement KC normalisation (needed for passing to libs/syscalls) -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "misc.h" -+ -+struct u32_range { -+ u_int32_t lo, hi; /* Inclusive */ -+}; -+ -+#include "stringprep-tables.c" -+ -+/* Returns 1 if code 'c' appears in the table or 0 otherwise */ -+static int -+code_in_table(u_int32_t c, const struct u32_range *table, size_t tlen) -+{ -+ const struct u32_range *e, *end = (void *)(tlen + (char *)table); -+ -+ for (e = table; e < end; e++) { -+ if (c >= e->lo && c <= e->hi) -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * Decode the next valid UCS character from a UTF-8 string, skipping past bad -+ * codes. Returns the decoded character or 0 for end-of-string and updates -+ * nextc to point to the start of the next character (if any). -+ * had_error is set if an invalid code was encountered. -+ */ -+static u_int32_t -+decode_utf8(const char *in, const char **nextc, int *had_error) -+{ -+ int state = 0; -+ size_t i; -+ u_int32_t c, e; -+ -+ e = c = 0; -+ for (i = 0; in[i] != '\0'; i++) { -+ e = (u_char)in[i]; -+ /* Invalid code point state */ -+ if (state == -1) { -+ /* -+ * Continue eating continuation characters until -+ * a new start character comes along. -+ */ -+ if ((e & 0xc0) == 0x80) -+ continue; -+ state = 0; -+ } -+ -+ /* New code point state */ -+ if (state == 0) { -+ if ((e & 0x80) == 0) { /* 7 bit code */ -+ c = e & 0x7f; -+ goto have_code; -+ } else if ((e & 0xe0) == 0xc0) { /* 11 bit code point */ -+ state = 1; -+ c = (e & 0x1f) << 6; -+ } else if ((e & 0xf0) == 0xe0) { /* 16 bit code point */ -+ state = 2; -+ c = (e & 0xf) << 12; -+ } else if ((e & 0xf8) == 0xf0) { /* 21 bit code point */ -+ state = 3; -+ c = (e & 0x7) << 18; -+ } else { -+ /* A five or six byte header, or 0xff */ -+ goto bad_encoding; -+ } -+ /* -+ * Check that the header byte has some non-zero data -+ * after masking off the length marker. If not it is -+ * an invalid encoding. -+ */ -+ if (c == 0) { -+ bad_encoding: -+ c = 0; -+ state = -1; -+ if (had_error != NULL) -+ *had_error = 1; -+ } -+ continue; -+ } -+ -+ /* Sanity check: should never happen */ -+ if (state < 1 || state > 5) { -+ *nextc = NULL; -+ if (had_error != NULL) -+ *had_error = 1; -+ return 0; -+ } -+ /* Multibyte code point state */ -+ state--; -+ c |= (e & 0x3f) << (state * 6); -+ if (state > 0) -+ continue; -+ -+ /* RFC3629 bans codepoints > U+10FFFF */ -+ if (c > 0x10FFFF) { -+ if (had_error != NULL) -+ *had_error = 1; -+ continue; -+ } -+ have_code: -+ *nextc = in + i + 1; -+ return c; -+ } -+ if (state != 0 && had_error != NULL) -+ *had_error = 1; -+ *nextc = in + i; -+ return 0; -+} -+ -+/* -+ * Attempt to encode a UCS character as a UTF-8 sequence. Returns the number -+ * of characters used or -1 on error (insufficient space or bad code). -+ */ -+static int -+encode_utf8(u_int32_t c, char *s, size_t slen) -+{ -+ size_t i, need; -+ u_char h; -+ -+ if (c < 0x80) { -+ if (slen >= 1) { -+ s[0] = (char)c; -+ } -+ return 1; -+ } else if (c < 0x800) { -+ need = 2; -+ h = 0xc0; -+ } else if (c < 0x10000) { -+ need = 3; -+ h = 0xe0; -+ } else if (c < 0x200000) { -+ need = 4; -+ h = 0xf0; -+ } else { -+ /* Invalid code point > U+10FFFF */ -+ return -1; -+ } -+ if (need > slen) -+ return -1; -+ for (i = 0; i < need; i++) { -+ s[i] = (i == 0 ? h : 0x80); -+ s[i] |= (c >> (need - i - 1) * 6) & 0x3f; -+ } -+ return need; -+} -+ -+ -+/* -+ * Normalise a UTF-8 string using the RFC3454 stringprep algorithm. -+ * Returns 0 on success or -1 on failure (prohibited code or insufficient -+ * length in the output string. -+ * Requires an output buffer at most the same length as the input. -+ */ -+int -+utf8_stringprep(const char *in, char *out, size_t olen) -+{ -+ int r; -+ size_t o; -+ u_int32_t c; -+ -+ if (olen < 1) -+ return -1; -+ -+ for (o = 0; (c = decode_utf8(in, &in, NULL)) != 0;) { -+ /* Mapping */ -+ if (code_in_table(c, map_to_nothing, sizeof(map_to_nothing))) -+ continue; -+ -+ /* Prohibitied output */ -+ if (code_in_table(c, prohibited, sizeof(prohibited)) && -+ !code_in_table(c, whitelist, sizeof(whitelist))) -+ return -1; -+ -+ /* Map unassigned code points to U+FFFD */ -+ if (code_in_table(c, unassigned, sizeof(unassigned))) -+ c = 0xFFFD; -+ -+ /* Encode the character */ -+ r = encode_utf8(c, out + o, olen - o - 1); -+ if (r < 0) -+ return -1; -+ o += r; -+ } -+ out[o] = '\0'; -+ return 0; -+} -+ diff --git a/SOURCES/openssh-6.6p1-AuthenticationMethods.patch b/SOURCES/openssh-6.6p1-AuthenticationMethods.patch deleted file mode 100644 index de7f59d..0000000 --- a/SOURCES/openssh-6.6p1-AuthenticationMethods.patch +++ /dev/null @@ -1,110 +0,0 @@ -diff -up openssh-6.6p1/servconf.c.auth_meth openssh-6.6p1/servconf.c ---- openssh-6.6p1/servconf.c.auth_meth 2016-06-24 13:39:30.022263557 +0200 -+++ openssh-6.6p1/servconf.c 2016-06-24 13:48:35.879948274 +0200 -@@ -327,6 +327,14 @@ fill_default_server_options(ServerOption - if (use_privsep == -1) - use_privsep = PRIVSEP_NOSANDBOX; - -+ /* Similar handling for AuthenticationMethods=any */ -+ if (options->num_auth_methods == 1 && -+ strcmp(options->auth_methods[0], "any") == 0) { -+ free(options->auth_methods[0]); -+ options->auth_methods[0] = NULL; -+ options->num_auth_methods = 0; -+ } -+ - #ifndef HAVE_MMAP - if (use_privsep && options->compression == 1) { - error("This platform does not support both privilege " -@@ -1680,22 +1688,42 @@ process_server_config_line(ServerOptions - break; - - case sAuthenticationMethods: -- if (cp == NULL || *cp == '\0') -- fatal("%.200s line %d: Missing argument.", filename, linenum); -- if (*activep && options->num_auth_methods == 0) { -+ if (options->num_auth_methods == 0) { -+ value = 0; /* seen "any" pseudo-method */ -+ value2 = 0; /* sucessfully parsed any method */ - while ((arg = strdelim(&cp)) && *arg != '\0') { - if (options->num_auth_methods >= - MAX_AUTH_METHODS) - fatal("%s line %d: " - "too many authentication methods.", - filename, linenum); -- if (auth2_methods_valid(arg, 0) != 0) -+ if (strcmp(arg, "any") == 0) { -+ if (options->num_auth_methods > 0) { -+ fatal("%s line %d: \"any\" " -+ "must appear alone in " -+ "AuthenticationMethods", -+ filename, linenum); -+ } -+ value = 1; -+ } else if (value) { -+ fatal("%s line %d: \"any\" must appear " -+ "alone in AuthenticationMethods", -+ filename, linenum); -+ } else if (auth2_methods_valid(arg, 0) != 0) { - fatal("%s line %d: invalid " - "authentication method list.", - filename, linenum); -+ } -+ value2 = 1; -+ if (!*activep) -+ continue; - options->auth_methods[ - options->num_auth_methods++] = xstrdup(arg); - } -+ if (value2 == 0) { -+ fatal("%s line %d: no AuthenticationMethods " -+ "specified", filename, linenum); -+ } - } - return 0; - -@@ -2195,11 +2221,13 @@ dump_cfg_strarray_oneline(ServerOpCodes code, u_int count, char **vals) - { - u_int i; - -- if (count <= 0) -+ if (count <= 0 && code != sAuthenticationMethods) - return; - printf("%s", lookup_opcode_name(code)); - for (i = 0; i < count; i++) - printf(" %s", vals[i]); -+ if (code == sAuthenticationMethods && count == 0) -+ printf(" any"); - printf("\n"); - } - -diff -up openssh-6.6p1/sshd_config.5.auth_meth openssh-6.6p1/sshd_config.5 ---- openssh-6.6p1/sshd_config.5.auth_meth 2016-06-24 13:39:30.007263566 +0200 -+++ openssh-6.6p1/sshd_config.5 2016-06-24 13:39:30.021263557 +0200 -@@ -172,9 +172,12 @@ for more information on patterns. - Specifies the authentication methods that must be successfully completed - for a user to be granted access. - This option must be followed by one or more comma-separated lists of --authentication method names. --Successful authentication requires completion of every method in at least --one of these lists. -+authentication method names, or by the single string -+.Dq any -+to indicate the default behaviour of accepting any single authentication -+method. -+if the default is overridden, then successful authentication requires -+completion of every method in at least one of these lists. - .Pp - For example, an argument of - .Dq publickey,password publickey,keyboard-interactive -@@ -202,7 +205,9 @@ This option is only available for SSH pr - error if enabled if protocol 1 is also enabled. - Note that each authentication method listed should also be explicitly enabled - in the configuration. --The default is not to require multiple authentication; successful completion -+The default -+.Dq any -+is not to require multiple authentication; successful completion - of a single authentication method is sufficient. - .It Cm AuthorizedKeysCommand - Specifies a program to be used to look up the user's public keys. diff --git a/SOURCES/openssh-6.6p1-CVE-2014-2653.patch b/SOURCES/openssh-6.6p1-CVE-2014-2653.patch deleted file mode 100644 index c3bd0a1..0000000 --- a/SOURCES/openssh-6.6p1-CVE-2014-2653.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/ChangeLog b/ChangeLog -index 38de846..1603a07 100644 ---- a/ChangeLog -+++ b/ChangeLog -@@ -1,3 +1,14 @@ -+20140420 -+ - djm@cvs.openbsd.org 2014/04/01 03:34:10 -+ [sshconnect.c] -+ When using VerifyHostKeyDNS with a DNSSEC resolver, down-convert any -+ certificate keys to plain keys and attempt SSHFP resolution. -+ -+ Prevents a server from skipping SSHFP lookup and forcing a new-hostkey -+ dialog by offering only certificate keys. -+ -+ Reported by mcv21 AT cam.ac.uk -+ - 20140313 - - (djm) Release OpenSSH 6.6 - -diff --git a/sshconnect.c b/sshconnect.c -index 394cca8..e636f33 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -1219,30 +1219,40 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) - { - int flags = 0; - char *fp; -+ Key *plain = NULL; - - fp = key_selected_fingerprint(host_key, SSH_FP_HEX); - debug("Server host key: %s %s%s", key_type(host_key), - key_fingerprint_prefix(), fp); - free(fp); - -- /* XXX certs are not yet supported for DNS */ -- if (!key_is_cert(host_key) && options.verify_host_key_dns && -- verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { -- if (flags & DNS_VERIFY_FOUND) { -- -- if (options.verify_host_key_dns == 1 && -- flags & DNS_VERIFY_MATCH && -- flags & DNS_VERIFY_SECURE) -- return 0; -- -- if (flags & DNS_VERIFY_MATCH) { -- matching_host_key_dns = 1; -- } else { -- warn_changed_key(host_key); -- error("Update the SSHFP RR in DNS with the new " -- "host key to get rid of this message."); -+ if (options.verify_host_key_dns) { -+ /* -+ * XXX certs are not yet supported for DNS, so downgrade -+ * them and try the plain key. -+ */ -+ plain = key_from_private(host_key); -+ if (key_is_cert(plain)) -+ key_drop_cert(plain); -+ if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { -+ if (flags & DNS_VERIFY_FOUND) { -+ if (options.verify_host_key_dns == 1 && -+ flags & DNS_VERIFY_MATCH && -+ flags & DNS_VERIFY_SECURE) { -+ key_free(plain); -+ return 0; -+ } -+ if (flags & DNS_VERIFY_MATCH) { -+ matching_host_key_dns = 1; -+ } else { -+ warn_changed_key(plain); -+ error("Update the SSHFP RR in DNS " -+ "with the new host key to get rid " -+ "of this message."); -+ } - } - } -+ key_free(plain); - } - - return check_host_key(host, hostaddr, options.port, host_key, RDRW, diff --git a/SOURCES/openssh-6.6p1-CVE-2015-8325.patch b/SOURCES/openssh-6.6p1-CVE-2015-8325.patch deleted file mode 100644 index 4224051..0000000 --- a/SOURCES/openssh-6.6p1-CVE-2015-8325.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 85bdcd7c92fe7ff133bbc4e10a65c91810f88755 Mon Sep 17 00:00:00 2001 -From: Damien Miller -Date: Wed, 13 Apr 2016 10:39:57 +1000 -Subject: ignore PAM environment vars when UseLogin=yes - -If PAM is configured to read user-specified environment variables -and UseLogin=yes in sshd_config, then a hostile local user may -attack /bin/login via LD_PRELOAD or similar environment variables -set via PAM. - -CVE-2015-8325, found by Shayan Sadigh, via Colin Watson ---- - session.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/session.c b/session.c -index 4859245..4653b09 100644 ---- a/session.c -+++ b/session.c -@@ -1322,7 +1322,7 @@ do_setup_env(Session *s, const char *shell) - * Pull in any environment variables that may have - * been set by PAM. - */ -- if (options.use_pam) { -+ if (options.use_pam && !options.use_login) { - char **p; - - p = fetch_pam_child_environment(); --- -cgit v0.11.2 - - diff --git a/SOURCES/openssh-6.6p1-CVE-2016-3115.patch b/SOURCES/openssh-6.6p1-CVE-2016-3115.patch deleted file mode 100644 index ed6d264..0000000 --- a/SOURCES/openssh-6.6p1-CVE-2016-3115.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/session.c b/session.c -index 9a75c62..4859245 100644 ---- a/session.c -+++ b/session.c -@@ -46,6 +46,7 @@ - - #include - -+#include - #include - #include - #include -@@ -292,6 +293,21 @@ do_authenticated(Authctxt *authctxt) - do_cleanup(authctxt); - } - -+/* Check untrusted xauth strings for metacharacters */ -+static int -+xauth_valid_string(const char *s) -+{ -+ size_t i; -+ -+ for (i = 0; s[i] != '\0'; i++) { -+ if (!isalnum((u_char)s[i]) && -+ s[i] != '.' && s[i] != ':' && s[i] != '/' && -+ s[i] != '-' && s[i] != '_') -+ return 0; -+ } -+ return 1; -+} -+ - /* - * Prepares for an interactive session. This is called after the user has - * been successfully authenticated. During this message exchange, pseudo -@@ -365,7 +381,13 @@ do_authenticated1(Authctxt *authctxt) - s->screen = 0; - } - packet_check_eom(); -- success = session_setup_x11fwd(s); -+ if (xauth_valid_string(s->auth_proto) && -+ xauth_valid_string(s->auth_data)) -+ success = session_setup_x11fwd(s); -+ else { -+ success = 0; -+ error("Invalid X11 forwarding data"); -+ } - if (!success) { - free(s->auth_proto); - free(s->auth_data); -@@ -2219,7 +2241,13 @@ session_x11_req(Session *s) - s->screen = packet_get_int(); - packet_check_eom(); - -- success = session_setup_x11fwd(s); -+ if (xauth_valid_string(s->auth_proto) && -+ xauth_valid_string(s->auth_data)) -+ success = session_setup_x11fwd(s); -+ else { -+ success = 0; -+ error("Invalid X11 forwarding data"); -+ } - if (!success) { - free(s->auth_proto); - free(s->auth_data); diff --git a/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch b/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch deleted file mode 100644 index 1cffa1b..0000000 --- a/SOURCES/openssh-6.6p1-ControlPersist-stderr.patch +++ /dev/null @@ -1,53 +0,0 @@ -From d2d6bf864e52af8491a60dd507f85b74361f5da3 Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Fri, 29 Apr 2016 08:07:53 +0000 -Subject: [PATCH] upstream commit - -close ControlPersist background process stderr when not - in debug mode or when logging to a file or syslog. bz#1988 ok dtucker - -Upstream-ID: 4fb726f0fdcb155ad419913cea10dc4afd409d24 ---- - log.c | 4 ++-- - ssh.c | 8 +++++--- - 2 files changed, 7 insertions(+), 5 deletions(-) - -diff --git a/log.c b/log.c -index ad12930..277afda 100644 ---- a/log.c -+++ b/log.c -@@ -342,7 +342,7 @@ log_change_level(LogLevel new_log_level) - int - log_is_on_stderr(void) - { -- return log_on_stderr; -+ return log_on_stderr && log_stderr_fd == STDERR_FILENO; - } - - /* redirect what would usually get written to stderr to specified file */ -diff --git a/ssh.c b/ssh.c -index a999d50..a881ba1 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1395,7 +1395,7 @@ static void - control_persist_detach(void) - { - pid_t pid; -- int devnull; -+ int devnull, keep_stderr; - - debug("%s: backgrounding master process", __func__); - -@@ -1426,8 +1426,10 @@ control_persist_detach(void) - error("%s: open(\"/dev/null\"): %s", __func__, - strerror(errno)); - } else { -+ keep_stderr = log_is_on_stderr() && debug_flag; - if (dup2(devnull, STDIN_FILENO) == -1 || -- dup2(devnull, STDOUT_FILENO) == -1) -+ dup2(devnull, STDOUT_FILENO) == -1 || -+ (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1)) - error("%s: dup2: %s", __func__, strerror(errno)); - if (devnull > STDERR_FILENO) - close(devnull); - diff --git a/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch b/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch index a60d608..a48aabb 100644 --- a/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -1,8 +1,7 @@ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 0a4930e..a7c0c5f 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -260,7 +260,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-serv-krb5.c +--- openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users 2017-02-09 10:10:47.403859893 +0100 ++++ openssh-7.4p1/gss-serv-krb5.c 2017-02-09 10:10:47.414859882 +0100 +@@ -260,7 +260,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri FILE *fp; char file[MAXPATHLEN]; char line[BUFSIZ]; @@ -10,7 +9,7 @@ index 0a4930e..a7c0c5f 100644 struct stat st; struct passwd *pw = the_authctxt->pw; int found_principal = 0; -@@ -269,7 +268,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +@@ -269,7 +268,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); /* If both .k5login and .k5users DNE, self-login is ok. */ @@ -19,37 +18,36 @@ index 0a4930e..a7c0c5f 100644 return ssh_krb5_kuserok(krb_context, principal, luser, k5login_exists); } -diff --git a/servconf.c b/servconf.c -index d482e79..ad5869b 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -158,6 +158,7 @@ initialize_server_options(ServerOptions *options) +diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.GSSAPIEnablek5users 2017-02-09 10:10:47.404859892 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 10:18:45.800385543 +0100 +@@ -166,6 +166,7 @@ initialize_server_options(ServerOptions options->ip_qos_bulk = -1; options->version_addendum = NULL; options->use_kuserok = -1; + options->enable_k5users = -1; + options->fingerprint_hash = -1; + options->disable_forwarding = -1; } - - void -@@ -315,6 +316,8 @@ fill_default_server_options(ServerOptions *options) +@@ -337,6 +338,8 @@ fill_default_server_options(ServerOption options->show_patchlevel = 0; if (options->use_kuserok == -1) options->use_kuserok = 1; + if (options->enable_k5users == -1) + options->enable_k5users = 0; - - /* Turn privilege separation on by default */ - if (use_privsep == -1) -@@ -356,7 +359,7 @@ typedef enum { - sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, + if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) + options->fwd_opts.streamlocal_bind_mask = 0177; + if (options->fwd_opts.streamlocal_bind_unlink == -1) +@@ -418,7 +421,7 @@ typedef enum { + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -430,6 +433,7 @@ static struct { +@@ -497,12 +500,14 @@ static struct { { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, @@ -57,7 +55,6 @@ index d482e79..ad5869b 100644 #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -@@ -437,6 +441,7 @@ static struct { { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, @@ -65,7 +62,7 @@ index d482e79..ad5869b 100644 #endif { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, -@@ -1536,6 +1541,10 @@ process_server_config_line(ServerOptions *options, char *line, +@@ -1653,6 +1658,10 @@ process_server_config_line(ServerOptions intptr = &options->use_kuserok; goto parse_flag; @@ -76,7 +73,7 @@ index d482e79..ad5869b 100644 case sPermitOpen: arg = strdelim(&cp); if (!arg || *arg == '\0') -@@ -1824,6 +1833,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) +@@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); M_CP_INTOPT(use_kuserok); @@ -84,19 +81,18 @@ index d482e79..ad5869b 100644 M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); -@@ -2076,6 +2086,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); +@@ -2319,6 +2329,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); + dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); /* string arguments */ - dump_cfg_string(sPidFile, o->pid_file); -diff --git a/servconf.h b/servconf.h -index 5117dfa..d63cb71 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -173,7 +173,8 @@ typedef struct { +diff -up openssh-7.4p1/servconf.h.GSSAPIEnablek5users openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.GSSAPIEnablek5users 2017-02-09 10:10:47.404859892 +0100 ++++ openssh-7.4p1/servconf.h 2017-02-09 10:10:47.415859881 +0100 +@@ -174,7 +174,8 @@ typedef struct { int num_permitted_opens; @@ -106,32 +102,30 @@ index 5117dfa..d63cb71 100644 char *chroot_directory; char *revoked_keys_file; char *trusted_user_ca_keys; -diff --git a/sshd_config b/sshd_config -index 43671f6..6ab00ed 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -94,6 +94,7 @@ GSSAPIAuthentication yes - GSSAPICleanupCredentials no - #GSSAPIStrictAcceptorCheck yes - #GSSAPIKeyExchange no -+#GSSAPIEnablek5users no - - # Set this to 'yes' to enable PAM authentication, account processing, - # and session processing. If this is enabled, PAM authentication will -diff --git a/sshd_config.5 b/sshd_config.5 -index e0e5fff..aa9525d 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -505,6 +505,12 @@ on logout. +diff -up openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users 2017-02-09 10:10:47.415859881 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-09 10:19:29.420336796 +0100 +@@ -633,6 +633,12 @@ Specifies whether key exchange based on + doesn't rely on ssh keys to verify host identity. The default is - .Dq yes . - Note that this option applies to protocol version 2 only. + .Dq no . +.It Cm GSSAPIEnablek5users +Specifies whether to look at .k5users file for GSSAPI authentication +access control. Further details are described in +.Xr ksu 1 . +The default is -+.Dq no . ++.Cm no . .It Cm GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI acceptor - a client authenticates against. If + Determines whether to be strict about the identity of the GSSAPI acceptor + a client authenticates against. +diff -up openssh-7.4p1/sshd_config.GSSAPIEnablek5users openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.GSSAPIEnablek5users 2017-02-09 10:10:47.404859892 +0100 ++++ openssh-7.4p1/sshd_config 2017-02-09 10:10:47.415859881 +0100 +@@ -80,6 +80,7 @@ GSSAPIAuthentication yes + GSSAPICleanupCredentials no + #GSSAPIStrictAcceptorCheck yes + #GSSAPIKeyExchange no ++#GSSAPIEnablek5users no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will diff --git a/SOURCES/openssh-6.6p1-allow-ip-opts.patch b/SOURCES/openssh-6.6p1-allow-ip-opts.patch index e56d8aa..953d613 100644 --- a/SOURCES/openssh-6.6p1-allow-ip-opts.patch +++ b/SOURCES/openssh-6.6p1-allow-ip-opts.patch @@ -1,20 +1,19 @@ -diff --git a/canohost.c b/canohost.c -index a61a8c9..97ce58c 100644 ---- a/canohost.c -+++ b/canohost.c -@@ -165,12 +165,29 @@ check_ip_options(int sock, char *ipaddr) - option_size = sizeof(options); - if (getsockopt(sock, ipproto, IP_OPTIONS, options, +diff -up openssh/sshd.c.ip-opts openssh/sshd.c +--- openssh/sshd.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 ++++ openssh/sshd.c 2016-07-25 14:01:28.346469878 +0200 +@@ -1507,12 +1507,29 @@ check_ip_options(struct ssh *ssh) + + if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, &option_size) >= 0 && option_size != 0) { - text[0] = '\0'; - for (i = 0; i < option_size; i++) - snprintf(text + i*3, sizeof(text) - i*3, -- " %2.2x", options[i]); -- fatal("Connection from %.100s with IP options:%.800s", -- ipaddr, text); +- " %2.2x", opts[i]); +- fatal("Connection from %.100s port %d with IP opts: %.800s", +- ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text); + i = 0; + do { -+ switch (options[i]) { ++ switch (opts[i]) { + case 0: + case 1: + ++i; @@ -22,7 +21,7 @@ index a61a8c9..97ce58c 100644 + case 130: + case 133: + case 134: -+ i += options[i + 1]; ++ i += opts[i + 1]; + break; + default: + /* Fail, fatally, if we detect either loose or strict @@ -30,11 +29,11 @@ index a61a8c9..97ce58c 100644 + text[0] = '\0'; + for (i = 0; i < option_size; i++) + snprintf(text + i*3, sizeof(text) - i*3, -+ " %2.2x", options[i]); -+ fatal("Connection from %.100s with IP options:%.800s", -+ ipaddr, text); ++ " %2.2x", opts[i]); ++ fatal("Connection from %.100s port %d with IP options:%.800s", ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), text); + } + } while (i < option_size); } + return; #endif /* IP_OPTIONS */ - } diff --git a/SOURCES/openssh-6.6p1-audit-race-condition.patch b/SOURCES/openssh-6.6p1-audit-race-condition.patch index a33187e..9bbfcb1 100644 --- a/SOURCES/openssh-6.6p1-audit-race-condition.patch +++ b/SOURCES/openssh-6.6p1-audit-race-condition.patch @@ -1,7 +1,7 @@ -diff -up openssh-7.3p1/monitor_wrap.c.audit-race openssh-7.3p1/monitor_wrap.c ---- openssh-7.3p1/monitor_wrap.c.audit-race 2016-12-15 14:27:22.376603747 +0100 -+++ openssh-7.3p1/monitor_wrap.c 2016-12-15 14:27:22.381603742 +0100 -@@ -1256,4 +1256,48 @@ mm_audit_destroy_sensitive_data(const ch +diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c +--- openssh-7.4p1/monitor_wrap.c.audit-race 2017-02-09 14:07:56.870994116 +0100 ++++ openssh-7.4p1/monitor_wrap.c 2017-02-09 14:07:56.874994112 +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); } @@ -50,10 +50,10 @@ diff -up openssh-7.3p1/monitor_wrap.c.audit-race openssh-7.3p1/monitor_wrap.c + pmonitor->m_recvfd = fd; +} #endif /* SSH_AUDIT_EVENTS */ -diff -up openssh-7.3p1/monitor_wrap.h.audit-race openssh-7.3p1/monitor_wrap.h ---- openssh-7.3p1/monitor_wrap.h.audit-race 2016-12-15 14:27:22.376603747 +0100 -+++ openssh-7.3p1/monitor_wrap.h 2016-12-15 14:27:22.381603742 +0100 -@@ -88,6 +88,8 @@ void mm_audit_unsupported_body(int); +diff -up openssh-7.4p1/monitor_wrap.h.audit-race openssh-7.4p1/monitor_wrap.h +--- openssh-7.4p1/monitor_wrap.h.audit-race 2017-02-09 14:07:56.870994116 +0100 ++++ openssh-7.4p1/monitor_wrap.h 2017-02-09 14:07:56.874994112 +0100 +@@ -80,6 +80,8 @@ void mm_audit_unsupported_body(int); void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); void mm_audit_session_key_free_body(int, pid_t, uid_t); void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); @@ -62,10 +62,10 @@ diff -up openssh-7.3p1/monitor_wrap.h.audit-race openssh-7.3p1/monitor_wrap.h #endif struct Session; -diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c ---- openssh-7.3p1/session.c.audit-race 2016-12-15 14:27:22.378603745 +0100 -+++ openssh-7.3p1/session.c 2016-12-15 14:27:22.382603741 +0100 -@@ -164,6 +164,10 @@ static Session *sessions = NULL; +diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.audit-race 2017-02-09 14:07:56.871994115 +0100 ++++ openssh-7.4p1/session.c 2017-02-09 14:09:44.710893783 +0100 +@@ -162,6 +162,10 @@ static Session *sessions = NULL; login_cap_t *lc; #endif @@ -74,10 +74,10 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c +#endif + static int is_child = 0; - + static int in_chroot = 0; static int have_dev_log = 1; -@@ -457,6 +457,8 @@ do_authenticated1(Authctxt *authctxt) - } +@@ -289,6 +293,8 @@ xauth_valid_string(const char *s) + return 1; } +void child_destory_sensitive_data(); @@ -85,7 +85,7 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c #define USE_PIPES 1 /* * This is called to fork and execute a command when we have no tty. This -@@ -588,6 +592,8 @@ do_exec_no_pty(Session *s, const char *c +@@ -424,6 +430,8 @@ do_exec_no_pty(Session *s, const char *c cray_init_job(s->pw); /* set up cray jid and tmpdir */ #endif @@ -94,7 +94,7 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c /* Do processing for the child (exec command etc). */ do_child(s, command); /* NOTREACHED */ -@@ -722,6 +728,9 @@ do_exec_pty(Session *s, const char *comm +@@ -547,6 +555,9 @@ do_exec_pty(Session *s, const char *comm /* Close the extra descriptor for the pseudo tty. */ close(ttyfd); @@ -102,9 +102,9 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c + child_destory_sensitive_data(); + /* record login, etc. similar to login(1) */ - #ifndef HAVE_OSF_SIA - if (!(options.use_login && command == NULL)) { -@@ -903,6 +912,8 @@ do_exec(Session *s, const char *command) + #ifdef _UNICOS + cray_init_job(s->pw); /* set up cray jid and tmpdir */ +@@ -717,6 +728,8 @@ do_exec(Session *s, const char *command) } if (s->command != NULL && s->ptyfd == -1) s->command_handle = PRIVSEP(audit_run_command(s->command)); @@ -113,7 +113,7 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c #endif if (s->ttyfd != -1) ret = do_exec_pty(s, command); -@@ -918,6 +929,20 @@ do_exec(Session *s, const char *command) +@@ -732,6 +745,20 @@ do_exec(Session *s, const char *command) */ buffer_clear(&loginmsg); @@ -134,7 +134,7 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c return ret; } -@@ -1751,6 +1776,33 @@ child_close_fds(void) +@@ -1542,6 +1569,33 @@ child_close_fds(void) endpwent(); } @@ -168,7 +168,7 @@ diff -up openssh-7.3p1/session.c.audit-race openssh-7.3p1/session.c /* * Performs common processing for the child, such as setting up the * environment, closing extra file descriptors, setting the user and group -@@ -1768,12 +1820,6 @@ do_child(Session *s, const char *command +@@ -1558,12 +1612,6 @@ do_child(Session *s, const char *command struct passwd *pw = s->pw; int r = 0; diff --git a/SOURCES/openssh-6.6p1-audit.patch b/SOURCES/openssh-6.6p1-audit.patch deleted file mode 100644 index 66f7438..0000000 --- a/SOURCES/openssh-6.6p1-audit.patch +++ /dev/null @@ -1,2305 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 0f0d39f..9d8c2eb 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -82,7 +82,8 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ - ssh-ed25519.o digest-openssl.o hmac.o utf8_stringprep.o \ -- sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o -+ sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ -+ auditstub.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect1.o sshconnect2.o mux.o \ -diff --git a/audit-bsm.c b/audit-bsm.c -index 6135591..5160869 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -375,10 +375,23 @@ audit_connection_from(const char *host, int port) - #endif - } - --void -+int - audit_run_command(const char *command) - { - /* not implemented */ -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_count_session_open(void) -+{ -+ /* not necessary */ - } - - void -@@ -393,6 +406,12 @@ audit_session_close(struct logininfo *li) - /* not implemented */ - } - -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ /* not implemented */ -+} -+ - void - audit_event(ssh_audit_event_t event) - { -@@ -454,4 +473,40 @@ audit_event(ssh_audit_event_t event) - debug("%s: unhandled event %d", __func__, event); - } - } -+ -+void -+audit_unsupported_body(int what) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ /* not implemented */ -+} -+ -+void -+audit_generate_ephemeral_server_key(const char *fp) -+{ -+ /* not implemented */ -+} - #endif /* BSM */ -diff --git a/audit-linux.c b/audit-linux.c -index b3ee2f4..946f7fa 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -35,13 +35,24 @@ - - #include "log.h" - #include "audit.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+#include "servconf.h" - #include "canohost.h" -+#include "packet.h" -+#include "cipher.h" - -+#define AUDIT_LOG_SIZE 256 -+ -+extern ServerOptions options; -+extern Authctxt *the_authctxt; -+extern u_int utmp_len; - const char* audit_username(void); - --int --linux_audit_record_event(int uid, const char *username, -- const char *hostname, const char *ip, const char *ttyn, int success) -+static void -+linux_audit_user_logxxx(int uid, const char *username, -+ const char *hostname, const char *ip, const char *ttyn, int success, int event) - { - int audit_fd, rc, saved_errno; - -@@ -49,11 +60,11 @@ linux_audit_record_event(int uid, const char *username, - if (audit_fd < 0) { - if (errno == EINVAL || errno == EPROTONOSUPPORT || - errno == EAFNOSUPPORT) -- return 1; /* No audit support in kernel */ -+ return; /* No audit support in kernel */ - else -- return 0; /* Must prevent login */ -+ goto fatal_report; /* Must prevent login */ - } -- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, -+ rc = audit_log_acct_message(audit_fd, event, - NULL, "login", username ? username : "(unknown)", - username == NULL ? uid : -1, hostname, ip, ttyn, success); - saved_errno = errno; -@@ -65,35 +76,150 @@ linux_audit_record_event(int uid, const char *username, - if ((rc == -EPERM) && (geteuid() != 0)) - rc = 0; - errno = saved_errno; -- return (rc >= 0); -+ if (rc < 0) { -+fatal_report: -+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ } - } - -+static void -+linux_audit_user_auth(int uid, const char *username, -+ const char *hostname, const char *ip, const char *ttyn, int success, int event) -+{ -+ int audit_fd, rc, saved_errno; -+ static const char *event_name[] = { -+ "maxtries exceeded", -+ "root denied", -+ "success", -+ "none", -+ "password", -+ "challenge-response", -+ "pubkey", -+ "hostbased", -+ "gssapi", -+ "invalid user", -+ "nologin", -+ "connection closed", -+ "connection abandoned", -+ "unknown" -+ }; -+ -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return; /* No audit support in kernel */ -+ else -+ goto fatal_report; /* Must prevent login */ -+ } -+ -+ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) -+ event = SSH_AUDIT_UNKNOWN; -+ -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, -+ NULL, event_name[event], username ? username : "(unknown)", -+ username == NULL ? uid : -1, hostname, ip, ttyn, success); -+ saved_errno = errno; -+ close(audit_fd); -+ /* -+ * Do not report error if the error is EPERM and sshd is run as non -+ * root user. -+ */ -+ if ((rc == -EPERM) && (geteuid() != 0)) -+ rc = 0; -+ errno = saved_errno; -+ if (rc < 0) { -+fatal_report: -+ fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ } -+} -+ -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, rc, saved_errno; -+ -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return 1; /* No audit support in kernel */ -+ else -+ return 0; /* Must prevent login */ -+ } -+ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", get_remote_port()); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", -+ type, bits, key_fingerprint_prefix(), fp, get_remote_port()); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, get_remote_ipaddr(), NULL, rv); -+out: -+ saved_errno = errno; -+ audit_close(audit_fd); -+ errno = saved_errno; -+ /* do not report error if the error is EPERM and sshd is run as non root user */ -+ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); -+} -+ -+static int user_login_count = 0; -+ - /* Below is the sshd audit API code */ - - void - audit_connection_from(const char *host, int port) - { --} - /* not implemented */ -+} - --void -+int - audit_run_command(const char *command) - { -- /* not implemented */ -+ if (!user_login_count++) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_START); -+ return 0; -+} -+ -+void -+audit_end_command(int handle, const char *command) -+{ -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+} -+ -+void -+audit_count_session_open(void) -+{ -+ user_login_count++; - } - - void - audit_session_open(struct logininfo *li) - { -- if (linux_audit_record_event(li->uid, NULL, li->hostname, -- NULL, li->line, 1) == 0) -- fatal("linux_audit_write_entry failed: %s", strerror(errno)); -+ if (!user_login_count++) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGIN); -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_START); - } - - void - audit_session_close(struct logininfo *li) - { -- /* not implemented */ -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_END); -+ if (user_login_count && !--user_login_count) -+ linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ NULL, li->line, 1, AUDIT_USER_LOGOUT); - } - - void -@@ -101,21 +227,43 @@ audit_event(ssh_audit_event_t event) - { - switch(event) { - case SSH_AUTH_SUCCESS: -- case SSH_CONNECTION_CLOSE: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 1, event); -+ break; -+ - case SSH_NOLOGIN: -- case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_LOGIN_ROOT_DENIED: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - -+ case SSH_LOGIN_EXCEED_MAXTRIES: - case SSH_AUTH_FAIL_NONE: - case SSH_AUTH_FAIL_PASSWD: - case SSH_AUTH_FAIL_KBDINT: - case SSH_AUTH_FAIL_PUBKEY: - case SSH_AUTH_FAIL_HOSTBASED: - case SSH_AUTH_FAIL_GSSAPI: -+ linux_audit_user_auth(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, event); -+ break; -+ -+ case SSH_CONNECTION_CLOSE: -+ if (user_login_count) { -+ while (user_login_count--) -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_END); -+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, get_remote_name_or_ip(utmp_len, options.use_dns), -+ NULL, "ssh", 1, AUDIT_USER_LOGOUT); -+ } -+ break; -+ -+ case SSH_CONNECTION_ABANDON: - case SSH_INVALID_USER: -- linux_audit_record_event(-1, audit_username(), NULL, -- get_remote_ipaddr(), "sshd", 0); -+ linux_audit_user_logxxx(-1, audit_username(), NULL, -+ get_remote_ipaddr(), "ssh", 0, AUDIT_USER_LOGIN); - break; - - default: -@@ -123,4 +271,135 @@ audit_event(ssh_audit_event_t event) - } - } - -+void -+audit_unsupported_body(int what) -+{ -+#ifdef AUDIT_CRYPTO_SESSION -+ char buf[AUDIT_LOG_SIZE]; -+ const static char *name[] = { "cipher", "mac", "comp" }; -+ char *s; -+ int audit_fd; -+ -+ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", -+ name[what], get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), -+ get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) -+ /* no problem, the next instruction will be fatal() */ -+ return; -+ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, get_remote_ipaddr(), NULL, 0); -+ audit_close(audit_fd); -+#endif -+} -+ -+const static char *direction[] = { "from-server", "from-client", "both" }; -+ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+ uid_t uid) -+{ -+#ifdef AUDIT_CRYPTO_SESSION -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ Cipher *cipher = cipher_by_name(enc); -+ char *s; -+ -+ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, -+ (intmax_t)pid, (intmax_t)uid, -+ get_remote_port(), (s = get_local_ipaddr(packet_get_connection_in())), get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno == EINVAL || errno == EPROTONOSUPPORT || -+ errno == EAFNOSUPPORT) -+ return; /* No audit support in kernel */ -+ else -+ fatal("cannot open audit"); /* Must prevent login */ -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, -+ buf, NULL, get_remote_ipaddr(), NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ fatal("cannot write into audit"); /* Must prevent login */ -+#endif -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ char *s; -+ -+ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", -+ direction[ctos], (intmax_t)pid, (intmax_t)uid, -+ get_remote_port(), -+ (s = get_local_ipaddr(packet_get_connection_in())), -+ get_local_port()); -+ free(s); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, get_remote_ipaddr(), NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} -+ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ -+ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", -+ fp, (intmax_t)pid, (intmax_t)uid); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, -+ listening_for_clients() ? NULL : get_remote_ipaddr(), -+ NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} -+ -+void -+audit_generate_ephemeral_server_key(const char *fp) -+{ -+ char buf[AUDIT_LOG_SIZE]; -+ int audit_fd, audit_ok; -+ -+ snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); -+ audit_fd = audit_open(); -+ if (audit_fd < 0) { -+ if (errno != EINVAL && errno != EPROTONOSUPPORT && -+ errno != EAFNOSUPPORT) -+ error("cannot open audit"); -+ return; -+ } -+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, -+ buf, NULL, 0, NULL, 1); -+ audit_close(audit_fd); -+ /* do not abort if the error is EPERM and sshd is run as non root user */ -+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) -+ error("cannot write into audit"); -+} - #endif /* USE_LINUX_AUDIT */ -diff --git a/audit.c b/audit.c -index ced57fa..13c6849 100644 ---- a/audit.c -+++ b/audit.c -@@ -28,6 +28,7 @@ - - #include - #include -+#include - - #ifdef SSH_AUDIT_EVENTS - -@@ -36,6 +37,9 @@ - #include "key.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "xmalloc.h" - - /* - * Care must be taken when using this since it WILL NOT be initialized when -@@ -71,13 +75,10 @@ audit_classify_auth(const char *method) - const char * - audit_username(void) - { -- static const char unknownuser[] = "(unknown user)"; -- static const char invaliduser[] = "(invalid user)"; -+ static const char unknownuser[] = "(unknown)"; - -- if (the_authctxt == NULL || the_authctxt->user == NULL) -+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) - return (unknownuser); -- if (!the_authctxt->valid) -- return (invaliduser); - return (the_authctxt->user); - } - -@@ -111,6 +112,40 @@ audit_event_lookup(ssh_audit_event_t ev) - return(event_lookup[i].name); - } - -+void -+audit_key(int host_user, int *rv, const Key *key) -+{ -+ char *fp; -+ const char *crypto_name; -+ -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ if (key->type == KEY_RSA1) -+ crypto_name = "ssh-rsa1"; -+ else -+ crypto_name = key_ssh_name(key); -+ if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) -+ *rv = 0; -+ free(fp); -+} -+ -+void -+audit_unsupported(int what) -+{ -+ PRIVSEP(audit_unsupported_body(what)); -+} -+ -+void -+audit_kex(int ctos, char *enc, char *mac, char *comp) -+{ -+ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, getpid(), getuid())); -+} -+ -+void -+audit_session_key_free(int ctos) -+{ -+ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); -+} -+ - # ifndef CUSTOM_SSH_AUDIT_EVENTS - /* - * Null implementations of audit functions. -@@ -140,6 +175,17 @@ audit_event(ssh_audit_event_t event) - } - - /* -+ * Called when a child process has called, or will soon call, -+ * audit_session_open. -+ */ -+void -+audit_count_session_open(void) -+{ -+ debug("audit count session open euid %d user %s", geteuid(), -+ audit_username()); -+} -+ -+/* - * Called when a user session is started. Argument is the tty allocated to - * the session, or NULL if no tty was allocated. - * -@@ -174,13 +220,91 @@ audit_session_close(struct logininfo *li) - /* - * This will be called when a user runs a non-interactive command. Note that - * it may be called multiple times for a single connection since SSH2 allows -- * multiple sessions within a single connection. -+ * multiple sessions within a single connection. Returns a "handle" for -+ * audit_end_command. - */ --void -+int - audit_run_command(const char *command) - { - debug("audit run command euid %d user %s command '%.200s'", geteuid(), - audit_username(), command); -+ return 0; -+} -+ -+/* -+ * This will be called when the non-interactive command finishes. Note that -+ * it may be called multiple times for a single connection since SSH2 allows -+ * multiple sessions within a single connection. "handle" should come from -+ * the corresponding audit_run_command. -+ */ -+void -+audit_end_command(int handle, const char *command) -+{ -+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), -+ audit_username(), command); -+} -+ -+/* -+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. -+ * -+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. -+ */ -+int -+audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) -+{ -+ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s%s, result %d", -+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, -+ key_fingerprint_prefix(), fp, rv); -+} -+ -+/* -+ * This will be called when the protocol negotiation fails. -+ */ -+void -+audit_unsupported_body(int what) -+{ -+ debug("audit unsupported protocol euid %d type %d", geteuid(), what); -+} -+ -+/* -+ * This will be called on succesfull protocol negotiation. -+ */ -+void -+audit_kex_body(int ctos, char *enc, char *mac, char *compress, pid_t pid, -+ uid_t uid) -+{ -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, (long)pid, -+ (unsigned)uid); -+} -+ -+/* -+ * This will be called on succesfull session key discard -+ */ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ debug("audit session key discard euid %u direction %d from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on destroy private part of the server key -+ */ -+void -+audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) -+{ -+ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", -+ geteuid(), fp, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on generation of the ephemeral server key -+ */ -+void -+audit_generate_ephemeral_server_key(const char *) -+{ -+ debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); - } - # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ - #endif /* SSH_AUDIT_EVENTS */ -diff --git a/audit.h b/audit.h -index 92ede5b..a2dc3ff 100644 ---- a/audit.h -+++ b/audit.h -@@ -28,6 +28,7 @@ - # define _SSH_AUDIT_H - - #include "loginrec.h" -+#include "key.h" - - enum ssh_audit_event_type { - SSH_LOGIN_EXCEED_MAXTRIES, -@@ -47,11 +48,25 @@ enum ssh_audit_event_type { - }; - typedef enum ssh_audit_event_type ssh_audit_event_t; - -+int listening_for_clients(void); -+ - void audit_connection_from(const char *, int); - void audit_event(ssh_audit_event_t); -+void audit_count_session_open(void); - void audit_session_open(struct logininfo *); - void audit_session_close(struct logininfo *); --void audit_run_command(const char *); -+int audit_run_command(const char *); -+void audit_end_command(int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(int, const char *, unsigned, char *, int); -+void audit_key(int, int *, const Key *); -+void audit_unsupported(int); -+void audit_kex(int, char *, char *, char *); -+void audit_unsupported_body(int); -+void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void audit_session_key_free(int ctos); -+void audit_session_key_free_body(int ctos, pid_t, uid_t); -+void audit_destroy_sensitive_data(const char *, pid_t, uid_t); -+void audit_generate_ephemeral_server_key(const char *); - - #endif /* _SSH_AUDIT_H */ -diff --git a/auditstub.c b/auditstub.c -new file mode 100644 -index 0000000..45817e0 ---- /dev/null -+++ b/auditstub.c -@@ -0,0 +1,50 @@ -+/* $Id: auditstub.c,v 1.1 jfch Exp $ */ -+ -+/* -+ * Copyright 2010 Red Hat, Inc. All rights reserved. -+ * Use is subject to license terms. -+ * -+ * 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. -+ * -+ * Red Hat author: Jan F. Chadima -+ */ -+ -+#include -+ -+void -+audit_unsupported(int n) -+{ -+} -+ -+void -+audit_kex(int ctos, char *enc, char *mac, char *comp) -+{ -+} -+ -+void -+audit_session_key_free(int ctos) -+{ -+} -+ -+void -+audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+} -diff --git a/auth-rsa.c b/auth-rsa.c -index 5dad6c3..f225b0b 100644 ---- a/auth-rsa.c -+++ b/auth-rsa.c -@@ -93,7 +93,10 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) - { - u_char buf[32], mdbuf[16]; - struct ssh_digest_ctx *md; -- int len; -+ int len, rv; -+#ifdef SSH_AUDIT_EVENTS -+ char *fp; -+#endif - - /* don't allow short keys */ - if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -@@ -117,12 +120,18 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) - ssh_digest_free(md); - - /* Verify that the response is the original challenge. */ -- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { -- /* Wrong answer. */ -- return (0); -+ rv = timingsafe_bcmp(response, mdbuf, 16) == 0; -+ -+#ifdef SSH_AUDIT_EVENTS -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { -+ debug("unsuccessful audit"); -+ rv = 0; - } -- /* Correct answer. */ -- return (1); -+ free(fp); -+#endif -+ -+ return rv; - } - - /* -diff --git a/auth.c b/auth.c -index 420a85b..d613f8c 100644 ---- a/auth.c -+++ b/auth.c -@@ -628,9 +628,6 @@ getpwnamallow(const char *user) - record_failed_login(user, - get_canonical_hostname(options.use_dns), "ssh"); - #endif --#ifdef SSH_AUDIT_EVENTS -- audit_event(SSH_INVALID_USER); --#endif /* SSH_AUDIT_EVENTS */ - return (NULL); - } - if (!allowed_user(pw)) -diff --git a/auth.h b/auth.h -index 4605588..f9d191c 100644 ---- a/auth.h -+++ b/auth.h -@@ -186,6 +186,7 @@ void abandon_challenge_response(Authctxt *); - - char *expand_authorized_keys(const char *, struct passwd *pw); - char *authorized_principals_file(struct passwd *); -+int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); - - FILE *auth_openkeyfile(const char *, struct passwd *, int); - FILE *auth_openprincipals(const char *, struct passwd *, int); -@@ -203,6 +204,7 @@ Key *get_hostkey_private_by_type(int); - int get_hostkey_index(Key *); - int ssh1_session_key(BIGNUM *); - void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int); -+int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); - - /* debug messages during authentication */ - void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 95d678e..48aede4 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -137,7 +137,7 @@ userauth_hostbased(Authctxt *authctxt) - /* test for allowed key and correct signature */ - authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) { - authenticated = 1; - authctxt->last_details = pubkey; -@@ -154,6 +154,18 @@ done: - return authenticated; - } - -+int -+hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(0, &rv, key); -+#endif -+ return rv; -+} -+ - /* return 1 if given hostkey is allowed */ - int - hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index cb0f931..6d1c872 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -160,7 +160,7 @@ userauth_pubkey(Authctxt *authctxt) - /* test for correct signature */ - authenticated = 0; - if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && -- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -+ PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), - buffer_len(&b))) == 1) { - authctxt->last_details = pubkey; - authenticated = 1; -@@ -231,6 +231,18 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) - free(extra); - } - -+int -+user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) -+{ -+ int rv; -+ -+ rv = key_verify(key, sig, slen, data, datalen); -+#ifdef SSH_AUDIT_EVENTS -+ audit_key(1, &rv, key); -+#endif -+ return rv; -+} -+ - static int - match_principals_option(const char *principal_list, struct KeyCert *cert) - { -diff --git a/auth2.c b/auth2.c -index 426dcd6..436cd60 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) - } else { - logit("input_userauth_request: invalid user %s", user); - authctxt->pw = fakepw(); --#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(SSH_INVALID_USER)); --#endif - } - #ifdef USE_PAM - if (options.use_pam) -diff --git a/cipher.c b/cipher.c -index 53d9b4f..226e56d 100644 ---- a/cipher.c -+++ b/cipher.c -@@ -57,20 +57,6 @@ extern const EVP_CIPHER *evp_ssh1_bf(void); - extern const EVP_CIPHER *evp_ssh1_3des(void); - extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); - --struct Cipher { -- char *name; -- int number; /* for ssh1 only */ -- u_int block_size; -- u_int key_len; -- u_int iv_len; /* defaults to block_size */ -- u_int auth_len; -- u_int discard_len; -- u_int flags; --#define CFLAG_CBC (1<<0) --#define CFLAG_CHACHAPOLY (1<<1) -- const EVP_CIPHER *(*evptype)(void); --}; -- - static const struct Cipher ciphers[] = { - { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, - { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, -diff --git a/cipher.h b/cipher.h -index 133d2e7..d41758e 100644 ---- a/cipher.h -+++ b/cipher.h -@@ -63,7 +63,20 @@ - typedef struct Cipher Cipher; - typedef struct CipherContext CipherContext; - --struct Cipher; -+struct Cipher { -+ char *name; -+ int number; /* for ssh1 only */ -+ u_int block_size; -+ u_int key_len; -+ u_int iv_len; /* defaults to block_size */ -+ u_int auth_len; -+ u_int discard_len; -+ u_int flags; -+#define CFLAG_CBC (1<<0) -+#define CFLAG_CHACHAPOLY (1<<1) -+ const EVP_CIPHER *(*evptype)(void); -+}; -+ - struct CipherContext { - int plaintext; - int encrypt; -diff --git a/kex.c b/kex.c -index bce2ab8..bc3e53e 100644 ---- a/kex.c -+++ b/kex.c -@@ -50,6 +50,7 @@ - #include "monitor.h" - #include "roaming.h" - #include "digest.h" -+#include "audit.h" - - #ifdef GSSAPI - #include "ssh-gss.h" -@@ -366,9 +367,13 @@ static void - choose_enc(Enc *enc, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(0); -+#endif - fatal("no matching cipher found: client %s server %s", - client, server); -+ } - if ((enc->cipher = cipher_by_name(name)) == NULL) - fatal("matching cipher is not supported: %s", name); - enc->name = name; -@@ -384,9 +389,13 @@ static void - choose_mac(Mac *mac, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(1); -+#endif - fatal("no matching mac found: client %s server %s", - client, server); -+ } - if (mac_setup(mac, name) < 0) - fatal("unsupported mac %s", name); - /* truncate the key */ -@@ -401,8 +410,12 @@ static void - choose_comp(Comp *comp, char *client, char *server) - { - char *name = match_list(client, server, NULL); -- if (name == NULL) -+ if (name == NULL) { -+#ifdef SSH_AUDIT_EVENTS -+ audit_unsupported(2); -+#endif - fatal("no matching comp found: client %s server %s", client, server); -+ } - if (strcmp(name, "zlib@openssh.com") == 0) { - comp->type = COMP_DELAYED; - } else if (strcmp(name, "zlib") == 0) { -@@ -517,6 +530,9 @@ kex_choose_conf(Kex *kex) - newkeys->enc.name, - authlen == 0 ? newkeys->mac.name : "", - newkeys->comp.name); -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(ctos, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name); -+#endif - } - choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); - choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], -@@ -702,3 +718,53 @@ dump_digest(char *msg, u_char *digest, int len) - fprintf(stderr, "\n"); - } - #endif -+ -+static void -+enc_destroy(Enc *enc) -+{ -+ if (enc == NULL) -+ return; -+ -+ if (enc->key) { -+ memset(enc->key, 0, enc->key_len); -+ free(enc->key); -+ } -+ -+ if (enc->iv) { -+ memset(enc->iv, 0, enc->block_size); -+ free(enc->iv); -+ } -+ -+ memset(enc, 0, sizeof(*enc)); -+} -+ -+void -+newkeys_destroy(Newkeys *newkeys) -+{ -+ if (newkeys == NULL) -+ return; -+ -+ free(newkeys->enc.name); -+ enc_destroy(&newkeys->enc); -+ -+ if (newkeys->mac.enabled) { -+ mac_clear(&newkeys->mac); -+ free(newkeys->mac.name); -+ mac_destroy(&newkeys->mac); -+ } -+ -+ free(newkeys->comp.name); -+ -+ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); -+} -+ -+void -+newkeys_destroy_and_free(Newkeys *newkeys) -+{ -+ if (newkeys == NULL) -+ return; -+ -+ newkeys_destroy(newkeys); -+ free(newkeys); -+} -+ -diff --git a/kex.h b/kex.h -index 313bb51..c643250 100644 ---- a/kex.h -+++ b/kex.h -@@ -182,6 +182,9 @@ void kexgss_client(Kex *); - void kexgss_server(Kex *); - #endif - -+void newkeys_destroy(Newkeys *newkeys); -+void newkeys_destroy_and_free(Newkeys *newkeys); -+ - void - kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, - BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); -diff --git a/key.c b/key.c -index 900b9e3..62f3edb 100644 ---- a/key.c -+++ b/key.c -@@ -1925,6 +1925,33 @@ key_demote(const Key *k) - } - - int -+key_is_private(const Key *k) -+{ -+ switch (k->type) { -+ case KEY_RSA_CERT_V00: -+ case KEY_RSA_CERT: -+ case KEY_RSA1: -+ case KEY_RSA: -+ return k->rsa->d != NULL; -+ case KEY_DSA_CERT_V00: -+ case KEY_DSA_CERT: -+ case KEY_DSA: -+ return k->dsa->priv_key != NULL; -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ fatal("key_is_private: bad key type %d", k->type); -+ return 1; -+ } -+} -+ -+int - key_is_cert(const Key *k) - { - if (k == NULL) -diff --git a/key.h b/key.h -index d51ed81..8f61605 100644 ---- a/key.h -+++ b/key.h -@@ -118,6 +118,7 @@ Key *key_generate(int, u_int); - Key *key_from_private(const Key *); - int key_type_from_name(char *); - int key_is_cert(const Key *); -+int key_is_private(const Key *k); - int key_type_is_cert(int); - int key_type_plain(int); - int key_to_certified(Key *, int); -diff --git a/mac.c b/mac.c -index 0977572..9388af4 100644 ---- a/mac.c -+++ b/mac.c -@@ -222,6 +222,20 @@ mac_clear(Mac *mac) - mac->umac_ctx = NULL; - } - -+void -+mac_destroy(Mac *mac) -+{ -+ if (mac == NULL) -+ return; -+ -+ if (mac->key) { -+ memset(mac->key, 0, mac->key_len); -+ free(mac->key); -+ } -+ -+ memset(mac, 0, sizeof(*mac)); -+} -+ - /* XXX copied from ciphers_valid */ - #define MAC_SEP "," - int -diff --git a/mac.h b/mac.h -index fbe18c4..7dc7f43 100644 ---- a/mac.h -+++ b/mac.h -@@ -29,3 +29,4 @@ int mac_setup(Mac *, char *); - int mac_init(Mac *); - u_char *mac_compute(Mac *, u_int32_t, u_char *, int); - void mac_clear(Mac *); -+void mac_destroy(Mac *); -diff --git a/monitor.c b/monitor.c -index 8b18086..5a65114 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -97,6 +97,7 @@ - #include "ssh2.h" - #include "roaming.h" - #include "authfd.h" -+#include "audit.h" - - #ifdef GSSAPI - static Gssctxt *gsscontext = NULL; -@@ -113,6 +114,8 @@ extern Buffer auth_debug; - extern int auth_debug_init; - extern Buffer loginmsg; - -+extern void destroy_sensitive_data(int); -+ - /* State exported from the child */ - - struct { -@@ -185,6 +188,11 @@ int mm_answer_gss_updatecreds(int, Buffer *); - #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 *); - #endif - - static int monitor_read_log(struct monitor *); -@@ -239,6 +247,10 @@ struct mon_table mon_dispatch_proto20[] = { - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - #ifdef BSD_AUTH - {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -274,6 +286,11 @@ struct mon_table mon_dispatch_postauth20[] = { - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -305,6 +322,10 @@ struct mon_table mon_dispatch_proto15[] = { - #endif - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -316,6 +337,11 @@ struct mon_table mon_dispatch_postauth15[] = { - #ifdef SSH_AUDIT_EVENTS - {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, - {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT|MON_ONCE, mm_answer_audit_command}, -+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, -+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, -+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, -+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, -+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, - #endif - {0, 0, NULL} - }; -@@ -1393,9 +1419,11 @@ mm_answer_keyverify(int sock, Buffer *m) - Key *key; - u_char *signature, *data, *blob; - u_int signaturelen, datalen, bloblen; -+ int type = 0; - int verified = 0; - int valid_data = 0; - -+ type = buffer_get_int(m); - blob = buffer_get_string(m, &bloblen); - signature = buffer_get_string(m, &signaturelen); - data = buffer_get_string(m, &datalen); -@@ -1403,6 +1431,8 @@ mm_answer_keyverify(int sock, Buffer *m) - if (hostbased_cuser == NULL || hostbased_chost == NULL || - !monitor_allowed_key(blob, bloblen)) - fatal("%s: bad key, not previously allowed", __func__); -+ if (type != key_blobtype) -+ fatal("%s: bad key type", __func__); - - key = key_from_blob(blob, bloblen); - if (key == NULL) -@@ -1423,7 +1453,17 @@ mm_answer_keyverify(int sock, Buffer *m) - if (!valid_data) - fatal("%s: bad signature data blob", __func__); - -- verified = key_verify(key, signature, signaturelen, data, datalen); -+ switch (key_blobtype) { -+ case MM_USERKEY: -+ verified = user_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ case MM_HOSTKEY: -+ verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); -+ break; -+ default: -+ verified = 0; -+ break; -+ } - debug3("%s: key %p signature %s", - __func__, key, (verified == 1) ? "verified" : "unverified"); - -@@ -1476,6 +1516,12 @@ mm_session_close(Session *s) - debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); - session_pty_cleanup2(s); - } -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL) { -+ debug3("%s: command %d", __func__, s->command_handle); -+ session_end_command2(s); -+ } -+#endif - session_unused(s->self); - } - -@@ -1756,6 +1802,8 @@ mm_answer_term(int sock, Buffer *req) - sshpam_cleanup(); - #endif - -+ destroy_sensitive_data(0); -+ - while (waitpid(pmonitor->m_pid, &status, 0) == -1) - if (errno != EINTR) - exit(1); -@@ -1798,11 +1846,43 @@ mm_answer_audit_command(int socket, Buffer *m) - { - u_int len; - char *cmd; -+ Session *s; - - debug3("%s entering", __func__); - cmd = buffer_get_string(m, &len); -+ - /* sanity check command, if so how? */ -- audit_run_command(cmd); -+ s = session_new(); -+ if (s == NULL) -+ fatal("%s: error allocating a session", __func__); -+ s->command = cmd; -+ s->command_handle = audit_run_command(cmd); -+ -+ buffer_clear(m); -+ buffer_put_int(m, s->self); -+ -+ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); -+ -+ return (0); -+} -+ -+int -+mm_answer_audit_end_command(int socket, Buffer *m) -+{ -+ int handle; -+ u_int len; -+ char *cmd; -+ Session *s; -+ -+ debug3("%s entering", __func__); -+ handle = buffer_get_int(m); -+ cmd = buffer_get_string(m, &len); -+ -+ s = session_by_id(handle); -+ if (s == NULL || s->ttyfd != -1 || s->command == NULL || -+ strcmp(s->command, cmd) != 0) -+ fatal("%s: invalid handle", __func__); -+ mm_session_close(s); - free(cmd); - return (0); - } -@@ -1946,11 +2026,13 @@ mm_get_keystate(struct monitor *pmonitor) - - blob = buffer_get_string(&m, &bloblen); - current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - debug3("%s: Waiting for second key", __func__); - blob = buffer_get_string(&m, &bloblen); - current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - /* Now get sequence numbers for the packets */ -@@ -1996,6 +2078,21 @@ mm_get_keystate(struct monitor *pmonitor) - } - - buffer_free(&m); -+ -+#ifdef SSH_AUDIT_EVENTS -+ if (compat20) { -+ buffer_init(&m); -+ 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); -+ } -+#endif -+ -+ /* Drain any buffered messages from the child */ -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) -+ ; -+ - } - - -@@ -2277,3 +2374,84 @@ mm_answer_gss_updatecreds(int socket, Buffer *m) { - - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+int -+mm_answer_audit_unsupported_body(int sock, Buffer *m) -+{ -+ int what; -+ -+ what = buffer_get_int(m); -+ -+ audit_unsupported_body(what); -+ -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_kex_body(int sock, Buffer *m) -+{ -+ int ctos, len; -+ char *cipher, *mac, *compress; -+ 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); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_kex_body(ctos, cipher, mac, compress, pid, uid); -+ -+ free(cipher); -+ free(mac); -+ free(compress); -+ buffer_clear(m); -+ -+ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); -+ return 0; -+} -+ -+int -+mm_answer_audit_session_key_free_body(int sock, Buffer *m) -+{ -+ int ctos; -+ pid_t pid; -+ uid_t uid; -+ -+ ctos = buffer_get_int(m); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_session_key_free_body(ctos, pid, uid); -+ -+ buffer_clear(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) -+{ -+ int len; -+ char *fp; -+ pid_t pid; -+ uid_t uid; -+ -+ fp = buffer_get_string(m, &len); -+ pid = buffer_get_int64(m); -+ uid = buffer_get_int64(m); -+ -+ audit_destroy_sensitive_data(fp, pid, uid); -+ -+ free(fp); -+ buffer_clear(m); -+ -+ return 0; -+} -+#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor.h b/monitor.h -index ff79fbb..6dfb234 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -69,7 +69,13 @@ enum monitor_reqtype { - MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, - MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, - MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, -- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, -+ MONITOR_REQ_AUDIT_EVENT = 112, -+ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, -+ MONITOR_REQ_AUDIT_END_COMMAND = 116, -+ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, -+ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, -+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, -+ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124 - - }; - -diff --git a/monitor_wrap.c b/monitor_wrap.c -index d1e1caa..6df236a 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -450,7 +450,7 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) - */ - - int --mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - { - Buffer m; - u_char *blob; -@@ -464,6 +464,7 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - 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); -@@ -481,6 +482,19 @@ mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) - return (verified); - } - -+int -+mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); -+} -+ -+int -+mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) -+{ -+ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); -+} -+ -+ - /* Export key state after authentication */ - Newkeys * - mm_newkeys_from_blob(u_char *blob, int blen) -@@ -659,12 +673,14 @@ mm_send_keystate(struct monitor *monitor) - fatal("%s: conversion of newkeys failed", __func__); - - buffer_put_string(&m, blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) - fatal("%s: conversion of newkeys failed", __func__); - - buffer_put_string(&m, blob, bloblen); -+ memset(blob, 0, bloblen); - free(blob); - - packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes); -@@ -1208,10 +1224,11 @@ mm_audit_event(ssh_audit_event_t event) - buffer_free(&m); - } - --void -+int - mm_audit_run_command(const char *command) - { - Buffer m; -+ int handle; - - debug3("%s entering command %s", __func__, command); - -@@ -1219,6 +1236,26 @@ mm_audit_run_command(const char *command) - buffer_put_cstring(&m, command); - - 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); -+ -+ return (handle); -+} -+ -+void -+mm_audit_end_command(int handle, const char *command) -+{ -+ Buffer m; -+ -+ debug3("%s entering command %s", __func__, command); -+ -+ buffer_init(&m); -+ buffer_put_int(&m, handle); -+ buffer_put_cstring(&m, command); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); - buffer_free(&m); - } - #endif /* SSH_AUDIT_EVENTS */ -@@ -1354,3 +1391,69 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *store) - - #endif /* GSSAPI */ - -+#ifdef SSH_AUDIT_EVENTS -+void -+mm_audit_unsupported_body(int what) -+{ -+ Buffer m; -+ -+ buffer_init(&m); -+ buffer_put_int(&m, what); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_kex_body(int ctos, char *cipher, char *mac, char *compress, 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_int64(&m, pid); -+ buffer_put_int64(&m, uid); -+ -+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, &m); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, -+ &m); -+ -+ buffer_free(&m); -+} -+ -+void -+mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) -+{ -+ Buffer 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); -+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, -+ &m); -+ buffer_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); -+} -+#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 93929e0..4cf0c78 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, char *, char *, Key *); - int mm_user_key_allowed(struct passwd *, Key *); - int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); - int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); --int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); -+int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); -+int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); - int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); - int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); - BIGNUM *mm_auth_rsa_generate_challenge(Key *); -@@ -79,7 +80,12 @@ void mm_sshpam_free_ctx(void *); - #ifdef SSH_AUDIT_EVENTS - #include "audit.h" - void mm_audit_event(ssh_audit_event_t); --void mm_audit_run_command(const char *); -+int mm_audit_run_command(const char *); -+void mm_audit_end_command(int, const char *); -+void mm_audit_unsupported_body(int); -+void mm_audit_kex_body(int, char *, char *, char *, pid_t, uid_t); -+void mm_audit_session_key_free_body(int, pid_t, uid_t); -+void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); - #endif - - struct Session; -diff --git a/packet.c b/packet.c -index 660a9fc..f5b122b 100644 ---- a/packet.c -+++ b/packet.c -@@ -61,6 +61,7 @@ - #include - - #include "xmalloc.h" -+#include "audit.h" - #include "buffer.h" - #include "packet.h" - #include "crc32.h" -@@ -476,6 +477,13 @@ packet_get_connection_out(void) - return active_state->connection_out; - } - -+static int -+packet_state_has_keys (const struct session_state *state) -+{ -+ return state != NULL && -+ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); -+} -+ - /* Closes the connection and clears and frees internal data structures. */ - - void -@@ -484,13 +492,6 @@ packet_close(void) - if (!active_state->initialized) - return; - active_state->initialized = 0; -- if (active_state->connection_in == active_state->connection_out) { -- shutdown(active_state->connection_out, SHUT_RDWR); -- close(active_state->connection_out); -- } else { -- close(active_state->connection_in); -- close(active_state->connection_out); -- } - buffer_free(&active_state->input); - buffer_free(&active_state->output); - buffer_free(&active_state->outgoing_packet); -@@ -499,8 +500,18 @@ packet_close(void) - buffer_free(&active_state->compression_buffer); - buffer_compress_uninit(); - } -- cipher_cleanup(&active_state->send_context); -- cipher_cleanup(&active_state->receive_context); -+ if (packet_state_has_keys(active_state)) { -+ cipher_cleanup(&active_state->send_context); -+ cipher_cleanup(&active_state->receive_context); -+ audit_session_key_free(2); -+ } -+ if (active_state->connection_in == active_state->connection_out) { -+ shutdown(active_state->connection_out, SHUT_RDWR); -+ close(active_state->connection_out); -+ } else { -+ close(active_state->connection_in); -+ close(active_state->connection_out); -+ } - } - - /* Sets remote side protocol flags. */ -@@ -761,6 +791,7 @@ set_newkeys(int mode) - } - if (active_state->newkeys[mode] != NULL) { - debug("set_newkeys: rekeying"); -+ audit_session_key_free(mode); - cipher_cleanup(cc); - enc = &active_state->newkeys[mode]->enc; - mac = &active_state->newkeys[mode]->mac; -@@ -2011,6 +2042,47 @@ packet_get_newkeys(int mode) - return (void *)active_state->newkeys[mode]; - } - -+static void -+packet_destroy_state(struct session_state *state) -+{ -+ if (state == NULL) -+ return; -+ -+ cipher_cleanup(&state->receive_context); -+ cipher_cleanup(&state->send_context); -+ -+ buffer_free(&state->input); -+ buffer_free(&state->output); -+ buffer_free(&state->outgoing_packet); -+ buffer_free(&state->incoming_packet); -+ buffer_free(&state->compression_buffer); -+ newkeys_destroy_and_free(state->newkeys[MODE_IN]); -+ state->newkeys[MODE_IN] = NULL; -+ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); -+ state->newkeys[MODE_OUT] = NULL; -+ mac_destroy(state->packet_discard_mac); -+// TAILQ_HEAD(, packet) outgoing; -+// memset(state, 0, sizeof(state)); -+} -+ -+void -+packet_destroy_all(int audit_it, int privsep) -+{ -+ if (audit_it) -+ audit_it = packet_state_has_keys (active_state) || -+ packet_state_has_keys (backup_state); -+ packet_destroy_state(active_state); -+ packet_destroy_state(backup_state); -+ if (audit_it) { -+#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ audit_session_key_free(2); -+ else -+ audit_session_key_free_body(2, getpid(), getuid()); -+#endif -+ } -+} -+ - /* - * Save the state for the real connection, and use a separate state when - * resuming a suspended connection. -@@ -2018,18 +2090,12 @@ packet_get_newkeys(int mode) - void - packet_backup_state(void) - { -- struct session_state *tmp; -- - close(active_state->connection_in); - active_state->connection_in = -1; - close(active_state->connection_out); - active_state->connection_out = -1; -- if (backup_state) -- tmp = backup_state; -- else -- tmp = alloc_session_state(); - backup_state = active_state; -- active_state = tmp; -+ active_state = alloc_session_state(); - } - - /* -@@ -2046,9 +2112,7 @@ packet_restore_state(void) - backup_state = active_state; - active_state = tmp; - active_state->connection_in = backup_state->connection_in; -- backup_state->connection_in = -1; - active_state->connection_out = backup_state->connection_out; -- backup_state->connection_out = -1; - len = buffer_len(&backup_state->input); - if (len > 0) { - buf = buffer_ptr(&backup_state->input); -@@ -2056,4 +2120,10 @@ packet_restore_state(void) - buffer_clear(&backup_state->input); - add_recv_bytes(len); - } -+ backup_state->connection_in = -1; -+ backup_state->connection_out = -1; -+ packet_destroy_state(backup_state); -+ free(backup_state); -+ backup_state = NULL; - } -+ -diff --git a/packet.h b/packet.h -index f8edf85..c36c812 100644 ---- a/packet.h -+++ b/packet.h -@@ -124,4 +124,5 @@ void packet_restore_state(void); - void *packet_get_input(void); - void *packet_get_output(void); - -+void packet_destroy_all(int, int); - #endif /* PACKET_H */ -diff --git a/session.c b/session.c -index df43592..b186ca1 100644 ---- a/session.c -+++ b/session.c -@@ -138,7 +138,7 @@ extern int log_stderr; - extern int debug_flag; - extern u_int utmp_len; - extern int startup_pipe; --extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(int); - extern Buffer loginmsg; - - /* original command from peer. */ -@@ -746,6 +746,14 @@ do_exec_pty(Session *s, const char *command) - /* Parent. Close the slave side of the pseudo tty. */ - close(ttyfd); - -+#ifndef HAVE_OSF_SIA -+ /* do_login in the child did not affect state in this process, -+ compensate. From an architectural standpoint, this is extremely -+ ugly. */ -+ if (!(options.use_login && command == NULL)) -+ audit_count_session_open(); -+#endif -+ - /* Enter interactive session. */ - s->ptymaster = ptymaster; - packet_set_interactive(1, -@@ -863,15 +871,19 @@ do_exec(Session *s, const char *command) - get_remote_port()); - - #ifdef SSH_AUDIT_EVENTS -+ if (s->command != NULL || s->command_handle != -1) -+ fatal("do_exec: command already set"); - if (command != NULL) -- PRIVSEP(audit_run_command(command)); -+ s->command = xstrdup(command); - else if (s->ttyfd == -1) { - char *shell = s->pw->pw_shell; - - if (shell[0] == '\0') /* empty shell means /bin/sh */ - shell =_PATH_BSHELL; -- PRIVSEP(audit_run_command(shell)); -+ s->command = xstrdup(shell); - } -+ if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = PRIVSEP(audit_run_command(s->command)); - #endif - if (s->ttyfd != -1) - ret = do_exec_pty(s, command); -@@ -1708,7 +1720,10 @@ do_child(Session *s, const char *command) - int r = 0; - - /* remove hostkey from the child's memory */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(1); -+ /* Don't audit this - both us and the parent would be talking to the -+ monitor over a single socket, with no synchronization. */ -+ packet_destroy_all(0, 1); - - /* Force a password change */ - if (s->authctxt->force_pwchange) { -@@ -1933,6 +1948,7 @@ session_unused(int id) - sessions[id].ttyfd = -1; - sessions[id].ptymaster = -1; - sessions[id].x11_chanids = NULL; -+ sessions[id].command_handle = -1; - sessions[id].next_unused = sessions_first_unused; - sessions_first_unused = id; - } -@@ -2015,6 +2031,19 @@ session_open(Authctxt *authctxt, int chanid) - } - - Session * -+session_by_id(int id) -+{ -+ if (id >= 0 && id < sessions_nalloc) { -+ Session *s = &sessions[id]; -+ if (s->used) -+ return s; -+ } -+ debug("session_by_id: unknown id %d", id); -+ session_dump(); -+ return NULL; -+} -+ -+Session * - session_by_tty(char *tty) - { - int i; -@@ -2531,6 +2560,32 @@ session_exit_message(Session *s, int status) - chan_write_failed(c); - } - -+#ifdef SSH_AUDIT_EVENTS -+void -+session_end_command2(Session *s) -+{ -+ if (s->command != NULL) { -+ if (s->command_handle != -1) -+ audit_end_command(s->command_handle, s->command); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+ -+static void -+session_end_command(Session *s) -+{ -+ if (s->command != NULL) { -+ if (s->command_handle != -1) -+ PRIVSEP(audit_end_command(s->command_handle, s->command)); -+ free(s->command); -+ s->command = NULL; -+ s->command_handle = -1; -+ } -+} -+#endif -+ - void - session_close(Session *s) - { -@@ -2539,6 +2592,10 @@ session_close(Session *s) - debug("session_close: session %d pid %ld", s->self, (long)s->pid); - if (s->ttyfd != -1) - session_pty_cleanup(s); -+#ifdef SSH_AUDIT_EVENTS -+ if (s->command) -+ session_end_command(s); -+#endif - free(s->term); - free(s->display); - free(s->x11_chanids); -@@ -2753,6 +2810,15 @@ do_authenticated2(Authctxt *authctxt) - server_loop2(authctxt); - } - -+static void -+do_cleanup_one_session(Session *s) -+{ -+ session_pty_cleanup2(s); -+#ifdef SSH_AUDIT_EVENTS -+ session_end_command2(s); -+#endif -+} -+ - void - do_cleanup(Authctxt *authctxt) - { -@@ -2801,5 +2867,5 @@ do_cleanup(Authctxt *authctxt) - * or if running in monitor. - */ - if (!use_privsep || mm_is_monitor()) -- session_destroy_all(session_pty_cleanup2); -+ session_destroy_all(do_cleanup_one_session); - } -diff --git a/session.h b/session.h -index 6a2f35e..e9b312e 100644 ---- a/session.h -+++ b/session.h -@@ -61,6 +61,12 @@ struct Session { - char *name; - char *val; - } *env; -+ -+ /* exec */ -+#ifdef SSH_AUDIT_EVENTS -+ int command_handle; -+ char *command; -+#endif - }; - - void do_authenticated(Authctxt *); -@@ -73,8 +79,10 @@ void session_close_by_pid(pid_t, int); - void session_close_by_channel(int, void *); - void session_destroy_all(void (*)(Session *)); - void session_pty_cleanup2(Session *); -+void session_end_command2(Session *); - - Session *session_new(void); -+Session *session_by_id(int); - Session *session_by_tty(char *); - void session_close(Session *); - void do_setusercontext(struct passwd *); -diff --git a/sshd.c b/sshd.c -index 8a0740a..2813aa2 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -119,6 +119,7 @@ - #endif - #include "monitor_wrap.h" - #include "roaming.h" -+#include "audit.h" - #include "ssh-sandbox.h" - #include "version.h" - -@@ -264,7 +265,7 @@ Buffer loginmsg; - struct passwd *privsep_pw = NULL; - - /* Prototypes for various functions defined later in this file. */ --void destroy_sensitive_data(void); -+void destroy_sensitive_data(int); - void demote_sensitive_data(void); - - static void do_ssh1_kex(void); -@@ -283,6 +284,15 @@ close_listen_socks(void) - num_listen_socks = -1; - } - -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) -+{ -+ return num_listen_socks > 0; -+} -+ - static void - close_startup_pipes(void) - { -@@ -562,22 +572,45 @@ sshd_exchange_identification(int sock_in, int sock_out) - } - } - --/* Destroy the host and server keys. They will no longer be needed. */ -+/* -+ * Destroy the host and server keys. They will no longer be needed. Careful, -+ * this can be called from cleanup_exit() - i.e. from just about anywhere. -+ */ - void --destroy_sensitive_data(void) -+destroy_sensitive_data(int privsep) - { - int i; -+ pid_t pid; -+ uid_t uid; - - if (sensitive_data.server_key) { - key_free(sensitive_data.server_key); - sensitive_data.server_key = NULL; - } -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX); -+ else -+ fp = NULL; - key_free(sensitive_data.host_keys[i]); - sensitive_data.host_keys[i] = NULL; -+ if (fp != NULL) { -+ if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(fp, -+ pid, uid)); -+ else -+ audit_destroy_sensitive_data(fp, -+ pid, uid); -+ free(fp); -+ } - } -- if (sensitive_data.host_certificates[i]) { -+ if (sensitive_data.host_certificates -+ && sensitive_data.host_certificates[i]) { - key_free(sensitive_data.host_certificates[i]); - sensitive_data.host_certificates[i] = NULL; - } -@@ -591,6 +624,8 @@ void - demote_sensitive_data(void) - { - Key *tmp; -+ pid_t pid; -+ uid_t uid; - int i; - - if (sensitive_data.server_key) { -@@ -599,13 +634,25 @@ demote_sensitive_data(void) - sensitive_data.server_key = tmp; - } - -+ pid = getpid(); -+ uid = getuid(); - for (i = 0; i < options.num_host_key_files; i++) { - if (sensitive_data.host_keys[i]) { -+ char *fp; -+ -+ if (key_is_private(sensitive_data.host_keys[i])) -+ fp = key_selected_fingerprint(sensitive_data.host_keys[i], SSH_FP_HEX); -+ else -+ fp = NULL; - tmp = key_demote(sensitive_data.host_keys[i]); - key_free(sensitive_data.host_keys[i]); - sensitive_data.host_keys[i] = tmp; - if (tmp->type == KEY_RSA1) - sensitive_data.ssh1_host_key = tmp; -+ if (fp != NULL) { -+ audit_destroy_sensitive_data(fp, pid, uid); -+ free(fp); -+ } - } - /* Certs do not need demotion */ - } -@@ -675,7 +722,7 @@ privsep_preauth(Authctxt *authctxt) - - if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(pmonitor); -- pid = fork(); -+ pmonitor->m_pid = pid = fork(); - if (pid == -1) { - fatal("fork of unprivileged child failed"); - } else if (pid != 0) { -@@ -729,6 +776,8 @@ privsep_preauth(Authctxt *authctxt) - } - } - -+extern Newkeys *current_keys[]; -+ - static void - privsep_postauth(Authctxt *authctxt) - { -@@ -753,6 +802,10 @@ privsep_postauth(Authctxt *authctxt) - else if (pmonitor->m_pid != 0) { - verbose("User child is on pid %ld", (long)pmonitor->m_pid); - buffer_clear(&loginmsg); -+ newkeys_destroy(current_keys[MODE_OUT]); -+ newkeys_destroy(current_keys[MODE_IN]); -+ audit_session_key_free_body(2, getpid(), getuid()); -+ packet_destroy_all(0, 0); - monitor_child_postauth(pmonitor); - - /* NEVERREACHED */ -@@ -1211,6 +1264,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) - if (received_sigterm) { - logit("Received signal %d; terminating.", - (int) received_sigterm); -+ destroy_sensitive_data(0); - close_listen_socks(); - unlink(options.pid_file); - exit(received_sigterm == SIGTERM ? 0 : 255); -@@ -2134,6 +2188,7 @@ main(int ac, char **av) - */ - if (use_privsep) { - mm_send_keystate(pmonitor); -+ packet_destroy_all(1, 1); - exit(0); - } - -@@ -2179,7 +2234,7 @@ main(int ac, char **av) - privsep_postauth(authctxt); - /* the monitor process [priv] will not return */ - if (!compat20) -- destroy_sensitive_data(); -+ destroy_sensitive_data(0); - } - - packet_set_timeout(options.client_alive_interval, -@@ -2189,6 +2244,9 @@ main(int ac, char **av) - do_authenticated(authctxt); - - /* The connection has been terminated. */ -+ packet_destroy_all(1, 1); -+ destroy_sensitive_data(1); -+ - packet_get_state(MODE_IN, NULL, NULL, NULL, &ibytes); - packet_get_state(MODE_OUT, NULL, NULL, NULL, &obytes); - verbose("Transferred: sent %llu, received %llu bytes", -@@ -2346,6 +2404,10 @@ do_ssh1_kex(void) - if (cookie[i] != packet_get_char()) - packet_disconnect("IP Spoofing check bytes do not match."); - -+#ifdef SSH_AUDIT_EVENTS -+ audit_kex(2, cipher_name(cipher_type), "crc", "none"); -+#endif -+ - debug("Encryption type: %.200s", cipher_name(cipher_type)); - - /* Get the encrypted integer. */ -@@ -2418,7 +2480,7 @@ do_ssh1_kex(void) - session_id[i] = session_key[i] ^ session_key[i + 16]; - } - /* Destroy the private and public keys. No longer. */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(0); - - if (use_privsep) - mm_ssh1_session_id(session_id); -@@ -2584,6 +2646,16 @@ do_ssh2_kex(void) - void - cleanup_exit(int i) - { -+ static int in_cleanup = 0; -+ int is_privsep_child; -+ -+ /* cleanup_exit can be called at the very least from the privsep -+ wrappers used for auditing. Make sure we don't recurse -+ indefinitely. */ -+ if (in_cleanup) -+ _exit(i); -+ in_cleanup = 1; -+ - if (the_authctxt) { - do_cleanup(the_authctxt); - if (use_privsep && privsep_is_preauth && pmonitor->m_pid > 1) { -@@ -2594,9 +2666,14 @@ cleanup_exit(int i) - pmonitor->m_pid, strerror(errno)); - } - } -+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL) -+ destroy_sensitive_data(is_privsep_child); -+ packet_destroy_all(1, is_privsep_child); - #ifdef SSH_AUDIT_EVENTS - /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (!use_privsep || mm_is_monitor()) -+ if ((the_authctxt == NULL || !the_authctxt->authenticated) && -+ (!use_privsep || mm_is_monitor())) - audit_event(SSH_CONNECTION_ABANDON); - #endif - _exit(i); diff --git a/SOURCES/openssh-6.6p1-authentication-limits-bypass.patch b/SOURCES/openssh-6.6p1-authentication-limits-bypass.patch deleted file mode 100644 index 10bde94..0000000 --- a/SOURCES/openssh-6.6p1-authentication-limits-bypass.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5b64f85bb811246c59ebab70aed331f26ba37b18 Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Sat, 18 Jul 2015 07:57:14 +0000 -Subject: upstream commit - -only query each keyboard-interactive device once per - authentication request regardless of how many times it is listed; ok markus@ - -Upstream-ID: d73fafba6e86030436ff673656ec1f33d9ffeda1 ---- - auth2-chall.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/auth2-chall.c b/auth2-chall.c -index ddabe1a..4aff09d 100644 ---- a/auth2-chall.c -+++ b/auth2-chall.c -@@ -83,6 +83,7 @@ struct KbdintAuthctxt - void *ctxt; - KbdintDevice *device; - u_int nreq; -+ u_int devices_done; - }; - - #ifdef USE_PAM -@@ -169,11 +170,15 @@ kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt) - if (len == 0) - break; - for (i = 0; devices[i]; i++) { -- if (!auth2_method_allowed(authctxt, -+ if ((kbdintctxt->devices_done & (1 << i)) != 0 || -+ !auth2_method_allowed(authctxt, - "keyboard-interactive", devices[i]->name)) - continue; -- if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0) -+ if (strncmp(kbdintctxt->devices, devices[i]->name, -+ len) == 0) { - kbdintctxt->device = devices[i]; -+ kbdintctxt->devices_done |= 1 << i; -+ } - } - t = kbdintctxt->devices; - kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL; --- -cgit v0.11.2 - - diff --git a/SOURCES/openssh-6.6p1-chroot-capabilities.patch b/SOURCES/openssh-6.6p1-chroot-capabilities.patch deleted file mode 100644 index 2b58b97..0000000 --- a/SOURCES/openssh-6.6p1-chroot-capabilities.patch +++ /dev/null @@ -1,101 +0,0 @@ -diff -up openssh-6.6p1/configure.ac.chroot-cap openssh-6.6p1/configure.ac ---- openssh-6.6p1/configure.ac.chroot-cap 2016-07-28 10:08:11.183483309 +0200 -+++ openssh-6.6p1/configure.ac 2016-07-28 10:08:11.273483277 +0200 -@@ -4783,6 +4783,37 @@ if test -n "$conf_lastlog_location"; the - [Define if you want to specify the path to your lastlog file]) - fi - -+AC_ARG_WITH(libcap-ng, -+ [ --with-libcap-ng=[auto/yes/no] Add Libcap-ng support [default=auto]],, -+ with_libcap_ng=auto) -+ -+dnl libcap-ng detection -+if test x$with_libcap_ng = xno ; then -+ have_libcap_ng=no; -+else -+ # Start by checking for header file -+ AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no) -+ -+ # See if we have libcap-ng library -+ AC_CHECK_LIB(cap-ng, capng_clear, CAPNG_LDADD=-lcap-ng,) -+ -+ # Check results are usable -+ if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then -+ AC_MSG_ERROR(libcap-ng support was requested and the library was not found) -+ fi -+ if test x$CAPNG_LDADD != x -a $capng_headers = no ; then -+ AC_MSG_ERROR(libcap-ng libraries found but headers are missing) -+ fi -+fi -+AC_MSG_CHECKING(whether to use libcap-ng) -+if test x$CAPNG_LDADD != x ; then -+ AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support]) -+ SSHDLIBS="$SSHDLIBS -lcap-ng" -+ AC_MSG_RESULT(yes) -+else -+ AC_MSG_RESULT(no) -+fi -+ - dnl utmp detection - AC_MSG_CHECKING([if your system defines UTMP_FILE]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -diff -up openssh-6.6p1/session.c.chroot-cap openssh-6.6p1/session.c ---- openssh-6.6p1/session.c.chroot-cap 2016-07-28 10:08:11.269483278 +0200 -+++ openssh-6.6p1/session.c 2016-07-28 10:09:10.458455211 +0200 -@@ -95,6 +95,10 @@ - #include "monitor_wrap.h" - #include "sftp.h" - -+#ifdef HAVE_LIBCAP_NG -+#include -+#endif -+ - #if defined(KRB5) && defined(USE_AFS) - #include - #endif -@@ -1569,6 +1573,7 @@ void - do_setusercontext(struct passwd *pw) - { - char *chroot_path, *tmp; -+ int dropped_suid = -1; - - platform_setusercontext(pw); - -@@ -1602,10 +1607,25 @@ do_setusercontext(struct passwd *pw) - pw->pw_uid); - chroot_path = percent_expand(tmp, "h", pw->pw_dir, - "u", pw->pw_name, (char *)NULL); -+#ifdef HAVE_LIBCAP_NG -+ /* drop suid soon, retain SYS_CHROOT capability */ -+ capng_clear(CAPNG_SELECT_BOTH); -+ capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_SYS_CHROOT); -+ if (pw->pw_uid != 0 && -+ (dropped_suid = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_INIT_SUPP_GRP)) != 0) -+ logit("capng_change_id() = %d (failure): Try to drop UID later", dropped_suid); -+#endif - #ifdef WITH_SELINUX - sshd_selinux_copy_context(); - #endif - safely_chroot(chroot_path, pw->pw_uid); -+#ifdef HAVE_LIBCAP_NG -+ /* Drop chroot capability. Already used */ -+ if (dropped_suid == 0) { -+ capng_clear(CAPNG_SELECT_BOTH); -+ capng_apply(CAPNG_SELECT_BOTH); -+ } -+#endif - free(tmp); - free(chroot_path); - /* Make sure we don't attempt to chroot again */ -@@ -1629,8 +1648,9 @@ do_setusercontext(struct passwd *pw) - fatal("set_id(%s) Failed", pw->pw_name); - } - # endif /* USE_LIBIAF */ -- /* Permanently switch to the desired uid. */ -- permanently_set_uid(pw); -+ /* Permanently switch to the desired uid if not yet done. */ -+ if (dropped_suid != 0) -+ permanently_set_uid(pw); - #endif - - #ifdef WITH_SELINUX diff --git a/SOURCES/openssh-6.6p1-ctr-cavstest.patch b/SOURCES/openssh-6.6p1-ctr-cavstest.patch deleted file mode 100644 index 3b0d744..0000000 --- a/SOURCES/openssh-6.6p1-ctr-cavstest.patch +++ /dev/null @@ -1,253 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 4ab6717..581b121 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -28,6 +28,7 @@ SSH_KEYSIGN=$(libexecdir)/ssh-keysign - SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper - SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper - SSH_KEYCAT=$(libexecdir)/ssh-keycat -+CTR_CAVSTEST=$(libexecdir)/ctr-cavstest - SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ - SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ - MANFMT=@MANFMT@ - INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ - --TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) -+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) - - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -180,6 +181,9 @@ ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o - ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o - $(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(SSHLIBS) - -+ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o -+ $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) -+ - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o - $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) - -@@ -288,6 +292,7 @@ install-files: - $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ - fi - $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) -+ $(INSTALL) -m 0755 $(STRIP_OPT) ctr-cavstest$(EXEEXT) $(DESTDIR)$(libexecdir)/ctr-cavstest$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) - $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -diff --git a/ctr-cavstest.c b/ctr-cavstest.c -new file mode 100644 -index 0000000..bbcbe8a ---- /dev/null -+++ b/ctr-cavstest.c -@@ -0,0 +1,208 @@ -+/* -+ * -+ * invocation (all of the following are equal): -+ * ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt --data a6deca405eef2e8e4609abf3c3ccf4a6 -+ * ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt --data a6deca405eef2e8e4609abf3c3ccf4a6 --iv 00000000000000000000000000000000 -+ * echo -n a6deca405eef2e8e4609abf3c3ccf4a6 | ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt -+ */ -+ -+#include "includes.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "xmalloc.h" -+#include "log.h" -+#include "cipher.h" -+ -+/* compatibility with old or broken OpenSSL versions */ -+#include "openbsd-compat/openssl-compat.h" -+ -+void usage(void) { -+ fprintf(stderr, "Usage: ctr-cavstest --algo \n" -+ " --key --mode \n" -+ " [--iv ] --data \n\n" -+ "Hexadecimal output is printed to stdout.\n" -+ "Hexadecimal input data can be alternatively read from stdin.\n"); -+ exit(1); -+} -+ -+void *fromhex(char *hex, size_t *len) -+{ -+ unsigned char *bin; -+ char *p; -+ size_t n = 0; -+ int shift = 4; -+ unsigned char out = 0; -+ unsigned char *optr; -+ -+ bin = xmalloc(strlen(hex)/2); -+ optr = bin; -+ -+ for (p = hex; *p != '\0'; ++p) { -+ unsigned char c; -+ -+ c = *p; -+ if (isspace(c)) -+ continue; -+ -+ if (c >= '0' && c <= '9') { -+ c = c - '0'; -+ } else if (c >= 'A' && c <= 'F') { -+ c = c - 'A' + 10; -+ } else if (c >= 'a' && c <= 'f') { -+ c = c - 'a' + 10; -+ } else { -+ /* truncate on nonhex cipher */ -+ break; -+ } -+ -+ out |= c << shift; -+ shift = (shift + 4) % 8; -+ -+ if (shift) { -+ *(optr++) = out; -+ out = 0; -+ ++n; -+ } -+ } -+ -+ *len = n; -+ return bin; -+} -+ -+#define READ_CHUNK 4096 -+#define MAX_READ_SIZE 1024*1024*100 -+char *read_stdin(void) -+{ -+ char *buf; -+ size_t n, total = 0; -+ -+ buf = xmalloc(READ_CHUNK); -+ -+ do { -+ n = fread(buf + total, 1, READ_CHUNK, stdin); -+ if (n < READ_CHUNK) /* terminate on short read */ -+ break; -+ -+ total += n; -+ buf = xrealloc(buf, total + READ_CHUNK, 1); -+ } while(total < MAX_READ_SIZE); -+ return buf; -+} -+ -+int main (int argc, char *argv[]) -+{ -+ -+ const Cipher *c; -+ CipherContext cc; -+ char *algo = "aes128-ctr"; -+ char *hexkey = NULL; -+ char *hexiv = "00000000000000000000000000000000"; -+ char *hexdata = NULL; -+ char *p; -+ int i; -+ int encrypt = 1; -+ void *key; -+ size_t keylen; -+ void *iv; -+ size_t ivlen; -+ void *data; -+ size_t datalen; -+ void *outdata; -+ -+ for (i = 1; i < argc; ++i) { -+ if (strcmp(argv[i], "--algo") == 0) { -+ algo = argv[++i]; -+ } else if (strcmp(argv[i], "--key") == 0) { -+ hexkey = argv[++i]; -+ } else if (strcmp(argv[i], "--mode") == 0) { -+ ++i; -+ if (argv[i] == NULL) { -+ usage(); -+ } -+ if (strncmp(argv[i], "enc", 3) == 0) { -+ encrypt = 1; -+ } else if (strncmp(argv[i], "dec", 3) == 0) { -+ encrypt = 0; -+ } else { -+ usage(); -+ } -+ } else if (strcmp(argv[i], "--iv") == 0) { -+ hexiv = argv[++i]; -+ } else if (strcmp(argv[i], "--data") == 0) { -+ hexdata = argv[++i]; -+ } -+ } -+ -+ if (hexkey == NULL || algo == NULL) { -+ usage(); -+ } -+ -+ SSLeay_add_all_algorithms(); -+ -+ c = cipher_by_name(algo); -+ if (c == NULL) { -+ fprintf(stderr, "Error: unknown algorithm\n"); -+ return 2; -+ } -+ -+ if (hexdata == NULL) { -+ hexdata = read_stdin(); -+ } else { -+ hexdata = xstrdup(hexdata); -+ } -+ -+ key = fromhex(hexkey, &keylen); -+ -+ if (keylen != 16 && keylen != 24 && keylen == 32) { -+ fprintf(stderr, "Error: unsupported key length\n"); -+ return 2; -+ } -+ -+ iv = fromhex(hexiv, &ivlen); -+ -+ if (ivlen != 16) { -+ fprintf(stderr, "Error: unsupported iv length\n"); -+ return 2; -+ } -+ -+ data = fromhex(hexdata, &datalen); -+ -+ if (data == NULL || datalen == 0) { -+ fprintf(stderr, "Error: no data to encrypt/decrypt\n"); -+ return 2; -+ } -+ -+ cipher_init(&cc, c, key, keylen, iv, ivlen, encrypt); -+ -+ free(key); -+ free(iv); -+ -+ outdata = malloc(datalen); -+ if(outdata == NULL) { -+ fprintf(stderr, "Error: memory allocation failure\n"); -+ return 2; -+ } -+ -+ cipher_crypt(&cc, 0, outdata, data, datalen, 0, 0); -+ -+ free(data); -+ -+ cipher_cleanup(&cc); -+ -+ for (p = outdata; datalen > 0; ++p, --datalen) { -+ printf("%02X", (unsigned char)*p); -+ } -+ -+ free(outdata); -+ -+ printf("\n"); -+ return 0; -+} -+ diff --git a/SOURCES/openssh-6.6p1-disable-roaming.patch b/SOURCES/openssh-6.6p1-disable-roaming.patch deleted file mode 100644 index 0e71113..0000000 --- a/SOURCES/openssh-6.6p1-disable-roaming.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -up openssh-6.6p1/readconf.c.roaming openssh-6.6p1/readconf.c ---- openssh-6.6p1/readconf.c.roaming 2016-01-13 15:42:00.423573980 +0100 -+++ openssh-6.6p1/readconf.c 2016-01-13 15:43:03.565529448 +0100 -@@ -1608,7 +1608,7 @@ initialize_options(Options * options) - options->tun_remote = -1; - options->local_command = NULL; - options->permit_local_command = -1; -- options->use_roaming = -1; -+ options->use_roaming = 0; - options->visual_host_key = -1; - options->ip_qos_interactive = -1; - options->ip_qos_bulk = -1; -@@ -1783,8 +1783,7 @@ fill_default_options(Options * options) - options->tun_remote = SSH_TUNID_ANY; - if (options->permit_local_command == -1) - options->permit_local_command = 0; -- if (options->use_roaming == -1) -- options->use_roaming = 1; -+ options->use_roaming = 0; - if (options->visual_host_key == -1) - options->visual_host_key = 0; - if (options->ip_qos_interactive == -1) diff --git a/SOURCES/openssh-6.6p1-document-TERM-env.patch b/SOURCES/openssh-6.6p1-document-TERM-env.patch deleted file mode 100644 index 66445d9..0000000 --- a/SOURCES/openssh-6.6p1-document-TERM-env.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/ssh_config.5 b/ssh_config.5 -index e7accd6..c95fda6 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -1253,6 +1253,10 @@ should be sent to the server. - Note that environment passing is only supported for protocol 2. - The server must also support it, and the server must be configured to - accept these environment variables. -+Note that the -+.Ev TERM -+environment variable is always sent whenever a -+pseudo-terminal is requested as it is required by the protocol. - Refer to - .Cm AcceptEnv - in -diff --git a/sshd_config.5 b/sshd_config.5 -index aa9525d..2320128 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -70,7 +70,11 @@ See - in - .Xr ssh_config 5 - for how to configure the client. --Note that environment passing is only supported for protocol 2. -+Note that environment passing is only supported for protocol 2, and -+that the -+.Ev TERM -+environment variable is always sent whenever the client -+requests a pseudo-terminal as it is required by the protocol. - Variables are specified by name, which may contain the wildcard characters - .Ql * - and diff --git a/SOURCES/openssh-6.6p1-entropy.patch b/SOURCES/openssh-6.6p1-entropy.patch index 67bd30f..6dcd38a 100644 --- a/SOURCES/openssh-6.6p1-entropy.patch +++ b/SOURCES/openssh-6.6p1-entropy.patch @@ -18,13 +18,23 @@ index b912dbe..9206337 100644 +++ b/openbsd-compat/Makefile.in @@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di - COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o + COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o -PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o +PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-linux-prng.o port-solaris.o port-tun.o port-uw.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 --git a/openbsd-compat/port-linux-prng.c b/openbsd-compat/port-linux-prng.c new file mode 100644 index 0000000..92a617c @@ -63,6 +73,7 @@ index 0000000..92a617c + +#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" @@ -72,10 +83,9 @@ index 0000000..92a617c +void +linux_seed(void) +{ -+ int len; + char *env = getenv("SSH_USE_STRONG_RNG"); + char *random = "/dev/random"; -+ size_t ienv, randlen = 14; ++ size_t len, ienv, randlen = 14; + + if (!env || !strcmp(env, "0")) + random = "/dev/urandom"; diff --git a/SOURCES/openssh-6.6p1-expose-auth-information.patch b/SOURCES/openssh-6.6p1-expose-auth-information.patch deleted file mode 100644 index ed508fd..0000000 --- a/SOURCES/openssh-6.6p1-expose-auth-information.patch +++ /dev/null @@ -1,512 +0,0 @@ -diff -up openssh-6.6p1/auth2.c.expose-auth openssh-6.6p1/auth2.c ---- openssh-6.6p1/auth2.c.expose-auth 2016-06-27 12:19:39.134443822 +0200 -+++ openssh-6.6p1/auth2.c 2016-06-27 12:19:39.178443747 +0200 -@@ -309,6 +309,7 @@ userauth_finish(Authctxt *authctxt, int - const char *submethod) - { - char *methods; -+ char *prev_auth_details; - int partial = 0; - - if (!authctxt->valid && authenticated) -@@ -339,6 +340,18 @@ userauth_finish(Authctxt *authctxt, int - if (authctxt->postponed) - return; - -+ if (authenticated || partial) { -+ prev_auth_details = authctxt->auth_details; -+ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", -+ prev_auth_details ? prev_auth_details : "", -+ prev_auth_details ? ", " : "", method, -+ authctxt->last_details ? ": " : "", -+ authctxt->last_details ? authctxt->last_details : ""); -+ free(authctxt->last_details); -+ authctxt->last_details = NULL; -+ free(prev_auth_details); -+ } -+ - #ifdef USE_PAM - if (options.use_pam && authenticated) { - if (!PRIVSEP(do_pam_account())) { -diff -up openssh-6.6p1/auth2-gss.c.expose-auth openssh-6.6p1/auth2-gss.c ---- openssh-6.6p1/auth2-gss.c.expose-auth 2016-06-27 12:19:39.102443877 +0200 -+++ openssh-6.6p1/auth2-gss.c 2016-06-27 12:19:39.179443745 +0200 -@@ -272,6 +272,9 @@ input_gssapi_exchange_complete(int type, - authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, - authctxt->pw)); - -+ if (authenticated) -+ authctxt->last_details = ssh_gssapi_get_displayname(); -+ - authctxt->postponed = 0; - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); -@@ -317,6 +320,9 @@ input_gssapi_mic(int type, u_int32_t ple - else - logit("GSSAPI MIC check failed"); - -+ if (authenticated) -+ authctxt->last_details = ssh_gssapi_get_displayname(); -+ - buffer_free(&b); - if (micuser != authctxt->user) - free(micuser); -diff -up openssh-6.6p1/auth2-hostbased.c.expose-auth openssh-6.6p1/auth2-hostbased.c ---- openssh-6.6p1/auth2-hostbased.c.expose-auth 2016-06-27 12:19:39.051443964 +0200 -+++ openssh-6.6p1/auth2-hostbased.c 2016-06-27 12:19:39.179443745 +0200 -@@ -58,7 +58,7 @@ userauth_hostbased(Authctxt *authctxt) - { - Buffer b; - Key *key = NULL; -- char *pkalg, *cuser, *chost, *service; -+ char *pkalg, *cuser, *chost, *service, *pubkey; - u_char *pkblob, *sig; - u_int alen, blen, slen; - int pktype; -@@ -131,15 +131,21 @@ userauth_hostbased(Authctxt *authctxt) - buffer_dump(&b); - #endif - -- pubkey_auth_info(authctxt, key, -- "client user \"%.100s\", client host \"%.100s\"", cuser, chost); -+ pubkey = key_format_oneline(key); -+ auth_info(authctxt, -+ "%s, client user \"%.100s\", client host \"%.100s\"", -+ pubkey, cuser, chost); - - /* test for allowed key and correct signature */ - authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && - PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -- buffer_len(&b))) == 1) -+ buffer_len(&b))) == 1) { - authenticated = 1; -+ authctxt->last_details = pubkey; -+ } else { -+ free(pubkey); -+ } - - buffer_free(&b); - done: -diff -up openssh-6.6p1/auth2-pubkey.c.expose-auth openssh-6.6p1/auth2-pubkey.c ---- openssh-6.6p1/auth2-pubkey.c.expose-auth 2016-06-27 12:19:39.068443935 +0200 -+++ openssh-6.6p1/auth2-pubkey.c 2016-06-27 12:19:39.179443745 +0200 -@@ -75,7 +75,7 @@ userauth_pubkey(Authctxt *authctxt) - { - Buffer b; - Key *key = NULL; -- char *pkalg, *userstyle; -+ char *pkalg, *userstyle, *pubkey; - u_char *pkblob, *sig; - u_int alen, blen, slen; - int have_sig, pktype; -@@ -155,14 +155,19 @@ userauth_pubkey(Authctxt *authctxt) - #ifdef DEBUG_PK - buffer_dump(&b); - #endif -- pubkey_auth_info(authctxt, key, NULL); -+ pubkey = key_format_oneline(key); -+ auth_info(authctxt, "%s", pubkey); - - /* test for correct signature */ - authenticated = 0; - if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && - PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), -- buffer_len(&b))) == 1) -+ buffer_len(&b))) == 1) { -+ authctxt->last_details = pubkey; - authenticated = 1; -+ } else { -+ free(pubkey); -+ } - buffer_free(&b); - free(sig); - } else { -@@ -200,7 +205,7 @@ done: - void - pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) - { -- char *fp, *extra; -+ char *extra, *pubkey; - va_list ap; - int i; - -@@ -210,24 +215,13 @@ pubkey_auth_info(Authctxt *authctxt, con - i = vasprintf(&extra, fmt, ap); - va_end(ap); - if (i < 0 || extra == NULL) -- fatal("%s: vasprintf failed", __func__); -+ fatal("%s: vasprintf failed", __func__); - } - -- if (key_is_cert(key)) { -- fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -- auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", -- key_type(key), key->cert->key_id, -- (unsigned long long)key->cert->serial, -- key_type(key->cert->signature_key), fp, -- extra == NULL ? "" : ", ", extra == NULL ? "" : extra); -- free(fp); -- } else { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- auth_info(authctxt, "%s %s%s%s", key_type(key), fp, -- extra == NULL ? "" : ", ", extra == NULL ? "" : extra); -- free(fp); -- } -+ pubkey = key_format_oneline(key); -+ auth_info(authctxt, "%s%s%s", pubkey, extra == NULL ? "" : ", ", -+ extra == NULL ? "" : extra); -+ free(pubkey); - free(extra); - } - -diff -up openssh-6.6p1/auth.h.expose-auth openssh-6.6p1/auth.h ---- openssh-6.6p1/auth.h.expose-auth 2016-06-27 12:19:39.144443805 +0200 -+++ openssh-6.6p1/auth.h 2016-06-27 12:19:39.179443745 +0200 -@@ -78,6 +78,9 @@ struct Authctxt { - #endif - Buffer *loginmsg; - void *methoddata; -+ -+ char *last_details; -+ char *auth_details; - }; - /* - * Every authentication method has to handle authentication requests for -diff -up openssh-6.6p1/auth-pam.c.expose-auth openssh-6.6p1/auth-pam.c ---- openssh-6.6p1/auth-pam.c.expose-auth 2016-06-27 12:19:39.049443967 +0200 -+++ openssh-6.6p1/auth-pam.c 2016-06-27 12:19:39.179443745 +0200 -@@ -688,6 +688,11 @@ sshpam_init_ctx(Authctxt *authctxt) - return (NULL); - } - -+ /* Notify PAM about any already successful auth methods */ -+ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMONLY && -+ authctxt->auth_details) -+ do_pam_putenv("SSH_USER_AUTH", authctxt->auth_details); -+ - ctxt = xcalloc(1, sizeof *ctxt); - - /* Start the authentication thread */ -diff -up openssh-6.6p1/gss-serv.c.expose-auth openssh-6.6p1/gss-serv.c ---- openssh-6.6p1/gss-serv.c.expose-auth 2016-06-27 12:19:39.160443778 +0200 -+++ openssh-6.6p1/gss-serv.c 2016-06-27 12:19:39.180443743 +0200 -@@ -471,6 +471,16 @@ ssh_gssapi_userok(char *user, struct pas - return (0); - } - -+/* Privileged */ -+char* -+ssh_gssapi_get_displayname(void) -+{ -+ if (gssapi_client.displayname.length != 0 && -+ gssapi_client.displayname.value != NULL) -+ return strdup((char *)gssapi_client.displayname.value); -+ return NULL; -+} -+ - /* These bits are only used for rekeying. The unpriviledged child is running - * as the user, the monitor is root. - * -diff -up openssh-6.6p1/key.c.expose-auth openssh-6.6p1/key.c ---- openssh-6.6p1/key.c.expose-auth 2016-06-27 12:19:39.105443872 +0200 -+++ openssh-6.6p1/key.c 2016-06-27 12:19:39.180443743 +0200 -@@ -57,6 +57,7 @@ - #include "misc.h" - #include "ssh2.h" - #include "digest.h" -+#include "xmalloc.h" - - static int to_blob(const Key *, u_char **, u_int *, int); - static Key *key_from_blob2(const u_char *, u_int, int); -@@ -628,6 +629,30 @@ key_fingerprint(const Key *k, enum fp_ty - return retval; - } - -+char * -+key_format_oneline(const Key *key) -+{ -+ char *fp, *result; -+ -+ if (key_is_cert(key)) { -+ fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, -+ SSH_FP_HEX); -+ xasprintf(&result, "%s ID %s (serial %llu) CA %s %s", -+ key_type(key), key->cert->key_id, -+ (unsigned long long)key->cert->serial, -+ key_type(key->cert->signature_key), -+ fp == NULL ? "(null)" : fp); -+ free(fp); -+ } else { -+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ xasprintf(&result, "%s %s", key_type(key), -+ fp == NULL ? "(null)" : fp); -+ free(fp); -+ } -+ -+ return result; -+} -+ - enum fp_type - key_fingerprint_selection(void) - { -diff -up openssh-6.6p1/key.h.expose-auth openssh-6.6p1/key.h ---- openssh-6.6p1/key.h.expose-auth 2016-06-27 12:19:43.322436657 +0200 -+++ openssh-6.6p1/key.h 2016-06-27 12:20:25.898363835 +0200 -@@ -108,6 +108,7 @@ u_char *key_fingerprint_raw(const Key * - enum fp_type key_fingerprint_selection(void); - char *key_selected_fingerprint(Key *, enum fp_rep); - char *key_fingerprint_prefix(void); -+char *key_format_oneline(const Key *k); - const char *key_type(const Key *); - const char *key_cert_type(const Key *); - int key_write(const Key *, FILE *); -diff -up openssh-6.6p1/monitor.c.expose-auth openssh-6.6p1/monitor.c ---- openssh-6.6p1/monitor.c.expose-auth 2016-06-27 12:19:39.165443769 +0200 -+++ openssh-6.6p1/monitor.c 2016-06-27 12:19:39.180443743 +0200 -@@ -357,6 +357,7 @@ monitor_child_preauth(Authctxt *_authctx - { - struct mon_table *ent; - int authenticated = 0, partial = 0; -+ char *prev_auth_details; - - debug3("preauth child monitor started"); - -@@ -394,6 +395,18 @@ monitor_child_preauth(Authctxt *_authctx - auth_submethod = NULL; - authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); - -+ if (authenticated) { -+ prev_auth_details = authctxt->auth_details; -+ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", -+ prev_auth_details ? prev_auth_details : "", -+ prev_auth_details ? ", " : "", auth_method, -+ authctxt->last_details ? ": " : "", -+ authctxt->last_details ? authctxt->last_details : ""); -+ free(authctxt->last_details); -+ authctxt->last_details = NULL; -+ free(prev_auth_details); -+ } -+ - /* Special handling for multiple required authentications */ - if (options.num_auth_methods != 0) { - if (!compat20) -@@ -1432,6 +1445,9 @@ mm_answer_keyverify(int sock, Buffer *m) - debug3("%s: key %p signature %s", - __func__, key, (verified == 1) ? "verified" : "unverified"); - -+ if (verified == 1) -+ authctxt->last_details = key_format_oneline(key); -+ - key_free(key); - free(blob); - free(signature); -@@ -2224,6 +2240,9 @@ mm_answer_gss_userok(int sock, Buffer *m - - auth_method = "gssapi-with-mic"; - -+ if (authenticated) -+ authctxt->last_details = ssh_gssapi_get_displayname(); -+ - /* Monitor loop will terminate if authenticated */ - return (authenticated); - } -diff -up openssh-6.6p1/servconf.c.expose-auth openssh-6.6p1/servconf.c ---- openssh-6.6p1/servconf.c.expose-auth 2016-06-27 12:19:39.177443748 +0200 -+++ openssh-6.6p1/servconf.c 2016-06-27 12:19:39.181443742 +0200 -@@ -161,6 +161,7 @@ initialize_server_options(ServerOptions - options->version_addendum = NULL; - options->use_kuserok = -1; - options->enable_k5users = -1; -+ options->expose_auth_methods = -1; - } - - void -@@ -322,6 +323,8 @@ fill_default_server_options(ServerOption - options->use_kuserok = 1; - if (options->enable_k5users == -1) - options->enable_k5users = 0; -+ if (options->expose_auth_methods == -1) -+ options->expose_auth_methods = EXPOSE_AUTHMETH_NEVER; - - /* Turn privilege separation on by default */ - if (use_privsep == -1) -@@ -380,6 +383,7 @@ typedef enum { - sKexAlgorithms, sIPQoS, sVersionAddendum, - sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, - sAuthenticationMethods, sHostKeyAgent, -+ sExposeAuthenticationMethods, - sDeprecated, sUnsupported - } ServerOpCodes; - -@@ -523,6 +527,7 @@ static struct { - { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, - { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, - { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, -+ { "exposeauthenticationmethods", sExposeAuthenticationMethods, SSHCFG_ALL }, - { NULL, sBadOption, 0 } - }; - -@@ -869,6 +874,12 @@ static const struct multistate multistat - { "local", FORWARD_LOCAL }, - { NULL, -1 } - }; -+static const struct multistate multistate_exposeauthmeth[] = { -+ { "never", EXPOSE_AUTHMETH_NEVER }, -+ { "pam-only", EXPOSE_AUTHMETH_PAMONLY }, -+ { "pam-and-env", EXPOSE_AUTHMETH_PAMENV }, -+ { NULL, -1} -+}; - - int - process_server_config_line(ServerOptions *options, char *line, -@@ -1727,6 +1738,11 @@ process_server_config_line(ServerOptions - } - return 0; - -+ case sExposeAuthenticationMethods: -+ intptr = &options->expose_auth_methods; -+ multistate_ptr = multistate_exposeauthmeth; -+ goto parse_multistate; -+ - case sDeprecated: - logit("%s line %d: Deprecated option %s", - filename, linenum, arg); -@@ -1883,6 +1899,7 @@ copy_set_server_options(ServerOptions *d - M_CP_INTOPT(enable_k5users); - M_CP_INTOPT(rekey_limit); - M_CP_INTOPT(rekey_interval); -+ M_CP_INTOPT(expose_auth_methods); - - /* M_CP_STROPT and M_CP_STRARRAYOPT should not appear before here */ - #define M_CP_STROPT(n) do {\ -@@ -1971,6 +1988,8 @@ fmt_intarg(ServerOpCodes code, int val) - return fmt_multistate_int(val, multistate_privsep); - case sAllowTcpForwarding: - return fmt_multistate_int(val, multistate_tcpfwd); -+ case sExposeAuthenticationMethods: -+ return fmt_multistate_int(val, multistate_exposeauthmeth); - case sProtocol: - switch (val) { - case SSH_PROTO_1: -@@ -2182,6 +2201,7 @@ dump_config(ServerOptions *o) - dump_cfg_strarray(sAcceptEnv, o->num_accept_env, o->accept_env); - dump_cfg_strarray_oneline(sAuthenticationMethods, - o->num_auth_methods, o->auth_methods); -+ dump_cfg_fmtint(sExposeAuthenticationMethods, o->expose_auth_methods); - - /* other arguments */ - for (i = 0; i < o->num_subsystems; i++) -diff -up openssh-6.6p1/servconf.h.expose-auth openssh-6.6p1/servconf.h ---- openssh-6.6p1/servconf.h.expose-auth 2016-06-27 12:19:39.162443774 +0200 -+++ openssh-6.6p1/servconf.h 2016-06-27 12:19:39.181443742 +0200 -@@ -48,6 +48,11 @@ - #define FORWARD_LOCAL (1<<1) - #define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL) - -+/* Expose AuthenticationMethods */ -+#define EXPOSE_AUTHMETH_NEVER 0 -+#define EXPOSE_AUTHMETH_PAMONLY 1 -+#define EXPOSE_AUTHMETH_PAMENV 2 -+ - #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ - #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ - -@@ -190,6 +195,8 @@ typedef struct { - - u_int num_auth_methods; - char *auth_methods[MAX_AUTH_METHODS]; -+ -+ int expose_auth_methods; /* EXPOSE_AUTHMETH_* above */ - } ServerOptions; - - /* Information about the incoming connection as used by Match */ -diff -up openssh-6.6p1/session.c.expose-auth openssh-6.6p1/session.c ---- openssh-6.6p1/session.c.expose-auth 2016-06-27 12:19:39.171443759 +0200 -+++ openssh-6.6p1/session.c 2016-06-27 12:19:39.181443742 +0200 -@@ -1196,6 +1196,12 @@ copy_environment(char **source, char *** - } - *var_val++ = '\0'; - -+ if (options.expose_auth_methods < EXPOSE_AUTHMETH_PAMENV && -+ strcmp(var_name, "SSH_USER_AUTH") == 0) { -+ free(var_name); -+ continue; -+ } -+ - debug3("Copy environment: %s=%s", var_name, var_val); - child_set_env(env, envsize, var_name, var_val); - -@@ -1375,6 +1381,11 @@ do_setup_env(Session *s, const char *she - } - #endif /* USE_PAM */ - -+ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMENV && -+ s->authctxt->auth_details) -+ child_set_env(&env, &envsize, "SSH_USER_AUTH", -+ s->authctxt->auth_details); -+ - if (auth_sock_name != NULL) - child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, - auth_sock_name); -@@ -2805,6 +2816,9 @@ do_cleanup(Authctxt *authctxt) - if (authctxt == NULL) - return; - -+ free(authctxt->auth_details); -+ authctxt->auth_details = NULL; -+ - #ifdef USE_PAM - if (options.use_pam) { - sshpam_cleanup(); -diff -up openssh-6.6p1/ssh.1.expose-auth openssh-6.6p1/ssh.1 ---- openssh-6.6p1/ssh.1.expose-auth 2016-06-27 12:19:39.163443772 +0200 -+++ openssh-6.6p1/ssh.1 2016-06-27 12:19:39.181443742 +0200 -@@ -1289,6 +1289,10 @@ server IP address, and server port numbe - This variable contains the original command line if a forced command - is executed. - It can be used to extract the original arguments. -+.It Ev SSH_USER_AUTH -+This variable contains, for SSH2 only, a comma-separated list of authentication -+methods that were successfuly used to authenticate. When possible, these -+methods are extended with detailed information on the credential used. - .It Ev SSH_TTY - This is set to the name of the tty (path to the device) associated - with the current shell or command. -diff -up openssh-6.6p1/sshd_config.5.expose-auth openssh-6.6p1/sshd_config.5 ---- openssh-6.6p1/sshd_config.5.expose-auth 2016-06-27 12:19:39.177443748 +0200 -+++ openssh-6.6p1/sshd_config.5 2016-06-27 12:19:39.182443740 +0200 -@@ -466,6 +466,21 @@ is allowed to log in. - See PATTERNS in - .Xr ssh_config 5 - for more information on patterns. -+.It Cm ExposeAuthenticationMethods -+When using SSH2, this option controls the exposure of the list of -+successful authentication methods to PAM during the authentication -+and to the shell environment via the -+.Cm SSH_USER_AUTH -+variable. See the description of this variable for more details. -+Valid options are: -+.Dq never -+(Do not expose successful authentication methods), -+.Dq pam-only -+(Only expose them to PAM during authentication, not afterwards), -+.Dq pam-and-env -+(Expose them to PAM and keep them in the shell environment). -+The default is -+.Dq never . - .It Cm ForceCommand - Forces the execution of the command specified by - .Cm ForceCommand , -diff -up openssh-6.6p1/ssh-gss.h.expose-auth openssh-6.6p1/ssh-gss.h ---- openssh-6.6p1/ssh-gss.h.expose-auth 2016-06-27 12:19:39.163443772 +0200 -+++ openssh-6.6p1/ssh-gss.h 2016-06-27 12:19:39.182443740 +0200 -@@ -160,6 +160,7 @@ int ssh_gssapi_server_check_mech(Gssctxt - const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); - int ssh_gssapi_userok(char *name, struct passwd *); -+char* ssh_gssapi_get_displayname(void); - 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); diff --git a/SOURCES/openssh-6.6p1-fallback-X11-untrusted.patch b/SOURCES/openssh-6.6p1-fallback-X11-untrusted.patch deleted file mode 100644 index b7e7a7e..0000000 --- a/SOURCES/openssh-6.6p1-fallback-X11-untrusted.patch +++ /dev/null @@ -1,387 +0,0 @@ -From f98a09cacff7baad8748c9aa217afd155a4d493f Mon Sep 17 00:00:00 2001 -From: "mmcc@openbsd.org" -Date: Tue, 20 Oct 2015 03:36:35 +0000 -Subject: upstream commit - -Replace a function-local allocation with stack memory. - -ok djm@ - -Upstream-ID: c09fbbab637053a2ab9f33ca142b4e20a4c5a17e ---- - clientloop.c | 9 ++------- - 1 file changed, 2 insertions(+), 7 deletions(-) - -diff --git a/clientloop.c b/clientloop.c -index 87ceb3d..1e05cba 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -311,11 +311,10 @@ client_x11_get_proto(const char *display, const char *xauth_path, - static char proto[512], data[512]; - FILE *f; - int got_data = 0, generated = 0, do_unlink = 0, i; -- char *xauthdir, *xauthfile; -+ char xauthdir[MAXPATHLEN] = "", xauthfile[MAXPATHLEN] = ""; - struct stat st; - u_int now, x11_timeout_real; - -- xauthdir = xauthfile = NULL; - *_proto = proto; - *_data = data; - proto[0] = data[0] = '\0'; -@@ -343,8 +342,6 @@ client_x11_get_proto(const char *display, const char *xauth_path, - display = xdisplay; - } - if (trusted == 0) { -- xauthdir = xmalloc(MAXPATHLEN); -- xauthfile = xmalloc(MAXPATHLEN); - mktemp_proto(xauthdir, MAXPATHLEN); - /* - * The authentication cookie should briefly outlive -@@ -407,8 +404,6 @@ client_x11_get_proto(const char *display, const char *xauth_path, - unlink(xauthfile); - rmdir(xauthdir); - } -- free(xauthdir); -- free(xauthfile); - - /* - * If we didn't get authentication data, just make up some --- -cgit v0.11.2 - -From ed4ce82dbfa8a3a3c8ea6fa0db113c71e234416c Mon Sep 17 00:00:00 2001 -From: "djm@openbsd.org" -Date: Wed, 13 Jan 2016 23:04:47 +0000 -Subject: upstream commit - -eliminate fallback from untrusted X11 forwarding to trusted - forwarding when the X server disables the SECURITY extension; Reported by - Thomas Hoger; ok deraadt@ - -Upstream-ID: f76195bd2064615a63ef9674a0e4096b0713f938 ---- - clientloop.c | 114 ++++++++++++++++++++++++++++++++++++----------------------- - clientloop.h | 4 +-- - mux.c | 22 ++++++------ - ssh.c | 23 +++++------- - 4 files changed, 93 insertions(+), 70 deletions(-) - -diff --git a/clientloop.c b/clientloop.c -index f555451..c0386d5 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -288,6 +288,9 @@ client_x11_display_valid(const char *display) - { - size_t i, dlen; - -+ if (display == NULL) -+ return 0; -+ - dlen = strlen(display); - for (i = 0; i < dlen; i++) { - if (!isalnum((u_char)display[i]) && -@@ -301,34 +304,33 @@ client_x11_display_valid(const char *display) - - #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" - #define X11_TIMEOUT_SLACK 60 --void -+int - client_x11_get_proto(const char *display, const char *xauth_path, - u_int trusted, u_int timeout, char **_proto, char **_data) - { -- char cmd[1024]; -- char line[512]; -- char xdisplay[512]; -+ char cmd[1024], line[512], xdisplay[512]; -+ char xauthfile[MAXPATHLEN], xauthdir[MAXPATHLEN]; - static char proto[512], data[512]; - FILE *f; -- int got_data = 0, generated = 0, do_unlink = 0, i; -- char xauthdir[MAXPATHLEN] = "", xauthfile[MAXPATHLEN] = ""; -+ int got_data = 0, generated = 0, do_unlink = 0, i, r; - struct stat st; - u_int now, x11_timeout_real; - - *_proto = proto; - *_data = data; -- proto[0] = data[0] = '\0'; -+ proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; - -- if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) { -- debug("No xauth program."); -- } else if (!client_x11_display_valid(display)) { -- logit("DISPLAY '%s' invalid, falling back to fake xauth data", -+ if (!client_x11_display_valid(display)) { -+ logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", - display); -- } else { -- if (display == NULL) { -- debug("x11_get_proto: DISPLAY not set"); -- return; -- } -+ return -1; -+ } -+ if (xauth_path != NULL && stat(xauth_path, &st) == -1) { -+ debug("No xauth program."); -+ xauth_path = NULL; -+ } -+ -+ if (xauth_path != NULL) { - /* - * Handle FamilyLocal case where $DISPLAY does - * not match an authorization entry. For this we -@@ -337,43 +339,60 @@ client_x11_get_proto(const char *display, const char *xauth_path, - * is not perfect. - */ - if (strncmp(display, "localhost:", 10) == 0) { -- snprintf(xdisplay, sizeof(xdisplay), "unix:%s", -- display + 10); -+ if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", -+ display + 10)) < 0 || -+ (size_t)r >= sizeof(xdisplay)) { -+ error("%s: display name too long", __func__); -+ return -1; -+ } - display = xdisplay; - } - if (trusted == 0) { -- mktemp_proto(xauthdir, MAXPATHLEN); - /* -+ * Generate an untrusted X11 auth cookie. -+ * - * The authentication cookie should briefly outlive - * ssh's willingness to forward X11 connections to - * avoid nasty fail-open behaviour in the X server. - */ -+ mktemp_proto(xauthdir, sizeof(xauthdir)); -+ if (mkdtemp(xauthdir) == NULL) { -+ error("%s: mkdtemp: %s", -+ __func__, strerror(errno)); -+ return -1; -+ } -+ do_unlink = 1; -+ if ((r = snprintf(xauthfile, sizeof(xauthfile), -+ "%s/xauthfile", xauthdir)) < 0 || -+ (size_t)r >= sizeof(xauthfile)) { -+ error("%s: xauthfile path too long", __func__); -+ unlink(xauthfile); -+ rmdir(xauthdir); -+ return -1; -+ } -+ - if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) - x11_timeout_real = UINT_MAX; - else - x11_timeout_real = timeout + X11_TIMEOUT_SLACK; -- if (mkdtemp(xauthdir) != NULL) { -- do_unlink = 1; -- snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", -- xauthdir); -- snprintf(cmd, sizeof(cmd), -- "%s -f %s generate %s " SSH_X11_PROTO -- " untrusted timeout %u 2>" _PATH_DEVNULL, -- xauth_path, xauthfile, display, -- x11_timeout_real); -- debug2("x11_get_proto: %s", cmd); -- if (x11_refuse_time == 0) { -- now = monotime() + 1; -- if (UINT_MAX - timeout < now) -- x11_refuse_time = UINT_MAX; -- else -- x11_refuse_time = now + timeout; -- channel_set_x11_refuse_time( -- x11_refuse_time); -- } -- if (system(cmd) == 0) -- generated = 1; -+ if ((r = snprintf(cmd, sizeof(cmd), -+ "%s -f %s generate %s " SSH_X11_PROTO -+ " untrusted timeout %u 2>" _PATH_DEVNULL, -+ xauth_path, xauthfile, display, -+ x11_timeout_real)) < 0 || -+ (size_t)r >= sizeof(cmd)) -+ fatal("%s: cmd too long", __func__); -+ debug2("%s: %s", __func__, cmd); -+ if (x11_refuse_time == 0) { -+ now = monotime() + 1; -+ if (UINT_MAX - timeout < now) -+ x11_refuse_time = UINT_MAX; -+ else -+ x11_refuse_time = now + timeout; -+ channel_set_x11_refuse_time(x11_refuse_time); - } -+ if (system(cmd) == 0) -+ generated = 1; - } - - /* -@@ -395,9 +414,7 @@ client_x11_get_proto(const char *display, const char *xauth_path, - got_data = 1; - if (f) - pclose(f); -- } else -- error("Warning: untrusted X11 forwarding setup failed: " -- "xauth key data not generated"); -+ } - } - - if (do_unlink) { -@@ -405,6 +422,13 @@ client_x11_get_proto(const char *display, const char *xauth_path, - rmdir(xauthdir); - } - -+ /* Don't fall back to fake X11 data for untrusted forwarding */ -+ if (!trusted && !got_data) { -+ error("Warning: untrusted X11 forwarding setup failed: " -+ "xauth key data not generated"); -+ return -1; -+ } -+ - /* - * If we didn't get authentication data, just make up some - * data. The forwarding code will check the validity of the -@@ -427,6 +451,8 @@ client_x11_get_proto(const char *display, const char *xauth_path, - rnd >>= 8; - } - } -+ -+ return 0; - } - - /* -diff --git a/clientloop.h b/clientloop.h -index 338d451..f4d4c69 100644 ---- a/clientloop.h -+++ b/clientloop.h -@@ -39,7 +39,7 @@ - - /* Client side main loop for the interactive session. */ - int client_loop(int, int, int); --void client_x11_get_proto(const char *, const char *, u_int, u_int, -+int client_x11_get_proto(const char *, const char *, u_int, u_int, - char **, char **); - void client_global_request_reply_fwd(int, u_int32_t, void *); - void client_session2_setup(int, int, int, const char *, struct termios *, -diff --git a/mux.c b/mux.c -index f9c3af6..6bf53eb 100644 ---- a/mux.c -+++ b/mux.c -@@ -1354,16 +1354,18 @@ mux_session_confirm(int id, int success, void *arg) - char *proto, *data; - - /* Get reasonable local authentication information. */ -- client_x11_get_proto(display, options.xauth_location, -+ if (client_x11_get_proto(display, options.xauth_location, - options.forward_x11_trusted, options.forward_x11_timeout, -- &proto, &data); -- /* Request forwarding with authentication spoofing. */ -- debug("Requesting X11 forwarding with authentication " -- "spoofing."); -- x11_request_forwarding_with_spoofing(id, display, proto, -- data, 1); -- client_expect_confirm(id, "X11 forwarding", CONFIRM_WARN); -- /* XXX exit_on_forward_failure */ -+ &proto, &data) == 0) { -+ /* Request forwarding with authentication spoofing. */ -+ debug("Requesting X11 forwarding with authentication " -+ "spoofing."); -+ x11_request_forwarding_with_spoofing(id, display, proto, -+ data, 1); -+ /* XXX exit_on_forward_failure */ -+ client_expect_confirm(id, "X11 forwarding", -+ CONFIRM_WARN); -+ } - } - - if (cctx->want_agent_fwd && options.forward_agent) { -diff --git a/ssh.c b/ssh.c -index 81704ab..096c5b5 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1626,6 +1626,7 @@ ssh_session(void) - struct winsize ws; - char *cp; - const char *display; -+ char *proto = NULL, *data = NULL; - - /* Enable compression if requested. */ - if (options.compression) { -@@ -1696,13 +1697,9 @@ ssh_session(void) - } - /* Request X11 forwarding if enabled and DISPLAY is set. */ - display = getenv("DISPLAY"); -- if (options.forward_x11 && display != NULL) { -- char *proto, *data; -- /* Get reasonable local authentication information. */ -- client_x11_get_proto(display, options.xauth_location, -- options.forward_x11_trusted, -- options.forward_x11_timeout, -- &proto, &data); -+ if (options.forward_x11 && client_x11_get_proto(display, -+ options.xauth_location, options.forward_x11_trusted, -+ options.forward_x11_timeout, &proto, &data) == 0) { - /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication " - "spoofing."); -@@ -1792,6 +1789,7 @@ ssh_session2_setup(int id, int success, void *arg) - extern char **environ; - const char *display; - int interactive = tty_flag; -+ char *proto = NULL, *data = NULL; - - if (!success) - return; /* No need for error message, channels code sens one */ -@@ -1799,12 +1797,9 @@ ssh_session2_setup(int id, int success, void *arg) - return; /* No need for error message, channels code sens one */ - - display = getenv("DISPLAY"); -- if (options.forward_x11 && display != NULL) { -- char *proto, *data; -- /* Get reasonable local authentication information. */ -- client_x11_get_proto(display, options.xauth_location, -- options.forward_x11_trusted, -- options.forward_x11_timeout, &proto, &data); -+ if (options.forward_x11 && client_x11_get_proto(display, -+ options.xauth_location, options.forward_x11_trusted, -+ options.forward_x11_timeout, &proto, &data) == 0) { - /* Request forwarding with authentication spoofing. */ - debug("Requesting X11 forwarding with authentication " - "spoofing."); --- -cgit v0.11.2 - -From 5658ef2501e785fbbdf5de2dc33b1ff7a4dca73a Mon Sep 17 00:00:00 2001 -From: "millert@openbsd.org" -Date: Mon, 1 Feb 2016 21:18:17 +0000 -Subject: upstream commit - -Avoid ugly "DISPLAY "(null)" invalid; disabling X11 - forwarding" message when DISPLAY is not set. This could also result in a - crash on systems with a printf that doesn't handle NULL. OK djm@ - -Upstream-ID: 20ee0cfbda678a247264c20ed75362042b90b412 ---- - clientloop.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/clientloop.c b/clientloop.c -index f8f9a3f..f0a08f2 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -318,8 +318,9 @@ client_x11_get_proto(const char *display, const char *xauth_path, - proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; - - if (!client_x11_display_valid(display)) { -- logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", -- display); -+ if (display != NULL) -+ logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", -+ display); - return -1; - } - if (xauth_path != NULL && stat(xauth_path, &st) == -1) { --- -cgit v0.11.2 - - diff --git a/SOURCES/openssh-6.6p1-fingerprint.patch b/SOURCES/openssh-6.6p1-fingerprint.patch deleted file mode 100644 index c5332fb..0000000 --- a/SOURCES/openssh-6.6p1-fingerprint.patch +++ /dev/null @@ -1,415 +0,0 @@ -diff --git a/auth.c b/auth.c -index 9a36f1d..420a85b 100644 ---- a/auth.c -+++ b/auth.c -@@ -685,9 +685,10 @@ auth_key_is_revoked(Key *key) - case 1: - revoked: - /* Key revoked */ -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_selected_fingerprint(key, SSH_FP_HEX); - error("WARNING: authentication attempt with a revoked " -- "%s key %s ", key_type(key), key_fp); -+ "%s key %s%s ", key_type(key), -+ key_fingerprint_prefix(), key_fp); - free(key_fp); - return 1; - } -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 488008f..eca0069 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -206,16 +206,18 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, - - if (host_status == HOST_OK) { - if (key_is_cert(key)) { -- fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key->cert->signature_key, -+ SSH_FP_HEX); - verbose("Accepted certificate ID \"%s\" signed by " -- "%s CA %s from %s@%s", key->cert->key_id, -- key_type(key->cert->signature_key), fp, -+ "%s CA %s%s from %s@%s", key->cert->key_id, -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), fp, - cuser, lookup); - } else { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- verbose("Accepted %s public key %s from %s@%s", -- key_type(key), fp, cuser, lookup); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ verbose("Accepted %s public key %s%s from %s@%s", -+ key_type(key), key_fingerprint_prefix(), -+ fp, cuser, lookup); - } - free(fp); - } -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 0fd27bb..749b11a 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -365,10 +365,10 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) - continue; - if (!key_is_cert_authority) - continue; -- fp = key_fingerprint(found, SSH_FP_MD5, -- SSH_FP_HEX); -- debug("matching CA found: file %s, line %lu, %s %s", -- file, linenum, key_type(found), fp); -+ fp = key_selected_fingerprint(found, SSH_FP_HEX); -+ debug("matching CA found: file %s, line %lu, %s %s%s", -+ file, linenum, key_type(found), -+ key_fingerprint_prefix(), fp); - /* - * If the user has specified a list of principals as - * a key option, then prefer that list to matching -@@ -406,9 +406,9 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) - if (key_is_cert_authority) - continue; - found_key = 1; -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -- debug("matching key found: file %s, line %lu %s %s", -- file, linenum, key_type(found), fp); -+ fp = key_selected_fingerprint(found, SSH_FP_HEX); -+ verbose("Found matching %s key: %s%s", -+ key_type(found), key_fingerprint_prefix(), fp); - free(fp); - break; - } -@@ -431,13 +431,13 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) - if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) - return 0; - -- ca_fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX); - - if (key_in_file(key->cert->signature_key, - options.trusted_user_ca_keys, 1) != 1) { -- debug2("%s: CA %s %s is not listed in %s", __func__, -- key_type(key->cert->signature_key), ca_fp, -+ debug2("%s: CA %s%s %s is not listed in %s", __func__, -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), ca_fp, - options.trusted_user_ca_keys); - goto out; - } -diff --git a/key.c b/key.c -index 168e1b7..eb98ea8 100644 ---- a/key.c -+++ b/key.c -@@ -628,6 +628,34 @@ key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) - return retval; - } - -+enum fp_type -+key_fingerprint_selection(void) -+{ -+ static enum fp_type rv; -+ static char rv_defined = 0; -+ char *env; -+ -+ if (!rv_defined) { -+ env = getenv("SSH_FINGERPRINT_TYPE"); -+ rv = (env && !strcmp (env, "sha")) ? -+ SSH_FP_SHA1 : SSH_FP_MD5; -+ rv_defined = 1; -+ } -+ return rv; -+} -+ -+char * -+key_selected_fingerprint(Key *k, enum fp_rep dgst_rep) -+{ -+ return key_fingerprint(k, key_fingerprint_selection(), dgst_rep); -+} -+ -+char * -+key_fingerprint_prefix(void) -+{ -+ return key_fingerprint_selection() == SSH_FP_SHA1 ? "sha1:" : ""; -+} -+ - /* - * Reads a multiple-precision integer in decimal from the buffer, and advances - * the pointer. The integer must already be initialized. This function is -diff --git a/key.h b/key.h -index d8ad13d..0e3eea5 100644 ---- a/key.h -+++ b/key.h -@@ -104,6 +104,9 @@ int key_equal_public(const Key *, const Key *); - int key_equal(const Key *, const Key *); - char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); - u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); -+enum fp_type key_fingerprint_selection(void); -+char *key_selected_fingerprint(Key *, enum fp_rep); -+char *key_fingerprint_prefix(void); - const char *key_type(const Key *); - const char *key_cert_type(const Key *); - int key_write(const Key *, FILE *); -diff --git a/ssh-add.c b/ssh-add.c -index 3421452..691949f 100644 ---- a/ssh-add.c -+++ b/ssh-add.c -@@ -330,10 +330,10 @@ list_identities(AuthenticationConnection *ac, int do_fp) - key = ssh_get_next_identity(ac, &comment, version)) { - had_identities = 1; - if (do_fp) { -- fp = key_fingerprint(key, SSH_FP_MD5, -- SSH_FP_HEX); -- printf("%d %s %s (%s)\n", -- key_size(key), fp, comment, key_type(key)); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ printf("%d %s%s %s (%s)\n", -+ key_size(key), key_fingerprint_prefix(), -+ fp, comment, key_type(key)); - free(fp); - } else { - if (!key_write(key, stdout)) -diff --git a/ssh-agent.c b/ssh-agent.c -index ba24612..117fdde 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -198,9 +198,9 @@ confirm_key(Identity *id) - char *p; - int ret = -1; - -- p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); -- if (ask_permission("Allow use of key %s?\nKey fingerprint %s.", -- id->comment, p)) -+ p = key_selected_fingerprint(id->key, SSH_FP_HEX); -+ if (ask_permission("Allow use of key %s?\nKey fingerprint %s%s.", -+ id->comment, key_fingerprint_prefix(), p)) - ret = 0; - free(p); - -diff --git a/ssh-keygen.c b/ssh-keygen.c -index 2a316bc..482dc1c 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -783,13 +783,14 @@ do_fingerprint(struct passwd *pw) - { - FILE *f; - Key *public; -- char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra; -+ char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra, *pfx; - int i, skip = 0, num = 0, invalid = 1; - enum fp_rep rep; - enum fp_type fptype; - struct stat st; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); -+ pfx = print_bubblebabble ? "" : key_fingerprint_prefix(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; - - if (!have_identity) -@@ -801,8 +802,8 @@ do_fingerprint(struct passwd *pw) - public = key_load_public(identity_file, &comment); - if (public != NULL) { - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, comment, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, comment, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -867,8 +868,8 @@ do_fingerprint(struct passwd *pw) - } - comment = *cp ? cp : comment; - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, - comment ? comment : "no comment", key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -986,13 +987,15 @@ printhost(FILE *f, const char *name, Key *public, int ca, int hash) - if (print_fingerprint) { - enum fp_rep rep; - enum fp_type fptype; -- char *fp, *ra; -+ char *fp, *ra, *pfx; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); -+ pfx = print_bubblebabble ? "" : key_fingerprint_prefix(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; -+ - fp = key_fingerprint(public, fptype, rep); -- ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); -- printf("%u %s %s (%s)\n", key_size(public), fp, name, -+ ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); -+ printf("%u %s%s %s (%s)\n", key_size(public), pfx, fp, name, - key_type(public)); - if (log_level >= SYSLOG_LEVEL_VERBOSE) - printf("%s\n", ra); -@@ -1878,16 +1881,17 @@ do_show_cert(struct passwd *pw) - fatal("%s is not a certificate", identity_file); - v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; - -- key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- ca_fp = key_fingerprint(key->cert->signature_key, -- SSH_FP_MD5, SSH_FP_HEX); -+ key_fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ ca_fp = key_selected_fingerprint(key->cert->signature_key, SSH_FP_HEX); - - printf("%s:\n", identity_file); - printf(" Type: %s %s certificate\n", key_ssh_name(key), - key_cert_type(key)); -- printf(" Public key: %s %s\n", key_type(key), key_fp); -- printf(" Signing CA: %s %s\n", -- key_type(key->cert->signature_key), ca_fp); -+ printf(" Public key: %s %s%s\n", key_type(key), -+ key_fingerprint_prefix(), key_fp); -+ printf(" Signing CA: %s %s%s\n", -+ key_type(key->cert->signature_key), -+ key_fingerprint_prefix(), ca_fp); - printf(" Key ID: \"%s\"\n", key->cert->key_id); - if (!v00) { - printf(" Serial: %llu\n", -@@ -2686,13 +2690,12 @@ passphrase_again: - fclose(f); - - if (!quiet) { -- char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); -- char *ra = key_fingerprint(public, SSH_FP_MD5, -- SSH_FP_RANDOMART); -+ char *fp = key_selected_fingerprint(public, SSH_FP_HEX); -+ char *ra = key_selected_fingerprint(public, SSH_FP_RANDOMART); - printf("Your public key has been saved in %s.\n", - identity_file); - printf("The key fingerprint is:\n"); -- printf("%s %s\n", fp, comment); -+ printf("%s%s %s\n", key_fingerprint_prefix(), fp, comment); - printf("The key's randomart image is:\n"); - printf("%s\n", ra); - free(ra); -diff --git a/sshconnect.c b/sshconnect.c -index 573d7a8..394cca8 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -914,10 +914,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - "key for IP address '%.128s' to the list " - "of known hosts.", type, ip); - } else if (options.visual_host_key) { -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(host_key, SSH_FP_MD5, -- SSH_FP_RANDOMART); -- logit("Host key fingerprint is %s\n%s\n", fp, ra); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART); -+ logit("Host key fingerprint is %s%s\n%s\n", -+ key_fingerprint_prefix(), fp, ra); - free(ra); - free(fp); - } -@@ -955,9 +955,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - else - snprintf(msg1, sizeof(msg1), "."); - /* The default */ -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(host_key, SSH_FP_MD5, -- SSH_FP_RANDOMART); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(host_key, SSH_FP_RANDOMART); - msg2[0] = '\0'; - if (options.verify_host_key_dns) { - if (matching_host_key_dns) -@@ -972,10 +971,11 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, - 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" -+ "%s key fingerprint is %s%s.%s%s\n%s" - "Are you sure you want to continue connecting " - "(yes/no)? ", -- host, ip, msg1, type, fp, -+ host, ip, msg1, type, -+ key_fingerprint_prefix(), fp, - options.visual_host_key ? "\n" : "", - options.visual_host_key ? ra : "", - msg2); -@@ -1220,8 +1220,9 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) - int flags = 0; - char *fp; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -- debug("Server host key: %s %s", key_type(host_key), fp); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); -+ debug("Server host key: %s %s%s", key_type(host_key), -+ key_fingerprint_prefix(), fp); - free(fp); - - /* XXX certs are not yet supported for DNS */ -@@ -1327,14 +1328,15 @@ show_other_keys(struct hostkeys *hostkeys, Key *key) - continue; - if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) - continue; -- fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); -- ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); -+ fp = key_selected_fingerprint(found->key, SSH_FP_HEX); -+ ra = key_selected_fingerprint(found->key, SSH_FP_RANDOMART); - logit("WARNING: %s key found for host %s\n" - "in %s:%lu\n" -- "%s key fingerprint %s.", -+ "%s key fingerprint %s%s.", - key_type(found->key), - found->host, found->file, found->line, -- key_type(found->key), fp); -+ key_type(found->key), -+ key_fingerprint_prefix(), fp); - if (options.visual_host_key) - logit("%s", ra); - free(ra); -@@ -1349,7 +1351,7 @@ warn_changed_key(Key *host_key) - { - char *fp; - -- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(host_key, SSH_FP_HEX); - - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); -@@ -1357,8 +1359,8 @@ warn_changed_key(Key *host_key) - error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); - error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); - error("It is also possible that a host key has just been changed."); -- error("The fingerprint for the %s key sent by the remote host is\n%s.", -- key_type(host_key), fp); -+ error("The fingerprint for the %s key sent by the remote host is\n%s%s.", -+ key_type(host_key),key_fingerprint_prefix(), fp); - error("Please contact your system administrator."); - - free(fp); -diff --git a/sshconnect2.c b/sshconnect2.c -index 7f4ff41..adbbfc7 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -577,8 +577,9 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) - key->type, pktype); - goto done; - } -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -- debug2("input_userauth_pk_ok: fp %s", fp); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); -+ debug2("input_userauth_pk_ok: fp %s%s", -+ key_fingerprint_prefix(), fp); - free(fp); - - /* -@@ -986,8 +987,9 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) - int have_sig = 1; - char *fp; - -- fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); -- debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp); -+ fp = key_selected_fingerprint(id->key, SSH_FP_HEX); -+ debug3("sign_and_send_pubkey: %s %s%s", key_type(id->key), -+ key_fingerprint_prefix(), fp); - free(fp); - - if (key_to_blob(id->key, &blob, &bloblen) == 0) { diff --git a/SOURCES/openssh-6.6p1-fips.patch b/SOURCES/openssh-6.6p1-fips.patch deleted file mode 100644 index a9a3145..0000000 --- a/SOURCES/openssh-6.6p1-fips.patch +++ /dev/null @@ -1,832 +0,0 @@ -diff -up openssh-6.6p1/Makefile.in.fips openssh-6.6p1/Makefile.in ---- openssh-6.6p1/Makefile.in.fips 2015-08-13 15:09:43.343350136 +0200 -+++ openssh-6.6p1/Makefile.in 2015-08-13 15:09:43.356350114 +0200 -@@ -154,25 +154,25 @@ libssh.a: $(LIBSSH_OBJS) - $(RANLIB) $@ - - ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) -- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) -+ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS) - - sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) -- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) -+ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -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) - - ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o -- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o -- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) - - ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o -- $(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 roaming_dummy.o readconf.o -- $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -+ $(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.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) -@@ -187,7 +187,7 @@ ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libs - $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) - - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o -- $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -+ $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) - - sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o - $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) -diff -up openssh-6.6p1/auth-rsa.c.fips openssh-6.6p1/auth-rsa.c ---- openssh-6.6p1/auth-rsa.c.fips 2015-08-13 15:09:43.344350134 +0200 -+++ openssh-6.6p1/auth-rsa.c 2015-08-13 15:09:43.354350118 +0200 -@@ -244,7 +244,7 @@ rsa_key_allowed_in_file(struct passwd *p - "actual %d vs. announced %d.", - file, linenum, BN_num_bits(key->rsa->n), bits); - -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); - debug("matching key found: file %s, line %lu %s %s", - file, linenum, key_type(key), fp); - free(fp); -diff -up openssh-6.6p1/auth2-pubkey.c.fips openssh-6.6p1/auth2-pubkey.c -diff -up openssh-6.6p1/authfile.c.fips openssh-6.6p1/authfile.c ---- openssh-6.6p1/authfile.c.fips 2016-06-27 09:51:39.334362038 +0200 -+++ openssh-6.6p1/authfile.c 2016-06-27 09:51:39.443361948 +0200 -@@ -46,6 +46,7 @@ - #include - #include - #include -+#include - - /* compatibility with old or broken OpenSSL versions */ - #include "openbsd-compat/openssl-compat.h" -@@ -1008,7 +1009,10 @@ key_parse_private_type(Buffer *blob, int - - switch (type) { - case KEY_RSA1: -- return key_parse_private_rsa1(blob, passphrase, commentp); -+ if (! FIPS_mode()) -+ return key_parse_private_rsa1(blob, passphrase, commentp); -+ error("%s: cannot parse rsa1 key in FIPS mode", __func__); -+ break; - case KEY_DSA: - case KEY_ECDSA: - case KEY_RSA: -@@ -1068,7 +1072,7 @@ Key * - key_parse_private(Buffer *buffer, const char *filename, - const char *passphrase, char **commentp) - { -- Key *pub, *prv; -+ Key *pub, *prv = NULL; - - /* it's a SSH v1 key if the public key part is readable */ - pub = key_parse_public_rsa1(buffer, commentp); -@@ -1080,9 +1084,10 @@ key_parse_private(Buffer *buffer, const - *commentp = xstrdup(filename); - } else { - key_free(pub); -- /* key_parse_public_rsa1() has already loaded the comment */ -- prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, -- NULL); -+ if (! FIPS_mode()) -+ /* key_parse_public_rsa1() has already loaded the comment */ -+ prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, -+ NULL); - } - return prv; - } -diff -up openssh-6.6p1/cipher-ctr.c.fips openssh-6.6p1/cipher-ctr.c ---- openssh-6.6p1/cipher-ctr.c.fips 2015-08-13 15:09:43.254350286 +0200 -+++ openssh-6.6p1/cipher-ctr.c 2015-08-13 15:09:43.354350118 +0200 -@@ -179,7 +179,8 @@ evp_aes_128_ctr(void) - aes_ctr.do_cipher = ssh_aes_ctr; - #ifndef SSH_OLD_EVP - aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | -- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; -+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV | -+ EVP_CIPH_FLAG_FIPS; - #endif - return (&aes_ctr); - } -diff -up openssh-6.6p1/cipher.c.fips openssh-6.6p1/cipher.c ---- openssh-6.6p1/cipher.c.fips 2015-08-13 15:09:43.345350133 +0200 -+++ openssh-6.6p1/cipher.c 2015-08-13 15:09:43.354350118 +0200 -@@ -39,6 +39,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -90,6 +92,25 @@ static const struct Cipher ciphers[] = { - { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } - }; - -+static const struct Cipher fips_ciphers[] = { -+ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, -+ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, -+ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, -+ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, -+ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, -+ { "rijndael-cbc@lysator.liu.se", -+ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, -+ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, -+ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, -+ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, -+#ifdef OPENSSL_HAVE_EVPGCM -+ { "aes128-gcm@openssh.com", -+ SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, -+ { "aes256-gcm@openssh.com", -+ SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, -+#endif -+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } -+}; - /*--*/ - - /* Returns a list of supported ciphers separated by the specified char. */ -@@ -100,7 +121,7 @@ cipher_alg_list(char sep, int auth_only) - size_t nlen, rlen = 0; - const Cipher *c; - -- for (c = ciphers; c->name != NULL; c++) { -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) { - if (c->number != SSH_CIPHER_SSH2) - continue; - if (auth_only && c->auth_len == 0) -@@ -180,7 +201,7 @@ const Cipher * - cipher_by_name(const char *name) - { - const Cipher *c; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (strcmp(c->name, name) == 0) - return c; - return NULL; -@@ -190,7 +211,7 @@ const Cipher * - cipher_by_number(int id) - { - const Cipher *c; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (c->number == id) - return c; - return NULL; -@@ -232,7 +253,7 @@ cipher_number(const char *name) - const Cipher *c; - if (name == NULL) - return -1; -- for (c = ciphers; c->name != NULL; c++) -+ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) - if (strcasecmp(c->name, name) == 0) - return c->number; - return -1; -diff -up openssh-6.6p1/dh.h.fips openssh-6.6p1/dh.h ---- openssh-6.6p1/dh.h.fips 2013-10-10 01:32:40.000000000 +0200 -+++ openssh-6.6p1/dh.h 2015-08-13 15:09:43.354350118 +0200 -@@ -45,6 +45,7 @@ int dh_estimate(int); - - /* Min and max values from RFC4419. */ - #define DH_GRP_MIN 1024 -+#define DH_GRP_MIN_FIPS 2048 - #define DH_GRP_MAX 8192 - - /* -diff -up openssh-6.6p1/entropy.c.fips openssh-6.6p1/entropy.c ---- openssh-6.6p1/entropy.c.fips 2015-08-13 15:09:43.238350313 +0200 -+++ openssh-6.6p1/entropy.c 2015-08-13 15:09:43.355350116 +0200 -@@ -222,6 +222,9 @@ seed_rng(void) - fatal("OpenSSL version mismatch. Built against %lx, you " - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - -+ /* clean the PRNG status when exiting the program */ -+ atexit(RAND_cleanup); -+ - #ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { - debug3("RNG is ready, skipping seeding"); -diff -up openssh-6.6p1/kex.c.fips openssh-6.6p1/kex.c ---- openssh-6.6p1/kex.c.fips 2015-08-13 15:09:43.350350124 +0200 -+++ openssh-6.6p1/kex.c 2015-08-13 15:09:43.355350116 +0200 -@@ -34,6 +34,7 @@ - #include - - #include -+#include - - #include "xmalloc.h" - #include "ssh2.h" -@@ -103,6 +104,25 @@ static const struct kexalg kexalgs[] = { - { NULL, -1, -1, -1}, - }; - -+static const struct kexalg kexalgs_fips[] = { -+ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+#ifdef HAVE_EVP_SHA256 -+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, -+#endif -+#ifdef OPENSSL_HAS_ECC -+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, -+ SSH_DIGEST_SHA384 }, -+# ifdef OPENSSL_HAS_NISTP521 -+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, -+ SSH_DIGEST_SHA512 }, -+# endif -+#endif -+ { NULL, -1, -1, NULL}, -+}; -+ - char * - kex_alg_list(char sep) - { -@@ -126,7 +146,7 @@ kex_alg_by_name(const char *name) - { - const struct kexalg *k; - -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) - return k; - #ifdef GSSAPI -@@ -151,7 +171,10 @@ kex_names_valid(const char *names) - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (kex_alg_by_name(p) == NULL) { -- error("Unsupported KEX algorithm \"%.100s\"", p); -+ if (FIPS_mode()) -+ error("\"%.100s\" is not allowed in FIPS mode", p); -+ else -+ error("Unsupported KEX algorithm \"%.100s\"", p); - free(s); - return 0; - } -diff -up openssh-6.6p1/kexecdhc.c.fips openssh-6.6p1/kexecdhc.c ---- openssh-6.6p1/kexecdhc.c.fips 2014-02-04 01:20:15.000000000 +0100 -+++ openssh-6.6p1/kexecdhc.c 2015-08-13 15:09:43.355350116 +0200 -@@ -154,6 +154,7 @@ kexecdh_client(Kex *kex) - - kex_derive_keys_bn(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); -+ memset(hash, 0, hashlen); - kex_finish(kex); - } - #else /* OPENSSL_HAS_ECC */ -diff -up openssh-6.6p1/kexecdhs.c.fips openssh-6.6p1/kexecdhs.c ---- openssh-6.6p1/kexecdhs.c.fips 2014-02-04 01:20:15.000000000 +0100 -+++ openssh-6.6p1/kexecdhs.c 2015-08-13 15:09:43.355350116 +0200 -@@ -150,6 +150,7 @@ kexecdh_server(Kex *kex) - - kex_derive_keys_bn(kex, hash, hashlen, shared_secret); - BN_clear_free(shared_secret); -+ memset(hash, 0, hashlen); - kex_finish(kex); - } - #else /* OPENSSL_HAS_ECC */ -diff -up openssh-6.6p1/kexgexc.c.fips openssh-6.6p1/kexgexc.c ---- openssh-6.6p1/kexgexc.c.fips 2014-02-04 01:20:15.000000000 +0100 -+++ openssh-6.6p1/kexgexc.c 2015-08-13 15:09:43.355350116 +0200 -@@ -26,6 +26,8 @@ - - #include "includes.h" - -+#include -+ - #include - - #include -@@ -64,13 +66,13 @@ kexgex_client(Kex *kex) - /* Old GEX request */ - packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); - packet_put_int(nbits); -- min = DH_GRP_MIN; -+ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - max = DH_GRP_MAX; - - debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); - } else { - /* New GEX request */ -- min = DH_GRP_MIN; -+ min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - max = DH_GRP_MAX; - packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); - packet_put_int(min); -diff -up openssh-6.6p1/kexgexs.c.fips openssh-6.6p1/kexgexs.c ---- openssh-6.6p1/kexgexs.c.fips 2014-02-04 01:20:15.000000000 +0100 -+++ openssh-6.6p1/kexgexs.c 2015-08-13 15:09:43.355350116 +0200 -@@ -76,16 +76,16 @@ kexgex_server(Kex *kex) - omin = min = packet_get_int(); - onbits = nbits = packet_get_int(); - omax = max = packet_get_int(); -- min = MAX(DH_GRP_MIN, min); -+ min = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); - max = MIN(DH_GRP_MAX, max); -- nbits = MAX(DH_GRP_MIN, nbits); -+ nbits = MAX(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); - nbits = MIN(DH_GRP_MAX, nbits); - break; - case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: - debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); - onbits = nbits = packet_get_int(); - /* unused for old GEX */ -- omin = min = DH_GRP_MIN; -+ omin = min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; - omax = max = DH_GRP_MAX; - break; - default: -diff -up openssh-6.6p1/key.c.fips openssh-6.6p1/key.c ---- openssh-6.6p1/key.c.fips 2015-08-13 15:09:43.345350133 +0200 -+++ openssh-6.6p1/key.c 2015-08-13 15:09:43.356350114 +0200 -@@ -42,6 +42,7 @@ - #include "crypto_api.h" - - #include -+#include - #include - - #include -@@ -635,7 +636,7 @@ sshkey_format_oneline(const struct sshke - char *fp, *result; - - if (key_is_cert(key)) { -- fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, -+ fp = key_selected_fingerprint(key->cert->signature_key, - SSH_FP_HEX); - xasprintf(&result, "%s ID %s (serial %llu) CA %s %s", - key_type(key), key->cert->key_id, -@@ -644,7 +645,7 @@ sshkey_format_oneline(const struct sshke - fp == NULL ? "(null)" : fp); - free(fp); - } else { -- fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_selected_fingerprint(key, SSH_FP_HEX); - xasprintf(&result, "%s %s", key_type(key), - fp == NULL ? "(null)" : fp); - free(fp); -@@ -661,9 +662,13 @@ key_fingerprint_selection(void) - char *env; - - if (!rv_defined) { -- env = getenv("SSH_FINGERPRINT_TYPE"); -- rv = (env && !strcmp (env, "sha")) ? -- SSH_FP_SHA1 : SSH_FP_MD5; -+ if (FIPS_mode()) -+ rv = SSH_FP_SHA1; -+ else { -+ env = getenv("SSH_FINGERPRINT_TYPE"); -+ rv = (env && !strcmp (env, "sha")) ? -+ SSH_FP_SHA1 : SSH_FP_MD5; -+ } - rv_defined = 1; - } - return rv; -@@ -1168,8 +1173,11 @@ rsa_generate_private_key(u_int bits) - fatal("%s: BN_new failed", __func__); - if (!BN_set_word(f4, RSA_F4)) - fatal("%s: BN_new failed", __func__); -- if (!RSA_generate_key_ex(private, bits, f4, NULL)) -+ if (!RSA_generate_key_ex(private, bits, f4, NULL)) { -+ if (FIPS_mode()) -+ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__); - fatal("%s: key generation failed.", __func__); -+ } - BN_free(f4); - return private; - } -diff -up openssh-6.6p1/mac.c.fips openssh-6.6p1/mac.c ---- openssh-6.6p1/mac.c.fips 2015-08-13 15:09:43.346350131 +0200 -+++ openssh-6.6p1/mac.c 2015-08-13 15:09:43.356350114 +0200 -@@ -27,6 +27,8 @@ - - #include - -+#include -+ - #include - #include - #include -@@ -60,7 +62,7 @@ struct macalg { - int etm; /* Encrypt-then-MAC */ - }; - --static const struct macalg macs[] = { -+static const struct macalg all_macs[] = { - /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ - { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, - { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, -@@ -91,6 +93,24 @@ static const struct macalg macs[] = { - { NULL, 0, 0, 0, 0, 0, 0 } - }; - -+static const struct macalg fips_macs[] = { -+ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ -+ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, -+#ifdef HAVE_EVP_SHA256 -+ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 }, -+ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, -+#endif -+ -+ /* Encrypt-then-MAC variants */ -+ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, -+#ifdef HAVE_EVP_SHA256 -+ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 }, -+ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 }, -+#endif -+ -+ { NULL, 0, 0, 0, 0, 0, 0 } -+}; -+ - /* Returns a list of supported MACs separated by the specified char. */ - char * - mac_alg_list(char sep) -@@ -99,7 +119,7 @@ mac_alg_list(char sep) - size_t nlen, rlen = 0; - const struct macalg *m; - -- for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(m->name); -@@ -133,7 +153,7 @@ mac_setup(Mac *mac, char *name) - { - const struct macalg *m; - -- for (m = macs; m->name != NULL; m++) { -+ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { - if (strcmp(name, m->name) != 0) - continue; - if (mac != NULL) { -diff -up openssh-6.6p1/myproposal.h.fips openssh-6.6p1/myproposal.h ---- openssh-6.6p1/myproposal.h.fips 2013-12-07 01:24:02.000000000 +0100 -+++ openssh-6.6p1/myproposal.h 2015-08-13 15:10:30.288271102 +0200 -@@ -88,6 +88,12 @@ - "diffie-hellman-group14-sha1," \ - "diffie-hellman-group1-sha1" - -+#define KEX_DEFAULT_KEX_FIPS \ -+ KEX_ECDH_METHODS \ -+ KEX_SHA256_METHODS \ -+ "diffie-hellman-group-exchange-sha1," \ -+ "diffie-hellman-group14-sha1" -+ - #define KEX_DEFAULT_PK_ALG \ - HOSTKEY_ECDSA_CERT_METHODS \ - "ssh-ed25519-cert-v01@openssh.com," \ -@@ -133,6 +139,22 @@ - #define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" - #define KEX_DEFAULT_LANG "" - -+#define KEX_FIPS_ENCRYPT \ -+ "aes128-ctr,aes192-ctr,aes256-ctr," \ -+ "aes128-cbc,3des-cbc," \ -+ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" -+#ifdef HAVE_EVP_SHA256 -+#define KEX_FIPS_MAC \ -+ "hmac-sha1," \ -+ "hmac-sha2-256," \ -+ "hmac-sha2-512," \ -+ "hmac-sha1-etm@openssh.com," \ -+ "hmac-sha2-256-etm@openssh.com," \ -+ "hmac-sha2-512-etm@openssh.com" -+#else -+#define KEX_FIPS_MAC \ -+ "hmac-sha1" -+#endif - - static char *myproposal[PROPOSAL_MAX] = { - KEX_DEFAULT_KEX, -diff -up openssh-6.6p1/ssh-keygen.c.fips openssh-6.6p1/ssh-keygen.c ---- openssh-6.6p1/ssh-keygen.c.fips 2015-08-13 15:09:43.296350215 +0200 -+++ openssh-6.6p1/ssh-keygen.c 2015-08-13 15:09:43.360350107 +0200 -@@ -195,6 +195,12 @@ type_bits_valid(int type, u_int32_t *bit - fprintf(stderr, "key bits exceeds maximum %d\n", maxbits); - exit(1); - } -+ if (FIPS_mode()) { -+ if (type == KEY_DSA) -+ fatal("DSA keys are not allowed in FIPS mode"); -+ if (type == KEY_ED25519) -+ fatal("ED25519 keys are not allowed in FIPS mode"); -+ } - if (type == KEY_DSA && *bitsp != 1024) - fatal("DSA keys must be 1024 bits"); - else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 768) -@@ -746,7 +752,7 @@ do_download(struct passwd *pw) - enum fp_type fptype; - char *fp, *ra; - -- fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; -+ fptype = print_bubblebabble ? SSH_FP_SHA1 : key_fingerprint_selection(); - rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; - - pkcs11_init(0); -@@ -756,8 +762,7 @@ do_download(struct passwd *pw) - for (i = 0; i < nkeys; i++) { - if (print_fingerprint) { - fp = key_fingerprint(keys[i], fptype, rep); -- ra = key_fingerprint(keys[i], SSH_FP_MD5, -- SSH_FP_RANDOMART); -+ ra = key_selected_fingerprint(keys[i], SSH_FP_RANDOMART); - printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), - fp, key_type(keys[i])); - if (log_level >= SYSLOG_LEVEL_VERBOSE) -diff -up openssh-6.6p1/ssh.c.fips openssh-6.6p1/ssh.c ---- openssh-6.6p1/ssh.c.fips 2014-02-27 00:17:13.000000000 +0100 -+++ openssh-6.6p1/ssh.c 2015-08-13 15:09:43.357350112 +0200 -@@ -73,6 +73,8 @@ - - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" - -@@ -427,6 +429,13 @@ main(int ac, char **av) - sanitise_stdfd(); - - __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)) -+ if (FIPS_mode()) -+ fatal("FIPS integrity verification test failed."); -+ else -+ logit("FIPS integrity verification test failed."); - - #ifndef HAVE_SETPROCTITLE - /* Prepare for later setproctitle emulation */ -@@ -504,6 +513,9 @@ main(int ac, char **av) - "ACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { - switch (opt) { - case '1': -+ if (FIPS_mode()) { -+ fatal("Protocol 1 not allowed in the FIPS mode."); -+ } - options.protocol = SSH_PROTO_1; - break; - case '2': -@@ -828,7 +840,6 @@ main(int ac, char **av) - - host_arg = xstrdup(host); - -- OpenSSL_add_all_algorithms(); - ERR_load_crypto_strings(); - - /* Initialize the command to execute on remote host. */ -@@ -973,6 +984,10 @@ main(int ac, char **av) - - seed_rng(); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - if (options.user == NULL) - options.user = xstrdup(pw->pw_name); - -@@ -1020,6 +1035,12 @@ main(int ac, char **av) - - timeout_ms = options.connection_timeout * 1000; - -+ if (FIPS_mode()) { -+ options.protocol &= SSH_PROTO_2; -+ if (options.protocol == 0) -+ fatal("Protocol 2 disabled by configuration but required in the FIPS mode."); -+ } -+ - /* Open a connection to the remote host. */ - if (ssh_connect(host, addrs, &hostaddr, options.port, - options.address_family, options.connection_attempts, -diff -up openssh-6.6p1/sshconnect2.c.fips openssh-6.6p1/sshconnect2.c ---- openssh-6.6p1/sshconnect2.c.fips 2015-08-13 15:09:43.342350138 +0200 -+++ openssh-6.6p1/sshconnect2.c 2015-08-13 15:09:43.357350112 +0200 -@@ -46,6 +46,8 @@ - #include - #endif - -+#include -+ - #include "openbsd-compat/sys-queue.h" - - #include "xmalloc.h" -@@ -170,21 +172,26 @@ ssh_kex2(char *host, struct sockaddr *ho - - #ifdef GSSAPI - if (options.gss_keyex) { -- /* Add the GSSAPI mechanisms currently supported on this -- * client to the key exchange algorithm proposal */ -- orig = myproposal[PROPOSAL_KEX_ALGS]; -- -- if (options.gss_trust_dns) -- gss_host = (char *)get_canonical_hostname(1); -- else -- gss_host = host; -- -- gss = ssh_gssapi_client_mechanisms(gss_host, -- options.gss_client_identity, options.gss_kex_algorithms); -- if (gss) { -- debug("Offering GSSAPI proposal: %s", gss); -- xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -- "%s,%s", gss, orig); -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ if (options.gss_trust_dns) -+ gss_host = (char *)get_canonical_hostname(1); -+ else -+ gss_host = host; -+ -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ } - } - } - #endif -@@ -196,6 +203,10 @@ ssh_kex2(char *host, struct sockaddr *ho - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = -+ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; -+ - } - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -211,7 +222,11 @@ ssh_kex2(char *host, struct sockaddr *ho - if (options.macs != NULL) { - myproposal[PROPOSAL_MAC_ALGS_CTOS] = - myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_MAC_ALGS_CTOS] = -+ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; - } -+ - if (options.hostkeyalgorithms != NULL) - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = - compat_pkalg_proposal(options.hostkeyalgorithms); -@@ -223,9 +238,11 @@ ssh_kex2(char *host, struct sockaddr *ho - } - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; -+ else if (FIPS_mode()) -+ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; -+ - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( - myproposal[PROPOSAL_KEX_ALGS]); -- - #ifdef GSSAPI - /* If we've got GSSAPI algorithms, then we also support the - * 'null' hostkey, as a last resort */ -diff -up openssh-6.6p1/sshd.c.fips openssh-6.6p1/sshd.c ---- openssh-6.6p1/sshd.c.fips 2015-08-13 15:09:43.352350121 +0200 -+++ openssh-6.6p1/sshd.c 2015-08-13 15:09:43.359350109 +0200 -@@ -75,6 +75,8 @@ - #include - #include - #include -+#include -+#include - #include "openbsd-compat/openssl-compat.h" - - #ifdef HAVE_SECUREWARE -@@ -1473,6 +1475,18 @@ main(int ac, char **av) - #endif - __progname = ssh_get_progname(av[0]); - -+ SSLeay_add_all_algorithms(); -+ if (access("/etc/system-fips", F_OK) == 0) -+ if (! FIPSCHECK_verify(NULL, NULL)) { -+ openlog(__progname, LOG_PID, LOG_AUTHPRIV); -+ if (FIPS_mode()) { -+ syslog(LOG_CRIT, "FIPS integrity verification test failed."); -+ cleanup_exit(255); -+ } -+ else -+ syslog(LOG_INFO, "FIPS integrity verification test failed."); -+ closelog(); -+ } - /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ - saved_argc = ac; - rexec_argc = ac; -@@ -1624,8 +1638,6 @@ main(int ac, char **av) - else - closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); - -- OpenSSL_add_all_algorithms(); -- - /* If requested, redirect the logs to the specified logfile. */ - if (logfile != NULL) { - log_redirect_stderr_to(logfile); -@@ -1803,6 +1815,10 @@ main(int ac, char **av) - debug("private host key: #%d type %d %s", i, keytype, - key_type(key ? key : pubkey)); - } -+ if ((options.protocol & SSH_PROTO_1) && FIPS_mode()) { -+ logit("Disabling protocol version 1. Not allowed in the FIPS mode."); -+ options.protocol &= ~SSH_PROTO_1; -+ } - if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { - logit("Disabling protocol version 1. Could not load host key"); - options.protocol &= ~SSH_PROTO_1; -@@ -1966,6 +1982,10 @@ main(int ac, char **av) - /* Reinitialize the log (because of the fork above). */ - log_init(__progname, options.log_level, options.log_facility, log_stderr); - -+ if (FIPS_mode()) { -+ logit("FIPS mode initialized"); -+ } -+ - /* Chdir to the root directory so that the current disk can be - unmounted if desired. */ - if (chdir("/") == -1) -@@ -2537,6 +2557,9 @@ do_ssh2_kex(void) - if (options.ciphers != NULL) { - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_ENC_ALGS_CTOS] = -+ myproposal[PROPOSAL_ENC_ALGS_STOC] = KEX_FIPS_ENCRYPT; - } - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); -@@ -2546,6 +2569,9 @@ do_ssh2_kex(void) - if (options.macs != NULL) { - myproposal[PROPOSAL_MAC_ALGS_CTOS] = - myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; -+ } else if (FIPS_mode()) { -+ myproposal[PROPOSAL_MAC_ALGS_CTOS] = -+ myproposal[PROPOSAL_MAC_ALGS_STOC] = KEX_FIPS_MAC; - } - if (options.compression == COMP_NONE) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = -@@ -2556,6 +2582,8 @@ do_ssh2_kex(void) - } - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; -+ else if (FIPS_mode()) -+ myproposal[PROPOSAL_KEX_ALGS] = KEX_DEFAULT_KEX_FIPS; - - myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( - myproposal[PROPOSAL_KEX_ALGS]); -@@ -2582,10 +2610,14 @@ do_ssh2_kex(void) - if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) - orig = NULL; - -- if (options.gss_keyex) -- gss = ssh_gssapi_server_mechanisms(); -- else -- gss = NULL; -+ if (options.gss_keyex) { -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ gss = ssh_gssapi_server_mechanisms(); -+ } -+ } - - if (gss && orig) - xasprintf(&newstr, "%s,%s", gss, orig); -diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -index 13b0a6f..3ec2454 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -+++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -@@ -54,6 +54,7 @@ - #include "secure_filename.h" - #include "uidswap.h" - #include -+#include - - #include "identity.h" - -@@ -103,7 +104,8 @@ pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key) - found_key = 1; - logit("matching key found: file/command %s, line %lu", file, - linenum); -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -+ fp = key_fingerprint(found, FIPS_mode() ? SSH_FP_SHA1 : SSH_FP_MD5, -+ SSH_FP_HEX); - logit("Found matching %s key: %s", - key_type(found), fp); - free(fp); diff --git a/SOURCES/openssh-6.6p1-fix-ssh-copy-id-on-non-sh-shell.patch b/SOURCES/openssh-6.6p1-fix-ssh-copy-id-on-non-sh-shell.patch deleted file mode 100644 index 358986b..0000000 --- a/SOURCES/openssh-6.6p1-fix-ssh-copy-id-on-non-sh-shell.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/contrib/ssh-copy-id b/contrib/ssh-copy-id -index 8e1091c..4bba5d6 100644 ---- a/contrib/ssh-copy-id -+++ b/contrib/ssh-copy-id -@@ -274,9 +274,7 @@ case "$REMOTE_VERSION" in - populate_new_ids 0 - fi - [ "$DRY_RUN" ] || printf '%s\n' "$NEW_IDS" | ssh "$@" " -- umask 077 ; -+ exec sh -c 'umask 077; mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1; if type restorecon >/dev/null 2>&1; then restorecon -F .ssh .ssh/authorized_keys; fi'" \ -- mkdir -p .ssh && cat >> .ssh/authorized_keys || exit 1 ; -- if type restorecon >/dev/null 2>&1 ; then restorecon -F .ssh .ssh/authorized_keys ; fi" \ - || exit 1 - ADDED=$(printf '%s\n' "$NEW_IDS" | wc -l) - ;; diff --git a/SOURCES/openssh-6.6p1-force_krb.patch b/SOURCES/openssh-6.6p1-force_krb.patch index a242394..7055e10 100644 --- a/SOURCES/openssh-6.6p1-force_krb.patch +++ b/SOURCES/openssh-6.6p1-force_krb.patch @@ -12,12 +12,7 @@ index 42de994..60de320 100644 #include "xmalloc.h" #include "key.h" -@@ -40,10 +42,12 @@ - #include "auth.h" - #include "log.h" - #include "servconf.h" -+#include "misc.h" - +@@ -40,6 +42,7 @@ #include "buffer.h" #include "ssh-gss.h" @@ -168,7 +163,7 @@ index 42de994..60de320 100644 + k5users_allowed_cmds[ncommands-1] = + xstrdup(pw->pw_shell); + k5users_allowed_cmds = -+ xrealloc(k5users_allowed_cmds, ++ncommands, ++ xreallocarray(k5users_allowed_cmds, ++ncommands, + sizeof(*k5users_allowed_cmds)); + break; + } @@ -181,7 +176,7 @@ index 42de994..60de320 100644 + k5users_allowed_cmds[ncommands-1] = + xstrdup(token); + k5users_allowed_cmds = -+ xrealloc(k5users_allowed_cmds, ++ncommands, ++ xreallocarray(k5users_allowed_cmds, ++ncommands, + sizeof(*k5users_allowed_cmds)); + token = strtok(NULL, " \t\n"); + } diff --git a/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch b/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch deleted file mode 100644 index 3854b40..0000000 --- a/SOURCES/openssh-6.6p1-gssKexAlgorithms.patch +++ /dev/null @@ -1,410 +0,0 @@ -diff -up openssh-6.6p1/gss-genr.c.gsskexalg openssh-6.6p1/gss-genr.c ---- openssh-6.6p1/gss-genr.c.gsskexalg 2015-08-14 16:07:33.271343064 +0200 -+++ openssh-6.6p1/gss-genr.c 2015-08-14 16:07:33.338342936 +0200 -@@ -76,7 +76,8 @@ ssh_gssapi_oid_table_ok() { - */ - - char * --ssh_gssapi_client_mechanisms(const char *host, const char *client) { -+ssh_gssapi_client_mechanisms(const char *host, const char *client, -+ const char *kex) { - gss_OID_set gss_supported; - OM_uint32 min_status; - -@@ -84,12 +85,12 @@ ssh_gssapi_client_mechanisms(const char - return NULL; - - return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, -- host, client)); -+ host, client, kex)); - } - - char * - ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, -- const char *host, const char *client) { -+ const char *host, const char *client, const char *kex) { - Buffer buf; - size_t i; - int oidpos, enclen; -@@ -98,6 +99,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - char deroid[2]; - const EVP_MD *evp_md = EVP_md5(); - EVP_MD_CTX md; -+ char *s, *cp, *p; - - if (gss_enc2oid != NULL) { - for (i = 0; gss_enc2oid[i].encoded != NULL; i++) -@@ -111,6 +113,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - buffer_init(&buf); - - 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)) { -@@ -129,26 +132,22 @@ 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, ','); -- -- 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); -+ 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); -+ } - - gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); - gss_enc2oid[oidpos].encoded = encoded; - oidpos++; - } - } -+ free(s); - gss_enc2oid[oidpos].oid = NULL; - gss_enc2oid[oidpos].encoded = NULL; - -diff -up openssh-6.6p1/gss-serv.c.gsskexalg openssh-6.6p1/gss-serv.c ---- openssh-6.6p1/gss-serv.c.gsskexalg 2015-08-14 16:07:33.296343016 +0200 -+++ openssh-6.6p1/gss-serv.c 2015-08-14 16:07:33.338342936 +0200 -@@ -151,7 +151,7 @@ ssh_gssapi_server_mechanisms() { - - ssh_gssapi_supported_oids(&supported); - return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech, -- NULL, NULL)); -+ NULL, NULL, options.gss_kex_algorithms)); - } - - /* Unprivileged */ -diff -up openssh-6.6p1/kex.c.gsskexalg openssh-6.6p1/kex.c ---- openssh-6.6p1/kex.c.gsskexalg 2015-08-14 16:07:33.271343064 +0200 -+++ openssh-6.6p1/kex.c 2015-08-14 16:07:33.339342935 +0200 -@@ -160,6 +160,29 @@ kex_names_valid(const char *names) - return 1; - } - -+/* Validate GSS KEX method name list */ -+int -+gss_kex_names_valid(const char *names) -+{ -+ char *s, *cp, *p; -+ -+ if (names == NULL || *names == '\0') -+ return 0; -+ s = cp = xstrdup(names); -+ for ((p = strsep(&cp, ",")); p && *p != '\0'; -+ (p = strsep(&cp, ","))) { -+ if (strncmp(p, "gss-", 4) != 0 -+ || kex_alg_by_name(p) == NULL) { -+ error("Unsupported KEX algorithm \"%.100s\"", p); -+ free(s); -+ return 0; -+ } -+ } -+ debug3("gss kex names ok: [%s]", names); -+ free(s); -+ return 1; -+} -+ - /* put algorithm proposal into buffer */ - static void - kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) -diff -up openssh-6.6p1/readconf.c.gsskexalg openssh-6.6p1/readconf.c ---- openssh-6.6p1/readconf.c.gsskexalg 2015-08-14 16:07:33.274343058 +0200 -+++ openssh-6.6p1/readconf.c 2015-08-14 16:14:17.600574919 +0200 -@@ -55,6 +55,7 @@ - #include "kex.h" - #include "mac.h" - #include "uidswap.h" -+#include "ssh-gss.h" - - /* Format of the configuration file: - -@@ -142,7 +143,7 @@ typedef enum { - oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, - oAddressFamily, oGssAuthentication, oGssDelegateCreds, - oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, -- oGssServerIdentity, -+ oGssServerIdentity, oGssKexAlgorithms, - oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, - oSendEnv, oControlPath, oControlMaster, oControlPersist, - oHashKnownHosts, -@@ -191,6 +192,7 @@ static struct { - { "gssapiclientidentity", oGssClientIdentity }, - { "gssapiserveridentity", oGssServerIdentity }, - { "gssapirenewalforcesrekey", oGssRenewalRekey }, -+ { "gssapikexalgorithms", oGssKexAlgorithms }, - #else - { "gssapiauthentication", oUnsupported }, - { "gssapikeyexchange", oUnsupported }, -@@ -198,6 +200,7 @@ static struct { - { "gssapitrustdns", oUnsupported }, - { "gssapiclientidentity", oUnsupported }, - { "gssapirenewalforcesrekey", oUnsupported }, -+ { "gssapikexalgorithms", oUnsupported }, - #endif - { "fallbacktorsh", oDeprecated }, - { "usersh", oDeprecated }, -@@ -876,6 +879,18 @@ parse_time: - intptr = &options->gss_renewal_rekey; - goto parse_flag; - -+ case oGssKexAlgorithms: -+ arg = strdelim(&s); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", -+ filename, linenum); -+ if (!gss_kex_names_valid(arg)) -+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", -+ filename, linenum, arg ? arg : ""); -+ if (*activep && options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = xstrdup(arg); -+ break; -+ - case oBatchMode: - intptr = &options->batch_mode; - goto parse_flag; -@@ -1534,6 +1549,7 @@ initialize_options(Options * options) - options->gss_renewal_rekey = -1; - options->gss_client_identity = NULL; - options->gss_server_identity = NULL; -+ options->gss_kex_algorithms = NULL; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->kbd_interactive_devices = NULL; -@@ -1660,6 +1676,8 @@ fill_default_options(Options * options) - options->gss_trust_dns = 0; - if (options->gss_renewal_rekey == -1) - options->gss_renewal_rekey = 0; -+ if (options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -diff -up openssh-6.6p1/readconf.h.gsskexalg openssh-6.6p1/readconf.h ---- openssh-6.6p1/readconf.h.gsskexalg 2015-08-14 16:07:33.274343058 +0200 -+++ openssh-6.6p1/readconf.h 2015-08-14 16:07:33.339342935 +0200 -@@ -60,6 +60,7 @@ typedef struct { - int gss_renewal_rekey; /* Credential renewal forces rekey */ - char *gss_client_identity; /* Principal to initiate GSSAPI with */ - char *gss_server_identity; /* GSSAPI target principal */ -+ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ - int password_authentication; /* Try password - * authentication. */ - int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff -up openssh-6.6p1/servconf.c.gsskexalg openssh-6.6p1/servconf.c ---- openssh-6.6p1/servconf.c.gsskexalg 2015-08-14 16:07:45.704319443 +0200 -+++ openssh-6.6p1/servconf.c 2015-08-14 16:14:15.306579277 +0200 -@@ -54,6 +54,7 @@ - #include "packet.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" - - static void add_listen_addr(ServerOptions *, char *, int); - static void add_one_listen_addr(ServerOptions *, char *, int); -@@ -112,6 +113,7 @@ initialize_server_options(ServerOptions - options->gss_cleanup_creds = -1; - options->gss_strict_acceptor = -1; - options->gss_store_rekey = -1; -+ options->gss_kex_algorithms = NULL; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; -@@ -258,6 +260,8 @@ fill_default_server_options(ServerOption - options->gss_strict_acceptor = 1; - if (options->gss_store_rekey == -1) - options->gss_store_rekey = 0; -+ if (options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -@@ -360,7 +364,7 @@ typedef enum { - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, -- sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, -+ sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, - sHostCertificate, -@@ -434,6 +438,7 @@ static struct { - { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, - { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, -+ { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -@@ -442,6 +447,7 @@ static struct { - { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, - { "gssapienablek5users", sUnsupported, SSHCFG_ALL }, -+ { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, - #endif - { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, - { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, -@@ -1137,6 +1143,18 @@ process_server_config_line(ServerOptions - intptr = &options->gss_store_rekey; - goto parse_flag; - -+ case sGssKexAlgorithms: -+ arg = strdelim(&cp); -+ if (!arg || *arg == '\0') -+ fatal("%.200s line %d: Missing argument.", -+ filename, linenum); -+ if (!gss_kex_names_valid(arg)) -+ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", -+ filename, linenum, arg ? arg : ""); -+ if (*activep && options->gss_kex_algorithms == NULL) -+ options->gss_kex_algorithms = xstrdup(arg); -+ break; -+ - case sPasswordAuthentication: - intptr = &options->password_authentication; - goto parse_flag; -@@ -2068,6 +2086,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); - dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); - dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); -+ dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); - #endif - dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); - dump_cfg_fmtint(sKbdInteractiveAuthentication, -diff -up openssh-6.6p1/servconf.h.gsskexalg openssh-6.6p1/servconf.h ---- openssh-6.6p1/servconf.h.gsskexalg 2015-08-14 16:07:48.160314777 +0200 -+++ openssh-6.6p1/servconf.h 2015-08-14 16:09:34.447112854 +0200 -@@ -116,6 +116,7 @@ typedef struct { - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ - int gss_store_rekey; -+ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ - int password_authentication; /* If true, permit password - * authentication. */ - int kbd_interactive_authentication; /* If true, permit */ -diff -up openssh-6.6p1/sshconnect2.c.gsskexalg openssh-6.6p1/sshconnect2.c ---- openssh-6.6p1/sshconnect2.c.gsskexalg 2015-08-14 16:07:33.304343001 +0200 -+++ openssh-6.6p1/sshconnect2.c 2015-08-14 16:07:33.339342935 +0200 -@@ -179,7 +179,8 @@ ssh_kex2(char *host, struct sockaddr *ho - else - gss_host = host; - -- gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); - if (gss) { - debug("Offering GSSAPI proposal: %s", gss); - xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -diff -up openssh-6.6p1/ssh-gss.h.gsskexalg openssh-6.6p1/ssh-gss.h ---- openssh-6.6p1/ssh-gss.h.gsskexalg 2015-08-14 16:07:33.278343050 +0200 -+++ openssh-6.6p1/ssh-gss.h 2015-08-14 16:07:33.340342932 +0200 -@@ -76,6 +76,11 @@ extern char **k5users_allowed_cmds; - #define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" - #define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" - -+#define GSS_KEX_DEFAULT_KEX \ -+ KEX_GSS_GEX_SHA1_ID "," \ -+ KEX_GSS_GRP1_SHA1_ID "," \ -+ KEX_GSS_GRP14_SHA1_ID -+ - typedef struct { - char *filename; - char *envvar; -@@ -147,9 +152,9 @@ int ssh_gssapi_credentials_updated(Gssct - /* 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_client_mechanisms(const char *, const char *, const char *); - char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, -- const char *); -+ const char *, const char *); - gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); - int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, - const char *); -diff --git a/ssh.1 b/ssh.1 -index 4a7d1cd..c795c40 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -449,6 +449,7 @@ For full details of the options listed below, and their possible values, see - .It GSSAPIDelegateCredentials - .It GSSAPIRenewalForcesRekey - .It GSSAPITrustDns -+.It GSSAPIKexAlgorithms - .It HashKnownHosts - .It Host - .It HostbasedAuthentication -diff --git a/ssh_config.5 b/ssh_config.5 -index c95fda6..a2af9c4 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -719,6 +719,18 @@ command line will be passed untouched to the GSSAPI library. - The default is - .Dq no . - This option only applies to protocol version 2 connections using GSSAPI. -+.It Cm GSSAPIKexAlgorithms -+The list of key exchange algorithms that are offered for GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1- -+.Ed -+.Pp -+The default is -+.Dq gss-gex-sha1-,gss-group1-sha1-,gss-group14-sha1- . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HashKnownHosts - Indicates that - .Xr ssh 1 -diff --git a/sshd_config.5 b/sshd_config.5 -index 5e8c6c6..4c670aa 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -545,6 +545,18 @@ 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 GSSAPIKexAlgorithms -+The list of key exchange algorithms that are accepted by GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1- -+.Ed -+.Pp -+The default is -+.Dq gss-gex-sha1-,gss-group1-sha1-,gss-group14-sha1- . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HostbasedAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication together - with successful public key client host authentication is allowed -diff --git a/kex.h b/kex.h -index db3dde4..17ae43b 100644 ---- a/kex.h -+++ b/kex.h -@@ -158,6 +158,7 @@ struct Kex { - - int kex_names_valid(const char *); - char *kex_alg_list(char); -+int gss_kex_names_valid(const char *); - - Kex *kex_setup(char *[PROPOSAL_MAX]); - void kex_finish(Kex *); diff --git a/SOURCES/openssh-6.6p1-gsskex.patch b/SOURCES/openssh-6.6p1-gsskex.patch deleted file mode 100644 index d1ee1ab..0000000 --- a/SOURCES/openssh-6.6p1-gsskex.patch +++ /dev/null @@ -1,2825 +0,0 @@ -diff --git a/Makefile.in b/Makefile.in -index 581b121..2ad26ff 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -77,6 +77,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ - kexdh.o kexgex.o kexdhc.o kexgexc.o bufec.o kexecdh.o kexecdhc.o \ -+ kexgssc.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ - ssh-pkcs11.o krl.o smult_curve25519_ref.o \ - kexc25519.o kexc25519c.o poly1305.o chacha.o cipher-chachapoly.o \ -@@ -96,7 +97,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o kexecdhs.o \ - kexc25519s.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 \ - roaming_common.o roaming_serv.o \ -diff --git a/auth2-gss.c b/auth2-gss.c -index 4756dd7..ad65059 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -52,6 +52,40 @@ static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); - static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); - static void input_gssapi_errtok(int, u_int32_t, void *); - -+/* -+ * The 'gssapi_keyex' userauth mechanism. -+ */ -+static int -+userauth_gsskeyex(Authctxt *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) -@@ -235,7 +269,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) - - packet_check_eom(); - -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw)); - - authctxt->postponed = 0; - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); -@@ -277,7 +312,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) - 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"); - -@@ -294,6 +330,12 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) - userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); - } - -+Authmethod method_gsskeyex = { -+ "gssapi-keyex", -+ userauth_gsskeyex, -+ &options.gss_authentication -+}; -+ - Authmethod method_gssapi = { - "gssapi-with-mic", - userauth_gssapi, -diff --git a/auth2.c b/auth2.c -index 5f4f26f..0f52b68 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -69,6 +69,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -76,6 +77,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - &method_passwd, -diff --git a/clientloop.c b/clientloop.c -index 59ad3a2..9c60108 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -111,6 +111,10 @@ - #include "msg.h" - #include "roaming.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* import options */ - extern Options options; - -@@ -1608,6 +1612,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) - /* Do channel operations unless rekeying in progress. */ - if (!rekeying) { - channel_after_select(readset, writeset); -+ -+#ifdef GSSAPI -+ if (options.gss_renewal_rekey && -+ ssh_gssapi_credentials_updated(GSS_C_NO_CONTEXT)) { -+ debug("credentials updated - forcing rekey"); -+ need_rekeying = 1; -+ } -+#endif -+ - if (need_rekeying || packet_need_rekeying()) { - debug("need rekeying"); - xxx_kex->done = 0; -diff --git a/configure.ac b/configure.ac -index 74e77db..9bde04e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -584,6 +584,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) - [Use tunnel device compatibility to OpenBSD]) - AC_DEFINE([SSH_TUN_PREPEND_AF], [1], - [Prepend the address family to IP tunnel traffic]) -+ AC_MSG_CHECKING(if we have the Security Authorization Session API) -+ AC_TRY_COMPILE([#include ], -+ [SessionCreate(0, 0);], -+ [ac_cv_use_security_session_api="yes" -+ AC_DEFINE(USE_SECURITY_SESSION_API, 1, -+ [platform has the Security Authorization Session API]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT(yes)], -+ [ac_cv_use_security_session_api="no" -+ AC_MSG_RESULT(no)]) -+ AC_MSG_CHECKING(if we have an in-memory credentials cache) -+ AC_TRY_COMPILE( -+ [#include ], -+ [cc_context_t c; -+ (void) cc_initialize (&c, 0, NULL, NULL);], -+ [AC_DEFINE(USE_CCAPI, 1, -+ [platform uses an in-memory credentials cache]) -+ LIBS="$LIBS -framework Security" -+ AC_MSG_RESULT(yes) -+ if test "x$ac_cv_use_security_session_api" = "xno"; then -+ AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***) -+ fi], -+ [AC_MSG_RESULT(no)] -+ ) - m4_pattern_allow([AU_IPv]) - AC_CHECK_DECL([AU_IPv4], [], - AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) -diff --git a/gss-genr.c b/gss-genr.c -index b39281b..a3a2289 100644 ---- a/gss-genr.c -+++ b/gss-genr.c -@@ -39,12 +39,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) -@@ -197,7 +352,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, - } - - ctx->major = gss_init_sec_context(&ctx->minor, -- GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, -+ ctx->client_creds, &ctx->context, ctx->name, ctx->oid, - GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, - 0, NULL, recv_tok, NULL, send_tok, flags, NULL); - -@@ -227,8 +382,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) - } - - 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); -@@ -236,6 +425,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) - return (ctx->major); - } - -+/* Priviledged when used by server */ -+OM_uint32 -+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+{ -+ if (ctx == NULL) -+ return -1; -+ -+ ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -+ gssbuf, gssmic, NULL); -+ -+ return (ctx->major); -+} -+ - void - ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, - const char *context) -@@ -249,11 +451,16 @@ ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, - } - - int --ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) -+ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host, -+ const char *client) - { - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - OM_uint32 major, minor; - gss_OID_desc spnego_oid = {6, (void *)"\x2B\x06\x01\x05\x05\x02"}; -+ Gssctxt *intctx = NULL; -+ -+ if (ctx == NULL) -+ ctx = &intctx; - - /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -263,6 +470,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) - ssh_gssapi_build_ctx(ctx); - ssh_gssapi_set_oid(*ctx, oid); - major = ssh_gssapi_import_name(*ctx, host); -+ -+ if (!GSS_ERROR(major) && client) -+ major = ssh_gssapi_client_identity(*ctx, client); -+ - if (!GSS_ERROR(major)) { - major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, - NULL); -@@ -272,10 +483,67 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) - GSS_C_NO_BUFFER); - } - -- if (GSS_ERROR(major)) -+ if (GSS_ERROR(major) || intctx != NULL) - ssh_gssapi_delete_ctx(ctx); - - return (!GSS_ERROR(major)); - } - -+int -+ssh_gssapi_credentials_updated(Gssctxt *ctxt) { -+ static gss_name_t saved_name = GSS_C_NO_NAME; -+ static OM_uint32 saved_lifetime = 0; -+ static gss_OID saved_mech = GSS_C_NO_OID; -+ static gss_name_t name; -+ static OM_uint32 last_call = 0; -+ OM_uint32 lifetime, now, major, minor; -+ int equal; -+ gss_cred_usage_t usage = GSS_C_INITIATE; -+ -+ now = time(NULL); -+ -+ if (ctxt) { -+ debug("Rekey has happened - updating saved versions"); -+ -+ if (saved_name != GSS_C_NO_NAME) -+ gss_release_name(&minor, &saved_name); -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &saved_name, &saved_lifetime, NULL, NULL); -+ -+ if (!GSS_ERROR(major)) { -+ saved_mech = ctxt->oid; -+ saved_lifetime+= now; -+ } else { -+ /* Handle the error */ -+ } -+ return 0; -+ } -+ -+ if (now - last_call < 10) -+ return 0; -+ -+ last_call = now; -+ -+ if (saved_mech == GSS_C_NO_OID) -+ return 0; -+ -+ major = gss_inquire_cred(&minor, GSS_C_NO_CREDENTIAL, -+ &name, &lifetime, NULL, NULL); -+ if (major == GSS_S_CREDENTIALS_EXPIRED) -+ return 0; -+ else if (GSS_ERROR(major)) -+ return 0; -+ -+ major = gss_compare_name(&minor, saved_name, name, &equal); -+ gss_release_name(&minor, &name); -+ if (GSS_ERROR(major)) -+ return 0; -+ -+ if (equal && (saved_lifetime < lifetime + now - 10)) -+ return 1; -+ -+ return 0; -+} -+ - #endif /* GSSAPI */ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 759fa10..42de994 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - krb5_error_code problem; - krb5_principal princ; - OM_uint32 maj_status, min_status; -- int len; -+ const char *new_ccname, *new_cctype; - const char *errmsg; - - if (client->creds == NULL) { -@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_cctype = krb5_cc_get_type(krb_context, ccache); -+ new_ccname = krb5_cc_get_name(krb_context, ccache); -+ - client->store.envvar = "KRB5CCNAME"; -- len = strlen(client->store.filename) + 6; -- client->store.envval = xmalloc(len); -- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); -+#ifdef USE_CCAPI -+ xasprintf(&client->store.envval, "API:%s", new_ccname); -+ client->store.filename = NULL; -+#else -+ if (new_ccname[0] == ':') -+ new_ccname++; -+ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); -+ if (strcmp(new_cctype, "DIR") == 0) { -+ char *p; -+ p = strrchr(client->store.envval, '/'); -+ if (p) -+ *p = '\0'; -+ } -+ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) -+ client->store.filename = xstrdup(new_ccname); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - - krb5_cc_close(krb_context, ccache); - -+ client->store.data = krb_context; -+ - return; - } - -+int -+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client) -+{ -+ krb5_ccache ccache = NULL; -+ krb5_principal principal = NULL; -+ char *name = NULL; -+ krb5_error_code problem; -+ OM_uint32 maj_status, min_status; -+ -+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { -+ logit("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ return 0; -+ } -+ -+ /* Find out who the principal in this cache is */ -+ if ((problem = krb5_cc_get_principal(krb_context, ccache, -+ &principal))) { -+ logit("krb5_cc_get_principal(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { -+ logit("krb5_unparse_name(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ -+ if (strcmp(name,client->exportedname.value)!=0) { -+ debug("Name in local credentials cache differs. Not storing"); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ krb5_free_unparsed_name(krb_context, name); -+ return 0; -+ } -+ krb5_free_unparsed_name(krb_context, name); -+ -+ /* Name matches, so lets get on with it! */ -+ -+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { -+ logit("krb5_cc_initialize(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ krb5_free_principal(krb_context, principal); -+ -+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, -+ ccache))) { -+ logit("gss_krb5_copy_ccache() failed. Sorry!"); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ return 1; -+} -+ - ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", -@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { - NULL, - &ssh_gssapi_krb5_userok, - NULL, -- &ssh_gssapi_krb5_storecreds -+ &ssh_gssapi_krb5_storecreds, -+ &ssh_gssapi_krb5_updatecreds - }; - - #endif /* KRB5 */ -diff --git a/gss-serv.c b/gss-serv.c -index e61b37b..14f540e 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -45,15 +45,20 @@ - #include "channels.h" - #include "session.h" - #include "misc.h" -+#include "servconf.h" -+#include "uidswap.h" - - #include "ssh-gss.h" -+#include "monitor_wrap.h" -+ -+extern ServerOptions options; - - static ssh_gssapi_client gssapi_client = - { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, -- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; -+ GSS_C_NO_CREDENTIAL, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL}, 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; -@@ -100,25 +105,32 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) - char lname[MAXHOSTNAMELEN]; - gss_OID_set oidset; - -- gss_create_empty_oid_set(&status, &oidset); -- gss_add_oid_set_member(&status, ctx->oid, &oidset); -+ if (options.gss_strict_acceptor) { -+ gss_create_empty_oid_set(&status, &oidset); -+ gss_add_oid_set_member(&status, ctx->oid, &oidset); - -- if (gethostname(lname, MAXHOSTNAMELEN)) { -- gss_release_oid_set(&status, &oidset); -- return (-1); -- } -+ if (gethostname(lname, MAXHOSTNAMELEN)) { -+ gss_release_oid_set(&status, &oidset); -+ return (-1); -+ } -+ -+ if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { -+ gss_release_oid_set(&status, &oidset); -+ return (ctx->major); -+ } -+ -+ if ((ctx->major = gss_acquire_cred(&ctx->minor, -+ ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, -+ NULL, NULL))) -+ ssh_gssapi_error(ctx); - -- if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { - gss_release_oid_set(&status, &oidset); - return (ctx->major); -+ } else { -+ ctx->name = GSS_C_NO_NAME; -+ ctx->creds = GSS_C_NO_CREDENTIAL; - } -- -- if ((ctx->major = gss_acquire_cred(&ctx->minor, -- ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) -- ssh_gssapi_error(ctx); -- -- gss_release_oid_set(&status, &oidset); -- return (ctx->major); -+ return GSS_S_COMPLETE; - } - - /* Privileged */ -@@ -133,6 +145,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) - } - - /* Unprivileged */ -+char * -+ssh_gssapi_server_mechanisms() { -+ gss_OID_set supported; -+ -+ ssh_gssapi_supported_oids(&supported); -+ return (ssh_gssapi_kex_mechs(supported, &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) - { -@@ -142,7 +177,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) - gss_OID_set supported; - - gss_create_empty_oid_set(&min_status, oidset); -- gss_indicate_mechs(&min_status, &supported); -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) -+ return; - - while (supported_mechs[i]->name != NULL) { - if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -268,8 +305,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); - -- gss_buffer_desc ename; -+ if (GSS_ERROR(ctx->major)) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ if (!equal) { -+ debug("Rekeyed credentials have different name"); -+ return GSS_S_COMPLETE; -+ } -+ -+ debug("Marking rekeyed credentials for export"); -+ -+ gss_release_name(&ctx->minor, &client->name); -+ gss_release_cred(&ctx->minor, &client->creds); -+ client->name = new_name; -+ client->creds = ctx->client_creds; -+ ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ client->updated = 1; -+ return GSS_S_COMPLETE; -+ } - - client->mech = NULL; - -@@ -284,6 +361,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ if (ctx->client_creds && -+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ - if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, - &client->displayname, NULL))) { - ssh_gssapi_error(ctx); -@@ -301,6 +385,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - return (ctx->major); - } - -+ gss_release_buffer(&ctx->minor, &ename); -+ - /* We can't copy this structure, so we just move the pointer to it */ - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; -@@ -311,11 +397,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - void - ssh_gssapi_cleanup_creds(void) - { -- if (gssapi_client.store.filename != NULL) { -- /* Unlink probably isn't sufficient */ -- debug("removing gssapi cred file\"%s\"", -- gssapi_client.store.filename); -- unlink(gssapi_client.store.filename); -+ krb5_ccache ccache = NULL; -+ krb5_error_code problem; -+ -+ if (gssapi_client.store.data != NULL) { -+ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { -+ debug("%s: krb5_cc_resolve(): %.100s", __func__, -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { -+ debug("%s: krb5_cc_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; -+ } - } - } - -@@ -348,7 +443,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) - - /* Privileged */ - int --ssh_gssapi_userok(char *user) -+ssh_gssapi_userok(char *user, struct passwd *pw) - { - OM_uint32 lmin; - -@@ -358,9 +453,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); -@@ -374,14 +471,90 @@ ssh_gssapi_userok(char *user) - return (0); - } - --/* Privileged */ --OM_uint32 --ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+/* These bits are only used for rekeying. The unpriviledged child is running -+ * as the user, the monitor is root. -+ * -+ * In the child, we want to : -+ * *) Ask the monitor to store our credentials into the store we specify -+ * *) If it succeeds, maybe do a PAM update -+ */ -+ -+/* Stuff for PAM */ -+ -+#ifdef USE_PAM -+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, -+ struct pam_response **resp, void *data) - { -- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -- gssbuf, gssmic, NULL); -+ return (PAM_CONV_ERR); -+} -+#endif - -- return (ctx->major); -+void -+ssh_gssapi_rekey_creds() { -+ int ok; -+ int ret; -+#ifdef USE_PAM -+ pam_handle_t *pamh = NULL; -+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; -+ char *envstr; -+#endif -+ -+ if (gssapi_client.store.filename == NULL && -+ gssapi_client.store.envval == NULL && -+ gssapi_client.store.envvar == NULL) -+ return; -+ -+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -+ -+ if (!ok) -+ return; -+ -+ debug("Rekeyed credentials stored successfully"); -+ -+ /* Actually managing to play with the ssh pam stack from here will -+ * be next to impossible. In any case, we may want different options -+ * for rekeying. So, use our own :) -+ */ -+#ifdef USE_PAM -+ if (!use_privsep) { -+ debug("Not even going to try and do PAM with privsep disabled"); -+ return; -+ } -+ -+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, -+ &pamconv, &pamh); -+ if (ret) -+ return; -+ -+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, -+ gssapi_client.store.envval); -+ -+ ret = pam_putenv(pamh, envstr); -+ if (!ret) -+ pam_setcred(pamh, PAM_REINITIALIZE_CRED); -+ pam_end(pamh, PAM_SUCCESS); -+#endif -+} -+ -+int -+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { -+ int ok = 0; -+ -+ /* Check we've got credentials to store */ -+ if (!gssapi_client.updated) -+ return 0; -+ -+ gssapi_client.updated = 0; -+ -+ temporarily_use_uid(gssapi_client.store.owner); -+ if (gssapi_client.mech && gssapi_client.mech->updatecreds) -+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); -+ else -+ debug("No update function for this mechanism"); -+ -+ restore_uid(); -+ -+ return ok; - } - - #endif -diff --git a/kex.c b/kex.c -index 74e2b86..bce2ab8 100644 ---- a/kex.c -+++ b/kex.c -@@ -51,6 +51,10 @@ - #include "roaming.h" - #include "digest.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - #if OPENSSL_VERSION_NUMBER >= 0x00907000L - # if defined(HAVE_EVP_SHA256) - # define evp_ssh_sha256 EVP_sha256 -@@ -90,6 +94,11 @@ static const struct kexalg kexalgs[] = { - #ifdef HAVE_EVP_SHA256 - { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - #endif -+#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}, - }; - -@@ -119,6 +128,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 --git a/kex.h b/kex.h -index c85680e..313bb51 100644 ---- a/kex.h -+++ b/kex.h -@@ -76,6 +76,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 - }; - -@@ -135,6 +140,12 @@ struct Kex { - 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; - int (*verify_host_key)(Key *); -@@ -166,6 +177,10 @@ void kexecdh_client(Kex *); - void kexecdh_server(Kex *); - void kexc25519_client(Kex *); - void kexc25519_server(Kex *); -+#ifdef GSSAPI -+void kexgss_client(Kex *); -+void kexgss_server(Kex *); -+#endif - - void - kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, -diff --git a/kexgssc.c b/kexgssc.c -new file mode 100644 -index 0000000..e90b567 ---- /dev/null -+++ b/kexgssc.c -@@ -0,0 +1,334 @@ -+/* -+ * 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 "ssh-gss.h" -+ -+void -+kexgss_client(Kex *kex) { -+ 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, hashlen, strlen; -+ DH *dh; -+ BIGNUM *dh_server_pub = NULL; -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ u_char *kbuf, *hash; -+ 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; -+ -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); -+ -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); -+ -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); -+ -+ switch (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(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__, kex->kex_type); -+ } -+ -+ /* Step 1 - e is dh->pub_key */ -+ dh_gen_key(dh, 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, -+ 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); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( kex->client_version_string, -+ kex->server_version_string, -+ buffer_ptr(&kex->my), buffer_len(&kex->my), -+ buffer_ptr(&kex->peer), buffer_len(&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( -+ 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), -+ (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__, 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 (kex->session_id == NULL) { -+ kex->session_id_len = hashlen; -+ kex->session_id = xmalloc(kex->session_id_len); -+ memcpy(kex->session_id, hash, kex->session_id_len); -+ } -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ kex_derive_keys_bn(kex, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ kex_finish(kex); -+} -+ -+#endif /* GSSAPI */ -diff --git a/kexgsss.c b/kexgsss.c -new file mode 100644 -index 0000000..6d7518c ---- /dev/null -+++ b/kexgsss.c -@@ -0,0 +1,288 @@ -+/* -+ * 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 "servconf.h" -+ -+extern ServerOptions options; -+ -+void -+kexgss_server(Kex *kex) -+{ -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ u_int slen, klen, kout, hashlen; -+ u_char *kbuf, *hash; -+ DH *dh; -+ int min = -1, max = -1, nbits = -1; -+ BIGNUM *shared_secret = NULL; -+ BIGNUM *dh_client_pub = NULL; -+ int type = 0; -+ gss_OID oid; -+ char *mechs; -+ -+ /* Initialise GSSAPI */ -+ -+ /* If we're rekeying, privsep means that some of the private structures -+ * in the GSSAPI code are no longer available. This kludges them back -+ * into life -+ */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ free(mechs); -+ -+ debug2("%s: Identifying %s", __func__, kex->name); -+ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); -+ if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); -+ -+ debug2("%s: Acquiring credentials", __func__); -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ fatal("Unable to acquire credentials for the server"); -+ -+ switch (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); -+ min = packet_get_int(); -+ nbits = packet_get_int(); -+ max = packet_get_int(); -+ min = MAX(DH_GRP_MIN, min); -+ max = MIN(DH_GRP_MAX, max); -+ 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__, kex->kex_type); -+ } -+ -+ dh_gen_key(dh, 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); -+ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ kex_dh_hash( -+ kex->client_version_string, kex->server_version_string, -+ buffer_ptr(&kex->peer), buffer_len(&kex->peer), -+ buffer_ptr(&kex->my), buffer_len(&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( -+ 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), -+ NULL, 0, -+ min, nbits, max, -+ dh->p, dh->g, -+ dh_client_pub, -+ dh->pub_key, -+ shared_secret, -+ &hash, &hashlen -+ ); -+ break; -+ default: -+ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); -+ } -+ -+ BN_clear_free(dh_client_pub); -+ -+ if (kex->session_id == NULL) { -+ kex->session_id_len = hashlen; -+ kex->session_id = xmalloc(kex->session_id_len); -+ memcpy(kex->session_id, hash, kex->session_id_len); -+ } -+ -+ 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(kex, hash, hashlen, shared_secret); -+ BN_clear_free(shared_secret); -+ kex_finish(kex); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+} -+#endif /* GSSAPI */ -diff --git a/key.c b/key.c -index eb98ea8..900b9e3 100644 ---- a/key.c -+++ b/key.c -@@ -1013,6 +1013,7 @@ static const struct keytype keytypes[] = { - KEY_DSA_CERT_V00, 0, 1 }, - { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", - KEY_ED25519_CERT, 0, 1 }, -+ { "null", "null", KEY_NULL, 0, 0 }, - { NULL, NULL, -1, -1, 0 } - }; - -diff --git a/key.h b/key.h -index 0e3eea5..d51ed81 100644 ---- a/key.h -+++ b/key.h -@@ -46,6 +46,7 @@ enum types { - KEY_ED25519_CERT, - KEY_RSA_CERT_V00, - KEY_DSA_CERT_V00, -+ KEY_NULL, - KEY_UNSPEC - }; - enum fp_type { -diff --git a/monitor.c b/monitor.c -index 229fada..aa70945 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -178,6 +178,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 -@@ -253,11 +255,18 @@ struct mon_table mon_dispatch_proto20[] = { - {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, - {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, - {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, 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 - {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, - {MONITOR_REQ_SIGN, 0, mm_answer_sign}, - {MONITOR_REQ_PTY, 0, mm_answer_pty}, -@@ -366,6 +375,10 @@ monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) - /* Permit requests for moduli and signatures */ - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - } else { - mon_dispatch = mon_dispatch_proto15; - -@@ -471,6 +484,10 @@ monitor_child_postauth(struct monitor *pmonitor) - monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -+#ifdef GSSAPI -+ /* and for the GSSAPI key exchange */ -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); -+#endif - } else { - mon_dispatch = mon_dispatch_postauth15; - monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); -@@ -1866,6 +1883,13 @@ mm_get_kex(Buffer *m) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; - kex->kex[KEX_ECDH_SHA2] = kexecdh_server; - 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->hostkey_type = buffer_get_int(m); - kex->kex_type = buffer_get_int(m); -@@ -2073,6 +2097,9 @@ mm_answer_gss_setup_ctx(int sock, Buffer *m) - OM_uint32 major; - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - goid.elements = buffer_get_string(m, &len); - goid.length = len; - -@@ -2100,6 +2127,9 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) - OM_uint32 flags = 0; /* GSI needs this */ - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - in.value = buffer_get_string(m, &len); - in.length = len; - major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); -@@ -2117,6 +2147,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m) - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); -+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); - } - return (0); - } -@@ -2128,6 +2159,9 @@ mm_answer_gss_checkmic(int sock, Buffer *m) - OM_uint32 ret; - u_int len; - -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ - gssbuf.value = buffer_get_string(m, &len); - gssbuf.length = len; - mic.value = buffer_get_string(m, &len); -@@ -2154,7 +2188,11 @@ mm_answer_gss_userok(int sock, Buffer *m) - { - int authenticated; - -- authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); -+ if (!options.gss_authentication && !options.gss_keyex) -+ fatal("In GSSAPI monitor when GSSAPI is disabled"); -+ -+ authenticated = authctxt->valid && -+ ssh_gssapi_userok(authctxt->user, authctxt->pw); - - buffer_clear(m); - buffer_put_int(m, authenticated); -@@ -2167,5 +2205,73 @@ 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.filename = buffer_get_string(m, NULL); -+ store.envvar = buffer_get_string(m, NULL); -+ store.envval = buffer_get_string(m, NULL); -+ -+ ok = ssh_gssapi_update_creds(&store); -+ -+ free(store.filename); -+ 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 --git a/monitor.h b/monitor.h -index 20e2b4a..ff79fbb 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -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 --git a/monitor_wrap.c b/monitor_wrap.c -index d1b6d99..d1e1caa 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -1290,7 +1290,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) - } - - int --mm_ssh_gssapi_userok(char *user) -+mm_ssh_gssapi_userok(char *user, struct passwd *pw) - { - Buffer m; - int authenticated = 0; -@@ -1307,5 +1307,50 @@ 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->filename ? store->filename : ""); -+ 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 --git a/monitor_wrap.h b/monitor_wrap.h -index 9d5e5ba..93929e0 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -61,8 +61,10 @@ BIGNUM *mm_auth_rsa_generate_challenge(Key *); - 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 --git a/readconf.c b/readconf.c -index dc884c9..7613ff2 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -141,6 +141,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, -@@ -183,10 +185,19 @@ static struct { - { "afstokenpassing", oUnsupported }, - #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 - { "fallbacktorsh", oDeprecated }, - { "usersh", oDeprecated }, -@@ -841,10 +852,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; -@@ -1497,7 +1528,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; -@@ -1616,8 +1652,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 --git a/readconf.h b/readconf.h -index 75e3f8f..5cc97f0 100644 ---- a/readconf.h -+++ b/readconf.h -@@ -54,7 +54,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 --git a/regress/cert-hostkey.sh b/regress/cert-hostkey.sh -index 1d9e0ed..1277409 100644 ---- a/regress/cert-hostkey.sh -+++ b/regress/cert-hostkey.sh -@@ -17,7 +17,7 @@ ${SSHKEYGEN} -q -N '' -t rsa -f $OBJ/host_ca_key ||\ - cat $OBJ/host_ca_key.pub - ) > $OBJ/known_hosts-cert - --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-//'` - - type_has_legacy() { - case $1 in -diff --git a/regress/cert-userkey.sh b/regress/cert-userkey.sh -index b093a91..4c8da00 100644 ---- a/regress/cert-userkey.sh -+++ b/regress/cert-userkey.sh -@@ -6,7 +6,7 @@ tid="certified user keys" - rm -f $OBJ/authorized_keys_$USER $OBJ/user_ca_key* $OBJ/cert_user_key* - cp $OBJ/sshd_proxy $OBJ/sshd_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-//'` - - type_has_legacy() { - case $1 in -diff --git a/regress/kextype.sh b/regress/kextype.sh -index 8c2ac09..a2a87ca 100644 ---- a/regress/kextype.sh -+++ b/regress/kextype.sh -@@ -9,6 +9,9 @@ cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak - - 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 --git a/regress/rekey.sh b/regress/rekey.sh -index cf9401e..31fb0f7 100644 ---- a/regress/rekey.sh -+++ b/regress/rekey.sh -@@ -30,6 +30,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 -@@ -48,6 +51,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 -oRekeyLimit=256k -oCiphers=$c -oKexAlgorithms=$kex - done -diff --git a/servconf.c b/servconf.c -index f763317..68fb9ef 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -108,7 +108,10 @@ initialize_server_options(ServerOptions *options) - options->kerberos_ticket_cleanup = -1; - options->kerberos_get_afs_token = -1; - options->gss_authentication=-1; -+ options->gss_keyex = -1; - options->gss_cleanup_creds = -1; -+ options->gss_strict_acceptor = -1; -+ options->gss_store_rekey = -1; - options->password_authentication = -1; - options->kbd_interactive_authentication = -1; - options->challenge_response_authentication = -1; -@@ -245,8 +248,14 @@ fill_default_server_options(ServerOptions *options) - options->kerberos_get_afs_token = 0; - if (options->gss_authentication == -1) - options->gss_authentication = 0; -+ if (options->gss_keyex == -1) -+ options->gss_keyex = 0; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; -+ if (options->gss_strict_acceptor == -1) -+ options->gss_strict_acceptor = 1; -+ if (options->gss_store_rekey == -1) -+ options->gss_store_rekey = 0; - if (options->password_authentication == -1) - options->password_authentication = 1; - if (options->kbd_interactive_authentication == -1) -@@ -344,7 +353,8 @@ typedef enum { - sBanner, sShowPatchLevel, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, -- sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, -+ sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, -+ sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, - sMatch, sPermitOpen, sForceCommand, sChrootDirectory, - sUsePrivilegeSeparation, sAllowAgentForwarding, - sHostCertificate, -@@ -411,10 +421,20 @@ static struct { - #ifdef GSSAPI - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, - #else - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, - #endif -+ { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, - { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, - { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, - { "challengeresponseauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, -@@ -1091,10 +1111,22 @@ process_server_config_line(ServerOptions *options, char *line, - intptr = &options->gss_authentication; - goto parse_flag; - -+ case sGssKeyEx: -+ intptr = &options->gss_keyex; -+ goto parse_flag; -+ - case sGssCleanupCreds: - intptr = &options->gss_cleanup_creds; - goto parse_flag; - -+ case sGssStrictAcceptor: -+ 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; -@@ -2005,6 +2037,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 --git a/servconf.h b/servconf.h -index 4572066..37cfa9b 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -112,7 +112,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 --git a/ssh-gss.h b/ssh-gss.h -index a99d7f0..0374c88 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 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,16 +136,30 @@ 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); - -+char *ssh_gssapi_server_mechanisms(void); -+int ssh_gssapi_oid_table_ok(); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -diff --git a/ssh_config b/ssh_config -index 6d1abaf..b0d343b 100644 ---- a/ssh_config -+++ b/ssh_config -@@ -26,6 +26,8 @@ - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP yes - # AddressFamily any -diff --git a/ssh_config.5 b/ssh_config.5 -index b580392..e7accd6 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -682,11 +682,43 @@ Specifies whether user authentication based on GSSAPI is allowed. - The default is - .Dq no . - Note that this option applies to protocol version 2 only. -+.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 . -+Note that this option applies to protocol version 2 only. -+.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 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 GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. - The default is - .Dq no . --Note that this option applies to protocol version 2 only. -+Note that this option applies to protocol version 2 connections using GSSAPI. -+.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 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 . -+This option only applies to protocol version 2 connections using GSSAPI. - .It Cm HashKnownHosts - Indicates that - .Xr ssh 1 -diff --git a/sshconnect2.c b/sshconnect2.c -index adbbfc7..cadf234 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -158,9 +158,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - { - Kex *kex; - -+#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 = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ if (options.gss_trust_dns) -+ gss_host = (char *)get_canonical_hostname(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(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ } -+ } -+#endif -+ - if (options.ciphers == (char *)-1) { - logit("No valid ciphers for protocol version 2 given, using defaults."); - options.ciphers = NULL; -@@ -196,6 +221,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - if (options.kex_algorithms != NULL) - myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; - -+#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((u_int32_t)options.rekey_limit, - (time_t)options.rekey_interval); -@@ -208,10 +244,30 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; - kex->kex[KEX_ECDH_SHA2] = kexecdh_client; - kex->kex[KEX_C25519_SHA256] = kexc25519_client; -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; -+ } -+#endif - kex->client_version_string=client_version_string; - kex->server_version_string=server_version_string; - kex->verify_host_key=&verify_host_key_callback; - -+#ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->gss_deleg_creds = options.gss_deleg_creds; -+ kex->gss_trust_dns = options.gss_trust_dns; -+ kex->gss_client = options.gss_client_identity; -+ if (options.gss_server_identity) { -+ kex->gss_host = options.gss_server_identity; -+ } else { -+ kex->gss_host = gss_host; -+ } -+ } -+#endif -+ - xxx_kex = kex; - - dispatch_run(DISPATCH_BLOCK, &kex->done, kex); -@@ -301,6 +357,7 @@ void input_gssapi_token(int type, u_int32_t, void *); - void input_gssapi_hash(int type, u_int32_t, void *); - void input_gssapi_error(int, u_int32_t, void *); - void input_gssapi_errtok(int, u_int32_t, void *); -+int userauth_gsskeyex(Authctxt *authctxt); - #endif - - void userauth(Authctxt *, char *); -@@ -316,6 +373,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, -@@ -613,19 +675,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(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++; -@@ -722,8 +796,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) - { - Authctxt *authctxt = ctxt; - Gssctxt *gssctxt; -- int oidlen; -- char *oidv; -+ u_int oidlen; -+ u_char *oidv; - - if (authctxt == NULL) - fatal("input_gssapi_response: no authentication context"); -@@ -832,6 +906,48 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt) - free(msg); - free(lang); - } -+ -+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 --git a/sshd.c b/sshd.c -index 24ab272..e4e406e 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -122,6 +122,10 @@ - #include "ssh-sandbox.h" - #include "version.h" - -+#ifdef USE_SECURITY_SESSION_API -+#include -+#endif -+ - #ifdef LIBWRAP - #include - #include -@@ -1744,10 +1748,13 @@ main(int ac, char **av) - logit("Disabling protocol version 1. Could not load host key"); - options.protocol &= ~SSH_PROTO_1; - } -+#ifndef GSSAPI -+ /* The GSSAPI key exchange can run without a host key */ - if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { - logit("Disabling protocol version 2. Could not load host key"); - options.protocol &= ~SSH_PROTO_2; - } -+#endif - if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { - logit("sshd: no hostkeys available -- exiting."); - exit(1); -@@ -2488,6 +2495,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 */ - kex = kex_setup(myproposal); - kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; -@@ -2496,6 +2545,13 @@ do_ssh2_kex(void) - kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; - kex->kex[KEX_ECDH_SHA2] = kexecdh_server; - 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 --git a/sshd_config b/sshd_config -index c1b7c03..adfd7b1 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -91,6 +91,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 --git a/sshd_config.5 b/sshd_config.5 -index 95b5f8c..1fb002d 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -493,12 +493,40 @@ Specifies whether user authentication based on GSSAPI is allowed. - The default is - .Dq no . - Note that this option applies to protocol version 2 only. -+.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 . -+Note that this option applies to protocol version 2 only. - .It Cm GSSAPICleanupCredentials - Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Dq yes . - Note that this option applies to protocol version 2 only. -+.It Cm GSSAPIStrictAcceptorCheck -+Determines whether to be strict about the identity of the GSSAPI acceptor -+a client authenticates against. If -+.Dq yes -+then the client must authenticate against the -+.Pa host -+service on the current hostname. If -+.Dq no -+then the client may authenticate against any service key stored in the -+machine's default store. This facility is provided to assist with operation -+on multi homed machines. -+The default is -+.Dq yes . -+Note that this option applies only to protocol version 2 GSSAPI connections, -+and setting it to -+.Dq no -+may only work with recent Kerberos GSSAPI libraries. -+.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 HostbasedAuthentication - Specifies whether rhosts or /etc/hosts.equiv authentication together - with successful public key client host authentication is allowed -diff --git a/ssh-gss.h b/ssh-gss.h -index 132fd0d..39f6645 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -169,6 +169,7 @@ 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(); - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ diff --git a/SOURCES/openssh-6.6p1-keycat.patch b/SOURCES/openssh-6.6p1-keycat.patch index 49b9798..37aa9c5 100644 --- a/SOURCES/openssh-6.6p1-keycat.patch +++ b/SOURCES/openssh-6.6p1-keycat.patch @@ -1,8 +1,61 @@ -diff --git a/HOWTO.ssh-keycat b/HOWTO.ssh-keycat -new file mode 100644 -index 0000000..630ec62 ---- /dev/null -+++ b/HOWTO.ssh-keycat +diff -up openssh-7.4p1/auth2-pubkey.c.keycat openssh-7.4p1/auth2-pubkey.c +--- openssh-7.4p1/auth2-pubkey.c.keycat 2017-02-08 14:32:33.015581448 +0100 ++++ openssh-7.4p1/auth2-pubkey.c 2017-02-08 14:40:26.125216292 +0100 +@@ -1043,6 +1043,14 @@ user_key_command_allowed2(struct passwd + xasprintf(&command, "%s %s", av[0], av[1]); + } + ++#ifdef WITH_SELINUX ++ if (sshd_selinux_setup_env_variables() < 0) { ++ error ("failed to copy environment: %s", ++ strerror(errno)); ++ _exit(127); ++ } ++#endif ++ + if ((pid = subprocess("AuthorizedKeysCommand", pw, command, + ac, av, &f)) == 0) + goto out; +diff -up openssh-7.4p1/configure.ac.keycat openssh-7.4p1/configure.ac +--- openssh-7.4p1/configure.ac.keycat 2017-02-08 14:32:33.011581451 +0100 ++++ openssh-7.4p1/configure.ac 2017-02-08 14:32:33.016581448 +0100 +@@ -3129,6 +3129,7 @@ AC_ARG_WITH([pam], + PAM_MSG="yes" + + SSHDLIBS="$SSHDLIBS -lpam" ++ KEYCATLIBS="$KEYCATLIBS -lpam" + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) + +@@ -3139,6 +3140,7 @@ AC_ARG_WITH([pam], + ;; + *) + SSHDLIBS="$SSHDLIBS -ldl" ++ KEYCATLIBS="$KEYCATLIBS -ldl" + ;; + esac + fi +@@ -4255,6 +4257,7 @@ AC_ARG_WITH([selinux], + ) + AC_SUBST([SSHLIBS]) + AC_SUBST([SSHDLIBS]) ++AC_SUBST([KEYCATLIBS]) + + # Check whether user wants Kerberos 5 support + KRB5_MSG="no" +@@ -5206,6 +5209,9 @@ fi + if test ! -z "${SSHLIBS}"; then + echo " +for ssh: ${SSHLIBS}" + fi ++if test ! -z "${KEYCATLIBS}"; then ++echo " +for ssh-keycat: ${KEYCATLIBS}" ++fi + + echo "" + +diff -up openssh-7.4p1/HOWTO.ssh-keycat.keycat openssh-7.4p1/HOWTO.ssh-keycat +--- openssh-7.4p1/HOWTO.ssh-keycat.keycat 2017-02-08 14:32:33.014581449 +0100 ++++ openssh-7.4p1/HOWTO.ssh-keycat 2017-02-08 14:32:33.014581449 +0100 @@ -0,0 +1,12 @@ +The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys +of an user in any environment. This includes environments with @@ -16,10 +69,9 @@ index 0000000..630ec62 + PubkeyAuthentication yes + + -diff --git a/Makefile.in b/Makefile.in -index 411eadb..4ab6717 100644 ---- a/Makefile.in -+++ b/Makefile.in +diff -up openssh-7.4p1/Makefile.in.keycat openssh-7.4p1/Makefile.in +--- openssh-7.4p1/Makefile.in.keycat 2017-02-08 14:32:33.012581451 +0100 ++++ openssh-7.4p1/Makefile.in 2017-02-08 14:38:28.839306815 +0100 @@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper @@ -28,7 +80,7 @@ index 411eadb..4ab6717 100644 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@ +@@ -51,6 +52,7 @@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHLIBS=@SSHLIBS@ SSHDLIBS=@SSHDLIBS@ @@ -36,26 +88,26 @@ index 411eadb..4ab6717 100644 LIBEDIT=@LIBEDIT@ AR=@AR@ AWK=@AWK@ -@@ -64,7 +65,7 @@ EXEEXT=@EXEEXT@ +@@ -65,7 +67,7 @@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -176,6 +177,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-pkcs11-helper.o ssh-pkcs11 + LIBOPENSSH_OBJS=\ + ssh_api.o \ +@@ -190,6 +192,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) 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 -lfipscheck $(LIBS) + $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat -lfipscheck $(LIBS) +ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o + $(LD) -o $@ ssh-keycat.o bufaux.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(KEYCATLIBS) $(SSHLIBS) + - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o - $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -@@ -283,6 +287,7 @@ install-files: +@@ -332,6 +337,7 @@ install-files: $(INSTALL) -m 0700 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ fi @@ -63,29 +115,23 @@ index 411eadb..4ab6717 100644 $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index c0ae0d4..cb0f931 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -600,6 +600,14 @@ user_key_command_allowed2(struct passwd *user_pw, Key *key) - _exit(1); - } +diff -up openssh-7.4p1/openbsd-compat/port-linux.h.keycat openssh-7.4p1/openbsd-compat/port-linux.h +--- openssh-7.4p1/openbsd-compat/port-linux.h.keycat 2017-02-08 14:32:33.009581453 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux.h 2017-02-08 14:32:33.015581448 +0100 +@@ -23,8 +23,10 @@ void ssh_selinux_setup_pty(char *, const + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); -+#ifdef WITH_SELINUX -+ if (sshd_selinux_setup_env_variables() < 0) { -+ error ("failed to copy environment: %s", -+ strerror(errno)); -+ _exit(127); -+ } -+#endif -+ - execl(options.authorized_keys_command, - options.authorized_keys_command, user_pw->pw_name, NULL); ++int sshd_selinux_enabled(void); + void sshd_selinux_copy_context(void); + void sshd_selinux_setup_exec_context(char *); ++int sshd_selinux_setup_env_variables(void); + #endif -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index d04f4ed..0077dd7 100644 ---- a/openbsd-compat/port-linux-sshd.c -+++ b/openbsd-compat/port-linux-sshd.c + #ifdef LINUX_OOM_ADJUST +diff -up openssh-7.4p1/openbsd-compat/port-linux-sshd.c.keycat openssh-7.4p1/openbsd-compat/port-linux-sshd.c +--- openssh-7.4p1/openbsd-compat/port-linux-sshd.c.keycat 2017-02-08 14:32:33.008581454 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2017-02-08 14:32:33.015581448 +0100 @@ -53,6 +53,20 @@ extern Authctxt *the_authctxt; extern int inetd_flag; extern int rexeced_flag; @@ -161,7 +207,7 @@ index d04f4ed..0077dd7 100644 /* Set the execution context to the default for the specified user */ void sshd_selinux_setup_exec_context(char *pwname) -@@ -343,7 +375,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -343,7 +375,7 @@ sshd_selinux_setup_exec_context(char *pw int r = 0; security_context_t default_ctx = NULL; @@ -179,26 +225,10 @@ index d04f4ed..0077dd7 100644 return; if (getexeccon((security_context_t *)&ctx) != 0) { -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index b18893c..cb51f99 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -25,8 +25,10 @@ void ssh_selinux_setup_pty(char *, const char *); - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); - -+int sshd_selinux_enabled(void); - void sshd_selinux_copy_context(void); - void sshd_selinux_setup_exec_context(char *); -+int sshd_selinux_setup_env_variables(void); - #endif - - #ifdef LINUX_OOM_ADJUST -diff --git a/platform.c b/platform.c -index 0d39ab2..0dae387 100644 ---- a/platform.c -+++ b/platform.c -@@ -102,7 +102,7 @@ platform_setusercontext(struct passwd *pw) +diff -up openssh-7.4p1/platform.c.keycat openssh-7.4p1/platform.c +--- openssh-7.4p1/platform.c.keycat 2017-02-08 14:32:33.007581455 +0100 ++++ openssh-7.4p1/platform.c 2017-02-08 14:32:33.015581448 +0100 +@@ -99,7 +99,7 @@ platform_setusercontext(struct passwd *p { #ifdef WITH_SELINUX /* Cache selinux status for later use */ @@ -207,11 +237,9 @@ index 0d39ab2..0dae387 100644 #endif #ifdef USE_SOLARIS_PROJECTS -diff --git a/ssh-keycat.c b/ssh-keycat.c -new file mode 100644 -index 0000000..f8ed7af ---- /dev/null -+++ b/ssh-keycat.c +diff -up openssh-7.4p1/ssh-keycat.c.keycat openssh-7.4p1/ssh-keycat.c +--- openssh-7.4p1/ssh-keycat.c.keycat 2017-02-08 14:32:33.015581448 +0100 ++++ openssh-7.4p1/ssh-keycat.c 2017-02-08 14:32:33.015581448 +0100 @@ -0,0 +1,238 @@ +/* + * Redistribution and use in source and binary forms, with or without @@ -451,41 +479,3 @@ index 0000000..f8ed7af + } + return ev; +} -diff --git a/configure.ac b/configure.ac -index 3bbccfd..6481f1f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2952,6 +2952,7 @@ AC_ARG_WITH([pam], - PAM_MSG="yes" - - SSHDLIBS="$SSHDLIBS -lpam" -+ KEYCATLIBS="$KEYCATLIBS -lpam" - AC_DEFINE([USE_PAM], [1], - [Define if you want to enable PAM support]) - -@@ -2962,6 +2963,7 @@ AC_ARG_WITH([pam], - ;; - *) - SSHDLIBS="$SSHDLIBS -ldl" -+ KEYCATLIBS="$KEYCATLIBS -ldl" - ;; - esac - fi -@@ -4042,6 +4044,7 @@ AC_ARG_WITH([selinux], - ) - AC_SUBST([SSHLIBS]) - AC_SUBST([SSHDLIBS]) -+AC_SUBST([KEYCATLIBS]) - - # Check whether user wants Kerberos 5 support - KRB5_MSG="no" -@@ -5031,6 +5034,9 @@ fi - if test ! -z "${SSHLIBS}"; then - echo " +for ssh: ${SSHLIBS}" - fi -+if test ! -z "${KEYCATLIBS}"; then -+echo " +for ssh-keycat: ${KEYCATLIBS}" -+fi - - echo "" - diff --git a/SOURCES/openssh-6.6p1-keyperm.patch b/SOURCES/openssh-6.6p1-keyperm.patch index fccb328..1ac2c55 100644 --- a/SOURCES/openssh-6.6p1-keyperm.patch +++ b/SOURCES/openssh-6.6p1-keyperm.patch @@ -6,8 +6,8 @@ diff -up openssh-6.6p1/authfile.c.keyperm openssh-6.6p1/authfile.c #include #include +#include - #include #include + #include #include @@ -979,6 +980,13 @@ key_perm_ok(int fd, const char *filename #ifdef HAVE_CYGWIN diff --git a/SOURCES/openssh-6.6p1-kuserok.patch b/SOURCES/openssh-6.6p1-kuserok.patch deleted file mode 100644 index f7c5a1c..0000000 --- a/SOURCES/openssh-6.6p1-kuserok.patch +++ /dev/null @@ -1,294 +0,0 @@ -diff --git a/auth-krb5.c b/auth-krb5.c -index 6c62bdf..11c8562 100644 ---- a/auth-krb5.c -+++ b/auth-krb5.c -@@ -54,6 +54,21 @@ - - extern ServerOptions options; - -+int -+ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client, -+ int k5login_exists) -+{ -+ if (options.use_kuserok || !k5login_exists) -+ return krb5_kuserok(krb5_ctx, krb5_user, client); -+ else { -+ char kuser[65]; -+ -+ if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser)) -+ return 0; -+ return strcmp(kuser, client) == 0; -+ } -+} -+ - static int - krb5_init(void *context) - { -@@ -157,8 +172,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) - if (problem) - goto out; - -- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, -- authctxt->pw->pw_name)) { -+ /* Use !options.use_kuserok here to make ssh_krb5_kuserok() not -+ * depend on the existance of .k5login */ -+ if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name, !options.use_kuserok)) { - problem = -1; - goto out; - } -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 60de320..0a4930e 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, - int); - - static krb5_context krb_context = NULL; -+extern int ssh_krb5_kuserok(krb5_context, krb5_principal, const char *, int); - - /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ - -@@ -92,6 +93,103 @@ ssh_gssapi_krb5_init(void) - * Returns true if the user is OK to log in, otherwise returns 0 - */ - -+/* The purpose of the function is to find out if a Kerberos principal is -+ * allowed to log in as the given local user. This is a general problem with -+ * Kerberized services because by design the Kerberos principals are -+ * completely independent from the local user names. This is one of the -+ * reasons why Kerberos is working well on different operating systems like -+ * Windows and UNIX/Linux. Nevertheless a relationship between a Kerberos -+ * principal and a local user name must be established because otherwise every -+ * access would be granted for every principal with a valid ticket. -+ * -+ * Since it is a general issue libkrb5 provides some functions for -+ * applications to find out about the relationship between the Kerberos -+ * principal and a local user name. They are krb5_kuserok() and -+ * krb5_aname_to_localname(). -+ * -+ * krb5_kuserok() can be used to "Determine if a principal is authorized to -+ * log in as a local user" (from the MIT Kerberos documentation of this -+ * function). Which is exactly what we are looking for and should be the -+ * preferred choice. It accepts the Kerberos principal and a local user name -+ * and let libkrb5 or its plugins determine if they relate to each other or -+ * not. -+ * -+ * krb5_aname_to_localname() can use used to "Convert a principal name to a -+ * local name" (from the MIT Kerberos documentation of this function). It -+ * accepts a Kerberos principle and returns a local name and it is up to the -+ * application to do any additional checks. There are two issues using -+ * krb5_aname_to_localname(). First, since POSIX user names are case -+ * sensitive, the calling application in general has no other choice than -+ * doing a case-sensitive string comparison between the name returned by -+ * krb5_aname_to_localname() and the name used at the login prompt. When the -+ * users are provided by a case in-sensitive server, e.g. Active Directory, -+ * this might lead to login failures because the user typing the name at the -+ * login prompt might not be aware of the right case. Another issue might be -+ * caused if there are multiple alias names available for a single user. E.g. -+ * the canonical name of a user is user@group.department.example.com but there -+ * exists a shorter login name, e.g. user@example.com, to safe typing at the -+ * login prompt. Here krb5_aname_to_localname() can only return the canonical -+ * name, but if the short alias is used at the login prompt authentication -+ * will fail as well. All this can be avoided by using krb5_kuserok() and -+ * configuring krb5.conf or using a suitable plugin to meet the needs of the -+ * given environment. -+ * -+ * The Fedora and RHEL version of openssh contain two patches which modify the -+ * access control behavior: -+ * - openssh-6.6p1-kuserok.patch -+ * - openssh-6.6p1-force_krb.patch -+ * -+ * openssh-6.6p1-kuserok.patch adds a new option KerberosUseKuserok for -+ * sshd_config which controls if krb5_kuserok() is used to check if the -+ * principle is authorized or if krb5_aname_to_localname() should be used. -+ * The reason to add this patch was that krb5_kuserok() by default checks if -+ * a .k5login file exits in the users home-directory. With this the user can -+ * give access to his account for any given principal which might be -+ * in violation with company policies and it would be useful if this can be -+ * rejected. Nevertheless the patch ignores the fact that krb5_kuserok() does -+ * no only check .k5login but other sources as well and checking .k5login can -+ * be disabled for all applications in krb5.conf as well. With this new -+ * option KerberosUseKuserok set to 'no' (and this is the default for RHEL7 -+ * and Fedora 21) openssh can only use krb5_aname_to_localname() with the -+ * restrictions mentioned above. -+ * -+ * openssh-6.6p1-force_krb.patch adds a ksu like behaviour to ssh, i.e. when -+ * using GSSAPI authentication only commands configured in the .k5user can be -+ * executed. Here the wrong assumption that krb5_kuserok() only checks -+ * .k5login is made as well. In contrast ksu checks .k5login directly and -+ * does not use krb5_kuserok() which might be more useful for the given -+ * purpose. Additionally this patch is not synced with -+ * openssh-6.6p1-kuserok.patch. -+ * -+ * The current patch tries to restore the usage of krb5_kuserok() so that e.g. -+ * localauth plugins can be used. It does so by adding a forth parameter to -+ * ssh_krb5_kuserok() which indicates whether .k5login exists or not. If it -+ * does not exists krb5_kuserok() is called even if KerberosUseKuserok is set -+ * to 'no' because the intent of the option is to not check .k5login and if it -+ * does not exists krb5_kuserok() returns a result without checking .k5login. -+ * If .k5login does exists and KerberosUseKuserok is 'no' we fall back to -+ * krb5_aname_to_localname(). This is in my point of view an acceptable -+ * limitation and does not break the current behaviour. -+ * -+ * Additionally with this patch ssh_krb5_kuserok() is called in -+ * ssh_gssapi_krb5_cmdok() instead of only krb5_aname_to_localname() is -+ * neither .k5login nor .k5users exists to allow plugin evaluation via -+ * krb5_kuserok() as well. -+ * -+ * I tried to keep the patch as minimal as possible, nevertheless I see some -+ * areas for improvement which, if they make sense, have to be evaluated -+ * carefully because they might change existing behaviour and cause breaks -+ * during upgrade: -+ * - I wonder if disabling .k5login usage make sense in sshd or if it should -+ * be better disabled globally in krb5.conf -+ * - if really needed openssh-6.6p1-kuserok.patch should be fixed to really -+ * only disable checking .k5login and maybe .k5users -+ * - the ksu behaviour should be configurable and maybe check the .k5login and -+ * .k5users files directly like ksu itself does -+ * - to make krb5_aname_to_localname() more useful an option for sshd to use -+ * the canonical name (the one returned by getpwnam()) instead of the name -+ * given at the login prompt might be useful */ -+ - static int - ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) - { -@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) - /* NOTE: .k5login and .k5users must opened as root, not the user, - * because if they are on a krb5-protected filesystem, user credentials - * to access these files aren't available yet. */ -- if (krb5_kuserok(krb_context, princ, name) && k5login_exists) { -+ if (ssh_krb5_kuserok(krb_context, princ, name, k5login_exists) -+ && k5login_exists) { - retval = 1; - logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", - name, (char *)client->displayname.value); -@@ -171,9 +270,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, - snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); - /* If both .k5login and .k5users DNE, self-login is ok. */ - if (!k5login_exists && (access(file, F_OK) == -1)) { -- return (krb5_aname_to_localname(krb_context, principal, -- sizeof(kuser), kuser) == 0) && -- (strcmp(kuser, luser) == 0); -+ return ssh_krb5_kuserok(krb_context, principal, luser, -+ k5login_exists); - } - if ((fp = fopen(file, "r")) == NULL) { - int saved_errno = errno; -diff --git a/servconf.c b/servconf.c -index 68fb9ef..904c869 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -157,6 +157,7 @@ initialize_server_options(ServerOptions *options) - options->ip_qos_interactive = -1; - options->ip_qos_bulk = -1; - options->version_addendum = NULL; -+ options->use_kuserok = -1; - } - - void -@@ -312,6 +313,8 @@ fill_default_server_options(ServerOptions *options) - options->version_addendum = xstrdup(""); - if (options->show_patchlevel == -1) - options->show_patchlevel = 0; -+ if (options->use_kuserok == -1) -+ options->use_kuserok = 1; - - /* Turn privilege separation on by default */ - if (use_privsep == -1) -@@ -338,7 +341,7 @@ typedef enum { - sPermitRootLogin, sLogFacility, sLogLevel, - sRhostsRSAAuthentication, sRSAAuthentication, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, -- sKerberosGetAFSToken, -+ sKerberosGetAFSToken, sKerberosUseKuserok, - sKerberosTgtPassing, sChallengeResponseAuthentication, - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, -@@ -410,11 +413,13 @@ static struct { - #else - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, - #endif -+ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL }, - #else - { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, - { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, - { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, -+ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL }, - #endif - { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, - { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1526,6 +1531,10 @@ process_server_config_line(ServerOptions *options, char *line, - *activep = value; - break; - -+ case sKerberosUseKuserok: -+ intptr = &options->use_kuserok; -+ goto parse_flag; -+ - case sPermitOpen: - arg = strdelim(&cp); - if (!arg || *arg == '\0') -@@ -1811,6 +1820,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) - M_CP_INTOPT(max_authtries); - M_CP_INTOPT(ip_qos_interactive); - M_CP_INTOPT(ip_qos_bulk); -+ M_CP_INTOPT(use_kuserok); - M_CP_INTOPT(rekey_limit); - M_CP_INTOPT(rekey_interval); - -@@ -2062,6 +2072,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sUseDNS, o->use_dns); - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); -+ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); - - /* string arguments */ - dump_cfg_string(sPidFile, o->pid_file); -diff --git a/servconf.h b/servconf.h -index 37cfa9b..5117dfa 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -173,6 +173,7 @@ typedef struct { - - int num_permitted_opens; - -+ int use_kuserok; - char *chroot_directory; - char *revoked_keys_file; - char *trusted_user_ca_keys; -diff --git a/sshd_config b/sshd_config -index adfd7b1..e772ed5 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -87,6 +87,7 @@ ChallengeResponseAuthentication no - #KerberosOrLocalPasswd yes - #KerberosTicketCleanup yes - #KerberosGetAFSToken no -+#KerberosUseKuserok yes - - # GSSAPI options - GSSAPIAuthentication yes -diff --git a/sshd_config.5 b/sshd_config.5 -index 1fb002d..e0e5fff 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -697,6 +697,10 @@ Specifies whether to automatically destroy the user's ticket cache - file on logout. - The default is - .Dq yes . -+.It Cm KerberosUseKuserok -+Specifies whether to look at .k5login file for user's aliases. -+The default is -+.Dq yes . - .It Cm KexAlgorithms - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. -@@ -862,6 +866,7 @@ Available keywords are - .Cm HostbasedUsesNameFromPacketOnly , - .Cm KbdInteractiveAuthentication , - .Cm KerberosAuthentication , -+.Cm KerberosUseKuserok , - .Cm MaxAuthTries , - .Cm MaxSessions , - .Cm PasswordAuthentication , diff --git a/SOURCES/openssh-6.6p1-ldap.patch b/SOURCES/openssh-6.6p1-ldap.patch index fb8dd2b..ef5b14b 100644 --- a/SOURCES/openssh-6.6p1-ldap.patch +++ b/SOURCES/openssh-6.6p1-ldap.patch @@ -1,8 +1,6 @@ -diff --git a/HOWTO.ldap-keys b/HOWTO.ldap-keys -new file mode 100644 -index 0000000..dd5f5cc ---- /dev/null -+++ b/HOWTO.ldap-keys +diff -up openssh-7.4p1/HOWTO.ldap-keys.ldap openssh-7.4p1/HOWTO.ldap-keys +--- openssh-7.4p1/HOWTO.ldap-keys.ldap 2017-02-08 14:26:19.935750452 +0100 ++++ openssh-7.4p1/HOWTO.ldap-keys 2017-02-08 14:26:19.935750452 +0100 @@ -0,0 +1,125 @@ + +HOW TO START @@ -129,10 +127,9 @@ index 0000000..dd5f5cc +5) Author + Jan F. Chadima + -diff --git a/Makefile.in b/Makefile.in -index 28a8ec4..411eadb 100644 ---- a/Makefile.in -+++ b/Makefile.in +diff -up openssh-7.4p1/Makefile.in.ldap openssh-7.4p1/Makefile.in +--- openssh-7.4p1/Makefile.in.ldap 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/Makefile.in 2017-02-08 14:31:36.851624797 +0100 @@ -25,6 +25,8 @@ SSH_PROGRAM=@bindir@/ssh ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass SFTP_SERVER=$(libexecdir)/sftp-server @@ -142,7 +139,7 @@ index 28a8ec4..411eadb 100644 SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper PRIVSEP_PATH=@PRIVSEP_PATH@ SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ -@@ -60,8 +62,9 @@ XAUTH_PATH=@XAUTH_PATH@ +@@ -61,8 +63,9 @@ XAUTH_PATH=@XAUTH_PATH@ LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ EXEEXT=@EXEEXT@ MANFMT=@MANFMT@ @@ -151,11 +148,11 @@ index 28a8ec4..411eadb 100644 -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) - LIBSSH_OBJS=authfd.o authfile.o bufaux.o bufbn.o buffer.o \ - canohost.o channels.o cipher.o cipher-aes.o \ -@@ -98,8 +101,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ - sandbox-seccomp-filter.o sandbox-capsicum.o + LIBOPENSSH_OBJS=\ + ssh_api.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 -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 @@ -164,17 +161,17 @@ index 28a8ec4..411eadb 100644 MANTYPE = @MANTYPE@ CONFIGFILES=sshd_config.out ssh_config.out moduli.out -@@ -170,6 +173,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o readco +@@ -184,6 +187,9 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss 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) +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 -lfipscheck $(LIBS) ++ $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat -lfipscheck $(LIBS) + - ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o - $(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) -@@ -273,6 +279,10 @@ install-files: +@@ -322,6 +328,10 @@ install-files: $(INSTALL) -m 0755 $(STRIP_OPT) sshd$(EXEEXT) $(DESTDIR)$(sbindir)/sshd$(EXEEXT) $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) @@ -185,7 +182,7 @@ index 28a8ec4..411eadb 100644 $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -@@ -289,6 +299,10 @@ install-files: +@@ -338,6 +348,10 @@ install-files: $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 @@ -193,10 +190,10 @@ index 28a8ec4..411eadb 100644 + $(INSTALL) -m 644 ssh-ldap-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 ; \ + $(INSTALL) -m 644 ssh-ldap.conf.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh-ldap.conf.5 ; \ + fi - -rm -f $(DESTDIR)$(bindir)/slogin - ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 -@@ -318,6 +332,13 @@ install-sysconf: + + install-sysconf: + if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ +@@ -363,6 +377,13 @@ install-sysconf: else \ echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ fi @@ -210,7 +207,7 @@ index 28a8ec4..411eadb 100644 host-key: ssh-keygen$(EXEEXT) @if [ -z "$(DESTDIR)" ] ; then \ -@@ -381,6 +402,8 @@ uninstall: +@@ -403,6 +424,8 @@ uninstall: -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) @@ -219,19 +216,18 @@ index 28a8ec4..411eadb 100644 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 -@@ -392,6 +415,7 @@ uninstall: +@@ -414,6 +437,7 @@ uninstall: -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-ldap-helper.8 - -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 - regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c -diff --git a/configure.ac b/configure.ac -index 7c6ce08..722a19e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1625,6 +1625,106 @@ if test "x$use_pie" != "xno"; then + regress-prep: + [ -d `pwd`/regress ] || mkdir -p `pwd`/regress +diff -up openssh-7.4p1/configure.ac.ldap openssh-7.4p1/configure.ac +--- openssh-7.4p1/configure.ac.ldap 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/configure.ac 2017-02-08 14:26:19.936750452 +0100 +@@ -1656,6 +1656,106 @@ if test "x$use_pie" != "xno"; then fi fi @@ -338,11 +334,9 @@ index 7c6ce08..722a19e 100644 dnl Checks for library functions. Please keep in alphabetical order AC_CHECK_FUNCS([ \ Blowfish_initstate \ -diff --git a/ldap-helper.c b/ldap-helper.c -new file mode 100644 -index 0000000..e95a94a ---- /dev/null -+++ b/ldap-helper.c +diff -up openssh-7.4p1/ldap-helper.c.ldap openssh-7.4p1/ldap-helper.c +--- openssh-7.4p1/ldap-helper.c.ldap 2017-02-08 14:26:19.936750452 +0100 ++++ openssh-7.4p1/ldap-helper.c 2017-02-08 14:26:19.936750452 +0100 @@ -0,0 +1,155 @@ +/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -499,11 +493,9 @@ index 0000000..e95a94a +void *buffer_get_string(Buffer *b, u_int *l) { return NULL; } +void buffer_put_string(Buffer *b, const void *f, u_int l) {} + -diff --git a/ldap-helper.h b/ldap-helper.h -new file mode 100644 -index 0000000..14cb29a ---- /dev/null -+++ b/ldap-helper.h +diff -up openssh-7.4p1/ldap-helper.h.ldap openssh-7.4p1/ldap-helper.h +--- openssh-7.4p1/ldap-helper.h.ldap 2017-02-08 14:26:19.936750452 +0100 ++++ openssh-7.4p1/ldap-helper.h 2017-02-08 14:26:19.936750452 +0100 @@ -0,0 +1,32 @@ +/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -537,12 +529,10 @@ index 0000000..14cb29a +extern int config_warning_config_file; + +#endif /* LDAP_HELPER_H */ -diff --git a/ldap.conf b/ldap.conf -new file mode 100644 -index 0000000..42e38d3 ---- /dev/null -+++ b/ldap.conf -@@ -0,0 +1,88 @@ +diff -up openssh-7.4p1/ldap.conf.ldap openssh-7.4p1/ldap.conf +--- openssh-7.4p1/ldap.conf.ldap 2017-02-08 14:26:19.936750452 +0100 ++++ openssh-7.4p1/ldap.conf 2017-02-08 14:26:19.936750452 +0100 +@@ -0,0 +1,94 @@ +# $Id: openssh-5.5p1-ldap.patch,v 1.3 2010/07/07 13:48:36 jfch2222 Exp $ +# +# This is the example configuration file for the OpenSSH @@ -631,11 +621,15 @@ index 0000000..42e38d3 +#tls_cert +#tls_key + -diff --git a/ldapbody.c b/ldapbody.c -new file mode 100644 -index 0000000..3029108 ---- /dev/null -+++ b/ldapbody.c ++# OpenLDAP search_format ++# format used to search for users in LDAP directory using substitution ++# for %u for user name and %f for SSH_Filter option (optional, empty by default) ++#search_format (&(objectclass=%c)(objectclass=ldapPublicKey)(uid=%u)%f) ++ ++#AccountClass posixAccount +diff -up openssh-7.4p1/ldapbody.c.ldap openssh-7.4p1/ldapbody.c +--- openssh-7.4p1/ldapbody.c.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapbody.c 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,493 @@ +/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1130,11 +1124,9 @@ index 0000000..3029108 + return; +} + -diff --git a/ldapbody.h b/ldapbody.h -new file mode 100644 -index 0000000..665dca2 ---- /dev/null -+++ b/ldapbody.h +diff -up openssh-7.4p1/ldapbody.h.ldap openssh-7.4p1/ldapbody.h +--- openssh-7.4p1/ldapbody.h.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapbody.h 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,37 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1173,12 +1165,10 @@ index 0000000..665dca2 + +#endif /* LDAPBODY_H */ + -diff --git a/ldapconf.c b/ldapconf.c -new file mode 100644 -index 0000000..525060a ---- /dev/null -+++ b/ldapconf.c -@@ -0,0 +1,729 @@ +diff -up openssh-7.4p1/ldapconf.c.ldap openssh-7.4p1/ldapconf.c +--- openssh-7.4p1/ldapconf.c.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapconf.c 2017-02-08 14:26:19.937750451 +0100 +@@ -0,0 +1,728 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* + * Copyright (c) 2009 Jan F. Chadima. All rights reserved. @@ -1641,7 +1631,7 @@ index 0000000..525060a +{ + FILE *f; + char line[1024]; -+ int active, linenum; ++ int linenum; + int bad_options = 0; + struct stat sb; + @@ -1660,7 +1650,6 @@ index 0000000..525060a + * Mark that we are now processing the options. This flag is turned + * on/off by Host specifications. + */ -+ active = 1; + linenum = 0; + while (fgets(line, sizeof(line), f)) { + /* Update line number counter. */ @@ -1755,7 +1744,7 @@ index 0000000..525060a + len = snprintf (options.uri, MAXURILEN, "ldap%s://%s:%d", + (options.ssl == 0) ? "" : "s", options.host, options.port); + options.uri[MAXURILEN - 1] = 0; -+ options.uri = xrealloc (options.uri, len + 1, 1); ++ options.uri = xreallocarray(options.uri, len + 1, 1); + } + if (options.binddn == NULL) + options.binddn = ""; @@ -1905,14 +1894,12 @@ index 0000000..525060a + dump_cfg_int(lDebug, options.debug); + dump_cfg_string(lSSH_Filter, options.ssh_filter); + dump_cfg_string(lSearch_Format, options.search_format); -+ dump_cfg_string(lAccountClass, options.logdir); ++ dump_cfg_string(lAccountClass, options.account_class); +} + -diff --git a/ldapconf.h b/ldapconf.h -new file mode 100644 -index 0000000..2cb550c ---- /dev/null -+++ b/ldapconf.h +diff -up openssh-7.4p1/ldapconf.h.ldap openssh-7.4p1/ldapconf.h +--- openssh-7.4p1/ldapconf.h.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapconf.h 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,73 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -1987,11 +1974,9 @@ index 0000000..2cb550c +void dump_config(void); + +#endif /* LDAPCONF_H */ -diff --git a/ldapincludes.h b/ldapincludes.h -new file mode 100644 -index 0000000..8539bdc ---- /dev/null -+++ b/ldapincludes.h +diff -up openssh-7.4p1/ldapincludes.h.ldap openssh-7.4p1/ldapincludes.h +--- openssh-7.4p1/ldapincludes.h.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapincludes.h 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,41 @@ +/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2034,11 +2019,9 @@ index 0000000..8539bdc +#endif + +#endif /* LDAPINCLUDES_H */ -diff --git a/ldapmisc.c b/ldapmisc.c -new file mode 100644 -index 0000000..de23c0c ---- /dev/null -+++ b/ldapmisc.c +diff -up openssh-7.4p1/ldapmisc.c.ldap openssh-7.4p1/ldapmisc.c +--- openssh-7.4p1/ldapmisc.c.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapmisc.c 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,79 @@ + +#include "ldapincludes.h" @@ -2119,11 +2102,9 @@ index 0000000..de23c0c +} +#endif + -diff --git a/ldapmisc.h b/ldapmisc.h -new file mode 100644 -index 0000000..4c271df ---- /dev/null -+++ b/ldapmisc.h +diff -up openssh-7.4p1/ldapmisc.h.ldap openssh-7.4p1/ldapmisc.h +--- openssh-7.4p1/ldapmisc.h.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/ldapmisc.h 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,35 @@ +/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ +/* @@ -2160,11 +2141,9 @@ index 0000000..4c271df + +#endif /* LDAPMISC_H */ + -diff --git a/openssh-lpk-openldap.schema b/openssh-lpk-openldap.schema -new file mode 100644 -index 0000000..c84f90f ---- /dev/null -+++ b/openssh-lpk-openldap.schema +diff -up openssh-7.4p1/openssh-lpk-openldap.schema.ldap openssh-7.4p1/openssh-lpk-openldap.schema +--- openssh-7.4p1/openssh-lpk-openldap.schema.ldap 2017-02-08 14:26:19.937750451 +0100 ++++ openssh-7.4p1/openssh-lpk-openldap.schema 2017-02-08 14:26:19.937750451 +0100 @@ -0,0 +1,21 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2187,11 +2166,9 @@ index 0000000..c84f90f + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -diff --git a/openssh-lpk-sun.schema b/openssh-lpk-sun.schema -new file mode 100644 -index 0000000..3136673 ---- /dev/null -+++ b/openssh-lpk-sun.schema +diff -up openssh-7.4p1/openssh-lpk-sun.schema.ldap openssh-7.4p1/openssh-lpk-sun.schema +--- openssh-7.4p1/openssh-lpk-sun.schema.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/openssh-lpk-sun.schema 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,23 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2216,11 +2193,9 @@ index 0000000..3136673 + DESC 'MANDATORY: OpenSSH LPK objectclass' + MUST ( sshPublicKey $ uid ) + ) -diff --git a/ssh-ldap-helper.8 b/ssh-ldap-helper.8 -new file mode 100644 -index 0000000..5d2d7be ---- /dev/null -+++ b/ssh-ldap-helper.8 +diff -up openssh-7.4p1/ssh-ldap-helper.8.ldap openssh-7.4p1/ssh-ldap-helper.8 +--- openssh-7.4p1/ssh-ldap-helper.8.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/ssh-ldap-helper.8 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,79 @@ +.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ +.\" @@ -2301,21 +2276,17 @@ index 0000000..5d2d7be +OpenSSH 5.5 + PKA-LDAP . +.Sh AUTHORS +.An Jan F. Chadima Aq jchadima@redhat.com -diff --git a/ssh-ldap-wrapper b/ssh-ldap-wrapper -new file mode 100644 -index 0000000..cb500aa ---- /dev/null -+++ b/ssh-ldap-wrapper +diff -up openssh-7.4p1/ssh-ldap-wrapper.ldap openssh-7.4p1/ssh-ldap-wrapper +--- openssh-7.4p1/ssh-ldap-wrapper.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/ssh-ldap-wrapper 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,4 @@ +#!/bin/sh + +exec /usr/libexec/openssh/ssh-ldap-helper -s "$1" + -diff --git a/ssh-ldap.conf.5 b/ssh-ldap.conf.5 -new file mode 100644 -index 0000000..f7081b8 ---- /dev/null -+++ b/ssh-ldap.conf.5 +diff -up openssh-7.4p1/ssh-ldap.conf.5.ldap openssh-7.4p1/ssh-ldap.conf.5 +--- openssh-7.4p1/ssh-ldap.conf.5.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/ssh-ldap.conf.5 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,379 @@ +.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $ +.\" @@ -2702,11 +2673,9 @@ index 0000000..f7081b8 +OpenSSH 5.5 + PKA-LDAP . +.Sh AUTHORS +.An Jan F. Chadima Aq jchadima@redhat.com -diff --git a/openssh-lpk-openldap.ldif b/openssh-lpk-openldap.ldif -new file mode 100644 -index 0000000..9adf4b8 ---- /dev/null -+++ b/openssh-lpk-openldap.ldif +diff -up openssh-7.4p1/openssh-lpk-openldap.ldif.ldap openssh-7.4p1/openssh-lpk-openldap.ldif +--- openssh-7.4p1/openssh-lpk-openldap.ldif.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/openssh-lpk-openldap.ldif 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,19 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey @@ -2727,11 +2696,9 @@ index 0000000..9adf4b8 +olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 + NAME 'ldapPublicKey' DESC 'MANDATORY: OpenSSH LPK objectclass' + SUP top AUXILIARY MUST ( sshPublicKey $ uid ) ) -diff --git a/openssh-lpk-sun.ldif b/openssh-lpk-sun.ldif -new file mode 100644 -index 0000000..9adf4b8 ---- /dev/null -+++ b/openssh-lpk-sun.ldif +diff -up openssh-7.4p1/openssh-lpk-sun.ldif.ldap openssh-7.4p1/openssh-lpk-sun.ldif +--- openssh-7.4p1/openssh-lpk-sun.ldif.ldap 2017-02-08 14:26:19.938750451 +0100 ++++ openssh-7.4p1/openssh-lpk-sun.ldif 2017-02-08 14:26:19.938750451 +0100 @@ -0,0 +1,17 @@ +# +# LDAP Public Key Patch schema for use with openssh-ldappubkey diff --git a/SOURCES/openssh-6.6p1-memory-problems.patch b/SOURCES/openssh-6.6p1-memory-problems.patch index f359193..0f5a0ab 100644 --- a/SOURCES/openssh-6.6p1-memory-problems.patch +++ b/SOURCES/openssh-6.6p1-memory-problems.patch @@ -1,8 +1,7 @@ -diff --git a/servconf.c b/servconf.c -index ad5869b..0255ed3 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -1910,6 +1910,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) +diff -up openssh-7.4p1/servconf.c.memory-problems openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.memory-problems 2017-02-09 10:41:42.483123417 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 10:42:16.392102462 +0100 +@@ -2006,6 +2006,8 @@ copy_set_server_options(ServerOptions *d dst->n = src->n; \ } while (0) @@ -10,8 +9,8 @@ index ad5869b..0255ed3 100644 + M_CP_INTOPT(password_authentication); M_CP_INTOPT(gss_authentication); - M_CP_INTOPT(rsa_authentication); -@@ -1947,8 +1949,10 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) + M_CP_INTOPT(pubkey_authentication); +@@ -2058,8 +2060,10 @@ copy_set_server_options(ServerOptions *d } while(0) #define M_CP_STRARRAYOPT(n, num_n) do {\ if (src->num_n != 0) { \ @@ -23,21 +22,4 @@ index ad5869b..0255ed3 100644 } \ } while(0) -diff --git a/sshd.c b/sshd.c -index 7e43153..f2a08f6 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2160,10 +2160,12 @@ main(int ac, char **av) - } - #endif /* LIBWRAP */ - -+ char *addr = get_local_ipaddr(sock_in); - /* Log the connection. */ - verbose("Connection from %s port %d on %s port %d", - remote_ip, remote_port, -- get_local_ipaddr(sock_in), get_local_port()); -+ addr, get_local_port()); -+ free(addr); - - /* - * We don't want to listen forever unless the other side +diff -up openssh-7.4p1/sshd.c.memory-problems openssh-7.4p1/sshd.c diff --git a/SOURCES/openssh-6.6p1-permitopen-any-host.patch b/SOURCES/openssh-6.6p1-permitopen-any-host.patch deleted file mode 100644 index ec519b2..0000000 --- a/SOURCES/openssh-6.6p1-permitopen-any-host.patch +++ /dev/null @@ -1,74 +0,0 @@ -diff -up openssh-6.6p1/channels.c.permitopen openssh-6.6p1/channels.c ---- openssh-6.6p1/channels.c.permitopen 2016-06-29 15:37:08.780327108 +0200 -+++ openssh-6.6p1/channels.c 2016-06-29 16:04:38.480857525 +0200 -@@ -128,6 +128,9 @@ static int num_adm_permitted_opens = 0; - /* special-case port number meaning allow any port */ - #define FWD_PERMIT_ANY_PORT 0 - -+/* special-case wildcard meaning allow any host */ -+#define FWD_PERMIT_ANY_HOST "*" -+ - /* - * If this is true, all opens are permitted. This is the case on the server - * on which we have to trust the client anyway, and the user could do -@@ -3271,6 +3274,21 @@ port_match(u_short allowedport, u_short - return 0; - } - -+static int -+open_match(ForwardPermission *allowed_open, const char *requestedhost, -+ u_short requestedport) -+{ -+ if (allowed_open->host_to_connect == NULL) -+ return 0; -+ if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT && -+ allowed_open->port_to_connect != requestedport) -+ return 0; -+ if (strcmp(allowed_open->host_to_connect, FWD_PERMIT_ANY_HOST) != 0 && -+ strcmp(allowed_open->host_to_connect, requestedhost) != 0) -+ return 0; -+ return 1; -+} -+ - /* Try to start non-blocking connect to next host in cctx list */ - static int - connect_next(struct channel_connect *cctx) -@@ -3391,20 +3409,18 @@ channel_connect_to(const char *host, u_s - permit = all_opens_permitted; - if (!permit) { - for (i = 0; i < num_permitted_opens; i++) -- if (permitted_opens[i].host_to_connect != NULL && -- port_match(permitted_opens[i].port_to_connect, port) && -- strcmp(permitted_opens[i].host_to_connect, host) == 0) -+ if (open_match(&permitted_opens[i], host, port)) { - permit = 1; -+ } - } - - if (num_adm_permitted_opens > 0) { - permit_adm = 0; - for (i = 0; i < num_adm_permitted_opens; i++) -- if (permitted_adm_opens[i].host_to_connect != NULL && -- port_match(permitted_adm_opens[i].port_to_connect, port) && -- strcmp(permitted_adm_opens[i].host_to_connect, host) -- == 0) -+ if (open_match(&permitted_adm_opens[i], host, port)) { - permit_adm = 1; -+ break; -+ } - } - - if (!permit || !permit_adm) { -diff -up openssh-6.6p1/sshd_config.5.permitopen openssh-6.6p1/sshd_config.5 ---- openssh-6.6p1/sshd_config.5.permitopen 2016-06-29 15:37:08.778327110 +0200 -+++ openssh-6.6p1/sshd_config.5 2016-06-29 15:37:08.782327106 +0200 -@@ -1005,6 +1005,9 @@ can be used to remove all restrictions a - An argument of - .Dq none - can be used to prohibit all forwarding requests. -+Wildcard -+.Dq * -+can be used for host or port to allow all hosts or all ports respectively. - By default all port forwarding requests are permitted. - .It Cm PermitRootLogin - Specifies whether root can log in using diff --git a/SOURCES/openssh-6.6p1-privsep-selinux.patch b/SOURCES/openssh-6.6p1-privsep-selinux.patch index 6507647..8b7d0c2 100644 --- a/SOURCES/openssh-6.6p1-privsep-selinux.patch +++ b/SOURCES/openssh-6.6p1-privsep-selinux.patch @@ -89,9 +89,9 @@ index 07f9926..a97f8b7 100644 + ssh_selinux_change_context("sshd_net_t"); +#endif + - /* Change our root directory */ - if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) - fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, + /* Demote the child */ + if (getuid() == 0 || geteuid() == 0) { + /* Change our root directory */ @@ -768,6 +772,13 @@ privsep_postauth(Authctxt *authctxt) do_setusercontext(authctxt->pw); diff --git a/SOURCES/openssh-6.6p1-redhat.patch b/SOURCES/openssh-6.6p1-redhat.patch index 12f4a9f..cd48484 100644 --- a/SOURCES/openssh-6.6p1-redhat.patch +++ b/SOURCES/openssh-6.6p1-redhat.patch @@ -1,8 +1,7 @@ -diff --git a/ssh_config b/ssh_config -index 49a4f6c..3f83c40 100644 ---- a/ssh_config -+++ b/ssh_config -@@ -50,3 +50,15 @@ +diff -up openssh-7.4p1/ssh_config.redhat openssh-7.4p1/ssh_config +--- openssh-7.4p1/ssh_config.redhat 2017-02-08 15:22:30.811307915 +0100 ++++ openssh-7.4p1/ssh_config 2017-02-08 15:22:30.812307915 +0100 +@@ -52,3 +52,15 @@ # Uncomment this if you want to use .local domain # Host *.local # CheckHostIP no @@ -18,11 +17,38 @@ index 49a4f6c..3f83c40 100644 + SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT + SendEnv LC_IDENTIFICATION LC_ALL LANGUAGE + SendEnv XMODIFIERS -diff --git a/sshd_config b/sshd_config -index c735429..e68ddee 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -10,6 +10,10 @@ +diff -up openssh-7.4p1/sshd_config.0.redhat openssh-7.4p1/sshd_config.0 +--- openssh-7.4p1/sshd_config.0.redhat 2016-12-19 06:21:22.000000000 +0100 ++++ openssh-7.4p1/sshd_config.0 2017-02-08 15:22:30.813307914 +0100 +@@ -837,9 +837,9 @@ DESCRIPTION + + SyslogFacility + Gives the facility code that is used when logging messages from +- sshd(8). The possible values are: DAEMON, USER, AUTH, LOCAL0, +- LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The +- default is AUTH. ++ sshd(8). The possible values are: DAEMON, USER, AUTH, AUTHPRIV, ++ LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. ++ The default is AUTH. + + TCPKeepAlive + Specifies whether the system should send TCP keepalive messages +diff -up openssh-7.4p1/sshd_config.5.redhat openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.redhat 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-08 15:22:30.813307914 +0100 +@@ -1393,7 +1393,7 @@ By default no subsystems are defined. + .It Cm SyslogFacility + Gives the facility code that is used when logging messages from + .Xr sshd 8 . +-The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, ++The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2, + LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. + The default is AUTH. + .It Cm TCPKeepAlive +diff -up openssh-7.4p1/sshd_config.redhat openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.redhat 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshd_config 2017-02-08 15:33:24.705736576 +0100 +@@ -10,21 +10,26 @@ # possible, but leave them commented. Uncommented options override the # default value. @@ -33,10 +59,8 @@ index c735429..e68ddee 100644 #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 -@@ -21,10 +25,10 @@ - # HostKey for protocol version 1 - #HostKey /etc/ssh/ssh_host_key - # HostKeys for protocol version 2 + #ListenAddress :: + -#HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key @@ -45,17 +69,16 @@ index c735429..e68ddee 100644 +HostKey /etc/ssh/ssh_host_ecdsa_key +HostKey /etc/ssh/ssh_host_ed25519_key - # Lifetime and size of ephemeral version 1 server key - #KeyRegenerationInterval 1h -@@ -36,6 +40,7 @@ + # Ciphers and keying + #RekeyLimit default none + # Logging - # obsoletes QuietMode and FascistLogging #SyslogFacility AUTH +SyslogFacility AUTHPRIV #LogLevel INFO # Authentication: -@@ -71,9 +76,11 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -57,9 +62,11 @@ AuthorizedKeysFile .ssh/authorized_keys # To disable tunneled clear text passwords, change to no here! #PasswordAuthentication yes #PermitEmptyPasswords no @@ -67,7 +90,7 @@ index c735429..e68ddee 100644 # Kerberos options #KerberosAuthentication no -@@ -82,8 +89,8 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -68,8 +75,8 @@ AuthorizedKeysFile .ssh/authorized_keys #KerberosGetAFSToken no # GSSAPI options @@ -78,7 +101,7 @@ index c735429..e68ddee 100644 # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will -@@ -94,12 +101,12 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -80,12 +87,12 @@ AuthorizedKeysFile .ssh/authorized_keys # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and ChallengeResponseAuthentication to 'no'. @@ -93,7 +116,7 @@ index c735429..e68ddee 100644 #X11DisplayOffset 10 #X11UseLocalhost yes #PermitTTY yes -@@ -122,6 +129,12 @@ UsePrivilegeSeparation sandbox # Default for new installations. +@@ -108,6 +115,12 @@ AuthorizedKeysFile .ssh/authorized_keys # no default banner path #Banner none @@ -106,33 +129,3 @@ index c735429..e68ddee 100644 # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server -diff --git a/sshd_config.0 b/sshd_config.0 -index 413c260..87e7ee7 100644 ---- a/sshd_config.0 -+++ b/sshd_config.0 -@@ -675,9 +675,9 @@ DESCRIPTION - - SyslogFacility - Gives the facility code that is used when logging messages from -- sshd(8). The possible values are: DAEMON, USER, AUTH, LOCAL0, -- LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The -- default is AUTH. -+ sshd(8). The possible values are: DAEMON, USER, AUTH, AUTHPRIV, -+ LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. -+ The default is AUTH. - - TCPKeepAlive - Specifies whether the system should send TCP keepalive messages -diff --git a/sshd_config.5 b/sshd_config.5 -index ce71efe..12465c2 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1131,7 +1131,7 @@ Note that this option applies to protocol version 2 only. - .It Cm SyslogFacility - Gives the facility code that is used when logging messages from - .Xr sshd 8 . --The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, -+The possible values are: DAEMON, USER, AUTH, AUTHPRIV, LOCAL0, LOCAL1, LOCAL2, - LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. - The default is AUTH. - .It Cm TCPKeepAlive diff --git a/SOURCES/openssh-6.6p1-role-mls.patch b/SOURCES/openssh-6.6p1-role-mls.patch deleted file mode 100644 index 4740c99..0000000 --- a/SOURCES/openssh-6.6p1-role-mls.patch +++ /dev/null @@ -1,896 +0,0 @@ -diff --git a/auth-pam.c b/auth-pam.c -index d789bad..cd1a775 100644 ---- a/auth-pam.c -+++ b/auth-pam.c -@@ -1068,7 +1068,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 --git a/auth-pam.h b/auth-pam.h -index a1a2b52..b109a5a 100644 ---- a/auth-pam.h -+++ b/auth-pam.h -@@ -38,7 +38,7 @@ void do_pam_session(void); - void do_pam_set_tty(const char *); - 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 --git a/auth.h b/auth.h -index 124e597..4605588 100644 ---- a/auth.h -+++ b/auth.h -@@ -59,6 +59,9 @@ struct Authctxt { - char *service; - struct passwd *pw; /* set if 'valid' */ - char *style; -+#ifdef WITH_SELINUX -+ char *role; -+#endif - void *kbdintctxt; - char *info; /* Extra info for next auth_log */ - #ifdef BSD_AUTH -diff --git a/auth1.c b/auth1.c -index 0f870b3..df040bb 100644 ---- a/auth1.c -+++ b/auth1.c -@@ -381,6 +381,9 @@ do_authentication(Authctxt *authctxt) - { - u_int ulen; - char *user, *style = NULL; -+#ifdef WITH_SELINUX -+ char *role=NULL; -+#endif - - /* Get the name of the user that we wish to log in as. */ - packet_read_expect(SSH_CMSG_USER); -@@ -389,11 +392,24 @@ do_authentication(Authctxt *authctxt) - user = packet_get_cstring(&ulen); - packet_check_eom(); - -+#ifdef WITH_SELINUX -+ if ((role = strchr(user, '/')) != NULL) -+ *role++ = '\0'; -+#endif -+ - if ((style = strchr(user, ':')) != NULL) - *style++ = '\0'; -+#ifdef WITH_SELINUX -+ else -+ if (role && (style = strchr(role, ':')) != NULL) -+ *style++ = '\0'; -+#endif - - authctxt->user = user; - authctxt->style = style; -+#ifdef WITH_SELINUX -+ authctxt->role = role; -+#endif - - /* Verify that the user is a valid user. */ - if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) -diff --git a/auth2-gss.c b/auth2-gss.c -index c28a705..4756dd7 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -251,6 +251,7 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) - Authctxt *authctxt = ctxt; - Gssctxt *gssctxt; - int authenticated = 0; -+ char *micuser; - Buffer b; - gss_buffer_desc mic, gssbuf; - u_int len; -@@ -263,7 +264,13 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) - 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); -@@ -275,6 +282,8 @@ input_gssapi_mic(int type, u_int32_t plen, void *ctxt) - logit("GSSAPI MIC check failed"); - - buffer_free(&b); -+ if (micuser != authctxt->user) -+ free(micuser); - free(mic.value); - - authctxt->postponed = 0; -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index eca0069..95d678e 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -112,7 +112,15 @@ userauth_hostbased(Authctxt *authctxt) - buffer_put_string(&b, session_id2, session_id2_len); - /* reconstruct packet */ - buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); -- buffer_put_cstring(&b, authctxt->user); -+#ifdef WITH_SELINUX -+ if (authctxt->role) { -+ buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1); -+ buffer_append(&b, authctxt->user, strlen(authctxt->user)); -+ buffer_put_char(&b, '/'); -+ buffer_append(&b, authctxt->role, strlen(authctxt->role)); -+ } else -+#endif -+ buffer_put_cstring(&b, authctxt->user); - buffer_put_cstring(&b, service); - buffer_put_cstring(&b, "hostbased"); - buffer_put_string(&b, pkalg, alen); -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 749b11a..c0ae0d4 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -133,9 +133,11 @@ userauth_pubkey(Authctxt *authctxt) - } - /* reconstruct packet */ - buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); -- 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 : "", -+ authctxt->role ? "/" : "", -+ authctxt->role ? authctxt->role : ""); - buffer_put_cstring(&b, userstyle); - free(userstyle); - buffer_put_cstring(&b, -diff --git a/auth2.c b/auth2.c -index a5490c0..5f4f26f 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt) - Authctxt *authctxt = ctxt; - 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_t seq, void *ctxt) - 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_t seq, void *ctxt) - 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 --git a/misc.c b/misc.c -index e4c8c32..f31cd91 100644 ---- a/misc.c -+++ b/misc.c -@@ -430,6 +430,7 @@ char * - colon(char *cp) - { - int flag = 0; -+ int start = 1; - - if (*cp == ':') /* Leading colon is part of file name. */ - return NULL; -@@ -445,6 +446,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 --git a/monitor.c b/monitor.c -index 531c4f9..229fada 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -145,6 +145,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 *); -@@ -219,6 +222,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 -@@ -805,6 +811,9 @@ mm_answer_pwnamallow(int sock, Buffer *m) - else { - /* 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 -@@ -846,6 +855,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) - { -@@ -1220,7 +1248,7 @@ static int - monitor_valid_userblob(u_char *data, u_int datalen) - { - Buffer b; -- char *p, *userstyle; -+ char *p, *r, *userstyle; - u_int len; - int fail = 0; - -@@ -1246,6 +1274,8 @@ monitor_valid_userblob(u_char *data, u_int datalen) - 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 : ""); -@@ -1281,7 +1311,7 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, - char *chost) - { - Buffer b; -- char *p, *userstyle; -+ char *p, *r, *userstyle; - u_int len; - int fail = 0; - -@@ -1298,6 +1328,8 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, - 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 --git a/monitor.h b/monitor.h -index 5bc41b5..20e2b4a 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -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 --git a/monitor_wrap.c b/monitor_wrap.c -index 1a47e41..d1b6d99 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -336,6 +336,25 @@ mm_inform_authserv(char *service, char *style) - 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(Authctxt *authctxt, char *password) -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 18c2501..9d5e5ba 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -42,6 +42,9 @@ int mm_is_monitor(void); - DH *mm_choose_dh(int, int, int); - int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int); - 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 Authctxt *, char *); -diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in -index 6ecfb93..b912dbe 100644 ---- a/openbsd-compat/Makefile.in -+++ b/openbsd-compat/Makefile.in -@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di - - COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o - --PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o -+PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.o - - .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -new file mode 100644 -index 0000000..c18524e ---- /dev/null -+++ b/openbsd-compat/port-linux-sshd.c -@@ -0,0 +1,414 @@ -+/* -+ * 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 "servconf.h" -+#include "port-linux.h" -+#include "key.h" -+#include "hostfile.h" -+#include "auth.h" -+ -+#ifdef WITH_SELINUX -+#include -+#include -+#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; -+ unsigned int bit = CONTEXT__CONTAINS; -+ -+ debug("%s: src:%s dst:%s", __func__, src, dst); -+ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, 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 --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index 4637a7a..22ea8ef 100644 ---- a/openbsd-compat/port-linux.c -+++ b/openbsd-compat/port-linux.c -@@ -103,37 +103,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) -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index e3d1004..8ef6cc4 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -22,9 +22,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 --git a/platform.c b/platform.c -index 30fc609..0d39ab2 100644 ---- a/platform.c -+++ b/platform.c -@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(struct passwd *pw) - } - #endif /* HAVE_SETPCRED */ - #ifdef WITH_SELINUX -- ssh_selinux_setup_exec_context(pw->pw_name); -+ sshd_selinux_setup_exec_context(pw->pw_name); - #endif - } - -diff --git a/sshd.c b/sshd.c -index 7523de9..07f9926 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -2138,6 +2138,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/SOURCES/openssh-6.6p1-security-7.0.patch b/SOURCES/openssh-6.6p1-security-7.0.patch deleted file mode 100644 index 1e6963d..0000000 --- a/SOURCES/openssh-6.6p1-security-7.0.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/monitor.c b/monitor.c -index b410965..f1b873d 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -1084,9 +1084,7 @@ extern KbdintDevice sshpam_device; - int - mm_answer_pam_init_ctx(int sock, Buffer *m) - { -- - debug3("%s", __func__); -- authctxt->user = buffer_get_string(m, NULL); - sshpam_ctxt = (sshpam_device.init_ctx)(authctxt); - sshpam_authok = NULL; - buffer_clear(m); -@@ -1166,14 +1166,16 @@ mm_answer_pam_respond(int sock, Buffer *m) - int - mm_answer_pam_free_ctx(int sock, Buffer *m) - { -+ int r = sshpam_authok != NULL && sshpam_authok == sshpam_ctxt; - - debug3("%s", __func__); - (sshpam_device.free_ctx)(sshpam_ctxt); -+ sshpam_ctxt = sshpam_authok = NULL; - buffer_clear(m); - mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m); - auth_method = "keyboard-interactive"; - auth_submethod = "pam"; -- return (sshpam_authok == sshpam_ctxt); -+ return r; - } - #endif - -diff --git a/monitor_wrap.c b/monitor_wrap.c -index e6217b3..eac421b 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -614,7 +614,6 @@ mm_sshpam_init_ctx(Authctxt *authctxt) - - debug3("%s", __func__); - buffer_init(&m); -- buffer_put_cstring(&m, authctxt->user); - mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m); - debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__); - mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m); diff --git a/SOURCES/openssh-6.6p1-set_remote_ipaddr.patch b/SOURCES/openssh-6.6p1-set_remote_ipaddr.patch deleted file mode 100644 index 166e569..0000000 --- a/SOURCES/openssh-6.6p1-set_remote_ipaddr.patch +++ /dev/null @@ -1,87 +0,0 @@ -diff --git a/canohost.c b/canohost.c -index 97ce58c..1f9320a 100644 ---- a/canohost.c -+++ b/canohost.c -@@ -338,6 +338,21 @@ clear_cached_addr(void) - cached_port = -1; - } - -+void set_remote_ipaddr(void) { -+ if (canonical_host_ip != NULL) -+ free(canonical_host_ip); -+ -+ if (packet_connection_is_on_socket()) { -+ canonical_host_ip = -+ get_peer_ipaddr(packet_get_connection_in()); -+ if (canonical_host_ip == NULL) -+ cleanup_exit(255); -+ } else { -+ /* If not on socket, return UNKNOWN. */ -+ canonical_host_ip = xstrdup("UNKNOWN"); -+ } -+} -+ - /* - * Returns the IP-address of the remote host as a string. The returned - * string must not be freed. -@@ -347,17 +362,9 @@ const char * - get_remote_ipaddr(void) - { - /* Check whether we have cached the ipaddr. */ -- if (canonical_host_ip == NULL) { -- if (packet_connection_is_on_socket()) { -- canonical_host_ip = -- get_peer_ipaddr(packet_get_connection_in()); -- if (canonical_host_ip == NULL) -- cleanup_exit(255); -- } else { -- /* If not on socket, return UNKNOWN. */ -- canonical_host_ip = xstrdup("UNKNOWN"); -- } -- } -+ if (canonical_host_ip == NULL) -+ set_remote_ipaddr(); -+ - return canonical_host_ip; - } - -diff --git a/canohost.h b/canohost.h -index 4c8636f..4079953 100644 ---- a/canohost.h -+++ b/canohost.h -@@ -13,6 +13,7 @@ - */ - - const char *get_canonical_hostname(int); -+void set_remote_ipaddr(void); - const char *get_remote_ipaddr(void); - const char *get_remote_name_or_ip(u_int, int); - -diff --git a/sshconnect.c b/sshconnect.c -index e636f33..451a58b 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -62,6 +62,7 @@ - #include "monitor_fdpass.h" - #include "ssh2.h" - #include "version.h" -+#include "canohost.h" - - char *client_version_string = NULL; - char *server_version_string = NULL; -@@ -170,6 +171,7 @@ ssh_proxy_fdpass_connect(const char *host, u_short port, - - /* Set the connection file descriptors. */ - packet_set_connection(sock, sock); -+ set_remote_ipaddr(); - - return 0; - } -@@ -492,6 +494,7 @@ ssh_connect_direct(const char *host, struct addrinfo *aitop, - - /* Set the connection. */ - packet_set_connection(sock, sock); -+ set_remote_ipaddr(); - - return 0; - } diff --git a/SOURCES/openssh-6.6p1-sftp-force-permission.patch b/SOURCES/openssh-6.6p1-sftp-force-permission.patch index a35b7b7..21607e7 100644 --- a/SOURCES/openssh-6.6p1-sftp-force-permission.patch +++ b/SOURCES/openssh-6.6p1-sftp-force-permission.patch @@ -1,6 +1,6 @@ -diff -up openssh-6.6p1/sftp-server.8.sftp-force-mode openssh-6.6p1/sftp-server.8 ---- openssh-6.6p1/sftp-server.8.sftp-force-mode 2013-10-15 03:07:05.000000000 +0200 -+++ openssh-6.6p1/sftp-server.8 2015-04-20 14:04:47.427562510 +0200 +diff -up openssh-7.4p1/sftp-server.8.sftp-force-mode openssh-7.4p1/sftp-server.8 +--- openssh-7.4p1/sftp-server.8.sftp-force-mode 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sftp-server.8 2017-02-09 10:35:41.926475399 +0100 @@ -38,6 +38,7 @@ .Op Fl P Ar blacklisted_requests .Op Fl p Ar whitelisted_requests @@ -19,11 +19,11 @@ diff -up openssh-6.6p1/sftp-server.8.sftp-force-mode openssh-6.6p1/sftp-server.8 +777, 755, 750, 666, 644, 640, etc. Option -u is ineffective if -m is set. .El .Pp - For logging to work, -diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c ---- openssh-6.6p1/sftp-server.c.sftp-force-mode 2015-04-20 14:04:47.420562526 +0200 -+++ openssh-6.6p1/sftp-server.c 2015-04-20 14:07:13.799231025 +0200 -@@ -71,6 +71,10 @@ static Buffer oqueue; + On some systems, +diff -up openssh-7.4p1/sftp-server.c.sftp-force-mode openssh-7.4p1/sftp-server.c +--- openssh-7.4p1/sftp-server.c.sftp-force-mode 2017-02-09 10:22:36.498019921 +0100 ++++ openssh-7.4p1/sftp-server.c 2017-02-09 10:35:07.190520959 +0100 +@@ -65,6 +65,10 @@ struct sshbuf *oqueue; /* Version of client */ static u_int version; @@ -34,18 +34,18 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c /* SSH2_FXP_INIT received */ static int init_done; -@@ -668,6 +672,7 @@ process_open(u_int32_t id) - Attrib *a; +@@ -679,6 +683,7 @@ process_open(u_int32_t id) + Attrib a; char *name; - int handle, fd, flags, mode, status = SSH2_FX_FAILURE; -+ mode_t old_umask; + int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE; ++ mode_t old_umask = 0; - name = get_string(NULL); - pflags = get_int(); /* portable flags */ -@@ -675,6 +680,10 @@ process_open(u_int32_t id) - a = get_attrib(); + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ +@@ -688,6 +693,10 @@ process_open(u_int32_t id) + debug3("request %u: open flags %d", id, pflags); flags = flags_from_portable(pflags); - mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; + mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; + if (permforce == 1) { /* Force perm if -m is set */ + mode = permforcemode; + old_umask = umask(0); /* so umask does not interfere */ @@ -53,7 +53,7 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); if (readonly && -@@ -696,6 +705,8 @@ process_open(u_int32_t id) +@@ -709,6 +718,8 @@ process_open(u_int32_t id) } } } @@ -62,7 +62,7 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c if (status != SSH2_FX_OK) send_status(id, status); free(name); -@@ -1430,7 +1441,7 @@ sftp_server_usage(void) +@@ -1490,7 +1501,7 @@ sftp_server_usage(void) fprintf(stderr, "usage: %s [-ehR] [-d start_directory] [-f log_facility] " "[-l log_level]\n\t[-P blacklisted_requests] " @@ -71,7 +71,7 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c " %s -Q protocol_feature\n", __progname, __progname); exit(1); -@@ -1455,7 +1463,7 @@ sftp_server_main(int argc, char **argv, +@@ -1516,7 +1527,7 @@ sftp_server_main(int argc, char **argv, pw = pwcopy(user_pw); while (!skipargs && (ch = getopt(argc, argv, @@ -80,7 +80,7 @@ diff -up openssh-6.6p1/sftp-server.c.sftp-force-mode openssh-6.6p1/sftp-server.c switch (ch) { case 'Q': if (strcasecmp(optarg, "requests") != 0) { -@@ -1515,6 +1523,15 @@ sftp_server_main(int argc, char **argv, +@@ -1576,6 +1587,15 @@ sftp_server_main(int argc, char **argv, fatal("Invalid umask \"%s\"", optarg); (void)umask((mode_t)mask); break; diff --git a/SOURCES/openssh-6.6p1-ssh-agent-and-xsecurity-bypass.patch b/SOURCES/openssh-6.6p1-ssh-agent-and-xsecurity-bypass.patch deleted file mode 100644 index 3435cf2..0000000 --- a/SOURCES/openssh-6.6p1-ssh-agent-and-xsecurity-bypass.patch +++ /dev/null @@ -1,214 +0,0 @@ -diff -up openssh-6.6p1/channels.c.security openssh-6.6p1/channels.c ---- openssh-6.6p1/channels.c.security 2015-07-01 19:27:08.521162690 +0200 -+++ openssh-6.6p1/channels.c 2015-07-01 19:27:08.597162521 +0200 -@@ -151,6 +151,9 @@ static char *x11_saved_proto = NULL; - static char *x11_saved_data = NULL; - static u_int x11_saved_data_len = 0; - -+/* Deadline after which all X11 connections are refused */ -+static u_int x11_refuse_time; -+ - /* - * Fake X11 authentication data. This is what the server will be sending us; - * we should replace any occurrences of this by the real data. -@@ -894,6 +897,13 @@ x11_open_helper(Buffer *b) - u_char *ucp; - u_int proto_len, data_len; - -+ /* Is this being called after the refusal deadline? */ -+ if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) { -+ verbose("Rejected X11 connection after ForwardX11Timeout " -+ "expired"); -+ return -1; -+ } -+ - /* Check if the fixed size part of the packet is in buffer. */ - if (buffer_len(b) < 12) - return 0; -@@ -1457,6 +1467,12 @@ channel_set_reuseaddr(int fd) - error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno)); - } - -+void -+channel_set_x11_refuse_time(u_int refuse_time) -+{ -+ x11_refuse_time = refuse_time; -+} -+ - /* - * This socket is listening for connections to a forwarded TCP/IP port. - */ -diff -up openssh-6.6p1/channels.h.security openssh-6.6p1/channels.h ---- openssh-6.6p1/channels.h.security 2015-07-01 19:27:08.597162521 +0200 -+++ openssh-6.6p1/channels.h 2015-07-01 19:43:32.900950560 +0200 -@@ -279,6 +279,7 @@ int permitopen_port(const char *); - - /* x11 forwarding */ - -+void channel_set_x11_refuse_time(u_int); - int x11_connect_display(void); - int x11_create_display_inet(int, int, int, u_int *, int **); - void x11_input_open(int, u_int32_t, void *); -diff -up openssh-6.6p1/clientloop.c.security openssh-6.6p1/clientloop.c ---- openssh-6.6p1/clientloop.c.security 2015-07-01 19:27:08.540162648 +0200 -+++ openssh-6.6p1/clientloop.c 2015-07-01 19:44:51.139761508 +0200 -@@ -164,7 +164,7 @@ static int connection_in; /* Connection - static int connection_out; /* Connection to server (output). */ - static int need_rekeying; /* Set to non-zero if rekeying is requested. */ - static int session_closed; /* In SSH2: login session closed. */ --static int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ -+static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ - - static void client_init_dispatch(void); - int session_ident = -1; -@@ -302,7 +302,8 @@ client_x11_display_valid(const char *dis - return 1; - } - --#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" -+#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" -+#define X11_TIMEOUT_SLACK 60 - void - client_x11_get_proto(const char *display, const char *xauth_path, - u_int trusted, u_int timeout, char **_proto, char **_data) -@@ -315,7 +316,7 @@ client_x11_get_proto(const char *display - int got_data = 0, generated = 0, do_unlink = 0, i; - char *xauthdir, *xauthfile; - struct stat st; -- u_int now; -+ u_int now, x11_timeout_real; - - xauthdir = xauthfile = NULL; - *_proto = proto; -@@ -348,6 +349,15 @@ client_x11_get_proto(const char *display - xauthdir = xmalloc(MAXPATHLEN); - xauthfile = xmalloc(MAXPATHLEN); - mktemp_proto(xauthdir, MAXPATHLEN); -+ /* -+ * The authentication cookie should briefly outlive -+ * ssh's willingness to forward X11 connections to -+ * avoid nasty fail-open behaviour in the X server. -+ */ -+ if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) -+ x11_timeout_real = UINT_MAX; -+ else -+ x11_timeout_real = timeout + X11_TIMEOUT_SLACK; - if (mkdtemp(xauthdir) != NULL) { - do_unlink = 1; - snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", -@@ -355,17 +365,20 @@ client_x11_get_proto(const char *display - snprintf(cmd, sizeof(cmd), - "%s -f %s generate %s " SSH_X11_PROTO - " untrusted timeout %u 2>" _PATH_DEVNULL, -- xauth_path, xauthfile, display, timeout); -+ xauth_path, xauthfile, display, -+ x11_timeout_real); - debug2("x11_get_proto: %s", cmd); -- if (system(cmd) == 0) -- generated = 1; - if (x11_refuse_time == 0) { - now = monotime() + 1; - if (UINT_MAX - timeout < now) - x11_refuse_time = UINT_MAX; - else - x11_refuse_time = now + timeout; -+ channel_set_x11_refuse_time( -+ x11_refuse_time); - } -+ if (system(cmd) == 0) -+ generated = 1; - } - } - -@@ -1884,7 +1897,7 @@ client_request_x11(const char *request_t - "malicious server."); - return NULL; - } -- if (x11_refuse_time != 0 && monotime() >= x11_refuse_time) { -+ if (x11_refuse_time != 0 && (u_int)monotime() >= x11_refuse_time) { - verbose("Rejected X11 connection after ForwardX11Timeout " - "expired"); - return NULL; -diff -up openssh-6.6p1/ssh-agent.c.security openssh-6.6p1/ssh-agent.c ---- openssh-6.6p1/ssh-agent.c.security 2015-07-01 19:27:08.597162521 +0200 -+++ openssh-6.6p1/ssh-agent.c 2015-07-01 19:42:35.691088800 +0200 -@@ -64,6 +64,9 @@ - #include - #include - #include -+#ifdef HAVE_UTIL_H -+#include -+#endif - - #include "xmalloc.h" - #include "ssh.h" -@@ -129,8 +130,12 @@ char socket_name[MAXPATHLEN]; - char socket_dir[MAXPATHLEN]; - - /* locking */ -+#define LOCK_SIZE 32 -+#define LOCK_SALT_SIZE 16 -+#define LOCK_ROUNDS 1 - int locked = 0; --char *lock_passwd = NULL; -+char lock_passwd[LOCK_SIZE]; -+char lock_salt[LOCK_SALT_SIZE]; - - extern char *__progname; - -@@ -548,22 +553,45 @@ send: - static void - process_lock_agent(SocketEntry *e, int lock) - { -- int success = 0; -- char *passwd; -+ int success = 0, delay; -+ char *passwd, passwdhash[LOCK_SIZE]; -+ static u_int fail_count = 0; -+ size_t pwlen; - - passwd = buffer_get_string(&e->request, NULL); -- if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { -- locked = 0; -- explicit_bzero(lock_passwd, strlen(lock_passwd)); -- free(lock_passwd); -- lock_passwd = NULL; -- success = 1; -+ pwlen = strlen(passwd); -+ if (pwlen == 0) { -+ debug("empty password not supported"); -+ } else if (locked && !lock) { -+ if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), -+ passwdhash, sizeof(passwdhash), LOCK_ROUNDS) < 0) -+ fatal("bcrypt_pbkdf"); -+ if (timingsafe_bcmp(passwdhash, lock_passwd, LOCK_SIZE) == 0) { -+ debug("agent unlocked"); -+ locked = 0; -+ fail_count = 0; -+ explicit_bzero(lock_passwd, sizeof(lock_passwd)); -+ success = 1; -+ } else { -+ /* delay in 0.1s increments up to 10s */ -+ if (fail_count < 100) -+ fail_count++; -+ delay = 100000 * fail_count; -+ debug("unlock failed, delaying %0.1lf seconds", -+ (double)delay/1000000); -+ usleep(delay); -+ } -+ explicit_bzero(passwdhash, sizeof(passwdhash)); - } else if (!locked && lock) { -+ debug("agent locked"); - locked = 1; -- lock_passwd = xstrdup(passwd); -+ arc4random_buf(lock_salt, sizeof(lock_salt)); -+ if (bcrypt_pbkdf(passwd, pwlen, lock_salt, sizeof(lock_salt), -+ lock_passwd, sizeof(lock_passwd), LOCK_ROUNDS) < 0) -+ fatal("bcrypt_pbkdf"); - success = 1; - } -- explicit_bzero(passwd, strlen(passwd)); -+ explicit_bzero(passwd, pwlen); - free(passwd); - - buffer_put_int(&e->output, 1); diff --git a/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch b/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch deleted file mode 100644 index 4cce020..0000000 --- a/SOURCES/openssh-6.6p1-ssh-copy-id-quiet.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -up openssh-6.6p1/contrib/ssh-copy-id.quiet openssh-6.6p1/contrib/ssh-copy-id ---- openssh-6.6p1/contrib/ssh-copy-id.quiet 2016-06-27 13:42:47.844393842 +0200 -+++ openssh-6.6p1/contrib/ssh-copy-id 2016-06-27 13:42:57.861398744 +0200 -@@ -215,6 +215,7 @@ populate_new_ids() { - # The point being that if file based, ssh needs the private key, which it cannot - # find if only given the contents of the .pub file in an unrelated tmpfile - ssh -i "${PRIV_ID_FILE:-$L_TMP_ID_FILE}" \ -+ -o LogLevel=INFO \ - -o PreferredAuthentications=publickey \ - -o IdentitiesOnly=yes "$@" exit 2>$L_TMP_ID_FILE.stderr use_pam); -+ dump_cfg_fmtint(sUsePAM, o->use_pam); - #endif - dump_cfg_int(sServerKeyBits, o->server_key_bits); - dump_cfg_int(sLoginGraceTime, o->login_grace_time); -@@ -2084,6 +2086,7 @@ dump_config(ServerOptions *o) - dump_cfg_fmtint(sShowPatchLevel, o->show_patchlevel); - dump_cfg_fmtint(sUseDNS, o->use_dns); - dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); -+ dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding); - dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); - dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); - dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users); -@@ -2094,14 +2097,15 @@ dump_config(ServerOptions *o) - dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : - cipher_alg_list(',', 0)); - dump_cfg_string(sMacs, o->macs ? o->macs : mac_alg_list(',')); +diff -up openssh-7.4p1/servconf.c.sshd-t openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.sshd-t 2017-02-09 10:19:56.859306131 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 10:22:07.895104402 +0100 +@@ -2337,7 +2337,7 @@ dump_config(ServerOptions *o) + dump_cfg_string(sXAuthLocation, o->xauth_location); + dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT); + dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC); - dump_cfg_string(sBanner, o->banner); + dump_cfg_string(sBanner, o->banner == NULL ? "none" : o->banner); dump_cfg_string(sForceCommand, o->adm_forced_command); dump_cfg_string(sChrootDirectory, o->chroot_directory); dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); - dump_cfg_string(sRevokedKeys, o->revoked_keys_file); - dump_cfg_string(sAuthorizedPrincipalsFile, - o->authorized_principals_file); -- dump_cfg_string(sVersionAddendum, o->version_addendum); -+ dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0' ? -+ "none" : o->version_addendum); - dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); - dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user); - dump_cfg_string(sHostKeyAgent, o->host_key_agent); -@@ -2117,7 +2121,7 @@ dump_config(ServerOptions *o) - o->authorized_keys_files); - dump_cfg_strarray(sHostKeyFile, o->num_host_key_files, - o->host_key_files); -- dump_cfg_strarray(sHostKeyFile, o->num_host_cert_files, -+ dump_cfg_strarray(sHostCertificate, o->num_host_cert_files, - o->host_cert_files); - dump_cfg_strarray(sAllowUsers, o->num_allow_users, o->allow_users); - dump_cfg_strarray(sDenyUsers, o->num_deny_users, o->deny_users); -diff --git a/ssh.1 b/ssh.1 -index f65e42f..4a7d1cd 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -444,7 +444,11 @@ For full details of the options listed below, and their possible values, see +diff -up openssh-7.4p1/ssh.1.sshd-t openssh-7.4p1/ssh.1 +--- openssh-7.4p1/ssh.1.sshd-t 2017-02-09 10:19:56.823306172 +0100 ++++ openssh-7.4p1/ssh.1 2017-02-09 10:19:56.859306131 +0100 +@@ -512,7 +512,11 @@ For full details of the options listed b .It GatewayPorts .It GlobalKnownHostsFile .It GSSAPIAuthentication diff --git a/SOURCES/openssh-6.6p1-x11-max-displays.patch b/SOURCES/openssh-6.6p1-x11-max-displays.patch index f5b339f..2c93ef1 100644 --- a/SOURCES/openssh-6.6p1-x11-max-displays.patch +++ b/SOURCES/openssh-6.6p1-x11-max-displays.patch @@ -1,7 +1,7 @@ -diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c ---- openssh-6.6p1/channels.c.x11max 2016-06-27 16:28:49.803631684 +0200 -+++ openssh-6.6p1/channels.c 2016-06-27 16:28:49.814631678 +0200 -@@ -138,8 +138,8 @@ static int all_opens_permitted = 0; +diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c +--- openssh-7.4p1/channels.c.x11max 2017-02-09 12:49:04.690996627 +0100 ++++ openssh-7.4p1/channels.c 2017-02-09 12:49:04.744996547 +0100 +@@ -152,8 +152,8 @@ static int all_opens_permitted = 0; /* -- X11 forwarding */ @@ -12,7 +12,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c /* Saved X11 local (client) display. */ static char *x11_saved_display = NULL; -@@ -3445,7 +3445,8 @@ channel_send_window_changes(void) +@@ -4228,7 +4228,8 @@ channel_send_window_changes(void) */ int x11_create_display_inet(int x11_display_offset, int x11_use_localhost, @@ -22,7 +22,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c { Channel *nc = NULL; int display_number, sock; -@@ -3457,10 +3458,15 @@ x11_create_display_inet(int x11_display_ +@@ -4240,10 +4241,15 @@ x11_create_display_inet(int x11_display_ if (chanids == NULL) return -1; @@ -40,7 +40,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; -@@ -3512,7 +3518,7 @@ x11_create_display_inet(int x11_display_ +@@ -4295,7 +4301,7 @@ x11_create_display_inet(int x11_display_ if (num_socks > 0) break; } @@ -49,7 +49,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c error("Failed to allocate internet-domain X11 display socket."); return -1; } -@@ -3658,7 +3664,7 @@ x11_connect_display(void) +@@ -4441,7 +4447,7 @@ x11_connect_display(void) memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_socktype = SOCK_STREAM; @@ -58,7 +58,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { error("%.100s: unknown host. (%s)", buf, ssh_gai_strerror(gaierr)); -@@ -3674,7 +3680,7 @@ x11_connect_display(void) +@@ -4457,7 +4463,7 @@ x11_connect_display(void) /* Connect it to the display. */ if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { debug2("connect %.100s port %u: %.100s", buf, @@ -67,7 +67,7 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c close(sock); continue; } -@@ -3683,8 +3689,8 @@ x11_connect_display(void) +@@ -4466,8 +4472,8 @@ x11_connect_display(void) } freeaddrinfo(aitop); if (!ai) { @@ -78,30 +78,30 @@ diff -up openssh-6.6p1/channels.c.x11max openssh-6.6p1/channels.c return -1; } set_nodelay(sock); -diff -up openssh-6.6p1/channels.h.x11max openssh-6.6p1/channels.h ---- openssh-6.6p1/channels.h.x11max 2016-06-27 16:28:49.814631678 +0200 -+++ openssh-6.6p1/channels.h 2016-06-27 16:31:18.925557840 +0200 -@@ -281,7 +281,7 @@ int permitopen_port(const char *); +diff -up openssh-7.4p1/channels.h.x11max openssh-7.4p1/channels.h +--- openssh-7.4p1/channels.h.x11max 2017-02-09 12:49:04.744996547 +0100 ++++ openssh-7.4p1/channels.h 2017-02-09 12:49:50.230929693 +0100 +@@ -293,7 +293,7 @@ int permitopen_port(const char *); void channel_set_x11_refuse_time(u_int); int x11_connect_display(void); -int x11_create_display_inet(int, int, int, u_int *, int **); +int x11_create_display_inet(int, int, int, int, u_int *, int **); - void x11_input_open(int, u_int32_t, void *); + int x11_input_open(int, u_int32_t, void *); void x11_request_forwarding_with_spoofing(int, const char *, const char *, const char *, int); -diff -up openssh-6.6p1/servconf.c.x11max openssh-6.6p1/servconf.c ---- openssh-6.6p1/servconf.c.x11max 2016-06-27 16:28:49.808631681 +0200 -+++ openssh-6.6p1/servconf.c 2016-06-27 16:30:46.941573678 +0200 -@@ -92,6 +92,7 @@ initialize_server_options(ServerOptions +diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.x11max 2017-02-09 12:49:04.741996552 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 12:51:03.167822492 +0100 +@@ -94,6 +94,7 @@ initialize_server_options(ServerOptions options->print_lastlog = -1; options->x11_forwarding = -1; options->x11_display_offset = -1; + options->x11_max_displays = -1; options->x11_use_localhost = -1; options->permit_tty = -1; - options->xauth_location = NULL; -@@ -219,6 +220,8 @@ fill_default_server_options(ServerOption + options->permit_user_rc = -1; +@@ -242,6 +243,8 @@ fill_default_server_options(ServerOption options->x11_forwarding = 0; if (options->x11_display_offset == -1) options->x11_display_offset = 10; @@ -110,16 +110,16 @@ diff -up openssh-6.6p1/servconf.c.x11max openssh-6.6p1/servconf.c if (options->x11_use_localhost == -1) options->x11_use_localhost = 1; if (options->xauth_location == NULL) -@@ -364,7 +367,7 @@ typedef enum { +@@ -416,7 +419,7 @@ typedef enum { sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, + sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, - sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression, + sPermitUserEnvironment, sAllowTcpForwarding, sCompression, sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, -@@ -476,6 +479,7 @@ static struct { +@@ -537,6 +540,7 @@ static struct { { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, @@ -127,9 +127,9 @@ diff -up openssh-6.6p1/servconf.c.x11max openssh-6.6p1/servconf.c { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, -@@ -1202,6 +1206,10 @@ process_server_config_line(ServerOptions - intptr = &options->x11_display_offset; - goto parse_int; +@@ -1313,6 +1317,10 @@ process_server_config_line(ServerOptions + *intptr = value; + break; + case sX11MaxDisplays: + intptr = &options->x11_max_displays; @@ -138,25 +138,25 @@ diff -up openssh-6.6p1/servconf.c.x11max openssh-6.6p1/servconf.c case sX11UseLocalhost: intptr = &options->x11_use_localhost; goto parse_flag; -@@ -1889,6 +1897,7 @@ copy_set_server_options(ServerOptions *d - M_CP_INTOPT(gateway_ports); +@@ -2060,6 +2068,7 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); + M_CP_INTOPT(x11_max_displays); M_CP_INTOPT(x11_use_localhost); M_CP_INTOPT(permit_tty); - M_CP_INTOPT(max_sessions); -@@ -2106,6 +2115,7 @@ dump_config(ServerOptions *o) + M_CP_INTOPT(permit_user_rc); +@@ -2312,6 +2321,7 @@ dump_config(ServerOptions *o) + #endif dump_cfg_int(sLoginGraceTime, o->login_grace_time); - dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time); dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); + dump_cfg_int(sX11MaxDisplays, o->x11_max_displays); dump_cfg_int(sMaxAuthTries, o->max_authtries); dump_cfg_int(sMaxSessions, o->max_sessions); dump_cfg_int(sClientAliveInterval, o->client_alive_interval); -diff -up openssh-6.6p1/servconf.h.x11max openssh-6.6p1/servconf.h ---- openssh-6.6p1/servconf.h.x11max 2016-06-27 16:28:49.809631681 +0200 -+++ openssh-6.6p1/servconf.h 2016-06-27 16:28:49.815631678 +0200 +diff -up openssh-7.4p1/servconf.h.x11max openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.x11max 2017-02-09 12:49:04.741996552 +0100 ++++ openssh-7.4p1/servconf.h 2017-02-09 12:49:04.744996547 +0100 @@ -55,6 +55,7 @@ #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ @@ -173,10 +173,10 @@ diff -up openssh-6.6p1/servconf.h.x11max openssh-6.6p1/servconf.h int x11_use_localhost; /* If true, use localhost for fake X11 server. */ char *xauth_location; /* Location of xauth program */ int permit_tty; /* If false, deny pty allocation */ -diff -up openssh-6.6p1/session.c.x11max openssh-6.6p1/session.c ---- openssh-6.6p1/session.c.x11max 2016-06-27 16:28:49.809631681 +0200 -+++ openssh-6.6p1/session.c 2016-06-27 16:28:49.815631678 +0200 -@@ -2741,8 +2741,9 @@ session_setup_x11fwd(Session *s) +diff -up openssh-7.4p1/session.c.x11max openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.x11max 2017-02-09 12:49:04.742996550 +0100 ++++ openssh-7.4p1/session.c 2017-02-09 12:49:04.745996546 +0100 +@@ -2502,8 +2502,9 @@ session_setup_x11fwd(Session *s) return 0; } if (x11_create_display_inet(options.x11_display_offset, @@ -188,18 +188,18 @@ diff -up openssh-6.6p1/session.c.x11max openssh-6.6p1/session.c debug("x11_create_display_inet failed."); return 0; } -diff -up openssh-6.6p1/sshd_config.5.x11max openssh-6.6p1/sshd_config.5 ---- openssh-6.6p1/sshd_config.5.x11max 2016-06-27 16:28:49.809631681 +0200 -+++ openssh-6.6p1/sshd_config.5 2016-06-27 16:32:01.253536879 +0200 -@@ -930,6 +930,7 @@ Available keywords are - .Cm RhostsRSAAuthentication , - .Cm RSAAuthentication , +diff -up openssh-7.4p1/sshd_config.5.x11max openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.x11max 2017-02-09 12:49:04.742996550 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-09 12:51:24.656790909 +0100 +@@ -1137,6 +1137,7 @@ Available keywords are + .Cm StreamLocalBindUnlink , + .Cm TrustedUserCAKeys , .Cm X11DisplayOffset , +.Cm X11MaxDisplays , .Cm X11Forwarding and .Cm X11UseLocalHost . -@@ -1339,6 +1340,12 @@ Specifies the first display number avail +@@ -1563,6 +1564,12 @@ Specifies the first display number avail X11 forwarding. This prevents sshd from interfering with real X11 servers. The default is 10. diff --git a/SOURCES/openssh-7.4p1-ControlPath_too_long.patch b/SOURCES/openssh-7.4p1-ControlPath_too_long.patch new file mode 100644 index 0000000..6d9125c --- /dev/null +++ b/SOURCES/openssh-7.4p1-ControlPath_too_long.patch @@ -0,0 +1,16 @@ +diff -up openssh-7.4p1/mux.c.controlPath openssh-7.4p1/mux.c +--- openssh-7.4p1/mux.c.controlPath 2017-05-04 14:49:44.629247946 +0200 ++++ openssh-7.4p1/mux.c 2017-05-04 14:52:54.955109022 +0200 +@@ -1290,6 +1290,12 @@ muxserver_listen(void) + oerrno = errno; + umask(old_umask); + if (muxserver_sock < 0) { ++ if (oerrno == ENAMETOOLONG) { ++ /* the error is already logged from unix_listener() */ ++ error("ControlPath %s too long, " ++ "disabling multiplexing", options.control_path); ++ goto disable_mux_master; ++ } + if (oerrno == EINVAL || oerrno == EADDRINUSE) { + error("ControlSocket %s already exists, " + "disabling multiplexing", options.control_path); diff --git a/SOURCES/openssh-7.4p1-audit.patch b/SOURCES/openssh-7.4p1-audit.patch new file mode 100644 index 0000000..4ce694a --- /dev/null +++ b/SOURCES/openssh-7.4p1-audit.patch @@ -0,0 +1,2168 @@ +diff -up openssh-7.4p1/audit-bsm.c.audit openssh-7.4p1/audit-bsm.c +--- openssh-7.4p1/audit-bsm.c.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/audit-bsm.c 2016-12-23 18:54:54.433080419 +0100 +@@ -373,10 +373,23 @@ audit_connection_from(const char *host, + #endif + } + +-void ++int + audit_run_command(const char *command) + { + /* not implemented */ ++ return 0; ++} ++ ++void ++audit_end_command(int handle, const char *command) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_count_session_open(void) ++{ ++ /* not necessary */ + } + + void +@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li + /* not implemented */ + } + ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ /* not implemented */ ++} ++ + void + audit_event(ssh_audit_event_t event) + { +@@ -452,4 +471,40 @@ audit_event(ssh_audit_event_t event) + debug("%s: unhandled event %d", __func__, event); + } + } ++ ++void ++audit_unsupported_body(int what) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ /* not implemented */ ++} ++ ++void ++audit_generate_ephemeral_server_key(const char *fp) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff -up openssh-7.4p1/audit.c.audit openssh-7.4p1/audit.c +--- openssh-7.4p1/audit.c.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/audit.c 2016-12-23 18:54:54.433080419 +0100 +@@ -26,6 +26,7 @@ + + #include + #include ++#include + + #ifdef SSH_AUDIT_EVENTS + +@@ -34,6 +35,11 @@ + #include "key.h" + #include "hostfile.h" + #include "auth.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "xmalloc.h" ++#include "misc.h" ++#include "servconf.h" + + /* + * Care must be taken when using this since it WILL NOT be initialized when +@@ -41,6 +47,7 @@ + * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. + */ + extern Authctxt *the_authctxt; ++extern ServerOptions options; + + /* Maybe add the audit class to struct Authmethod? */ + ssh_audit_event_t +@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) + const char * + audit_username(void) + { +- static const char unknownuser[] = "(unknown user)"; +- static const char invaliduser[] = "(invalid user)"; ++ static const char unknownuser[] = "(unknown)"; + +- if (the_authctxt == NULL || the_authctxt->user == NULL) ++ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) + return (unknownuser); +- if (!the_authctxt->valid) +- return (invaliduser); + return (the_authctxt->user); + } + +@@ -109,6 +113,40 @@ audit_event_lookup(ssh_audit_event_t ev) + return(event_lookup[i].name); + } + ++void ++audit_key(int host_user, int *rv, const Key *key) ++{ ++ char *fp; ++ const char *crypto_name; ++ ++ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (key->type == KEY_RSA1) ++ crypto_name = "ssh-rsa1"; ++ else ++ crypto_name = key_ssh_name(key); ++ if (audit_keyusage(host_user, crypto_name, key_size(key), fp, *rv) == 0) ++ *rv = 0; ++ free(fp); ++} ++ ++void ++audit_unsupported(int what) ++{ ++ PRIVSEP(audit_unsupported_body(what)); ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++ PRIVSEP(audit_kex_body(ctos, enc, mac, comp, pfs, getpid(), getuid())); ++} ++ ++void ++audit_session_key_free(int ctos) ++{ ++ PRIVSEP(audit_session_key_free_body(ctos, getpid(), getuid())); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. +@@ -138,6 +176,17 @@ audit_event(ssh_audit_event_t event) + } + + /* ++ * Called when a child process has called, or will soon call, ++ * audit_session_open. ++ */ ++void ++audit_count_session_open(void) ++{ ++ debug("audit count session open euid %d user %s", geteuid(), ++ audit_username()); ++} ++ ++/* + * Called when a user session is started. Argument is the tty allocated to + * the session, or NULL if no tty was allocated. + * +@@ -172,13 +221,91 @@ audit_session_close(struct logininfo *li + /* + * This will be called when a user runs a non-interactive command. Note that + * it may be called multiple times for a single connection since SSH2 allows +- * multiple sessions within a single connection. ++ * multiple sessions within a single connection. Returns a "handle" for ++ * audit_end_command. + */ +-void ++int + audit_run_command(const char *command) + { + debug("audit run command euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); ++ return 0; ++} ++ ++/* ++ * This will be called when the non-interactive command finishes. Note that ++ * it may be called multiple times for a single connection since SSH2 allows ++ * multiple sessions within a single connection. "handle" should come from ++ * the corresponding audit_run_command. ++ */ ++void ++audit_end_command(int handle, const char *command) ++{ ++ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), ++ audit_username(), command); ++} ++ ++/* ++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. ++ * ++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. ++ */ ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s key type %s key length %d fingerprint %s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), type, bits, ++ fp, rv); ++} ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, ++ (unsigned)uid); ++} ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on destroy private part of the server key ++ */ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", ++ geteuid(), fp, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on generation of the ephemeral server key ++ */ ++void ++audit_generate_ephemeral_server_key(const char *) ++{ ++ debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); + } + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-7.4p1/audit.h.audit openssh-7.4p1/audit.h +--- openssh-7.4p1/audit.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/audit.h 2016-12-23 18:54:54.433080419 +0100 +@@ -26,6 +26,7 @@ + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "key.h" + + enum ssh_audit_event_type { + SSH_LOGIN_EXCEED_MAXTRIES, +@@ -43,13 +44,33 @@ enum ssh_audit_event_type { + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN + }; ++ ++enum ssh_audit_kex { ++ SSH_AUDIT_UNSUPPORTED_CIPHER, ++ SSH_AUDIT_UNSUPPORTED_MAC, ++ SSH_AUDIT_UNSUPPORTED_COMPRESSION ++}; + typedef enum ssh_audit_event_type ssh_audit_event_t; + ++int listening_for_clients(void); ++ + void audit_connection_from(const char *, int); + void audit_event(ssh_audit_event_t); ++void audit_count_session_open(void); + void audit_session_open(struct logininfo *); + void audit_session_close(struct logininfo *); +-void audit_run_command(const char *); ++int audit_run_command(const char *); ++void audit_end_command(int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); ++int audit_keyusage(int, const char *, unsigned, char *, int); ++void audit_key(int, int *, const Key *); ++void audit_unsupported(int); ++void audit_kex(int, char *, char *, char *, char *); ++void audit_unsupported_body(int); ++void audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(int ctos); ++void audit_session_key_free_body(int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(const char *, pid_t, uid_t); ++void audit_generate_ephemeral_server_key(const char *); + + #endif /* _SSH_AUDIT_H */ +diff -up openssh-7.4p1/audit-linux.c.audit openssh-7.4p1/audit-linux.c +--- openssh-7.4p1/audit-linux.c.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/audit-linux.c 2016-12-23 18:54:54.434080419 +0100 +@@ -33,25 +33,38 @@ + + #include "log.h" + #include "audit.h" ++#include "key.h" ++#include "hostfile.h" ++#include "auth.h" ++#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ ++#include "servconf.h" + #include "canohost.h" + #include "packet.h" +- ++#include "cipher.h" ++#include "channels.h" ++#include "session.h" ++ ++#define AUDIT_LOG_SIZE 256 ++ ++extern ServerOptions options; ++extern Authctxt *the_authctxt; ++extern u_int utmp_len; + const char *audit_username(void); + +-int +-linux_audit_record_event(int uid, const char *username, const char *hostname, +- const char *ip, const char *ttyn, int success) ++static void ++linux_audit_user_logxxx(int uid, const char *username, const char *hostname, ++ const char *ip, const char *ttyn, int success, int event) + { + int audit_fd, rc, saved_errno; + + if ((audit_fd = audit_open()) < 0) { + if (errno == EINVAL || errno == EPROTONOSUPPORT || + errno == EAFNOSUPPORT) +- return 1; /* No audit support in kernel */ ++ return; /* No audit support in kernel */ + else +- return 0; /* Must prevent login */ ++ goto fatal_report; /* Must prevent login */ + } +- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, ++ rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", + username == NULL ? uid : -1, hostname, ip, ttyn, success); + saved_errno = errno; +@@ -65,9 +78,97 @@ linux_audit_record_event(int uid, const + rc = 0; + errno = saved_errno; + +- return rc >= 0; ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } ++} ++ ++static void ++linux_audit_user_auth(int uid, const char *username, ++ const char *hostname, const char *ip, const char *ttyn, int success, int event) ++{ ++ int audit_fd, rc, saved_errno; ++ static const char *event_name[] = { ++ "maxtries exceeded", ++ "root denied", ++ "success", ++ "none", ++ "password", ++ "challenge-response", ++ "pubkey", ++ "hostbased", ++ "gssapi", ++ "invalid user", ++ "nologin", ++ "connection closed", ++ "connection abandoned", ++ "unknown" ++ }; ++ ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return; /* No audit support in kernel */ ++ else ++ goto fatal_report; /* Must prevent login */ ++ } ++ ++ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN)) ++ event = SSH_AUDIT_UNKNOWN; ++ ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, ++ NULL, event_name[event], username ? username : "(unknown)", ++ username == NULL ? uid : -1, hostname, ip, ttyn, success); ++ saved_errno = errno; ++ close(audit_fd); ++ /* ++ * Do not report error if the error is EPERM and sshd is run as non ++ * root user. ++ */ ++ if ((rc == -EPERM) && (geteuid() != 0)) ++ rc = 0; ++ errno = saved_errno; ++ if (rc < 0) { ++fatal_report: ++ fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ } ++} ++ ++int ++audit_keyusage(int host_user, const char *type, unsigned bits, char *fp, int rv) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, rc, saved_errno; ++ ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return 1; /* No audit support in kernel */ ++ else ++ return 0; /* Must prevent login */ ++ } ++ snprintf(buf, sizeof(buf), "%s_auth rport=%d", host_user ? "pubkey" : "hostbased", ssh_remote_port(active_state)); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(active_state), NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d", ++ type, bits, fp, ssh_remote_port(active_state)); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(active_state), NULL, rv); ++out: ++ saved_errno = errno; ++ audit_close(audit_fd); ++ errno = saved_errno; ++ /* do not report error if the error is EPERM and sshd is run as non root user */ ++ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0)); + } + ++static int user_login_count = 0; ++ + /* Below is the sshd audit API code */ + + void +@@ -76,24 +177,51 @@ audit_connection_from(const char *host, + /* not implemented */ + } + +-void ++int + audit_run_command(const char *command) + { +- /* not implemented */ ++ if (!user_login_count++) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, session_get_remote_name_or_ip(active_state, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, session_get_remote_name_or_ip(active_state, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_START); ++ return 0; ++} ++ ++void ++audit_end_command(int handle, const char *command) ++{ ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, session_get_remote_name_or_ip(active_state, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, session_get_remote_name_or_ip(active_state, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGOUT); ++} ++ ++void ++audit_count_session_open(void) ++{ ++ user_login_count++; + } + + void + audit_session_open(struct logininfo *li) + { +- if (linux_audit_record_event(li->uid, NULL, li->hostname, NULL, +- li->line, 1) == 0) +- fatal("linux_audit_write_entry failed: %s", strerror(errno)); ++ if (!user_login_count++) ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_LOGIN); ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_START); + } + + void + audit_session_close(struct logininfo *li) + { +- /* not implemented */ ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_END); ++ if (user_login_count && !--user_login_count) ++ linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ NULL, li->line, 1, AUDIT_USER_LOGOUT); + } + + void +@@ -103,24 +231,180 @@ audit_event(ssh_audit_event_t event) + + switch(event) { + case SSH_AUTH_SUCCESS: +- case SSH_CONNECTION_CLOSE: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ ssh_remote_ipaddr(ssh), "ssh", 1, event); ++ break; ++ + case SSH_NOLOGIN: +- case SSH_LOGIN_EXCEED_MAXTRIES: + case SSH_LOGIN_ROOT_DENIED: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ ssh_remote_ipaddr(ssh), "ssh", 0, event); ++ linux_audit_user_logxxx(-1, audit_username(), NULL, ++ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; ++ case SSH_LOGIN_EXCEED_MAXTRIES: + case SSH_AUTH_FAIL_NONE: + case SSH_AUTH_FAIL_PASSWD: + case SSH_AUTH_FAIL_KBDINT: + case SSH_AUTH_FAIL_PUBKEY: + case SSH_AUTH_FAIL_HOSTBASED: + case SSH_AUTH_FAIL_GSSAPI: ++ linux_audit_user_auth(-1, audit_username(), NULL, ++ ssh_remote_ipaddr(ssh), "ssh", 0, event); ++ break; ++ ++ case SSH_CONNECTION_CLOSE: ++ if (user_login_count) { ++ while (user_login_count--) ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_END); ++ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ session_get_remote_name_or_ip(ssh, utmp_len, options.use_dns), ++ NULL, "ssh", 1, AUDIT_USER_LOGOUT); ++ } ++ break; ++ ++ case SSH_CONNECTION_ABANDON: + case SSH_INVALID_USER: +- linux_audit_record_event(-1, audit_username(), NULL, +- ssh_remote_ipaddr(ssh), "sshd", 0); ++ linux_audit_user_logxxx(-1, audit_username(), NULL, ++ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + default: + debug("%s: unhandled event %d", __func__, event); + break; + } + } ++ ++void ++audit_unsupported_body(int what) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ const static char *name[] = { "cipher", "mac", "comp" }; ++ char *s; ++ int audit_fd; ++ ++ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ", ++ name[what], ssh_remote_port(active_state), (s = get_local_ipaddr(packet_get_connection_in())), ++ ssh_local_port(active_state)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) ++ /* no problem, the next instruction will be fatal() */ ++ return; ++ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 0); ++ audit_close(audit_fd); ++#endif ++} ++ ++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) ++{ ++#ifdef AUDIT_CRYPTO_SESSION ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ const struct sshcipher *cipher = cipher_by_name(enc); ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs, ++ (intmax_t)pid, (intmax_t)uid, ++ ssh_remote_port(active_state), (s = get_local_ipaddr(packet_get_connection_in())), ssh_local_port(active_state)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno == EINVAL || errno == EPROTONOSUPPORT || ++ errno == EAFNOSUPPORT) ++ return; /* No audit support in kernel */ ++ else ++ fatal("cannot open audit"); /* Must prevent login */ ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION, ++ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ fatal("cannot write into audit"); /* Must prevent login */ ++#endif ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ char *s; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ", ++ direction[ctos], (intmax_t)pid, (intmax_t)uid, ++ ssh_remote_port(active_state), ++ (s = get_local_ipaddr(packet_get_connection_in())), ++ ssh_local_port(active_state)); ++ free(s); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, ssh_remote_ipaddr(active_state), NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} ++ ++void ++audit_destroy_sensitive_data(const char *fp, pid_t pid, uid_t uid) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ", ++ fp, (intmax_t)pid, (intmax_t)uid); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, ++ listening_for_clients() ? NULL : ssh_remote_ipaddr(active_state), ++ NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} ++ ++void ++audit_generate_ephemeral_server_key(const char *fp) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=create kind=server fp=%s direction=? ", fp); ++ audit_fd = audit_open(); ++ if (audit_fd < 0) { ++ if (errno != EINVAL && errno != EPROTONOSUPPORT && ++ errno != EAFNOSUPPORT) ++ error("cannot open audit"); ++ return; ++ } ++ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, ++ buf, NULL, 0, NULL, 1); ++ audit_close(audit_fd); ++ /* do not abort if the error is EPERM and sshd is run as non root user */ ++ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) ++ error("cannot write into audit"); ++} + #endif /* USE_LINUX_AUDIT */ +diff -up openssh-7.4p1/auditstub.c.audit openssh-7.4p1/auditstub.c +--- openssh-7.4p1/auditstub.c.audit 2016-12-23 18:54:54.434080419 +0100 ++++ openssh-7.4p1/auditstub.c 2016-12-23 18:54:54.434080419 +0100 +@@ -0,0 +1,50 @@ ++/* $Id: auditstub.c,v 1.1 jfch Exp $ */ ++ ++/* ++ * Copyright 2010 Red Hat, Inc. All rights reserved. ++ * Use is subject to license terms. ++ * ++ * 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. ++ * ++ * Red Hat author: Jan F. Chadima ++ */ ++ ++#include ++ ++void ++audit_unsupported(int n) ++{ ++} ++ ++void ++audit_kex(int ctos, char *enc, char *mac, char *comp, char *pfs) ++{ ++} ++ ++void ++audit_session_key_free(int ctos) ++{ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++} +diff -up openssh-7.4p1/auth2.c.audit openssh-7.4p1/auth2.c +--- openssh-7.4p1/auth2.c.audit 2016-12-23 18:54:54.422080416 +0100 ++++ openssh-7.4p1/auth2.c 2016-12-23 18:54:54.434080419 +0100 +@@ -249,9 +249,6 @@ input_userauth_request(int type, u_int32 + } else { + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); +-#ifdef SSH_AUDIT_EVENTS +- PRIVSEP(audit_event(SSH_INVALID_USER)); +-#endif + } + #ifdef USE_PAM + if (options.use_pam) +diff -up openssh-7.4p1/auth2-hostbased.c.audit openssh-7.4p1/auth2-hostbased.c +--- openssh-7.4p1/auth2-hostbased.c.audit 2016-12-23 18:54:54.422080416 +0100 ++++ openssh-7.4p1/auth2-hostbased.c 2016-12-23 18:54:54.434080419 +0100 +@@ -148,7 +148,7 @@ userauth_hostbased(Authctxt *authctxt) + /* test for allowed key and correct signature */ + authenticated = 0; + if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && +- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), ++ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) { + authenticated = 1; + authctxt->last_details = pubkey; +@@ -169,6 +169,18 @@ done: + return authenticated; + } + ++int ++hostbased_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) ++{ ++ int rv; ++ ++ rv = key_verify(key, sig, slen, data, datalen); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(0, &rv, key); ++#endif ++ return rv; ++} ++ + /* return 1 if given hostkey is allowed */ + int + hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, +diff -up openssh-7.4p1/auth2-pubkey.c.audit openssh-7.4p1/auth2-pubkey.c +--- openssh-7.4p1/auth2-pubkey.c.audit 2016-12-23 18:54:54.423080416 +0100 ++++ openssh-7.4p1/auth2-pubkey.c 2016-12-23 18:54:54.435080419 +0100 +@@ -183,7 +183,7 @@ userauth_pubkey(Authctxt *authctxt) + /* test for correct signature */ + authenticated = 0; + if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && +- PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), ++ PRIVSEP(user_key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) { + authenticated = 1; + authctxt->last_details = pubkey; +@@ -252,6 +252,18 @@ pubkey_auth_info(Authctxt *authctxt, con + free(extra); + } + ++int ++user_key_verify(const Key *key, const u_char *sig, u_int slen, const u_char *data, u_int datalen) ++{ ++ int rv; ++ ++ rv = key_verify(key, sig, slen, data, datalen); ++#ifdef SSH_AUDIT_EVENTS ++ audit_key(1, &rv, key); ++#endif ++ return rv; ++} ++ + /* + * Splits 's' into an argument vector. Handles quoted string and basic + * escape characters (\\, \", \'). Caller must free the argument vector +diff -up openssh-7.4p1/auth.c.audit openssh-7.4p1/auth.c +--- openssh-7.4p1/auth.c.audit 2016-12-23 18:54:54.373080404 +0100 ++++ openssh-7.4p1/auth.c 2016-12-23 18:54:54.435080419 +0100 +@@ -666,9 +666,6 @@ getpwnamallow(const char *user) + record_failed_login(user, + auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); + #endif +-#ifdef SSH_AUDIT_EVENTS +- audit_event(SSH_INVALID_USER); +-#endif /* SSH_AUDIT_EVENTS */ + return (NULL); + } + if (!allowed_user(pw)) +diff -up openssh-7.4p1/auth.h.audit openssh-7.4p1/auth.h +--- openssh-7.4p1/auth.h.audit 2016-12-23 18:54:54.423080416 +0100 ++++ openssh-7.4p1/auth.h 2016-12-23 18:54:54.435080419 +0100 +@@ -185,6 +185,7 @@ struct passwd * getpwnamallow(const char + + char *expand_authorized_keys(const char *, struct passwd *pw); + char *authorized_principals_file(struct passwd *); ++int user_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); +@@ -204,6 +205,7 @@ Key *get_hostkey_private_by_type(int, in + int get_hostkey_index(Key *, int, struct ssh *); + int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, + const u_char *, size_t, const char *, u_int); ++int hostbased_key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + + /* debug messages during authentication */ + void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); +diff -up openssh-7.4p1/cipher.c.audit openssh-7.4p1/cipher.c +--- openssh-7.4p1/cipher.c.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/cipher.c 2016-12-23 18:54:54.435080419 +0100 +@@ -66,26 +66,6 @@ struct sshcipher_ctx { + const struct sshcipher *cipher; + }; + +-struct sshcipher { +- char *name; +- int number; /* for ssh1 only */ +- u_int block_size; +- u_int key_len; +- u_int iv_len; /* defaults to block_size */ +- u_int auth_len; +- u_int discard_len; +- u_int flags; +-#define CFLAG_CBC (1<<0) +-#define CFLAG_CHACHAPOLY (1<<1) +-#define CFLAG_AESCTR (1<<2) +-#define CFLAG_NONE (1<<3) +-#ifdef WITH_OPENSSL +- const EVP_CIPHER *(*evptype)(void); +-#else +- void *ignored; +-#endif +-}; +- + static const struct sshcipher ciphers[] = { + #ifdef WITH_SSH1 + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, +diff -up openssh-7.4p1/cipher.h.audit openssh-7.4p1/cipher.h +--- openssh-7.4p1/cipher.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/cipher.h 2016-12-23 18:54:54.436080419 +0100 +@@ -62,7 +62,25 @@ + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + +-struct sshcipher; ++struct sshcipher { /* from cipher.c */ ++ char *name; ++ int number; /* for ssh1 only */ ++ u_int block_size; ++ u_int key_len; ++ u_int iv_len; /* defaults to block_size */ ++ u_int auth_len; ++ u_int discard_len; ++ u_int flags; ++#define CFLAG_CBC (1<<0) ++#define CFLAG_CHACHAPOLY (1<<1) ++#define CFLAG_AESCTR (1<<2) ++#define CFLAG_NONE (1<<3) ++#ifdef WITH_OPENSSL ++ const EVP_CIPHER *(*evptype)(void); ++#else ++ void *ignored; ++#endif ++}; + struct sshcipher_ctx; + + u_int cipher_mask_ssh1(int); +diff -up openssh-7.4p1/kex.c.audit openssh-7.4p1/kex.c +--- openssh-7.4p1/kex.c.audit 2016-12-23 18:54:54.410080413 +0100 ++++ openssh-7.4p1/kex.c 2016-12-23 18:54:54.436080419 +0100 +@@ -54,6 +54,7 @@ + #include "ssherr.h" + #include "sshbuf.h" + #include "digest.h" ++#include "audit.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -683,8 +684,12 @@ choose_enc(struct sshenc *enc, char *cli + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_CIPHER); ++#endif + return SSH_ERR_NO_CIPHER_ALG_MATCH; ++ } + if ((enc->cipher = cipher_by_name(name)) == NULL) + return SSH_ERR_INTERNAL_ERROR; + enc->name = name; +@@ -702,8 +707,12 @@ choose_mac(struct ssh *ssh, struct sshma + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_MAC); ++#endif + return SSH_ERR_NO_MAC_ALG_MATCH; ++ } + if (mac_setup(mac, name) < 0) + return SSH_ERR_INTERNAL_ERROR; + /* truncate the key */ +@@ -720,8 +729,12 @@ choose_comp(struct sshcomp *comp, char * + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_COMPRESSION); ++#endif + return SSH_ERR_NO_COMPRESS_ALG_MATCH; ++ } + if (strcmp(name, "zlib@openssh.com") == 0) { + comp->type = COMP_DELAYED; + } else if (strcmp(name, "zlib") == 0) { +@@ -890,6 +903,10 @@ kex_choose_conf(struct ssh *ssh) + dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); + dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); + dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); ++ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need); ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name); ++#endif + } + /* XXX need runden? */ + kex->we_need = need; +@@ -1064,3 +1081,33 @@ dump_digest(char *msg, u_char *digest, i + sshbuf_dump_data(digest, len, stderr); + } + #endif ++ ++static void ++enc_destroy(struct sshenc *enc) ++{ ++ if (enc == NULL) ++ return; ++ ++ if (enc->key) { ++ memset(enc->key, 0, enc->key_len); ++ free(enc->key); ++ } ++ ++ if (enc->iv) { ++ memset(enc->iv, 0, enc->iv_len); ++ free(enc->iv); ++ } ++ ++ memset(enc, 0, sizeof(*enc)); ++} ++ ++void ++newkeys_destroy(struct newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ enc_destroy(&newkeys->enc); ++ mac_destroy(&newkeys->mac); ++ memset(&newkeys->comp, 0, sizeof(newkeys->comp)); ++} +diff -up openssh-7.4p1/kex.h.audit openssh-7.4p1/kex.h +--- openssh-7.4p1/kex.h.audit 2016-12-23 18:54:54.410080413 +0100 ++++ openssh-7.4p1/kex.h 2016-12-23 18:54:54.436080419 +0100 +@@ -213,6 +213,8 @@ int kexgss_client(struct ssh *); + int kexgss_server(struct ssh *); + #endif + ++void newkeys_destroy(struct newkeys *newkeys); ++ + int kex_dh_hash(int, const char *, const char *, + const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, + const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); +diff -up openssh-7.4p1/key.h.audit openssh-7.4p1/key.h +--- openssh-7.4p1/key.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/key.h 2016-12-23 18:54:54.436080419 +0100 +@@ -50,6 +50,7 @@ typedef struct sshkey Key; + #define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid + #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid + #define key_is_cert sshkey_is_cert ++#define key_is_private sshkey_is_private + #define key_type_plain sshkey_type_plain + #define key_curve_name_to_nid sshkey_curve_name_to_nid + #define key_curve_nid_to_bits sshkey_curve_nid_to_bits +diff -up openssh-7.4p1/mac.c.audit openssh-7.4p1/mac.c +--- openssh-7.4p1/mac.c.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/mac.c 2016-12-23 18:54:54.436080419 +0100 +@@ -249,6 +249,20 @@ mac_clear(struct sshmac *mac) + mac->umac_ctx = NULL; + } + ++void ++mac_destroy(struct sshmac *mac) ++{ ++ if (mac == NULL) ++ return; ++ ++ if (mac->key) { ++ memset(mac->key, 0, mac->key_len); ++ free(mac->key); ++ } ++ ++ memset(mac, 0, sizeof(*mac)); ++} ++ + /* XXX copied from ciphers_valid */ + #define MAC_SEP "," + int +diff -up openssh-7.4p1/mac.h.audit openssh-7.4p1/mac.h +--- openssh-7.4p1/mac.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/mac.h 2016-12-23 18:54:54.436080419 +0100 +@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int3 + int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t, + const u_char *, size_t); + void mac_clear(struct sshmac *); ++void mac_destroy(struct sshmac *); + + #endif /* SSHMAC_H */ +diff -up openssh-7.4p1/Makefile.in.audit openssh-7.4p1/Makefile.in +--- openssh-7.4p1/Makefile.in.audit 2016-12-23 18:54:54.375080404 +0100 ++++ openssh-7.4p1/Makefile.in 2016-12-23 18:54:54.436080419 +0100 +@@ -100,7 +100,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ + kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ + kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ +- platform-pledge.o platform-tracing.o ++ platform-pledge.o platform-tracing.o auditstub.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o +diff -up openssh-7.4p1/monitor.c.audit openssh-7.4p1/monitor.c +--- openssh-7.4p1/monitor.c.audit 2016-12-23 18:54:54.423080416 +0100 ++++ openssh-7.4p1/monitor.c 2016-12-23 18:54:54.437080420 +0100 +@@ -102,6 +102,7 @@ + #include "compat.h" + #include "ssh2.h" + #include "authfd.h" ++#include "audit.h" + #include "match.h" + #include "ssherr.h" + +@@ -117,6 +118,8 @@ extern Buffer auth_debug; + extern int auth_debug_init; + extern Buffer loginmsg; + ++extern void destroy_sensitive_data(int); ++ + /* State exported from the child */ + static struct sshbuf *child_state; + +@@ -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 *); + #endif + + static int monitor_read_log(struct monitor *); +@@ -222,6 +230,10 @@ struct mon_table mon_dispatch_proto20[] + #endif + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + #ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, +@@ -260,6 +272,11 @@ struct mon_table mon_dispatch_postauth20 + #ifdef SSH_AUDIT_EVENTS + {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, + {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, ++ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command}, ++ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body}, ++ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body}, ++ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body}, ++ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free}, + #endif + {0, 0, NULL} + }; +@@ -1396,9 +1413,11 @@ mm_answer_keyverify(int sock, Buffer *m) + Key *key; + u_char *signature, *data, *blob; + u_int signaturelen, datalen, bloblen; ++ int type = 0; + int verified = 0; + int valid_data = 0; + ++ type = buffer_get_int(m); + blob = buffer_get_string(m, &bloblen); + signature = buffer_get_string(m, &signaturelen); + data = buffer_get_string(m, &datalen); +@@ -1406,6 +1425,8 @@ mm_answer_keyverify(int sock, Buffer *m) + if (hostbased_cuser == NULL || hostbased_chost == NULL || + !monitor_allowed_key(blob, bloblen)) + fatal("%s: bad key, not previously allowed", __func__); ++ if (type != key_blobtype) ++ fatal("%s: bad key type", __func__); + + key = key_from_blob(blob, bloblen); + if (key == NULL) +@@ -1426,7 +1447,17 @@ mm_answer_keyverify(int sock, Buffer *m) + if (!valid_data) + fatal("%s: bad signature data blob", __func__); + +- verified = key_verify(key, signature, signaturelen, data, datalen); ++ switch (key_blobtype) { ++ case MM_USERKEY: ++ verified = user_key_verify(key, signature, signaturelen, data, datalen); ++ break; ++ case MM_HOSTKEY: ++ verified = hostbased_key_verify(key, signature, signaturelen, data, datalen); ++ break; ++ default: ++ verified = 0; ++ break; ++ } + debug3("%s: key %p signature %s", + __func__, key, (verified == 1) ? "verified" : "unverified"); + +@@ -1489,6 +1520,12 @@ mm_session_close(Session *s) + debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); + session_pty_cleanup2(s); + } ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL) { ++ debug3("%s: command %d", __func__, s->command_handle); ++ session_end_command2(s); ++ } ++#endif + session_unused(s->self); + } + +@@ -1591,6 +1628,8 @@ mm_answer_term(int sock, Buffer *req) + sshpam_cleanup(); + #endif + ++ destroy_sensitive_data(0); ++ + while (waitpid(pmonitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); +@@ -1633,11 +1672,45 @@ mm_answer_audit_command(int socket, Buff + { + u_int len; + char *cmd; ++ Session *s; + + debug3("%s entering", __func__); + cmd = buffer_get_string(m, &len); ++ + /* sanity check command, if so how? */ +- audit_run_command(cmd); ++ s = session_new(); ++ if (s == NULL) ++ fatal("%s: error allocating a session", __func__); ++ s->command = cmd; ++#ifdef SSH_AUDIT_EVENTS ++ s->command_handle = audit_run_command(cmd); ++#endif ++ ++ buffer_clear(m); ++ buffer_put_int(m, s->self); ++ ++ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m); ++ ++ return (0); ++} ++ ++int ++mm_answer_audit_end_command(int socket, Buffer *m) ++{ ++ int handle; ++ u_int len; ++ char *cmd; ++ Session *s; ++ ++ debug3("%s entering", __func__); ++ handle = buffer_get_int(m); ++ cmd = buffer_get_string(m, &len); ++ ++ s = session_by_id(handle); ++ if (s == NULL || s->ttyfd != -1 || s->command == NULL || ++ strcmp(s->command, cmd) != 0) ++ fatal("%s: invalid handle", __func__); ++ mm_session_close(s); + free(cmd); + return (0); + } +@@ -1690,6 +1763,7 @@ monitor_apply_keystate(struct monitor *p + void + mm_get_keystate(struct monitor *pmonitor) + { ++ Buffer m; + debug3("%s: Waiting for new keys", __func__); + + if ((child_state = sshbuf_new()) == NULL) +@@ -1697,6 +1771,21 @@ mm_get_keystate(struct monitor *pmonitor + mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, + child_state); + debug3("%s: GOT new keys", __func__); ++ ++#ifdef SSH_AUDIT_EVENTS ++ if (compat20) { ++ buffer_init(&m); ++ 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); ++ } ++#endif ++ ++ /* Drain any buffered messages from the child */ ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) ++ ; ++ + } + + +@@ -1953,3 +2042,86 @@ mm_answer_gss_updatecreds(int socket, Bu + + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++int ++mm_answer_audit_unsupported_body(int sock, Buffer *m) ++{ ++ int what; ++ ++ what = buffer_get_int(m); ++ ++ audit_unsupported_body(what); ++ ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_kex_body(int sock, Buffer *m) ++{ ++ int ctos, len; ++ char *cipher, *mac, *compress, *pfs; ++ 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); ++ ++ audit_kex_body(ctos, cipher, mac, compress, pfs, pid, uid); ++ ++ free(cipher); ++ free(mac); ++ free(compress); ++ free(pfs); ++ buffer_clear(m); ++ ++ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m); ++ return 0; ++} ++ ++int ++mm_answer_audit_session_key_free_body(int sock, Buffer *m) ++{ ++ int ctos; ++ pid_t pid; ++ uid_t uid; ++ ++ ctos = buffer_get_int(m); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_session_key_free_body(ctos, pid, uid); ++ ++ buffer_clear(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) ++{ ++ int len; ++ char *fp; ++ pid_t pid; ++ uid_t uid; ++ ++ fp = buffer_get_string(m, &len); ++ pid = buffer_get_int64(m); ++ uid = buffer_get_int64(m); ++ ++ audit_destroy_sensitive_data(fp, pid, uid); ++ ++ free(fp); ++ buffer_clear(m); ++ ++ return 0; ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-7.4p1/monitor.h.audit openssh-7.4p1/monitor.h +--- openssh-7.4p1/monitor.h.audit 2016-12-23 18:54:54.393080409 +0100 ++++ openssh-7.4p1/monitor.h 2016-12-23 18:54:54.437080420 +0100 +@@ -69,7 +69,13 @@ enum monitor_reqtype { + MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, + MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, + MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, +- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, ++ MONITOR_REQ_AUDIT_EVENT = 112, ++ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115, ++ MONITOR_REQ_AUDIT_END_COMMAND = 116, ++ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119, ++ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121, ++ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, ++ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124 + + }; + +diff -up openssh-7.4p1/monitor_wrap.c.audit openssh-7.4p1/monitor_wrap.c +--- openssh-7.4p1/monitor_wrap.c.audit 2016-12-23 18:54:54.376080405 +0100 ++++ openssh-7.4p1/monitor_wrap.c 2016-12-23 18:54:54.437080420 +0100 +@@ -453,7 +453,7 @@ mm_key_allowed(enum mm_keytype type, con + */ + + int +-mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++mm_key_verify(enum mm_keytype type, Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) + { + Buffer m; + u_char *blob; +@@ -467,6 +467,7 @@ mm_key_verify(Key *key, u_char *sig, u_i + 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); +@@ -484,6 +485,18 @@ mm_key_verify(Key *key, u_char *sig, u_i + return (verified); + } + ++int ++mm_hostbased_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++{ ++ return mm_key_verify(MM_HOSTKEY, key, sig, siglen, data, datalen); ++} ++ ++int ++mm_user_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) ++{ ++ return mm_key_verify(MM_USERKEY, key, sig, siglen, data, datalen); ++} ++ + void + mm_send_keystate(struct monitor *monitor) + { +@@ -861,10 +874,11 @@ mm_audit_event(ssh_audit_event_t event) + buffer_free(&m); + } + +-void ++int + mm_audit_run_command(const char *command) + { + Buffer m; ++ int handle; + + debug3("%s entering command %s", __func__, command); + +@@ -872,6 +886,26 @@ mm_audit_run_command(const char *command + buffer_put_cstring(&m, command); + + 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); ++ ++ return (handle); ++} ++ ++void ++mm_audit_end_command(int handle, const char *command) ++{ ++ Buffer m; ++ ++ debug3("%s entering command %s", __func__, command); ++ ++ buffer_init(&m); ++ buffer_put_int(&m, handle); ++ buffer_put_cstring(&m, command); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, &m); + buffer_free(&m); + } + #endif /* SSH_AUDIT_EVENTS */ +@@ -1007,3 +1041,70 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc + + #endif /* GSSAPI */ + ++#ifdef SSH_AUDIT_EVENTS ++void ++mm_audit_unsupported_body(int what) ++{ ++ Buffer m; ++ ++ buffer_init(&m); ++ buffer_put_int(&m, what); ++ ++ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, &m); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED, ++ &m); ++ ++ buffer_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); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX, ++ &m); ++ ++ buffer_free(&m); ++} ++ ++void ++mm_audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++ Buffer 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); ++ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, ++ &m); ++ buffer_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); ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff -up openssh-7.4p1/monitor_wrap.h.audit openssh-7.4p1/monitor_wrap.h +--- openssh-7.4p1/monitor_wrap.h.audit 2016-12-23 18:54:54.376080405 +0100 ++++ openssh-7.4p1/monitor_wrap.h 2016-12-23 18:54:54.437080420 +0100 +@@ -52,7 +52,8 @@ int mm_key_allowed(enum mm_keytype, cons + int mm_user_key_allowed(struct passwd *, Key *, int); + int mm_hostbased_key_allowed(struct passwd *, const char *, + const char *, Key *); +-int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_hostbased_key_verify(Key *, u_char *, u_int, u_char *, u_int); ++int mm_user_key_verify(Key *, u_char *, u_int, u_char *, u_int); + + #ifdef GSSAPI + OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +@@ -76,7 +77,12 @@ void mm_sshpam_free_ctx(void *); + #ifdef SSH_AUDIT_EVENTS + #include "audit.h" + void mm_audit_event(ssh_audit_event_t); +-void mm_audit_run_command(const char *); ++int mm_audit_run_command(const char *); ++void mm_audit_end_command(int, const char *); ++void mm_audit_unsupported_body(int); ++void mm_audit_kex_body(int, char *, char *, char *, char *, pid_t, uid_t); ++void mm_audit_session_key_free_body(int, pid_t, uid_t); ++void mm_audit_destroy_sensitive_data(const char *, pid_t, uid_t); + #endif + + struct Session; +diff -up openssh-7.4p1/packet.c.audit openssh-7.4p1/packet.c +--- openssh-7.4p1/packet.c.audit 2016-12-23 18:54:54.318080390 +0100 ++++ openssh-7.4p1/packet.c 2016-12-23 18:54:54.438080420 +0100 +@@ -67,6 +67,7 @@ + #include "key.h" /* typedefs XXX */ + + #include "xmalloc.h" ++#include "audit.h" + #include "crc32.h" + #include "deattack.h" + #include "compat.h" +@@ -494,6 +495,13 @@ ssh_packet_get_connection_out(struct ssh + return ssh->state->connection_out; + } + ++static int ++packet_state_has_keys (const struct session_state *state) ++{ ++ return state != NULL && ++ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL); ++} ++ + /* + * Returns the IP-address of the remote host as a string. The returned + * string must not be freed. +@@ -562,13 +570,6 @@ ssh_packet_close(struct ssh *ssh) + if (!state->initialized) + return; + state->initialized = 0; +- if (state->connection_in == state->connection_out) { +- shutdown(state->connection_out, SHUT_RDWR); +- close(state->connection_out); +- } else { +- close(state->connection_in); +- close(state->connection_out); +- } + sshbuf_free(state->input); + sshbuf_free(state->output); + sshbuf_free(state->outgoing_packet); +@@ -600,11 +601,21 @@ ssh_packet_close(struct ssh *ssh) + inflateEnd(stream); + } + } +- cipher_free(state->send_context); +- cipher_free(state->receive_context); ++ if (packet_state_has_keys(state)) { ++ cipher_free(state->send_context); ++ cipher_free(state->receive_context); ++ audit_session_key_free(MODE_MAX); ++ } + state->send_context = state->receive_context = NULL; + free(ssh->remote_ipaddr); + ssh->remote_ipaddr = NULL; ++ if (state->connection_in == state->connection_out) { ++ shutdown(state->connection_out, SHUT_RDWR); ++ close(state->connection_out); ++ } else { ++ close(state->connection_in); ++ close(state->connection_out); ++ } + free(ssh->state); + ssh->state = NULL; + } +@@ -950,6 +961,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod + " (%llu bytes total)", __func__, + (unsigned long long)ps->blocks, dir, + (unsigned long long)ps->bytes); ++ audit_session_key_free(mode); + cipher_free(*ccp); + *ccp = NULL; + enc = &state->newkeys[mode]->enc; +@@ -2440,6 +2452,72 @@ ssh_packet_get_output(struct ssh *ssh) + return (void *)ssh->state->output; + } + ++static void ++newkeys_destroy_and_free(struct newkeys *newkeys) ++{ ++ if (newkeys == NULL) ++ return; ++ ++ free(newkeys->enc.name); ++ ++ if (newkeys->mac.enabled) { ++ mac_clear(&newkeys->mac); ++ free(newkeys->mac.name); ++ } ++ ++ free(newkeys->comp.name); ++ ++ newkeys_destroy(newkeys); ++ free(newkeys); ++} ++ ++static void ++packet_destroy_state(struct session_state *state) ++{ ++ if (state == NULL) ++ return; ++ ++ cipher_free(state->receive_context); ++ cipher_free(state->send_context); ++ ++ buffer_free(state->input); ++ state->input = NULL; ++ buffer_free(state->output); ++ state->output = NULL; ++ buffer_free(state->outgoing_packet); ++ state->outgoing_packet = NULL; ++ buffer_free(state->incoming_packet); ++ state->incoming_packet = NULL; ++ if( state->compression_buffer ) { ++ buffer_free(state->compression_buffer); ++ state->compression_buffer = NULL; ++ } ++ newkeys_destroy_and_free(state->newkeys[MODE_IN]); ++ state->newkeys[MODE_IN] = NULL; ++ newkeys_destroy_and_free(state->newkeys[MODE_OUT]); ++ state->newkeys[MODE_OUT] = NULL; ++ mac_destroy(state->packet_discard_mac); ++// TAILQ_HEAD(, packet) outgoing; ++// memset(state, 0, sizeof(state)); ++} ++ ++void ++packet_destroy_all(int audit_it, int privsep) ++{ ++ if (audit_it) ++ audit_it = (active_state != NULL && packet_state_has_keys(active_state->state)); ++ if (active_state != NULL) ++ packet_destroy_state(active_state->state); ++ if (audit_it) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ audit_session_key_free(MODE_MAX); ++ else ++ audit_session_key_free_body(MODE_MAX, getpid(), getuid()); ++#endif ++ } ++} ++ + /* Reset after_authentication and reset compression in post-auth privsep */ + static int + ssh_packet_set_postauth(struct ssh *ssh) +diff -up openssh-7.4p1/packet.h.audit openssh-7.4p1/packet.h +--- openssh-7.4p1/packet.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/packet.h 2016-12-23 18:54:54.438080420 +0100 +@@ -208,4 +208,5 @@ extern struct ssh *active_state; + # undef EC_POINT + #endif + ++void packet_destroy_all(int, int); + #endif /* PACKET_H */ +diff -up openssh-7.4p1/session.c.audit openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.audit 2016-12-23 18:54:54.430080418 +0100 ++++ openssh-7.4p1/session.c 2016-12-23 18:57:45.068115466 +0100 +@@ -142,7 +142,7 @@ extern int log_stderr; + extern int debug_flag; + extern u_int utmp_len; + extern int startup_pipe; +-extern void destroy_sensitive_data(void); ++extern void destroy_sensitive_data(int); + extern Buffer loginmsg; + + /* original command from peer. */ +@@ -576,6 +576,14 @@ do_exec_pty(Session *s, const char *comm + /* Parent. Close the slave side of the pseudo tty. */ + close(ttyfd); + ++#if !defined(HAVE_OSF_SIA) && defined(SSH_AUDIT_EVENTS) ++ /* do_login in the child did not affect state in this process, ++ compensate. From an architectural standpoint, this is extremely ++ ugly. */ ++ if (command != NULL) ++ audit_count_session_open(); ++#endif ++ + /* Enter interactive session. */ + s->ptymaster = ptymaster; + packet_set_interactive(1, +@@ -696,15 +704,19 @@ do_exec(Session *s, const char *command) + s->self); + + #ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL || s->command_handle != -1) ++ fatal("do_exec: command already set"); + if (command != NULL) +- PRIVSEP(audit_run_command(command)); ++ s->command = xstrdup(command); + else if (s->ttyfd == -1) { + char *shell = s->pw->pw_shell; + + if (shell[0] == '\0') /* empty shell means /bin/sh */ + shell =_PATH_BSHELL; +- PRIVSEP(audit_run_command(shell)); ++ s->command = xstrdup(shell); + } ++ if (s->command != NULL && s->ptyfd == -1) ++ s->command_handle = PRIVSEP(audit_run_command(s->command)); + #endif + if (s->ttyfd != -1) + ret = do_exec_pty(s, command); +@@ -1543,7 +1555,10 @@ do_child(Session *s, const char *command + int r = 0; + + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(1); ++ /* Don't audit this - both us and the parent would be talking to the ++ monitor over a single socket, with no synchronization. */ ++ packet_destroy_all(0, 1); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { +@@ -1757,6 +1772,9 @@ session_unused(int id) + sessions[id].ttyfd = -1; + sessions[id].ptymaster = -1; + sessions[id].x11_chanids = NULL; ++#ifdef SSH_AUDIT_EVENTS ++ sessions[id].command_handle = -1; ++#endif + sessions[id].next_unused = sessions_first_unused; + sessions_first_unused = id; + } +@@ -1839,6 +1857,19 @@ session_open(Authctxt *authctxt, int cha + } + + Session * ++session_by_id(int id) ++{ ++ if (id >= 0 && id < sessions_nalloc) { ++ Session *s = &sessions[id]; ++ if (s->used) ++ return s; ++ } ++ debug("%s: unknown id %d", __func__, id); ++ session_dump(); ++ return NULL; ++} ++ ++Session * + session_by_tty(char *tty) + { + int i; +@@ -2351,6 +2382,32 @@ session_exit_message(Session *s, int sta + chan_write_failed(c); + } + ++#ifdef SSH_AUDIT_EVENTS ++void ++session_end_command2(Session *s) ++{ ++ if (s->command != NULL) { ++ if (s->command_handle != -1) ++ audit_end_command(s->command_handle, s->command); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++ ++static void ++session_end_command(Session *s) ++{ ++ if (s->command != NULL) { ++ if (s->command_handle != -1) ++ PRIVSEP(audit_end_command(s->command_handle, s->command)); ++ free(s->command); ++ s->command = NULL; ++ s->command_handle = -1; ++ } ++} ++#endif ++ + void + session_close(Session *s) + { +@@ -2365,6 +2422,10 @@ session_close(Session *s) + + if (s->ttyfd != -1) + session_pty_cleanup(s); ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command) ++ session_end_command(s); ++#endif + free(s->term); + free(s->display); + free(s->x11_chanids); +@@ -2575,6 +2636,15 @@ do_authenticated2(Authctxt *authctxt) + server_loop2(authctxt); + } + ++static void ++do_cleanup_one_session(Session *s) ++{ ++ session_pty_cleanup2(s); ++#ifdef SSH_AUDIT_EVENTS ++ session_end_command2(s); ++#endif ++} ++ + void + do_cleanup(Authctxt *authctxt) + { +@@ -2626,7 +2696,7 @@ do_cleanup(Authctxt *authctxt) + * or if running in monitor. + */ + if (!use_privsep || mm_is_monitor()) +- session_destroy_all(session_pty_cleanup2); ++ session_destroy_all(do_cleanup_one_session); + } + + /* Return a name for the remote host that fits inside utmp_size */ +diff -up openssh-7.4p1/session.h.audit openssh-7.4p1/session.h +--- openssh-7.4p1/session.h.audit 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/session.h 2016-12-23 18:54:54.438080420 +0100 +@@ -60,6 +60,12 @@ struct Session { + char *name; + char *val; + } *env; ++ ++ /* exec */ ++#ifdef SSH_AUDIT_EVENTS ++ int command_handle; ++ char *command; ++#endif + }; + + void do_authenticated(Authctxt *); +@@ -72,8 +78,10 @@ void session_close_by_pid(pid_t, int); + void session_close_by_channel(int, void *); + void session_destroy_all(void (*)(Session *)); + void session_pty_cleanup2(Session *); ++void session_end_command2(Session *); + + Session *session_new(void); ++Session *session_by_id(int); + Session *session_by_tty(char *); + void session_close(Session *); + void do_setusercontext(struct passwd *); +diff -up openssh-7.4p1/sshd.c.audit openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.audit 2016-12-23 18:54:54.403080411 +0100 ++++ openssh-7.4p1/sshd.c 2016-12-23 18:56:18.992101105 +0100 +@@ -119,6 +119,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" +@@ -244,7 +245,7 @@ Buffer loginmsg; + struct passwd *privsep_pw = NULL; + + /* Prototypes for various functions defined later in this file. */ +-void destroy_sensitive_data(void); ++void destroy_sensitive_data(int); + void demote_sensitive_data(void); + static void do_ssh2_kex(void); + +@@ -261,6 +262,15 @@ close_listen_socks(void) + num_listen_socks = -1; + } + ++/* ++ * Is this process listening for clients (i.e. not specific to any specific ++ * client connection?) ++ */ ++int listening_for_clients(void) ++{ ++ return num_listen_socks >= 0; ++} ++ + static void + close_startup_pipes(void) + { +@@ -473,18 +483,45 @@ sshd_exchange_identification(struct ssh + } + } + +-/* Destroy the host and server keys. They will no longer be needed. */ ++/* ++ * Destroy the host and server keys. They will no longer be needed. Careful, ++ * this can be called from cleanup_exit() - i.e. from just about anywhere. ++ */ + void +-destroy_sensitive_data(void) ++destroy_sensitive_data(int privsep) + { + int i; ++#ifdef SSH_AUDIT_EVENTS ++ pid_t pid; ++ uid_t uid; + ++ pid = getpid(); ++ uid = getuid(); ++#endif + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (key_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]); + sensitive_data.host_keys[i] = NULL; ++ if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ if (privsep) ++ PRIVSEP(audit_destroy_sensitive_data(fp, ++ pid, uid)); ++ else ++ audit_destroy_sensitive_data(fp, ++ pid, uid); ++#endif ++ free(fp); ++ } + } +- if (sensitive_data.host_certificates[i]) { ++ if (sensitive_data.host_certificates ++ && sensitive_data.host_certificates[i]) { + key_free(sensitive_data.host_certificates[i]); + sensitive_data.host_certificates[i] = NULL; + } +@@ -497,12 +534,30 @@ demote_sensitive_data(void) + { + Key *tmp; + int i; ++#ifdef SSH_AUDIT_EVENTS ++ pid_t pid; ++ uid_t uid; + ++ pid = getpid(); ++ uid = getuid(); ++#endif + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { ++ char *fp; ++ ++ if (key_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]); + sensitive_data.host_keys[i] = tmp; ++ if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_destroy_sensitive_data(fp, pid, uid); ++#endif ++ free(fp); ++ } + } + /* Certs do not need demotion */ + } +@@ -585,7 +640,7 @@ privsep_preauth(Authctxt *authctxt) + + if (use_privsep == PRIVSEP_ON) + box = ssh_sandbox_init(pmonitor); +- pid = fork(); ++ pmonitor->m_pid = pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { +@@ -665,6 +720,12 @@ privsep_postauth(Authctxt *authctxt) + else if (pmonitor->m_pid != 0) { + verbose("User child is on pid %ld", (long)pmonitor->m_pid); + buffer_clear(&loginmsg); ++ if (*pmonitor->m_pkex != NULL ){ ++ newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_OUT]); ++ newkeys_destroy((*pmonitor->m_pkex)->newkeys[MODE_IN]); ++ audit_session_key_free_body(2, getpid(), getuid()); ++ packet_destroy_all(0, 0); ++ } + monitor_child_postauth(pmonitor); + + /* NEVERREACHED */ +@@ -1154,6 +1215,7 @@ server_accept_loop(int *sock_in, int *so + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ destroy_sensitive_data(0); + close_listen_socks(); + if (options.pid_file != NULL) + unlink(options.pid_file); +@@ -2092,6 +2150,7 @@ main(int ac, char **av) + */ + if (use_privsep) { + mm_send_keystate(pmonitor); ++ packet_destroy_all(1, 1); + exit(0); + } + +@@ -2148,6 +2207,9 @@ main(int ac, char **av) + do_authenticated(authctxt); + + /* The connection has been terminated. */ ++ packet_destroy_all(1, 1); ++ destroy_sensitive_data(1); ++ + packet_get_bytes(&ibytes, &obytes); + verbose("Transferred: sent %llu, received %llu bytes", + (unsigned long long)obytes, (unsigned long long)ibytes); +@@ -2321,6 +2383,16 @@ do_ssh2_kex(void) + void + cleanup_exit(int i) + { ++ static int in_cleanup = 0; ++ int is_privsep_child; ++ ++ /* cleanup_exit can be called at the very least from the privsep ++ wrappers used for auditing. Make sure we don't recurse ++ indefinitely. */ ++ if (in_cleanup) ++ _exit(i); ++ in_cleanup = 1; ++ + if (the_authctxt) { + do_cleanup(the_authctxt); + if (use_privsep && privsep_is_preauth && +@@ -2332,9 +2404,14 @@ cleanup_exit(int i) + pmonitor->m_pid, strerror(errno)); + } + } ++ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; ++ if (sensitive_data.host_keys != NULL) ++ destroy_sensitive_data(is_privsep_child); ++ packet_destroy_all(1, is_privsep_child); + #ifdef SSH_AUDIT_EVENTS + /* done after do_cleanup so it can cancel the PAM auth 'thread' */ +- if (!use_privsep || mm_is_monitor()) ++ if ((the_authctxt == NULL || !the_authctxt->authenticated) && ++ (!use_privsep || mm_is_monitor())) + audit_event(SSH_CONNECTION_ABANDON); + #endif + _exit(i); +diff -up openssh-7.4p1/sshkey.c.audit openssh-7.4p1/sshkey.c +--- openssh-7.4p1/sshkey.c.audit 2016-12-23 18:54:54.425080417 +0100 ++++ openssh-7.4p1/sshkey.c 2016-12-23 18:54:54.439080420 +0100 +@@ -303,6 +303,33 @@ sshkey_type_is_valid_ca(int type) + } + + int ++sshkey_is_private(const struct sshkey *k) ++{ ++ switch (k->type) { ++#ifdef WITH_OPENSSL ++ case KEY_RSA_CERT: ++ case KEY_RSA1: ++ case KEY_RSA: ++ return k->rsa->d != NULL; ++ case KEY_DSA_CERT: ++ case KEY_DSA: ++ return k->dsa->priv_key != NULL; ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: ++ return EC_KEY_get0_private_key(k->ecdsa) != NULL; ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } ++} ++ ++int + sshkey_is_cert(const struct sshkey *k) + { + if (k == NULL) +diff -up openssh-7.4p1/sshkey.h.audit openssh-7.4p1/sshkey.h +--- openssh-7.4p1/sshkey.h.audit 2016-12-23 18:54:54.425080417 +0100 ++++ openssh-7.4p1/sshkey.h 2016-12-23 18:54:54.439080420 +0100 +@@ -134,6 +134,7 @@ u_int sshkey_size(const struct sshkey + int sshkey_generate(int type, u_int bits, struct sshkey **keyp); + int sshkey_from_private(const struct sshkey *, struct sshkey **); + int sshkey_type_from_name(const char *); ++int sshkey_is_private(const struct sshkey *); + int sshkey_is_cert(const struct sshkey *); + int sshkey_type_is_cert(int); + int sshkey_type_plain(int); diff --git a/SOURCES/openssh-7.4p1-canonize-pkcs11-provider.patch b/SOURCES/openssh-7.4p1-canonize-pkcs11-provider.patch new file mode 100644 index 0000000..f626a1d --- /dev/null +++ b/SOURCES/openssh-7.4p1-canonize-pkcs11-provider.patch @@ -0,0 +1,50 @@ +diff --git a/ssh-agent.c b/ssh-agent.c +index 1320cda..2441329 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -821,7 +821,7 @@ send: + static void + process_remove_smartcard_key(SocketEntry *e) + { +- char *provider = NULL, *pin = NULL; ++ char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX]; + int r, version, success = 0; + Identity *id, *nxt; + Idtab *tab; +@@ -831,6 +831,13 @@ process_remove_smartcard_key(SocketEntry *e) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + free(pin); + ++ if (realpath(provider, canonical_provider) == NULL) { ++ verbose("failed PKCS#11 add of \"%.100s\": realpath: %s", ++ provider, strerror(errno)); ++ goto send; ++ } ++ ++ debug("%s: remove %.100s", __func__, canonical_provider); + for (version = 1; version < 3; version++) { + tab = idtab_lookup(version); + for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { +@@ -838,18 +845,19 @@ process_remove_smartcard_key(SocketEntry *e) + /* Skip file--based keys */ + if (id->provider == NULL) + continue; +- if (!strcmp(provider, id->provider)) { ++ if (!strcmp(canonical_provider, id->provider)) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + tab->nentries--; + } + } + } +- if (pkcs11_del_provider(provider) == 0) ++ if (pkcs11_del_provider(canonical_provider) == 0) + success = 1; + else + error("process_remove_smartcard_key:" + " pkcs11_del_provider failed"); ++send: + free(provider); + send_status(e, success); + } + diff --git a/SOURCES/openssh-7.4p1-cbc-weakness.patch b/SOURCES/openssh-7.4p1-cbc-weakness.patch new file mode 100644 index 0000000..f05b564 --- /dev/null +++ b/SOURCES/openssh-7.4p1-cbc-weakness.patch @@ -0,0 +1,30 @@ +commit 0fb1a617a07b8df5de188dd5a0c8bf293d4bfc0e +Author: markus@openbsd.org +Date: Sat Mar 11 13:07:35 2017 +0000 + + upstream commit + + Don't count the initial block twice when computing how + many bytes to discard for the work around for the attacks against CBC-mode. + ok djm@; report from Jean Paul, Kenny, Martin and Torben @ RHUL + + Upstream-ID: f445f509a4e0a7ba3b9c0dae7311cb42458dc1e2 + +diff --git a/packet.c b/packet.c +index 01e2d45..2f3a2ec 100644 +--- a/packet.c ++++ b/packet.c +@@ -1850,11 +1850,11 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) + if (r != SSH_ERR_MAC_INVALID) + goto out; + logit("Corrupted MAC on input."); +- if (need > PACKET_MAX_SIZE) ++ if (need + block_size > PACKET_MAX_SIZE) + return SSH_ERR_INTERNAL_ERROR; + return ssh_packet_start_discard(ssh, enc, mac, + sshbuf_len(state->incoming_packet), +- PACKET_MAX_SIZE - need); ++ PACKET_MAX_SIZE - need - block_size); + } + /* Remove MAC from input buffer */ + DBG(debug("MAC #%d ok", state->p_read.seqnr)); diff --git a/SOURCES/openssh-7.4p1-coverity.patch b/SOURCES/openssh-7.4p1-coverity.patch new file mode 100644 index 0000000..a80d4d5 --- /dev/null +++ b/SOURCES/openssh-7.4p1-coverity.patch @@ -0,0 +1,574 @@ +diff -up openssh-7.4p1/auth-pam.c.coverity openssh-7.4p1/auth-pam.c +diff -up openssh-7.4p1/channels.c.coverity openssh-7.4p1/channels.c +--- openssh-7.4p1/channels.c.coverity 2017-02-09 14:58:32.786064600 +0100 ++++ openssh-7.4p1/channels.c 2017-02-09 15:01:28.869890219 +0100 +@@ -266,11 +266,11 @@ channel_register_fds(Channel *c, int rfd + channel_max_fd = MAXIMUM(channel_max_fd, wfd); + channel_max_fd = MAXIMUM(channel_max_fd, efd); + +- if (rfd != -1) ++ if (rfd >= 0) + fcntl(rfd, F_SETFD, FD_CLOEXEC); +- if (wfd != -1 && wfd != rfd) ++ if (wfd >= 0 && wfd != rfd) + fcntl(wfd, F_SETFD, FD_CLOEXEC); +- if (efd != -1 && efd != rfd && efd != wfd) ++ if (efd >= 0 && efd != rfd && efd != wfd) + fcntl(efd, F_SETFD, FD_CLOEXEC); + + c->rfd = rfd; +@@ -288,11 +288,11 @@ channel_register_fds(Channel *c, int rfd + + /* enable nonblocking mode */ + if (nonblock) { +- if (rfd != -1) ++ if (rfd >= 0) + set_nonblock(rfd); +- if (wfd != -1) ++ if (wfd >= 0) + set_nonblock(wfd); +- if (efd != -1) ++ if (efd >= 0) + set_nonblock(efd); + } + } +diff -up openssh-7.4p1/clientloop.c.coverity openssh-7.4p1/clientloop.c +diff -up openssh-7.4p1/key.c.coverity openssh-7.4p1/key.c +diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c +--- openssh-7.4p1/monitor.c.coverity 2017-02-09 14:58:32.793064593 +0100 ++++ openssh-7.4p1/monitor.c 2017-02-09 14:58:32.805064581 +0100 +@@ -411,7 +411,7 @@ monitor_child_preauth(Authctxt *_authctx + mm_get_keystate(pmonitor); + + /* Drain any buffered messages from the child */ +- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) + ; + + close(pmonitor->m_sendfd); +diff -up openssh-7.4p1/monitor_wrap.c.coverity openssh-7.4p1/monitor_wrap.c +--- openssh-7.4p1/monitor_wrap.c.coverity 2017-02-09 14:58:32.797064589 +0100 ++++ openssh-7.4p1/monitor_wrap.c 2017-02-09 14:58:32.805064581 +0100 +@@ -525,10 +525,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, + if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || + (tmp2 = dup(pmonitor->m_recvfd)) == -1) { + error("%s: cannot allocate fds for pty", __func__); +- if (tmp1 > 0) ++ if (tmp1 >= 0) + close(tmp1); +- if (tmp2 > 0) +- close(tmp2); ++ /*DEAD CODE if (tmp2 >= 0) ++ close(tmp2);*/ + return 0; + } + close(tmp1); +diff -up openssh-7.4p1/openbsd-compat/bindresvport.c.coverity openssh-7.4p1/openbsd-compat/bindresvport.c +--- openssh-7.4p1/openbsd-compat/bindresvport.c.coverity 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/openbsd-compat/bindresvport.c 2017-02-09 14:58:32.805064581 +0100 +@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr + struct sockaddr_in6 *in6; + u_int16_t *portp; + u_int16_t port; +- socklen_t salen; ++ socklen_t salen = sizeof(struct sockaddr_storage); + int i; + + if (sa == NULL) { +diff -up openssh-7.4p1/packet.c.coverity openssh-7.4p1/packet.c +diff -up openssh-7.4p1/progressmeter.c.coverity openssh-7.4p1/progressmeter.c +diff -up openssh-7.4p1/scp.c.coverity openssh-7.4p1/scp.c +--- openssh-7.4p1/scp.c.coverity 2017-02-09 14:58:32.761064625 +0100 ++++ openssh-7.4p1/scp.c 2017-02-09 14:58:38.590058852 +0100 +@@ -157,7 +157,7 @@ killchild(int signo) + { + if (do_cmd_pid > 1) { + kill(do_cmd_pid, signo ? signo : SIGTERM); +- waitpid(do_cmd_pid, NULL, 0); ++ (void) waitpid(do_cmd_pid, NULL, 0); + } + + if (signo) +diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.coverity 2017-02-09 14:58:32.801064585 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 14:58:38.591058851 +0100 +@@ -1544,7 +1544,7 @@ process_server_config_line(ServerOptions + fatal("%s line %d: Missing subsystem name.", + filename, linenum); + if (!*activep) { +- arg = strdelim(&cp); ++ /*arg =*/ (void) strdelim(&cp); + break; + } + for (i = 0; i < options->num_subsystems; i++) +@@ -1635,8 +1635,9 @@ process_server_config_line(ServerOptions + if (*activep && *charptr == NULL) { + *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ +- if (intptr != NULL) +- *intptr = *intptr + 1; ++ /* DEAD CODE intptr is still NULL ;) ++ if (intptr != NULL) ++ *intptr = *intptr + 1; */ + } + break; + +diff -up openssh-7.4p1/serverloop.c.coverity openssh-7.4p1/serverloop.c +--- openssh-7.4p1/serverloop.c.coverity 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/serverloop.c 2017-02-09 14:58:38.592058850 +0100 +@@ -125,13 +125,13 @@ notify_setup(void) + static void + notify_parent(void) + { +- if (notify_pipe[1] != -1) ++ if (notify_pipe[1] >= 0) + (void)write(notify_pipe[1], "", 1); + } + static void + notify_prepare(fd_set *readset) + { +- if (notify_pipe[0] != -1) ++ if (notify_pipe[0] >= 0) + FD_SET(notify_pipe[0], readset); + } + static void +@@ -139,8 +139,8 @@ notify_done(fd_set *readset) + { + char c; + +- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) +- while (read(notify_pipe[0], &c, 1) != -1) ++ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) ++ while (read(notify_pipe[0], &c, 1) >= 0) + debug2("notify_done: reading"); + } + +@@ -518,7 +518,7 @@ server_request_tun(void) + } + + tun = packet_get_int(); +- if (forced_tun_device != -1) { ++ if (forced_tun_device >= 0) { + if (tun != SSH_TUNID_ANY && forced_tun_device != tun) + goto done; + tun = forced_tun_device; +diff -up openssh-7.4p1/sftp.c.coverity openssh-7.4p1/sftp.c +--- openssh-7.4p1/sftp.c.coverity 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sftp.c 2017-02-09 14:58:38.598058844 +0100 +@@ -224,7 +224,7 @@ killchild(int signo) + { + if (sshpid > 1) { + kill(sshpid, SIGTERM); +- waitpid(sshpid, NULL, 0); ++ (void) waitpid(sshpid, NULL, 0); + } + + _exit(1); +diff -up openssh-7.4p1/sftp-client.c.coverity openssh-7.4p1/sftp-client.c +--- openssh-7.4p1/sftp-client.c.coverity 2017-02-09 14:58:38.596058846 +0100 ++++ openssh-7.4p1/sftp-client.c 2017-02-09 15:20:18.893624636 +0100 +@@ -973,7 +973,7 @@ do_symlink(struct sftp_conn *conn, const + } + + int +-do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) ++do_fsync(struct sftp_conn *conn, const u_char *handle, u_int handle_len) + { + struct sshbuf *msg; + u_int status, id; +--- openssh-7.4p1/sftp-client.h.coverity 2017-02-10 09:28:10.951155129 +0100 ++++ openssh-7.4p1/sftp-client.h 2017-02-10 09:27:28.685069870 +0100 +@@ -107,7 +107,7 @@ int do_hardlink(struct sftp_conn *, cons + int do_symlink(struct sftp_conn *, const char *, const char *); + + /* Call fsync() on open file 'handle' */ +-int do_fsync(struct sftp_conn *conn, u_char *, u_int); ++int do_fsync(struct sftp_conn *conn, const u_char *, u_int); + + /* + * Download 'remote_path' to 'local_path'. Preserve permissions and times +diff -up openssh-7.4p1/ssh-agent.c.coverity openssh-7.4p1/ssh-agent.c +--- openssh-7.4p1/ssh-agent.c.coverity 2017-02-09 14:58:38.599058843 +0100 ++++ openssh-7.4p1/ssh-agent.c 2017-02-09 15:29:21.938917065 +0100 +@@ -1220,8 +1220,8 @@ main(int ac, char **av) + sanitise_stdfd(); + + /* drop */ +- setegid(getgid()); +- setgid(getgid()); ++ (void) setegid(getgid()); ++ (void) setgid(getgid()); + + platform_disable_tracing(0); /* strict=no */ + +diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.coverity 2017-02-09 14:58:38.600058842 +0100 ++++ openssh-7.4p1/sshd.c 2017-02-09 15:30:33.403800831 +0100 +@@ -679,8 +679,10 @@ privsep_preauth(Authctxt *authctxt) + + privsep_preauth_child(); + setproctitle("%s", "[net]"); +- if (box != NULL) ++ if (box != NULL) { + ssh_sandbox_child(box); ++ free(box); ++ } + + return 0; + } +@@ -1382,6 +1384,9 @@ server_accept_loop(int *sock_in, int *so + if (num_listen_socks < 0) + break; + } ++ ++ if (fdset != NULL) ++ free(fdset); + } + + /* +diff --git a/auth-pam.c b/auth-pam.c +index e554ec4..bd16d80 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -834,6 +834,8 @@ fake_password(const char *wire_password) + fatal("%s: password length too long: %zu", __func__, l); + + ret = malloc(l + 1); ++ if (ret == NULL) ++ return NULL; + for (i = 0; i < l; i++) + ret[i] = junk[i % (sizeof(junk) - 1)]; + ret[i] = '\0'; +diff --git a/clientloop.c b/clientloop.c +index c6a4138..9b00e12 100644 +--- a/clientloop.c ++++ b/clientloop.c +@@ -2290,7 +2290,7 @@ update_known_hosts(struct hostkeys_update_ctx *ctx) + free(response); + response = read_passphrase("Accept updated hostkeys? " + "(yes/no): ", RP_ECHO); +- if (strcasecmp(response, "yes") == 0) ++ if (response != NULL && strcasecmp(response, "yes") == 0) + break; + else if (quit_pending || response == NULL || + strcasecmp(response, "no") == 0) { +diff --git a/digest-openssl.c b/digest-openssl.c +index 13b63c2..dfa9b8d 100644 +--- a/digest-openssl.c ++++ b/digest-openssl.c +@@ -158,7 +158,7 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) + const struct ssh_digest *digest = ssh_digest_by_alg(ctx->alg); + u_int l = dlen; + +- if (dlen > UINT_MAX) ++ if (digest == NULL || dlen > UINT_MAX) + return SSH_ERR_INVALID_ARGUMENT; + if (dlen < digest->digest_len) /* No truncation allowed */ + return SSH_ERR_INVALID_ARGUMENT; +diff --git a/kex.c b/kex.c +index a30dabe..a8ac91f 100644 +--- a/kex.c ++++ b/kex.c +@@ -178,7 +178,7 @@ kex_names_valid(const char *names) + char * + kex_names_cat(const char *a, const char *b) + { +- char *ret = NULL, *tmp = NULL, *cp, *p; ++ char *ret = NULL, *tmp = NULL, *cp, *p, *m; + size_t len; + + if (a == NULL || *a == '\0') +@@ -195,8 +195,10 @@ kex_names_cat(const char *a, const char *b) + } + strlcpy(ret, a, len); + for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { +- if (match_list(ret, p, NULL) != NULL) ++ if ((m = match_list(ret, p, NULL)) != NULL) { ++ free(m); + continue; /* Algorithm already present */ ++ } + if (strlcat(ret, ",", len) >= len || + strlcat(ret, p, len) >= len) { + free(tmp); +@@ -651,8 +653,10 @@ choose_enc(struct sshenc *enc, char *client, char *server) + #endif + return SSH_ERR_NO_CIPHER_ALG_MATCH; + } +- if ((enc->cipher = cipher_by_name(name)) == NULL) ++ if ((enc->cipher = cipher_by_name(name)) == NULL) { ++ free(name); + return SSH_ERR_INTERNAL_ERROR; ++ } + enc->name = name; + enc->enabled = 0; + enc->iv = NULL; +@@ -670,8 +674,10 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) + #endif + return SSH_ERR_NO_MAC_ALG_MATCH; + } +- if (mac_setup(mac, name) < 0) ++ if (mac_setup(mac, name) < 0) { ++ free(name); + return SSH_ERR_INTERNAL_ERROR; ++ } + /* truncate the key */ + if (ssh->compat & SSH_BUG_HMAC) + mac->key_len = 16; +@@ -695,6 +701,7 @@ choose_comp(struct sshcomp *comp, char *client, char *server) + } else if (strcmp(name, "none") == 0) { + comp->type = COMP_NONE; + } else { ++ free(name); + return SSH_ERR_INTERNAL_ERROR; + } + comp->name = name; +diff --git a/readconf.c b/readconf.c +index 3e7a5d8..acc1391 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -1500,6 +1500,7 @@ parse_keytypes: + if (r == GLOB_NOMATCH) { + debug("%.200s line %d: include %s matched no " + "files",filename, linenum, arg2); ++ free(arg2); + continue; + } else if (r != 0 || gl.gl_pathc < 0) + fatal("%.200s line %d: glob failed for %s.", +diff --git a/servconf.c b/servconf.c +index 6ab1cb4..5f2464a 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -2284,8 +2284,6 @@ dump_cfg_fmtint(ServerOpCodes code, int val) + static void + dump_cfg_string(ServerOpCodes code, const char *val) + { +- if (val == NULL) +- return; + printf("%s %s\n", lookup_opcode_name(code), + val == NULL ? "none" : val); + } +diff --git a/sshconnect.c b/sshconnect.c +index 07f80cd..5d4b41b 100644 +--- a/sshconnect.c ++++ b/sshconnect.c +@@ -1533,6 +1533,7 @@ maybe_add_key_to_agent(char *authfile, Key *private, char *comment, + if (options.add_keys_to_agent == 2 && + !ask_permission("Add key %s (%s) to agent?", authfile, comment)) { + debug3("user denied adding this key"); ++ close(auth_sock); + return; + } + +@@ -1541,4 +1542,5 @@ maybe_add_key_to_agent(char *authfile, Key *private, char *comment, + debug("identity added to agent: %s", authfile); + else + debug("could not add identity to agent: %s (%d)", authfile, r); ++ close(auth_sock); + } +diff --git a/sshconnect2.c b/sshconnect2.c +index f31c24c..aecf765 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -1061,6 +1061,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id) + + if (key_to_blob(id->key, &blob, &bloblen) == 0) { + /* we cannot handle this key */ ++ free(blob); + debug3("sign_and_send_pubkey: cannot handle key"); + return 0; + } +@@ -1170,6 +1171,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id) + + if (key_to_blob(id->key, &blob, &bloblen) == 0) { + /* we cannot handle this key */ ++ free(blob); + debug3("send_pubkey_test: cannot handle key"); + return 0; + } +diff --git a/sshkey.c b/sshkey.c +index 85fd1bd..58c1051 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -1375,8 +1375,6 @@ sshkey_read(struct sshkey *ret, char **cpp) + retval = 0; + /*XXXX*/ + sshkey_free(k); +- if (retval != 0) +- break; + break; + default: + return SSH_ERR_INVALID_ARGUMENT; +diff --git a/krl.c b/krl.c +index e271a19..69bec99 100644 +--- a/krl.c ++++ b/krl.c +@@ -1089,7 +1089,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, + break; + case KRL_SECTION_SIGNATURE: + /* Handled above, but still need to stay in synch */ +- sshbuf_reset(sect); ++ sshbuf_free(sect); + sect = NULL; + if ((r = sshbuf_skip_string(copy)) != 0) + goto out; +@@ -1288,7 +1288,8 @@ ssh_krl_file_contains_key(const char *path, const struct sshkey *key) + debug2("%s: checking KRL %s", __func__, path); + r = ssh_krl_check_key(krl, key); + out: +- close(fd); ++ if (fd != -1) ++ close(fd); + sshbuf_free(krlbuf); + ssh_krl_free(krl); + if (r != 0) +diff --git a/readconf.c b/readconf.c +index acc1391..c4dff15 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -1185,7 +1185,7 @@ parse_int: + value = cipher_number(arg); + if (value == -1) + fatal("%.200s line %d: Bad cipher '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && *intptr == -1) + *intptr = value; + break; +@@ -1196,7 +1196,7 @@ parse_int: + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (!ciphers_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && options->ciphers == NULL) + options->ciphers = xstrdup(arg); + break; +@@ -1207,7 +1207,7 @@ parse_int: + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (!mac_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && options->macs == NULL) + options->macs = xstrdup(arg); + break; +@@ -1220,7 +1220,7 @@ parse_int: + filename, linenum); + if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && options->kex_algorithms == NULL) + options->kex_algorithms = xstrdup(arg); + break; +@@ -1235,7 +1235,7 @@ parse_keytypes: + filename, linenum); + if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) + fatal("%s line %d: Bad key types '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; +@@ -1248,7 +1248,7 @@ parse_keytypes: + value = proto_spec(arg); + if (value == SSH_PROTO_UNKNOWN) + fatal("%.200s line %d: Bad protocol spec '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && *intptr == SSH_PROTO_UNKNOWN) + *intptr = value; + break; +diff --git a/servconf.c b/servconf.c +index 5f2464a..4564494 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -1217,7 +1217,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, + filename, linenum); + if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) + fatal("%s line %d: Bad key types '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; +@@ -1476,7 +1476,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, + fatal("%s line %d: Missing argument.", filename, linenum); + if (!ciphers_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%s line %d: Bad SSH2 cipher spec '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (options->ciphers == NULL) + options->ciphers = xstrdup(arg); + break; +@@ -1487,7 +1487,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, + fatal("%s line %d: Missing argument.", filename, linenum); + if (!mac_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%s line %d: Bad SSH2 mac spec '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (options->macs == NULL) + options->macs = xstrdup(arg); + break; +@@ -1500,7 +1500,7 @@ process_server_config_line_depth(ServerOptions *options, char *line, + filename, linenum); + if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) + fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", +- filename, linenum, arg ? arg : ""); ++ filename, linenum, arg); + if (options->kex_algorithms == NULL) + options->kex_algorithms = xstrdup(arg); + break; +diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c +index aaf712d..62a76b3 100644 +--- a/ssh-pkcs11.c ++++ b/ssh-pkcs11.c +@@ -536,8 +536,8 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, + X509_free(x509); + } + if (rsa && rsa->n && rsa->e && +- pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { +- key = sshkey_new(KEY_UNSPEC); ++ pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0 && ++ (key = sshkey_new(KEY_UNSPEC)) != NULL) { + key->rsa = rsa; + key->type = KEY_RSA; + key->flags |= SSHKEY_FLAG_EXT; +diff --git a/sshconnect1.c b/sshconnect1.c +index a045361..0e1a506 100644 +--- a/sshconnect1.c ++++ b/sshconnect1.c +@@ -520,7 +520,8 @@ ssh_kex(char *host, struct sockaddr *hostaddr) + cookie[i] = packet_get_char(); + + /* Get the public key. */ +- server_key = key_new(KEY_RSA1); ++ if ((server_key = key_new(KEY_RSA1)) == NULL) ++ fatal("%s: key_new(KEY_RSA1) failed", __func__); + bits = packet_get_int(); + packet_get_bignum(server_key->rsa->e); + packet_get_bignum(server_key->rsa->n); +@@ -532,7 +533,8 @@ ssh_kex(char *host, struct sockaddr *hostaddr) + logit("Warning: This may be due to an old implementation of ssh."); + } + /* Get the host key. */ +- host_key = key_new(KEY_RSA1); ++ if ((host_key = key_new(KEY_RSA1)) == NULL) ++ fatal("%s: key_new(KEY_RSA1) failed", __func__); + bits = packet_get_int(); + packet_get_bignum(host_key->rsa->e); + packet_get_bignum(host_key->rsa->n); +diff --git a/sshkey.c b/sshkey.c +index 58c1051..6afacb5 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -1239,6 +1239,9 @@ sshkey_read(struct sshkey *ret, char **cpp) + u_long bits; + #endif /* WITH_SSH1 */ + ++ if (ret == NULL) ++ return SSH_ERR_INVALID_ARGUMENT; ++ + cp = *cpp; + + switch (ret->type) { diff --git a/SOURCES/openssh-7.4p1-ctr-cavstest.patch b/SOURCES/openssh-7.4p1-ctr-cavstest.patch new file mode 100644 index 0000000..eb43c79 --- /dev/null +++ b/SOURCES/openssh-7.4p1-ctr-cavstest.patch @@ -0,0 +1,250 @@ +diff -up openssh-6.8p1/Makefile.in.ctr-cavs openssh-6.8p1/Makefile.in +--- openssh-6.8p1/Makefile.in.ctr-cavs 2015-03-18 11:22:05.493289018 +0100 ++++ openssh-6.8p1/Makefile.in 2015-03-18 11:22:44.504196316 +0100 +@@ -28,6 +28,7 @@ SSH_KEYSIGN=$(libexecdir)/ssh-keysign + SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper + SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper + SSH_KEYCAT=$(libexecdir)/ssh-keycat ++CTR_CAVSTEST=$(libexecdir)/ctr-cavstest + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +@@ -66,7 +67,7 @@ EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ + +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) + + LIBOPENSSH_OBJS=\ + ssh_api.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) $(SSHLIBS) + ++ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o ++ $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) ++ + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + +@@ -326,6 +330,7 @@ install-files: + $(INSTALL) -m 0700 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ + fi + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ctr-cavstest$(EXEEXT) $(DESTDIR)$(libexecdir)/ctr-cavstest$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 +diff -up openssh-6.8p1/ctr-cavstest.c.ctr-cavs openssh-6.8p1/ctr-cavstest.c +--- openssh-6.8p1/ctr-cavstest.c.ctr-cavs 2015-03-18 11:22:05.521288952 +0100 ++++ openssh-6.8p1/ctr-cavstest.c 2015-03-18 11:22:05.521288952 +0100 +@@ -0,0 +1,208 @@ ++/* ++ * ++ * invocation (all of the following are equal): ++ * ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt --data a6deca405eef2e8e4609abf3c3ccf4a6 ++ * ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt --data a6deca405eef2e8e4609abf3c3ccf4a6 --iv 00000000000000000000000000000000 ++ * echo -n a6deca405eef2e8e4609abf3c3ccf4a6 | ./ctr-cavstest --algo aes128-ctr --key 987212980144b6a632e864031f52dacc --mode encrypt ++ */ ++ ++#include "includes.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "xmalloc.h" ++#include "log.h" ++#include "cipher.h" ++ ++/* compatibility with old or broken OpenSSL versions */ ++#include "openbsd-compat/openssl-compat.h" ++ ++void usage(void) { ++ fprintf(stderr, "Usage: ctr-cavstest --algo \n" ++ " --key --mode \n" ++ " [--iv ] --data \n\n" ++ "Hexadecimal output is printed to stdout.\n" ++ "Hexadecimal input data can be alternatively read from stdin.\n"); ++ exit(1); ++} ++ ++void *fromhex(char *hex, size_t *len) ++{ ++ unsigned char *bin; ++ char *p; ++ size_t n = 0; ++ int shift = 4; ++ unsigned char out = 0; ++ unsigned char *optr; ++ ++ bin = xmalloc(strlen(hex)/2); ++ optr = bin; ++ ++ for (p = hex; *p != '\0'; ++p) { ++ unsigned char c; ++ ++ c = *p; ++ if (isspace(c)) ++ continue; ++ ++ if (c >= '0' && c <= '9') { ++ c = c - '0'; ++ } else if (c >= 'A' && c <= 'F') { ++ c = c - 'A' + 10; ++ } else if (c >= 'a' && c <= 'f') { ++ c = c - 'a' + 10; ++ } else { ++ /* truncate on nonhex cipher */ ++ break; ++ } ++ ++ out |= c << shift; ++ shift = (shift + 4) % 8; ++ ++ if (shift) { ++ *(optr++) = out; ++ out = 0; ++ ++n; ++ } ++ } ++ ++ *len = n; ++ return bin; ++} ++ ++#define READ_CHUNK 4096 ++#define MAX_READ_SIZE 1024*1024*100 ++char *read_stdin(void) ++{ ++ char *buf; ++ size_t n, total = 0; ++ ++ buf = xmalloc(READ_CHUNK); ++ ++ do { ++ n = fread(buf + total, 1, READ_CHUNK, stdin); ++ if (n < READ_CHUNK) /* terminate on short read */ ++ break; ++ ++ total += n; ++ buf = xreallocarray(buf, total + READ_CHUNK, 1); ++ } while(total < MAX_READ_SIZE); ++ return buf; ++} ++ ++int main (int argc, char *argv[]) ++{ ++ ++ const struct sshcipher *c; ++ struct sshcipher_ctx *cc; ++ char *algo = "aes128-ctr"; ++ char *hexkey = NULL; ++ char *hexiv = "00000000000000000000000000000000"; ++ char *hexdata = NULL; ++ char *p; ++ int i; ++ int encrypt = 1; ++ void *key; ++ size_t keylen; ++ void *iv; ++ size_t ivlen; ++ void *data; ++ size_t datalen; ++ void *outdata; ++ ++ for (i = 1; i < argc; ++i) { ++ if (strcmp(argv[i], "--algo") == 0) { ++ algo = argv[++i]; ++ } else if (strcmp(argv[i], "--key") == 0) { ++ hexkey = argv[++i]; ++ } else if (strcmp(argv[i], "--mode") == 0) { ++ ++i; ++ if (argv[i] == NULL) { ++ usage(); ++ } ++ if (strncmp(argv[i], "enc", 3) == 0) { ++ encrypt = 1; ++ } else if (strncmp(argv[i], "dec", 3) == 0) { ++ encrypt = 0; ++ } else { ++ usage(); ++ } ++ } else if (strcmp(argv[i], "--iv") == 0) { ++ hexiv = argv[++i]; ++ } else if (strcmp(argv[i], "--data") == 0) { ++ hexdata = argv[++i]; ++ } ++ } ++ ++ if (hexkey == NULL || algo == NULL) { ++ usage(); ++ } ++ ++ SSLeay_add_all_algorithms(); ++ ++ c = cipher_by_name(algo); ++ if (c == NULL) { ++ fprintf(stderr, "Error: unknown algorithm\n"); ++ return 2; ++ } ++ ++ if (hexdata == NULL) { ++ hexdata = read_stdin(); ++ } else { ++ hexdata = xstrdup(hexdata); ++ } ++ ++ key = fromhex(hexkey, &keylen); ++ ++ if (keylen != 16 && keylen != 24 && keylen == 32) { ++ fprintf(stderr, "Error: unsupported key length\n"); ++ return 2; ++ } ++ ++ iv = fromhex(hexiv, &ivlen); ++ ++ if (ivlen != 16) { ++ fprintf(stderr, "Error: unsupported iv length\n"); ++ return 2; ++ } ++ ++ data = fromhex(hexdata, &datalen); ++ ++ if (data == NULL || datalen == 0) { ++ fprintf(stderr, "Error: no data to encrypt/decrypt\n"); ++ return 2; ++ } ++ ++ cipher_init(&cc, c, key, keylen, iv, ivlen, encrypt); ++ ++ free(key); ++ free(iv); ++ ++ outdata = malloc(datalen); ++ if(outdata == NULL) { ++ fprintf(stderr, "Error: memory allocation failure\n"); ++ return 2; ++ } ++ ++ cipher_crypt(cc, 0, outdata, data, datalen, 0, 0); ++ ++ free(data); ++ ++ cipher_free(cc); ++ ++ for (p = outdata; datalen > 0; ++p, --datalen) { ++ printf("%02X", (unsigned char)*p); ++ } ++ ++ free(outdata); ++ ++ printf("\n"); ++ return 0; ++} ++ diff --git a/SOURCES/openssh-7.4p1-debian-restore-tcp-wrappers.patch b/SOURCES/openssh-7.4p1-debian-restore-tcp-wrappers.patch new file mode 100644 index 0000000..5fcc451 --- /dev/null +++ b/SOURCES/openssh-7.4p1-debian-restore-tcp-wrappers.patch @@ -0,0 +1,140 @@ +diff -up openssh-7.4p1/configure.ac.tcp_wrappers openssh-7.4p1/configure.ac +--- openssh-7.4p1/configure.ac.tcp_wrappers 2016-12-23 15:36:38.745411192 +0100 ++++ openssh-7.4p1/configure.ac 2016-12-23 15:36:38.777411197 +0100 +@@ -1491,6 +1491,62 @@ AC_ARG_WITH([skey], + ] + ) + ++# Check whether user wants TCP wrappers support ++TCPW_MSG="no" ++AC_ARG_WITH([tcp-wrappers], ++ [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], ++ [ ++ if test "x$withval" != "xno" ; then ++ saved_LIBS="$LIBS" ++ saved_LDFLAGS="$LDFLAGS" ++ saved_CPPFLAGS="$CPPFLAGS" ++ if test -n "${withval}" && \ ++ test "x${withval}" != "xyes"; then ++ if test -d "${withval}/lib"; then ++ if test -n "${need_dash_r}"; then ++ LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" ++ else ++ LDFLAGS="-L${withval}/lib ${LDFLAGS}" ++ fi ++ else ++ if test -n "${need_dash_r}"; then ++ LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" ++ else ++ LDFLAGS="-L${withval} ${LDFLAGS}" ++ fi ++ fi ++ if test -d "${withval}/include"; then ++ CPPFLAGS="-I${withval}/include ${CPPFLAGS}" ++ else ++ CPPFLAGS="-I${withval} ${CPPFLAGS}" ++ fi ++ fi ++ LIBS="-lwrap $LIBS" ++ AC_MSG_CHECKING([for libwrap]) ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++#include ++int deny_severity = 0, allow_severity = 0; ++ ]], [[ ++ hosts_access(0); ++ ]])], [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE([LIBWRAP], [1], ++ [Define if you want ++ TCP Wrappers support]) ++ SSHDLIBS="$SSHDLIBS -lwrap" ++ TCPW_MSG="yes" ++ ], [ ++ AC_MSG_ERROR([*** libwrap missing]) ++ ++ ]) ++ LIBS="$saved_LIBS" ++ fi ++ ] ++) ++ + # Check whether user wants to use ldns + LDNS_MSG="no" + AC_ARG_WITH(ldns, +@@ -5214,6 +5270,7 @@ echo " KerberosV support + echo " SELinux support: $SELINUX_MSG" + echo " Smartcard support: $SCARD_MSG" + echo " S/KEY support: $SKEY_MSG" ++echo " TCP Wrappers support: $TCPW_MSG" + echo " MD5 password support: $MD5_MSG" + echo " libedit support: $LIBEDIT_MSG" + echo " Solaris process contract support: $SPC_MSG" +diff -up openssh-7.4p1/sshd.8.tcp_wrappers openssh-7.4p1/sshd.8 +--- openssh-7.4p1/sshd.8.tcp_wrappers 2016-12-23 15:36:38.759411194 +0100 ++++ openssh-7.4p1/sshd.8 2016-12-23 15:36:38.778411197 +0100 +@@ -836,6 +836,12 @@ the user's home directory becomes access + This file should be writable only by the user, and need not be + readable by anyone else. + .Pp ++.It Pa /etc/hosts.allow ++.It Pa /etc/hosts.deny ++Access controls that should be enforced by tcp-wrappers are defined here. ++Further details are described in ++.Xr hosts_access 5 . ++.Pp + .It Pa /etc/hosts.equiv + This file is for host-based authentication (see + .Xr ssh 1 ) . +@@ -960,6 +966,7 @@ IPv6 address can be used everywhere wher + .Xr ssh-keygen 1 , + .Xr ssh-keyscan 1 , + .Xr chroot 2 , ++.Xr hosts_access 5 , + .Xr login.conf 5 , + .Xr moduli 5 , + .Xr sshd_config 5 , +diff -up openssh-7.4p1/sshd.c.tcp_wrappers openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.tcp_wrappers 2016-12-23 15:36:38.772411196 +0100 ++++ openssh-7.4p1/sshd.c 2016-12-23 15:37:15.032417028 +0100 +@@ -123,6 +123,13 @@ + #include "version.h" + #include "ssherr.h" + ++#ifdef LIBWRAP ++#include ++#include ++int allow_severity; ++int deny_severity; ++#endif /* LIBWRAP */ ++ + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) + #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) +@@ -2012,6 +2019,24 @@ main(int ac, char **av) + #ifdef SSH_AUDIT_EVENTS + audit_connection_from(remote_ip, remote_port); + #endif ++#ifdef LIBWRAP ++ allow_severity = options.log_facility|LOG_INFO; ++ deny_severity = options.log_facility|LOG_WARNING; ++ /* Check whether logins are denied from this host. */ ++ if (packet_connection_is_on_socket()) { ++ struct request_info req; ++ ++ request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); ++ fromhost(&req); ++ ++ if (!hosts_access(&req)) { ++ debug("Connection refused by tcp wrapper"); ++ refuse(&req); ++ /* NOTREACHED */ ++ fatal("libwrap refuse returns"); ++ } ++ } ++#endif /* LIBWRAP */ + + /* Log the connection. */ + laddr = get_local_ipaddr(sock_in); diff --git a/SOURCES/openssh-7.4p1-expose-pam.patch b/SOURCES/openssh-7.4p1-expose-pam.patch new file mode 100644 index 0000000..e4e6d82 --- /dev/null +++ b/SOURCES/openssh-7.4p1-expose-pam.patch @@ -0,0 +1,517 @@ +diff -up openssh-7.4p1/auth2.c.expose-pam openssh-7.4p1/auth2.c +--- openssh-7.4p1/auth2.c.expose-pam 2016-12-23 15:40:26.768447868 +0100 ++++ openssh-7.4p1/auth2.c 2016-12-23 15:40:26.818447876 +0100 +@@ -310,6 +310,7 @@ userauth_finish(Authctxt *authctxt, int + const char *submethod) + { + char *methods; ++ char *prev_auth_details; + int partial = 0; + + if (!authctxt->valid && authenticated) +@@ -340,6 +341,18 @@ userauth_finish(Authctxt *authctxt, int + if (authctxt->postponed) + return; + ++ if (authenticated || partial) { ++ prev_auth_details = authctxt->auth_details; ++ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", ++ prev_auth_details ? prev_auth_details : "", ++ prev_auth_details ? ", " : "", method, ++ authctxt->last_details ? ": " : "", ++ authctxt->last_details ? authctxt->last_details : ""); ++ free(prev_auth_details); ++ } ++ free(authctxt->last_details); ++ authctxt->last_details = NULL; ++ + #ifdef USE_PAM + if (options.use_pam && authenticated) { + if (!PRIVSEP(do_pam_account())) { +diff -up openssh-7.4p1/auth2-gss.c.expose-pam openssh-7.4p1/auth2-gss.c +--- openssh-7.4p1/auth2-gss.c.expose-pam 2016-12-23 15:40:26.769447868 +0100 ++++ openssh-7.4p1/auth2-gss.c 2016-12-23 15:40:26.818447876 +0100 +@@ -276,6 +276,9 @@ input_gssapi_exchange_complete(int type, + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, + authctxt->pw)); + ++ if (authenticated) ++ authctxt->last_details = ssh_gssapi_get_displayname(); ++ + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); +@@ -322,6 +325,9 @@ input_gssapi_mic(int type, u_int32_t ple + else + logit("GSSAPI MIC check failed"); + ++ if (authenticated) ++ authctxt->last_details = ssh_gssapi_get_displayname(); ++ + buffer_free(&b); + if (micuser != authctxt->user) + free(micuser); +diff -up openssh-7.4p1/auth2-hostbased.c.expose-pam openssh-7.4p1/auth2-hostbased.c +--- openssh-7.4p1/auth2-hostbased.c.expose-pam 2016-12-23 15:40:26.731447862 +0100 ++++ openssh-7.4p1/auth2-hostbased.c 2016-12-23 15:40:26.818447876 +0100 +@@ -60,7 +60,7 @@ userauth_hostbased(Authctxt *authctxt) + { + Buffer b; + Key *key = NULL; +- char *pkalg, *cuser, *chost, *service; ++ char *pkalg, *cuser, *chost, *service, *pubkey; + u_char *pkblob, *sig; + u_int alen, blen, slen; + int pktype; +@@ -140,15 +140,21 @@ userauth_hostbased(Authctxt *authctxt) + buffer_dump(&b); + #endif + +- pubkey_auth_info(authctxt, key, +- "client user \"%.100s\", client host \"%.100s\"", cuser, chost); ++ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); ++ auth_info(authctxt, ++ "%s, client user \"%.100s\", client host \"%.100s\"", ++ pubkey, cuser, chost); + + /* test for allowed key and correct signature */ + authenticated = 0; + if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && + PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), +- buffer_len(&b))) == 1) ++ buffer_len(&b))) == 1) { + authenticated = 1; ++ authctxt->last_details = pubkey; ++ } else { ++ free(pubkey); ++ } + + buffer_free(&b); + done: +diff -up openssh-7.4p1/auth2-pubkey.c.expose-pam openssh-7.4p1/auth2-pubkey.c +--- openssh-7.4p1/auth2-pubkey.c.expose-pam 2016-12-23 15:40:26.746447864 +0100 ++++ openssh-7.4p1/auth2-pubkey.c 2016-12-23 15:40:26.819447876 +0100 +@@ -79,7 +79,7 @@ userauth_pubkey(Authctxt *authctxt) + { + Buffer b; + Key *key = NULL; +- char *pkalg, *userstyle, *fp = NULL; ++ char *pkalg, *userstyle, *pubkey, *fp = NULL; + u_char *pkblob, *sig; + u_int alen, blen, slen; + int have_sig, pktype; +@@ -177,7 +177,8 @@ userauth_pubkey(Authctxt *authctxt) + #ifdef DEBUG_PK + buffer_dump(&b); + #endif +- pubkey_auth_info(authctxt, key, NULL); ++ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); ++ auth_info(authctxt, "%s", pubkey); + + /* test for correct signature */ + authenticated = 0; +@@ -185,9 +186,12 @@ userauth_pubkey(Authctxt *authctxt) + PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) { + authenticated = 1; ++ authctxt->last_details = pubkey; + /* Record the successful key to prevent reuse */ + auth2_record_userkey(authctxt, key); + key = NULL; /* Don't free below */ ++ } else { ++ free(pubkey); + } + buffer_free(&b); + free(sig); +@@ -228,7 +232,7 @@ done: + void + pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) + { +- char *fp, *extra; ++ char *extra, *pubkey; + va_list ap; + int i; + +@@ -238,27 +242,13 @@ pubkey_auth_info(Authctxt *authctxt, con + i = vasprintf(&extra, fmt, ap); + va_end(ap); + if (i < 0 || extra == NULL) +- fatal("%s: vasprintf failed", __func__); ++ fatal("%s: vasprintf failed", __func__); + } + +- if (key_is_cert(key)) { +- fp = sshkey_fingerprint(key->cert->signature_key, +- options.fingerprint_hash, SSH_FP_DEFAULT); +- auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", +- key_type(key), key->cert->key_id, +- (unsigned long long)key->cert->serial, +- key_type(key->cert->signature_key), +- fp == NULL ? "(null)" : fp, +- extra == NULL ? "" : ", ", extra == NULL ? "" : extra); +- free(fp); +- } else { +- fp = sshkey_fingerprint(key, options.fingerprint_hash, +- SSH_FP_DEFAULT); +- auth_info(authctxt, "%s %s%s%s", key_type(key), +- fp == NULL ? "(null)" : fp, +- extra == NULL ? "" : ", ", extra == NULL ? "" : extra); +- free(fp); +- } ++ pubkey = sshkey_format_oneline(key, options.fingerprint_hash); ++ auth_info(authctxt, "%s%s%s", pubkey, extra == NULL ? "" : ", ", ++ extra == NULL ? "" : extra); ++ free(pubkey); + free(extra); + } + +diff -up openssh-7.4p1/auth.h.expose-pam openssh-7.4p1/auth.h +--- openssh-7.4p1/auth.h.expose-pam 2016-12-23 15:40:26.782447870 +0100 ++++ openssh-7.4p1/auth.h 2016-12-23 15:40:26.819447876 +0100 +@@ -84,6 +84,9 @@ struct Authctxt { + + struct sshkey **prev_userkeys; + u_int nprev_userkeys; ++ ++ char *last_details; ++ char *auth_details; + }; + /* + * Every authentication method has to handle authentication requests for +diff -up openssh-7.4p1/auth-pam.c.expose-pam openssh-7.4p1/auth-pam.c +--- openssh-7.4p1/auth-pam.c.expose-pam 2016-12-23 15:40:26.731447862 +0100 ++++ openssh-7.4p1/auth-pam.c 2016-12-23 15:40:26.819447876 +0100 +@@ -688,6 +688,11 @@ sshpam_init_ctx(Authctxt *authctxt) + return (NULL); + } + ++ /* Notify PAM about any already successful auth methods */ ++ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMONLY && ++ authctxt->auth_details) ++ do_pam_putenv("SSH_USER_AUTH", authctxt->auth_details); ++ + ctxt = xcalloc(1, sizeof *ctxt); + + /* Start the authentication thread */ +diff -up openssh-7.4p1/gss-serv.c.expose-pam openssh-7.4p1/gss-serv.c +--- openssh-7.4p1/gss-serv.c.expose-pam 2016-12-23 15:40:26.808447874 +0100 ++++ openssh-7.4p1/gss-serv.c 2016-12-23 15:40:26.819447876 +0100 +@@ -441,6 +441,16 @@ ssh_gssapi_do_child(char ***envp, u_int + } + + /* Privileged */ ++char* ++ssh_gssapi_get_displayname(void) ++{ ++ if (gssapi_client.displayname.length != 0 && ++ gssapi_client.displayname.value != NULL) ++ return strdup((char *)gssapi_client.displayname.value); ++ return NULL; ++} ++ ++/* Privileged */ + int + ssh_gssapi_userok(char *user, struct passwd *pw) + { +diff -up openssh-7.4p1/monitor.c.expose-pam openssh-7.4p1/monitor.c +--- openssh-7.4p1/monitor.c.expose-pam 2016-12-23 15:40:26.794447872 +0100 ++++ openssh-7.4p1/monitor.c 2016-12-23 15:41:16.473455863 +0100 +@@ -300,6 +300,7 @@ monitor_child_preauth(Authctxt *_authctx + { + struct mon_table *ent; + int authenticated = 0, partial = 0; ++ char *prev_auth_details; + + debug3("preauth child monitor started"); + +@@ -330,6 +331,18 @@ monitor_child_preauth(Authctxt *_authctx + auth_submethod = NULL; + authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); + ++ if (authenticated) { ++ prev_auth_details = authctxt->auth_details; ++ xasprintf(&authctxt->auth_details, "%s%s%s%s%s", ++ prev_auth_details ? prev_auth_details : "", ++ prev_auth_details ? ", " : "", auth_method, ++ authctxt->last_details ? ": " : "", ++ authctxt->last_details ? authctxt->last_details : ""); ++ free(prev_auth_details); ++ } ++ free(authctxt->last_details); ++ authctxt->last_details = NULL; ++ + /* Special handling for multiple required authentications */ + if (options.num_auth_methods != 0) { + if (authenticated && +@@ -1417,6 +1430,10 @@ mm_answer_keyverify(int sock, Buffer *m) + debug3("%s: key %p signature %s", + __func__, key, (verified == 1) ? "verified" : "unverified"); + ++ if (verified == 1) ++ authctxt->last_details = sshkey_format_oneline(key, ++ options.fingerprint_hash); ++ + /* If auth was successful then record key to ensure it isn't reused */ + if (verified == 1 && key_blobtype == MM_USERKEY) + auth2_record_userkey(authctxt, key); +@@ -1860,6 +1877,9 @@ mm_answer_gss_userok(int sock, Buffer *m + + auth_method = "gssapi-with-mic"; + ++ if (authenticated) ++ authctxt->last_details = ssh_gssapi_get_displayname(); ++ + /* Monitor loop will terminate if authenticated */ + return (authenticated); + } +diff -up openssh-7.4p1/servconf.c.expose-pam openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.expose-pam 2016-12-23 15:40:26.810447875 +0100 ++++ openssh-7.4p1/servconf.c 2016-12-23 15:44:04.691482920 +0100 +@@ -171,6 +171,7 @@ initialize_server_options(ServerOptions + options->version_addendum = NULL; + options->use_kuserok = -1; + options->enable_k5users = -1; ++ options->expose_auth_methods = -1; + options->fingerprint_hash = -1; + options->disable_forwarding = -1; + } +@@ -354,6 +355,8 @@ fill_default_server_options(ServerOption + options->use_kuserok = 1; + if (options->enable_k5users == -1) + options->enable_k5users = 0; ++ if (options->expose_auth_methods == -1) ++ options->expose_auth_methods = EXPOSE_AUTHMETH_NEVER; + if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) + options->fwd_opts.streamlocal_bind_mask = 0177; + if (options->fwd_opts.streamlocal_bind_unlink == -1) +@@ -439,6 +442,7 @@ typedef enum { + sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, + sStreamLocalBindMask, sStreamLocalBindUnlink, + sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, ++ sExposeAuthenticationMethods, + sDeprecated, sIgnore, sUnsupported + } ServerOpCodes; + +@@ -595,6 +599,7 @@ static struct { + { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, + { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, + { "disableforwarding", sDisableForwarding, SSHCFG_ALL }, ++ { "exposeauthenticationmethods", sExposeAuthenticationMethods, SSHCFG_ALL }, + { NULL, sBadOption, 0 } + }; + +@@ -984,6 +989,12 @@ static const struct multistate multistat + { "local", FORWARD_LOCAL }, + { NULL, -1 } + }; ++static const struct multistate multistate_exposeauthmeth[] = { ++ { "never", EXPOSE_AUTHMETH_NEVER }, ++ { "pam-only", EXPOSE_AUTHMETH_PAMONLY }, ++ { "pam-and-env", EXPOSE_AUTHMETH_PAMENV }, ++ { NULL, -1} ++}; + + int + process_server_config_line(ServerOptions *options, char *line, +@@ -1902,6 +1913,11 @@ process_server_config_line(ServerOptions + options->fingerprint_hash = value; + break; + ++ case sExposeAuthenticationMethods: ++ intptr = &options->expose_auth_methods; ++ multistate_ptr = multistate_exposeauthmeth; ++ goto parse_multistate; ++ + case sDeprecated: + case sIgnore: + case sUnsupported: +@@ -2060,6 +2076,7 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(enable_k5users); + M_CP_INTOPT(rekey_limit); + M_CP_INTOPT(rekey_interval); ++ M_CP_INTOPT(expose_auth_methods); + + /* + * The bind_mask is a mode_t that may be unsigned, so we can't use +@@ -2176,6 +2193,8 @@ fmt_intarg(ServerOpCodes code, int val) + return fmt_multistate_int(val, multistate_tcpfwd); + case sFingerprintHash: + return ssh_digest_alg_name(val); ++ case sExposeAuthenticationMethods: ++ return fmt_multistate_int(val, multistate_exposeauthmeth); + default: + switch (val) { + case 0: +@@ -2356,6 +2375,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); + dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); + dump_cfg_fmtint(sGssEnablek5users, o->enable_k5users); ++ dump_cfg_fmtint(sExposeAuthenticationMethods, o->expose_auth_methods); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); + + /* string arguments */ +diff -up openssh-7.4p1/servconf.h.expose-pam openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.expose-pam 2016-12-23 15:40:26.810447875 +0100 ++++ openssh-7.4p1/servconf.h 2016-12-23 15:40:26.821447876 +0100 +@@ -48,6 +48,11 @@ + #define FORWARD_LOCAL (1<<1) + #define FORWARD_ALLOW (FORWARD_REMOTE|FORWARD_LOCAL) + ++/* Expose AuthenticationMethods */ ++#define EXPOSE_AUTHMETH_NEVER 0 ++#define EXPOSE_AUTHMETH_PAMONLY 1 ++#define EXPOSE_AUTHMETH_PAMENV 2 ++ + #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ + #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ + +@@ -195,6 +200,8 @@ typedef struct { + char *auth_methods[MAX_AUTH_METHODS]; + + int fingerprint_hash; ++ ++ int expose_auth_methods; /* EXPOSE_AUTHMETH_* above */ + } ServerOptions; + + /* Information about the incoming connection as used by Match */ +diff -up openssh-7.4p1/session.c.expose-pam openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.expose-pam 2016-12-23 15:40:26.794447872 +0100 ++++ openssh-7.4p1/session.c 2016-12-23 15:40:26.821447876 +0100 +@@ -997,6 +997,12 @@ copy_environment(char **source, char *** + } + *var_val++ = '\0'; + ++ if (options.expose_auth_methods < EXPOSE_AUTHMETH_PAMENV && ++ strcmp(var_name, "SSH_USER_AUTH") == 0) { ++ free(var_name); ++ continue; ++ } ++ + debug3("Copy environment: %s=%s", var_name, var_val); + child_set_env(env, envsize, var_name, var_val); + +@@ -1173,6 +1179,11 @@ do_setup_env(Session *s, const char *she + } + #endif /* USE_PAM */ + ++ if (options.expose_auth_methods >= EXPOSE_AUTHMETH_PAMENV && ++ s->authctxt->auth_details) ++ child_set_env(&env, &envsize, "SSH_USER_AUTH", ++ s->authctxt->auth_details); ++ + if (auth_sock_name != NULL) + child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, + auth_sock_name); +@@ -2561,6 +2572,9 @@ do_cleanup(Authctxt *authctxt) + if (authctxt == NULL) + return; + ++ free(authctxt->auth_details); ++ authctxt->auth_details = NULL; ++ + #ifdef USE_PAM + if (options.use_pam) { + sshpam_cleanup(); +diff -up openssh-7.4p1/ssh.1.expose-pam openssh-7.4p1/ssh.1 +--- openssh-7.4p1/ssh.1.expose-pam 2016-12-23 15:40:26.810447875 +0100 ++++ openssh-7.4p1/ssh.1 2016-12-23 15:40:26.822447877 +0100 +@@ -1421,6 +1421,10 @@ server IP address, and server port numbe + This variable contains the original command line if a forced command + is executed. + It can be used to extract the original arguments. ++.It Ev SSH_USER_AUTH ++This variable contains, for SSH2 only, a comma-separated list of authentication ++methods that were successfuly used to authenticate. When possible, these ++methods are extended with detailed information on the credential used. + .It Ev SSH_TTY + This is set to the name of the tty (path to the device) associated + with the current shell or command. +diff -up openssh-7.4p1/sshd_config.5.expose-pam openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.expose-pam 2016-12-23 15:40:26.822447877 +0100 ++++ openssh-7.4p1/sshd_config.5 2016-12-23 15:45:22.411495421 +0100 +@@ -570,6 +570,21 @@ Disables all forwarding features, includ + TCP and StreamLocal. + This option overrides all other forwarding-related options and may + simplify restricted configurations. ++.It Cm ExposeAuthenticationMethods ++When using SSH2, this option controls the exposure of the list of ++successful authentication methods to PAM during the authentication ++and to the shell environment via the ++.Cm SSH_USER_AUTH ++variable. See the description of this variable for more details. ++Valid options are: ++.Cm never ++(Do not expose successful authentication methods), ++.Cm pam-only ++(Only expose them to PAM during authentication, not afterwards), ++.Cm pam-and-env ++(Expose them to PAM and keep them in the shell environment). ++The default is ++.Cm never . + .It Cm FingerprintHash + Specifies the hash algorithm used when logging key fingerprints. + Valid options are: +diff -up openssh-7.4p1/ssh-gss.h.expose-pam openssh-7.4p1/ssh-gss.h +--- openssh-7.4p1/ssh-gss.h.expose-pam 2016-12-23 15:40:26.811447875 +0100 ++++ openssh-7.4p1/ssh-gss.h 2016-12-23 15:40:26.823447877 +0100 +@@ -159,6 +159,7 @@ int ssh_gssapi_server_check_mech(Gssctxt + const char *); + OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); + int ssh_gssapi_userok(char *name, struct passwd *); ++char* ssh_gssapi_get_displayname(void); + 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); +diff -up openssh-7.4p1/sshkey.c.expose-pam openssh-7.4p1/sshkey.c +--- openssh-7.4p1/sshkey.c.expose-pam 2016-12-23 15:40:26.777447869 +0100 ++++ openssh-7.4p1/sshkey.c 2016-12-23 15:40:26.823447877 +0100 +@@ -57,6 +57,7 @@ + #define SSHKEY_INTERNAL + #include "sshkey.h" + #include "match.h" ++#include "xmalloc.h" + + /* openssh private key file format */ + #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" +@@ -1191,6 +1192,30 @@ sshkey_fingerprint(const struct sshkey * + return retval; + } + ++char * ++sshkey_format_oneline(const struct sshkey *key, int dgst_alg) ++{ ++ char *fp, *result; ++ ++ if (sshkey_is_cert(key)) { ++ fp = sshkey_fingerprint(key->cert->signature_key, dgst_alg, ++ SSH_FP_DEFAULT); ++ xasprintf(&result, "%s ID %s (serial %llu) CA %s %s", ++ sshkey_type(key), key->cert->key_id, ++ (unsigned long long)key->cert->serial, ++ sshkey_type(key->cert->signature_key), ++ fp == NULL ? "(null)" : fp); ++ free(fp); ++ } else { ++ fp = sshkey_fingerprint(key, dgst_alg, SSH_FP_DEFAULT); ++ xasprintf(&result, "%s %s", sshkey_type(key), ++ fp == NULL ? "(null)" : fp); ++ free(fp); ++ } ++ ++ return result; ++} ++ + #ifdef WITH_SSH1 + /* + * Reads a multiple-precision integer in decimal from the buffer, and advances +diff -up openssh-7.4p1/sshkey.h.expose-pam openssh-7.4p1/sshkey.h +--- openssh-7.4p1/sshkey.h.expose-pam 2016-12-23 15:40:26.777447869 +0100 ++++ openssh-7.4p1/sshkey.h 2016-12-23 15:40:26.823447877 +0100 +@@ -124,6 +124,7 @@ char *sshkey_fingerprint(const struct s + int, enum sshkey_fp_rep); + int sshkey_fingerprint_raw(const struct sshkey *k, + int, u_char **retp, size_t *lenp); ++char *sshkey_format_oneline(const struct sshkey *k, int dgst_alg); + const char *sshkey_type(const struct sshkey *); + const char *sshkey_cert_type(const struct sshkey *); + int sshkey_write(const struct sshkey *, FILE *); diff --git a/SOURCES/openssh-7.4p1-fips.patch b/SOURCES/openssh-7.4p1-fips.patch new file mode 100644 index 0000000..38bd6f8 --- /dev/null +++ b/SOURCES/openssh-7.4p1-fips.patch @@ -0,0 +1,710 @@ +diff -up openssh-7.4p1/cipher.c.fips openssh-7.4p1/cipher.c +--- openssh-7.4p1/cipher.c.fips 2017-02-09 14:53:47.174347449 +0100 ++++ openssh-7.4p1/cipher.c 2017-02-09 14:53:47.182347441 +0100 +@@ -39,6 +39,8 @@ + + #include + ++#include ++ + #include + #include + #include +@@ -116,6 +118,20 @@ static const struct sshcipher ciphers[] + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } + }; + ++static const struct sshcipher fips_ciphers[] = { ++ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, ++ { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, ++ { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, ++ { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, ++ { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, ++ { "rijndael-cbc@lysator.liu.se", ++ SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, ++ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, ++ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, ++ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, ++ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } ++}; ++ + /*--*/ + + /* Returns a comma-separated list of supported ciphers. */ +@@ -126,7 +142,7 @@ cipher_alg_list(char sep, int auth_only) + size_t nlen, rlen = 0; + const struct sshcipher *c; + +- for (c = ciphers; c->name != NULL; c++) { ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) { + if (c->number != SSH_CIPHER_SSH2) + continue; + if (auth_only && c->auth_len == 0) +@@ -222,7 +238,7 @@ const struct sshcipher * + cipher_by_name(const char *name) + { + const struct sshcipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (strcmp(c->name, name) == 0) + return c; + return NULL; +@@ -232,7 +248,7 @@ const struct sshcipher * + cipher_by_number(int id) + { + const struct sshcipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (c->number == id) + return c; + return NULL; +@@ -273,7 +289,7 @@ cipher_number(const char *name) + const struct sshcipher *c; + if (name == NULL) + return -1; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = FIPS_mode() ? fips_ciphers : ciphers; c->name != NULL; c++) + if (strcasecmp(c->name, name) == 0) + return c->number; + return -1; +diff -up openssh-7.4p1/cipher-ctr.c.fips openssh-7.4p1/cipher-ctr.c +--- openssh-7.4p1/cipher-ctr.c.fips 2017-02-09 14:53:47.125347498 +0100 ++++ openssh-7.4p1/cipher-ctr.c 2017-02-09 14:53:47.182347441 +0100 +@@ -179,7 +179,8 @@ evp_aes_128_ctr(void) + aes_ctr.do_cipher = ssh_aes_ctr; + #ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | +- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; ++ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV | ++ EVP_CIPH_FLAG_FIPS; + #endif + return (&aes_ctr); + } +diff -up openssh-7.4p1/dh.h.fips openssh-7.4p1/dh.h +--- openssh-7.4p1/dh.h.fips 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/dh.h 2017-02-09 14:53:47.182347441 +0100 +@@ -51,6 +51,7 @@ u_int dh_estimate(int); + * Miniumum increased in light of DH precomputation attacks. + */ + #define DH_GRP_MIN 1024 ++#define DH_GRP_MIN_FIPS 2048 + #define DH_GRP_MAX 8192 + + /* +diff -up openssh-7.4p1/entropy.c.fips openssh-7.4p1/entropy.c +--- openssh-7.4p1/entropy.c.fips 2017-02-09 14:53:47.116347507 +0100 ++++ openssh-7.4p1/entropy.c 2017-02-09 14:53:47.182347441 +0100 +@@ -217,6 +217,9 @@ seed_rng(void) + fatal("OpenSSL version mismatch. Built against %lx, you " + "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + ++ /* clean the PRNG status when exiting the program */ ++ atexit(RAND_cleanup); ++ + #ifndef OPENSSL_PRNG_ONLY + if (RAND_status() == 1) { + debug3("RNG is ready, skipping seeding"); +diff -up openssh-7.4p1/kex.c.fips openssh-7.4p1/kex.c +--- openssh-7.4p1/kex.c.fips 2017-02-09 14:53:47.174347449 +0100 ++++ openssh-7.4p1/kex.c 2017-02-09 14:53:47.183347440 +0100 +@@ -35,6 +35,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + #endif + + #include "ssh2.h" +@@ -124,6 +125,28 @@ static const struct kexalg kexalgs[] = { + { NULL, -1, -1, -1}, + }; + ++static const struct kexalg kexalgs_fips[] = { ++ { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, ++ { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, ++ { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, ++ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++#ifdef HAVE_EVP_SHA256 ++ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, ++#endif ++#ifdef OPENSSL_HAS_ECC ++ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, ++ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, ++ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, ++ SSH_DIGEST_SHA384 }, ++# ifdef OPENSSL_HAS_NISTP521 ++ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, ++ SSH_DIGEST_SHA512 }, ++# endif ++#endif ++ { NULL, -1, -1, -1}, ++}; ++ + char * + kex_alg_list(char sep) + { +@@ -151,7 +169,7 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = (FIPS_mode() ? kexalgs_fips : kexalgs); k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; + #ifdef GSSAPI +@@ -177,7 +195,10 @@ kex_names_valid(const char *names) + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (kex_alg_by_name(p) == NULL) { +- error("Unsupported KEX algorithm \"%.100s\"", p); ++ if (FIPS_mode()) ++ error("\"%.100s\" is not allowed in FIPS mode", p); ++ else ++ error("Unsupported KEX algorithm \"%.100s\"", p); + free(s); + return 0; + } +diff -up openssh-7.4p1/kexgexc.c.fips openssh-7.4p1/kexgexc.c +--- openssh-7.4p1/kexgexc.c.fips 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/kexgexc.c 2017-02-09 14:53:47.183347440 +0100 +@@ -28,6 +28,7 @@ + + #ifdef WITH_OPENSSL + ++#include + #include + + #include +@@ -63,7 +64,7 @@ kexgex_client(struct ssh *ssh) + + nbits = dh_estimate(kex->dh_need * 8); + +- kex->min = DH_GRP_MIN; ++ kex->min = FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN; + kex->max = DH_GRP_MAX; + kex->nbits = nbits; + if (datafellows & SSH_BUG_DHGEX_LARGE) +diff -up openssh-7.4p1/kexgexs.c.fips openssh-7.4p1/kexgexs.c +--- openssh-7.4p1/kexgexs.c.fips 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/kexgexs.c 2017-02-09 14:53:47.183347440 +0100 +@@ -83,9 +83,9 @@ input_kex_dh_gex_request(int type, u_int + kex->nbits = nbits; + kex->min = min; + kex->max = max; +- min = MAXIMUM(DH_GRP_MIN, min); ++ min = MAXIMUM(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, min); + max = MINIMUM(DH_GRP_MAX, max); +- nbits = MAXIMUM(DH_GRP_MIN, nbits); ++ nbits = MAXIMUM(FIPS_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN, nbits); + nbits = MINIMUM(DH_GRP_MAX, nbits); + + if (kex->max < kex->min || kex->nbits < kex->min || +diff -up openssh-7.4p1/mac.c.fips openssh-7.4p1/mac.c +--- openssh-7.4p1/mac.c.fips 2017-02-09 14:53:47.175347448 +0100 ++++ openssh-7.4p1/mac.c 2017-02-09 14:53:47.183347440 +0100 +@@ -27,6 +27,8 @@ + + #include + ++#include ++ + #include + #include + +@@ -54,7 +56,7 @@ struct macalg { + int etm; /* Encrypt-then-MAC */ + }; + +-static const struct macalg macs[] = { ++static const struct macalg all_macs[] = { + /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ + { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, + { "hmac-sha1-96", SSH_DIGEST, SSH_DIGEST_SHA1, 96, 0, 0, 0 }, +@@ -89,6 +91,24 @@ static const struct macalg macs[] = { + { NULL, 0, 0, 0, 0, 0, 0 } + }; + ++static const struct macalg fips_macs[] = { ++ /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ ++ { "hmac-sha1", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 0 }, ++#ifdef HAVE_EVP_SHA256 ++ { "hmac-sha2-256", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 0 }, ++ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, ++#endif ++ ++ /* Encrypt-then-MAC variants */ ++ { "hmac-sha1-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA1, 0, 0, 0, 1 }, ++#ifdef HAVE_EVP_SHA256 ++ { "hmac-sha2-256-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA256, 0, 0, 0, 1 }, ++ { "hmac-sha2-512-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 1 }, ++#endif ++ ++ { NULL, 0, 0, 0, 0, 0, 0 } ++}; ++ + /* Returns a list of supported MACs separated by the specified char. */ + char * + mac_alg_list(char sep) +@@ -97,7 +117,7 @@ mac_alg_list(char sep) + size_t nlen, rlen = 0; + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(m->name); +@@ -136,7 +156,7 @@ mac_setup(struct sshmac *mac, char *name + { + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = FIPS_mode() ? fips_macs : all_macs; m->name != NULL; m++) { + if (strcmp(name, m->name) != 0) + continue; + if (mac != NULL) +diff -up openssh-7.4p1/Makefile.in.fips openssh-7.4p1/Makefile.in +--- openssh-7.4p1/Makefile.in.fips 2017-02-09 14:53:47.175347448 +0100 ++++ openssh-7.4p1/Makefile.in 2017-02-09 14:53:47.184347440 +0100 +@@ -168,25 +168,25 @@ libssh.a: $(LIBSSH_OBJS) + $(RANLIB) $@ + + ssh$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHOBJS) +- $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHLIBS) $(LIBS) $(GSSLIBS) ++ $(LD) -o $@ $(SSHOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(SSHLIBS) $(LIBS) $(GSSLIBS) + + sshd$(EXEEXT): libssh.a $(LIBCOMPAT) $(SSHDOBJS) +- $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) ++ $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat -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) + + ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-add.o +- $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-add.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-agent$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-agent.o ssh-pkcs11-client.o +- $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ ssh-agent.o ssh-pkcs11-client.o $(LDFLAGS) -lssh -lopenbsd-compat -lfipscheck $(LIBS) + + ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o +- $(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-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) +@@ -205,7 +205,7 @@ ssh-cavs$(EXEEXT): $(LIBCOMPAT) libssh.a + $(LD) -o $@ ssh-cavs.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o +- $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) +diff -up openssh-7.4p1/myproposal.h.fips openssh-7.4p1/myproposal.h +--- openssh-7.4p1/myproposal.h.fips 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/myproposal.h 2017-02-09 14:53:47.184347440 +0100 +@@ -144,6 +144,37 @@ + + #define KEX_CLIENT_MAC KEX_SERVER_MAC + ++#define KEX_FIPS_ENCRYPT \ ++ "aes128-ctr,aes192-ctr,aes256-ctr," \ ++ "aes128-cbc,3des-cbc," \ ++ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" ++#ifdef HAVE_EVP_SHA256 ++# define KEX_DEFAULT_KEX_FIPS \ ++ KEX_ECDH_METHODS \ ++ KEX_SHA2_METHODS \ ++ "diffie-hellman-group14-sha256" ++# define KEX_FIPS_MAC \ ++ "hmac-sha1," \ ++ "hmac-sha2-256," \ ++ "hmac-sha2-512," \ ++ "hmac-sha1-etm@openssh.com," \ ++ "hmac-sha2-256-etm@openssh.com," \ ++ "hmac-sha2-512-etm@openssh.com" ++#else ++# ifdef OPENSSL_HAS_NISTP521 ++# define KEX_DEFAULT_KEX_FIPS \ ++ "ecdh-sha2-nistp256," \ ++ "ecdh-sha2-nistp384," \ ++ "ecdh-sha2-nistp521" ++# else ++# define KEX_DEFAULT_KEX_FIPS \ ++ "ecdh-sha2-nistp256," \ ++ "ecdh-sha2-nistp384" ++# endif ++#define KEX_FIPS_MAC \ ++ "hmac-sha1" ++#endif ++ + #else /* WITH_OPENSSL */ + + #define KEX_SERVER_KEX \ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.fips 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.fips 2017-02-09 14:53:47.184347440 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2017-02-09 14:55:25.123250447 +0100 +@@ -102,7 +102,8 @@ pamsshagentauth_check_authkeys_file(FILE + found_key = 1; + logit("matching key found: file/command %s, line %lu", file, + linenum); +- fp = key_fingerprint(found, SSH_FP_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", + key_type(found), fp); + free(fp); +diff -up openssh-7.4p1/readconf.c.fips openssh-7.4p1/readconf.c +--- openssh-7.4p1/readconf.c.fips 2017-02-09 14:53:47.185347438 +0100 ++++ openssh-7.4p1/readconf.c 2017-02-09 14:56:24.840191308 +0100 +@@ -2104,9 +2104,12 @@ 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 || ++ 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(KEX_DEFAULT_PK_ALG, + &options->hostbased_key_types) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, +diff -up openssh-7.4p1/sandbox-seccomp-filter.c.fips openssh-7.4p1/sandbox-seccomp-filter.c +--- openssh-7.4p1/sandbox-seccomp-filter.c.fips 2017-02-09 14:53:47.177347446 +0100 ++++ openssh-7.4p1/sandbox-seccomp-filter.c 2017-02-09 14:53:47.185347438 +0100 +@@ -118,6 +118,9 @@ static const struct sock_filter preauth_ + #ifdef __NR_open + SC_DENY(open, EACCES), + #endif ++#ifdef __NR_socket ++ SC_DENY(socket, EACCES), ++#endif + #ifdef __NR_openat + SC_DENY(openat, EACCES), + #endif +diff -up openssh-7.4p1/servconf.c.fips openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.fips 2017-02-09 14:53:47.169347454 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 14:57:24.957131771 +0100 +@@ -184,9 +184,12 @@ 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 || ++ 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(KEX_DEFAULT_PK_ALG, + &o->hostkeyalgorithms) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, +@@ -2386,8 +2389,10 @@ dump_config(ServerOptions *o) + /* string arguments */ + dump_cfg_string(sPidFile, o->pid_file); + dump_cfg_string(sXAuthLocation, o->xauth_location); +- dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : KEX_SERVER_ENCRYPT); +- dump_cfg_string(sMacs, o->macs ? o->macs : KEX_SERVER_MAC); ++ dump_cfg_string(sCiphers, o->ciphers ? o->ciphers : FIPS_mode() ++ ? KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT); ++ dump_cfg_string(sMacs, o->macs ? o->macs : FIPS_mode() ++ ? KEX_FIPS_MAC : KEX_SERVER_MAC); + dump_cfg_string(sBanner, o->banner == NULL ? "none" : o->banner); + dump_cfg_string(sForceCommand, o->adm_forced_command); + dump_cfg_string(sChrootDirectory, o->chroot_directory); +@@ -2402,8 +2407,8 @@ dump_config(ServerOptions *o) + dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command); + dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user); + dump_cfg_string(sHostKeyAgent, o->host_key_agent); +- dump_cfg_string(sKexAlgorithms, +- o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); ++ dump_cfg_string(sKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : ++ FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX); + dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ? + o->hostbased_key_types : KEX_DEFAULT_PK_ALG); + dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms ? +diff -up openssh-7.4p1/ssh.c.fips openssh-7.4p1/ssh.c +--- openssh-7.4p1/ssh.c.fips 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/ssh.c 2017-02-09 14:53:47.185347438 +0100 +@@ -76,6 +76,8 @@ + #include + #include + #endif ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + #include "openbsd-compat/sys-queue.h" + +@@ -530,6 +532,14 @@ main(int ac, char **av) + sanitise_stdfd(); + + __progname = ssh_get_progname(av[0]); ++ SSLeay_add_all_algorithms(); ++ if (access("/etc/system-fips", F_OK) == 0) ++ if (! FIPSCHECK_verify(NULL, NULL)){ ++ if (FIPS_mode()) ++ fatal("FIPS integrity verification test failed."); ++ else ++ logit("FIPS integrity verification test failed."); ++ } + + #ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ +@@ -609,6 +619,9 @@ main(int ac, char **av) + "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { + switch (opt) { + case '1': ++ if (FIPS_mode()) { ++ fatal("Protocol 1 not allowed in the FIPS mode."); ++ } + options.protocol = SSH_PROTO_1; + break; + case '2': +@@ -964,7 +977,6 @@ main(int ac, char **av) + host_arg = xstrdup(host); + + #ifdef WITH_OPENSSL +- OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + #endif + +@@ -1175,6 +1187,10 @@ main(int ac, char **av) + + seed_rng(); + ++ if (FIPS_mode()) { ++ logit("FIPS mode initialized"); ++ } ++ + if (options.user == NULL) + options.user = xstrdup(pw->pw_name); + +@@ -1263,6 +1279,12 @@ main(int ac, char **av) + + timeout_ms = options.connection_timeout * 1000; + ++ if (FIPS_mode()) { ++ options.protocol &= SSH_PROTO_2; ++ if (options.protocol == 0) ++ fatal("Protocol 2 disabled by configuration but required in the FIPS mode."); ++ } ++ + /* Open a connection to the remote host. */ + if (ssh_connect(host, addrs, &hostaddr, options.port, + options.address_family, options.connection_attempts, +diff -up openssh-7.4p1/sshconnect2.c.fips openssh-7.4p1/sshconnect2.c +--- openssh-7.4p1/sshconnect2.c.fips 2017-02-09 14:53:47.162347461 +0100 ++++ openssh-7.4p1/sshconnect2.c 2017-02-09 14:53:47.186347437 +0100 +@@ -44,6 +44,8 @@ + #include + #endif + ++#include ++ + #include "openbsd-compat/sys-queue.h" + + #include "xmalloc.h" +@@ -172,21 +174,26 @@ ssh_kex2(char *host, struct sockaddr *ho + + #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, options.gss_kex_algorithms); +- if (gss) { +- debug("Offering GSSAPI proposal: %s", gss); +- xasprintf(&options.kex_algorithms, +- "%s,%s", gss, orig); ++ if (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ /* Add the GSSAPI mechanisms currently supported on this ++ * client to the key exchange algorithm proposal */ ++ orig = options.kex_algorithms; ++ ++ if (options.gss_trust_dns) ++ gss_host = (char *)get_canonical_hostname(active_state, 1); ++ else ++ gss_host = host; ++ ++ gss = ssh_gssapi_client_mechanisms(gss_host, ++ options.gss_client_identity, options.gss_kex_algorithms); ++ if (gss) { ++ debug("Offering GSSAPI proposal: %s", gss); ++ xasprintf(&options.kex_algorithms, ++ "%s,%s", gss, orig); ++ } + } + } + #endif +diff -up openssh-7.4p1/sshd.c.fips openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.fips 2017-02-09 14:53:47.178347445 +0100 ++++ openssh-7.4p1/sshd.c 2017-02-09 14:53:47.186347437 +0100 +@@ -66,6 +66,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -77,6 +78,8 @@ + #include + #include + #include ++#include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -1471,6 +1474,18 @@ main(int ac, char **av) + #endif + __progname = ssh_get_progname(av[0]); + ++ SSLeay_add_all_algorithms(); ++ if (access("/etc/system-fips", F_OK) == 0) ++ if (! FIPSCHECK_verify(NULL, NULL)) { ++ openlog(__progname, LOG_PID, LOG_AUTHPRIV); ++ if (FIPS_mode()) { ++ syslog(LOG_CRIT, "FIPS integrity verification test failed."); ++ cleanup_exit(255); ++ } ++ else ++ syslog(LOG_INFO, "FIPS integrity verification test failed."); ++ closelog(); ++ } + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = ac; + rexec_argc = ac; +@@ -1619,7 +1634,7 @@ main(int ac, char **av) + else + closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); + +-#ifdef WITH_OPENSSL ++#if 0 /* FIPS */ + OpenSSL_add_all_algorithms(); + #endif + +@@ -1928,6 +1943,10 @@ main(int ac, char **av) + /* Reinitialize the log (because of the fork above). */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + ++ if (FIPS_mode()) { ++ logit("FIPS mode initialized"); ++ } ++ + /* Chdir to the root directory so that the current disk can be + unmounted if desired. */ + if (chdir("/") == -1) +@@ -2282,10 +2301,14 @@ do_ssh2_kex(void) + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) + orig = NULL; + +- if (options.gss_keyex) +- gss = ssh_gssapi_server_mechanisms(); +- else +- gss = NULL; ++ if (options.gss_keyex) { ++ if (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ gss = ssh_gssapi_server_mechanisms(); ++ } ++ } + + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); +diff -up openssh-7.4p1/sshkey.c.fips openssh-7.4p1/sshkey.c +--- openssh-7.4p1/sshkey.c.fips 2017-02-09 14:53:47.179347444 +0100 ++++ openssh-7.4p1/sshkey.c 2017-02-09 14:58:02.117094971 +0100 +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #endif + + #include "crypto_api.h" +@@ -57,6 +58,7 @@ + #include "sshkey.h" + #include "match.h" + #include "xmalloc.h" ++#include "log.h" + + /* openssh private key file format */ + #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" +@@ -1555,6 +1557,8 @@ rsa_generate_private_key(u_int bits, RSA + } + if (!BN_set_word(f4, RSA_F4) || + !RSA_generate_key_ex(private, bits, f4, NULL)) { ++ if (FIPS_mode()) ++ logit("%s: the key length might be unsupported by FIPS mode approved key generation method", __func__); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -3921,8 +3925,11 @@ sshkey_parse_private_fileblob_type(struc + switch (type) { + #ifdef WITH_SSH1 + case KEY_RSA1: +- return sshkey_parse_private_rsa1(blob, passphrase, +- keyp, commentp); ++ if (! FIPS_mode()) ++ return sshkey_parse_private_rsa1(blob, passphrase, ++ keyp, commentp); ++ error("%s: cannot parse rsa1 key in FIPS mode", __func__); ++ return SSH_ERR_KEY_TYPE_UNKNOWN; + #endif /* WITH_SSH1 */ + #ifdef WITH_OPENSSL + case KEY_DSA: +@@ -3961,8 +3968,9 @@ sshkey_parse_private_fileblob(struct ssh + #ifdef WITH_SSH1 + /* it's a SSH v1 key if the public key part is readable */ + if (sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL) == 0) { +- return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1, +- passphrase, keyp, commentp); ++ if (!FIPS_mode()) ++ return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1, ++ passphrase, keyp, commentp); + } + #endif /* WITH_SSH1 */ + return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, +diff -up openssh-7.4p1/ssh-keygen.c.fips openssh-7.4p1/ssh-keygen.c +--- openssh-7.4p1/ssh-keygen.c.fips 2017-05-22 13:50:06.731776762 +0200 ++++ openssh-7.4p1/ssh-keygen.c 2017-05-22 13:50:11.843773909 +0200 +@@ -215,6 +215,12 @@ type_bits_valid(int type, const char *na + OPENSSL_DSA_MAX_MODULUS_BITS : OPENSSL_RSA_MAX_MODULUS_BITS; + if (*bitsp > maxbits) + fatal("key bits exceeds maximum %d", maxbits); ++ if (FIPS_mode()) { ++ if (type == KEY_DSA) ++ fatal("DSA keys are not allowed in FIPS mode"); ++ if (type == KEY_ED25519) ++ fatal("ED25519 keys are not allowed in FIPS mode"); ++ } + if (type == KEY_DSA && *bitsp != 1024) + fatal("DSA keys must be 1024 bits"); + else if (type != KEY_ECDSA && type != KEY_ED25519 && *bitsp < 1024) diff --git a/SOURCES/openssh-7.4p1-gssKexAlgorithms.patch b/SOURCES/openssh-7.4p1-gssKexAlgorithms.patch new file mode 100644 index 0000000..657610d --- /dev/null +++ b/SOURCES/openssh-7.4p1-gssKexAlgorithms.patch @@ -0,0 +1,410 @@ +diff -up openssh-7.4p1/gss-genr.c.gsskexalg openssh-7.4p1/gss-genr.c +--- openssh-7.4p1/gss-genr.c.gsskexalg 2017-02-09 10:46:50.417893132 +0100 ++++ openssh-7.4p1/gss-genr.c 2017-02-09 10:46:50.448893107 +0100 +@@ -77,7 +77,8 @@ ssh_gssapi_oid_table_ok() { + */ + + char * +-ssh_gssapi_client_mechanisms(const char *host, const char *client) { ++ssh_gssapi_client_mechanisms(const char *host, const char *client, ++ const char *kex) { + gss_OID_set gss_supported; + OM_uint32 min_status; + +@@ -85,12 +86,12 @@ ssh_gssapi_client_mechanisms(const char + return NULL; + + return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, +- host, client)); ++ host, client, kex)); + } + + char * + ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, +- const char *host, const char *client) { ++ const char *host, const char *client, const char *kex) { + Buffer buf; + size_t i; + int oidpos, enclen; +@@ -99,6 +100,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup + char deroid[2]; + const EVP_MD *evp_md = EVP_md5(); + EVP_MD_CTX md; ++ char *s, *cp, *p; + + if (gss_enc2oid != NULL) { + for (i = 0; gss_enc2oid[i].encoded != NULL; i++) +@@ -112,6 +114,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup + buffer_init(&buf); + + oidpos = 0; ++ s = cp = strdup(kex); + for (i = 0; i < gss_supported->count; i++) { + if (gss_supported->elements[i].length < 128 && + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { +@@ -130,26 +133,22 @@ 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, ','); +- +- 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); ++ 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); ++ } + + gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]); + gss_enc2oid[oidpos].encoded = encoded; + oidpos++; + } + } ++ free(s); + gss_enc2oid[oidpos].oid = NULL; + gss_enc2oid[oidpos].encoded = NULL; + +diff -up openssh-7.4p1/gss-serv.c.gsskexalg openssh-7.4p1/gss-serv.c +--- openssh-7.4p1/gss-serv.c.gsskexalg 2017-02-09 10:46:50.449893106 +0100 ++++ openssh-7.4p1/gss-serv.c 2017-02-09 10:55:12.189422901 +0100 +@@ -149,7 +149,7 @@ 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)); ++ &ssh_gssapi_server_check_mech, NULL, NULL, options.gss_kex_algorithms)); + } + + /* Unprivileged */ +diff -up openssh-7.4p1/kex.c.gsskexalg openssh-7.4p1/kex.c +--- openssh-7.4p1/kex.c.gsskexalg 2017-02-09 10:46:50.449893106 +0100 ++++ openssh-7.4p1/kex.c 2017-02-09 10:55:44.008393539 +0100 +@@ -248,6 +248,29 @@ kex_assemble_names(const char *def, char + return 0; + } + ++/* Validate GSS KEX method name list */ ++int ++gss_kex_names_valid(const char *names) ++{ ++ char *s, *cp, *p; ++ ++ if (names == NULL || *names == '\0') ++ return 0; ++ s = cp = strdup(names); ++ for ((p = strsep(&cp, ",")); p && *p != '\0'; ++ (p = strsep(&cp, ","))) { ++ if (strncmp(p, "gss-", 4) != 0 ++ || kex_alg_by_name(p) == NULL) { ++ error("Unsupported KEX algorithm \"%.100s\"", p); ++ free(s); ++ return 0; ++ } ++ } ++ debug3("gss kex names ok: [%s]", names); ++ free(s); ++ return 1; ++} ++ + /* put algorithm proposal into buffer */ + int + kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) +diff -up openssh-7.4p1/kex.h.gsskexalg openssh-7.4p1/kex.h +--- openssh-7.4p1/kex.h.gsskexalg 2017-02-09 10:46:50.452893104 +0100 ++++ openssh-7.4p1/kex.h 2017-02-09 11:02:35.313012903 +0100 +@@ -179,6 +179,7 @@ struct kex { + char *kex_alg_list(char); + char *kex_names_cat(const char *, const char *); + int kex_assemble_names(const char *, char **); ++int gss_kex_names_valid(const char *); + + int kex_new(struct ssh *, char *[PROPOSAL_MAX], struct kex **); + int kex_setup(struct ssh *, char *[PROPOSAL_MAX]); +diff -up openssh-7.4p1/readconf.c.gsskexalg openssh-7.4p1/readconf.c +--- openssh-7.4p1/readconf.c.gsskexalg 2017-02-09 10:46:50.420893129 +0100 ++++ openssh-7.4p1/readconf.c 2017-02-09 10:56:06.759372540 +0100 +@@ -64,6 +64,7 @@ + #include "uidswap.h" + #include "myproposal.h" + #include "digest.h" ++#include "ssh-gss.h" + + /* Format of the configuration file: + +@@ -161,7 +162,7 @@ typedef enum { + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, + oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, +- oGssServerIdentity, ++ oGssServerIdentity, oGssKexAlgorithms, + oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oSendEnv, oControlPath, oControlMaster, oControlPersist, + oHashKnownHosts, +@@ -213,6 +214,7 @@ static struct { + { "gssapiclientidentity", oGssClientIdentity }, + { "gssapiserveridentity", oGssServerIdentity }, + { "gssapirenewalforcesrekey", oGssRenewalRekey }, ++ { "gssapikexalgorithms", oGssKexAlgorithms }, + #else + { "gssapiauthentication", oUnsupported }, + { "gssapikeyexchange", oUnsupported }, +@@ -220,6 +222,7 @@ static struct { + { "gssapitrustdns", oUnsupported }, + { "gssapiclientidentity", oUnsupported }, + { "gssapirenewalforcesrekey", oUnsupported }, ++ { "gssapikexalgorithms", oUnsupported }, + #endif + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, +@@ -996,6 +999,18 @@ parse_time: + intptr = &options->gss_renewal_rekey; + goto parse_flag; + ++ case oGssKexAlgorithms: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", ++ filename, linenum); ++ if (!gss_kex_names_valid(arg)) ++ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", ++ filename, linenum, arg ? arg : ""); ++ if (*activep && options->gss_kex_algorithms == NULL) ++ options->gss_kex_algorithms = strdup(arg); ++ break; ++ + case oBatchMode: + intptr = &options->batch_mode; + goto parse_flag; +@@ -1813,6 +1828,7 @@ initialize_options(Options * options) + options->gss_renewal_rekey = -1; + options->gss_client_identity = NULL; + options->gss_server_identity = NULL; ++ options->gss_kex_algorithms = NULL; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->kbd_interactive_devices = NULL; +@@ -1964,6 +1980,10 @@ fill_default_options(Options * options) + options->gss_trust_dns = 0; + if (options->gss_renewal_rekey == -1) + options->gss_renewal_rekey = 0; ++#ifdef GSSAPI ++ if (options->gss_kex_algorithms == NULL) ++ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); ++#endif + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) +diff -up openssh-7.4p1/readconf.h.gsskexalg openssh-7.4p1/readconf.h +--- openssh-7.4p1/readconf.h.gsskexalg 2017-02-09 10:46:50.420893129 +0100 ++++ openssh-7.4p1/readconf.h 2017-02-09 10:46:50.450893106 +0100 +@@ -51,6 +51,7 @@ typedef struct { + int gss_renewal_rekey; /* Credential renewal forces rekey */ + char *gss_client_identity; /* Principal to initiate GSSAPI with */ + char *gss_server_identity; /* GSSAPI target principal */ ++ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ + int password_authentication; /* Try password + * authentication. */ + int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ +diff -up openssh-7.4p1/servconf.c.gsskexalg openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.gsskexalg 2017-02-09 10:46:50.446893109 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 10:57:15.784309297 +0100 +@@ -57,6 +57,7 @@ + #include "auth.h" + #include "myproposal.h" + #include "digest.h" ++#include "ssh-gss.h" + + static void add_listen_addr(ServerOptions *, char *, int); + static void add_one_listen_addr(ServerOptions *, char *, int); +@@ -117,6 +117,7 @@ initialize_server_options(ServerOptions + options->gss_cleanup_creds = -1; + options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; ++ options->gss_kex_algorithms = NULL; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->challenge_response_authentication = -1; +@@ -280,6 +281,10 @@ fill_default_server_options(ServerOption + options->gss_strict_acceptor = 0; + if (options->gss_store_rekey == -1) + options->gss_store_rekey = 0; ++#ifdef GSSAPI ++ if (options->gss_kex_algorithms == NULL) ++ options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); ++#endif + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) +@@ -422,7 +425,7 @@ typedef enum { + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, +- sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, ++ sGssKeyEx, sGssStoreRekey, sGssKexAlgorithms, sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sHostCertificate, +@@ -501,6 +504,7 @@ static struct { + { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, ++ { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, +@@ -508,6 +512,7 @@ static struct { + { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + { "gssapienablek5users", sUnsupported, SSHCFG_ALL }, ++ { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, +@@ -1249,6 +1254,18 @@ process_server_config_line(ServerOptions + intptr = &options->gss_store_rekey; + goto parse_flag; + ++ case sGssKexAlgorithms: ++ arg = strdelim(&cp); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", ++ filename, linenum); ++ if (!gss_kex_names_valid(arg)) ++ fatal("%.200s line %d: Bad GSSAPI KexAlgorithms '%s'.", ++ filename, linenum, arg ? arg : ""); ++ if (*activep && options->gss_kex_algorithms == NULL) ++ options->gss_kex_algorithms = strdup(arg); ++ break; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -2304,6 +2321,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); ++ dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, +diff -up openssh-7.4p1/servconf.h.gsskexalg openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.gsskexalg 2017-02-09 10:46:50.450893106 +0100 ++++ openssh-7.4p1/servconf.h 2017-02-09 10:57:33.717292870 +0100 +@@ -116,6 +116,7 @@ typedef struct { + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ + int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ + int gss_store_rekey; ++ char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ + int password_authentication; /* If true, permit password + * authentication. */ + int kbd_interactive_authentication; /* If true, permit */ +diff -up openssh-7.4p1/ssh.1.gsskexalg openssh-7.4p1/ssh.1 +--- openssh-7.4p1/ssh.1.gsskexalg 2017-02-09 10:46:50.443893111 +0100 ++++ openssh-7.4p1/ssh.1 2017-02-09 10:46:50.451893105 +0100 +@@ -517,6 +517,7 @@ For full details of the options listed b + .It GSSAPIDelegateCredentials + .It GSSAPIRenewalForcesRekey + .It GSSAPITrustDns ++.It GSSAPIKexAlgorithms + .It HashKnownHosts + .It Host + .It HostbasedAuthentication +diff -up openssh-7.4p1/ssh_config.5.gsskexalg openssh-7.4p1/ssh_config.5 +--- openssh-7.4p1/ssh_config.5.gsskexalg 2017-02-09 10:46:50.452893104 +0100 ++++ openssh-7.4p1/ssh_config.5 2017-02-09 11:00:39.053122745 +0100 +@@ -782,6 +782,18 @@ the name of the host being connected to. + command line will be passed untouched to the GSSAPI library. + The default is + .Dq no . ++.It Cm GSSAPIKexAlgorithms ++The list of key exchange algorithms that are offered for GSSAPI ++key exchange. Possible values are ++.Bd -literal -offset 3n ++gss-gex-sha1-, ++gss-group1-sha1-, ++gss-group14-sha1- ++.Ed ++.Pp ++The default is ++.Dq gss-gex-sha1-,gss-group1-sha1-,gss-group14-sha1- . ++This option only applies to protocol version 2 connections using GSSAPI. + .It Cm HashKnownHosts + Indicates that + .Xr ssh 1 +diff -up openssh-7.4p1/sshconnect2.c.gsskexalg openssh-7.4p1/sshconnect2.c +--- openssh-7.4p1/sshconnect2.c.gsskexalg 2017-02-09 10:46:50.451893105 +0100 ++++ openssh-7.4p1/sshconnect2.c 2017-02-09 10:58:08.533260973 +0100 +@@ -181,7 +181,8 @@ ssh_kex2(char *host, struct sockaddr *ho + else + gss_host = host; + +- gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity); ++ gss = ssh_gssapi_client_mechanisms(gss_host, ++ options.gss_client_identity, options.gss_kex_algorithms); + if (gss) { + debug("Offering GSSAPI proposal: %s", gss); + xasprintf(&options.kex_algorithms, +diff -up openssh-7.4p1/sshd_config.5.gsskexalg openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.gsskexalg 2017-02-09 10:46:50.452893104 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-09 11:01:55.141050861 +0100 +@@ -666,6 +666,18 @@ Controls whether the user's GSSAPI crede + 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 GSSAPIKexAlgorithms ++The list of key exchange algorithms that are accepted by GSSAPI ++key exchange. Possible values are ++.Bd -literal -offset 3n ++gss-gex-sha1-, ++gss-group1-sha1-, ++gss-group14-sha1- ++.Ed ++.Pp ++The default is ++.Dq gss-gex-sha1-,gss-group1-sha1-,gss-group14-sha1- . ++This option only applies to protocol version 2 connections using GSSAPI. + .It Cm HostbasedAcceptedKeyTypes + Specifies the key types that will be accepted for hostbased authentication + as a comma-separated pattern list. +diff -up openssh-7.4p1/ssh-gss.h.gsskexalg openssh-7.4p1/ssh-gss.h +--- openssh-7.4p1/ssh-gss.h.gsskexalg 2017-02-09 10:46:50.425893125 +0100 ++++ openssh-7.4p1/ssh-gss.h 2017-02-09 10:46:50.451893105 +0100 +@@ -76,6 +76,11 @@ extern char **k5users_allowed_cmds; + #define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" + #define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" + ++#define GSS_KEX_DEFAULT_KEX \ ++ KEX_GSS_GEX_SHA1_ID "," \ ++ KEX_GSS_GRP1_SHA1_ID "," \ ++ KEX_GSS_GRP14_SHA1_ID ++ + typedef struct { + char *filename; + char *envvar; +@@ -147,9 +152,9 @@ int ssh_gssapi_credentials_updated(Gssct + /* 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_client_mechanisms(const char *, const char *, const char *); + char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, +- const char *); ++ const char *, const char *); + gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); + int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, + const char *); diff --git a/SOURCES/openssh-7.4p1-gsskex.patch b/SOURCES/openssh-7.4p1-gsskex.patch new file mode 100644 index 0000000..0ab2e04 --- /dev/null +++ b/SOURCES/openssh-7.4p1-gsskex.patch @@ -0,0 +1,3000 @@ +diff -up openssh-7.4p1/auth2.c.gsskex openssh-7.4p1/auth2.c +--- openssh-7.4p1/auth2.c.gsskex 2016-12-23 13:38:53.685300997 +0100 ++++ openssh-7.4p1/auth2.c 2016-12-23 13:38:53.725301005 +0100 +@@ -70,6 +70,7 @@ extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif + +@@ -77,6 +78,7 @@ Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + &method_passwd, +diff -up openssh-7.4p1/auth2-gss.c.gsskex openssh-7.4p1/auth2-gss.c +--- openssh-7.4p1/auth2-gss.c.gsskex 2016-12-23 13:38:53.685300997 +0100 ++++ openssh-7.4p1/auth2-gss.c 2016-12-23 13:38:53.725301005 +0100 +@@ -31,6 +31,7 @@ + #include + + #include ++#include + + #include "xmalloc.h" + #include "key.h" +@@ -53,6 +54,40 @@ static int input_gssapi_mic(int type, u_ + static int input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); + static int input_gssapi_errtok(int, u_int32_t, void *); + ++/* ++ * The 'gssapi_keyex' userauth mechanism. ++ */ ++static int ++userauth_gsskeyex(Authctxt *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) +@@ -238,7 +273,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)); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -281,7 +317,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"); + +@@ -299,6 +336,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-7.4p1/clientloop.c.gsskex openssh-7.4p1/clientloop.c +--- openssh-7.4p1/clientloop.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/clientloop.c 2016-12-23 13:38:53.725301005 +0100 +@@ -113,6 +113,10 @@ + #include "ssherr.h" + #include "hostfile.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* import options */ + extern Options options; + +@@ -1664,9 +1668,18 @@ client_loop(int have_pty, int escape_cha + break; + + /* Do channel operations unless rekeying in progress. */ +- if (!ssh_packet_is_rekeying(active_state)) ++ if (!ssh_packet_is_rekeying(active_state)) { + channel_after_select(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-7.4p1/configure.ac.gsskex openssh-7.4p1/configure.ac +--- openssh-7.4p1/configure.ac.gsskex 2016-12-23 13:38:53.716301003 +0100 ++++ openssh-7.4p1/configure.ac 2016-12-23 13:38:53.726301005 +0100 +@@ -623,6 +623,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-7.4p1/gss-genr.c.gsskex openssh-7.4p1/gss-genr.c +--- openssh-7.4p1/gss-genr.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/gss-genr.c 2016-12-23 13:38:53.726301005 +0100 +@@ -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-7.4p1/gss-serv.c.gsskex openssh-7.4p1/gss-serv.c +--- openssh-7.4p1/gss-serv.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/gss-serv.c 2016-12-23 13:38:53.727301005 +0100 +@@ -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, 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 +176,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 +304,48 @@ OM_uint32 + ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + { + int i = 0; ++ int equal = 0; ++ gss_name_t new_name = GSS_C_NO_NAME; ++ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; ++ ++ if (options.gss_store_rekey && client->used && ctx->client_creds) { ++ if (client->mech->oid.length != ctx->oid->length || ++ (memcmp(client->mech->oid.elements, ++ ctx->oid->elements, ctx->oid->length) !=0)) { ++ debug("Rekeyed credentials have different mechanism"); ++ return GSS_S_COMPLETE; ++ } ++ ++ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &new_name, ++ NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } + +- gss_buffer_desc ename; ++ ctx->major = gss_compare_name(&ctx->minor, client->name, ++ new_name, &equal); ++ ++ if (GSS_ERROR(ctx->major)) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ if (!equal) { ++ debug("Rekeyed credentials have different name"); ++ return GSS_S_COMPLETE; ++ } ++ ++ debug("Marking rekeyed credentials for export"); ++ ++ gss_release_name(&ctx->minor, &client->name); ++ gss_release_cred(&ctx->minor, &client->creds); ++ client->name = new_name; ++ client->creds = ctx->client_creds; ++ ctx->client_creds = GSS_C_NO_CREDENTIAL; ++ client->updated = 1; ++ return GSS_S_COMPLETE; ++ } + + client->mech = NULL; + +@@ -293,6 +360,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 +384,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 +396,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 +442,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 +452,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 +470,90 @@ ssh_gssapi_userok(char *user) + return (0); + } + +-/* Privileged */ +-OM_uint32 +-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) ++/* These bits are only used for rekeying. The unpriviledged child is running ++ * as the user, the monitor is root. ++ * ++ * In the child, we want to : ++ * *) Ask the monitor to store our credentials into the store we specify ++ * *) If it succeeds, maybe do a PAM update ++ */ ++ ++/* Stuff for PAM */ ++ ++#ifdef USE_PAM ++static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, ++ struct pam_response **resp, void *data) + { +- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, +- gssbuf, gssmic, NULL); ++ return (PAM_CONV_ERR); ++} ++#endif + +- return (ctx->major); ++void ++ssh_gssapi_rekey_creds() { ++ int ok; ++ int ret; ++#ifdef USE_PAM ++ pam_handle_t *pamh = NULL; ++ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; ++ char *envstr; ++#endif ++ ++ if (gssapi_client.store.filename == NULL && ++ gssapi_client.store.envval == NULL && ++ gssapi_client.store.envvar == NULL) ++ return; ++ ++ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); ++ ++ if (!ok) ++ return; ++ ++ debug("Rekeyed credentials stored successfully"); ++ ++ /* Actually managing to play with the ssh pam stack from here will ++ * be next to impossible. In any case, we may want different options ++ * for rekeying. So, use our own :) ++ */ ++#ifdef USE_PAM ++ if (!use_privsep) { ++ debug("Not even going to try and do PAM with privsep disabled"); ++ return; ++ } ++ ++ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, ++ &pamconv, &pamh); ++ if (ret) ++ return; ++ ++ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, ++ gssapi_client.store.envval); ++ ++ ret = pam_putenv(pamh, envstr); ++ if (!ret) ++ pam_setcred(pamh, PAM_REINITIALIZE_CRED); ++ pam_end(pamh, PAM_SUCCESS); ++#endif ++} ++ ++int ++ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { ++ int ok = 0; ++ ++ /* Check we've got credentials to store */ ++ if (!gssapi_client.updated) ++ return 0; ++ ++ gssapi_client.updated = 0; ++ ++ temporarily_use_uid(gssapi_client.store.owner); ++ if (gssapi_client.mech && gssapi_client.mech->updatecreds) ++ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); ++ else ++ debug("No update function for this mechanism"); ++ ++ restore_uid(); ++ ++ return ok; + } + + #endif +diff -up openssh-7.4p1/gss-serv-krb5.c.gsskex openssh-7.4p1/gss-serv-krb5.c +--- openssh-7.4p1/gss-serv-krb5.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/gss-serv-krb5.c 2016-12-23 13:38:53.727301005 +0100 +@@ -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,26 @@ 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); ++ client->store.filename = NULL; ++#else ++ if (new_ccname[0] == ':') ++ new_ccname++; ++ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); ++ if (strcmp(new_cctype, "DIR") == 0) { ++ char *p; ++ p = strrchr(client->store.envval, '/'); ++ if (p) ++ *p = '\0'; ++ } ++ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) ++ client->store.filename = xstrdup(new_ccname); ++#endif + + #ifdef USE_PAM + if (options.use_pam) +@@ -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-7.4p1/kex.c.gsskex openssh-7.4p1/kex.c +--- openssh-7.4p1/kex.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/kex.c 2016-12-23 13:39:56.064313151 +0100 +@@ -54,6 +54,10 @@ + #include "sshbuf.h" + #include "digest.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= 0x00907000L + # if defined(HAVE_EVP_SHA256) + # define evp_ssh_sha256 EVP_sha256 +@@ -111,6 +115,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}, + }; + +@@ -144,6 +153,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-7.4p1/kexgssc.c.gsskex openssh-7.4p1/kexgssc.c +--- openssh-7.4p1/kexgssc.c.gsskex 2016-12-23 13:38:53.727301005 +0100 ++++ openssh-7.4p1/kexgssc.c 2016-12-23 13:38:53.727301005 +0100 +@@ -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-7.4p1/kexgsss.c.gsskex openssh-7.4p1/kexgsss.c +--- openssh-7.4p1/kexgsss.c.gsskex 2016-12-23 13:38:53.728301005 +0100 ++++ openssh-7.4p1/kexgsss.c 2016-12-23 13:38:53.728301005 +0100 +@@ -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-7.4p1/kex.h.gsskex openssh-7.4p1/kex.h +--- openssh-7.4p1/kex.h.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/kex.h 2016-12-23 13:38:53.728301005 +0100 +@@ -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-7.4p1/Makefile.in.gsskex openssh-7.4p1/Makefile.in +--- openssh-7.4p1/Makefile.in.gsskex 2016-12-23 13:38:53.723301004 +0100 ++++ openssh-7.4p1/Makefile.in 2016-12-23 13:40:32.226320197 +0100 +@@ -91,6 +91,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + readpass.o rsa.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-7.4p1/monitor.c.gsskex openssh-7.4p1/monitor.c +--- openssh-7.4p1/monitor.c.gsskex 2016-12-23 13:38:53.687300997 +0100 ++++ openssh-7.4p1/monitor.c 2016-12-23 13:45:49.347381091 +0100 +@@ -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 +@@ -307,6 +316,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) { +@@ -406,6 +419,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 (!no_pty_flag) { + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); +@@ -1633,6 +1650,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; +@@ -1712,7 +1736,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); +@@ -1742,7 +1766,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); +@@ -1762,6 +1786,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); + } +@@ -1773,7 +1798,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); +@@ -1802,10 +1827,11 @@ mm_answer_gss_userok(int sock, Buffer *m + { + int authenticated; + +- 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); +@@ -1818,5 +1844,73 @@ 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.filename = buffer_get_string(m, NULL); ++ store.envvar = buffer_get_string(m, NULL); ++ store.envval = buffer_get_string(m, NULL); ++ ++ ok = ssh_gssapi_update_creds(&store); ++ ++ free(store.filename); ++ 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-7.4p1/monitor.h.gsskex openssh-7.4p1/monitor.h +--- openssh-7.4p1/monitor.h.gsskex 2016-12-23 13:38:53.687300997 +0100 ++++ openssh-7.4p1/monitor.h 2016-12-23 13:38:53.729301005 +0100 +@@ -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-7.4p1/monitor_wrap.c.gsskex openssh-7.4p1/monitor_wrap.c +--- openssh-7.4p1/monitor_wrap.c.gsskex 2016-12-23 13:38:53.687300997 +0100 ++++ openssh-7.4p1/monitor_wrap.c 2016-12-23 13:38:53.729301005 +0100 +@@ -943,7 +943,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; +@@ -960,5 +960,50 @@ 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->filename ? store->filename : ""); ++ 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-7.4p1/monitor_wrap.h.gsskex openssh-7.4p1/monitor_wrap.h +--- openssh-7.4p1/monitor_wrap.h.gsskex 2016-12-23 13:38:53.687300997 +0100 ++++ openssh-7.4p1/monitor_wrap.h 2016-12-23 13:38:53.729301005 +0100 +@@ -58,8 +58,10 @@ int mm_key_verify(Key *, u_char *, u_int + 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-7.4p1/readconf.c.gsskex openssh-7.4p1/readconf.c +--- openssh-7.4p1/readconf.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/readconf.c 2016-12-23 13:38:53.730301005 +0100 +@@ -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, +@@ -205,10 +207,19 @@ static struct { + { "afstokenpassing", oUnsupported }, + #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 + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, +@@ -961,10 +972,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; +@@ -1776,7 +1807,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; +@@ -1920,8 +1956,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-7.4p1/readconf.h.gsskex openssh-7.4p1/readconf.h +--- openssh-7.4p1/readconf.h.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/readconf.h 2016-12-23 13:38:53.730301005 +0100 +@@ -45,7 +45,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-7.4p1/regress/cert-hostkey.sh.gsskex openssh-7.4p1/regress/cert-hostkey.sh +--- openssh-7.4p1/regress/cert-hostkey.sh.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/regress/cert-hostkey.sh 2016-12-23 13:38:53.731301006 +0100 +@@ -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-7.4p1/regress/cert-userkey.sh.gsskex openssh-7.4p1/regress/cert-userkey.sh +--- openssh-7.4p1/regress/cert-userkey.sh.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/regress/cert-userkey.sh 2016-12-23 13:38:53.731301006 +0100 +@@ -7,7 +7,7 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us + cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak + cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak + +-PLAIN_TYPES=`$SSH -Q key-plain | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` ++PLAIN_TYPES=`$SSH -Q key-plain | grep -v null | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` + + if echo "$PLAIN_TYPES" | grep '^rsa$' >/dev/null 2>&1 ; then + PLAIN_TYPES="$PLAIN_TYPES rsa-sha2-256 rsa-sha2-512" +diff -up openssh-7.4p1/regress/kextype.sh.gsskex openssh-7.4p1/regress/kextype.sh +--- openssh-7.4p1/regress/kextype.sh.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/regress/kextype.sh 2016-12-23 13:38:53.731301006 +0100 +@@ -14,6 +14,9 @@ echo "KexAlgorithms=$KEXOPT" >> $OBJ/ssh + + tries="1 2 3 4" + for k in `${SSH} -Q kex`; do ++ if [ $k = "gss-gex-sha1-" -o $k = "gss-group1-sha1-" -o $k = "gss-group14-sha1-" ]; then ++ continue ++ fi + verbose "kex $k" + for i in $tries; do + ${SSH} -F $OBJ/ssh_proxy -o KexAlgorithms=$k x true +diff -up openssh-7.4p1/regress/rekey.sh.gsskex openssh-7.4p1/regress/rekey.sh +--- openssh-7.4p1/regress/rekey.sh.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/regress/rekey.sh 2016-12-23 13:38:53.731301006 +0100 +@@ -38,6 +38,9 @@ increase_datafile_size 300 + + opts="" + for i in `${SSH} -Q kex`; do ++ if [ $i = "gss-gex-sha1-" -o $i = "gss-group1-sha1-" -o $i = "gss-group14-sha1-" ]; then ++ continue ++ fi + opts="$opts KexAlgorithms=$i" + done + for i in `${SSH} -Q cipher`; do +@@ -56,6 +59,9 @@ done + if ${SSH} -Q cipher-auth | grep '^.*$' >/dev/null 2>&1 ; then + for c in `${SSH} -Q cipher-auth`; do + for kex in `${SSH} -Q kex`; do ++ if [ $kex = "gss-gex-sha1-" -o $kex = "gss-group1-sha1-" -o $kex = "gss-group14-sha1-" ]; then ++ continue ++ fi + verbose "client rekey $c $kex" + ssh_data_rekeying "KexAlgorithms=$kex" -oRekeyLimit=256k -oCiphers=$c + done +diff -up openssh-7.4p1/servconf.c.gsskex openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.gsskex 2016-12-23 13:38:53.717301003 +0100 ++++ openssh-7.4p1/servconf.c 2016-12-23 13:38:53.732301006 +0100 +@@ -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; +@@ -268,10 +270,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 = 0; ++ 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) +@@ -410,7 +416,7 @@ typedef enum { + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, +- sAcceptEnv, sPermitTunnel, ++ sGssKeyEx, sGssStoreRekey, sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sHostCertificate, +@@ -484,11 +490,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 }, +@@ -1211,6 +1223,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; +@@ -1219,6 +1235,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; +@@ -2257,6 +2277,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-7.4p1/servconf.h.gsskex openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.gsskex 2016-12-23 13:38:53.717301003 +0100 ++++ openssh-7.4p1/servconf.h 2016-12-23 13:38:53.732301006 +0100 +@@ -112,8 +112,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-7.4p1/ssh_config.5.gsskex openssh-7.4p1/ssh_config.5 +--- openssh-7.4p1/ssh_config.5.gsskex 2016-12-23 13:38:53.732301006 +0100 ++++ openssh-7.4p1/ssh_config.5 2016-12-23 13:48:00.502331870 +0100 +@@ -748,10 +748,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-7.4p1/ssh_config.gsskex openssh-7.4p1/ssh_config +--- openssh-7.4p1/ssh_config.gsskex 2016-12-23 13:38:53.708301001 +0100 ++++ openssh-7.4p1/ssh_config 2016-12-23 13:38:53.733301006 +0100 +@@ -26,6 +26,8 @@ + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes + # AddressFamily any +diff -up openssh-7.4p1/sshconnect2.c.gsskex openssh-7.4p1/sshconnect2.c +--- openssh-7.4p1/sshconnect2.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshconnect2.c 2016-12-23 13:38:53.733301006 +0100 +@@ -162,9 +162,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 +217,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((u_int32_t)options.rekey_limit, + (time_t)options.rekey_interval); +@@ -212,11 +248,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 ++ + dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); + + /* remove ext-info from the KEX proposals for rekeying */ +@@ -311,6 +367,7 @@ int input_gssapi_token(int type, u_int32 + int input_gssapi_hash(int type, u_int32_t, void *); + int input_gssapi_error(int, u_int32_t, void *); + int input_gssapi_errtok(int, u_int32_t, void *); ++int userauth_gsskeyex(Authctxt *authctxt); + #endif + + void userauth(Authctxt *, char *); +@@ -327,6 +384,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, +@@ -652,19 +714,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++; +@@ -761,8 +835,8 @@ input_gssapi_response(int type, u_int32_ + { + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; +- int oidlen; +- char *oidv; ++ u_int oidlen; ++ u_char *oidv; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); +@@ -875,6 +949,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-7.2p1/sshd.c.gsskex openssh-7.2p1/sshd.c +--- openssh-7.2p1/sshd.c.gsskex 2016-02-19 10:01:04.860969328 +0100 ++++ openssh-7.2p1/sshd.c 2016-02-19 10:01:04.872969321 +0100 +@@ -547,7 +547,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 + +@@ -974,8 +974,9 @@ notify_hostkeys(struct ssh *ssh) + } + debug3("%s: sent %d hostkeys", __func__, nkeys); + if (nkeys == 0) +- fatal("%s: no hostkeys", __func__); +- packet_send(); ++ debug3("%s: no hostkeys", __func__); ++ else ++ packet_send(); + sshbuf_free(buf); + } + +@@ -1739,7 +1740,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); + } +@@ -2196,6 +2198,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)); +@@ -2213,6 +2257,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-7.4p1/sshd_config.5.gsskex openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.gsskex 2016-12-23 13:38:53.734301006 +0100 ++++ openssh-7.4p1/sshd_config.5 2016-12-23 13:48:57.825310358 +0100 +@@ -628,6 +628,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. +@@ -642,6 +647,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-7.4p1/sshd_config.gsskex openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.gsskex 2016-12-23 13:38:53.719301003 +0100 ++++ openssh-7.4p1/sshd_config 2016-12-23 13:38:53.734301006 +0100 +@@ -77,6 +77,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-7.4p1/ssh-gss.h.gsskex openssh-7.4p1/ssh-gss.h +--- openssh-7.4p1/ssh-gss.h.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/ssh-gss.h 2016-12-23 13:38:53.734301006 +0100 +@@ -1,6 +1,6 @@ + /* $OpenBSD: ssh-gss.h,v 1.11 2014/02/26 20:28:44 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,16 +136,32 @@ 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); + ++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-7.4p1/sshkey.c.gsskex openssh-7.4p1/sshkey.c +--- openssh-7.4p1/sshkey.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshkey.c 2016-12-23 13:38:53.735301006 +0100 +@@ -114,6 +114,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-7.4p1/sshkey.h.gsskex openssh-7.4p1/sshkey.h +--- openssh-7.4p1/sshkey.h.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshkey.h 2016-12-23 13:38:53.735301006 +0100 +@@ -62,6 +62,7 @@ enum sshkey_types { + KEY_DSA_CERT, + KEY_ECDSA_CERT, + KEY_ED25519_CERT, ++ KEY_NULL, + KEY_UNSPEC + }; + +diff -up openssh-7.4p1/auth.c.gsskex openssh-7.4p1/auth.c +--- openssh-7.4p1/auth.c.gsskex 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/auth.c 2016-12-23 13:38:53.735301006 +0100 +@@ -372,6 +372,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; +@@ -795,99 +796,6 @@ fakepw(void) + } + + /* +- * Returns the remote DNS hostname as a string. The returned string must not +- * be freed. NB. this will usually trigger a DNS query the first time it is +- * called. +- * This function does additional checks on the hostname to mitigate some +- * attacks on legacy rhosts-style authentication. +- * XXX is RhostsRSAAuthentication vulnerable to these? +- * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) +- */ +- +-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. +diff -up openssh-7.4p1/openbsd-compat/port-linux.c.gsskex openssh-7.4p1/openbsd-compat/port-linux.c +--- openssh-7.4p1/openbsd-compat/port-linux.c.gsskex 2016-12-23 13:38:53.688300997 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux.c 2016-12-23 13:38:53.735301006 +0100 +@@ -30,6 +30,8 @@ + #include "log.h" + #include "xmalloc.h" + #include "port-linux.h" ++#include "canohost.h" ++#include "misc.h" + + #ifdef WITH_SELINUX + #include +@@ -279,4 +281,121 @@ oom_adjust_restore(void) + return; + } + #endif /* LINUX_OOM_ADJUST */ ++ ++/**************** XXX moved from auth.c ****************/ ++ ++/* ++ * Returns the remote DNS hostname as a string. The returned string must not ++ * be freed. NB. this will usually trigger a DNS query the first time it is ++ * called. ++ * This function does additional checks on the hostname to mitigate some ++ * attacks on legacy rhosts-style authentication. ++ * XXX is RhostsRSAAuthentication vulnerable to these? ++ * XXX Can we remove these checks? (or if not, remove RhostsRSAAuthentication?) ++ */ ++ ++char * ++remote_hostname(struct ssh *ssh) ++{ ++ struct sockaddr_storage from; ++ socklen_t fromlen; ++ struct addrinfo hints, *ai, *aitop; ++ char name[NI_MAXHOST], ntop2[NI_MAXHOST]; ++ const char *ntop = ssh_remote_ipaddr(ssh); ++ ++ /* Get IP address of client. */ ++ fromlen = sizeof(from); ++ memset(&from, 0, sizeof(from)); ++ if (getpeername(ssh_packet_get_connection_in(ssh), ++ (struct sockaddr *)&from, &fromlen) < 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 - POSSIBLE BREAK-IN ATTEMPT!", 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 - POSSIBLE BREAK-IN ATTEMPT!", ++ 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; ++ } ++} + #endif /* WITH_SELINUX || LINUX_OOM_ADJUST */ +diff -up openssh-7.4p1/openbsd-compat/port-linux.h.gsskex openssh-7.4p1/openbsd-compat/port-linux.h +--- openssh-7.4p1/openbsd-compat/port-linux.h.gsskex 2016-12-23 13:38:53.712301002 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 13:38:53.735301006 +0100 +@@ -16,6 +16,7 @@ + + #ifndef _PORT_LINUX_H + #define _PORT_LINUX_H ++#include "packet.h" + + #ifdef WITH_SELINUX + int ssh_selinux_enabled(void); +@@ -36,4 +37,8 @@ void oom_adjust_setup(void); + + void linux_seed(void); + ++const char *get_canonical_hostname(struct ssh *, int); ++char *remote_hostname(struct ssh *); ++ ++ + #endif /* ! _PORT_LINUX_H */ diff --git a/SOURCES/openssh-7.4p1-kdf-cavs.patch b/SOURCES/openssh-7.4p1-kdf-cavs.patch new file mode 100644 index 0000000..65feb96 --- /dev/null +++ b/SOURCES/openssh-7.4p1-kdf-cavs.patch @@ -0,0 +1,611 @@ +diff -up openssh-6.8p1/Makefile.in.kdf-cavs openssh-6.8p1/Makefile.in +--- openssh-6.8p1/Makefile.in.kdf-cavs 2015-03-18 11:23:46.346049359 +0100 ++++ openssh-6.8p1/Makefile.in 2015-03-18 11:24:20.395968445 +0100 +@@ -29,6 +29,7 @@ SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-h + SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper + SSH_KEYCAT=$(libexecdir)/ssh-keycat + CTR_CAVSTEST=$(libexecdir)/ctr-cavstest ++SSH_CAVS=$(libexecdir)/ssh-cavs + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ +@@ -67,7 +68,7 @@ EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ + +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-keycat$(EXEEXT) ctr-cavstest$(EXEEXT) ssh-cavs$(EXEEXT) + + LIBOPENSSH_OBJS=\ + ssh_api.o \ +@@ -198,6 +199,9 @@ ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHD + ctr-cavstest$(EXEEXT): $(LIBCOMPAT) libssh.a ctr-cavstest.o + $(LD) -o $@ ctr-cavstest.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lfipscheck $(LIBS) + ++ssh-cavs$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-cavs.o ++ $(LD) -o $@ ssh-cavs.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + +@@ -331,6 +335,8 @@ install-files: + fi + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ctr-cavstest$(EXEEXT) $(DESTDIR)$(libexecdir)/ctr-cavstest$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-cavs$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-cavs_driver.pl $(DESTDIR)$(libexecdir)/ssh-cavs_driver.pl + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 +diff -up openssh-6.8p1/ssh-cavs.c.kdf-cavs openssh-6.8p1/ssh-cavs.c +--- openssh-6.8p1/ssh-cavs.c.kdf-cavs 2015-03-18 11:23:46.348049354 +0100 ++++ openssh-6.8p1/ssh-cavs.c 2015-03-18 11:23:46.348049354 +0100 +@@ -0,0 +1,380 @@ ++/* ++ * Copyright (C) 2015, Stephan Mueller ++ * ++ * 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, and the entire permission notice in its entirety, ++ * including the disclaimer of warranties. ++ * 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. ++ * 3. The name of the author may not be used to endorse or promote ++ * products derived from this software without specific prior ++ * written permission. ++ * ++ * ALTERNATIVELY, this product may be distributed under the terms of ++ * the GNU General Public License, in which case the provisions of the GPL2 ++ * are required INSTEAD OF the above restrictions. (This clause is ++ * necessary due to a potential bad interaction between the GPL and ++ * the restrictions contained in a BSD-style copyright.) ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY 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 NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#include "includes.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "xmalloc.h" ++#include "buffer.h" ++#include "key.h" ++#include "cipher.h" ++#include "kex.h" ++#include "packet.h" ++ ++static int bin_char(unsigned char hex) ++{ ++ if (48 <= hex && 57 >= hex) ++ return (hex - 48); ++ if (65 <= hex && 70 >= hex) ++ return (hex - 55); ++ if (97 <= hex && 102 >= hex) ++ return (hex - 87); ++ return 0; ++} ++ ++/* ++ * Convert hex representation into binary string ++ * @hex input buffer with hex representation ++ * @hexlen length of hex ++ * @bin output buffer with binary data ++ * @binlen length of already allocated bin buffer (should be at least ++ * half of hexlen -- if not, only a fraction of hexlen is converted) ++ */ ++static void hex2bin(const char *hex, size_t hexlen, ++ unsigned char *bin, size_t binlen) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ bin[i] = bin_char(hex[(i*2)]) << 4; ++ bin[i] |= bin_char(hex[((i*2)+1)]); ++ } ++} ++ ++/* ++ * Allocate sufficient space for binary representation of hex ++ * and convert hex into bin ++ * ++ * Caller must free bin ++ * @hex input buffer with hex representation ++ * @hexlen length of hex ++ * @bin return value holding the pointer to the newly allocated buffer ++ * @binlen return value holding the allocated size of bin ++ * ++ * return: 0 on success, !0 otherwise ++ */ ++static int hex2bin_alloc(const char *hex, size_t hexlen, ++ unsigned char **bin, size_t *binlen) ++{ ++ unsigned char *out = NULL; ++ size_t outlen = 0; ++ ++ if (!hexlen) ++ return -EINVAL; ++ ++ outlen = (hexlen + 1) / 2; ++ ++ out = calloc(1, outlen); ++ if (!out) ++ return -errno; ++ ++ hex2bin(hex, hexlen, out, outlen); ++ *bin = out; ++ *binlen = outlen; ++ return 0; ++} ++ ++static char hex_char_map_l[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; ++static char hex_char_map_u[] = { '0', '1', '2', '3', '4', '5', '6', '7', ++ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; ++static char hex_char(unsigned int bin, int u) ++{ ++ if (bin < sizeof(hex_char_map_l)) ++ return (u) ? hex_char_map_u[bin] : hex_char_map_l[bin]; ++ return 'X'; ++} ++ ++/* ++ * Convert binary string into hex representation ++ * @bin input buffer with binary data ++ * @binlen length of bin ++ * @hex output buffer to store hex data ++ * @hexlen length of already allocated hex buffer (should be at least ++ * twice binlen -- if not, only a fraction of binlen is converted) ++ * @u case of hex characters (0=>lower case, 1=>upper case) ++ */ ++static void bin2hex(const unsigned char *bin, size_t binlen, ++ char *hex, size_t hexlen, int u) ++{ ++ size_t i = 0; ++ size_t chars = (binlen > (hexlen / 2)) ? (hexlen / 2) : binlen; ++ ++ for (i = 0; i < chars; i++) { ++ hex[(i*2)] = hex_char((bin[i] >> 4), u); ++ hex[((i*2)+1)] = hex_char((bin[i] & 0x0f), u); ++ } ++} ++ ++struct kdf_cavs { ++ unsigned char *K; ++ size_t Klen; ++ unsigned char *H; ++ size_t Hlen; ++ unsigned char *session_id; ++ size_t session_id_len; ++ ++ unsigned int iv_len; ++ unsigned int ek_len; ++ unsigned int ik_len; ++}; ++ ++static int sshkdf_cavs(struct kdf_cavs *test) ++{ ++ int ret = 0; ++ struct kex kex; ++ BIGNUM *Kbn = NULL; ++ int mode = 0; ++ struct newkeys *ctoskeys; ++ struct newkeys *stockeys; ++ struct ssh *ssh = NULL; ++ ++#define HEXOUTLEN 500 ++ char hex[HEXOUTLEN]; ++ ++ memset(&kex, 0, sizeof(struct kex)); ++ ++ Kbn = BN_new(); ++ BN_bin2bn(test->K, test->Klen, Kbn); ++ if (!Kbn) { ++ printf("cannot convert K into BIGNUM\n"); ++ ret = 1; ++ goto out; ++ } ++ ++ kex.session_id = test->session_id; ++ kex.session_id_len = test->session_id_len; ++ ++ /* setup kex */ ++ ++ /* select the right hash based on struct ssh_digest digests */ ++ switch (test->ik_len) { ++ case 20: ++ kex.hash_alg = 2; ++ break; ++ case 32: ++ kex.hash_alg = 3; ++ break; ++ case 48: ++ kex.hash_alg = 4; ++ break; ++ case 64: ++ kex.hash_alg = 5; ++ break; ++ default: ++ printf("Wrong hash type %u\n", test->ik_len); ++ ret = 1; ++ goto out; ++ } ++ ++ /* implement choose_enc */ ++ for (mode = 0; mode < 2; mode++) { ++ kex.newkeys[mode] = calloc(1, sizeof(struct newkeys)); ++ if (!kex.newkeys[mode]) { ++ printf("allocation of newkeys failed\n"); ++ ret = 1; ++ goto out; ++ } ++ kex.newkeys[mode]->enc.iv_len = test->iv_len; ++ kex.newkeys[mode]->enc.key_len = test->ek_len; ++ kex.newkeys[mode]->enc.block_size = (test->iv_len == 64) ? 8 : 16; ++ kex.newkeys[mode]->mac.key_len = test->ik_len; ++ } ++ ++ /* implement kex_choose_conf */ ++ kex.we_need = kex.newkeys[0]->enc.key_len; ++ if (kex.we_need < kex.newkeys[0]->enc.block_size) ++ kex.we_need = kex.newkeys[0]->enc.block_size; ++ if (kex.we_need < kex.newkeys[0]->enc.iv_len) ++ kex.we_need = kex.newkeys[0]->enc.iv_len; ++ if (kex.we_need < kex.newkeys[0]->mac.key_len) ++ kex.we_need = kex.newkeys[0]->mac.key_len; ++ ++ /* MODE_OUT (1) -> server to client ++ * MODE_IN (0) -> client to server */ ++ kex.server = 1; ++ ++ /* do it */ ++ if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL){ ++ printf("Allocation error\n"); ++ goto out; ++ } ++ ssh->kex = &kex; ++ kex_derive_keys_bn(ssh, test->H, test->Hlen, Kbn); ++ ++ ctoskeys = kex.newkeys[0]; ++ stockeys = kex.newkeys[1]; ++ ++ /* get data */ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->enc.iv, (size_t)ctoskeys->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->enc.iv, (size_t)stockeys->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->enc.key, (size_t)ctoskeys->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->enc.key, (size_t)stockeys->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(ctoskeys->mac.key, (size_t)ctoskeys->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (client to server) = %s\n", hex); ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(stockeys->mac.key, (size_t)stockeys->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (server to client) = %s\n", hex); ++ ++out: ++ if (Kbn) ++ BN_free(Kbn); ++ if (kex.newkeys[0]) ++ free(kex.newkeys[0]); ++ if (kex.newkeys[1]) ++ free(kex.newkeys[1]); ++ if (ssh) ++ ssh_packet_close(ssh); ++ return ret; ++} ++ ++static void usage(void) ++{ ++ fprintf(stderr, "\nOpenSSH KDF CAVS Test\n\n"); ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, "\t-K\tShared secret string\n"); ++ fprintf(stderr, "\t-H\tHash string\n"); ++ fprintf(stderr, "\t-s\tSession ID string\n"); ++ fprintf(stderr, "\t-i\tIV length to be generated\n"); ++ fprintf(stderr, "\t-e\tEncryption key length to be generated\n"); ++ fprintf(stderr, "\t-m\tMAC key length to be generated\n"); ++} ++ ++/* ++ * Test command example: ++ * ./ssh-cavs -K 0055d50f2d163cc07cd8a93cc7c3430c30ce786b572c01ad29fec7597000cf8618d664e2ec3dcbc8bb7a1a7eb7ef67f61cdaf291625da879186ac0a5cb27af571b59612d6a6e0627344d846271959fda61c78354aa498773d59762f8ca2d0215ec590d8633de921f920d41e47b3de6ab9a3d0869e1c826d0e4adebf8e3fb646a15dea20a410b44e969f4b791ed6a67f13f1b74234004d5fa5e87eff7abc32d49bbdf44d7b0107e8f10609233b7e2b7eff74a4daf25641de7553975dac6ac1e5117df6f6dbaa1c263d23a6c3e5a3d7d49ae8a828c1e333ac3f85fbbf57b5c1a45be45e43a7be1a4707eac779b8285522d1f531fe23f890fd38a004339932b93eda4 -H d3ab91a850febb417a25d892ec48ed5952c7a5de -s d3ab91a850febb417a25d892ec48ed5952c7a5de -i 8 -e 24 -m 20 ++ * ++ * Initial IV (client to server) = 4bb320d1679dfd3a ++ * Initial IV (server to client) = 43dea6fdf263a308 ++ * Encryption key (client to server) = 13048cc600b9d3cf9095aa6cf8e2ff9cf1c54ca0520c89ed ++ * Encryption key (server to client) = 1e483c5134e901aa11fc4e0a524e7ec7b75556148a222bb0 ++ * Integrity key (client to server) = ecef63a092b0dcc585bdc757e01b2740af57d640 ++ * Integrity key (server to client) = 7424b05f3c44a72b4ebd281fb71f9cbe7b64d479 ++ */ ++int main(int argc, char *argv[]) ++{ ++ struct kdf_cavs test; ++ int ret = 1; ++ int opt = 0; ++ ++ memset(&test, 0, sizeof(struct kdf_cavs)); ++ while((opt = getopt(argc, argv, "K:H:s:i:e:m:")) != -1) ++ { ++ size_t len = 0; ++ switch(opt) ++ { ++ /* ++ * CAVS K is MPINT ++ * we want a hex (i.e. the caller must ensure the ++ * following transformations already happened): ++ * 1. cut off first four bytes ++ * 2. if most significant bit of value is ++ * 1, prepend 0 byte ++ */ ++ case 'K': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.K, &test.Klen); ++ if (ret) ++ goto out; ++ break; ++ case 'H': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.H, &test.Hlen); ++ if (ret) ++ goto out; ++ break; ++ case 's': ++ len = strlen(optarg); ++ ret = hex2bin_alloc(optarg, len, ++ &test.session_id, ++ &test.session_id_len); ++ if (ret) ++ goto out; ++ break; ++ case 'i': ++ test.iv_len = strtoul(optarg, NULL, 10); ++ break; ++ case 'e': ++ test.ek_len = strtoul(optarg, NULL, 10); ++ break; ++ case 'm': ++ test.ik_len = strtoul(optarg, NULL, 10); ++ break; ++ default: ++ usage(); ++ goto out; ++ } ++ } ++ ++ ret = sshkdf_cavs(&test); ++ ++out: ++ if (test.session_id) ++ free(test.session_id); ++ if (test.K) ++ free(test.K); ++ if (test.H) ++ free(test.H); ++ return ret; ++ ++} +diff -up openssh-6.8p1/ssh-cavs_driver.pl.kdf-cavs openssh-6.8p1/ssh-cavs_driver.pl +--- openssh-6.8p1/ssh-cavs_driver.pl.kdf-cavs 2015-03-18 11:23:46.348049354 +0100 ++++ openssh-6.8p1/ssh-cavs_driver.pl 2015-03-18 11:23:46.348049354 +0100 +@@ -0,0 +1,184 @@ ++#!/usr/bin/env perl ++# ++# CAVS test driver for OpenSSH ++# ++# Copyright (C) 2015, Stephan Mueller ++# ++# Permission is hereby granted, free of charge, to any person obtaining a copy ++# of this software and associated documentation files (the "Software"), to deal ++# in the Software without restriction, including without limitation the rights ++# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++# copies of the Software, and to permit persons to whom the Software is ++# furnished to do so, subject to the following conditions: ++# ++# The above copyright notice and this permission notice shall be included in ++# all copies or substantial portions of the Software. ++# ++# NO WARRANTY ++# ++# BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++# FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++# OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++# PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++# OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++# TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++# PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++# REPAIR OR CORRECTION. ++# ++# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++# REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++# INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++# OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++# TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++# YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++# PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++# POSSIBILITY OF SUCH DAMAGES. ++# ++use strict; ++use warnings; ++use IPC::Open2; ++ ++# Executing a program by feeding STDIN and retrieving ++# STDOUT ++# $1: data string to be piped to the app on STDIN ++# rest: program and args ++# returns: STDOUT of program as string ++sub pipe_through_program($@) { ++ my $in = shift; ++ my @args = @_; ++ ++ my ($CO, $CI); ++ my $pid = open2($CO, $CI, @args); ++ ++ my $out = ""; ++ my $len = length($in); ++ my $first = 1; ++ while (1) { ++ my $rin = ""; ++ my $win = ""; ++ # Output of prog is FD that we read ++ vec($rin,fileno($CO),1) = 1; ++ # Input of prog is FD that we write ++ # check for $first is needed because we can have NULL input ++ # that is to be written to the app ++ if ( $len > 0 || $first) { ++ (vec($win,fileno($CI),1) = 1); ++ $first=0; ++ } ++ # Let us wait for 100ms ++ my $nfound = select(my $rout=$rin, my $wout=$win, undef, 0.1); ++ if ( $wout ) { ++ my $written = syswrite($CI, $in, $len); ++ die "broken pipe" if !defined $written; ++ $len -= $written; ++ substr($in, 0, $written) = ""; ++ if ($len <= 0) { ++ close $CI or die "broken pipe: $!"; ++ } ++ } ++ if ( $rout ) { ++ my $tmp_out = ""; ++ my $bytes_read = sysread($CO, $tmp_out, 4096); ++ $out .= $tmp_out; ++ last if ($bytes_read == 0); ++ } ++ } ++ close $CO or die "broken pipe: $!"; ++ waitpid $pid, 0; ++ ++ return $out; ++} ++ ++# Parser of CAVS test vector file ++# $1: Test vector file ++# $2: Output file for test results ++# return: nothing ++sub parse($$) { ++ my $infile = shift; ++ my $outfile = shift; ++ ++ my $out = ""; ++ ++ my $K = ""; ++ my $H = ""; ++ my $session_id = ""; ++ my $ivlen = 0; ++ my $eklen = ""; ++ my $iklen = ""; ++ ++ open(IN, "<$infile"); ++ while() { ++ ++ my $line = $_; ++ chomp($line); ++ $line =~ s/\r//; ++ ++ if ($line =~ /\[SHA-1\]/) { ++ $iklen = 20; ++ } elsif ($line =~ /\[SHA-256\]/) { ++ $iklen = 32; ++ } elsif ($line =~ /\[SHA-384\]/) { ++ $iklen = 48; ++ } elsif ($line =~ /\[SHA-512\]/) { ++ $iklen = 64; ++ } elsif ($line =~ /^\[IV length\s*=\s*(.*)\]/) { ++ $ivlen = $1; ++ $ivlen = $ivlen / 8; ++ } elsif ($line =~ /^\[encryption key length\s*=\s*(.*)\]/) { ++ $eklen = $1; ++ $eklen = $eklen / 8; ++ } elsif ($line =~ /^K\s*=\s*(.*)/) { ++ $K = $1; ++ $K = substr($K, 8); ++ $K = "00" . $K; ++ } elsif ($line =~ /^H\s*=\s*(.*)/) { ++ $H = $1; ++ } elsif ($line =~ /^session_id\s*=\s*(.*)/) { ++ $session_id = $1; ++ } ++ $out .= $line . "\n"; ++ ++ if ($K ne "" && $H ne "" && $session_id ne "" && ++ $ivlen ne "" && $eklen ne "" && $iklen > 0) { ++ $out .= pipe_through_program("", "./ssh-cavs -H $H -K $K -s $session_id -i $ivlen -e $eklen -m $iklen"); ++ ++ $K = ""; ++ $H = ""; ++ $session_id = ""; ++ } ++ } ++ close IN; ++ $out =~ s/\n/\r\n/g; # make it a dos file ++ open(OUT, ">$outfile") or die "Cannot create output file $outfile: $?"; ++ print OUT $out; ++ close OUT; ++} ++ ++############################################################ ++# ++# let us pretend to be C :-) ++sub main() { ++ ++ my $infile=$ARGV[0]; ++ die "Error: Test vector file $infile not found" if (! -f $infile); ++ ++ my $outfile = $infile; ++ # let us add .rsp regardless whether we could strip .req ++ $outfile =~ s/\.req$//; ++ $outfile .= ".rsp"; ++ if (-f $outfile) { ++ die "Output file $outfile could not be removed: $?" ++ unless unlink($outfile); ++ } ++ print STDERR "Performing tests from source file $infile with results stored in destination file $outfile\n"; ++ ++ # Do the job ++ parse($infile, $outfile); ++} ++ ++########################################### ++# Call it ++main(); ++1; diff --git a/SOURCES/openssh-7.4p1-kuserok.patch b/SOURCES/openssh-7.4p1-kuserok.patch new file mode 100644 index 0000000..ff0d6d4 --- /dev/null +++ b/SOURCES/openssh-7.4p1-kuserok.patch @@ -0,0 +1,288 @@ +diff -up openssh-7.4p1/auth-krb5.c.kuserok openssh-7.4p1/auth-krb5.c +--- openssh-7.4p1/auth-krb5.c.kuserok 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/auth-krb5.c 2017-02-09 09:20:00.958084311 +0100 +@@ -54,6 +54,21 @@ + + extern ServerOptions options; + ++int ++ssh_krb5_kuserok(krb5_context krb5_ctx, krb5_principal krb5_user, const char *client, ++ int k5login_exists) ++{ ++ if (options.use_kuserok || !k5login_exists) ++ return krb5_kuserok(krb5_ctx, krb5_user, client); ++ else { ++ char kuser[65]; ++ ++ if (krb5_aname_to_localname(krb5_ctx, krb5_user, sizeof(kuser), kuser)) ++ return 0; ++ return strcmp(kuser, client) == 0; ++ } ++} ++ + static int + krb5_init(void *context) + { +@@ -157,8 +172,9 @@ auth_krb5_password(Authctxt *authctxt, c + if (problem) + goto out; + +- if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, +- authctxt->pw->pw_name)) { ++ /* Use !options.use_kuserok here to make ssh_krb5_kuserok() not ++ * depend on the existance of .k5login */ ++ if (!ssh_krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, authctxt->pw->pw_name, !options.use_kuserok)) { + problem = -1; + goto out; + } +diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c +--- openssh-7.4p1/gss-serv-krb5.c.kuserok 2017-02-09 09:20:00.955084317 +0100 ++++ openssh-7.4p1/gss-serv-krb5.c 2017-02-09 09:20:00.958084311 +0100 +@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_pr + int); + + static krb5_context krb_context = NULL; ++extern int ssh_krb5_kuserok(krb5_context, krb5_principal, const char *, int); + + /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ + +@@ -92,6 +93,103 @@ ssh_gssapi_krb5_init(void) + * Returns true if the user is OK to log in, otherwise returns 0 + */ + ++/* The purpose of the function is to find out if a Kerberos principal is ++ * allowed to log in as the given local user. This is a general problem with ++ * Kerberized services because by design the Kerberos principals are ++ * completely independent from the local user names. This is one of the ++ * reasons why Kerberos is working well on different operating systems like ++ * Windows and UNIX/Linux. Nevertheless a relationship between a Kerberos ++ * principal and a local user name must be established because otherwise every ++ * access would be granted for every principal with a valid ticket. ++ * ++ * Since it is a general issue libkrb5 provides some functions for ++ * applications to find out about the relationship between the Kerberos ++ * principal and a local user name. They are krb5_kuserok() and ++ * krb5_aname_to_localname(). ++ * ++ * krb5_kuserok() can be used to "Determine if a principal is authorized to ++ * log in as a local user" (from the MIT Kerberos documentation of this ++ * function). Which is exactly what we are looking for and should be the ++ * preferred choice. It accepts the Kerberos principal and a local user name ++ * and let libkrb5 or its plugins determine if they relate to each other or ++ * not. ++ * ++ * krb5_aname_to_localname() can use used to "Convert a principal name to a ++ * local name" (from the MIT Kerberos documentation of this function). It ++ * accepts a Kerberos principle and returns a local name and it is up to the ++ * application to do any additional checks. There are two issues using ++ * krb5_aname_to_localname(). First, since POSIX user names are case ++ * sensitive, the calling application in general has no other choice than ++ * doing a case-sensitive string comparison between the name returned by ++ * krb5_aname_to_localname() and the name used at the login prompt. When the ++ * users are provided by a case in-sensitive server, e.g. Active Directory, ++ * this might lead to login failures because the user typing the name at the ++ * login prompt might not be aware of the right case. Another issue might be ++ * caused if there are multiple alias names available for a single user. E.g. ++ * the canonical name of a user is user@group.department.example.com but there ++ * exists a shorter login name, e.g. user@example.com, to safe typing at the ++ * login prompt. Here krb5_aname_to_localname() can only return the canonical ++ * name, but if the short alias is used at the login prompt authentication ++ * will fail as well. All this can be avoided by using krb5_kuserok() and ++ * configuring krb5.conf or using a suitable plugin to meet the needs of the ++ * given environment. ++ * ++ * The Fedora and RHEL version of openssh contain two patches which modify the ++ * access control behavior: ++ * - openssh-6.6p1-kuserok.patch ++ * - openssh-6.6p1-force_krb.patch ++ * ++ * openssh-6.6p1-kuserok.patch adds a new option KerberosUseKuserok for ++ * sshd_config which controls if krb5_kuserok() is used to check if the ++ * principle is authorized or if krb5_aname_to_localname() should be used. ++ * The reason to add this patch was that krb5_kuserok() by default checks if ++ * a .k5login file exits in the users home-directory. With this the user can ++ * give access to his account for any given principal which might be ++ * in violation with company policies and it would be useful if this can be ++ * rejected. Nevertheless the patch ignores the fact that krb5_kuserok() does ++ * no only check .k5login but other sources as well and checking .k5login can ++ * be disabled for all applications in krb5.conf as well. With this new ++ * option KerberosUseKuserok set to 'no' (and this is the default for RHEL7 ++ * and Fedora 21) openssh can only use krb5_aname_to_localname() with the ++ * restrictions mentioned above. ++ * ++ * openssh-6.6p1-force_krb.patch adds a ksu like behaviour to ssh, i.e. when ++ * using GSSAPI authentication only commands configured in the .k5user can be ++ * executed. Here the wrong assumption that krb5_kuserok() only checks ++ * .k5login is made as well. In contrast ksu checks .k5login directly and ++ * does not use krb5_kuserok() which might be more useful for the given ++ * purpose. Additionally this patch is not synced with ++ * openssh-6.6p1-kuserok.patch. ++ * ++ * The current patch tries to restore the usage of krb5_kuserok() so that e.g. ++ * localauth plugins can be used. It does so by adding a forth parameter to ++ * ssh_krb5_kuserok() which indicates whether .k5login exists or not. If it ++ * does not exists krb5_kuserok() is called even if KerberosUseKuserok is set ++ * to 'no' because the intent of the option is to not check .k5login and if it ++ * does not exists krb5_kuserok() returns a result without checking .k5login. ++ * If .k5login does exists and KerberosUseKuserok is 'no' we fall back to ++ * krb5_aname_to_localname(). This is in my point of view an acceptable ++ * limitation and does not break the current behaviour. ++ * ++ * Additionally with this patch ssh_krb5_kuserok() is called in ++ * ssh_gssapi_krb5_cmdok() instead of only krb5_aname_to_localname() is ++ * neither .k5login nor .k5users exists to allow plugin evaluation via ++ * krb5_kuserok() as well. ++ * ++ * I tried to keep the patch as minimal as possible, nevertheless I see some ++ * areas for improvement which, if they make sense, have to be evaluated ++ * carefully because they might change existing behaviour and cause breaks ++ * during upgrade: ++ * - I wonder if disabling .k5login usage make sense in sshd or if it should ++ * be better disabled globally in krb5.conf ++ * - if really needed openssh-6.6p1-kuserok.patch should be fixed to really ++ * only disable checking .k5login and maybe .k5users ++ * - the ksu behaviour should be configurable and maybe check the .k5login and ++ * .k5users files directly like ksu itself does ++ * - to make krb5_aname_to_localname() more useful an option for sshd to use ++ * the canonical name (the one returned by getpwnam()) instead of the name ++ * given at the login prompt might be useful */ ++ + static int + ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + { +@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client + /* NOTE: .k5login and .k5users must opened as root, not the user, + * because if they are on a krb5-protected filesystem, user credentials + * to access these files aren't available yet. */ +- if (krb5_kuserok(krb_context, princ, name) && k5login_exists) { ++ if (ssh_krb5_kuserok(krb_context, princ, name, k5login_exists) ++ && k5login_exists) { + retval = 1; + logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", + name, (char *)client->displayname.value); +@@ -171,9 +270,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri + snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); + /* If both .k5login and .k5users DNE, self-login is ok. */ + if (!k5login_exists && (access(file, F_OK) == -1)) { +- return (krb5_aname_to_localname(krb_context, principal, +- sizeof(kuser), kuser) == 0) && +- (strcmp(kuser, luser) == 0); ++ return ssh_krb5_kuserok(krb_context, principal, luser, ++ k5login_exists); + } + if ((fp = fopen(file, "r")) == NULL) { + int saved_errno = errno; +diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.kuserok 2017-02-09 09:20:00.951084326 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-09 09:21:29.802896034 +0100 +@@ -165,6 +165,7 @@ initialize_server_options(ServerOptions + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; + options->version_addendum = NULL; ++ options->use_kuserok = -1; + options->fingerprint_hash = -1; + options->disable_forwarding = -1; + } +@@ -334,6 +335,8 @@ fill_default_server_options(ServerOption + options->version_addendum = xstrdup(""); + if (options->show_patchlevel == -1) + options->show_patchlevel = 0; ++ if (options->use_kuserok == -1) ++ options->use_kuserok = 1; + if (options->fwd_opts.streamlocal_bind_mask == (mode_t)-1) + options->fwd_opts.streamlocal_bind_mask = 0177; + if (options->fwd_opts.streamlocal_bind_unlink == -1) +@@ -399,7 +402,7 @@ typedef enum { + sPermitRootLogin, sLogFacility, sLogLevel, + sRhostsRSAAuthentication, sRSAAuthentication, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +- sKerberosGetAFSToken, ++ sKerberosGetAFSToken, sKerberosUseKuserok, + sKerberosTgtPassing, sChallengeResponseAuthentication, + sPasswordAuthentication, sKbdInteractiveAuthentication, + sListenAddress, sAddressFamily, +@@ -478,11 +481,13 @@ static struct { + #else + { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, + #endif ++ { "kerberosusekuserok", sKerberosUseKuserok, SSHCFG_ALL }, + #else + { "kerberosauthentication", sUnsupported, SSHCFG_ALL }, + { "kerberosorlocalpasswd", sUnsupported, SSHCFG_GLOBAL }, + { "kerberosticketcleanup", sUnsupported, SSHCFG_GLOBAL }, + { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, ++ { "kerberosusekuserok", sUnsupported, SSHCFG_ALL }, + #endif + { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, + { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, +@@ -1644,6 +1649,10 @@ process_server_config_line(ServerOptions + *activep = value; + break; + ++ case sKerberosUseKuserok: ++ intptr = &options->use_kuserok; ++ goto parse_flag; ++ + case sPermitOpen: + arg = strdelim(&cp); + if (!arg || *arg == '\0') +@@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(client_alive_interval); + M_CP_INTOPT(ip_qos_interactive); + M_CP_INTOPT(ip_qos_bulk); ++ M_CP_INTOPT(use_kuserok); + M_CP_INTOPT(rekey_limit); + M_CP_INTOPT(rekey_interval); + +@@ -2308,6 +2318,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); + dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); ++ dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); + + /* string arguments */ +diff -up openssh-7.4p1/servconf.h.kuserok openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.kuserok 2017-02-09 09:20:00.951084326 +0100 ++++ openssh-7.4p1/servconf.h 2017-02-09 09:20:00.959084309 +0100 +@@ -174,6 +174,7 @@ typedef struct { + + int num_permitted_opens; + ++ int use_kuserok; + char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; +diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.kuserok 2017-02-09 09:20:00.959084309 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-09 09:22:33.517761012 +0100 +@@ -846,6 +846,10 @@ Specifies whether to automatically destr + file on logout. + The default is + .Cm yes . ++.It Cm KerberosUseKuserok ++Specifies whether to look at .k5login file for user's aliases. ++The default is ++.Cm yes . + .It Cm KexAlgorithms + Specifies the available KEX (Key Exchange) algorithms. + Multiple algorithms must be comma-separated. +@@ -1074,6 +1078,7 @@ Available keywords are + .Cm IPQoS , + .Cm KbdInteractiveAuthentication , + .Cm KerberosAuthentication , ++.Cm KerberosUseKuserok , + .Cm MaxAuthTries , + .Cm MaxSessions , + .Cm PasswordAuthentication , +diff -up openssh-7.4p1/sshd_config.kuserok openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.kuserok 2017-02-09 09:20:00.953084322 +0100 ++++ openssh-7.4p1/sshd_config 2017-02-09 09:20:00.959084309 +0100 +@@ -73,6 +73,7 @@ ChallengeResponseAuthentication no + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no ++#KerberosUseKuserok yes + + # GSSAPI options + GSSAPIAuthentication yes diff --git a/SOURCES/openssh-7.4p1-legacy-algorithms.patch b/SOURCES/openssh-7.4p1-legacy-algorithms.patch new file mode 100644 index 0000000..1d8178c --- /dev/null +++ b/SOURCES/openssh-7.4p1-legacy-algorithms.patch @@ -0,0 +1,263 @@ +diff -up openssh-7.4p1/dh.h.legacy openssh-7.4p1/dh.h +--- openssh-7.4p1/dh.h.legacy 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/dh.h 2017-03-02 17:00:37.640695985 +0100 +@@ -50,7 +50,7 @@ u_int dh_estimate(int); + * Max value from RFC4419. + * Miniumum increased in light of DH precomputation attacks. + */ +-#define DH_GRP_MIN 2048 ++#define DH_GRP_MIN 1024 + #define DH_GRP_MAX 8192 + + /* +diff -up openssh-7.4p1/moduli.legacy openssh-7.4p1/moduli +--- openssh-7.4p1/moduli.legacy 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/moduli 2017-03-02 17:00:37.642695983 +0100 +@@ -1,5 +1,83 @@ + # $OpenBSD: moduli,v 1.18 2016/08/11 01:42:11 dtucker Exp $ + # Time Type Tests Tries Size Generator Modulus ++20150520233853 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA2AC62AF ++20150520233854 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA2BCC50F ++20150520233854 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA2C241F3 ++20150520233855 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA2DDF347 ++20150520233856 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA2E3FDBB ++20150520233857 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3006603 ++20150520233858 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA31D9C37 ++20150520233859 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA333355B ++20150520233900 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3428B23 ++20150520233902 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA37C9A43 ++20150520233903 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA384B367 ++20150520233903 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3903453 ++20150520233904 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3946C77 ++20150520233904 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA39F6A9B ++20150520233904 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3A0E88B ++20150520233905 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3A37763 ++20150520233906 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3BBDD57 ++20150520233906 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3BDCDD7 ++20150520233906 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3BF5D73 ++20150520233907 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3C9BB83 ++20150520233908 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3E5ADCF ++20150520233909 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA3F82077 ++20150520233910 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA406944F ++20150520233910 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA40F7457 ++20150520233912 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA438733B ++20150520233913 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA44707FB ++20150520233914 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA4588A2B ++20150520233916 2 6 100 1023 2 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA48CC01B ++20150520233917 2 6 100 1023 5 DB662973FB21C0B7BF21AB46AFD3E2002AE70C92DE6B9AEAFECF7B0A96D7ACB024B7C29DB18E70CB945FA54C7773519BC7161648AFE4939058AC40ECDBBD3636F5BF45863117E955007C9D0F9333BB4EF62F7C9F6298AB79A309C734F3CF201C61EBC3926ADD4E80968A65D9F60535164ACE7A7BFEDC1022002BB2BBA4960077 ++20150522025931 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAD18DA1F ++20150522025936 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAD3763B3 ++20150522025942 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAD702B8B ++20150522025943 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAD77C283 ++20150522025947 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAD96C25B ++20150522025953 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DADD9B3DB ++20150522025956 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DADE84F07 ++20150522025957 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DADEC1DB3 ++20150522030001 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE0E297F ++20150522030004 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE2A1E23 ++20150522030005 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE2ADE53 ++20150522030008 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE47B9F7 ++20150522030009 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE4E1343 ++20150522030014 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE715CBB ++20150522030016 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE7BC9EF ++20150522030018 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE84579B ++20150522030019 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAE8A564B ++20150522030023 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAEAF7AD7 ++20150522030025 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAEB9DC53 ++20150522030027 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAECD976F ++20150522030034 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF07F063 ++20150522030034 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF08ACBB ++20150522030037 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF192C07 ++20150522030039 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF241333 ++20150522030040 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF255B3B ++20150522030044 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF3DEC37 ++20150522030048 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF60F05B ++20150522030049 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF6255DF ++20150522030055 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAF8EE01F ++20150522030059 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAFAD237B ++20150522030104 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAFD13587 ++20150522030105 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAFD2BE6F ++20150522030108 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAFECF32F ++20150522030112 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DAFFDEED7 ++20150522030115 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB01CAA63 ++20150522030116 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB01F3647 ++20150522030119 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB034B30F ++20150522030122 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB04822EF ++20150522030124 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0528867 ++20150522030131 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB08D3CAB ++20150522030136 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0B10C6F ++20150522030138 2 6 100 1535 5 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0C688A7 ++20150522030140 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0CCDF9B ++20150522030141 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0CFD81B ++20150522030145 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB0F59763 ++20150522030148 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB10339FB ++20150522030149 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB10E3ACB ++20150522030150 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB11127F3 ++20150522030159 2 6 100 1535 2 F4EE15F22E5F49997A027769656DF0240598C9470C7D67A7D7DA2777883C1C243A6F3D04E1CFA6A0350B165ECABE89A684C11ABB7E5B93B54FD6EAC85BBA9F23C6306E485BB9AC5515ABC739CE9B1A79F7DEF6D00B643856DB903E23E7F985EDCAFF867FE15498E7EF6A91057DE337A9AAEDE941C934E65243AC7888A33C78FB2490BBA2BA06F18ECC51DE9AA54BADD061CC5BE1EA060CC3217CA11E26772BD088898D2882CB49A9FF40168E49AE6A90EE1F61132E1B6E4E7F99797DB15B8BDB + 20160301052556 2 6 100 2047 5 DA57B18976E9C55CEAC3BFFF70419A1550258EA7359400BD4FAC8F4203B73E0BC54D62C0A2D9AA9B543FACA0290514EA426DE6FEF897CB858243511DCE5170420C799D888DCFDC4502FF49B66F34E75C00E98A55408A791FF5CFEA7C288F8E6664226A6A90BE237D2E40C207B5AD0CAEDFDA4946E63AEA351A09EF462515FED4098694241CD07E2CB7727B39B8B1B9467D72DFB908D8169F5DB3CD5A6BEBE1344C585A882508B760402E86EB9B5548A7B98635ECFCDC02FF62B29C53847142FC598ADC66F622F6E9F73BDF02B3D795C0DF23D00E5A3A7748F3E1D5B06F46D4568CE3F4CC57E67D4C36DF5C12800620698C727CC5F5BCACF3B7E17E37D19F4647 + 20160301052601 2 6 100 2047 2 DA57B18976E9C55CEAC3BFFF70419A1550258EA7359400BD4FAC8F4203B73E0BC54D62C0A2D9AA9B543FACA0290514EA426DE6FEF897CB858243511DCE5170420C799D888DCFDC4502FF49B66F34E75C00E98A55408A791FF5CFEA7C288F8E6664226A6A90BE237D2E40C207B5AD0CAEDFDA4946E63AEA351A09EF462515FED4098694241CD07E2CB7727B39B8B1B9467D72DFB908D8169F5DB3CD5A6BEBE1344C585A882508B760402E86EB9B5548A7B98635ECFCDC02FF62B29C53847142FC598ADC66F622F6E9F73BDF02B3D795C0DF23D00E5A3A7748F3E1D5B06F46D4568CE3F4CC57E67D4C36DF5C12800620698C727CC5F5BCACF3B7E17E37D1A5C13B + 20160301052612 2 6 100 2047 5 DA57B18976E9C55CEAC3BFFF70419A1550258EA7359400BD4FAC8F4203B73E0BC54D62C0A2D9AA9B543FACA0290514EA426DE6FEF897CB858243511DCE5170420C799D888DCFDC4502FF49B66F34E75C00E98A55408A791FF5CFEA7C288F8E6664226A6A90BE237D2E40C207B5AD0CAEDFDA4946E63AEA351A09EF462515FED4098694241CD07E2CB7727B39B8B1B9467D72DFB908D8169F5DB3CD5A6BEBE1344C585A882508B760402E86EB9B5548A7B98635ECFCDC02FF62B29C53847142FC598ADC66F622F6E9F73BDF02B3D795C0DF23D00E5A3A7748F3E1D5B06F46D4568CE3F4CC57E67D4C36DF5C12800620698C727CC5F5BCACF3B7E17E37D1B7A3EF +diff -up openssh-7.4p1/myproposal.h.legacy openssh-7.4p1/myproposal.h +--- openssh-7.4p1/myproposal.h.legacy 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/myproposal.h 2017-03-02 17:05:12.353352522 +0100 +@@ -96,34 +96,40 @@ + KEX_SHA2_METHODS + + #define KEX_SERVER_KEX KEX_COMMON_KEX \ ++ "diffie-hellman-group-exchange-sha1," \ + KEX_SHA2_GROUP14 \ +- "diffie-hellman-group14-sha1" \ ++ "diffie-hellman-group14-sha1," \ ++ "diffie-hellman-group1-sha1" + + #define KEX_CLIENT_KEX KEX_COMMON_KEX \ + "diffie-hellman-group-exchange-sha1," \ + KEX_SHA2_GROUP14 \ +- "diffie-hellman-group14-sha1" ++ "diffie-hellman-group14-sha1," \ ++ "diffie-hellman-group1-sha1" + + #define KEX_DEFAULT_PK_ALG \ + HOSTKEY_ECDSA_CERT_METHODS \ + "ssh-ed25519-cert-v01@openssh.com," \ + "ssh-rsa-cert-v01@openssh.com," \ ++ "ssh-dss-cert-v01@openssh.com," \ + HOSTKEY_ECDSA_METHODS \ + "ssh-ed25519," \ + "rsa-sha2-512," \ + "rsa-sha2-256," \ +- "ssh-rsa" ++ "ssh-rsa," \ ++ "ssh-dss" + + /* the actual algorithms */ + +-#define KEX_SERVER_ENCRYPT \ ++#define KEX_CLIENT_ENCRYPT \ + "chacha20-poly1305@openssh.com," \ + "aes128-ctr,aes192-ctr,aes256-ctr" \ +- AESGCM_CIPHER_MODES +- +-#define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT "," \ ++ AESGCM_CIPHER_MODES "," \ + "aes128-cbc,aes192-cbc,aes256-cbc" + ++#define KEX_SERVER_ENCRYPT KEX_CLIENT_ENCRYPT "," \ ++ "blowfish-cbc,cast128-cbc,3des-cbc" ++ + #define KEX_SERVER_MAC \ + "umac-64-etm@openssh.com," \ + "umac-128-etm@openssh.com," \ +diff -up openssh-7.4p1/ssh_config.5.legacy openssh-7.4p1/ssh_config.5 +--- openssh-7.4p1/ssh_config.5.legacy 2017-03-02 17:00:37.620696010 +0100 ++++ openssh-7.4p1/ssh_config.5 2017-03-02 17:00:37.642695983 +0100 +@@ -833,8 +833,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dss + .Ed + .Pp + The +@@ -856,8 +857,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dss + .Ed + .Pp + If hostkeys are known for the destination host then this default is modified +@@ -1075,7 +1077,8 @@ curve25519-sha256,curve25519-sha256@libs + ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, + diffie-hellman-group-exchange-sha256, + diffie-hellman-group-exchange-sha1, +-diffie-hellman-group14-sha1 ++diffie-hellman-group14-sha1, ++diffie-hellman-group1-sha1 + .Ed + .Pp + The list of available key exchange algorithms may also be obtained using +@@ -1313,8 +1316,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dsa + .Ed + .Pp + The list of available key types may also be obtained using +diff -up openssh-7.4p1/sshd_config.5.legacy openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.legacy 2017-03-02 17:00:37.636695990 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-03-02 17:04:17.528421067 +0100 +@@ -481,7 +481,9 @@ The default is: + .Bd -literal -offset indent + chacha20-poly1305@openssh.com, + aes128-ctr,aes192-ctr,aes256-ctr, +-aes128-gcm@openssh.com,aes256-gcm@openssh.com ++aes128-gcm@openssh.com,aes256-gcm@openssh.com, ++aes128-cbc,aes192-cbc,aes256-cbc, ++blowfish-cbc,cast128-cbc,3des-cbc + .Ed + .Pp + The list of available ciphers may also be obtained using +@@ -707,8 +709,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dss + .Ed + .Pp + The list of available key types may also be obtained using +@@ -785,8 +788,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dss + .Ed + .Pp + The list of available key types may also be obtained using +@@ -926,7 +930,8 @@ The default is: + curve25519-sha256,curve25519-sha256@libssh.org, + ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, + diffie-hellman-group-exchange-sha256, +-diffie-hellman-group14-sha1 ++diffie-hellman-group14-sha1, ++diffie-hellman-group1-sha1 + .Ed + .Pp + The list of available key exchange algorithms may also be obtained using +@@ -1040,7 +1045,8 @@ umac-64-etm@openssh.com,umac-128-etm@ope + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, + hmac-sha1-etm@openssh.com, + umac-64@openssh.com,umac-128@openssh.com, +-hmac-sha2-256,hmac-sha2-512,hmac-sha1 ++hmac-sha2-256,hmac-sha2-512,hmac-sha1, ++hmac-sha1-etm@openssh.com + .Ed + .Pp + The list of available MAC algorithms may also be obtained using +@@ -1344,8 +1350,9 @@ ecdsa-sha2-nistp384-cert-v01@openssh.com + ecdsa-sha2-nistp521-cert-v01@openssh.com, + ssh-ed25519-cert-v01@openssh.com, + ssh-rsa-cert-v01@openssh.com, ++ssh-dss-cert-v01@openssh.com, + ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-ssh-ed25519,ssh-rsa ++ssh-ed25519,ssh-rsa,ssh-dss + .Ed + .Pp + The list of available key types may also be obtained using diff --git a/SOURCES/openssh-7.4p1-legacy-ssh-copy-id.patch b/SOURCES/openssh-7.4p1-legacy-ssh-copy-id.patch new file mode 100644 index 0000000..c6770ff --- /dev/null +++ b/SOURCES/openssh-7.4p1-legacy-ssh-copy-id.patch @@ -0,0 +1,36 @@ +diff -up openssh-7.4p1/contrib/ssh-copy-id.1.legacy-ssh-copy-id openssh-7.4p1/contrib/ssh-copy-id.1 +--- openssh-7.4p1/contrib/ssh-copy-id.1.legacy-ssh-copy-id 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/contrib/ssh-copy-id.1 2017-02-09 09:23:25.366651136 +0100 +@@ -185,6 +185,19 @@ should prove enlightening (N.B. the mode + .Fl W + option, rather than + .Xr nc 1 ) . ++.Sh ENVIRONMENT ++.Bl -tag -width Ds ++.Pp ++.It Pa SSH_COPY_ID_LEGACY ++If the ++.Cm SSH_COPY_ID_LEGACY ++environment variable is set, the ++.Nm ++is run in a legacy mode. In this mode, the ++.Nm ++doesn't check an existence of a private key and doesn't do remote checks ++of the remote server versions or if public keys are already installed. ++.El + .Sh "SEE ALSO" + .Xr ssh 1 , + .Xr ssh-agent 1 , +diff -up openssh-7.4p1/contrib/ssh-copy-id.legacy-ssh-copy-id openssh-7.4p1/contrib/ssh-copy-id +--- openssh-7.4p1/contrib/ssh-copy-id.legacy-ssh-copy-id 2017-02-09 09:23:25.366651136 +0100 ++++ openssh-7.4p1/contrib/ssh-copy-id 2017-02-09 09:33:07.896518169 +0100 +@@ -99,6 +99,9 @@ if [ -n "$SSH_AUTH_SOCK" ] && ssh-add -L + GET_ID="ssh-add -L" + fi + ++# legacy environment variable implies forced copy ++[ "x$SSH_COPY_ID_LEGACY" != "x" ] && FORCED=1 ++ + while test "$#" -gt 0 + do + [ "${SEEN_OPT_I}" ] && expr "$1" : "[-]i" >/dev/null && { diff --git a/SOURCES/openssh-7.4p1-log-in-chroot.patch b/SOURCES/openssh-7.4p1-log-in-chroot.patch new file mode 100644 index 0000000..eedd198 --- /dev/null +++ b/SOURCES/openssh-7.4p1-log-in-chroot.patch @@ -0,0 +1,285 @@ +diff -up openssh-7.4p1/log.c.log-in-chroot openssh-7.4p1/log.c +--- openssh-7.4p1/log.c.log-in-chroot 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/log.c 2017-02-09 09:51:07.571909000 +0100 +@@ -250,6 +250,11 @@ debug3(const char *fmt,...) + void + log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) + { ++ log_init_handler(av0, level, facility, on_stderr, 1); ++} ++ ++void ++log_init_handler(char *av0, LogLevel level, SyslogFacility facility, int on_stderr, int reset_handler) { + #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) + struct syslog_data sdata = SYSLOG_DATA_INIT; + #endif +@@ -273,8 +278,10 @@ log_init(char *av0, LogLevel level, Sysl + exit(1); + } + +- log_handler = NULL; +- log_handler_ctx = NULL; ++ if (reset_handler) { ++ log_handler = NULL; ++ log_handler_ctx = NULL; ++ } + + log_on_stderr = on_stderr; + if (on_stderr) +diff -up openssh-7.4p1/log.h.log-in-chroot openssh-7.4p1/log.h +--- openssh-7.4p1/log.h.log-in-chroot 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/log.h 2017-02-09 09:51:07.571909000 +0100 +@@ -49,6 +49,7 @@ typedef enum { + typedef void (log_handler_fn)(LogLevel, const char *, void *); + + void log_init(char *, LogLevel, SyslogFacility, int); ++void log_init_handler(char *, LogLevel, SyslogFacility, int, int); + void 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 2017-02-09 09:51:07.554909017 +0100 ++++ openssh-7.4p1/monitor.c 2017-02-09 10:05:21.067174230 +0100 +@@ -307,6 +307,8 @@ monitor_child_preauth(Authctxt *_authctx + close(pmonitor->m_log_sendfd); + pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; + ++ pmonitor->m_state = "preauth"; ++ + authctxt = _authctxt; + memset(authctxt, 0, sizeof(*authctxt)); + +@@ -405,6 +407,8 @@ monitor_child_postauth(struct monitor *p + close(pmonitor->m_recvfd); + pmonitor->m_recvfd = -1; + ++ pmonitor->m_state = "postauth"; ++ + monitor_set_child_handler(pmonitor->m_pid); + signal(SIGHUP, &monitor_child_handler); + signal(SIGTERM, &monitor_child_handler); +@@ -472,7 +476,7 @@ monitor_read_log(struct monitor *pmonito + if (log_level_name(level) == NULL) + fatal("%s: invalid log level %u (corrupted message?)", + __func__, level); +- do_log2(level, "%s [preauth]", msg); ++ do_log2(level, "%s [%s]", msg, pmonitor->m_state); + + buffer_free(&logmsg); + free(msg); +@@ -1719,13 +1723,28 @@ monitor_init(void) + mon = xcalloc(1, sizeof(*mon)); + monitor_openfds(mon, 1); + ++ mon->m_state = ""; ++ + return mon; + } + + void +-monitor_reinit(struct monitor *mon) ++monitor_reinit(struct monitor *mon, const char *chroot_dir) + { +- monitor_openfds(mon, 0); ++ struct stat dev_log_stat; ++ char *dev_log_path; ++ int do_logfds = 0; ++ ++ if (chroot_dir != NULL) { ++ xasprintf(&dev_log_path, "%s/dev/log", chroot_dir); ++ ++ if (stat(dev_log_path, &dev_log_stat) != 0) { ++ debug("%s: /dev/log doesn't exist in %s chroot - will try to log via monitor using [postauth] suffix", __func__, chroot_dir); ++ do_logfds = 1; ++ } ++ free(dev_log_path); ++ } ++ monitor_openfds(mon, do_logfds); + } + + #ifdef GSSAPI +diff -up openssh-7.4p1/monitor.h.log-in-chroot openssh-7.4p1/monitor.h +--- openssh-7.4p1/monitor.h.log-in-chroot 2017-02-09 09:51:07.571909000 +0100 ++++ openssh-7.4p1/monitor.h 2017-02-09 10:05:49.792146561 +0100 +@@ -83,10 +83,11 @@ struct monitor { + int m_log_sendfd; + struct kex **m_pkex; + pid_t m_pid; ++ char *m_state; + }; + + struct monitor *monitor_init(void); +-void monitor_reinit(struct monitor *); ++void monitor_reinit(struct monitor *, const char *); + + struct Authctxt; + void monitor_child_preauth(struct Authctxt *, struct monitor *); +diff -up openssh-7.4p1/session.c.log-in-chroot openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.log-in-chroot 2017-02-09 09:51:07.570909002 +0100 ++++ openssh-7.4p1/session.c 2017-02-09 10:08:16.241005497 +0100 +@@ -160,6 +160,7 @@ login_cap_t *lc; + + static int is_child = 0; + static int in_chroot = 0; ++static int have_dev_log = 1; + + /* Name and directory of socket for authentication agent forwarding. */ + static char *auth_sock_name = NULL; +@@ -365,8 +366,8 @@ do_exec_no_pty(Session *s, const char *c + is_child = 1; + + /* Child. Reinitialize the log since the pid has changed. */ +- log_init(__progname, options.log_level, +- options.log_facility, log_stderr); ++ log_init_handler(__progname, options.log_level, ++ options.log_facility, log_stderr, have_dev_log); + + /* + * Create a new session and process group since the 4.4BSD +@@ -523,8 +524,8 @@ do_exec_pty(Session *s, const char *comm + close(ptymaster); + + /* Child. Reinitialize the log because the pid has changed. */ +- log_init(__progname, options.log_level, +- options.log_facility, log_stderr); ++ log_init_handler(__progname, options.log_level, ++ options.log_facility, log_stderr, have_dev_log); + /* Close the master side of the pseudo tty. */ + close(ptyfd); + +@@ -619,6 +620,7 @@ do_exec(Session *s, const char *command) + int ret; + const char *forced = NULL, *tty = NULL; + char session_type[1024]; ++ struct stat dev_log_stat; + + if (options.adm_forced_command) { + original_command = command; +@@ -676,6 +678,10 @@ do_exec(Session *s, const char *command) + tty += 5; + } + ++ if (lstat("/dev/log", &dev_log_stat) != 0) { ++ have_dev_log = 0; ++ } ++ + verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", + session_type, + tty == NULL ? "" : " on ", +@@ -1490,14 +1496,6 @@ child_close_fds(void) + * descriptors left by system functions. They will be closed later. + */ + endpwent(); +- +- /* +- * Close any extra open file descriptors so that we don't have them +- * hanging around in clients. Note that we want to do this after +- * initgroups, because at least on Solaris 2.3 it leaves file +- * descriptors open. +- */ +- closefrom(STDERR_FILENO + 1); + } + + /* +@@ -1633,8 +1631,6 @@ do_child(Session *s, const char *command + exit(1); + } + +- closefrom(STDERR_FILENO + 1); +- + do_rc_files(s, shell); + + /* restore SIGPIPE for child */ +@@ -1658,9 +1654,17 @@ do_child(Session *s, const char *command + argv[i] = NULL; + optind = optreset = 1; + __progname = argv[0]; +- exit(sftp_server_main(i, argv, s->pw)); ++ exit(sftp_server_main(i, argv, s->pw, have_dev_log)); + } + ++ /* ++ * Close any extra open file descriptors so that we don't have them ++ * hanging around in clients. Note that we want to do this after ++ * initgroups, because at least on Solaris 2.3 it leaves file ++ * descriptors open. ++ */ ++ closefrom(STDERR_FILENO + 1); ++ + fflush(NULL); + + /* Get the last component of the shell name. */ +diff -up openssh-7.4p1/sftp.h.log-in-chroot openssh-7.4p1/sftp.h +--- openssh-7.4p1/sftp.h.log-in-chroot 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sftp.h 2017-02-09 09:51:07.572908999 +0100 +@@ -97,5 +97,5 @@ + + struct passwd; + +-int sftp_server_main(int, char **, struct passwd *); ++int sftp_server_main(int, char **, struct passwd *, int); + void sftp_server_cleanup_exit(int) __attribute__((noreturn)); +diff -up openssh-7.4p1/sftp-server.c.log-in-chroot openssh-7.4p1/sftp-server.c +--- openssh-7.4p1/sftp-server.c.log-in-chroot 2017-02-09 09:51:07.572908999 +0100 ++++ openssh-7.4p1/sftp-server.c 2017-02-09 10:09:39.662925141 +0100 +@@ -1497,7 +1497,7 @@ sftp_server_usage(void) + } + + int +-sftp_server_main(int argc, char **argv, struct passwd *user_pw) ++sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler) + { + fd_set *rset, *wset; + int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0; +@@ -1511,7 +1511,7 @@ sftp_server_main(int argc, char **argv, + + ssh_malloc_init(); /* must be called before any mallocs */ + __progname = ssh_get_progname(argv[0]); +- log_init(__progname, log_level, log_facility, log_stderr); ++ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); + + pw = pwcopy(user_pw); + +@@ -1582,7 +1582,7 @@ sftp_server_main(int argc, char **argv, + } + } + +- log_init(__progname, log_level, log_facility, log_stderr); ++ log_init_handler(__progname, log_level, log_facility, log_stderr, reset_handler); + + /* + * On platforms where we can, avoid making /proc/self/{mem,maps} +diff -up openssh-7.4p1/sftp-server-main.c.log-in-chroot openssh-7.4p1/sftp-server-main.c +--- openssh-7.4p1/sftp-server-main.c.log-in-chroot 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sftp-server-main.c 2017-02-09 09:51:07.572908999 +0100 +@@ -49,5 +49,5 @@ main(int argc, char **argv) + return 1; + } + +- return (sftp_server_main(argc, argv, user_pw)); ++ return (sftp_server_main(argc, argv, user_pw, 0)); + } +diff -up openssh-7.4p1/sshd.c.log-in-chroot openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.log-in-chroot 2017-02-09 09:51:07.557909015 +0100 ++++ openssh-7.4p1/sshd.c 2017-02-09 09:51:07.573908998 +0100 +@@ -642,7 +642,7 @@ privsep_postauth(Authctxt *authctxt) + } + + /* New socket pair */ +- monitor_reinit(pmonitor); ++ monitor_reinit(pmonitor, options.chroot_directory); + + pmonitor->m_pid = fork(); + if (pmonitor->m_pid == -1) +@@ -660,6 +660,11 @@ privsep_postauth(Authctxt *authctxt) + + close(pmonitor->m_sendfd); + pmonitor->m_sendfd = -1; ++ close(pmonitor->m_log_recvfd); ++ pmonitor->m_log_recvfd = -1; ++ ++ if (pmonitor->m_log_sendfd != -1) ++ set_log_handler(mm_log_handler, pmonitor); + + /* Demote the private keys to public keys. */ + demote_sensitive_data(); diff --git a/SOURCES/openssh-7.4p1-newline-banner.patch b/SOURCES/openssh-7.4p1-newline-banner.patch new file mode 100644 index 0000000..32ff492 --- /dev/null +++ b/SOURCES/openssh-7.4p1-newline-banner.patch @@ -0,0 +1,22 @@ +diff -up openssh-7.4p1/sshd.c.newline-banner openssh-7.4p1/sshd.c +--- openssh-7.4p1/sshd.c.newline-banner 2017-02-17 14:00:47.237168594 +0100 ++++ openssh-7.4p1/sshd.c 2017-02-17 14:02:10.933096707 +0100 +@@ -369,15 +369,15 @@ sshd_exchange_identification(struct ssh + { + u_int i; + int remote_major, remote_minor; +- char *s, *newline = "\n"; ++ char *s; + char buf[256]; /* Must not be larger than remote_version. */ + char remote_version[256]; /* Must be at least as big as buf. */ + +- xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s%s", ++ xasprintf(&server_version_string, "SSH-%d.%d-%.100s%s%s\r\n", + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, + (options.show_patchlevel == 1) ? SSH_VENDOR_PATCHLEVEL : SSH_VERSION, + *options.version_addendum == '\0' ? "" : " ", +- options.version_addendum, newline); ++ options.version_addendum); + + /* Send our protocol version identification. */ + if (atomicio(vwrite, sock_out, server_version_string, diff --git a/SOURCES/openssh-7.4p1-permit-root-login.patch b/SOURCES/openssh-7.4p1-permit-root-login.patch new file mode 100644 index 0000000..3689fdd --- /dev/null +++ b/SOURCES/openssh-7.4p1-permit-root-login.patch @@ -0,0 +1,36 @@ +diff -up openssh-7.4p1/servconf.c.permit-root openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.permit-root 2017-02-10 10:27:18.109487568 +0100 ++++ openssh-7.4p1/servconf.c 2017-02-10 10:28:12.385776132 +0100 +@@ -231,7 +231,7 @@ fill_default_server_options(ServerOption + if (options->login_grace_time == -1) + options->login_grace_time = 120; + if (options->permit_root_login == PERMIT_NOT_SET) +- options->permit_root_login = PERMIT_NO_PASSWD; ++ options->permit_root_login = PERMIT_YES; + if (options->ignore_rhosts == -1) + options->ignore_rhosts = 1; + if (options->ignore_user_known_hosts == -1) +diff -up openssh-7.4p1/sshd_config.5.permit-root openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.permit-root 2017-02-10 10:28:24.174605582 +0100 ++++ openssh-7.4p1/sshd_config.5 2017-02-10 10:28:42.254344023 +0100 +@@ -1227,7 +1227,7 @@ The argument must be + or + .Cm no . + The default is +-.Cm prohibit-password . ++.Cm yes . + .Pp + If this option is set to + .Cm prohibit-password +diff -up openssh-7.4p1/sshd_config.permit-root openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.permit-root 2017-02-10 10:26:52.256797645 +0100 ++++ openssh-7.4p1/sshd_config 2017-02-10 10:26:52.276797405 +0100 +@@ -35,7 +35,7 @@ SyslogFacility AUTHPRIV + # Authentication: + + #LoginGraceTime 2m +-#PermitRootLogin prohibit-password ++#PermitRootLogin yes + #StrictModes yes + #MaxAuthTries 6 + #MaxSessions 10 diff --git a/SOURCES/openssh-7.4p1-pkcs11-whitelist.patch b/SOURCES/openssh-7.4p1-pkcs11-whitelist.patch new file mode 100644 index 0000000..36b4232 --- /dev/null +++ b/SOURCES/openssh-7.4p1-pkcs11-whitelist.patch @@ -0,0 +1,24 @@ +diff -up openssh-7.4p1/ssh-agent.1.pkcs11-whitelist openssh-7.4p1/ssh-agent.1 +--- openssh-7.4p1/ssh-agent.1.pkcs11-whitelist 2017-01-03 10:41:01.916331710 +0100 ++++ openssh-7.4p1/ssh-agent.1 2017-01-03 10:40:06.549366029 +0100 +@@ -129,7 +129,7 @@ that may be added using the + option to + .Xr ssh-add 1 . + The default is to allow loading PKCS#11 libraries from +-.Dq /usr/lib/*,/usr/local/lib/* . ++.Dq /usr/lib*/*,/usr/local/lib*/* . + PKCS#11 libraries that do not match the whitelist will be refused. + See PATTERNS in + .Xr ssh_config 5 +diff -up openssh-7.4p1/ssh-agent.c.pkcs11-whitelist openssh-7.4p1/ssh-agent.c +--- openssh-7.4p1/ssh-agent.c.pkcs11-whitelist 2017-01-03 10:41:09.324327118 +0100 ++++ openssh-7.4p1/ssh-agent.c 2017-01-03 10:40:21.212356939 +0100 +@@ -89,7 +89,7 @@ + #endif + + #ifndef DEFAULT_PKCS11_WHITELIST +-# define DEFAULT_PKCS11_WHITELIST "/usr/lib/*,/usr/local/lib/*" ++# define DEFAULT_PKCS11_WHITELIST "/usr/lib*/*,/usr/local/lib*/*" + #endif + + typedef enum { diff --git a/SOURCES/openssh-7.4p1-role-mls.patch b/SOURCES/openssh-7.4p1-role-mls.patch new file mode 100644 index 0000000..75c1710 --- /dev/null +++ b/SOURCES/openssh-7.4p1-role-mls.patch @@ -0,0 +1,840 @@ +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 2017-02-08 14:08:30.271308186 +0100 +@@ -215,6 +215,9 @@ input_userauth_request(int type, u_int32 + Authctxt *authctxt = ctxt; + 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 2017-02-08 14:08:30.270308187 +0100 +@@ -255,6 +255,7 @@ input_gssapi_mic(int type, u_int32_t ple + Authctxt *authctxt = ctxt; + 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); + + authctxt->postponed = 0; +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 2017-02-08 14:08:30.270308187 +0100 +@@ -121,7 +121,15 @@ userauth_hostbased(Authctxt *authctxt) + buffer_put_string(&b, session_id2, session_id2_len); + /* reconstruct packet */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); +- buffer_put_cstring(&b, authctxt->user); ++#ifdef WITH_SELINUX ++ if (authctxt->role) { ++ buffer_put_int(&b, strlen(authctxt->user)+strlen(authctxt->role)+1); ++ buffer_append(&b, authctxt->user, strlen(authctxt->user)); ++ buffer_put_char(&b, '/'); ++ buffer_append(&b, authctxt->role, strlen(authctxt->role)); ++ } else ++#endif ++ buffer_put_cstring(&b, authctxt->user); + buffer_put_cstring(&b, service); + buffer_put_cstring(&b, "hostbased"); + buffer_put_string(&b, pkalg, alen); +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 2017-02-08 14:08:30.270308187 +0100 +@@ -151,9 +151,11 @@ userauth_pubkey(Authctxt *authctxt) + } + /* reconstruct packet */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); +- 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 : "", ++ authctxt->role ? "/" : "", ++ authctxt->role ? authctxt->role : ""); + buffer_put_cstring(&b, userstyle); + free(userstyle); + buffer_put_cstring(&b, +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 2017-02-08 14:08:30.270308187 +0100 +@@ -62,6 +62,9 @@ struct Authctxt { + char *service; + struct passwd *pw; /* set if 'valid' */ + char *style; ++#ifdef WITH_SELINUX ++ char *role; ++#endif + void *kbdintctxt; + char *info; /* Extra info for next auth_log */ + #ifdef BSD_AUTH +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 2017-02-08 14:08:30.270308187 +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 2017-02-08 14:08:30.270308187 +0100 ++++ openssh-7.4p1/auth-pam.h 2017-02-08 14:09:09.711273302 +0100 +@@ -31,7 +31,7 @@ u_int do_pam_account(void); + void do_pam_session(void); + 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 2017-02-08 14:08:30.271308186 +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 2017-02-08 14:18:13.289928913 +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 2017-02-08 14:08:30.271308186 +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 2017-02-08 14:08:30.271308186 +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(Authctxt *authctxt, 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); + DH *mm_choose_dh(int, int, int); + int mm_key_sign(Key *, 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 Authctxt *, char *); +diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in +index 6ecfb93..b912dbe 100644 +--- a/openbsd-compat/Makefile.in ++++ b/openbsd-compat/Makefile.in +@@ -20,7 +20,7 @@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o di + + COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o + +-PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o ++PORTS=port-aix.o port-irix.o port-linux.o port-linux-sshd.o port-solaris.o port-tun.o port-uw.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 2017-02-08 14:08:30.272308185 +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) +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 2017-02-08 14:08:30.272308185 +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 2017-02-08 14:08:30.272308185 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2017-02-08 14:08:30.272308185 +0100 +@@ -0,0 +1,415 @@ ++/* ++ * 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 ++#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; ++ unsigned int bit = CONTEXT__CONTAINS; ++ ++ debug("%s: src:%s dst:%s", __func__, src, dst); ++ retval = security_compute_av(src, dst, SECCLASS_CONTEXT, 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 2017-02-08 14:08:30.272308185 +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 2017-02-08 14:08:30.273308184 +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); diff --git a/SOURCES/openssh-7.4p1-rsa1-segfault.patch b/SOURCES/openssh-7.4p1-rsa1-segfault.patch new file mode 100644 index 0000000..1128800 --- /dev/null +++ b/SOURCES/openssh-7.4p1-rsa1-segfault.patch @@ -0,0 +1,19 @@ +diff --git a/sshd.c b/sshd.c +--- a/sshd.c ++++ b/sshd.c +@@ -1551,6 +1551,15 @@ main(int ac, char **av) + continue; + key = key_load_private(options.host_key_files[i], "", NULL); + pubkey = key_load_public(options.host_key_files[i], NULL); ++ ++ if ((pubkey != NULL && pubkey->type == KEY_RSA1) || ++ (key != NULL && key->type == KEY_RSA1)) { ++ verbose("Ignoring RSA1 key %s", ++ options.host_key_files[i]); ++ key_free(key); ++ key_free(pubkey); ++ continue; ++ } + if (pubkey == NULL && key != NULL) + pubkey = key_demote(key); + sensitive_data.host_keys[i] = key; diff --git a/SOURCES/openssh-7.4p1-sandbox-ibmca.patch b/SOURCES/openssh-7.4p1-sandbox-ibmca.patch new file mode 100644 index 0000000..5479c65 --- /dev/null +++ b/SOURCES/openssh-7.4p1-sandbox-ibmca.patch @@ -0,0 +1,149 @@ +From 5f1596e11d55539678c41f68aed358628d33d86f Mon Sep 17 00:00:00 2001 +From: Damien Miller +Date: Tue, 14 Mar 2017 13:15:18 +1100 +Subject: [PATCH] support ioctls for ICA crypto card on Linux/s390 + +Based on patch from Eduardo Barretto; ok dtucker@ +--- + sandbox-seccomp-filter.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index af5525a..6ceee33 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -223,6 +223,12 @@ static const struct sock_filter preauth_insns[] = { + SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), + SC_DENY(socketcall, EACCES), + #endif ++#if defined(__NR_ioctl) && defined(__s390__) ++ /* Allow ioctls for ICA crypto card on s390 */ ++ SC_ALLOW_ARG(ioctl, 1, Z90STAT_STATUS_MASK), ++ SC_ALLOW_ARG(ioctl, 1, ICARSAMODEXPO), ++ SC_ALLOW_ARG(ioctl, 1, ICARSACRT), ++#endif /* defined(__NR_ioctl) && defined(__s390__) */ + + /* Default deny */ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), + +From 9e96b41682aed793fadbea5ccd472f862179fb02 Mon Sep 17 00:00:00 2001 +From: Damien Miller +Date: Tue, 14 Mar 2017 12:24:47 +1100 +Subject: [PATCH] Fix weakness in seccomp-bpf sandbox arg inspection + +Syscall arguments are passed via an array of 64-bit values in struct +seccomp_data, but we were only inspecting the bottom 32 bits and not +even those correctly for BE systems. + +Fortunately, the only case argument inspection was used was in the +socketcall filtering so using this for sandbox escape seems +impossible. + +ok dtucker +--- + sandbox-seccomp-filter.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index 2e1ed2c..af5525a 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -73,6 +73,16 @@ + # define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP + #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ + ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++# define ARG_LO_OFFSET 0 ++# define ARG_HI_OFFSET sizeof(uint32_t) ++#elif __BYTE_ORDER == __BIG_ENDIAN ++# define ARG_LO_OFFSET sizeof(uint32_t) ++# define ARG_HI_OFFSET 0 ++#else ++#error "Unknown endianness" ++#endif ++ + /* Simple helpers to avoid manual errors (but larger BPF programs). */ + #define SC_DENY(_nr, _errno) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ +@@ -81,11 +91,17 @@ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + #define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \ +- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 4), \ +- /* load first syscall argument */ \ ++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 6), \ ++ /* load and test first syscall argument, low word */ \ ++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ ++ offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \ ++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ ++ ((_arg_val) & 0xFFFFFFFF), 0, 3), \ ++ /* load and test first syscall argument, high word */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ +- offsetof(struct seccomp_data, args[(_arg_nr)])), \ +- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_arg_val), 0, 1), \ ++ offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \ ++ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \ ++ (((uint32_t)((uint64_t)(_arg_val) >> 32)) & 0xFFFFFFFF), 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \ + /* reload syscall number; all rules expect it in accumulator */ \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + +From 58b8cfa2a062b72139d7229ae8de567f55776f24 Mon Sep 17 00:00:00 2001 +From: Damien Miller +Date: Wed, 22 Mar 2017 12:43:02 +1100 +Subject: [PATCH] Missing header on Linux/s390 + +Patch from Jakub Jelen +--- + sandbox-seccomp-filter.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index a8d472a..2831e9d 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -50,6 +50,9 @@ + #include + + #include ++#ifdef __s390__ ++#include ++#endif + + #include + #include + +getuid and geteuid are needed when using an openssl engine that calls a +crypto card, e.g. ICA (libica). +Those syscalls are also needed by the distros for audit code. + +Signed-off-by: Eduardo Barretto +--- + sandbox-seccomp-filter.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index 6e7de31..e86aa2c 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -175,6 +175,18 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_getpid + SC_ALLOW(getpid), + #endif ++#ifdef __NR_getuid ++ SC_ALLOW(getuid), ++#endif ++#ifdef __NR_getuid32 ++ SC_ALLOW(getuid32), ++#endif ++#ifdef __NR_geteuid ++ SC_ALLOW(geteuid), ++#endif ++#ifdef __NR_geteuid32 ++ SC_ALLOW(geteuid32), ++#endif + #ifdef __NR_getrandom + SC_ALLOW(getrandom), + #endif +-- +1.9.1 diff --git a/SOURCES/openssh-7.4p1-sandbox-ppc64le.patch b/SOURCES/openssh-7.4p1-sandbox-ppc64le.patch new file mode 100644 index 0000000..09eae99 --- /dev/null +++ b/SOURCES/openssh-7.4p1-sandbox-ppc64le.patch @@ -0,0 +1,11 @@ +diff -up openssh-7.4p1/sandbox-seccomp-filter.c.sandbox openssh-7.4p1/sandbox-seccomp-filter.c +--- openssh-7.4p1/sandbox-seccomp-filter.c.sandbox 2017-04-21 13:30:49.692650798 +0200 ++++ openssh-7.4p1/sandbox-seccomp-filter.c 2017-04-21 13:30:52.259647579 +0200 +@@ -215,6 +215,7 @@ static const struct sock_filter preauth_ + #endif + #ifdef __NR_socketcall + SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), ++ SC_DENY(socketcall, EACCES), + #endif + + /* Default deny */ diff --git a/SOURCES/openssh-7.4p1-sha2-signatures.patch b/SOURCES/openssh-7.4p1-sha2-signatures.patch new file mode 100644 index 0000000..951e641 --- /dev/null +++ b/SOURCES/openssh-7.4p1-sha2-signatures.patch @@ -0,0 +1,28 @@ +diff -up openssh-7.4p1/kex.c.sha2 openssh-7.4p1/kex.c +--- openssh-7.4p1/kex.c.sha2 2017-02-17 18:15:53.589835864 +0100 ++++ openssh-7.4p1/kex.c 2017-02-17 18:17:20.404781663 +0100 +@@ -379,21 +379,14 @@ static int + kex_send_ext_info(struct ssh *ssh) + { + int r; +- char *algs; + +- if ((algs = sshkey_alg_list(0, 1, ',')) == NULL) +- return SSH_ERR_ALLOC_FAIL; + if ((r = sshpkt_start(ssh, SSH2_MSG_EXT_INFO)) != 0 || + (r = sshpkt_put_u32(ssh, 1)) != 0 || + (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || +- (r = sshpkt_put_cstring(ssh, algs)) != 0 || ++ (r = sshpkt_put_cstring(ssh, "rsa-sha2-256,rsa-sha2-512")) != 0 || + (r = sshpkt_send(ssh)) != 0) +- goto out; +- /* success */ +- r = 0; +- out: +- free(algs); +- return r; ++ return r; ++ return 0; + } + + int diff --git a/SOURCES/openssh-7.4p1-show-more-fingerprints.patch b/SOURCES/openssh-7.4p1-show-more-fingerprints.patch new file mode 100644 index 0000000..570f11c --- /dev/null +++ b/SOURCES/openssh-7.4p1-show-more-fingerprints.patch @@ -0,0 +1,315 @@ +diff -up openssh-7.4p1/clientloop.c.fingerprint openssh-7.4p1/clientloop.c +--- openssh-7.4p1/clientloop.c.fingerprint 2016-12-23 15:38:50.520432387 +0100 ++++ openssh-7.4p1/clientloop.c 2016-12-23 15:38:50.564432394 +0100 +@@ -2279,7 +2279,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); +@@ -2287,7 +2287,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); +@@ -2330,7 +2330,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)); + } +@@ -2443,7 +2443,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-7.4p1/readconf.c.fingerprint openssh-7.4p1/readconf.c +--- openssh-7.4p1/readconf.c.fingerprint 2016-12-23 15:38:50.559432393 +0100 ++++ openssh-7.4p1/readconf.c 2016-12-23 15:38:50.565432394 +0100 +@@ -1668,16 +1668,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: +@@ -1905,7 +1907,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; +@@ -2102,8 +2104,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++] = (FIPS_mode() ? SSH_DIGEST_SHA1 : SSH_DIGEST_MD5); ++ } + if (options->update_hostkeys == -1) + options->update_hostkeys = 0; + if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || +@@ -2489,6 +2493,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; +@@ -2564,7 +2579,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); +@@ -2634,6 +2648,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-7.4p1/readconf.h.fingerprint openssh-7.4p1/readconf.h +--- openssh-7.4p1/readconf.h.fingerprint 2016-12-23 15:38:50.559432393 +0100 ++++ openssh-7.4p1/readconf.h 2016-12-23 15:38:50.565432394 +0100 +@@ -21,6 +21,7 @@ + #define MAX_SEND_ENV 256 + #define SSH_MAX_HOSTS_FILES 32 + #define MAX_CANON_DOMAINS 32 ++#define MAX_SSH_DIGESTS 8 + #define PATH_MAX_SUN (sizeof((struct sockaddr_un *)0)->sun_path) + + struct allowed_cname { +@@ -162,7 +163,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-7.4p1/ssh_config.5.fingerprint openssh-7.4p1/ssh_config.5 +--- openssh-7.4p1/ssh_config.5.fingerprint 2016-12-23 15:38:50.565432394 +0100 ++++ openssh-7.4p1/ssh_config.5 2016-12-23 15:40:03.754444166 +0100 +@@ -652,12 +652,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-7.4p1/sshconnect2.c.fingerprint openssh-7.4p1/sshconnect2.c +--- openssh-7.4p1/sshconnect2.c.fingerprint 2016-12-23 15:38:50.561432394 +0100 ++++ openssh-7.4p1/sshconnect2.c 2016-12-23 15:38:50.566432394 +0100 +@@ -677,7 +677,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); +@@ -1172,7 +1172,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); +@@ -1864,7 +1864,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-7.4p1/sshconnect.c.fingerprint openssh-7.4p1/sshconnect.c +--- openssh-7.4p1/sshconnect.c.fingerprint 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/sshconnect.c 2016-12-23 15:38:50.566432394 +0100 +@@ -922,9 +922,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); +@@ -966,12 +966,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) +@@ -985,16 +979,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 */ +@@ -1244,7 +1250,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; +@@ -1252,7 +1258,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; +@@ -1432,9 +1438,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" +@@ -1457,7 +1463,7 @@ warn_changed_key(Key *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-7.4p1/ssh-keysign.c.fingerprint openssh-7.4p1/ssh-keysign.c +--- openssh-7.4p1/ssh-keysign.c.fingerprint 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/ssh-keysign.c 2016-12-23 15:38:50.566432394 +0100 +@@ -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/SOURCES/pam_ssh_agent-rmheaders b/SOURCES/pam_ssh_agent-rmheaders index 5f036cc..06d899d 100644 --- a/SOURCES/pam_ssh_agent-rmheaders +++ b/SOURCES/pam_ssh_agent-rmheaders @@ -1,20 +1,37 @@ -atomicio.h +authfd.c authfd.h +atomicio.c +atomicio.h +bufaux.c +bufbn.c buffer.h +buffer.c +cleanup.c cipher.h compat.h defines.h +entropy.c entropy.h +fatal.c includes.h kex.h +key.c key.h +log.c log.h match.h +misc.c misc.h pathnames.h platform.h rsa.h +ssh-dss.c +ssh-rsa.c ssh.h ssh2.h +uidswap.c +uidswap.h +uuencode.c uuencode.h +xmalloc.c xmalloc.h diff --git a/SOURCES/pam_ssh_agent_auth-0.10.3-agent_structure.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-agent_structure.patch new file mode 100644 index 0000000..91e1c3d --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-agent_structure.patch @@ -0,0 +1,690 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-agent 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-agent 2017-02-14 10:19:16.466070259 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c 2017-02-14 10:26:10.062866980 +0100 +@@ -65,8 +65,8 @@ proc_pid_cmdline(char *** inargv) + case EOF: + case '\0': + if (len > 0) { +- argv = pamsshagentauth_xrealloc(argv, count + 1, sizeof(*argv)); +- argv[count] = pamsshagentauth_xcalloc(len + 1, sizeof(*argv[count])); ++ argv = xrealloc(argv, count + 1, sizeof(*argv)); ++ argv[count] = xcalloc(len + 1, sizeof(*argv[count])); + strncpy(argv[count++], argbuf, len); + memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); + len = 0; +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent openssh-7.4p1/pam_ssh_agent_auth-0.10.3/identity.h +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/identity.h 2017-02-14 10:19:12.225071868 +0100 +@@ -38,6 +38,12 @@ + typedef struct identity Identity; + typedef struct idlist Idlist; + ++typedef struct { ++ int fd; ++ Buffer identities; ++ int howmany; ++} AuthenticationConnection; ++ + struct identity { + TAILQ_ENTRY(identity) next; + AuthenticationConnection *ac; /* set if agent supports key */ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent 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-agent 2017-02-14 10:19:12.224071868 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-14 10:19:12.226071867 +0100 +@@ -52,12 +52,15 @@ + #include + #include "ssh2.h" + #include "misc.h" ++#include "ssherr.h" + + #include "userauth_pubkey_from_id.h" + #include "identity.h" + #include "get_command_line.h" + extern char **environ; + ++#define PAM_SSH_AGENT_AUTH_REQUESTv1 101 ++ + static char * + log_action(char ** action, size_t count) + { +@@ -67,7 +70,7 @@ log_action(char ** action, size_t count) + if (count == 0) + return NULL; + +- buf = pamsshagentauth_xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); ++ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); + for (i = 0; i < count; i++) { + strcat(buf, (i > 0) ? " '" : "'"); + strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); +@@ -80,12 +83,12 @@ void + agent_action(Buffer *buf, char ** action, size_t count) + { + size_t i; +- pamsshagentauth_buffer_init(buf); ++ buffer_init(buf); + +- pamsshagentauth_buffer_put_int(buf, count); ++ buffer_put_int(buf, count); + + for (i = 0; i < count; i++) { +- pamsshagentauth_buffer_put_cstring(buf, action[i]); ++ buffer_put_cstring(buf, action[i]); + } + } + +@@ -109,17 +112,17 @@ pamsshagentauth_session_id2_gen(Buffer * + char * retc; + int32_t reti; + +- rnd = pamsshagentauth_arc4random(); ++ rnd = arc4random(); + cookie_len = ((uint8_t) rnd); + while (cookie_len < 16) { + cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */ + } + +- cookie = pamsshagentauth_xcalloc(1,cookie_len); ++ cookie = xcalloc(1,cookie_len); + + for (i = 0; i < cookie_len; i++) { + if (i % 4 == 0) { +- rnd = pamsshagentauth_arc4random(); ++ rnd = arc4random(); + } + cookie[i] = (char) rnd; + rnd >>= 8; +@@ -134,7 +137,7 @@ pamsshagentauth_session_id2_gen(Buffer * + } + else { + action_logbuf = "unknown on this platform"; +- pamsshagentauth_buffer_init(&action_agentbuf); /* stays empty, means unavailable */ ++ buffer_init(&action_agentbuf); /* stays empty, means unavailable */ + } + + /* +@@ -151,35 +154,35 @@ pamsshagentauth_session_id2_gen(Buffer * + retc = getcwd(pwd, sizeof(pwd) - 1); + time(&ts); + +- pamsshagentauth_buffer_init(session_id2); ++ buffer_init(session_id2); + +- pamsshagentauth_buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); +- /* pamsshagentauth_debug3("cookie: %s", pamsshagentauth_tohex(cookie, cookie_len)); */ +- pamsshagentauth_buffer_put_string(session_id2, cookie, cookie_len); +- /* pamsshagentauth_debug3("user: %s", user); */ +- pamsshagentauth_buffer_put_cstring(session_id2, user); +- /* pamsshagentauth_debug3("ruser: %s", ruser); */ +- pamsshagentauth_buffer_put_cstring(session_id2, ruser); +- /* 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) +- pamsshagentauth_buffer_put_cstring(session_id2, pwd); ++ buffer_put_cstring(session_id2, pwd); + 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 (free_logbuf) { + free(action_logbuf); +- pamsshagentauth_buffer_free(&action_agentbuf); ++ buffer_free(&action_agentbuf); + } +- /* pamsshagentauth_debug3("hostname: %s", hostname); */ ++ /* debug3("hostname: %s", hostname); */ + if(reti >= 0) +- pamsshagentauth_buffer_put_cstring(session_id2, hostname); ++ buffer_put_cstring(session_id2, hostname); + 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("ts: %ld", ts); */ ++ buffer_put_int64(session_id2, (uint64_t) ts); + + free(cookie); + return; +@@ -288,39 +291,47 @@ pamsshagentauth_find_authorized_keys(con + { + Buffer session_id2 = { 0 }; + Identity *id; +- Key *key; + AuthenticationConnection *ac; +- char *comment; + uint8_t retval = 0; + uid_t uid = getpwnam(ruser)->pw_uid; ++ struct ssh_identitylist *idlist; ++ int r; ++ unsigned int i; + + OpenSSL_add_all_digests(); + 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); +- for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) ++ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); ++ if ((r = ssh_fetch_identitylist(ac->fd, 2, ++ &idlist)) != 0) { ++ if (r != SSH_ERR_AGENT_NO_IDENTITIES) ++ fprintf(stderr, "error fetching identities for " ++ "protocol %d: %s\n", 2, ssh_err(r)); ++ } else { ++ for (i = 0; i < idlist->nkeys; i++) + { +- if(key != NULL) { +- id = pamsshagentauth_xcalloc(1, sizeof(*id)); +- id->key = key; +- id->filename = comment; ++ if(idlist->keys[i] != NULL) { ++ id = xcalloc(1, sizeof(*id)); ++ id->key = idlist->keys[i]; ++ id->filename = idlist->comments[i]; + id->ac = ac; + if(userauth_pubkey_from_id(ruser, id, &session_id2)) { + retval = 1; + } +- free(id->filename); +- pamsshagentauth_key_free(id->key); + free(id); + if(retval == 1) + break; + } + } +- pamsshagentauth_buffer_free(&session_id2); +- ssh_close_authentication_connection(ac); ++ buffer_free(&session_id2); ++ ssh_free_identitylist(idlist); ++ ssh_close_authentication_socket(ac->fd); ++ free(ac); ++ } + } + else { +- pamsshagentauth_verbose("No ssh-agent could be contacted"); ++ verbose("No ssh-agent could be contacted"); + } + /* pamsshagentauth_xfree(session_id2); */ + EVP_cleanup(); +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c.psaa-agent 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-agent 2017-02-14 10:19:12.223071868 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_ssh_agent_auth.c 2017-02-14 10:19:12.226071867 +0100 +@@ -104,7 +104,7 @@ pam_sm_authenticate(pam_handle_t * pamh, + * a patch 8-) + */ + #if ! HAVE___PROGNAME || HAVE_BUNDLE +- __progname = pamsshagentauth_xstrdup(servicename); ++ __progname = xstrdup(servicename); + #endif + + for(i = argc, argv_ptr = (char **) argv; i > 0; ++argv_ptr, i--) { +@@ -130,11 +130,11 @@ pam_sm_authenticate(pam_handle_t * pamh, + #endif + } + +- pamsshagentauth_log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); ++ log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); + pam_get_item(pamh, PAM_USER, (void *) &user); + pam_get_item(pamh, PAM_RUSER, (void *) &ruser_ptr); + +- pamsshagentauth_verbose("Beginning pam_ssh_agent_auth for user %s", user); ++ verbose("Beginning pam_ssh_agent_auth for user %s", user); + + if(ruser_ptr) { + strncpy(ruser, ruser_ptr, sizeof(ruser) - 1); +@@ -149,12 +149,12 @@ pam_sm_authenticate(pam_handle_t * pamh, + #ifdef ENABLE_SUDO_HACK + if( (strlen(sudo_service_name) > 0) && strncasecmp(servicename, sudo_service_name, sizeof(sudo_service_name) - 1) == 0 && getenv("SUDO_USER") ) { + strncpy(ruser, getenv("SUDO_USER"), sizeof(ruser) - 1 ); +- pamsshagentauth_verbose( "Using environment variable SUDO_USER (%s)", ruser ); ++ verbose( "Using environment variable SUDO_USER (%s)", ruser ); + } else + #endif + { + if( ! getpwuid(getuid()) ) { +- pamsshagentauth_verbose("Unable to getpwuid(getuid())"); ++ verbose("Unable to getpwuid(getuid())"); + goto cleanexit; + } + strncpy(ruser, getpwuid(getuid())->pw_name, sizeof(ruser) - 1); +@@ -163,11 +163,11 @@ pam_sm_authenticate(pam_handle_t * pamh, + + /* Might as well explicitely confirm the user exists here */ + if(! getpwnam(ruser) ) { +- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", ruser); ++ verbose("getpwnam(%s) failed, bailing out", ruser); + goto cleanexit; + } + if( ! getpwnam(user) ) { +- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", user); ++ verbose("getpwnam(%s) failed, bailing out", user); + goto cleanexit; + } + +@@ -177,8 +177,8 @@ pam_sm_authenticate(pam_handle_t * pamh, + */ + parse_authorized_key_file(user, authorized_keys_file_input); + } else { +- pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys"); +- authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys"); ++ verbose("Using default file=/etc/security/authorized_keys"); ++ authorized_keys_file = xstrdup("/etc/security/authorized_keys"); + } + + /* +@@ -187,19 +187,19 @@ pam_sm_authenticate(pam_handle_t * pamh, + */ + + if(user && strlen(ruser) > 0) { +- pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); + + /* + * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user + */ + if(pamsshagentauth_find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */ +- pamsshagentauth_logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file); + retval = PAM_SUCCESS; + } else { +- pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); + } + } else { +- pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); ++ logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); + } + + cleanexit: +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_authorized_keys.c.psaa-agent 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-agent 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-14 10:19:12.226071867 +0100 +@@ -117,12 +117,12 @@ parse_authorized_key_file(const char *us + } else { + slash_ptr = strchr(auth_keys_file_buf, '/'); + if(!slash_ptr) +- pamsshagentauth_fatal ++ fatal + ("cannot expand tilde in path without a `/'"); + + owner_uname_len = slash_ptr - auth_keys_file_buf - 1; + if(owner_uname_len > (sizeof(owner_uname) - 1)) +- pamsshagentauth_fatal("Username too long"); ++ fatal("Username too long"); + + 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 + getpwnam(owner_uname)->pw_uid; + } + authorized_keys_file = +- pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, ++ tilde_expand_filename(auth_keys_file_buf, + authorized_keys_file_allowed_owner_uid); + strncpy(auth_keys_file_buf, authorized_keys_file, + sizeof(auth_keys_file_buf) - 1); +- pamsshagentauth_xfree(authorized_keys_file) /* when we ++ free(authorized_keys_file) /* when we + percent_expand + later, we'd step + on this, so free +@@ -150,7 +150,7 @@ parse_authorized_key_file(const char *us + strncat(hostname, fqdn, strcspn(fqdn, ".")); + #endif + authorized_keys_file = +- pamsshagentauth_percent_expand(auth_keys_file_buf, "h", ++ percent_expand(auth_keys_file_buf, "h", + 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-agent 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-agent 2017-02-14 10:19:12.224071868 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2017-02-14 10:19:12.226071867 +0100 +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -53,6 +54,7 @@ + #include "misc.h" + #include "secure_filename.h" + #include "uidswap.h" ++#include "digest.h" + + #include "identity.h" + +@@ -68,7 +70,7 @@ pamsshagentauth_check_authkeys_file(FILE + char *fp; + + found_key = 0; +- found = pamsshagentauth_key_new(key->type); ++ found = key_new(key->type); + + while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { + char *cp = NULL; /* *key_options = NULL; */ +@@ -78,11 +80,11 @@ pamsshagentauth_check_authkeys_file(FILE + if(!*cp || *cp == '\n' || *cp == '#') + continue; + +- if(pamsshagentauth_key_read(found, &cp) != 1) { ++ if(key_read(found, &cp) != 1) { + /* no key? check if there are options for this key */ + int quoted = 0; + +- pamsshagentauth_verbose("user_key_allowed: check options: '%s'", cp); ++ verbose("user_key_allowed: check options: '%s'", cp); + /* key_options = cp; */ + for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if(*cp == '\\' && cp[1] == '"') +@@ -92,26 +94,26 @@ 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) { ++ 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)) { + found_key = 1; +- pamsshagentauth_logit("matching key found: file/command %s, line %lu", file, ++ logit("matching key found: file/command %s, line %lu", file, + linenum); +- fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); +- pamsshagentauth_logit("Found matching %s key: %s", +- pamsshagentauth_key_type(found), fp); ++ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); ++ logit("Found matching %s key: %s", ++ key_type(found), fp); + free(fp); + break; + } + } +- pamsshagentauth_key_free(found); ++ key_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]; + + /* Temporarily use the user's uid. */ +- pamsshagentauth_verbose("trying public key file %s", file); ++ verbose("trying public key file %s", file); + + /* Fail not so quietly if file does not exist */ + if(stat(file, &st) < 0) { +- pamsshagentauth_verbose("File not found: %s", file); ++ verbose("File not found: %s", file); + return 0; + } + +@@ -144,7 +146,7 @@ pamsshagentauth_user_key_allowed2(struct + + if(pamsshagentauth_secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { + fclose(f); +- pamsshagentauth_logit("Authentication refused: %s", buf); ++ logit("Authentication refused: %s", buf); + return 0; + } + +@@ -187,44 +189,44 @@ pamsshagentauth_user_key_command_allowed + else { + pw = getpwnam(authorized_keys_command_user); + if(pw == NULL) { +- pamsshagentauth_logerror("authorized_keys_command_user \"%s\" not found: %s", ++ error("authorized_keys_command_user \"%s\" not found: %s", + authorized_keys_command_user, strerror(errno)); + return 0; + } + } + +- pamsshagentauth_temporarily_use_uid(pw); ++ temporarily_use_uid(pw); + + if(stat(authorized_keys_command, &st) < 0) { +- pamsshagentauth_logerror ++ error + ("Could not stat AuthorizedKeysCommand \"%s\": %s", + authorized_keys_command, strerror(errno)); + goto out; + } + if(pamsshagentauth_auth_secure_path + (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { +- pamsshagentauth_logerror("Unsafe AuthorizedKeysCommand: %s", errmsg); ++ error("Unsafe AuthorizedKeysCommand: %s", errmsg); + goto out; + } + + /* open the pipe and read the keys */ + if(pipe(p) != 0) { +- pamsshagentauth_logerror("%s: pipe: %s", __func__, strerror(errno)); ++ error("%s: pipe: %s", __func__, strerror(errno)); + goto out; + } + +- pamsshagentauth_debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", ++ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", + authorized_keys_command, pw->pw_name, username); + + /* + * Don't want to call this in the child, where it can fatal() and + * run cleanup_exit() code. + */ +- pamsshagentauth_restore_uid(); ++ restore_uid(); + + switch ((pid = fork())) { + case -1: /* error */ +- pamsshagentauth_logerror("%s: fork: %s", __func__, strerror(errno)); ++ error("%s: fork: %s", __func__, strerror(errno)); + close(p[0]); + close(p[1]); + return 0; +@@ -234,13 +236,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) { +- pamsshagentauth_logerror("%s: open %s: %s", __func__, _PATH_DEVNULL, ++ error("%s: open %s: %s", __func__, _PATH_DEVNULL, + strerror(errno)); + _exit(1); + } + if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1 + || dup2(devnull, STDERR_FILENO) == -1) { +- pamsshagentauth_logerror("%s: dup2: %s", __func__, strerror(errno)); ++ error("%s: dup2: %s", __func__, strerror(errno)); + _exit(1); + } + #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) +@@ -248,7 +250,7 @@ pamsshagentauth_user_key_command_allowed + #else + if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { + #endif +- pamsshagentauth_logerror("setresgid %u: %s", (u_int) pw->pw_gid, ++ error("setresgid %u: %s", (u_int) pw->pw_gid, + strerror(errno)); + _exit(1); + } +@@ -258,7 +260,7 @@ pamsshagentauth_user_key_command_allowed + #else + if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { + #endif +- pamsshagentauth_logerror("setresuid %u: %s", (u_int) pw->pw_uid, ++ error("setresuid %u: %s", (u_int) pw->pw_uid, + strerror(errno)); + _exit(1); + } +@@ -270,18 +272,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 */ +- pamsshagentauth_logerror("AuthorizedKeysCommand %s exec failed: %s", ++ error("AuthorizedKeysCommand %s exec failed: %s", + authorized_keys_command, strerror(errno)); + _exit(127); + default: /* parent */ + break; + } + +- pamsshagentauth_temporarily_use_uid(pw); ++ temporarily_use_uid(pw); + + close(p[1]); + if((f = fdopen(p[0], "r")) == NULL) { +- pamsshagentauth_logerror("%s: fdopen: %s", __func__, strerror(errno)); ++ error("%s: fdopen: %s", __func__, strerror(errno)); + 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 + + while(waitpid(pid, &status, 0) == -1) { + if(errno != EINTR) { +- pamsshagentauth_logerror("%s: waitpid: %s", __func__, ++ error("%s: waitpid: %s", __func__, + strerror(errno)); + goto out; + } + } + if(WIFSIGNALED(status)) { +- pamsshagentauth_logerror("AuthorizedKeysCommand %s exited on signal %d", ++ error("AuthorizedKeysCommand %s exited on signal %d", + authorized_keys_command, WTERMSIG(status)); + goto out; + } else if(WEXITSTATUS(status) != 0) { +- pamsshagentauth_logerror("AuthorizedKeysCommand %s returned status %d", ++ error("AuthorizedKeysCommand %s returned status %d", + authorized_keys_command, WEXITSTATUS(status)); + goto out; + } + found_key = ok; + out: +- pamsshagentauth_restore_uid(); ++ restore_uid(); + return found_key; + } +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c.psaa-agent 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-agent 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/secure_filename.c 2017-02-14 10:19:12.226071867 +0100 +@@ -80,7 +80,7 @@ pamsshagentauth_auth_secure_path(const c + int comparehome = 0; + struct stat st; + +- pamsshagentauth_verbose("auth_secure_filename: checking for uid: %u", uid); ++ verbose("auth_secure_filename: checking for uid: %u", uid); + + if (realpath(name, buf) == NULL) { + snprintf(err, errlen, "realpath %s failed: %s", name, +@@ -115,9 +115,9 @@ pamsshagentauth_auth_secure_path(const c + snprintf(err, errlen, "dirname() failed"); + return -1; + } +- pamsshagentauth_strlcpy(buf, cp, sizeof(buf)); ++ strlcpy(buf, cp, sizeof(buf)); + +- pamsshagentauth_verbose("secure_filename: checking '%s'", buf); ++ verbose("secure_filename: checking '%s'", buf); + if (stat(buf, &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { +@@ -128,7 +128,7 @@ pamsshagentauth_auth_secure_path(const c + + /* If are passed the homedir then we can stop */ + if (comparehome && strcmp(homedir, buf) == 0) { +- pamsshagentauth_verbose("secure_filename: terminating check at '%s'", ++ verbose("secure_filename: terminating check at '%s'", + buf); + break; + } +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent 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-agent 2017-02-14 10:19:12.224071868 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-02-14 10:19:12.226071867 +0100 +@@ -48,6 +48,8 @@ + #include "identity.h" + #include "pam_user_authorized_keys.h" + ++#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54 ++ + /* extern u_char *session_id2; + extern uint8_t session_id_len; + */ +@@ -58,7 +60,8 @@ userauth_pubkey_from_id(const char *ruse + Buffer b = { 0 }; + 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); +@@ -67,31 +70,31 @@ userauth_pubkey_from_id(const char *ruse + if(! pam_user_key_allowed(ruser, id->key)) + goto user_auth_clean_exit; + +- if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) ++ if(key_to_blob(id->key, &pkblob, &blen) == 0) + goto user_auth_clean_exit; + + /* construct packet to sign and test */ +- pamsshagentauth_buffer_init(&b); ++ buffer_init(&b); + +- 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); +- pamsshagentauth_buffer_put_cstring(&b, ruser); +- pamsshagentauth_buffer_put_cstring(&b, "pam_ssh_agent_auth"); +- pamsshagentauth_buffer_put_cstring(&b, "publickey"); +- 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(ssh_agent_sign(id->ac, id->key, &sig, &slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) != 0) ++ if(ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, buffer_ptr(&b), buffer_len(&b), NULL, 0) != 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) + authenticated = 1; + + user_auth_clean_exit: + /* if(&b != NULL) */ +- pamsshagentauth_buffer_free(&b); ++ buffer_free(&b); + if(sig != NULL) + free(sig); + if(pkblob != NULL) diff --git a/SOURCES/pam_ssh_agent_auth-0.10.3-build.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-build.patch new file mode 100644 index 0000000..18b4078 --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-build.patch @@ -0,0 +1,177 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build 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-build 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-13 16:06:17.468680048 +0100 +@@ -39,6 +39,15 @@ + #include "buffer.h" + #include "key.h" + #include "authfd.h" ++#include "ssh.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + #include + #include + #include "ssh2.h" +@@ -176,6 +185,96 @@ pamsshagentauth_session_id2_gen(Buffer * + return; + } + ++/* ++ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user ++ * A cursory check is done, but to avoid race conditions, it is necessary ++ * to drop effective UID when connecting to the socket. ++ * ++ * If the cause of error is EACCES, because we verified we would not have that ++ * problem initially, we can safely assume that somebody is attempting to find a ++ * race condition; so a more "direct" log message is generated. ++ */ ++ ++int ++ssh_get_authentication_socket_for_uid(uid_t uid) ++{ ++ const char *authsocket; ++ int sock; ++ struct sockaddr_un sunaddr; ++ struct stat sock_st; ++ ++ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); ++ if (!authsocket) ++ return -1; ++ ++ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ ++ if( stat(authsocket,&sock_st) == 0) { ++ if(uid != 0 && sock_st.st_uid != uid) { ++ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); ++ return -1; ++ } ++ } ++ ++ /* ++ * Ensures that the EACCES tested for below can _only_ happen if somebody ++ * is attempting to race the stat above to bypass authentication. ++ */ ++ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { ++ error("ssh-agent socket has incorrect permissions for owner"); ++ return -1; ++ } ++ ++ sunaddr.sun_family = AF_UNIX; ++ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); ++ ++ sock = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sock < 0) ++ return -1; ++ ++ /* close on exec */ ++ if (fcntl(sock, F_SETFD, 1) == -1) { ++ close(sock); ++ return -1; ++ } ++ ++ errno = 0; ++ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat ++ above, we will temporarily drop UID to the caller */ ++ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ close(sock); ++ if(errno == EACCES) ++ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ return -1; ++ } ++ ++ seteuid(0); /* we now continue the regularly scheduled programming */ ++ ++ return sock; ++} ++ ++AuthenticationConnection * ++ssh_get_authentication_connection_for_uid(uid_t uid) ++{ ++ AuthenticationConnection *auth; ++ int sock; ++ ++ sock = ssh_get_authentication_socket_for_uid(uid); ++ ++ /* ++ * Fail if we couldn't obtain a connection. This happens if we ++ * exited due to a timeout. ++ */ ++ if (sock < 0) ++ return NULL; ++ ++ auth = xmalloc(sizeof(*auth)); ++ auth->fd = sock; ++ buffer_init(&auth->identities); ++ auth->howmany = 0; ++ ++ return auth; ++} ++ + int + pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) + { +@@ -190,7 +289,7 @@ pamsshagentauth_find_authorized_keys(con + OpenSSL_add_all_digests(); + pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); + +- if ((ac = ssh_get_authentication_connection(uid))) { ++ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { + pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); + for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) + { +@@ -219,3 +318,4 @@ pamsshagentauth_find_authorized_keys(con + EVP_cleanup(); + return retval; + } ++ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in 2017-02-13 16:04:58.685753236 +0100 +@@ -52,7 +52,7 @@ PATHS= + CC=@CC@ + LD=@LD@ + CFLAGS=@CFLAGS@ +-CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ ++CPPFLAGS=-I.. -I$(srcdir) -I/usr/include/nss3 -I/usr/include/nspr4 @CPPFLAGS@ $(PATHS) @DEFS@ + LIBS=@LIBS@ + AR=@AR@ + AWK=@AWK@ +@@ -61,7 +61,7 @@ INSTALL=@INSTALL@ + PERL=@PERL@ + SED=@SED@ + ENT=@ENT@ +-LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ ++LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ + LDFLAGS_SHARED = @LDFLAGS_SHARED@ + EXEEXT=@EXEEXT@ + +@@ -74,7 +74,7 @@ SSHOBJS=xmalloc.o atomicio.o authfd.o bu + + ED25519OBJS=ed25519-donna/ed25519.o + +-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o ++PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o secure_filename.o + + + MANPAGES_IN = pam_ssh_agent_auth.pod +@@ -94,13 +94,13 @@ $(PAM_MODULES): Makefile.in config.h + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +-LIBCOMPAT=openbsd-compat/libopenbsd-compat.a ++LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a + $(LIBCOMPAT): always + (cd openbsd-compat && $(MAKE)) + always: + +-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 -lnss3 + + $(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/pam_ssh_agent_auth-0.10.3-dereference.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-dereference.patch new file mode 100644 index 0000000..351aea8 --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-dereference.patch @@ -0,0 +1,20 @@ +diff --git a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c +--- a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c ++++ 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) + { ++ struct passwd *pw; + return +- pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), +- key, authorized_keys_file) +- || pamsshagentauth_user_key_allowed2(getpwuid(0), key, +- authorized_keys_file) ++ ( (pw = getpwuid(authorized_keys_file_allowed_owner_uid)) && ++ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) ++ || ((pw = getpwuid(0)) && ++ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) + || pamsshagentauth_user_key_command_allowed2(authorized_keys_command, + authorized_keys_command_user, + getpwnam(ruser), key); diff --git a/SOURCES/pam_ssh_agent_auth-0.10.3-man-date.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-man-date.patch new file mode 100644 index 0000000..8305c12 --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-man-date.patch @@ -0,0 +1,12 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.pss-pod openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.pod 2017-05-12 16:10:50.484898322 +0200 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in 2017-05-12 16:10:20.149908941 +0200 +@@ -103,7 +103,7 @@ pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_A + $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam -lnss3 + + $(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 ++ pod2man --date="2016-11-12" --section=8 --release=v0.10.3 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 + + clean: regressclean + rm -f *.o *.a $(PAM_MODULES) logintest config.cache config.log diff --git a/SOURCES/pam_ssh_agent_auth-0.10.3-no-xfree.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-no-xfree.patch new file mode 100644 index 0000000..e766610 --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-no-xfree.patch @@ -0,0 +1,66 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c.psaa-xfree 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-xfree 2017-02-13 16:06:46.260653300 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/get_command_line.c 2017-02-13 16:07:22.228619884 +0100 +@@ -105,9 +105,9 @@ pamsshagentauth_free_command_line(char * + { + size_t i; + for (i = 0; i < n_args; i++) +- pamsshagentauth_xfree(argv[i]); ++ free(argv[i]); + +- pamsshagentauth_xfree(argv); ++ free(argv); + return; + } + +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-xfree 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-xfree 2017-02-13 16:06:46.261653299 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-13 16:08:01.263583622 +0100 +@@ -170,7 +170,7 @@ pamsshagentauth_session_id2_gen(Buffer * + /* pamsshagentauth_debug3("action: %s", action_logbuf); */ + pamsshagentauth_buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); + if (free_logbuf) { +- pamsshagentauth_xfree(action_logbuf); ++ free(action_logbuf); + pamsshagentauth_buffer_free(&action_agentbuf); + } + /* pamsshagentauth_debug3("hostname: %s", hostname); */ +@@ -306,9 +306,9 @@ pamsshagentauth_find_authorized_keys(con + if(userauth_pubkey_from_id(ruser, id, &session_id2)) { + retval = 1; + } +- pamsshagentauth_xfree(id->filename); ++ free(id->filename); + pamsshagentauth_key_free(id->key); +- pamsshagentauth_xfree(id); ++ free(id); + if(retval == 1) + break; + } +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c.psaa-xfree 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-xfree 2017-02-13 16:06:46.261653299 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/pam_user_key_allowed2.c 2017-02-13 16:08:25.507561099 +0100 +@@ -105,7 +105,7 @@ pamsshagentauth_check_authkeys_file(FILE + fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); + pamsshagentauth_logit("Found matching %s key: %s", + pamsshagentauth_key_type(found), fp); +- pamsshagentauth_xfree(fp); ++ free(fp); + break; + } + } +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-xfree 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-xfree 2017-02-13 16:06:46.261653299 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-02-13 16:08:44.164543767 +0100 +@@ -93,9 +93,9 @@ userauth_pubkey_from_id(const char *ruse + /* if(&b != NULL) */ + pamsshagentauth_buffer_free(&b); + if(sig != NULL) +- pamsshagentauth_xfree(sig); ++ free(sig); + if(pkblob != NULL) +- pamsshagentauth_xfree(pkblob); ++ free(pkblob); + CRYPTO_cleanup_all_ex_data(); + return authenticated; + } diff --git a/SOURCES/pam_ssh_agent_auth-0.10.3-seteuid.patch b/SOURCES/pam_ssh_agent_auth-0.10.3-seteuid.patch new file mode 100644 index 0000000..bf485c0 --- /dev/null +++ b/SOURCES/pam_ssh_agent_auth-0.10.3-seteuid.patch @@ -0,0 +1,36 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid 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-seteuid 2017-02-13 17:51:29.790005199 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-13 17:52:53.640919947 +0100 +@@ -238,17 +238,25 @@ ssh_get_authentication_socket_for_uid(ui + } + + errno = 0; +- seteuid(uid); /* To ensure a race condition is not used to circumvent the stat +- above, we will temporarily drop UID to the caller */ +- if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ /* To ensure a race condition is not used to circumvent the stat ++ above, we will temporarily drop UID to the caller */ ++ if (seteuid(uid) == -1) { + close(sock); +- if(errno == EACCES) +- fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ error("seteuid(%lu) failed with error: %s", (unsigned long) uid, strerror(errno)); + return -1; + } ++ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ close(sock); ++ sock = -1; ++ if(errno == EACCES) ++ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ } + +- seteuid(0); /* we now continue the regularly scheduled programming */ +- ++ /* we now continue the regularly scheduled programming */ ++ if (0 != seteuid(0)) { ++ fatal("setuid(0) failed with error: %s", strerror(errno)); ++ return -1; ++ } + return sock; + } + diff --git a/SOURCES/pam_ssh_agent_auth-0.9.2-seteuid.patch b/SOURCES/pam_ssh_agent_auth-0.9.2-seteuid.patch deleted file mode 100644 index b7f12a4..0000000 --- a/SOURCES/pam_ssh_agent_auth-0.9.2-seteuid.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff -up pam_ssh_agent_auth-0.9.2/iterate_ssh_agent_keys.c.seteuid pam_ssh_agent_auth-0.9.2/iterate_ssh_agent_keys.c ---- pam_ssh_agent_auth-0.9.2/iterate_ssh_agent_keys.c.seteuid 2010-09-08 08:54:29.000000000 +0200 -+++ pam_ssh_agent_auth-0.9.2/iterate_ssh_agent_keys.c 2010-11-22 08:38:05.000000000 +0100 -@@ -131,13 +131,18 @@ ssh_get_authentication_socket_for_uid(ui - } - - errno = 0; -- seteuid(uid); /* To ensure a race condition is not used to circumvent the stat -- above, we will temporarily drop UID to the caller */ -+ /* To ensure a race condition is not used to circumvent the stat -+ above, we will temporarily drop UID to the caller */ -+ if (seteuid(uid) == -1) { -+ close(sock); -+ error("seteuid(%lu) failed", (unsigned long) uid); -+ return -1; -+ } - if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { - close(sock); -- if(errno == EACCES) -- fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); -- return -1; -+ sock = -1; -+ if(errno == EACCES) -+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); - } - - seteuid(0); /* we now continue the regularly scheduled programming */ diff --git a/SOURCES/pam_ssh_agent_auth-0.9.2-visibility.patch b/SOURCES/pam_ssh_agent_auth-0.9.2-visibility.patch index f229144..b3127b6 100644 --- a/SOURCES/pam_ssh_agent_auth-0.9.2-visibility.patch +++ b/SOURCES/pam_ssh_agent_auth-0.9.2-visibility.patch @@ -18,4 +18,4 @@ diff -up pam_ssh_agent_auth-0.9.2/pam_ssh_agent_auth.c.visibility pam_ssh_agent_ +PAM_EXTERN int __attribute__ ((visibility ("default"))) pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) { - return PAM_SUCCESS; + UNUSED(pamh); diff --git a/SOURCES/pam_ssh_agent_auth-0.9.3-build.patch b/SOURCES/pam_ssh_agent_auth-0.9.3-build.patch deleted file mode 100644 index 40ab19d..0000000 --- a/SOURCES/pam_ssh_agent_auth-0.9.3-build.patch +++ /dev/null @@ -1,179 +0,0 @@ -diff -up pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c.psaa-build pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c ---- pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c.psaa-build 2010-01-13 03:17:01.000000000 +0100 -+++ pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c 2012-06-21 20:14:56.432527764 +0200 -@@ -37,7 +37,16 @@ - #include "buffer.h" - #include "key.h" - #include "authfd.h" -+#include "ssh.h" - #include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include - #include - - #include "userauth_pubkey_from_id.h" -@@ -69,6 +78,96 @@ session_id2_gen() - return cookie; - } - -+/* -+ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user -+ * A cursory check is done, but to avoid race conditions, it is necessary -+ * to drop effective UID when connecting to the socket. -+ * -+ * If the cause of error is EACCES, because we verified we would not have that -+ * problem initially, we can safely assume that somebody is attempting to find a -+ * race condition; so a more "direct" log message is generated. -+ */ -+ -+int -+ssh_get_authentication_socket_for_uid(uid_t uid) -+{ -+ const char *authsocket; -+ int sock; -+ struct sockaddr_un sunaddr; -+ struct stat sock_st; -+ -+ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); -+ if (!authsocket) -+ return -1; -+ -+ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ -+ if( stat(authsocket,&sock_st) == 0) { -+ if(uid != 0 && sock_st.st_uid != uid) { -+ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); -+ return -1; -+ } -+ } -+ -+ /* -+ * Ensures that the EACCES tested for below can _only_ happen if somebody -+ * is attempting to race the stat above to bypass authentication. -+ */ -+ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { -+ error("ssh-agent socket has incorrect permissions for owner"); -+ return -1; -+ } -+ -+ sunaddr.sun_family = AF_UNIX; -+ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); -+ -+ sock = socket(AF_UNIX, SOCK_STREAM, 0); -+ if (sock < 0) -+ return -1; -+ -+ /* close on exec */ -+ if (fcntl(sock, F_SETFD, 1) == -1) { -+ close(sock); -+ return -1; -+ } -+ -+ errno = 0; -+ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat -+ above, we will temporarily drop UID to the caller */ -+ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { -+ close(sock); -+ if(errno == EACCES) -+ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); -+ return -1; -+ } -+ -+ seteuid(0); /* we now continue the regularly scheduled programming */ -+ -+ return sock; -+} -+ -+AuthenticationConnection * -+ssh_get_authentication_connection_for_uid(uid_t uid) -+{ -+ AuthenticationConnection *auth; -+ int sock; -+ -+ sock = ssh_get_authentication_socket_for_uid(uid); -+ -+ /* -+ * Fail if we couldn't obtain a connection. This happens if we -+ * exited due to a timeout. -+ */ -+ if (sock < 0) -+ return NULL; -+ -+ auth = xmalloc(sizeof(*auth)); -+ auth->fd = sock; -+ buffer_init(&auth->identities); -+ auth->howmany = 0; -+ -+ return auth; -+} -+ - int - find_authorized_keys(uid_t uid) - { -@@ -81,7 +180,7 @@ find_authorized_keys(uid_t uid) - OpenSSL_add_all_digests(); - session_id2 = session_id2_gen(); - -- if ((ac = ssh_get_authentication_connection(uid))) { -+ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { - verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid); - for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) - { -@@ -109,3 +208,4 @@ find_authorized_keys(uid_t uid) - EVP_cleanup(); - return retval; - } -+ -diff -up pam_ssh_agent_auth-0.9.3/Makefile.in.psaa-build pam_ssh_agent_auth-0.9.3/Makefile.in ---- pam_ssh_agent_auth-0.9.3/Makefile.in.psaa-build 2009-10-27 21:19:41.000000000 +0100 -+++ pam_ssh_agent_auth-0.9.3/Makefile.in 2012-06-21 20:14:56.432527764 +0200 -@@ -28,7 +28,7 @@ PATHS= - CC=@CC@ - LD=@LD@ - CFLAGS=@CFLAGS@ --CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ -+CPPFLAGS=-I.. -I$(srcdir) -I/usr/include/nss3 -I/usr/include/nspr4 @CPPFLAGS@ $(PATHS) @DEFS@ - LIBS=@LIBS@ - AR=@AR@ - AWK=@AWK@ -@@ -37,7 +37,7 @@ INSTALL=@INSTALL@ - PERL=@PERL@ - SED=@SED@ - ENT=@ENT@ --LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ -+LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ - LDFLAGS_SHARED = @LDFLAGS_SHARED@ - EXEEXT=@EXEEXT@ - -@@ -48,7 +48,7 @@ PAM_MODULES=pam_ssh_agent_auth.so - - SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o - --PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o -+PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o - - - MANPAGES_IN = pam_ssh_agent_auth.pod -@@ -67,13 +67,13 @@ $(PAM_MODULES): Makefile.in config.h - .c.o: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $< - --LIBCOMPAT=openbsd-compat/libopenbsd-compat.a -+LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a - $(LIBCOMPAT): always - (cd openbsd-compat && $(MAKE)) - always: - --pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o -- $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat $(LIBS) -lpam pam_ssh_agent_auth.o -+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 $(LIBS) -lpam -lnss3 pam_ssh_agent_auth.o - - $(MANPAGES): $(MANPAGES_IN) - pod2man --section=8 --release=v0.8 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 -diff -up pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c.psaa-build pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c diff --git a/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch b/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch deleted file mode 100644 index 88e8d7d..0000000 --- a/SOURCES/pam_ssh_agent_auth-0.9.3-command.patch +++ /dev/null @@ -1,1451 +0,0 @@ -From b0695cc9f5478daa14d3f451ecdd39ba6e6abe0f Mon Sep 17 00:00:00 2001 -From: Jakub Jelen -Date: Tue, 19 Jan 2016 15:29:22 +0100 -Subject: [PATCH] authorized_keys_command - ---- - pam_ssh_agent_auth-0.9.3/CONTRIBUTORS | 2 + - pam_ssh_agent_auth-0.9.3/Makefile.in | 28 +- - pam_ssh_agent_auth-0.9.3/README | 38 +++ - pam_ssh_agent_auth-0.9.3/configure.ac | 27 +- - pam_ssh_agent_auth-0.9.3/get_command_line.c | 113 +++++++ - pam_ssh_agent_auth-0.9.3/get_command_line.h | 40 +++ - pam_ssh_agent_auth-0.9.3/identity.h | 24 ++ - pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c | 137 ++++++++- - pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h | 2 +- - pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c | 16 +- - pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod | 50 ++- - pam_ssh_agent_auth-0.9.3/pam_static_macros.h | 29 ++ - .../pam_user_authorized_keys.c | 23 +- - .../pam_user_authorized_keys.h | 2 +- - pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c | 334 ++++++++++++++++----- - pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h | 3 +- - pam_ssh_agent_auth-0.9.3/secure_filename.c | 51 +++- - pam_ssh_agent_auth-0.9.3/secure_filename.h | 4 +- - pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c | 20 +- - pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h | 2 +- - 20 files changed, 805 insertions(+), 140 deletions(-) - create mode 100644 pam_ssh_agent_auth-0.9.3/README - create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.c - create mode 100644 pam_ssh_agent_auth-0.9.3/get_command_line.h - -diff --git a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS -index d5a21cb..22b424a 100644 ---- a/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS -+++ b/pam_ssh_agent_auth-0.9.3/CONTRIBUTORS -@@ -1,3 +1,5 @@ - * Foremost, OpenSSH from which this project is derived. - * Jamie Beverly - * Rafael D'Halleweyn - 2011-06-05 18:56:24 EDT -+* Jan-Pieter Cornet ( johnpc ) - 2012-03-23 03:25:52 PDT -+* chrysn@fsfe.org -diff --git a/pam_ssh_agent_auth-0.9.3/Makefile.in b/pam_ssh_agent_auth-0.9.3/Makefile.in -index 47bb103..4977838 100644 ---- a/pam_ssh_agent_auth-0.9.3/Makefile.in -+++ b/pam_ssh_agent_auth-0.9.3/Makefile.in -@@ -1,4 +1,28 @@ - # $Id: Makefile.in,v 1.289 2008/03/13 01:41:31 djm Exp $ -+# -+# Copyright (c) 2000 Markus Friedl. All rights reserved. -+# Modifications Copyright (c) 2008-2014 Jamie Beverly. 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. -+# - - # uncomment if you run a non bourne compatable shell. Ie. csh - #SHELL = @SH@ -@@ -46,9 +70,9 @@ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@ - - PAM_MODULES=pam_ssh_agent_auth.so - --SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o -+SSHOBJS=xmalloc.o atomicio.o authfd.o bufaux.o bufbn.o buffer.o cleanup.o entropy.o fatal.o key.o log.o misc.o secure_filename.o ssh-dss.o ssh-rsa.o uuencode.o compat.o uidswap.o - --PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o -+PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o secure_filename.o get_command_line.o - - - MANPAGES_IN = pam_ssh_agent_auth.pod -diff --git a/pam_ssh_agent_auth-0.9.3/README b/pam_ssh_agent_auth-0.9.3/README -new file mode 100644 -index 0000000..c1a49ef ---- /dev/null -+++ b/pam_ssh_agent_auth-0.9.3/README -@@ -0,0 +1,38 @@ -+pam_ssh_agent_auth is a PAM module which permits PAM authentication via your -+keyring in a forwarded ssh-agent. -+ -+Release 0.10.1 is stable, and has been tested on FreeBSD, Solaris 10, Solaris 11, -+RHEL5, RHEL6, Debian Wheezy, Ubuntu 12.04 (LTS), Ubuntu 13.10, -+and MacOS X 10.7. -+ -+This module can be used to provide authentication for anything run locally that -+supports PAM. It was written specifically with the intention of permitting -+authentication for sudo without password entry, and also has been proven useful -+for use with su as an alternative to wheel. -+ -+It serves as middle ground between the two most common, and suboptimal -+alternatives for large-scale system administration: allowing rootlogin via ssh, -+or using NOPASSWD in sudoers. This module allows for ssh public-key -+authentication, and it does this by leveraging an authentication mechanism you -+are probably already using, ssh-agent. -+ -+There are caveats of course, ssh-agent forwarding has it’s own security risks -+which must be carefully considered for your environment. In cases where there -+are not untrustworthy intermediate servers, and you wish to retain traceability, -+accountability, and required authentication for privileged command invocation, -+the benefits should outweigh the risks. Release 0.10.1 can be downloaded from -+SourceForge: https://sourceforge.net/project/showfiles.php?group_id=249556 -+ -+If you encounter any issues with usability or security, please use the project's -+SourceForge tracker: -+https://sourceforge.net/tracker2/?group_id=249556&atid=1126337 -+ -+Note that if you wish to use this for sudo, you will need a version of sudo that -+preserves the env_keep environment during authentication; and ideally a version -+incorporating my minor patch which ensures RUSER is set during PAM authentication. -+ -+sudo 1.6.8p12 does not work correctly with this PAM module, because it clears the -+environment (even env_keep variables) prior to attempting PAM authentication. -+ -+sudo 1.7.2p1 or later is preferred, as it correctly sets PAM_RUSER for -+authentication. -diff --git a/pam_ssh_agent_auth-0.9.3/configure.ac b/pam_ssh_agent_auth-0.9.3/configure.ac -index 1f372ce..4eb1f32 100644 ---- a/pam_ssh_agent_auth-0.9.3/configure.ac -+++ b/pam_ssh_agent_auth-0.9.3/configure.ac -@@ -18,8 +18,10 @@ AC_INIT(OpenSSH, Portable, openssh-unix-dev@mindrot.org) - AC_REVISION($Revision: 1.397 $) - AC_CONFIG_SRCDIR([pam_ssh_agent_auth.c]) - --AC_CONFIG_HEADER(config.h) -+AC_CONFIG_SRCDIR([config.h.in]) -+AC_CONFIG_HEADERS([config.h]) - AC_PROG_CC -+AC_C_INLINE - AC_CANONICAL_HOST - AC_C_BIGENDIAN - -@@ -117,7 +119,6 @@ if test -z "$LD" ; then - fi - AC_SUBST(LD) - --AC_C_INLINE - - AC_CHECK_DECL(LLONG_MAX, have_llong_max=1, , [#include ]) - -@@ -151,7 +152,7 @@ if test "$GCC" = "yes" || test "$GCC" = "egcs"; then - ;; - 2.*) no_attrib_nonnull=1 ;; - 3.*) CFLAGS="$CFLAGS -Wsign-compare" ;; -- 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wno-pointer-sign" ;; -+ 4.*) CFLAGS="$CFLAGS -Wsign-compare -Wall -Wextra" ;; - *) ;; - esac - -@@ -1656,11 +1657,11 @@ fi - - if test "x$check_for_conflicting_getspnam" = "x1"; then - AC_MSG_CHECKING(for conflicting getspnam in shadow.h) -- AC_COMPILE_IFELSE( -+ AC_COMPILE_IFELSE([AC_LANG_SOURCE( - [ - #include - int main(void) {exit(0);} -- ], -+ ])], - [ - AC_MSG_RESULT(no) - ], -@@ -2720,7 +2721,7 @@ fi - dnl make sure we're using the real structure members and not defines - AC_CACHE_CHECK([for msg_accrights field in struct msghdr], - ac_cv_have_accrights_in_msghdr, [ -- AC_COMPILE_IFELSE( -+ AC_COMPILE_IFELSE([AC_LANG_SOURCE( - [ - #include - #include -@@ -2734,7 +2735,7 @@ struct msghdr m; - m.msg_accrights = 0; - exit(0); - } -- ], -+ ])], - [ ac_cv_have_accrights_in_msghdr="yes" ], - [ ac_cv_have_accrights_in_msghdr="no" ] - ) -@@ -2747,7 +2748,7 @@ fi - - AC_CACHE_CHECK([for msg_control field in struct msghdr], - ac_cv_have_control_in_msghdr, [ -- AC_COMPILE_IFELSE( -+ AC_COMPILE_IFELSE([AC_LANG_SOURCE( - [ - #include - #include -@@ -2761,7 +2762,7 @@ struct msghdr m; - m.msg_control = 0; - exit(0); - } -- ], -+ ])], - [ ac_cv_have_control_in_msghdr="yes" ], - [ ac_cv_have_control_in_msghdr="no" ] - ) -@@ -2891,14 +2892,14 @@ AC_SEARCH_LIBS(getrrsetbyname, resolv, - saved_LIBS="$LIBS" - LIBS="$LIBS -lresolv" - AC_MSG_CHECKING(for res_query in -lresolv) -- AC_LINK_IFELSE([ -+ AC_LINK_IFELSE([AC_LANG_SOURCE([ - #include - int main() - { - res_query (0, 0, 0, 0, 0); - return 0; - } -- ], -+ ])], - [LIBS="$LIBS -lresolv" - AC_MSG_RESULT(yes)], - [LIBS="$saved_LIBS" -@@ -2915,7 +2916,7 @@ int main() - ]) - - AC_MSG_CHECKING(if struct __res_state _res is an extern) --AC_LINK_IFELSE([ -+AC_LINK_IFELSE([AC_LANG_SOURCE([ - #include - #if HAVE_SYS_TYPES_H - # include -@@ -2925,7 +2926,7 @@ AC_LINK_IFELSE([ - #include - extern struct __res_state _res; - int main() { return 0; } -- ], -+ ])], - [AC_MSG_RESULT(yes) - AC_DEFINE(HAVE__RES_EXTERN, 1, - [Define if you have struct __res_state _res as an extern]) -diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.c b/pam_ssh_agent_auth-0.9.3/get_command_line.c -new file mode 100644 -index 0000000..e880fee ---- /dev/null -+++ b/pam_ssh_agent_auth-0.9.3/get_command_line.c -@@ -0,0 +1,113 @@ -+/* -+ * Copyright (c) 2014, Jamie Beverly. -+ * 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 Jamie Beverly ``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 Jamie Beverly OR -+ * CONTRIBUTORS 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. -+ * -+ * The views and conclusions contained in the software and documentation are those of the -+ * authors and should not be interpreted as representing official policies, either expressed -+ * or implied, of Jamie Beverly. -+ */ -+ -+#include -+#include -+#include -+ -+#include "includes.h" -+#include "xmalloc.h" -+#include "get_command_line.h" -+ -+#ifdef HAVE_PROC_PID_CMDLINE -+ -+static size_t -+proc_pid_cmdline(char *** inargv) -+{ -+ pid_t pid; -+ FILE *f = NULL; -+ char filename[64] = { 0 }, c = '\0'; -+ char ** argv; -+ char argbuf[MAX_LEN_PER_CMDLINE_ARG + 1] = { 0 }; -+ size_t count = 0, len = 0; -+ -+ pid = getpid(); -+ argv = NULL; -+ -+ snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid); -+ f = fopen(filename, "r"); -+ -+ if (f) { -+ while (!feof(f) && count < MAX_CMDLINE_ARGS) { -+ if (len > MAX_LEN_PER_CMDLINE_ARG) { -+ while (!feof(f) && (c = fgetc(f)) != '\0'); -+ } -+ else { -+ c = fgetc(f); -+ } -+ switch (c) { -+ case EOF: -+ case '\0': -+ if (len > 0) { -+ argv = xrealloc(argv, count + 1, sizeof(*argv)); -+ argv[count] = xcalloc(len + 1, sizeof(*argv[count])); -+ strncpy(argv[count++], argbuf, len); -+ memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); -+ len = 0; -+ } -+ break; -+ default: -+ argbuf[len++] = c; -+ break; -+ } -+ } -+ fclose(f); -+ } -+ *inargv = argv; -+ return count; -+} -+#endif -+ -+ -+/* -+ * takes a pointer to an unallocated array of arrays of strings, populates the -+ * given pointer with the address of the allocated array of strings collected -+ */ -+size_t -+pamsshagentauth_get_command_line(char *** argv) -+{ -+#ifdef HAVE_PROC_PID_CMDLINE -+ return proc_pid_cmdline(argv); -+#else -+ /* No other supported implementations at this time */ -+ return 0; -+#endif -+} -+ -+void -+pamsshagentauth_free_command_line(char ** argv, size_t n_args) -+{ -+ size_t i; -+ for (i = 0; i < n_args; i++) -+ free(argv[i]); -+ -+ free(argv); -+ return; -+} -+ -diff --git a/pam_ssh_agent_auth-0.9.3/get_command_line.h b/pam_ssh_agent_auth-0.9.3/get_command_line.h -new file mode 100644 -index 0000000..37cd077 ---- /dev/null -+++ b/pam_ssh_agent_auth-0.9.3/get_command_line.h -@@ -0,0 +1,40 @@ -+/* -+ * Copyright (c) 2014, Jamie Beverly. -+ * 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 Jamie Beverly ``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 Jamie Beverly OR -+ * CONTRIBUTORS 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. -+ * -+ * The views and conclusions contained in the software and documentation are those of the -+ * authors and should not be interpreted as representing official policies, either expressed -+ * or implied, of Jamie Beverly. -+ */ -+ -+#ifndef _GET_COMMAND_LINE_H -+#define _GET_COMMAND_LINE_H -+ -+#include "includes.h" -+ -+size_t pamsshagentauth_get_command_line(char ***); -+void pamsshagentauth_free_command_line(char **, size_t); -+#define MAX_CMDLINE_ARGS 255 -+#define MAX_LEN_PER_CMDLINE_ARG 255 -+ -+#endif -diff --git a/pam_ssh_agent_auth-0.9.3/identity.h b/pam_ssh_agent_auth-0.9.3/identity.h -index eb21320..0bde782 100644 ---- a/pam_ssh_agent_auth-0.9.3/identity.h -+++ b/pam_ssh_agent_auth-0.9.3/identity.h -@@ -1,3 +1,27 @@ -+/* -+ * Copyright (c) 2000 Markus Friedl. 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. -+ */ -+ - #ifndef _IDENTITY_H - #define _IDENTITY_H - #include "includes.h" -diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c -index 11ab6e2..6b4d531 100644 ---- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c -+++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.c -@@ -28,6 +28,8 @@ - */ - - -+#include -+ - #include "includes.h" - #include "config.h" - -@@ -48,26 +50,75 @@ - #include - #include - #include -+#include "ssh2.h" -+#include "misc.h" - - #include "userauth_pubkey_from_id.h" - #include "identity.h" -+#include "get_command_line.h" -+extern char **environ; -+ -+#define PAM_SSH_AGENT_AUTH_REQUESTv1 101 -+ -+static char * -+log_action(char ** action, size_t count) -+{ -+ size_t i; -+ char *buf = NULL; -+ -+ if (count == 0) -+ return NULL; -+ -+ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); -+ for (i = 0; i < count; i++) { -+ strcat(buf, (i > 0) ? " '" : "'"); -+ strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); -+ strcat(buf, "'"); -+ } -+ return buf; -+} -+ -+void -+agent_action(Buffer *buf, char ** action, size_t count) -+{ -+ size_t i; -+ buffer_init(buf); - --u_char * session_id2 = NULL; --uint8_t session_id_len = 0; -+ buffer_put_int(buf, count); -+ -+ for (i = 0; i < count; i++) { -+ buffer_put_cstring(buf, action[i]); -+ } -+} - --u_char * --session_id2_gen() -+void -+session_id2_gen(Buffer * session_id2, const char * user, -+ const char * ruser, const char * servicename) - { - char *cookie = NULL; - uint8_t i = 0; - uint32_t rnd = 0; -+ uint8_t cookie_len; -+ char hostname[256] = { 0 }; -+ char pwd[1024] = { 0 }; -+ time_t ts; -+ char ** reported_argv = NULL; -+ size_t count = 0; -+ char * action_logbuf = NULL; -+ Buffer action_agentbuf; -+ uint8_t free_logbuf = 0; -+ char * retc; -+ int32_t reti; - - rnd = arc4random(); -- session_id_len = (uint8_t) rnd; -+ cookie_len = ((uint8_t) rnd); -+ while (cookie_len < 16) { -+ cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */ -+ } - -- cookie = calloc(1,session_id_len); -+ cookie = xcalloc(1, cookie_len); - -- for (i = 0; i < session_id_len; i++) { -+ for (i = 0; i < cookie_len; i++) { - if (i % 4 == 0) { - rnd = arc4random(); - } -@@ -75,7 +126,64 @@ session_id2_gen() - rnd >>= 8; - } - -- return cookie; -+ count = pamsshagentauth_get_command_line(&reported_argv); -+ if (count > 0) { -+ free_logbuf = 1; -+ action_logbuf = log_action(reported_argv, count); -+ agent_action(&action_agentbuf, reported_argv, count); -+ pamsshagentauth_free_command_line(reported_argv, count); -+ } -+ else { -+ action_logbuf = "unknown on this platform"; -+ buffer_init(&action_agentbuf); /* stays empty, means unavailable */ -+ } -+ -+ /* -+ action = getenv("SUDO_COMMAND"); -+ if(!action) { -+ action = getenv("PAM_AUTHORIZED_ACTION"); -+ if(!action) { -+ action = empty; -+ } -+ } -+ */ -+ -+ reti = gethostname(hostname, sizeof(hostname) - 1); -+ retc = getcwd(pwd, sizeof(pwd) - 1); -+ time(&ts); -+ -+ buffer_init(session_id2); -+ -+ 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) -+ buffer_put_cstring(session_id2, pwd); -+ else -+ buffer_put_cstring(session_id2, ""); -+ /* debug3("action: %s", action_logbuf); */ -+ buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); -+ if (free_logbuf) { -+ free(action_logbuf); -+ buffer_free(&action_agentbuf); -+ } -+ /* debug3("hostname: %s", hostname); */ -+ if(reti >= 0) -+ buffer_put_cstring(session_id2, hostname); -+ else -+ buffer_put_cstring(session_id2, ""); -+ /* debug3("ts: %ld", ts); */ -+ buffer_put_int64(session_id2, (uint64_t) ts); -+ -+ free(cookie); -+ return; - } - - /* -@@ -174,19 +282,21 @@ ssh_get_authentication_connection_for_uid(uid_t uid) - } - - int --find_authorized_keys(uid_t uid) -+find_authorized_keys(const char * user, const char * ruser, const char * servicename) - { -+ Buffer session_id2 = { 0 }; - Identity *id; - Key *key; - AuthenticationConnection *ac; - char *comment; - uint8_t retval = 0; -+ uid_t uid = getpwnam(ruser)->pw_uid; - - OpenSSL_add_all_digests(); -- session_id2 = session_id2_gen(); -+ session_id2_gen(&session_id2, user, ruser, servicename); - - if ((ac = ssh_get_authentication_connection_for_uid(uid))) { -- verbose("Contacted ssh-agent of user %s (%u)", getpwuid(uid)->pw_name, uid); -+ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); - for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) - { - if(key != NULL) { -@@ -194,7 +304,7 @@ find_authorized_keys(uid_t uid) - id->key = key; - id->filename = comment; - id->ac = ac; -- if(userauth_pubkey_from_id(id)) { -+ if(userauth_pubkey_from_id(ruser, id, &session_id2)) { - retval = 1; - } - free(id->filename); -@@ -204,12 +314,13 @@ find_authorized_keys(uid_t uid) - break; - } - } -+ buffer_free(&session_id2); - ssh_close_authentication_connection(ac); - } - else { - verbose("No ssh-agent could be contacted"); - } -- free(session_id2); -+ /*free(session_id2);*/ - EVP_cleanup(); - return retval; - } -diff --git a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h -index ed7549e..e6c75aa 100644 ---- a/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h -+++ b/pam_ssh_agent_auth-0.9.3/iterate_ssh_agent_keys.h -@@ -31,6 +31,6 @@ - #ifndef _ITERATE_SSH_AGENT_KEYS_H - #define _ITERATE_SSH_AGENT_KEYS_H - --int find_authorized_keys(uid_t); -+int find_authorized_keys(const char * user, const char * ruser, const char * servicename); - - #endif -diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c -index d3f4325..37309f7 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c -+++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.c -@@ -59,9 +59,12 @@ - #include "pam_user_authorized_keys.h" - - #define strncasecmp_literal(A,B) strncasecmp( A, B, sizeof(B) - 1) -+#define UNUSED(expr) do { (void)(expr); } while (0) - - char *authorized_keys_file = NULL; - uint8_t allow_user_owned_authorized_keys_file = 0; -+char *authorized_keys_command = NULL; -+char *authorized_keys_command_user = NULL; - - #if ! HAVE___PROGNAME || HAVE_BUNDLE - char *__progname; -@@ -90,6 +93,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) - facility = SYSLOG_FACILITY_AUTHPRIV; - #endif - -+ UNUSED(flags); - pam_get_item(pamh, PAM_SERVICE, (void *) &servicename); - /* - * XXX: -@@ -113,6 +117,12 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) - if(strncasecmp_literal(*argv_ptr, "file=") == 0 ) { - authorized_keys_file_input = *argv_ptr + sizeof("file=") - 1; - } -+ if(strncasecmp_literal(*argv_ptr, "authorized_keys_command=") == 0 ) { -+ authorized_keys_command = *argv_ptr + sizeof("authorized_keys_command=") - 1; -+ } -+ if(strncasecmp_literal(*argv_ptr, "authorized_keys_command_user=") == 0 ) { -+ authorized_keys_command_user = *argv_ptr + sizeof("authorized_keys_command_user=") - 1; -+ } - #ifdef ENABLE_SUDO_HACK - if(strncasecmp_literal(*argv_ptr, "sudo_service_name=") == 0) { - strncpy( sudo_service_name, *argv_ptr + sizeof("sudo_service_name=") - 1, sizeof(sudo_service_name) - 1); -@@ -182,7 +192,7 @@ pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) - /* - * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user - */ -- if(find_authorized_keys(getpwnam(ruser)->pw_uid)) { -+ if(find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */ - logit("Authenticated: `%s' as `%s' using %s", ruser, user, authorized_keys_file); - retval = PAM_SUCCESS; - } else { -@@ -207,6 +217,10 @@ cleanexit: - PAM_EXTERN int __attribute__ ((visibility ("default"))) - pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) - { -+ UNUSED(pamh); -+ UNUSED(flags); -+ UNUSED(argc); -+ UNUSED(argv); - return PAM_SUCCESS; - } - -diff --git a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod -index 4570746..76b1f0f 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod -+++ b/pam_ssh_agent_auth-0.9.3/pam_ssh_agent_auth.pod -@@ -1,8 +1,12 @@ --=head1 PAM_SSH_AGENT_AUTH -+=head1 NAME -+ -+pam_ssh_agent_auth - PAM module for granting permissions based on SSH agent requests -+ -+=head1 DESCRIPTION - - This module provides authentication via ssh-agent. If an ssh-agent listening at SSH_AUTH_SOCK can successfully authenticate that it has the secret key for a public key in the specified file, authentication is granted, otherwise authentication fails. - --=head1 SUMMARY -+=head1 CONFIGURATION - - =over - -@@ -10,7 +14,8 @@ This module provides authentication via ssh-agent. If an ssh-agent listening at - auth sufficient pam_ssh_agent_auth.so file=/etc/security/authorized_keys - - =item /etc/sudoers: -- -+ -+In older versions of sudo (< 1.8.5) it was necessary to set: - Defaults env_keep += "SSH_AUTH_SOCK" - - =back -@@ -33,6 +38,15 @@ Specify the path to the authorized_keys file(s) you would like to use for authen - A flag which enables authorized_keys files to be owned by the invoking user, instead of root. This flag is enabled automatically whenever - the expansions %h or ~ are used. - -+=item authorized_keys_command= -+ -+Specify an external command to run, which should take a single argument, the username of the person being authenticated, and emit to its stdout a file in authorized_keys format. -+This is ideally suited for use with sssd's sss_ssh_authorizedkeys, for authenticating users via authorized_keys stored in ldap or other sssd supported security service. -+ -+=item authorized_keys_command_user= -+ -+Specify a user to run the authorized_keys_command as. If this option is not specified, the authorized_keys_command will be run as the user being authenticated. -+ - =item debug - - A flag which enables verbose logging -@@ -105,4 +119,34 @@ so this file must be owned by root. - - =back - -+=head1 COPYRIGHT -+ -+ Copyright (c) 2008-2014, Jamie Beverly. -+ And is based on openssh, and the included works by Markus Friedl, Darren Tucker, -+ Todd C. Miller, Ben Lindstrom, Tim Rice, Damien Miller, and many others. -+ -+ All rights reserved. -+ -+ See sources for complete attributions. -+ -+ 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 Jamie Beverly ``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 Jamie Beverly OR -+ CONTRIBUTORS 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. -+ - =cut -diff --git a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h -index a4938d3..a991704 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_static_macros.h -+++ b/pam_ssh_agent_auth-0.9.3/pam_static_macros.h -@@ -1,3 +1,32 @@ -+/* -+ * Copyright (c) 2008, Jamie Beverly. -+ * 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 Jamie Beverly ``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 Jamie Beverly OR -+ * CONTRIBUTORS 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. -+ * -+ * The views and conclusions contained in the software and documentation are those of the -+ * authors and should not be interpreted as representing official policies, either expressed -+ * or implied, of Jamie Beverly. -+ */ -+ - #ifndef __PAM_STATIC_MACROS_H - #define __PAM_STATIC_MACROS_H - -diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c -index 60bef68..abc0a62 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c -+++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c -@@ -1,4 +1,4 @@ --/* -+/* - * Copyright (c) 2008, Jamie Beverly. - * All rights reserved. - * -@@ -80,9 +80,15 @@ - #include "identity.h" - #include "pam_user_key_allowed2.h" - --extern char *authorized_keys_file; --extern uint8_t allow_user_owned_authorized_keys_file; --uid_t authorized_keys_file_allowed_owner_uid; -+extern char *authorized_keys_file; -+ -+extern char *authorized_keys_command; -+ -+extern char *authorized_keys_command_user; -+ -+extern uint8_t allow_user_owned_authorized_keys_file; -+ -+uid_t authorized_keys_file_allowed_owner_uid; - - void - parse_authorized_key_file(const char *user, const char *authorized_keys_file_input) -@@ -137,8 +143,11 @@ parse_authorized_key_file(const char *user, const char *authorized_keys_file_inp - } - - int --pam_user_key_allowed(Key * key) -+pam_user_key_allowed(const char *ruser, Key * key) - { - return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file) -- || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file); -+ || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file) -+ || pam_user_key_command_allowed2(authorized_keys_command, -+ authorized_keys_command_user, -+ getpwnam(ruser), key); - } -diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h -index ae9a4b8..a871bf0 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h -+++ b/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.h -@@ -32,7 +32,7 @@ - #define _PAM_USER_KEY_ALLOWED_H - - #include "identity.h" --int pam_user_key_allowed(Key *); -+int pam_user_key_allowed(const char *, Key *); - void parse_authorized_key_file(const char *, const char *); - - #endif -diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -index c6680e4..4aceecb 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -+++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.c -@@ -1,4 +1,4 @@ --/* -+/* - * Copyright (c) 2000 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without -@@ -33,9 +33,14 @@ - - #include - #include -+#include -+#include - - #include - #include -+#include -+#include -+#include - - #include "xmalloc.h" - #include "ssh.h" -@@ -48,87 +53,263 @@ - #include "pathnames.h" - #include "misc.h" - #include "secure_filename.h" -+#include "uidswap.h" -+#include - - #include "identity.h" - - /* 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) -+{ -+ char line[SSH_MAX_PUBKEY_BYTES]; -+ int found_key = 0; -+ u_long linenum = 0; -+ Key *found; -+ char *fp; -+ -+ found_key = 0; -+ found = key_new(key->type); -+ -+ while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { -+ char *cp = NULL; /* *key_options = NULL; */ -+ -+ /* Skip leading whitespace, empty and comment lines. */ -+ for(cp = line; *cp == ' ' || *cp == '\t'; cp++); -+ if(!*cp || *cp == '\n' || *cp == '#') -+ continue; -+ -+ if(key_read(found, &cp) != 1) { -+ /* no key? check if there are options for this key */ -+ int quoted = 0; -+ -+ verbose("user_key_allowed: check options: '%s'", cp); -+ /* key_options = cp; */ -+ for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { -+ if(*cp == '\\' && cp[1] == '"') -+ cp++; /* Skip both */ -+ else if(*cp == '"') -+ quoted = !quoted; -+ } -+ /* Skip remaining whitespace. */ -+ for(; *cp == ' ' || *cp == '\t'; cp++); -+ if(key_read(found, &cp) != 1) { -+ verbose("user_key_allowed: advance: '%s'", cp); -+ /* still no key? advance to next line */ -+ continue; -+ } -+ } -+ if(key_equal(found, key)) { -+ found_key = 1; -+ logit("matching key found: file/command %s, line %lu", file, -+ linenum); -+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -+ logit("Found matching %s key: %s", -+ key_type(found), fp); -+ free(fp); -+ break; -+ } -+ } -+ key_free(found); -+ if(!found_key) -+ verbose("key not found"); -+ return found_key; -+} -+ -+/* -+ * Checks whether key is allowed in file. -+ * returns 1 if the key is allowed or 0 otherwise. -+ */ - int - pam_user_key_allowed2(struct passwd *pw, Key *key, char *file) - { -- char line[SSH_MAX_PUBKEY_BYTES]; -- int found_key = 0; -- FILE *f; -- u_long linenum = 0; -- struct stat st; -- Key *found; -- char *fp; -- -- verbose("trying public key file %s", file); -- -- /* Fail not so quietly if file does not exist */ -- if (stat(file, &st) < 0) { -+ FILE *f; -+ int found_key = 0; -+ struct stat st; -+ char buf[SSH_MAX_PUBKEY_BYTES]; -+ -+ /* Temporarily use the user's uid. */ -+ verbose("trying public key file %s", file); -+ -+ /* Fail not so quietly if file does not exist */ -+ if(stat(file, &st) < 0) { - verbose("File not found: %s", file); -- return 0; -- } -- /* Open the file containing the authorized keys. */ -- f = fopen(file, "r"); -- if (!f) { -- return 0; -- } -- if ( -- secure_filename(f, file, pw, line, sizeof(line)) != 0) { -- fclose(f); -- logit("Authentication refused: %s", line); -- return 0; -- } -- -- found_key = 0; -- found = key_new(key->type); -- -- while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { -- char *cp, *key_options = NULL; -- -- /* Skip leading whitespace, empty and comment lines. */ -- for (cp = line; *cp == ' ' || *cp == '\t'; cp++) -- ; -- if (!*cp || *cp == '\n' || *cp == '#') -- continue; -- -- if (key_read(found, &cp) != 1) { -- /* no key? check if there are options for this key */ -- int quoted = 0; -- verbose("user_key_allowed: check options: '%s'", cp); -- key_options = cp; -- for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { -- if (*cp == '\\' && cp[1] == '"') -- cp++; /* Skip both */ -- else if (*cp == '"') -- quoted = !quoted; -- } -- /* Skip remaining whitespace. */ -- for (; *cp == ' ' || *cp == '\t'; cp++) -- ; -- if (key_read(found, &cp) != 1) { -- verbose("user_key_allowed: advance: '%s'", cp); -- /* still no key? advance to next line*/ -- continue; -- } -- } -- if (key_equal(found, key)) { -- found_key = 1; -- logit("matching key found: file %s, line %lu", -- file, linenum); -- fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); -- logit("Found matching %s key: %s", -- key_type(found), fp); -- free(fp); -- break; -- } -- } -- fclose(f); -- key_free(found); -- if (!found_key) -- verbose("key not found"); -- return found_key; -+ return 0; -+ } -+ -+ /* Open the file containing the authorized keys. */ -+ f = fopen(file, "r"); -+ if(!f) { -+ return 0; -+ } -+ -+ if(secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { -+ fclose(f); -+ logit("Authentication refused: %s", buf); -+ return 0; -+ } -+ -+ found_key = pamsshagentauth_check_authkeys_file(f, file, key); -+ fclose(f); -+ return found_key; -+} -+ -+/* -+ * Checks whether key is allowed in output of command. -+ * returns 1 if the key is allowed or 0 otherwise. -+ */ -+int -+pam_user_key_command_allowed2(char *authorized_keys_command, -+ char *authorized_keys_command_user, -+ struct passwd *user_pw, Key * key) -+{ -+ FILE *f; -+ int ok, found_key = 0; -+ struct passwd *pw; -+ struct stat st; -+ int status, devnull, p[2], i; -+ pid_t pid; -+ char errmsg[512]; -+ char username[512] = { 0 }; -+ -+ -+ -+ if(authorized_keys_command == NULL || authorized_keys_command[0] != '/') -+ return 0; -+ -+ -+ /* getpwnam of authorized_keys_command_user will overwrite the statics used by getpwnam (including pw_name) */ -+ strncpy(username, user_pw->pw_name, sizeof(username) - 1); -+ -+ /* If no user specified to run commands the default to target user */ -+ if(authorized_keys_command_user == NULL) { -+ pw = user_pw; -+ } -+ else { -+ pw = getpwnam(authorized_keys_command_user); -+ if(pw == NULL) { -+ error("authorized_keys_command_user \"%s\" not found: %s", -+ authorized_keys_command_user, strerror(errno)); -+ return 0; -+ } -+ } -+ -+ temporarily_use_uid(pw); -+ -+ if(stat(authorized_keys_command, &st) < 0) { -+ error -+ ("Could not stat AuthorizedKeysCommand \"%s\": %s", -+ authorized_keys_command, strerror(errno)); -+ goto out; -+ } -+ if(pamsshagentauth_auth_secure_path -+ (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { -+ error("Unsafe AuthorizedKeysCommand: %s", errmsg); -+ goto out; -+ } -+ -+ /* open the pipe and read the keys */ -+ if(pipe(p) != 0) { -+ error("%s: pipe: %s", __func__, strerror(errno)); -+ goto out; -+ } -+ -+ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", -+ authorized_keys_command, pw->pw_name, username); -+ -+ /* -+ * Don't want to call this in the child, where it can fatal() and -+ * run cleanup_exit() code. -+ */ -+ restore_uid(); -+ -+ switch ((pid = fork())) { -+ case -1: /* error */ -+ error("%s: fork: %s", __func__, strerror(errno)); -+ close(p[0]); -+ close(p[1]); -+ return 0; -+ case 0: /* child */ -+ for(i = 0; i < NSIG; i++) -+ signal(i, SIG_DFL); -+ -+ /* do this before the setresuid so thta they can be logged */ -+ if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { -+ error("%s: open %s: %s", __func__, _PATH_DEVNULL, -+ strerror(errno)); -+ _exit(1); -+ } -+ if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1 -+ || dup2(devnull, STDERR_FILENO) == -1) { -+ error("%s: dup2: %s", __func__, strerror(errno)); -+ _exit(1); -+ } -+#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) -+ if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { -+#else -+ if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { -+#endif -+ error("setresgid %u: %s", (u_int) pw->pw_gid, -+ strerror(errno)); -+ _exit(1); -+ } -+ -+#ifdef HAVE_SETRESUID -+ if(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { -+#else -+ if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { -+#endif -+ error("setresuid %u: %s", (u_int) pw->pw_uid, -+ strerror(errno)); -+ _exit(1); -+ } -+ -+ close(p[0]); -+ closefrom(STDERR_FILENO + 1); -+ -+ execl(authorized_keys_command, authorized_keys_command, username, (char *)NULL); -+ -+ /* pretty sure this will barf because we are now suid, but since we -+ should't reach this anyway, I'll leave it here */ -+ error("AuthorizedKeysCommand %s exec failed: %s", -+ authorized_keys_command, strerror(errno)); -+ _exit(127); -+ default: /* parent */ -+ break; -+ } -+ -+ temporarily_use_uid(pw); -+ -+ close(p[1]); -+ if((f = fdopen(p[0], "r")) == NULL) { -+ error("%s: fdopen: %s", __func__, strerror(errno)); -+ close(p[0]); -+ /* Don't leave zombie child */ -+ while(waitpid(pid, NULL, 0) == -1 && errno == EINTR); -+ goto out; -+ } -+ ok = pamsshagentauth_check_authkeys_file(f, authorized_keys_command, key); -+ fclose(f); -+ -+ while(waitpid(pid, &status, 0) == -1) { -+ if(errno != EINTR) { -+ error("%s: waitpid: %s", __func__, -+ strerror(errno)); -+ goto out; -+ } -+ } -+ if(WIFSIGNALED(status)) { -+ error("AuthorizedKeysCommand %s exited on signal %d", -+ authorized_keys_command, WTERMSIG(status)); -+ goto out; -+ } else if(WEXITSTATUS(status) != 0) { -+ error("AuthorizedKeysCommand %s returned status %d", -+ authorized_keys_command, WEXITSTATUS(status)); -+ goto out; -+ } -+ found_key = ok; -+ out: -+ restore_uid(); -+ return found_key; - } -diff --git a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h -index 416d055..24533a0 100644 ---- a/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h -+++ b/pam_ssh_agent_auth-0.9.3/pam_user_key_allowed2.h -@@ -32,5 +32,6 @@ - - #include "identity.h" - int pam_user_key_allowed2(struct passwd *, Key *, char *); -+int pam_user_key_command_allowed2(char *, char *, struct passwd *, Key *); - - #endif -diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.c b/pam_ssh_agent_auth-0.9.3/secure_filename.c -index c24cab2..d685599 100644 ---- a/pam_ssh_agent_auth-0.9.3/secure_filename.c -+++ b/pam_ssh_agent_auth-0.9.3/secure_filename.c -@@ -71,29 +71,38 @@ - * Returns 0 on success and -1 on failure - */ - int --secure_filename(FILE *f, const char *file, struct passwd *pw, -- char *err, size_t errlen) -+pamsshagentauth_auth_secure_path(const char *name, struct stat *stp, -+ const char *pw_dir, uid_t uid, char *err, size_t errlen) - { -- uid_t uid = pw->pw_uid; - char buf[MAXPATHLEN], homedir[MAXPATHLEN]; - char *cp; - int comparehome = 0; - struct stat st; - -- verbose("secure_filename: checking for uid: %u", uid); -+ verbose("auth_secure_filename: checking for uid: %u", uid); - -- if (realpath(file, buf) == NULL) { -- snprintf(err, errlen, "realpath %s failed: %s", file, -+ /* if (realpath(pw->pw_dir, homedir) != NULL) */ -+ if (realpath(name, buf) == NULL) { -+ snprintf(err, errlen, "realpath %s failed: %s", name, - strerror(errno)); - return -1; - } -- if (realpath(pw->pw_dir, homedir) != NULL) -+ if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL) - comparehome = 1; - - /* check the open file to avoid races */ -- if (fstat(fileno(f), &st) < 0 || -- (st.st_uid != 0 && st.st_uid != uid) || -- (st.st_mode & 022) != 0) { -+ /* -+ * if (fstat(fileno(f), &st) < 0 || -+ * (st.st_uid != 0 && st.st_uid != uid) || -+ * (st.st_mode & 022) != 0) { -+ */ -+ if (!S_ISREG(stp->st_mode)) { -+ snprintf(err, errlen, "%s is not a regular file", buf); -+ return -1; -+ } -+ -+ if ((stp->st_uid != 0 && stp->st_uid != uid) || -+ (stp->st_mode & 022) != 0) { - snprintf(err, errlen, "bad ownership or modes for file %s", - buf); - return -1; -@@ -132,3 +141,25 @@ secure_filename(FILE *f, const char *file, struct passwd *pw, - return 0; - } - -+/* -+ * Version of secure_path() that accepts an open file descriptor to -+ * avoid races. -+ * -+ * Returns 0 on success and -1 on failure -+ */ -+int -+secure_filename(FILE *f, const char *file, struct passwd *pw, -+ char *err, size_t errlen) -+{ -+ struct stat st; -+ char buf[MAXPATHLEN] = { 0 }; -+ -+ /* check the open file to avoid races */ -+ if (fstat(fileno(f), &st) < 0) { -+ snprintf(err, errlen, "cannot stat file %s: %s", -+ buf, strerror(errno)); -+ return -1; -+ } -+ return pamsshagentauth_auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen); -+} -+ -diff --git a/pam_ssh_agent_auth-0.9.3/secure_filename.h b/pam_ssh_agent_auth-0.9.3/secure_filename.h -index 198c13d..4c1a208 100644 ---- a/pam_ssh_agent_auth-0.9.3/secure_filename.h -+++ b/pam_ssh_agent_auth-0.9.3/secure_filename.h -@@ -28,5 +28,7 @@ - #define _SECURE_FILENAME_H - #include - #include -+struct stat; - int secure_filename(FILE *, const char *, struct passwd *, char *, size_t); -+int pamsshagentauth_auth_secure_path(const char *, struct stat *, const char *, uid_t, char *, size_t); - #endif -diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c -index 163278b..31849f8 100644 ---- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c -+++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.c -@@ -48,11 +48,14 @@ - #include "identity.h" - #include "pam_user_authorized_keys.h" - --extern u_char *session_id2; -+#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54 -+ -+/* extern u_char *session_id2; - extern uint8_t session_id_len; -+ */ - - int --userauth_pubkey_from_id(Identity * id) -+userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) - { - Buffer b = { 0 }; - char *pkalg = NULL; -@@ -63,7 +66,7 @@ userauth_pubkey_from_id(Identity * id) - pkalg = (char *) key_ssh_name(id->key); - - /* first test if this key is even allowed */ -- if(! pam_user_key_allowed(id->key)) -+ if(! pam_user_key_allowed(ruser, id->key)) - goto user_auth_clean_exit; - - if(key_to_blob(id->key, &pkblob, &blen) == 0) -@@ -72,10 +75,10 @@ userauth_pubkey_from_id(Identity * id) - /* construct packet to sign and test */ - buffer_init(&b); - -- buffer_put_string(&b, session_id2, session_id_len); -- buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); -- buffer_put_cstring(&b, "root"); -- buffer_put_cstring(&b, "ssh-userauth"); -+ buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset); -+ 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); -@@ -89,8 +92,7 @@ userauth_pubkey_from_id(Identity * id) - authenticated = 1; - - user_auth_clean_exit: -- if(&b != NULL) -- buffer_free(&b); -+ buffer_free(&b); - if(sig != NULL) - free(sig); - if(pkblob != NULL) -diff --git a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h -index 1e14231..7758808 100644 ---- a/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h -+++ b/pam_ssh_agent_auth-0.9.3/userauth_pubkey_from_id.h -@@ -32,6 +32,6 @@ - #define _USERAUTH_PUBKEY_FROM_ID_H - - #include --int userauth_pubkey_from_id(Identity *); -+int userauth_pubkey_from_id(const char *, Identity *, Buffer *); - - #endif --- -2.5.0 - ---- openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c.psaa-command 2016-04-20 09:31:32.164686370 +0200 -+++ openssh-6.6p1/pam_ssh_agent_auth-0.9.3/pam_user_authorized_keys.c 2016-04-20 09:35:49.778344576 +0200 -@@ -145,8 +145,12 @@ - int - pam_user_key_allowed(const char *ruser, Key * key) - { -- return pam_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), key, authorized_keys_file) -- || pam_user_key_allowed2(getpwuid(0), key, authorized_keys_file) -+ struct passwd *pw; -+ return -+ ((pw = getpwuid(authorized_keys_file_allowed_owner_uid)) && -+ pam_user_key_allowed2(pw, key, authorized_keys_file)) -+ || ((pw = getpwuid(0)) && -+ pam_user_key_allowed2(pw, key, authorized_keys_file)) - || pam_user_key_command_allowed2(authorized_keys_command, - authorized_keys_command_user, - getpwnam(ruser), key); diff --git a/SOURCES/pam_ssh_agent_auth-0.9.3-no-xfree.patch b/SOURCES/pam_ssh_agent_auth-0.9.3-no-xfree.patch deleted file mode 100644 index ba67c33..0000000 --- a/SOURCES/pam_ssh_agent_auth-0.9.3-no-xfree.patch +++ /dev/null @@ -1,430 +0,0 @@ ---- pam_ssh_agent_auth-0.9.3.orig/authfd.c 2013-10-30 17:14:26.013615342 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/authfd.c 2013-10-30 17:15:07.353327799 +0100 -@@ -260,7 +260,7 @@ - { - buffer_free(&auth->identities); - close(auth->fd); -- xfree(auth); -+ free(auth); - } - - /* Lock/unlock agent */ -@@ -379,7 +379,7 @@ - blob = buffer_get_string(&auth->identities, &blen); - *comment = buffer_get_string(&auth->identities, NULL); - key = key_from_blob(blob, blen); -- xfree(blob); -+ free(blob); - break; - default: - return NULL; -@@ -472,7 +472,7 @@ - buffer_put_string(&msg, blob, blen); - buffer_put_string(&msg, data, datalen); - buffer_put_int(&msg, flags); -- xfree(blob); -+ free(blob); - - if (ssh_request_reply(auth, &msg, &msg) == 0) { - buffer_free(&msg); -@@ -612,7 +612,7 @@ - key_to_blob(key, &blob, &blen); - buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); - buffer_put_string(&msg, blob, blen); -- xfree(blob); -+ free(blob); - } else { - buffer_free(&msg); - return 0; ---- pam_ssh_agent_auth-0.9.3.orig/bufaux.c 2013-10-30 17:14:26.014615310 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/bufaux.c 2013-10-30 17:15:07.354327768 +0100 -@@ -176,7 +176,7 @@ - /* Get the string. */ - if (buffer_get_ret(buffer, value, len) == -1) { - logerror("buffer_get_string_ret: buffer_get failed"); -- xfree(value); -+ free(value); - return (NULL); - } - /* Append a null character to make processing easier. */ ---- pam_ssh_agent_auth-0.9.3.orig/bufbn.c 2013-10-30 17:14:26.014615310 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/bufbn.c 2013-10-30 17:15:07.354327768 +0100 -@@ -69,7 +69,7 @@ - if (oi != bin_size) { - logerror("buffer_put_bignum_ret: BN_bn2bin() failed: oi %d != bin_size %d", - oi, bin_size); -- xfree(buf); -+ free(buf); - return (-1); - } - -@@ -80,7 +80,7 @@ - buffer_append(buffer, buf, oi); - - memset(buf, 0, bin_size); -- xfree(buf); -+ free(buf); - - return (0); - } -@@ -167,13 +167,13 @@ - if (oi < 0 || (u_int)oi != bytes - 1) { - logerror("buffer_put_bignum2_ret: BN_bn2bin() failed: " - "oi %d != bin_size %d", oi, bytes); -- xfree(buf); -+ free(buf); - return (-1); - } - hasnohigh = (buf[1] & 0x80) ? 0 : 1; - buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); - memset(buf, 0, bytes); -- xfree(buf); -+ free(buf); - return (0); - } - -@@ -197,21 +197,21 @@ - - if (len > 0 && (bin[0] & 0x80)) { - logerror("buffer_get_bignum2_ret: negative numbers not supported"); -- xfree(bin); -+ free(bin); - return (-1); - } - if (len > 8 * 1024) { - logerror("buffer_get_bignum2_ret: cannot handle BN of size %d", - len); -- xfree(bin); -+ free(bin); - return (-1); - } - if (BN_bin2bn(bin, len, value) == NULL) { - logerror("buffer_get_bignum2_ret: BN_bin2bn failed"); -- xfree(bin); -+ free(bin); - return (-1); - } -- xfree(bin); -+ free(bin); - return (0); - } - ---- pam_ssh_agent_auth-0.9.3.orig/buffer.c 2013-10-30 17:14:26.014615310 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/buffer.c 2013-10-30 17:15:07.355327737 +0100 -@@ -50,7 +50,7 @@ - if (buffer->alloc > 0) { - memset(buffer->buf, 0, buffer->alloc); - buffer->alloc = 0; -- xfree(buffer->buf); -+ free(buffer->buf); - } - } - ---- pam_ssh_agent_auth-0.9.3.orig/iterate_ssh_agent_keys.c 2013-10-30 17:14:26.031614782 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/iterate_ssh_agent_keys.c 2013-10-30 17:15:07.357327674 +0100 -@@ -197,9 +197,9 @@ - if(userauth_pubkey_from_id(id)) { - retval = 1; - } -- xfree(id->filename); -+ free(id->filename); - key_free(id->key); -- xfree(id); -+ free(id); - if(retval == 1) - break; - } -@@ -209,7 +209,7 @@ - else { - verbose("No ssh-agent could be contacted"); - } -- xfree(session_id2); -+ free(session_id2); - EVP_cleanup(); - return retval; - } ---- pam_ssh_agent_auth-0.9.3.orig/key.c 2013-10-30 17:14:26.017615218 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/key.c 2013-10-30 17:15:07.358327643 +0100 -@@ -154,7 +154,7 @@ - fatal("key_free: bad key type %d", k->type); - break; - } -- xfree(k); -+ free(k); - } - - int -@@ -229,7 +229,7 @@ - EVP_DigestUpdate(&ctx, blob, len); - EVP_DigestFinal(&ctx, retval, dgst_raw_length); - memset(blob, 0, len); -- xfree(blob); -+ free(blob); - } else { - fatal("key_fingerprint_raw: blob is null"); - } -@@ -324,7 +324,7 @@ - break; - } - memset(dgst_raw, 0, dgst_raw_len); -- xfree(dgst_raw); -+ free(dgst_raw); - return retval; - } - -@@ -447,11 +447,11 @@ - n = uudecode(cp, blob, len); - if (n < 0) { - logerror("key_read: uudecode %s failed", cp); -- xfree(blob); -+ free(blob); - return -1; - } - k = key_from_blob(blob, (u_int)n); -- xfree(blob); -+ free(blob); - if (k == NULL) { - logerror("key_read: key_from_blob %s failed", cp); - return -1; -@@ -526,8 +526,8 @@ - fprintf(f, "%s %s", key_ssh_name(key), uu); - success = 1; - } -- xfree(blob); -- xfree(uu); -+ free(blob); -+ free(uu); - } - return success; - } -@@ -673,12 +673,12 @@ - switch (key_type_from_name(p)) { - case KEY_RSA1: - case KEY_UNSPEC: -- xfree(s); -+ free(s); - return 0; - } - } - verbose("key names ok: [%s]", names); -- xfree(s); -+ free(s); - return 1; - } - -@@ -743,7 +743,7 @@ - logerror("key_from_blob: remaining bytes in key blob %d", rlen); - out: - if (ktype != NULL) -- xfree(ktype); -+ free(ktype); - buffer_free(&b); - return key; - } ---- pam_ssh_agent_auth-0.9.3.orig/misc.c 2013-10-30 17:14:26.017615218 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/misc.c 2013-10-30 17:15:07.360327581 +0100 -@@ -251,13 +251,13 @@ - *remote = SSH_TUNID_ANY; - sp = xstrdup(s); - if ((ep = strchr(sp, ':')) == NULL) { -- xfree(sp); -+ free(sp); - return (a2tun(s, NULL)); - } - ep[0] = '\0'; ep++; - *remote = a2tun(ep, NULL); - tun = a2tun(sp, NULL); -- xfree(sp); -+ free(sp); - return (*remote == SSH_TUNID_ERR ? *remote : tun); - } - -@@ -490,7 +490,7 @@ - if (which >= args->num) - fatal("replacearg: tried to replace invalid arg %d >= %d", - which, args->num); -- xfree(args->list[which]); -+ free(args->list[which]); - args->list[which] = cp; - } - -@@ -501,8 +501,8 @@ - - if (args->list != NULL) { - for (i = 0; i < args->num; i++) -- xfree(args->list[i]); -- xfree(args->list); -+ free(args->list[i]); -+ free(args->list); - args->nalloc = args->num = 0; - args->list = NULL; - } ---- pam_ssh_agent_auth-0.9.3.orig/pam_user_authorized_keys.c 2013-10-30 17:14:26.017615218 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/pam_user_authorized_keys.c 2013-10-30 17:15:07.361327550 +0100 -@@ -121,7 +121,7 @@ - } - authorized_keys_file = tilde_expand_filename(auth_keys_file_buf, authorized_keys_file_allowed_owner_uid); - strncpy(auth_keys_file_buf, authorized_keys_file, sizeof(auth_keys_file_buf) - 1 ); -- xfree(authorized_keys_file) /* when we percent_expand later, we'd step on this, so free it immediately */; -+ free(authorized_keys_file) /* when we percent_expand later, we'd step on this, so free it immediately */; - } - - if(strstr(auth_keys_file_buf, "%h")) { ---- pam_ssh_agent_auth-0.9.3.orig/pam_user_key_allowed2.c 2013-10-30 17:14:26.018615187 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/pam_user_key_allowed2.c 2013-10-30 17:15:07.361327550 +0100 -@@ -121,7 +121,7 @@ - fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); - logit("Found matching %s key: %s", - key_type(found), fp); -- xfree(fp); -+ free(fp); - break; - } - } ---- pam_ssh_agent_auth-0.9.3.orig/ssh-dss.c 2013-10-30 17:14:26.014615310 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/ssh-dss.c 2013-10-30 17:15:07.361327550 +0100 -@@ -135,17 +135,17 @@ - if (strcmp("ssh-dss", ktype) != 0) { - logerror("ssh_dss_verify: cannot handle type %s", ktype); - buffer_free(&b); -- xfree(ktype); -+ free(ktype); - return -1; - } -- xfree(ktype); -+ free(ktype); - sigblob = buffer_get_string(&b, &len); - rlen = buffer_len(&b); - buffer_free(&b); - if (rlen != 0) { - logerror("ssh_dss_verify: " - "remaining bytes in signature %d", rlen); -- xfree(sigblob); -+ free(sigblob); - return -1; - } - } -@@ -167,7 +167,7 @@ - - /* clean up */ - memset(sigblob, 0, len); -- xfree(sigblob); -+ free(sigblob); - - /* sha1 the data */ - EVP_DigestInit(&md, evp_md); ---- pam_ssh_agent_auth-0.9.3.orig/ssh-rsa.c 2013-10-30 17:14:26.015615278 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/ssh-rsa.c 2013-10-30 17:15:07.362327518 +0100 -@@ -70,7 +70,7 @@ - - logerror("ssh_rsa_sign: RSA_sign failed: %s", - ERR_error_string(ecode, NULL)); -- xfree(sig); -+ free(sig); - return -1; - } - if (len < slen) { -@@ -80,7 +80,7 @@ - memset(sig, 0, diff); - } else if (len > slen) { - logerror("ssh_rsa_sign: slen %u slen2 %u", slen, len); -- xfree(sig); -+ free(sig); - return -1; - } - /* encode signature */ -@@ -96,7 +96,7 @@ - } - buffer_free(&b); - memset(sig, 's', slen); -- xfree(sig); -+ free(sig); - - return 0; - } -@@ -128,23 +128,23 @@ - if (strcmp("ssh-rsa", ktype) != 0) { - logerror("ssh_rsa_verify: cannot handle type %s", ktype); - buffer_free(&b); -- xfree(ktype); -+ free(ktype); - return -1; - } -- xfree(ktype); -+ free(ktype); - sigblob = buffer_get_string(&b, &len); - rlen = buffer_len(&b); - buffer_free(&b); - if (rlen != 0) { - logerror("ssh_rsa_verify: remaining bytes in signature %d", rlen); -- xfree(sigblob); -+ free(sigblob); - return -1; - } - /* RSA_verify expects a signature of RSA_size */ - modlen = RSA_size(key->rsa); - if (len > modlen) { - logerror("ssh_rsa_verify: len %u > modlen %u", len, modlen); -- xfree(sigblob); -+ free(sigblob); - return -1; - } else if (len < modlen) { - u_int diff = modlen - len; -@@ -158,7 +158,7 @@ - nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; - if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { - logerror("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); -- xfree(sigblob); -+ free(sigblob); - return -1; - } - EVP_DigestInit(&md, evp_md); -@@ -168,7 +168,7 @@ - ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); - memset(digest, 'd', sizeof(digest)); - memset(sigblob, 's', len); -- xfree(sigblob); -+ free(sigblob); - verbose("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); - return ret; - } -@@ -258,6 +258,6 @@ - ret = 1; - done: - if (decrypted) -- xfree(decrypted); -+ free(decrypted); - return ret; - } ---- pam_ssh_agent_auth-0.9.3.orig/userauth_pubkey_from_id.c 2013-10-30 17:14:26.014615310 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/userauth_pubkey_from_id.c 2013-10-30 17:15:07.362327518 +0100 -@@ -92,9 +92,9 @@ - if(&b != NULL) - buffer_free(&b); - if(sig != NULL) -- xfree(sig); -+ free(sig); - if(pkblob != NULL) -- xfree(pkblob); -+ free(pkblob); - CRYPTO_cleanup_all_ex_data(); - return authenticated; - } ---- pam_ssh_agent_auth-0.9.3.orig/uuencode.c 2013-10-30 17:14:26.015615278 +0100 -+++ pam_ssh_agent_auth-0.9.3.orig/uuencode.c 2013-10-30 17:15:07.362327518 +0100 -@@ -56,7 +56,7 @@ - /* and remove trailing whitespace because __b64_pton needs this */ - *p = '\0'; - len = __b64_pton(encoded, target, targsize); -- xfree(encoded); -+ free(encoded); - return len; - } - -@@ -79,5 +79,5 @@ - } - if (i % 70 != 69) - fprintf(fp, "\n"); -- xfree(buf); -+ free(buf); - } diff --git a/SOURCES/sshd.service b/SOURCES/sshd.service index ce0cdee..af7845c 100644 --- a/SOURCES/sshd.service +++ b/SOURCES/sshd.service @@ -12,7 +12,6 @@ ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s -RestartPreventExitStatus=255 [Install] WantedBy=multi-user.target diff --git a/SPECS/openssh.spec b/SPECS/openssh.spec index 4738d20..6f417e6 100644 --- a/SPECS/openssh.spec +++ b/SPECS/openssh.spec @@ -63,10 +63,10 @@ %endif # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%define openssh_ver 6.6.1p1 -%define openssh_rel 35 -%define pam_ssh_agent_ver 0.9.3 -%define pam_ssh_agent_rel 9 +%define openssh_ver 7.4p1 +%define openssh_rel 11 +%define pam_ssh_agent_ver 0.10.3 +%define pam_ssh_agent_rel 1 Summary: An open source implementation of SSH protocol versions 1 and 2 Name: openssh @@ -74,8 +74,7 @@ Version: %{openssh_ver} Release: %{openssh_rel}%{?dist}%{?rescue_rel} URL: http://www.openssh.com/portable.html #URL1: http://pamsshagentauth.sourceforge.net -# Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz -Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-6.6p1.tar.gz +Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz #Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc Source2: sshd.pam Source3: sshd.init @@ -93,34 +92,35 @@ Source13: sshd-keygen Patch0: openssh-5.9p1-wIm.patch #? -Patch100: openssh-6.6.1p1-coverity.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1872 -Patch101: openssh-6.6p1-fingerprint.patch +Patch100: openssh-7.4p1-coverity.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1889 Patch103: openssh-5.8p1-packet.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1402 -Patch200: openssh-6.6p1-audit.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1171248 # record pfs= field in CRYPTO_SESSION audit event -Patch201: openssh-6.6.1p1-audit-pfs.patch +Patch200: openssh-7.4p1-audit.patch # Do not write to one socket from more processes (#1310684) Patch202: openssh-6.6p1-audit-race-condition.patch # --- pam_ssh-agent --- # make it build reusing the openssh sources -Patch300: pam_ssh_agent_auth-0.9.3-build.patch +Patch300: pam_ssh_agent_auth-0.10.3-build.patch # check return value of seteuid() -Patch301: pam_ssh_agent_auth-0.9.2-seteuid.patch +Patch301: pam_ssh_agent_auth-0.10.3-seteuid.patch # explicitly make pam callbacks visible Patch302: pam_ssh_agent_auth-0.9.2-visibility.patch # don't use xfree (#1024965) -Patch303: pam_ssh_agent_auth-0.9.3-no-xfree.patch -# don't use xfree (#1024965) -Patch304: pam_ssh_agent_auth-0.9.3-command.patch +Patch303: pam_ssh_agent_auth-0.10.3-no-xfree.patch +# update to current version of agent structure +Patch304: pam_ssh_agent_auth-0.10.3-agent_structure.patch +# do not directly dereference return value of getpwuid() +Patch305: pam_ssh_agent_auth-0.10.3-dereference.patch +# Use hardcoded date -- getting it from file is broken on i386 +Patch306: pam_ssh_agent_auth-0.10.3-man-date.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) -Patch400: openssh-6.6p1-role-mls.patch +Patch400: openssh-7.4p1-role-mls.patch #https://bugzilla.redhat.com/show_bug.cgi?id=781634 Patch404: openssh-6.6p1-privsep-selinux.patch @@ -137,13 +137,11 @@ Patch604: openssh-6.6p1-keyperm.patch Patch606: openssh-5.9p1-ipv6man.patch #? Patch607: openssh-5.8p2-sigpipe.patch -#? -Patch608: openssh-6.1p1-askpass-ld.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1789 Patch609: openssh-5.5p1-x11.patch #? -Patch700: openssh-6.6p1-fips.patch +Patch700: openssh-7.4p1-fips.patch #? # drop? Patch701: openssh-5.6p1-exit-deadlock.patch #? @@ -165,12 +163,14 @@ Patch711: openssh-6.6p1-log-usepam-no.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 -Patch713: openssh-6.6p1-ctr-cavstest.patch +Patch713: openssh-7.4p1-ctr-cavstest.patch +# add SSH KDF CAVS test driver +Patch714: openssh-7.4p1-kdf-cavs.patch #http://www.sxw.org.uk/computing/patches/openssh.html #changed cache storage type - #848228 -Patch800: openssh-6.6p1-gsskex.patch +Patch800: openssh-7.4p1-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) @@ -180,97 +180,63 @@ Patch802: openssh-6.6p1-GSSAPIEnablek5users.patch Patch803: openssh-6.6p1-k5login_directory.patch Patch900: openssh-6.1p1-gssapi-canohost.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1780 -Patch901: openssh-6.6p1-kuserok.patch +Patch901: openssh-7.4p1-kuserok.patch # use default_ccache_name from /etc/krb5.conf (#991186) Patch902: openssh-6.3p1-krb5-use-default_ccache_name.patch # Run ssh-copy-id in the legacy mode when SSH_COPY_ID_LEGACY variable is set (#969375 -Patch905: openssh-6.4p1-legacy-ssh-copy-id.patch +Patch905: openssh-7.4p1-legacy-ssh-copy-id.patch # Use tty allocation for a remote scp (#985650) Patch906: openssh-6.4p1-fromto-remote.patch -# Try CLOCK_BOOTTIME with fallback (#1091992) -Patch907: openssh-6.4p1-CLOCK_BOOTTIME.patch -# Prevents a server from skipping SSHFP lookup and forcing a new-hostkey -# dialog by offering only certificate keys. (#1081338) -Patch908: openssh-6.6p1-CVE-2014-2653.patch -# OpenSSH 6.5 and 6.6 sometimes encode a value used in the curve25519 key exchange incorrectly -# Disable the curve25519 KEX when speaking to OpenSSH 6.5 or 6.6 -Patch909: openssh-5618210618256bbf5f4f71b2887ff186fd451736.patch -# standardise on NI_MAXHOST for gethostname() string lengths (#1051490) -Patch910: openssh-6.6.1p1-NI_MAXHOST.patch -# set a client's address right after a connection is set -# http://bugzilla.mindrot.org/show_bug.cgi?id=2257 -Patch911: openssh-6.6p1-set_remote_ipaddr.patch -# apply RFC3454 stringprep to banners when possible -# https://bugzilla.mindrot.org/show_bug.cgi?id=2058 -# slightly changed patch from comment 10 -Patch912: openssh-6.6.1p1-utf8-banner.patch -# don't consider a partial success as a failure -# https://bugzilla.mindrot.org/show_bug.cgi?id=2270 -Patch913: openssh-6.6.1p1-partial-success.patch # log when a client requests an interactive session and only sftp is allowed (#1130198) Patch914: openssh-6.6.1p1-log-sftp-only-connections.patch -# fix parsing of empty options in sshd_conf -# https://bugzilla.mindrot.org/show_bug.cgi?id=2281 -Patch915: openssh-6.6.1p1-servconf-parser.patch -# Ignore SIGXFSZ in postauth monitor -# https://bugzilla.mindrot.org/show_bug.cgi?id=2263 -Patch916: openssh-6.6.1p1-ignore-SIGXFSZ-in-postauth.patch # log via monitor in chroots without /dev/log (#1083482) -Patch918: openssh-6.6.1p1-log-in-chroot.patch +Patch918: openssh-7.4p1-log-in-chroot.patch # MLS labeling according to chosen sensitivity (#1202843) Patch919: openssh-6.6.1p1-mls-fix-labeling.patch # sshd test mode show all config values (#1187597) Patch920: openssh-6.6p1-test-mode-all-values.patch # Add sftp option to force mode of created files (#1191055) Patch921: openssh-6.6p1-sftp-force-permission.patch -# TERM env variable is always accepted by sshd, regardless the empty AcceptEnv setting (#1162683) -Patch922: openssh-6.6p1-document-TERM-env.patch -# fix ssh-copy-id on non-sh remote shells (#1201758) -Patch923: openssh-6.6p1-fix-ssh-copy-id-on-non-sh-shell.patch # fix memory problem (#1223218) Patch924: openssh-6.6p1-memory-problems.patch # Enhance AllowGroups documentation in man page (#1150007) Patch925: openssh-6.6p1-allowGroups-documentation.patch -# authentication limits (MaxAuthTries) bypass [security] (#1246521) -Patch926: openssh-6.6p1-authentication-limits-bypass.patch -# CVE-2015-5352: Security fixes backported from openssh-6.9 (#1247864) -# XSECURITY restrictions bypass under certain conditions in ssh(1) (#1238231) -# weakness of agent locking (ssh-add -x) to password guessing (#1238238) -Patch927: openssh-6.6p1-ssh-agent-and-xsecurity-bypass.patch # provide option GssKexAlgorithms to disable vulnerable groun1 kex -Patch928: openssh-6.6p1-gssKexAlgorithms.patch -# Vulnerabilities published with openssh-7.0 (#1265807): -# Privilege separation weakness related to PAM support -# Use-after-free bug related to PAM support -Patch929: openssh-6.6p1-security-7.0.patch -# Disable completely Roaming feature on client (#1298218) (#1298217) -# Mitigates CVE-2016-0777 and CVE-2016-0778 -Patch930: openssh-6.6p1-disable-roaming.patch -# CVE-2016-3115: missing sanitisation of input for X11 forwarding (#1316829) -Patch931: openssh-6.6p1-CVE-2016-3115.patch -# CVE-2016-1908: possible fallback from untrusted X11 forwarding (#1298741) -Patch932: openssh-6.6p1-fallback-X11-untrusted.patch -# CVE-2015-8325: privilege escalation via user's PAM environment and UseLogin=yes (#1328012) -Patch933: openssh-6.6p1-CVE-2015-8325.patch -# close ControlPersist background process stderr when not in debug mode (#1335540) -Patch934: openssh-6.6p1-ControlPersist-stderr.patch +Patch928: openssh-7.4p1-gssKexAlgorithms.patch # make s390 use /dev/ crypto devices -- ignore closefrom (#1318760) Patch935: openssh-6.6p1-s390-closefrom.patch -# Default value and proper dump of AuthenticationMethods (#1237129) -Patch936: openssh-6.6p1-AuthenticationMethods.patch -# ssh-copy-id does not work with LogLevel=quiet (#1349556) -Patch937: openssh-6.6p1-ssh-copy-id-quiet.patch # expose more information to PAM (#1312304) -Patch938: openssh-6.6p1-expose-auth-information.patch +Patch938: openssh-7.4p1-expose-pam.patch # Move MAX_DISPLAYS to a configuration option (#1341302) Patch939: openssh-6.6p1-x11-max-displays.patch -# Add a wildcard option to PermitOpen directive (#1344106) -Patch940: openssh-6.6p1-permitopen-any-host.patch -# Rework capabilities handling for SELinux confined users (#1357859) -Patch941: openssh-6.6p1-chroot-capabilities.patch # Add systemd stuff so it can track running service (#1381997) Patch942: openssh-6.6p1-systemd.patch - +# Permit root login to preserve backward compatibility +Patch943: openssh-7.4p1-permit-root-login.patch +# Restore TCP wrappers support +Patch944: openssh-7.4p1-debian-restore-tcp-wrappers.patch +# Set sane whitelist for PKCS#11 modules in ssh-agent +Patch945: openssh-7.4p1-pkcs11-whitelist.patch +# Allow legacy algorithms and formats for key exchange after rebase +Patch946: openssh-7.4p1-legacy-algorithms.patch +# Show more fingerprints +Patch947: openssh-7.4p1-show-more-fingerprints.patch +# Fix newline in the end of server ident banner (upstream 5b9070) +Patch948: openssh-7.4p1-newline-banner.patch +# Do not utilize SHA1 by default for digital signatures (#1322911) +Patch949: openssh-7.4p1-sha2-signatures.patch +# Canonize pkcs11 provider path when removing smartcard (#2682) +Patch950: openssh-7.4p1-canonize-pkcs11-provider.patch +# Do not segfault sshd if it loads RSA1 keys (#2686) +Patch951: openssh-7.4p1-rsa1-segfault.patch +# OpenSSH 7.5 fixes CBC cipher weakness +Patch952: openssh-7.4p1-cbc-weakness.patch +# sandbox-seccomp filter is not denying socketcall() on ppc64le (#1443916) +Patch953: openssh-7.4p1-sandbox-ppc64le.patch +# ControlPath too long should not be fatal (#1447561) +Patch954: openssh-7.4p1-ControlPath_too_long.patch +# sandbox-seccomp for ibmca engine from upstream (#1451809) +Patch955: openssh-7.4p1-sandbox-ibmca.patch License: BSD Group: Applications/Internet @@ -313,7 +279,6 @@ Requires: libselinux >= 1.27.7 BuildRequires: libselinux-devel >= 1.27.7 Requires: audit-libs >= 1.0.8 BuildRequires: audit-libs >= 1.0.8 -BuildRequires: libcap-ng-devel %endif BuildRequires: xauth @@ -359,6 +324,11 @@ Requires: openssh = %{version}-%{release} Obsoletes: openssh-askpass-gnome Provides: openssh-askpass-gnome +%package cavs +Summary: CAVS tests for FIPS validation +Group: Applications/Internet +Requires: openssh = %{version}-%{release} + %package -n pam_ssh_agent_auth Summary: PAM module for authentication with ssh-agent Group: System Environment/Base @@ -414,6 +384,10 @@ OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains an X11 passphrase dialog for OpenSSH. +%description cavs +This package contains test binaries and scripts to make FIPS validation +easier. Now contains CTR and KDF CAVS test driver. + %description -n pam_ssh_agent_auth This package contains a PAM module which can be used to authenticate users using ssh keys stored in a ssh-agent. Through the use of the @@ -423,22 +397,23 @@ remote ssh-agent instance. The module is most useful for su and sudo service stacks. %prep -%setup -q -a 4 -n openssh-6.6p1 +%setup -q -a 4 #Do not enable by default %if 0 %patch0 -p1 -b .wIm %endif -%patch101 -p1 -b .fingerprint %patch103 -p1 -b .packet %if %{pam_ssh_agent} pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} -%patch300 -p1 -b .psaa-build -%patch301 -p1 -b .psaa-seteuid +%patch300 -p2 -b .psaa-build +%patch301 -p2 -b .psaa-seteuid %patch302 -p1 -b .psaa-visibility -%patch303 -p1 -b .psaa-xfree -%patch304 -p2 -b .psaa-command +%patch303 -p2 -b .psaa-xfree +%patch304 -p2 -b .psaa-agent +%patch305 -p2 -b .psaa-dereference +%patch306 -p2 -b .psaa-pod # Remove duplicate headers rm -f $(cat %{SOURCE5}) popd @@ -458,7 +433,6 @@ popd %patch604 -p1 -b .keyperm %patch606 -p1 -b .ipv6man %patch607 -p1 -b .sigpipe -%patch608 -p1 -b .askpass-ld %patch609 -p1 -b .x11 # # drop? %patch701 -p1 -b .exit-deadlock @@ -473,6 +447,7 @@ popd %patch711 -p1 -b .log-usepam-no %patch712 -p1 -b .evp-ctr %patch713 -p1 -b .ctr-cavs +%patch714 -p1 -b .kdf-cavs # %patch800 -p1 -b .gsskex %patch801 -p1 -b .force_krb @@ -482,46 +457,35 @@ popd %patch902 -p1 -b .ccache_name %patch905 -p1 -b .legacy-ssh-copy-id %patch906 -p1 -b .fromto-remote -%patch907 -p1 -b .CLOCK_BOOTTIME -%patch908 -p1 -b .CVE-2014-2653 -%patch909 -p1 -b .6.6.1 -%patch910 -p1 -b .NI_MAXHOST -%patch911 -p1 -b .set_remote_ipaddr -%patch912 -p1 -b .utf8-banner -%patch913 -p1 -b .partial-success %patch914 -p1 -b .log-sftp-only -%patch915 -p1 -b .servconf -%patch916 -p1 -b .SIGXFSZ %patch918 -p1 -b .log-in-chroot %patch919 -p1 -b .mls-labels %patch802 -p1 -b .GSSAPIEnablek5users %patch803 -p1 -b .k5login %patch920 -p1 -b .sshd-t %patch921 -p1 -b .sftp-force-mode -%patch922 -p1 -b .term -%patch923 -p1 -b .ssh-copy-id %patch924 -p1 -b .memory-problems %patch925 -p1 -b .allowGroups -%patch926 -p1 -b .kbd -%patch927 -p1 -b .xsecurity %patch928 -p1 -b .gsskexalg -%patch929 -p1 -b .security7 -%patch930 -p1 -b .roaming -%patch931 -p1 -b .xauth -%patch932 -p1 -b .untrusted -%patch933 -p1 -b .uselogin -%patch934 -p1 -b .stderr %patch935 -p1 -b .s390 -%patch936 -p1 -b .auth_meth -%patch937 -p1 -b .quiet -%patch938 -p1 -b .expose-auth +%patch938 -p1 -b .expose-pam %patch939 -p1 -b .x11max -%patch940 -p1 -b .permitopen -%patch941 -p1 -b .chroot-cap %patch942 -p1 -b .patch +%patch943 -p1 -b .permit-root +%patch944 -p1 -b .tcp_wrappers +%patch945 -p1 -b .pkcs11-whitelist +%patch946 -p1 -b .legacy +%patch947 -p1 -b .fingerprint +%patch948 -p1 -b .newline-banner +%patch949 -p1 -b .sha2 +%patch950 -p1 -b .smartcard +%patch951 -p1 -b .rsa1 +%patch952 -p1 -b .cbc +%patch953 -p1 -b .seccomp +%patch954 -p1 -b .ControlPath +%patch955 -p1 -b .ibmca %patch200 -p1 -b .audit -%patch201 -p1 -b .audit-fps %patch202 -p1 -b .audit-race %patch700 -p1 -b .fips @@ -586,6 +550,7 @@ fi --with-ssl-engine \ --with-ipaddr-display \ --with-systemd \ + --with-ssh1 \ %if %{ldap} --with-ldap \ %endif @@ -596,8 +561,7 @@ fi %endif %if %{WITH_SELINUX} --with-selinux --with-audit=linux \ -%if 0 -#seccomp_filter cannot be build right now +%ifnarch ppc --with-sandbox=seccomp_filter \ %else --with-sandbox=rlimit \ @@ -688,6 +652,13 @@ install -m644 %{SOURCE12} $RPM_BUILD_ROOT/%{_unitdir}/sshd-keygen.service install -m755 contrib/ssh-copy-id $RPM_BUILD_ROOT%{_bindir}/ install contrib/ssh-copy-id.1 $RPM_BUILD_ROOT%{_mandir}/man1/ +#restore slogin symlink +pushd $RPM_BUILD_ROOT%{_bindir} +ln -s ./ssh slogin +pushd $RPM_BUILD_ROOT%{_mandir}/man1 +ln -s ./ssh.1 slogin.1 +popd; popd; + %if ! %{no_gnome_askpass} install contrib/gnome-ssh-askpass $RPM_BUILD_ROOT%{_libexecdir}/openssh/gnome-ssh-askpass %endif @@ -823,6 +794,11 @@ getent passwd sshd >/dev/null || \ %attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass %endif +%files cavs +%attr(0755,root,root) %{_libexecdir}/openssh/ctr-cavstest +%attr(0755,root,root) %{_libexecdir}/openssh/ssh-cavs +%attr(0755,root,root) %{_libexecdir}/openssh/ssh-cavs_driver.pl + %if %{pam_ssh_agent} %files -n pam_ssh_agent_auth %defattr(-,root,root) @@ -833,6 +809,43 @@ getent passwd sshd >/dev/null || \ %endif %changelog +* Mon May 22 2017 Jakub Jelen - 7.4p1-11 + 0.10.3-1 +- Compiler warnings (#1341754) + +* Mon May 22 2017 Jakub Jelen - 7.4p1-10 + 0.10.3-1 +- Add missing messages in FIPS mode (#1341754) + +* Fri May 19 2017 Jakub Jelen - 7.4p1-9 + 0.10.3-1 +- Allow harmless syscalls for s390 crypto modules (#1451809) + +* Mon May 15 2017 Jakub Jelen - 7.4p1-8 + 0.10.3-1 +- Fix multilib issue in documentation (#1450361) + +* Thu May 04 2017 Jakub Jelen - 7.4p1-6 + 0.10.3-1 +- ControlPath too long should not be a fatal error (#1447561) + +* Wed Apr 26 2017 Jakub Jelen - 7.4p1-5 + 0.10.3-1 +- Fix the default key exchange proposal in FIPS mode (#1438414) +- Remove another wrong coverity chunk to unbreak gsskex (#1438414) + +* Mon Apr 24 2017 Jakub Jelen - 7.4p1-4 + 0.10.3-1 +- Update seccomp filter to work on ppc64le (#1443916) + +* Wed Apr 05 2017 Jakub Jelen - 7.4p1-3 + 0.10.3-1 +- Do not completely disable SHA-1 key exchange methods in FIPS (#1324493) +- Remove wrong coverity patches + +* Thu Mar 23 2017 Jakub Jelen - 7.4p1-2 + 0.10.3-1 +- Fix coverity scan results +- Adjust FIPS algorithms list (#1420910) +- Revert problematic feature for chroot(#1418062) +- Fix CBC weakness in released OpenSSH 7.5 + +* Wed Mar 01 2017 Jakub Jelen - 7.4p1-1 + 0.10.3-1 +- Rebase to openssh 7.4 and pam_ssh_agent_auth 0.10.3 (#1341754) +- detach -cavs subpackage +- enable seccomp filter for sandboxed child + * Wed Mar 01 2017 Jakub Jelen - 6.6.1p1-35 + 0.9.3-9 - Do not send SD_NOTIFY from forked childern (#1381997)