From 56e0af81548d743d14831fd2e52a1e038f4870891c5f39c1f725cf26542ef7bf Mon Sep 17 00:00:00 2001 From: Petr Cerny Date: Fri, 1 Dec 2017 15:03:13 +0000 Subject: [PATCH] Accepting request 547144 from home:pcerny:factory temporarily downgrading to 7.2p2 to run tests on additional 7.2p2 patches OBS-URL: https://build.opensuse.org/request/show/547144 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=124 --- openssh-7.2p2-IPv6_X_forwarding.patch | 72 + ...openssh-7.2p2-X11_trusted_forwarding.patch | 22 +- ...h-7.2p2-X_forward_with_disabled_ipv6.patch | 34 + openssh-7.2p2-additional_seccomp_archs.patch | 56 + openssh-7.2p2-allow_DSS_by_default.patch | 129 + openssh-7.2p2-allow_root_password_login.patch | 95 + openssh-7.2p2-audit.patch | 3239 ++++++++++++++ openssh-7.2p2-audit_fixes.patch | 35 + openssh-7.2p2-audit_seed_prng.patch | 116 + ....patch => openssh-7.2p2-blocksigalrm.patch | 25 +- openssh-7.2p2-cavstest-ctr.patch | 300 ++ openssh-7.2p2-cavstest-kdf.patch | 469 ++ openssh-7.2p2-disable_openssl_abi_check.patch | 64 + ...sh-7.2p2-disable_preauth_compression.patch | 1317 ++++++ ...sh-7.2p2-disable_short_DH_parameters.patch | 345 +- openssh-7.2p2-dont_use_pthreads_in_PAM.patch | 29 + openssh-7.2p2-eal3.patch | 87 + openssh-7.2p2-enable_PAM_by_default.patch | 47 + openssh-7.2p2-fips.patch | 1834 ++++++++ openssh-7.2p2-fips_fixes.patch | 31 + openssh-7.2p2-gssapi_key_exchange.patch | 3963 +++++++++++++++++ openssh-7.2p2-host_ident.patch | 29 + ...2-hostname_changes_when_forwarding_X.patch | 56 +- openssh-7.2p2-ignore_PAM_with_UseLogin.patch | 33 + openssh-7.2p2-keep_slogin.patch | 66 + openssh-7.2p2-kex_resource_depletion.patch | 30 + ...stlog.patch => openssh-7.2p2-lastlog.patch | 8 +- openssh-7.2p2-ldap.patch | 2838 ++++++++++++ openssh-7.2p2-limit_password_length.patch | 52 + openssh-7.2p2-login_options.patch | 32 + openssh-7.2p2-no_fork-no_pid_file.patch | 26 + ...tch => openssh-7.2p2-pam_check_locks.patch | 102 +- ...sh-7.2p2-prevent_private_key_leakage.patch | 188 + ....2p2-prevent_timing_user_enumeration.patch | 264 ++ ...> openssh-7.2p2-pts_names_formatting.patch | 8 +- ...h-7.2p2-remove_xauth_cookies_on_exit.patch | 14 +- openssh-7.2p2-restrict_pkcs11-modules.patch | 297 ++ ....2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch | 82 + openssh-7.2p2-s390_hw_crypto_syscalls.patch | 100 + openssh-7.2p2-seccomp_geteuid.patch | 34 + openssh-7.2p2-seccomp_getuid.patch | 31 + openssh-7.2p2-seccomp_stat.patch | 30 + ...7.2p2-secure_unix_sockets_forwarding.patch | 51 + openssh-7.2p2-seed-prng.patch | 461 ++ ...e.patch => openssh-7.2p2-send_locale.patch | 20 +- openssh-7.2p2-sftp_force_permissions.patch | 157 + openssh-7.2p2-sftp_homechroot.patch | 366 ++ ...7.2p2-sftp_print_diagnostic_messages.patch | 130 + ...2-ssh_case_insensitive_host_matching.patch | 87 + openssh-7.2p2-stricter_readonly_sftp.patch | 32 + openssh-7.2p2-systemd-notify.patch | 134 + openssh-7.2p2-tcpwrappers.patch | 433 ++ ...ssh-7.2p2-verify_CIDR_address_ranges.patch | 175 + openssh-7.2p2.tar.gz | 3 + openssh-7.2p2.tar.gz.asc | 14 + openssh-7.6p1-allow_root_password_login.patch | 95 - openssh-7.6p1-eal3.patch | 27 - openssh-7.6p1-enable_PAM_by_default.patch | 28 - openssh-7.6p1-seccomp_geteuid.patch | 34 - openssh-7.6p1-seccomp_getuid.patch | 31 - openssh-7.6p1-seccomp_stat.patch | 30 - openssh-7.6p1.tar.gz | 3 - openssh-7.6p1.tar.gz.asc | 14 - openssh-askpass-gnome.changes | 6 - openssh-askpass-gnome.spec | 2 +- openssh.changes | 597 +-- openssh.spec | 133 +- 67 files changed, 18515 insertions(+), 1177 deletions(-) create mode 100644 openssh-7.2p2-IPv6_X_forwarding.patch rename openssh-7.6p1-X11_trusted_forwarding.patch => openssh-7.2p2-X11_trusted_forwarding.patch (80%) create mode 100644 openssh-7.2p2-X_forward_with_disabled_ipv6.patch create mode 100644 openssh-7.2p2-additional_seccomp_archs.patch create mode 100644 openssh-7.2p2-allow_DSS_by_default.patch create mode 100644 openssh-7.2p2-allow_root_password_login.patch create mode 100644 openssh-7.2p2-audit.patch create mode 100644 openssh-7.2p2-audit_fixes.patch create mode 100644 openssh-7.2p2-audit_seed_prng.patch rename openssh-7.6p1-blocksigalrm.patch => openssh-7.2p2-blocksigalrm.patch (75%) create mode 100644 openssh-7.2p2-cavstest-ctr.patch create mode 100644 openssh-7.2p2-cavstest-kdf.patch create mode 100644 openssh-7.2p2-disable_openssl_abi_check.patch create mode 100644 openssh-7.2p2-disable_preauth_compression.patch rename openssh-7.6p1-disable_short_DH_parameters.patch => openssh-7.2p2-disable_short_DH_parameters.patch (72%) create mode 100644 openssh-7.2p2-dont_use_pthreads_in_PAM.patch create mode 100644 openssh-7.2p2-eal3.patch create mode 100644 openssh-7.2p2-enable_PAM_by_default.patch create mode 100644 openssh-7.2p2-fips.patch create mode 100644 openssh-7.2p2-fips_fixes.patch create mode 100644 openssh-7.2p2-gssapi_key_exchange.patch create mode 100644 openssh-7.2p2-host_ident.patch rename openssh-7.6p1-hostname_changes_when_forwarding_X.patch => openssh-7.2p2-hostname_changes_when_forwarding_X.patch (67%) create mode 100644 openssh-7.2p2-ignore_PAM_with_UseLogin.patch create mode 100644 openssh-7.2p2-keep_slogin.patch create mode 100644 openssh-7.2p2-kex_resource_depletion.patch rename openssh-7.6p1-lastlog.patch => openssh-7.2p2-lastlog.patch (77%) create mode 100644 openssh-7.2p2-ldap.patch create mode 100644 openssh-7.2p2-limit_password_length.patch create mode 100644 openssh-7.2p2-login_options.patch create mode 100644 openssh-7.2p2-no_fork-no_pid_file.patch rename openssh-7.6p1-pam_check_locks.patch => openssh-7.2p2-pam_check_locks.patch (67%) create mode 100644 openssh-7.2p2-prevent_private_key_leakage.patch create mode 100644 openssh-7.2p2-prevent_timing_user_enumeration.patch rename openssh-7.6p1-pts_names_formatting.patch => openssh-7.2p2-pts_names_formatting.patch (88%) rename openssh-7.6p1-remove_xauth_cookies_on_exit.patch => openssh-7.2p2-remove_xauth_cookies_on_exit.patch (80%) create mode 100644 openssh-7.2p2-restrict_pkcs11-modules.patch create mode 100644 openssh-7.2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch create mode 100644 openssh-7.2p2-s390_hw_crypto_syscalls.patch create mode 100644 openssh-7.2p2-seccomp_geteuid.patch create mode 100644 openssh-7.2p2-seccomp_getuid.patch create mode 100644 openssh-7.2p2-seccomp_stat.patch create mode 100644 openssh-7.2p2-secure_unix_sockets_forwarding.patch create mode 100644 openssh-7.2p2-seed-prng.patch rename openssh-7.6p1-send_locale.patch => openssh-7.2p2-send_locale.patch (79%) create mode 100644 openssh-7.2p2-sftp_force_permissions.patch create mode 100644 openssh-7.2p2-sftp_homechroot.patch create mode 100644 openssh-7.2p2-sftp_print_diagnostic_messages.patch create mode 100644 openssh-7.2p2-ssh_case_insensitive_host_matching.patch create mode 100644 openssh-7.2p2-stricter_readonly_sftp.patch create mode 100644 openssh-7.2p2-systemd-notify.patch create mode 100644 openssh-7.2p2-tcpwrappers.patch create mode 100644 openssh-7.2p2-verify_CIDR_address_ranges.patch create mode 100644 openssh-7.2p2.tar.gz create mode 100644 openssh-7.2p2.tar.gz.asc delete mode 100644 openssh-7.6p1-allow_root_password_login.patch delete mode 100644 openssh-7.6p1-eal3.patch delete mode 100644 openssh-7.6p1-enable_PAM_by_default.patch delete mode 100644 openssh-7.6p1-seccomp_geteuid.patch delete mode 100644 openssh-7.6p1-seccomp_getuid.patch delete mode 100644 openssh-7.6p1-seccomp_stat.patch delete mode 100644 openssh-7.6p1.tar.gz delete mode 100644 openssh-7.6p1.tar.gz.asc diff --git a/openssh-7.2p2-IPv6_X_forwarding.patch b/openssh-7.2p2-IPv6_X_forwarding.patch new file mode 100644 index 0000000..8cbf2f8 --- /dev/null +++ b/openssh-7.2p2-IPv6_X_forwarding.patch @@ -0,0 +1,72 @@ +# HG changeset patch +# Parent 9130c9e19c8a076a7f6f214070283cd3e0326894 +Correctly parse DISPLAY variable for cases where it contains an IPv6 address +(which should - but not always is - in (square) brackets). + +bnc#847710 - https://bugzilla.novell.com/show_bug.cgi?id=847710 + +diff --git a/openssh-7.2p2/channels.c b/openssh-7.2p2/channels.c +--- a/openssh-7.2p2/channels.c ++++ b/openssh-7.2p2/channels.c +@@ -4049,18 +4049,19 @@ x11_connect_display(void) + /* OK, we now have a connection to the display. */ + return sock; + } + #endif + /* + * Check if it is a unix domain socket. Unix domain displays are in + * one of the following formats: unix:d[.s], :d[.s], ::d[.s] + */ ++ cp = strrchr(display, ':'); + if (strncmp(display, "unix:", 5) == 0 || +- display[0] == ':') { ++ (display[0] == ':' && ((cp - display) < 2)) ) { + /* Connect to the unix domain socket. */ + if (sscanf(strrchr(display, ':') + 1, "%u", &display_number) != 1) { + error("Could not parse display number from DISPLAY: %.100s", + display); + return -1; + } + /* Create a socket. */ + sock = connect_local_xsocket(display_number); +@@ -4068,30 +4069,39 @@ x11_connect_display(void) + return -1; + + /* OK, we now have a connection to the display. */ + return sock; + } + /* + * Connect to an inet socket. The DISPLAY value is supposedly + * hostname:d[.s], where hostname may also be numeric IP address. ++ * Note that IPv6 numberic addresses contain colons (e.g. ::1:0) + */ + strlcpy(buf, display, sizeof(buf)); +- cp = strchr(buf, ':'); ++ cp = strrchr(buf, ':'); + if (!cp) { + error("Could not find ':' in DISPLAY: %.100s", display); + return -1; + } + *cp = 0; + /* buf now contains the host name. But first we parse the display number. */ + if (sscanf(cp + 1, "%u", &display_number) != 1) { + error("Could not parse display number from DISPLAY: %.100s", + display); + return -1; + } ++ ++ /* Remove brackets surrounding IPv6 addresses if there are any. */ ++ if (buf[0] == '[' && (cp = strchr(buf, ']'))) { ++ *cp = 0; ++ cp = buf + 1; ++ } else { ++ cp = buf; ++ } + + /* Look up the host address */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%u", 6000 + display_number); + if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { + error("%.100s: unknown host. (%s)", buf, diff --git a/openssh-7.6p1-X11_trusted_forwarding.patch b/openssh-7.2p2-X11_trusted_forwarding.patch similarity index 80% rename from openssh-7.6p1-X11_trusted_forwarding.patch rename to openssh-7.2p2-X11_trusted_forwarding.patch index 0aaae6c..95b8d04 100644 --- a/openssh-7.6p1-X11_trusted_forwarding.patch +++ b/openssh-7.2p2-X11_trusted_forwarding.patch @@ -1,14 +1,14 @@ # HG changeset patch -# Parent c004421528bc443fa9a56db1123005c92014e6b3 +# Parent 7197d7a6b7c90566c68e980b5f8b937c183e79d0 # enable trusted X11 forwarding by default in both sshd and sshsystem-wide # configuration # bnc#50836 (was suse #35836) Enable Trusted X11 forwarding by default, since the security benefits of having it disabled are negligible these days with XI2 being widely used. -diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config ---- a/openssh-7.6p1/ssh_config -+++ b/openssh-7.6p1/ssh_config +diff --git a/openssh-7.2p2/ssh_config b/openssh-7.2p2/ssh_config +--- a/openssh-7.2p2/ssh_config ++++ b/openssh-7.2p2/ssh_config @@ -12,19 +12,30 @@ # Any configuration value is only changed the first time it is set. # Thus, host-specific definitions should be at the beginning of the @@ -33,18 +33,18 @@ diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config +# expire after twenty minutes after remote login. + ForwardX11Trusted yes + + # RhostsRSAAuthentication no + # RSAAuthentication yes # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # BatchMode no # CheckHostIP yes - # AddressFamily any - # ConnectTimeout 0 -diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config ---- a/openssh-7.6p1/sshd_config -+++ b/openssh-7.6p1/sshd_config -@@ -80,17 +80,17 @@ AuthorizedKeysFile .ssh/authorized_keys +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -94,17 +94,17 @@ 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'. @@ -62,4 +62,4 @@ diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config #PrintLastLog yes #TCPKeepAlive yes #UseLogin no - #PermitUserEnvironment no + #UsePrivilegeSeparation sandbox diff --git a/openssh-7.2p2-X_forward_with_disabled_ipv6.patch b/openssh-7.2p2-X_forward_with_disabled_ipv6.patch new file mode 100644 index 0000000..89b74b5 --- /dev/null +++ b/openssh-7.2p2-X_forward_with_disabled_ipv6.patch @@ -0,0 +1,34 @@ +# HG changeset patch +# Parent a9e60634acb905a830a0f57ece296781ab08d0fb +Do not throw away already open sockets for X11 forwarding if another socket +family is not available for bind() + +diff --git a/openssh-7.2p2/channels.c b/openssh-7.2p2/channels.c +--- a/openssh-7.2p2/channels.c ++++ b/openssh-7.2p2/channels.c +@@ -3938,16 +3938,25 @@ x11_create_display_inet(int x11_display_ + if (ai->ai_family == AF_INET6) + sock_set_v6only(sock); + if (x11_use_localhost) + channel_set_reuseaddr(sock); + if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + debug2("bind port %d: %.100s", port, strerror(errno)); + close(sock); + ++ /* do not remove successfully opened ++ * sockets if the request failed because ++ * the protocol IPv4/6 is not available ++ * (e.g. IPv6 may be disabled while being ++ * supported) ++ */ ++ if (EADDRNOTAVAIL == errno) ++ continue; ++ + for (n = 0; n < num_socks; n++) { + close(socks[n]); + } + num_socks = 0; + break; + } + socks[num_socks++] = sock; + if (num_socks == NUM_SOCKS) diff --git a/openssh-7.2p2-additional_seccomp_archs.patch b/openssh-7.2p2-additional_seccomp_archs.patch new file mode 100644 index 0000000..a410f8d --- /dev/null +++ b/openssh-7.2p2-additional_seccomp_archs.patch @@ -0,0 +1,56 @@ +# HG changeset patch +# Parent e7bdbc5ea8971599466becf01bff12b9fcb5df3e +Enable the seccomp-bpf sandbox on more architectures + +upstream commit: b9c50614eba9d90939b2b119b6e1b7e03b462278 (7.3p1) +Author: Damien Miller +Date: Fri Jul 8 13:59:13 2016 +1000 + + whitelist more architectures for seccomp-bpf + + bz#2590 - testing and patch from Jakub Jelen + +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -818,16 +818,40 @@ main() { if (NSVersionOfRunTimeLibrary(" + seccomp_audit_arch=AUDIT_ARCH_I386 + ;; + arm*-*) + seccomp_audit_arch=AUDIT_ARCH_ARM + ;; + aarch64*-*) + seccomp_audit_arch=AUDIT_ARCH_AARCH64 + ;; ++ s390x-*) ++ seccomp_audit_arch=AUDIT_ARCH_S390X ++ ;; ++ s390-*) ++ seccomp_audit_arch=AUDIT_ARCH_S390 ++ ;; ++ powerpc64-*) ++ seccomp_audit_arch=AUDIT_ARCH_PPC64 ++ ;; ++ powerpc64le-*) ++ seccomp_audit_arch=AUDIT_ARCH_PPC64LE ++ ;; ++ mips-*) ++ seccomp_audit_arch=AUDIT_ARCH_MIPS ++ ;; ++ mipsel-*) ++ seccomp_audit_arch=AUDIT_ARCH_MIPSEL ++ ;; ++ mips64-*) ++ seccomp_audit_arch=AUDIT_ARCH_MIPS64 ++ ;; ++ mips64el-*) ++ seccomp_audit_arch=AUDIT_ARCH_MIPSEL64 ++ ;; + esac + if test "x$seccomp_audit_arch" != "x" ; then + AC_MSG_RESULT(["$seccomp_audit_arch"]) + AC_DEFINE_UNQUOTED([SECCOMP_AUDIT_ARCH], [$seccomp_audit_arch], + [Specify the system call convention in use]) + else + AC_MSG_RESULT([architecture not supported]) + fi diff --git a/openssh-7.2p2-allow_DSS_by_default.patch b/openssh-7.2p2-allow_DSS_by_default.patch new file mode 100644 index 0000000..ad19e35 --- /dev/null +++ b/openssh-7.2p2-allow_DSS_by_default.patch @@ -0,0 +1,129 @@ +# HG changeset patch +# Parent d33bce122aa351a56ce457be35feda52171f9088 +Enable DSS authentication by default to maintain compatibility with older +versions. + +bsc#983784 + +diff --git a/openssh-7.2p2/myproposal.h b/openssh-7.2p2/myproposal.h +--- a/openssh-7.2p2/myproposal.h ++++ b/openssh-7.2p2/myproposal.h +@@ -94,21 +94,23 @@ + #define KEX_CLIENT_KEX KEX_COMMON_KEX \ + "diffie-hellman-group-exchange-sha1," \ + "diffie-hellman-group14-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 \ + "chacha20-poly1305@openssh.com," \ + "aes128-ctr,aes192-ctr,aes256-ctr" \ + AESGCM_CIPHER_MODES + +diff --git a/openssh-7.2p2/ssh_config.5 b/openssh-7.2p2/ssh_config.5 +--- a/openssh-7.2p2/ssh_config.5 ++++ b/openssh-7.2p2/ssh_config.5 +@@ -887,19 +887,19 @@ Alternately if the specified value begin + character, then the specified key types will be appended to the default set + instead of replacing them. + The default for this option is: + .Bd -literal -offset 3n + ecdsa-sha2-nistp256-cert-v01@openssh.com, + 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-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 + to prefer their algorithms. + .Pp + The list of available key types may also be obtained using the + .Fl Q + option of +@@ -1325,19 +1325,19 @@ Alternately if the specified value begin + character, then the key types after it will be appended to the default + instead of replacing it. + The default for this option is: + .Bd -literal -offset 3n + ecdsa-sha2-nistp256-cert-v01@openssh.com, + 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-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 + .Fl Q + option of + .Xr ssh 1 + may be used to list supported key types. + .It Cm PubkeyAuthentication +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -651,19 +651,19 @@ Alternately if the specified value begin + character, then the specified key types will be appended to the default set + instead of replacing them. + The default for this option is: + .Bd -literal -offset 3n + ecdsa-sha2-nistp256-cert-v01@openssh.com, + 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-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 + .Fl Q + option of + .Xr ssh 1 + may be used to list supported key types. + .It Cm HostbasedAuthentication +@@ -743,19 +743,19 @@ environment variable. + Specifies the host key algorithms + that the server offers. + The default for this option is: + .Bd -literal -offset 3n + ecdsa-sha2-nistp256-cert-v01@openssh.com, + 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-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 the + .Fl Q + option of + .Xr ssh 1 + with an argument of + .Dq key . diff --git a/openssh-7.2p2-allow_root_password_login.patch b/openssh-7.2p2-allow_root_password_login.patch new file mode 100644 index 0000000..9500ee5 --- /dev/null +++ b/openssh-7.2p2-allow_root_password_login.patch @@ -0,0 +1,95 @@ +# HG changeset patch +# Parent c43ae523939377778762e81743b77b3c75eb4bd1 +Allow root login with password by default. While less secure than upstream +default of forbidding access to the root account with a password, we are +temporarily introducing this change to keep the default used in older OpenSSH +versions shipped with SLE. + +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -233,17 +233,17 @@ fill_default_server_options(ServerOption + options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); + if (options->server_key_bits == -1) + options->server_key_bits = 1024; + if (options->login_grace_time == -1) + options->login_grace_time = 120; + if (options->key_regeneration_time == -1) + options->key_regeneration_time = 3600; + 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) + options->ignore_user_known_hosts = 0; + if (options->print_motd == -1) + options->print_motd = 1; + if (options->print_lastlog == -1) + options->print_lastlog = 1; +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -36,17 +36,17 @@ + # Logging + # obsoletes QuietMode and FascistLogging + #SyslogFacility AUTH + #LogLevel INFO + + # Authentication: + + #LoginGraceTime 2m +-#PermitRootLogin prohibit-password ++#PermitRootLogin yes + #StrictModes yes + #MaxAuthTries 6 + #MaxSessions 10 + + #RSAAuthentication yes + #PubkeyAuthentication yes + + # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -710,17 +710,17 @@ DESCRIPTION + restrictions and permit any forwarding requests. An argument of + M-bM-^@M-^\noneM-bM-^@M-^] can be used to prohibit all forwarding requests. By + default all port forwarding requests are permitted. + + PermitRootLogin + Specifies whether root can log in using ssh(1). The argument + must be M-bM-^@M-^\yesM-bM-^@M-^], M-bM-^@M-^\prohibit-passwordM-bM-^@M-^], M-bM-^@M-^\without-passwordM-bM-^@M-^], + M-bM-^@M-^\forced-commands-onlyM-bM-^@M-^], or M-bM-^@M-^\noM-bM-^@M-^]. The default is +- M-bM-^@M-^\prohibit-passwordM-bM-^@M-^]. ++ M-bM-^@M-^\yesM-bM-^@M-^]. + + If this option is set to M-bM-^@M-^\prohibit-passwordM-bM-^@M-^] or + M-bM-^@M-^\without-passwordM-bM-^@M-^], password and keyboard-interactive + authentication are disabled for root. + + If this option is set to M-bM-^@M-^\forced-commands-onlyM-bM-^@M-^], root login with + public key authentication will be allowed, but only if the + command option has been specified (which may be useful for taking +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -1213,17 +1213,17 @@ Specifies whether root can log in using + The argument must be + .Dq yes , + .Dq prohibit-password , + .Dq without-password , + .Dq forced-commands-only , + or + .Dq no . + The default is +-.Dq prohibit-password . ++.Dq yes . + .Pp + If this option is set to + .Dq prohibit-password + or + .Dq without-password , + password and keyboard-interactive authentication are disabled for root. + .Pp + If this option is set to diff --git a/openssh-7.2p2-audit.patch b/openssh-7.2p2-audit.patch new file mode 100644 index 0000000..6394aca --- /dev/null +++ b/openssh-7.2p2-audit.patch @@ -0,0 +1,3239 @@ +# HG changeset patch +# Parent 83f18171bc2394ccd39fb176fe110b529da83a78 +Extended auditing through the Linux Auditing subsystem + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -94,16 +94,17 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ + kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ + kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o kexgssc.o \ + kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o kexgsss.o \ + platform-pledge.o + + LIBSSH_OBJS += fips.o ++LIBSSH_OBJS += auditstub.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o + + SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + audit.o audit-bsm.o audit-linux.o platform.o \ + sshpty.o sshlogin.o servconf.o serverloop.o \ + auth.o auth1.o auth2.o auth-options.o session.o \ +diff --git a/openssh-7.2p2/audit-bsm.c b/openssh-7.2p2/audit-bsm.c +--- a/openssh-7.2p2/audit-bsm.c ++++ b/openssh-7.2p2/audit-bsm.c +@@ -370,34 +370,53 @@ audit_connection_from(const char *host, + /* this is used on IPv4-only machines */ + tid->port = (dev_t)port; + tid->machine = inet_addr(host); + snprintf(buf, sizeof(buf), "%08x", tid->machine); + debug3("BSM audit: machine ID %s", buf); + #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 + audit_session_open(struct logininfo *li) + { + /* not implemented */ + } + + void + 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) + { + char textbuf[BSM_TEXTBUFSZ]; + static int logged_in = 0; + const char *user = the_authctxt ? the_authctxt->user : "(unknown user)"; + + if (cannot_audit(0)) +@@ -449,9 +468,45 @@ audit_event(ssh_audit_event_t event) + case SSH_AUTH_FAIL_KBDINT: + bsm_audit_bad_login("interactive password entry"); + break; + + default: + 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 --git a/openssh-7.2p2/audit-linux.c b/openssh-7.2p2/audit-linux.c +--- a/openssh-7.2p2/audit-linux.c ++++ b/openssh-7.2p2/audit-linux.c +@@ -30,97 +30,381 @@ + #include "includes.h" + #if defined(USE_LINUX_AUDIT) + #include + #include + #include + + #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" + ++#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; + + audit_fd = audit_open(); + 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; + 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; +- 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; ++ /* is the fingerprint_prefix() still needed? ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s%s rport=%d", ++ type, bits, sshkey_fingerprint_prefix(), fp, get_remote_port()); ++ */ ++ snprintf(buf, sizeof(buf), "key algo=%s size=%d fp=%s rport=%d", ++ type, bits, 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 */ + } +- /* not implemented */ ++ ++int ++audit_run_command(const char *command) ++{ ++ 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_run_command(const char *command) ++audit_end_command(int handle, const char *command) + { +- /* not implemented */ ++ 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 + audit_event(ssh_audit_event_t event) + { + switch(event) { + case SSH_AUTH_SUCCESS: +- case SSH_CONNECTION_CLOSE: +- 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", 1, event); + break; + ++ case SSH_NOLOGIN: ++ 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: + debug("%s: unhandled event %d", __func__, 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, 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, ++ 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/openssh-7.2p2/audit.c b/openssh-7.2p2/audit.c +--- a/openssh-7.2p2/audit.c ++++ b/openssh-7.2p2/audit.c +@@ -23,31 +23,38 @@ + * (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" + + #include + #include ++#include + + #ifdef SSH_AUDIT_EVENTS + + #include "audit.h" + #include "log.h" + #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 + * audit_connection_from() is called and MAY NOT be initialized when + * 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 + audit_classify_auth(const char *method) + { + if (strcmp(method, "none") == 0) + return SSH_AUTH_FAIL_NONE; + else if (strcmp(method, "password") == 0) +@@ -66,23 +73,20 @@ audit_classify_auth(const char *method) + else + return SSH_AUDIT_UNKNOWN; + } + + /* helper to return supplied username */ + 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); + } + + const char * + audit_event_lookup(ssh_audit_event_t ev) + { + int i; + static struct event_lookup_struct { +@@ -106,16 +110,50 @@ audit_event_lookup(ssh_audit_event_t ev) + }; + + for (i = 0; event_lookup[i].event != SSH_AUDIT_UNKNOWN; i++) + if (event_lookup[i].event == ev) + break; + 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. + * These get used if SSH_AUDIT_EVENTS is defined but no audit module is enabled. + */ + + /* + * Called after a connection has been accepted but before any authentication +@@ -135,16 +173,27 @@ audit_connection_from(const char *host, + void + audit_event(ssh_audit_event_t event) + { + debug("audit event euid %d user %s event %d (%s)", geteuid(), + audit_username(), event, audit_event_lookup(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. + * + * Note that this may be called multiple times if multiple sessions are used + * within a single connection. + */ + void + audit_session_open(struct logininfo *li) +@@ -169,18 +218,96 @@ audit_session_close(struct logininfo *li + + debug("audit session close euid %d user %s tty name %s", geteuid(), + audit_username(), t); + } + + /* + * 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, ++ sshkey_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, 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 --git a/openssh-7.2p2/audit.h b/openssh-7.2p2/audit.h +--- a/openssh-7.2p2/audit.h ++++ b/openssh-7.2p2/audit.h +@@ -23,16 +23,17 @@ + * (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 _SSH_AUDIT_H + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "key.h" + + enum ssh_audit_event_type { + SSH_LOGIN_EXCEED_MAXTRIES, + SSH_LOGIN_ROOT_DENIED, + SSH_AUTH_SUCCESS, + SSH_AUTH_FAIL_NONE, + SSH_AUTH_FAIL_PASSWD, + SSH_AUTH_FAIL_KBDINT, /* keyboard-interactive or challenge-response */ +@@ -40,18 +41,38 @@ enum ssh_audit_event_type { + SSH_AUTH_FAIL_HOSTBASED, /* ssh2 hostbased or ssh1 rhostsrsa */ + SSH_AUTH_FAIL_GSSAPI, + SSH_INVALID_USER, + SSH_NOLOGIN, /* denied by /etc/nologin, not implemented */ + SSH_CONNECTION_CLOSE, /* closed after attempting auth or session */ + 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 --git a/openssh-7.2p2/auditstub.c b/openssh-7.2p2/auditstub.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/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, char *pfs) ++{ ++} ++ ++void ++audit_session_key_free(int ctos) ++{ ++} ++ ++void ++audit_session_key_free_body(int ctos, pid_t pid, uid_t uid) ++{ ++} +diff --git a/openssh-7.2p2/auth-rsa.c b/openssh-7.2p2/auth-rsa.c +--- a/openssh-7.2p2/auth-rsa.c ++++ b/openssh-7.2p2/auth-rsa.c +@@ -96,16 +96,20 @@ int + auth_rsa_verify_response(Key *key, BIGNUM *challenge, + u_char response[SSH_DIGEST_MAX_LENGTH]) + { + u_char buf[2 * SSH_DIGEST_MAX_LENGTH], mdbuf[SSH_DIGEST_MAX_LENGTH]; + struct ssh_digest_ctx *md; + int len; + int dgst; + size_t dgst_len; ++ int 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) { + error("%s: RSA modulus too small: %d < minimum %d bits", + __func__, + BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); + return (0); + } +@@ -123,22 +127,28 @@ auth_rsa_verify_response(Key *key, BIGNU + if ((md = ssh_digest_start(dgst)) == NULL || + ssh_digest_update(md, buf, 2 * dgst_len) < 0 || + ssh_digest_update(md, session_id, dgst_len) < 0 || + ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0) + fatal("%s: md5 failed", __func__); + ssh_digest_free(md); + + /* Verify that the response is the original challenge. */ +- if (timingsafe_bcmp(response, mdbuf, dgst_len) != 0) { +- /* Wrong answer. */ +- return (0); +- } +- /* Correct answer. */ +- return (1); ++ rv = (timingsafe_bcmp(response, mdbuf, dgst_len) == 0); ++ ++#ifdef SSH_AUDIT_EVENTS ++ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (audit_keyusage(1, "ssh-rsa1", RSA_size(key->rsa) * 8, fp, rv) == 0) { ++ debug("unsuccessful audit"); ++ rv = 0; ++ } ++ free(fp); ++#endif ++ ++ return rv; + } + + /* + * Performs the RSA authentication challenge-response dialog with the client, + * and returns true (non-zero) if the client gave the correct answer to + * our challenge; returns zero if the client gives a wrong answer. + */ + +diff --git a/openssh-7.2p2/auth.c b/openssh-7.2p2/auth.c +--- a/openssh-7.2p2/auth.c ++++ b/openssh-7.2p2/auth.c +@@ -640,19 +640,16 @@ getpwnamallow(const char *user) + #endif + if (pw == NULL) { + logit("Invalid user %.100s from %.100s", + user, get_remote_ipaddr()); + #ifdef CUSTOM_FAILED_LOGIN + 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)) + return (NULL); + #ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(pw->pw_class)) == NULL) { + debug("unable to get login class: %s", user); + return (NULL); +diff --git a/openssh-7.2p2/auth.h b/openssh-7.2p2/auth.h +--- a/openssh-7.2p2/auth.h ++++ b/openssh-7.2p2/auth.h +@@ -187,16 +187,17 @@ int allowed_user(struct passwd *); + struct passwd * getpwnamallow(const char *user); + + char *get_challenge(Authctxt *); + int verify_response(Authctxt *, const char *); + 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); + int auth_key_is_revoked(Key *); + + HostStatus + check_key_in_hostfiles(struct passwd *, Key *, const char *, + const char *, const char *); +@@ -205,16 +206,17 @@ check_key_in_hostfiles(struct passwd *, + Key *get_hostkey_by_index(int); + Key *get_hostkey_public_by_index(int, struct ssh *); + Key *get_hostkey_public_by_type(int, int, struct ssh *); + Key *get_hostkey_private_by_type(int, int, struct ssh *); + int get_hostkey_index(Key *, int, struct ssh *); + int ssh1_session_key(BIGNUM *); + 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))); + void auth_debug_send(void); + void auth_debug_reset(void); + + struct passwd *fakepw(void); + +diff --git a/openssh-7.2p2/auth2-hostbased.c b/openssh-7.2p2/auth2-hostbased.c +--- a/openssh-7.2p2/auth2-hostbased.c ++++ b/openssh-7.2p2/auth2-hostbased.c +@@ -133,33 +133,45 @@ userauth_hostbased(Authctxt *authctxt) + #endif + + pubkey_auth_info(authctxt, key, + "client user \"%.100s\", client host \"%.100s\"", 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), ++ PRIVSEP(hostbased_key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) + authenticated = 1; + + buffer_free(&b); + done: + debug2("userauth_hostbased: authenticated %d", authenticated); + if (key != NULL) + key_free(key); + free(pkalg); + free(pkblob); + free(cuser); + free(chost); + free(sig); + 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, + Key *key) + { + const char *resolvedname, *ipaddr, *lookup, *reason; + HostStatus host_status; + int len; +diff --git a/openssh-7.2p2/auth2-pubkey.c b/openssh-7.2p2/auth2-pubkey.c +--- a/openssh-7.2p2/auth2-pubkey.c ++++ b/openssh-7.2p2/auth2-pubkey.c +@@ -171,17 +171,17 @@ userauth_pubkey(Authctxt *authctxt) + #ifdef DEBUG_PK + buffer_dump(&b); + #endif + pubkey_auth_info(authctxt, key, NULL); + + /* 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; + /* Record the successful key to prevent reuse */ + auth2_record_userkey(authctxt, key); + key = NULL; /* Don't free below */ + } + buffer_free(&b); + free(sig); +@@ -251,16 +251,28 @@ pubkey_auth_info(Authctxt *authctxt, con + auth_info(authctxt, "%s %s%s%s", key_type(key), + fp == NULL ? "(null)" : fp, + extra == NULL ? "" : ", ", extra == NULL ? "" : extra); + free(fp); + } + 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 + * and its members. + */ + static int + split_argv(const char *s, int *argcp, char ***argvp) + { +diff --git a/openssh-7.2p2/auth2.c b/openssh-7.2p2/auth2.c +--- a/openssh-7.2p2/auth2.c ++++ b/openssh-7.2p2/auth2.c +@@ -236,19 +236,16 @@ input_userauth_request(int type, u_int32 + authctxt->pw = PRIVSEP(getpwnamallow(user)); + authctxt->user = xstrdup(user); + if (authctxt->pw && strcmp(service, "ssh-connection")==0) { + authctxt->valid = 1; + debug2("input_userauth_request: setting up authctxt for %s", user); + } 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) + PRIVSEP(start_pam(authctxt)); + #endif + setproctitle("%s%s", authctxt->valid ? user : "unknown", + use_privsep ? " [net]" : ""); + authctxt->service = xstrdup(service); +diff --git a/openssh-7.2p2/cipher.c b/openssh-7.2p2/cipher.c +--- a/openssh-7.2p2/cipher.c ++++ b/openssh-7.2p2/cipher.c +@@ -55,36 +55,16 @@ + #include "log.h" + + #ifdef WITH_SSH1 + extern const EVP_CIPHER *evp_ssh1_bf(void); + extern const EVP_CIPHER *evp_ssh1_3des(void); + extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + #endif + +-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_all[] = { + #ifdef WITH_SSH1 + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, + { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, + { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, + #endif /* WITH_SSH1 */ + #ifdef WITH_OPENSSL + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, +diff --git a/openssh-7.2p2/cipher.h b/openssh-7.2p2/cipher.h +--- a/openssh-7.2p2/cipher.h ++++ b/openssh-7.2p2/cipher.h +@@ -57,17 +57,36 @@ + #define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ + #define SSH_CIPHER_BLOWFISH 6 + #define SSH_CIPHER_RESERVED 7 + #define SSH_CIPHER_MAX 31 + + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + +-struct sshcipher; ++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 ++}; ++ + struct sshcipher_ctx { + int plaintext; + int encrypt; + EVP_CIPHER_CTX evp; + struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ + struct aesctr_ctx ac_ctx; /* XXX union with evp? */ + const struct sshcipher *cipher; + }; +diff --git a/openssh-7.2p2/kex.c b/openssh-7.2p2/kex.c +--- a/openssh-7.2p2/kex.c ++++ b/openssh-7.2p2/kex.c +@@ -48,16 +48,17 @@ + #include "match.h" + #include "misc.h" + #include "dispatch.h" + #include "monitor.h" + + #include "ssherr.h" + #include "sshbuf.h" + #include "digest.h" ++#include "audit.h" + + #include "fips.h" + + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + + #if OPENSSL_VERSION_NUMBER >= 0x00907000L +@@ -684,18 +685,22 @@ kex_start_rekex(struct ssh *ssh) + return kex_send_kexinit(ssh); + } + + static int + choose_enc(struct sshenc *enc, char *client, char *server) + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_CIPHER); ++#endif + return SSH_ERR_NO_CIPHER_ALG_MATCH; ++ } + if ((enc->cipher = cipher_by_name(name)) == NULL) + return SSH_ERR_INTERNAL_ERROR; + enc->name = name; + enc->enabled = 0; + enc->iv = NULL; + enc->iv_len = cipher_ivlen(enc->cipher); + enc->key = NULL; + enc->key_len = cipher_keylen(enc->cipher); +@@ -703,36 +708,44 @@ choose_enc(struct sshenc *enc, char *cli + return 0; + } + + static int + choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_MAC); ++#endif + return SSH_ERR_NO_MAC_ALG_MATCH; ++ } + if (mac_setup(mac, name) < 0) + return SSH_ERR_INTERNAL_ERROR; + /* truncate the key */ + if (ssh->compat & SSH_BUG_HMAC) + mac->key_len = 16; + mac->name = name; + mac->key = NULL; + mac->enabled = 0; + return 0; + } + + static int + choose_comp(struct sshcomp *comp, char *client, char *server) + { + char *name = match_list(client, server, NULL); + +- if (name == NULL) ++ if (name == NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_unsupported(SSH_AUDIT_UNSUPPORTED_COMPRESSION); ++#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) { + comp->type = COMP_ZLIB; + } else if (strcmp(name, "none") == 0) { + comp->type = COMP_NONE; + } else { + return SSH_ERR_INTERNAL_ERROR; +@@ -893,16 +906,20 @@ kex_choose_conf(struct ssh *ssh) + need = MAX(need, newkeys->enc.key_len); + need = MAX(need, newkeys->enc.block_size); + need = MAX(need, newkeys->enc.iv_len); + need = MAX(need, newkeys->mac.key_len); + dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher)); + 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) && + !(ssh->compat & SSH_BUG_FIRSTKEX)) +@@ -1069,8 +1086,38 @@ derive_ssh1_session_id(BIGNUM *host_modu + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void + dump_digest(char *msg, u_char *digest, int len) + { + fprintf(stderr, "%s\n", msg); + 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 --git a/openssh-7.2p2/kex.h b/openssh-7.2p2/kex.h +--- a/openssh-7.2p2/kex.h ++++ b/openssh-7.2p2/kex.h +@@ -199,16 +199,18 @@ 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 + ++void newkeys_destroy(struct newkeys *newkeys); ++ + int kex_dh_hash(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 *); + + int kexgex_hash(int, const char *, const char *, + const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, + int, int, int, + const BIGNUM *, const BIGNUM *, const BIGNUM *, +diff --git a/openssh-7.2p2/key.h b/openssh-7.2p2/key.h +--- a/openssh-7.2p2/key.h ++++ b/openssh-7.2p2/key.h +@@ -45,16 +45,17 @@ typedef struct sshkey Key; + #define key_ssh_name_plain sshkey_ssh_name_plain + #define key_type_from_name sshkey_type_from_name + #define key_ecdsa_nid_from_name sshkey_ecdsa_nid_from_name + #define key_type_is_cert sshkey_type_is_cert + #define key_size sshkey_size + #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 + #define key_curve_nid_to_name sshkey_curve_nid_to_name + #define key_ec_nid_to_hash_alg sshkey_ec_nid_to_hash_alg + #define key_dump_ec_point sshkey_dump_ec_point + #define key_dump_ec_key sshkey_dump_ec_key + #endif +diff --git a/openssh-7.2p2/mac.c b/openssh-7.2p2/mac.c +--- a/openssh-7.2p2/mac.c ++++ b/openssh-7.2p2/mac.c +@@ -259,16 +259,30 @@ mac_clear(struct sshmac *mac) + if (mac->umac_ctx != NULL) + umac128_delete(mac->umac_ctx); + } else if (mac->hmac_ctx != NULL) + ssh_hmac_free(mac->hmac_ctx); + mac->hmac_ctx = NULL; + 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 + mac_valid(const char *names) + { + char *maclist, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) +diff --git a/openssh-7.2p2/mac.h b/openssh-7.2p2/mac.h +--- a/openssh-7.2p2/mac.h ++++ b/openssh-7.2p2/mac.h +@@ -42,10 +42,11 @@ struct sshmac { + + int mac_valid(const char *); + char *mac_alg_list(char); + int mac_setup(struct sshmac *, char *); + int mac_init(struct sshmac *); + int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, + u_char *, size_t); + void mac_clear(struct sshmac *); ++void mac_destroy(struct sshmac *); + + #endif /* SSHMAC_H */ +diff --git a/openssh-7.2p2/monitor.c b/openssh-7.2p2/monitor.c +--- a/openssh-7.2p2/monitor.c ++++ b/openssh-7.2p2/monitor.c +@@ -96,31 +96,34 @@ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "monitor_fdpass.h" + #include "compat.h" + #include "ssh2.h" + #include "authfd.h" ++#include "audit.h" + #include "match.h" + #include "ssherr.h" + + #ifdef GSSAPI + static Gssctxt *gsscontext = NULL; + #endif + + /* Imports */ + extern ServerOptions options; + extern u_int utmp_len; + extern u_char session_id[]; + 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; + + /* Functions on the monitor that answer unprivileged requests */ + + int mm_answer_moduli(int, Buffer *); + int mm_answer_sign(int, Buffer *); + int mm_answer_pwnamallow(int, Buffer *); +@@ -158,16 +161,21 @@ 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 + 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 *); + + static Authctxt *authctxt; + + #ifdef WITH_SSH1 + static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ +@@ -214,16 +222,20 @@ struct mon_table mon_dispatch_proto20[] + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, + {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, + {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, + #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}, + {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH, mm_answer_bsdauthrespond}, + #endif + #ifdef SKEY + {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, +@@ -252,16 +264,21 @@ struct mon_table mon_dispatch_postauth20 + #endif + {MONITOR_REQ_SIGN, 0, mm_answer_sign}, + {MONITOR_REQ_PTY, 0, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + #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} + }; + + struct mon_table mon_dispatch_proto15[] = { + #ifdef WITH_SSH1 + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, +@@ -284,29 +301,38 @@ struct mon_table mon_dispatch_proto15[] + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, + {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, + {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, + #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 + #endif /* WITH_SSH1 */ + {0, 0, NULL} + }; + + struct mon_table mon_dispatch_postauth15[] = { + #ifdef WITH_SSH1 + {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + #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 + #endif /* WITH_SSH1 */ + {0, 0, NULL} + }; + + struct mon_table *mon_dispatch; + + /* Specifies if a certain message is allowed at the moment */ +@@ -1423,26 +1449,30 @@ monitor_valid_hostbasedblob(u_char *data + } + + int + 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); + + 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) + fatal("%s: bad public key blob", __func__); + + switch (key_blobtype) { + case MM_USERKEY: + valid_data = monitor_valid_userblob(data, datalen); +@@ -1453,17 +1483,27 @@ mm_answer_keyverify(int sock, Buffer *m) + break; + default: + valid_data = 0; + break; + } + 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"); + + /* 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); + else + key_free(key); +@@ -1514,16 +1554,22 @@ mm_record_login(Session *s, struct passw + static void + mm_session_close(Session *s) + { + debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid); + if (s->ttyfd != -1) { + debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); + session_pty_cleanup2(s); + } ++#ifdef SSH_AUDIT_EVENTS ++ if (s->command != NULL) { ++ debug3("%s: command %d", __func__, s->command_handle); ++ session_end_command2(s); ++ } ++#endif + session_unused(s->self); + } + + int + mm_answer_pty(int sock, Buffer *m) + { + extern struct monitor *pmonitor; + Session *s; +@@ -1796,16 +1842,18 @@ mm_answer_term(int sock, Buffer *req) + /* The child is terminating */ + session_destroy_all(&mm_session_close); + + #ifdef USE_PAM + if (options.use_pam) + sshpam_cleanup(); + #endif + ++ destroy_sensitive_data(0); ++ + while (waitpid(pmonitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); + + res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; + + /* Terminate process */ + exit(res); +@@ -1838,21 +1886,53 @@ mm_answer_audit_event(int socket, Buffer + return (0); + } + + int + 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); + } + #endif /* SSH_AUDIT_EVENTS */ + + void + monitor_apply_keystate(struct monitor *pmonitor) + { +@@ -1899,23 +1979,39 @@ monitor_apply_keystate(struct monitor *p + } + } + + /* This function requries careful sanity checking */ + + void + mm_get_keystate(struct monitor *pmonitor) + { ++ Buffer m; + debug3("%s: Waiting for new keys", __func__); + + if ((child_state = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + 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) ++ ; ++ + } + + + /* XXX */ + + #define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, FD_CLOEXEC) == -1) \ + fatal("fcntl(%d, F_SETFD)", x); \ +@@ -2157,8 +2253,91 @@ mm_answer_gss_updatecreds(int socket, Bu + + mm_request_send(socket, MONITOR_ANS_GSSUPCREDS, m); + + return(0); + } + + #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 --git a/openssh-7.2p2/monitor.h b/openssh-7.2p2/monitor.h +--- a/openssh-7.2p2/monitor.h ++++ b/openssh-7.2p2/monitor.h +@@ -58,17 +58,23 @@ enum monitor_reqtype { + MONITOR_REQ_TERM = 50, + + 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, + 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, + + MONITOR_REQ_GSSSIGN = 201, MONITOR_ANS_GSSSIGN = 202, + MONITOR_REQ_GSSUPCREDS = 203, MONITOR_ANS_GSSUPCREDS = 204, + + }; + + struct mm_master; + struct monitor { +diff --git a/openssh-7.2p2/monitor_wrap.c b/openssh-7.2p2/monitor_wrap.c +--- a/openssh-7.2p2/monitor_wrap.c ++++ b/openssh-7.2p2/monitor_wrap.c +@@ -438,30 +438,31 @@ mm_key_allowed(enum mm_keytype type, cha + + /* + * This key verify needs to send the key type along, because the + * privileged parent makes the decision if the key is allowed + * for authentication. + */ + + 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; + u_int len; + int verified = 0; + + debug3("%s entering", __func__); + + /* Convert the key to a blob and the pass it over */ + if (!key_to_blob(key, &blob, &len)) + 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); + free(blob); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); + + debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__); +@@ -469,16 +470,28 @@ mm_key_verify(Key *key, u_char *sig, u_i + + verified = buffer_get_int(&m); + + buffer_free(&m); + + 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) + { + struct ssh *ssh = active_state; /* XXX */ + struct sshbuf *m; + int r; + + if ((m = sshbuf_new()) == NULL) +@@ -981,27 +994,48 @@ mm_audit_event(ssh_audit_event_t event) + + buffer_init(&m); + buffer_put_int(&m, event); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, &m); + buffer_free(&m); + } + +-void ++int + mm_audit_run_command(const char *command) + { + Buffer m; ++ int handle; + + debug3("%s entering command %s", __func__, command); + + buffer_init(&m); + 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 */ + + #ifdef GSSAPI + OM_uint32 + mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid) + { +@@ -1127,8 +1161,119 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc + + buffer_free(&m); + + return (ok); + } + + #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); ++} ++ ++int mm_forward_audit_messages(int fdin) ++{ ++ u_char buf[4]; ++ u_int blen, msg_len; ++ Buffer m; ++ int ret = 0; ++ ++ debug3("%s: entering", __func__); ++ buffer_init(&m); ++ do { ++ blen = atomicio(read, fdin, buf, sizeof(buf)); ++ if (blen == 0) /* closed pipe */ ++ break; ++ if (blen != sizeof(buf)) { ++ error("%s: Failed to read the buffer from child", __func__); ++ ret = -1; ++ break; ++ } ++ ++ msg_len = get_u32(buf); ++ if (msg_len > 256 * 1024) ++ fatal("%s: read: bad msg_len %d", __func__, msg_len); ++ buffer_clear(&m); ++ buffer_append_space(&m, msg_len); ++ if (atomicio(read, fdin, buffer_ptr(&m), msg_len) != msg_len) { ++ error("%s: Failed to read the the buffer conent from the child", __func__); ++ ret = -1; ++ break; ++ } ++ if (atomicio(vwrite, pmonitor->m_recvfd, buf, blen) != blen || ++ atomicio(vwrite, pmonitor->m_recvfd, buffer_ptr(&m), msg_len) != msg_len) { ++ error("%s: Failed to write the messag to the monitor", __func__); ++ ret = -1; ++ break; ++ } ++ } while (1); ++ buffer_free(&m); ++ return ret; ++} ++void mm_set_monitor_pipe(int fd) ++{ ++ pmonitor->m_recvfd = fd; ++} ++#endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-7.2p2/monitor_wrap.h b/openssh-7.2p2/monitor_wrap.h +--- a/openssh-7.2p2/monitor_wrap.h ++++ b/openssh-7.2p2/monitor_wrap.h +@@ -44,17 +44,18 @@ int mm_key_sign(Key *, u_char **, u_int + void mm_inform_authserv(char *, char *); + struct passwd *mm_getpwnamallow(const char *); + char *mm_auth2_read_banner(void); + int mm_auth_password(struct Authctxt *, char *); + int mm_key_allowed(enum mm_keytype, char *, char *, Key *, int); + int mm_user_key_allowed(struct passwd *, Key *, int); + 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 *); + + #ifdef GSSAPI + 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 *); +@@ -71,17 +72,24 @@ void *mm_sshpam_init_ctx(struct Authctxt + int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **); + int mm_sshpam_respond(void *, u_int, char **); + void mm_sshpam_free_ctx(void *); + #endif + + #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); ++int mm_forward_audit_messages(int); ++void mm_set_monitor_pipe(int); + #endif + + struct Session; + void mm_terminate(void); + int mm_pty_allocate(int *, int *, char *, size_t); + void mm_session_pty_cleanup2(struct Session *); + + /* SSHv1 interfaces */ +diff --git a/openssh-7.2p2/packet.c b/openssh-7.2p2/packet.c +--- a/openssh-7.2p2/packet.c ++++ b/openssh-7.2p2/packet.c +@@ -62,16 +62,17 @@ + #include + + #include + + #include "buffer.h" /* typedefs XXX */ + #include "key.h" /* typedefs XXX */ + + #include "xmalloc.h" ++#include "audit.h" + #include "crc32.h" + #include "deattack.h" + #include "compat.h" + #include "ssh1.h" + #include "ssh2.h" + #include "cipher.h" + #include "sshkey.h" + #include "kex.h" +@@ -449,16 +450,23 @@ ssh_packet_get_connection_in(struct ssh + /* Returns the descriptor used for writing. */ + + int + ssh_packet_get_connection_out(struct ssh *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. + */ + + const char * + ssh_remote_ipaddr(struct ssh *ssh) + { +@@ -493,23 +501,16 @@ ssh_packet_close(struct ssh *ssh) + { + struct session_state *state = ssh->state; + int r; + u_int mode; + + 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); + sshbuf_free(state->incoming_packet); + for (mode = 0; mode < MODE_MAX; mode++) + kex_free_newkeys(state->newkeys[mode]); + if (state->compression_buffer) { + sshbuf_free(state->compression_buffer); +@@ -531,22 +532,32 @@ ssh_packet_close(struct ssh *ssh) + (unsigned long long)stream->total_out, + (unsigned long long)stream->total_in, + stream->total_out == 0 ? 0.0 : + (double) stream->total_in / stream->total_out); + if (state->compression_in_failures == 0) + inflateEnd(stream); + } + } +- if ((r = cipher_cleanup(&state->send_context)) != 0) +- error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); +- if ((r = cipher_cleanup(&state->receive_context)) != 0) +- error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); ++ if (packet_state_has_keys(state)) { ++ if ((r = cipher_cleanup(&state->send_context)) != 0) ++ error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); ++ if ((r = cipher_cleanup(&state->receive_context)) != 0) ++ error("%s: cipher_cleanup failed: %s", __func__, ssh_err(r)); ++ audit_session_key_free(MODE_OUT); ++ } + 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; + } + + /* Sets remote side protocol flags. */ + + void + ssh_packet_set_protocol_flags(struct ssh *ssh, u_int protocol_flags) +@@ -961,16 +972,17 @@ ssh_set_newkeys(struct ssh *ssh, int mod + } + if (state->newkeys[mode] != NULL) { + debug("set_newkeys: rekeying, input %llu bytes %llu blocks, " + "output %llu bytes %llu blocks", + (unsigned long long)state->p_read.bytes, + (unsigned long long)state->p_read.blocks, + (unsigned long long)state->p_send.bytes, + (unsigned long long)state->p_send.blocks); ++ audit_session_key_free(mode); + if ((r = cipher_cleanup(cc)) != 0) + return r; + enc = &state->newkeys[mode]->enc; + mac = &state->newkeys[mode]->mac; + comp = &state->newkeys[mode]->comp; + mac_clear(mac); + explicit_bzero(enc->iv, enc->iv_len); + explicit_bzero(enc->key, enc->key_len); +@@ -2401,16 +2413,82 @@ ssh_packet_get_input(struct ssh *ssh) + } + + void * + 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_cleanup(&state->receive_context); ++ cipher_cleanup(&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_OUT); ++ else ++ audit_session_key_free_body(MODE_OUT, getpid(), getuid()); ++#endif ++ } ++} ++ + /* Reset after_authentication and reset compression in post-auth privsep */ + static int + ssh_packet_set_postauth(struct ssh *ssh) + { + struct sshcomp *comp; + int r, mode; + + debug("%s: called", __func__); +diff --git a/openssh-7.2p2/packet.h b/openssh-7.2p2/packet.h +--- a/openssh-7.2p2/packet.h ++++ b/openssh-7.2p2/packet.h +@@ -195,9 +195,10 @@ extern struct ssh *active_state; + # undef EC_GROUP + # undef EC_POINT + #elif !defined(OPENSSL_HAS_ECC) + # undef EC_KEY + # undef EC_GROUP + # undef EC_POINT + #endif + ++void packet_destroy_all(int, int); + #endif /* PACKET_H */ +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -163,16 +163,22 @@ static const struct sock_filter preauth_ + SC_ALLOW(geteuid32), + #endif + #ifdef __NR_getrandom + SC_ALLOW(getrandom), + #endif + #ifdef __NR_gettimeofday + SC_ALLOW(gettimeofday), + #endif ++#ifdef SSH_AUDIT_EVENTS ++ SC_ALLOW(getuid), ++#ifdef __NR_getuid32 /* not defined on x86_64 */ ++ SC_ALLOW(getuid32), ++#endif ++#endif + #ifdef __NR_madvise + SC_ALLOW(madvise), + #endif + #ifdef __NR_mmap + SC_ALLOW(mmap), + #endif + #ifdef __NR_mmap2 + SC_ALLOW(mmap2), +diff --git a/openssh-7.2p2/session.c b/openssh-7.2p2/session.c +--- a/openssh-7.2p2/session.c ++++ b/openssh-7.2p2/session.c +@@ -135,17 +135,17 @@ static int session_pty_req(Session *); + + /* import */ + extern ServerOptions options; + extern char *__progname; + 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. */ + const char *original_command = NULL; + + /* data */ + static int sessions_first_unused = -1; + static int sessions_nalloc = 0; +@@ -155,16 +155,20 @@ static Session *sessions = NULL; + #define SUBSYSTEM_EXT 1 + #define SUBSYSTEM_INT_SFTP 2 + #define SUBSYSTEM_INT_SFTP_ERROR 3 + + #ifdef HAVE_LOGIN_CAP + login_cap_t *lc; + #endif + ++#ifdef SSH_AUDIT_EVENTS ++int paudit[2]; ++#endif ++ + static int is_child = 0; + static int in_chroot = 0; + + /* Name and directory of socket for authentication agent forwarding. */ + static char *auth_sock_name = NULL; + static char *auth_sock_dir = NULL; + + /* removes the agent forwarding socket */ +@@ -747,16 +751,24 @@ do_exec_pty(Session *s, const char *comm + cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); + #endif + + s->pid = pid; + + /* 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 (!(options.use_login && command == NULL)) ++ audit_count_session_open(); ++#endif ++ + /* Enter interactive session. */ + s->ptymaster = ptymaster; + packet_set_interactive(1, + options.ip_qos_interactive, options.ip_qos_bulk); + if (compat20) { + session_set_fds(s, ptyfd, fdout, -1, 1, 1); + } else { + server_loop(pid, ptyfd, fdout, -1); +@@ -842,40 +854,60 @@ do_exec(Session *s, const char *command) + tty == NULL ? "" : " on ", + tty == NULL ? "" : tty, + s->pw->pw_name, + get_remote_ipaddr(), + get_remote_port(), + 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)); ++ if (pipe(paudit) < 0) ++ fatal("pipe: %s", strerror(errno)); + #endif + if (s->ttyfd != -1) + ret = do_exec_pty(s, command); + else + ret = do_exec_no_pty(s, command); + + original_command = NULL; + + /* + * Clear loginmsg: it's the child's responsibility to display + * it to the user, otherwise multiple sessions may accumulate + * multiple copies of the login messages. + */ + buffer_clear(&loginmsg); + ++#ifdef SSH_AUDIT_EVENTS ++ close(paudit[1]); ++ if (use_privsep && ret == 0) { ++ /* ++ * Read the audit messages from forked child and send them ++ * back to monitor. We don't want to communicate directly, ++ * because the messages might get mixed up. ++ * Continue after the pipe gets closed (all messages sent). ++ */ ++ ret = mm_forward_audit_messages(paudit[0]); ++ } ++ close(paudit[0]); ++#endif /* SSH_AUDIT_EVENTS */ ++ + return ret; + } + + /* administrative, login(1)-like work */ + void + do_login(Session *s, const char *command) + { + socklen_t fromlen; +@@ -1697,18 +1729,37 @@ do_child(Session *s, const char *command + extern char **environ; + char **env; + int env_size; + char *argv[ARGV_MAX]; + const char *shell, *shell0, *hostname = NULL; + struct passwd *pw = s->pw; + int r = 0; + ++#ifdef SSH_AUDIT_EVENTS ++ int pparent = paudit[1]; ++ close(paudit[0]); ++ /* Hack the monitor pipe to avoid race condition with parent */ ++ if (use_privsep) ++ mm_set_monitor_pipe(pparent); ++#endif ++ + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(use_privsep); ++ /* ++ * We can audit this, because wer hacked the pipe to direct the ++ * messages over postauth child. But this message requires answer ++ * which we can't do using one-way pipe. ++ */ ++ packet_destroy_all(0, 1); ++ ++#ifdef SSH_AUDIT_EVENTS ++ /* Notify parent that we are done */ ++ close(pparent); ++#endif + + /* Force a password change */ + if (s->authctxt->force_pwchange) { + do_setusercontext(pw); + child_close_fds(); + do_pwchange(s); + exit(1); + } +@@ -1925,16 +1976,19 @@ session_unused(int id) + memset(&sessions[id], 0, sizeof(*sessions)); + sessions[id].self = id; + sessions[id].used = 0; + sessions[id].chanid = -1; + sessions[id].ptyfd = -1; + 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; + } + + Session * + session_new(void) + { + Session *s, *tmp; +@@ -2007,16 +2061,29 @@ session_open(Authctxt *authctxt, int cha + if (s->pw == NULL || !authctxt->valid) + fatal("no user for session %d", s->self); + debug("session_open: session %d: link with channel %d", s->self, chanid); + s->chanid = chanid; + return 1; + } + + 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; + for (i = 0; i < sessions_nalloc; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { + debug("session_by_tty: session %d tty %s", i, tty); + return s; +@@ -2529,16 +2596,42 @@ session_exit_message(Session *s, int sta + * interested in data we write. + * Note that we must not call 'chan_read_failed', since there could + * be some more data waiting in the pipe. + */ + if (c->ostate != CHAN_OUTPUT_CLOSED) + 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) + { + u_int i; + + verbose("Close session: user %s from %.200s port %d id %d", + s->pw->pw_name, + get_remote_ipaddr(), +@@ -2570,16 +2663,20 @@ session_close(Session *s) + exit(0); + } else if (pid > 0) { + waitpid(pid, NULL, 0); + } + } + + 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); + free(s->auth_display); + free(s->auth_data); + free(s->auth_proto); + free(s->subsys); + if (s->env != NULL) { +@@ -2784,16 +2881,25 @@ session_setup_x11fwd(Session *s) + } + + static void + 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) + { + static int called = 0; + + debug("do_cleanup"); + + /* no cleanup if we're in the child for login shell */ +@@ -2832,10 +2938,10 @@ do_cleanup(Authctxt *authctxt) + /* remove agent socket */ + auth_sock_cleanup_proc(authctxt->pw); + + /* + * Cleanup ptys/utmp only if privsep is disabled, + * 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/openssh-7.2p2/session.h b/openssh-7.2p2/session.h +--- a/openssh-7.2p2/session.h ++++ b/openssh-7.2p2/session.h +@@ -56,29 +56,37 @@ struct Session { + int *x11_chanids; + int is_subsystem; + char *subsys; + u_int num_env; + struct { + char *name; + char *val; + } *env; ++ ++ /* exec */ ++#ifdef SSH_AUDIT_EVENTS ++ int command_handle; ++ char *command; ++#endif + }; + + void do_authenticated(Authctxt *); + void do_cleanup(Authctxt *); + + int session_open(Authctxt *, int); + void session_unused(int); + int session_input_channel_req(Channel *, const char *); + 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 *); + void child_set_env(char ***envp, u_int *envsizep, const char *name, + const char *value); + + #endif +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -118,16 +118,17 @@ + #include "channels.h" + #include "session.h" + #include "monitor_mm.h" + #include "monitor.h" + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" + + #include "fips.h" + + #ifdef USE_SECURITY_SESSION_API + #include +@@ -263,17 +264,17 @@ Buffer cfg; + + /* message to be displayed after login */ + Buffer loginmsg; + + /* Unprivileged user */ + 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); + + #ifdef WITH_SSH1 + static void do_ssh1_kex(void); + #endif + static void do_ssh2_kex(void); + + /* +@@ -284,16 +285,25 @@ close_listen_socks(void) + { + int i; + + for (i = 0; i < num_listen_socks; i++) + close(listen_socks[i]); + 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) + { + int i; + + if (startup_pipes) + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1) +@@ -563,60 +573,105 @@ sshd_exchange_identification(int sock_in + close(sock_out); + logit("Protocol major versions differ for %s: %.200s vs. %.200s", + get_remote_ipaddr(), + server_version_string, client_version_string); + cleanup_exit(255); + } + } + +-/* 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 + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } + 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; + } + } + sensitive_data.ssh1_host_key = NULL; + explicit_bzero(sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); + } + + /* Demote private to public keys for network child */ + void + demote_sensitive_data(void) + { + Key *tmp; + int i; ++#ifdef SSH_AUDIT_EVENTS ++ pid_t pid; ++ uid_t uid; + ++ pid = getpid(); ++ uid = getuid(); ++#endif + if (sensitive_data.server_key) { + tmp = key_demote(sensitive_data.server_key); + key_free(sensitive_data.server_key); + sensitive_data.server_key = tmp; + } + + 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 (tmp->type == KEY_RSA1) + sensitive_data.ssh1_host_key = tmp; ++ if (fp != NULL) { ++#ifdef SSH_AUDIT_EVENTS ++ audit_destroy_sensitive_data(fp, pid, uid); ++#endif ++ free(fp); ++ } + } + /* Certs do not need demotion */ + } + + /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ + } + + static void +@@ -756,16 +811,22 @@ privsep_postauth(Authctxt *authctxt) + monitor_reinit(pmonitor); + + pmonitor->m_pid = fork(); + if (pmonitor->m_pid == -1) + fatal("fork of unprivileged child failed"); + 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 */ + exit(0); + } + + /* child */ + +@@ -1283,16 +1344,17 @@ server_accept_loop(int *sock_in, int *so + + /* Wait in select until there is a connection. */ + ret = select(maxfd+1, fdset, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + error("select: %.100s", strerror(errno)); + 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); + exit(received_sigterm == SIGTERM ? 0 : 255); + } + if (key_used && key_do_regen) { + generate_ephemeral_server_key(); + key_used = 0; +@@ -2341,16 +2403,17 @@ main(int ac, char **av) + #endif + } + /* + * If we use privilege separation, the unprivileged child transfers + * the current keystate and exits + */ + if (use_privsep) { + mm_send_keystate(pmonitor); ++ packet_destroy_all(1, 1); + exit(0); + } + + authenticated: + /* + * Cancel the alarm we set to limit the time taken for + * authentication. + */ +@@ -2383,30 +2446,33 @@ main(int ac, char **av) + /* + * In privilege separation, we fork another child and prepare + * file descriptor passing. + */ + if (use_privsep) { + 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, + options.client_alive_count_max); + + /* Try to send all our hostkeys to the client */ + if (compat20) + notify_hostkeys(active_state); + + /* Start session. */ + 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); + + verbose("Closing connection to %.500s port %d", remote_ip, remote_port); + + #ifdef USE_PAM + if (options.use_pam) +@@ -2557,16 +2623,20 @@ do_ssh1_kex(void) + packet_disconnect("Warning: client selects unsupported cipher."); + + /* Get check bytes from the packet. These must match those we + sent earlier with the public key packet. */ + for (i = 0; i < 8; i++) + if (cookie[i] != packet_get_char()) + packet_disconnect("IP Spoofing check bytes do not match."); + ++#ifdef SSH_AUDIT_EVENTS ++ audit_kex(MODE_OUT, cipher_name(cipher_type), "crc", "none", "none"); ++#endif ++ + debug("Encryption type: %.200s", cipher_name(cipher_type)); + + /* Get the encrypted integer. */ + if ((real_key_int = BN_new()) == NULL) + fatal("do_ssh1_kex: BN_new failed"); + packet_get_bignum(real_key_int); + + protocol_flags = packet_get_int(); +@@ -2616,17 +2686,17 @@ do_ssh1_kex(void) + * Xor the first 16 bytes of the session key with the + * session id. + */ + for (i = 0; i < 16; i++) + session_key[i] ^= session_id[i]; + } + + /* Destroy the private and public keys. No longer. */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(1); + + if (use_privsep) + mm_ssh1_session_id(session_id); + + /* Destroy the decrypted integer. It is no longer needed. */ + BN_clear_free(real_key_int); + BN_clear_free(fake_key_int); + +@@ -2790,26 +2860,41 @@ do_ssh2_kex(void) + #endif + debug("KEX done"); + } + + /* server specific fatal cleanup */ + 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 != NULL && pmonitor->m_pid > 1) { + debug("Killing privsep child %d", pmonitor->m_pid); + if (kill(pmonitor->m_pid, SIGKILL) != 0 && + errno != ESRCH) + error("%s: kill(%d): %s", __func__, + 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/openssh-7.2p2/sshkey.c b/openssh-7.2p2/sshkey.c +--- a/openssh-7.2p2/sshkey.c ++++ b/openssh-7.2p2/sshkey.c +@@ -299,16 +299,43 @@ sshkey_type_is_valid_ca(int type) + case KEY_ED25519: + return 1; + default: + return 0; + } + } + + 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) + return 0; + return sshkey_type_is_cert(k->type); + } + + /* Return the cert-less equivalent to a certified key type */ +diff --git a/openssh-7.2p2/sshkey.h b/openssh-7.2p2/sshkey.h +--- a/openssh-7.2p2/sshkey.h ++++ b/openssh-7.2p2/sshkey.h +@@ -128,16 +128,17 @@ const char *sshkey_type(const struct ssh + const char *sshkey_cert_type(const struct sshkey *); + int sshkey_write(const struct sshkey *, FILE *); + int sshkey_read(struct sshkey *, char **); + 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); + int sshkey_to_certified(struct sshkey *); + int sshkey_drop_cert(struct sshkey *); + int sshkey_certify(struct sshkey *, struct sshkey *); + int sshkey_cert_copy(const struct sshkey *, struct sshkey *); + int sshkey_cert_check_authority(const struct sshkey *, int, int, diff --git a/openssh-7.2p2-audit_fixes.patch b/openssh-7.2p2-audit_fixes.patch new file mode 100644 index 0000000..9658e38 --- /dev/null +++ b/openssh-7.2p2-audit_fixes.patch @@ -0,0 +1,35 @@ +# HG changeset patch +# Parent fdc9167221e501a9f4db5343cf8cadc31e13fd56 +Various auditing fixes to be merged into the RH-originated patch. + +diff --git a/openssh-7.2p2/packet.c b/openssh-7.2p2/packet.c +--- a/openssh-7.2p2/packet.c ++++ b/openssh-7.2p2/packet.c +@@ -371,20 +371,26 @@ ssh_packet_start_discard(struct ssh *ssh + return 0; + } + + /* Returns 1 if remote host is connected via socket, 0 if not. */ + + int + ssh_packet_connection_is_on_socket(struct ssh *ssh) + { +- struct session_state *state = ssh->state; ++ struct session_state *state; + struct sockaddr_storage from, to; + socklen_t fromlen, tolen; + ++ /* auditing might get here without valid connection structure when ++ * destroying sensitive data on exit and thus aborting disgracefully */ ++ if ((!ssh) || (!(ssh->state))) ++ return 0; ++ state = ssh->state; ++ + /* filedescriptors in and out are the same, so it's a socket */ + if (state->connection_in == state->connection_out) + return 1; + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(state->connection_in, (struct sockaddr *)&from, + &fromlen) < 0) + return 0; diff --git a/openssh-7.2p2-audit_seed_prng.patch b/openssh-7.2p2-audit_seed_prng.patch new file mode 100644 index 0000000..9346f80 --- /dev/null +++ b/openssh-7.2p2-audit_seed_prng.patch @@ -0,0 +1,116 @@ +# HG changeset patch +# Parent e6ff441d171012183f7bd37cb7399473e8376acd +Audit PRNG re-seeding + +diff --git a/openssh-7.2p2/audit-bsm.c b/openssh-7.2p2/audit-bsm.c +--- a/openssh-7.2p2/audit-bsm.c ++++ b/openssh-7.2p2/audit-bsm.c +@@ -504,9 +504,15 @@ audit_destroy_sensitive_data(const char + /* not implemented */ + } + + void + audit_generate_ephemeral_server_key(const char *fp) + { + /* not implemented */ + } ++ ++void ++audit_linux_prng_seed(long bytes, const char *rf) ++{ ++ /* not implemented */ ++} + #endif /* BSM */ +diff --git a/openssh-7.2p2/audit-linux.c b/openssh-7.2p2/audit-linux.c +--- a/openssh-7.2p2/audit-linux.c ++++ b/openssh-7.2p2/audit-linux.c +@@ -402,9 +402,31 @@ audit_generate_ephemeral_server_key(cons + } + 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"); + } ++ ++void ++audit_linux_prng_seed(long bytes, const char *rf) ++{ ++ char buf[AUDIT_LOG_SIZE]; ++ int audit_fd, audit_ok; ++ ++ snprintf(buf, sizeof(buf), "op=prng_seed kind=server bytes=%li source=%s ", bytes, rf); ++ 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_PARAM_CHANGE_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/openssh-7.2p2/audit.c b/openssh-7.2p2/audit.c +--- a/openssh-7.2p2/audit.c ++++ b/openssh-7.2p2/audit.c +@@ -304,10 +304,16 @@ audit_destroy_sensitive_data(const char + /* + * 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); + } ++ ++void ++audit_linux_prng_seed(long bytes, const char *rf) ++{ ++ debug("audit PRNG seed euid %d bytes %li source %s", geteuid(), bytes, rf); ++} + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #endif /* SSH_AUDIT_EVENTS */ +diff --git a/openssh-7.2p2/audit.h b/openssh-7.2p2/audit.h +--- a/openssh-7.2p2/audit.h ++++ b/openssh-7.2p2/audit.h +@@ -69,10 +69,11 @@ 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 *); ++void audit_linux_prng_seed(long, const char *); + + #endif /* _SSH_AUDIT_H */ +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -1421,16 +1421,19 @@ server_accept_loop(int *sock_in, int *so + if (maxfd < startup_p[0]) + maxfd = startup_p[0]; + startups++; + break; + } + if(!(--re_seeding_counter)) { + re_seeding_counter = RESEED_AFTER; + linux_seed(); ++#ifdef SSH_AUDIT_EVENTS ++ audit_linux_prng_seed(rand_bytes, rand_file); ++#endif + } + + /* + * Got connection. Fork a child to handle it, unless + * we are in debugging mode. + */ + if (debug_flag) { + /* diff --git a/openssh-7.6p1-blocksigalrm.patch b/openssh-7.2p2-blocksigalrm.patch similarity index 75% rename from openssh-7.6p1-blocksigalrm.patch rename to openssh-7.2p2-blocksigalrm.patch index 4715fed..c2350b1 100644 --- a/openssh-7.6p1-blocksigalrm.patch +++ b/openssh-7.2p2-blocksigalrm.patch @@ -1,13 +1,13 @@ # HG changeset patch -# Parent 724c9ea86fe2c4a1f0e0d3aba168357ab1b2c3aa +# Parent 0bfb5dd4b190b546a3e40a59483b2b2884a47c39 block SIGALRM while logging through syslog to prevent deadlocks (through grace_alarm_handler()) bnc#57354 -diff --git a/openssh-7.6p1/log.c b/openssh-7.6p1/log.c ---- a/openssh-7.6p1/log.c -+++ b/openssh-7.6p1/log.c +diff --git a/openssh-7.2p2/log.c b/openssh-7.2p2/log.c +--- a/openssh-7.2p2/log.c ++++ b/openssh-7.2p2/log.c @@ -46,16 +46,17 @@ #include #include @@ -26,7 +26,7 @@ diff --git a/openssh-7.6p1/log.c b/openssh-7.6p1/log.c static char *argv0; static log_handler_fn *log_handler; static void *log_handler_ctx; -@@ -396,16 +397,17 @@ do_log(LogLevel level, const char *fmt, +@@ -383,16 +384,17 @@ do_log(LogLevel level, const char *fmt, { #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) struct syslog_data sdata = SYSLOG_DATA_INIT; @@ -44,19 +44,20 @@ diff --git a/openssh-7.6p1/log.c b/openssh-7.6p1/log.c switch (level) { case SYSLOG_LEVEL_FATAL: -@@ -455,20 +457,28 @@ do_log(LogLevel level, const char *fmt, +@@ -441,20 +443,29 @@ do_log(LogLevel level, const char *fmt, + tmp_handler = log_handler; log_handler = NULL; tmp_handler(level, fmtbuf, log_handler_ctx); log_handler = tmp_handler; } else if (log_on_stderr) { - snprintf(msgbuf, sizeof msgbuf, "%.*s\r\n", - (int)sizeof msgbuf - 3, fmtbuf); + snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); (void)write(log_stderr_fd, msgbuf, strlen(msgbuf)); } else { -+ /* Prevent a race between the grace_alarm which writes a -+ * log message and terminates and main sshd code that leads -+ * to deadlock as syslog is not async safe. -+ */ ++ /* Prevent a race between the grace_alarm ++ * which writes a log message and terminates ++ * and main sshd code that leads to deadlock ++ * as syslog is not async safe. ++ */ + sigemptyset(&nset); + sigaddset(&nset, SIGALRM); + sigprocmask(SIG_BLOCK, &nset, &oset); diff --git a/openssh-7.2p2-cavstest-ctr.patch b/openssh-7.2p2-cavstest-ctr.patch new file mode 100644 index 0000000..6a8763d --- /dev/null +++ b/openssh-7.2p2-cavstest-ctr.patch @@ -0,0 +1,300 @@ +# HG changeset patch +# Parent cb502e7e796ac9289a571167a97ad9ec91562efb +CAVS test for OpenSSH's own CTR encryption mode implementation + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -21,16 +21,17 @@ top_srcdir=@top_srcdir@ + + DESTDIR= + VPATH=@srcdir@ + SSH_PROGRAM=@bindir@/ssh + ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper ++CAVSTEST_CTR=$(libexecdir)/cavstest-ctr + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ + STRIP_OPT=@STRIP_OPT@ + TEST_SHELL=@TEST_SHELL@ + + PATHS= -DSSHDIR=\"$(sysconfdir)\" \ + -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ + -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ +@@ -59,16 +60,18 @@ SED=@SED@ + ENT=@ENT@ + XAUTH_PATH=@XAUTH_PATH@ + LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ + EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + + 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 += cavstest-ctr$(EXEEXT) ++ + LIBOPENSSH_OBJS=\ + ssh_api.o \ + ssherr.o \ + sshbuf.o \ + sshkey.o \ + sshbuf-getput-basic.o \ + sshbuf-misc.o \ + sshbuf-getput-crypto.o \ +@@ -190,16 +193,20 @@ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libss + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + + sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o + $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) + ++# FIPS tests ++cavstest-ctr$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-ctr.o ++ $(LD) -o $@ cavstest-ctr.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ + # test driver for the loginrec code - not built by default + logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o + $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) + + $(MANPAGES): $(MANPAGES_IN) + if test "$(MANTYPE)" = "cat"; then \ + manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ + else \ +@@ -310,16 +317,17 @@ install-files: + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-agent$(EXEEXT) $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + $(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) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 + $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 + $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 + $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 + $(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 + $(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 + $(INSTALL) -m 644 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5 + $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 +diff --git a/openssh-7.2p2/cavstest-ctr.c b/openssh-7.2p2/cavstest-ctr.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/cavstest-ctr.c +@@ -0,0 +1,212 @@ ++/* ++ * ++ * 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[]) ++{ ++ ++ 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_cleanup(&cc); ++ ++ for (p = outdata; datalen > 0; ++p, --datalen) { ++ printf("%02X", (unsigned char) *p); ++ } ++ ++ free(outdata); ++ ++ printf("\n"); ++ return 0; ++} diff --git a/openssh-7.2p2-cavstest-kdf.patch b/openssh-7.2p2-cavstest-kdf.patch new file mode 100644 index 0000000..893078b --- /dev/null +++ b/openssh-7.2p2-cavstest-kdf.patch @@ -0,0 +1,469 @@ +# HG changeset patch +# Parent f9ffcfb88e5a9d611a61aee3571050dea67e363e +CAVS test for KDF implementation in OpenSSH + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -22,16 +22,17 @@ top_srcdir=@top_srcdir@ + DESTDIR= + VPATH=@srcdir@ + SSH_PROGRAM=@bindir@/ssh + ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + CAVSTEST_CTR=$(libexecdir)/cavstest-ctr ++CAVSTEST_KDF=$(libexecdir)/cavstest-kdf + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ + STRIP_OPT=@STRIP_OPT@ + TEST_SHELL=@TEST_SHELL@ + + PATHS= -DSSHDIR=\"$(sysconfdir)\" \ + -D_PATH_SSH_PROGRAM=\"$(SSH_PROGRAM)\" \ + -D_PATH_SSH_ASKPASS_DEFAULT=\"$(ASKPASS_PROGRAM)\" \ +@@ -60,17 +61,17 @@ SED=@SED@ + ENT=@ENT@ + XAUTH_PATH=@XAUTH_PATH@ + LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ + EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + + 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 += cavstest-ctr$(EXEEXT) ++TARGETS += cavstest-ctr$(EXEEXT) cavstest-kdf$(EXEEXT) + + LIBOPENSSH_OBJS=\ + ssh_api.o \ + ssherr.o \ + sshbuf.o \ + sshkey.o \ + sshbuf-getput-basic.o \ + sshbuf-misc.o \ +@@ -197,16 +198,19 @@ sftp-server$(EXEEXT): $(LIBCOMPAT) libss + + sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o + $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) + + # FIPS tests + cavstest-ctr$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-ctr.o + $(LD) -o $@ cavstest-ctr.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + ++cavstest-kdf$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-kdf.o ++ $(LD) -o $@ cavstest-kdf.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ + # test driver for the loginrec code - not built by default + logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o + $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) + + $(MANPAGES): $(MANPAGES_IN) + if test "$(MANTYPE)" = "cat"; then \ + manpage=$(srcdir)/`echo $@ | sed 's/\.[1-9]\.out$$/\.0/'`; \ + else \ +@@ -318,16 +322,17 @@ install-files: + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + $(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) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-kdf$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-kdf$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 + $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 + $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 + $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 + $(INSTALL) -m 644 ssh-keygen.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 + $(INSTALL) -m 644 ssh-keyscan.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 + $(INSTALL) -m 644 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5 + $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 +diff --git a/openssh-7.2p2/cavstest-kdf.c b/openssh-7.2p2/cavstest-kdf.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/cavstest-kdf.c +@@ -0,0 +1,382 @@ ++/* ++ * 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; ++ struct ssh ssh; ++ BIGNUM *Kbn = NULL; ++ int mode = 0; ++ struct newkeys *keys_client; ++ struct newkeys *keys_server; ++ ++#define HEXOUTLEN 500 ++ char hex[HEXOUTLEN]; ++ ++ memset(&ssh, 0, sizeof(struct ssh)); ++ memset(&kex, 0, sizeof(struct kex)); ++ ssh.kex = &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 */ ++ kex_derive_keys_bn(&ssh, test->H, test->Hlen, Kbn); ++ ++ keys_client = ssh.kex->newkeys[0]; ++ keys_server = ssh.kex->newkeys[1]; ++ ++ /* get data */ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_client->enc.iv, (size_t)keys_client->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (client to server) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_server->enc.iv, (size_t)keys_server->enc.iv_len, ++ hex, HEXOUTLEN, 0); ++ printf("Initial IV (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_client->enc.key, (size_t)keys_client->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (client to server) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_server->enc.key, (size_t)keys_server->enc.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Encryption key (server to client) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_client->mac.key, (size_t)keys_client->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (client to server) = %s\n", hex); ++ ++ memset(hex, 0, HEXOUTLEN); ++ bin2hex(keys_server->mac.key, (size_t)keys_server->mac.key_len, ++ hex, HEXOUTLEN, 0); ++ printf("Integrity key (server to client) = %s\n", hex); ++ ++ free(keys_client); ++ free(keys_server); ++ ++out: ++ if (Kbn) ++ BN_free(Kbn); ++ if (kex.newkeys[0]) ++ free(kex.newkeys[0]); ++ if (kex.newkeys[1]) ++ free(kex.newkeys[1]); ++ 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 ++ * ++ * Expected result for example: ++ * Initial IV (client to server) = 4bb320d1679dfd3a ++ * Encryption key (client to server) = 13048cc600b9d3cf9095aa6cf8e2ff9cf1c54ca0520c89ed ++ * Integrity key (client to server) = ecef63a092b0dcc585bdc757e01b2740af57d640 ++ * Initial IV (server to client) = 43dea6fdf263a308 ++ * Encryption key (server to client) = 1e483c5134e901aa11fc4e0a524e7ec7b75556148a222bb0 ++ * 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 --git a/openssh-7.2p2-disable_openssl_abi_check.patch b/openssh-7.2p2-disable_openssl_abi_check.patch new file mode 100644 index 0000000..fbc0932 --- /dev/null +++ b/openssh-7.2p2-disable_openssl_abi_check.patch @@ -0,0 +1,64 @@ +# HG changeset patch +# Parent 4821397c95e57962905e6d47554bef9e4ea57483 +disable run-time check for OpenSSL ABI by version number as that is not a +reliable indicator of ABI changes and doesn't make much sense in a +distribution package + +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -4663,16 +4663,29 @@ AC_ARG_WITH([bsd-auth], + if test "x$withval" != "xno" ; then + AC_DEFINE([BSD_AUTH], [1], + [Define if you have BSD auth support]) + BSD_AUTH_MSG=yes + fi + ] + ) + ++# Whether we are using distribution (Open)SSL, so no runtime checks are necessary ++DISTRO_SSL=no ++AC_ARG_WITH([distro-ssl], ++ [ --with-distro-ssl Disable runtime OpenSSL version checks (good for distributions)], ++ [ ++ if test "x$withval" != "xno" ; then ++ AC_DEFINE([DISTRO_SSL], [1], ++ [Define if you are using distribution SSL library and don;t expect its API/ABI to change]) ++ DISTRO_SSL=yes ++ fi ++ ] ++) ++ + # Where to place sshd.pid + piddir=/var/run + # make sure the directory exists + if test ! -d $piddir ; then + piddir=`eval echo ${sysconfdir}` + case $piddir in + NONE/*) piddir=`echo $piddir | sed "s~NONE~$ac_default_prefix~"` ;; + esac +diff --git a/openssh-7.2p2/entropy.c b/openssh-7.2p2/entropy.c +--- a/openssh-7.2p2/entropy.c ++++ b/openssh-7.2p2/entropy.c +@@ -209,19 +209,21 @@ rexec_recv_rng_seed(Buffer *m) + #endif /* OPENSSL_PRNG_ONLY */ + + void + seed_rng(void) + { + #ifndef OPENSSL_PRNG_ONLY + unsigned char buf[RANDOM_SEED_SIZE]; + #endif ++#ifndef DISTRO_SSL + if (!ssh_compatible_openssl(OPENSSL_VERSION_NUMBER, SSLeay())) + fatal("OpenSSL version mismatch. Built against %lx, you " + "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); ++#endif + + #ifndef OPENSSL_PRNG_ONLY + if (RAND_status() == 1) { + debug3("RNG is ready, skipping seeding"); + return; + } + + if (seed_from_prngd(buf, sizeof(buf)) == -1) diff --git a/openssh-7.2p2-disable_preauth_compression.patch b/openssh-7.2p2-disable_preauth_compression.patch new file mode 100644 index 0000000..8905ec0 --- /dev/null +++ b/openssh-7.2p2-disable_preauth_compression.patch @@ -0,0 +1,1317 @@ +# HG changeset patch +# Parent 37850c481e0e7840bdb6bcf2c07279ed8391335c +Remove preauth compression support for security reasons and cleanup unused +code. + +CVE-2016-10012 - part 1 +bsc#1016370 + +backported upstream commit 0082fba4efdd492f765ed4c53f0d0fbd3bdbdf7f +backported upstream commit 1cfd5c06efb121e58e8b6671548fda77ef4b4455 +backported upstream commit 4577adead6a7d600c8e764619d99477a08192c8f +backported upstream commit b7689155f3f5c4999846c07a852b1c7a43b09cec + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -111,17 +111,17 @@ SSHOBJS= ssh.o readconf.o clientloop.o s + + SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + audit.o audit-bsm.o audit-linux.o platform.o \ + sshpty.o sshlogin.o servconf.o serverloop.o \ + auth.o auth1.o auth2.o auth-options.o session.o \ + auth-chall.o auth2-chall.o groupaccess.o \ + auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ + auth2-none.o auth2-passwd.o auth2-pubkey.o \ +- monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ ++ monitor.o monitor_wrap.o auth-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.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 \ + 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 ssh-ldap-helper.8.out ssh-ldap.conf.5.out +diff --git a/openssh-7.2p2/README.privsep b/openssh-7.2p2/README.privsep +--- a/openssh-7.2p2/README.privsep ++++ b/openssh-7.2p2/README.privsep +@@ -3,20 +3,16 @@ operations that require root privilege a + privileged monitor process. Its purpose is to prevent privilege + escalation by containing corruption to an unprivileged process. + More information is available at: + http://www.citi.umich.edu/u/provos/ssh/privsep.html + + Privilege separation is now enabled by default; see the + UsePrivilegeSeparation option in sshd_config(5). + +-On systems which lack mmap or anonymous (MAP_ANON) memory mapping, +-compression must be disabled in order for privilege separation to +-function. +- + When privsep is enabled, during the pre-authentication phase sshd will + chroot(2) to "/var/empty" and change its privileges to the "sshd" user + and its primary group. sshd is a pseudo-account that should not be + used by other daemons, and must be locked and should contain a + "nologin" or invalid shell. + + You should do something like the following to prepare the privsep + preauth environment: +@@ -30,19 +26,16 @@ preauth environment: + /var/empty should not contain any files. + + configure supports the following options to change the default + privsep user and chroot directory: + + --with-privsep-path=xxx Path for privilege separation chroot + --with-privsep-user=user Specify non-privileged user for privilege separation + +-Privsep requires operating system support for file descriptor passing. +-Compression will be disabled on systems without a working mmap MAP_ANON. +- + PAM-enabled OpenSSH is known to function with privsep on AIX, FreeBSD, + HP-UX (including Trusted Mode), Linux, NetBSD and Solaris. + + On Cygwin, Tru64 Unix, OpenServer, and Unicos only the pre-authentication + part of privsep is supported. Post-authentication privsep is disabled + automatically (so you won't see the additional process mentioned below). + + Note that for a normal interactive login with a shell, enabling privsep +diff --git a/openssh-7.2p2/TODO b/openssh-7.2p2/TODO +--- a/openssh-7.2p2/TODO ++++ b/openssh-7.2p2/TODO +@@ -64,20 +64,16 @@ Clean up configure/makefiles: + similar tests. E.g move all the type detection stuff into one file, + entropy related stuff into another. + + Packaging: + - HP-UX: Provide DEPOT package scripts. + (gilbert.r.loomis@saic.com) + + PrivSep Issues: +-- mmap() issues. +- + /dev/zero solution (Solaris) +- + No/broken MAP_ANON (Irix) +- + broken /dev/zero parse (Linux) + - PAM + + See above PAM notes + - AIX + + usrinfo() does not set TTY, but only required for legacy systems. Works + with PrivSep. + - OSF + + SIA is broken + - Cygwin +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -1176,17 +1176,16 @@ mips-sony-bsd|mips-sony-newsos4) + *-*-nto-qnx6*) + AC_DEFINE([DISABLE_FD_PASSING]) + ;; + esac + ;; + + *-*-ultrix*) + AC_DEFINE([BROKEN_GETGROUPS], [1], [getgroups(0,NULL) will return -1]) +- AC_DEFINE([BROKEN_MMAP], [1], [Ultrix mmap can't map files]) + AC_DEFINE([NEED_SETPGRP]) + AC_DEFINE([HAVE_SYS_SYSLOG_H], [1], [Force use of sys/syslog.h on Ultrix]) + ;; + + *-*-lynxos) + CFLAGS="$CFLAGS -D__NO_INCLUDE_WARN__" + AC_DEFINE([BROKEN_SETVBUF], [1], [LynxOS has broken setvbuf() implementation]) + ;; +@@ -1842,17 +1841,16 @@ AC_CHECK_FUNCS([ \ + inet_ntop \ + innetgr \ + login_getcapbool \ + mblen \ + md5_crypt \ + memmove \ + memset_s \ + mkdtemp \ +- mmap \ + ngetaddrinfo \ + nsleep \ + ogetaddrinfo \ + openlog_r \ + pledge \ + poll \ + prctl \ + pstat \ +diff --git a/openssh-7.2p2/monitor.c b/openssh-7.2p2/monitor.c +--- a/openssh-7.2p2/monitor.c ++++ b/openssh-7.2p2/monitor.c +@@ -87,17 +87,16 @@ + #include "channels.h" + #include "session.h" + #include "sshlogin.h" + #include "canohost.h" + #include "log.h" + #include "misc.h" + #include "servconf.h" + #include "monitor.h" +-#include "monitor_mm.h" + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "monitor_fdpass.h" + #include "compat.h" + #include "ssh2.h" + #include "authfd.h" +@@ -511,41 +510,16 @@ monitor_child_postauth(struct monitor *p + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); + } + + for (;;) + monitor_read(pmonitor, mon_dispatch, NULL); + } + +-void +-monitor_sync(struct monitor *pmonitor) +-{ +- if (options.compression) { +- /* The member allocation is not visible, so sync it */ +- mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); +- } +-} +- +-/* Allocation functions for zlib */ +-static void * +-mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) +-{ +- if (size == 0 || ncount == 0 || ncount > SIZE_MAX / size) +- fatal("%s: mm_zalloc(%u, %u)", __func__, ncount, size); +- +- return mm_malloc(mm, size * ncount); +-} +- +-static void +-mm_zfree(struct mm_master *mm, void *address) +-{ +- mm_free(mm, address); +-} +- + static int + monitor_read_log(struct monitor *pmonitor) + { + Buffer logmsg; + u_int len, level; + char *msg; + + buffer_init(&logmsg); +@@ -1965,23 +1939,16 @@ monitor_apply_keystate(struct monitor *p + 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; + kex->sign = sshd_hostkey_sign; + } +- +- /* Update with new address */ +- if (options.compression) { +- ssh_packet_set_compress_hooks(ssh, pmonitor->m_zlib, +- (ssh_packet_comp_alloc_func *)mm_zalloc, +- (ssh_packet_comp_free_func *)mm_zfree); +- } + } + + /* This function requries careful sanity checking */ + + void + mm_get_keystate(struct monitor *pmonitor) + { + Buffer m; +@@ -2040,34 +2007,21 @@ monitor_openfds(struct monitor *mon, int + mon->m_log_recvfd = mon->m_log_sendfd = -1; + } + + #define MM_MEMSIZE 65536 + + struct monitor * + monitor_init(void) + { +- struct ssh *ssh = active_state; /* XXX */ + struct monitor *mon; + + mon = xcalloc(1, sizeof(*mon)); +- + monitor_openfds(mon, 1); + +- /* Used to share zlib space across processes */ +- if (options.compression) { +- mon->m_zback = mm_create(NULL, MM_MEMSIZE); +- mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); +- +- /* Compression needs to share state across borders */ +- ssh_packet_set_compress_hooks(ssh, mon->m_zlib, +- (ssh_packet_comp_alloc_func *)mm_zalloc, +- (ssh_packet_comp_free_func *)mm_zfree); +- } +- + return mon; + } + + void + monitor_reinit(struct monitor *mon) + { + monitor_openfds(mon, 0); + } +diff --git a/openssh-7.2p2/monitor.h b/openssh-7.2p2/monitor.h +--- a/openssh-7.2p2/monitor.h ++++ b/openssh-7.2p2/monitor.h +@@ -1,9 +1,9 @@ +-/* $OpenBSD: monitor.h,v 1.19 2015/01/19 19:52:16 markus Exp $ */ ++/* $OpenBSD: monitor.h,v 1.20 2016/09/28 16:33:07 djm Exp $ */ + + /* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: +@@ -71,31 +71,27 @@ enum monitor_reqtype { + MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123, + MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124, + + MONITOR_REQ_GSSSIGN = 201, MONITOR_ANS_GSSSIGN = 202, + MONITOR_REQ_GSSUPCREDS = 203, MONITOR_ANS_GSSUPCREDS = 204, + + }; + +-struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; + int m_log_sendfd; +- struct mm_master *m_zback; +- struct mm_master *m_zlib; + struct kex **m_pkex; + pid_t m_pid; + }; + + struct monitor *monitor_init(void); + void monitor_reinit(struct monitor *); +-void monitor_sync(struct monitor *); + + struct Authctxt; + void monitor_child_preauth(struct Authctxt *, struct monitor *); + void monitor_child_postauth(struct monitor *); + + struct mon_table; + int monitor_read(struct monitor*, struct mon_table *, struct mon_table **); + +diff --git a/openssh-7.2p2/monitor_mm.c b/openssh-7.2p2/monitor_mm.c +deleted file mode 100644 +--- a/openssh-7.2p2/monitor_mm.c ++++ /dev/null +@@ -1,357 +0,0 @@ +-/* $OpenBSD: monitor_mm.c,v 1.21 2015/02/06 23:21:59 millert Exp $ */ +-/* +- * Copyright 2002 Niels Provos +- * 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" +- +-#include +-#ifdef HAVE_SYS_MMAN_H +-#include +-#endif +-#include "openbsd-compat/sys-tree.h" +- +-#include +-#include +-#include +-#ifdef HAVE_STDINT_H +-#include +-#endif +-#include +-#include +- +-#include "xmalloc.h" +-#include "ssh.h" +-#include "log.h" +-#include "monitor_mm.h" +- +-static int +-mm_compare(struct mm_share *a, struct mm_share *b) +-{ +- ptrdiff_t diff = (char *)a->address - (char *)b->address; +- +- if (diff == 0) +- return (0); +- else if (diff < 0) +- return (-1); +- else +- return (1); +-} +- +-RB_GENERATE(mmtree, mm_share, next, mm_compare) +- +-static struct mm_share * +-mm_make_entry(struct mm_master *mm, struct mmtree *head, +- void *address, size_t size) +-{ +- struct mm_share *tmp, *tmp2; +- +- if (mm->mmalloc == NULL) +- tmp = xcalloc(1, sizeof(struct mm_share)); +- else +- tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); +- tmp->address = address; +- tmp->size = size; +- +- tmp2 = RB_INSERT(mmtree, head, tmp); +- if (tmp2 != NULL) +- fatal("mm_make_entry(%p): double address %p->%p(%zu)", +- mm, tmp2, address, size); +- +- return (tmp); +-} +- +-/* Creates a shared memory area of a certain size */ +- +-struct mm_master * +-mm_create(struct mm_master *mmalloc, size_t size) +-{ +- void *address; +- struct mm_master *mm; +- +- if (mmalloc == NULL) +- mm = xcalloc(1, sizeof(struct mm_master)); +- else +- mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); +- +- /* +- * If the memory map has a mm_master it can be completely +- * shared including authentication between the child +- * and the client. +- */ +- mm->mmalloc = mmalloc; +- +- address = xmmap(size); +- if (address == (void *)MAP_FAILED) +- fatal("mmap(%zu): %s", size, strerror(errno)); +- +- mm->address = address; +- mm->size = size; +- +- RB_INIT(&mm->rb_free); +- RB_INIT(&mm->rb_allocated); +- +- mm_make_entry(mm, &mm->rb_free, address, size); +- +- return (mm); +-} +- +-/* Frees either the allocated or the free list */ +- +-static void +-mm_freelist(struct mm_master *mmalloc, struct mmtree *head) +-{ +- struct mm_share *mms, *next; +- +- for (mms = RB_ROOT(head); mms; mms = next) { +- next = RB_NEXT(mmtree, head, mms); +- RB_REMOVE(mmtree, head, mms); +- if (mmalloc == NULL) +- free(mms); +- else +- mm_free(mmalloc, mms); +- } +-} +- +-/* Destroys a memory mapped area */ +- +-void +-mm_destroy(struct mm_master *mm) +-{ +- mm_freelist(mm->mmalloc, &mm->rb_free); +- mm_freelist(mm->mmalloc, &mm->rb_allocated); +- +-#ifdef HAVE_MMAP +- if (munmap(mm->address, mm->size) == -1) +- fatal("munmap(%p, %zu): %s", mm->address, mm->size, +- strerror(errno)); +-#else +- fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", +- __func__); +-#endif +- if (mm->mmalloc == NULL) +- free(mm); +- else +- mm_free(mm->mmalloc, mm); +-} +- +-void * +-mm_xmalloc(struct mm_master *mm, size_t size) +-{ +- void *address; +- +- address = mm_malloc(mm, size); +- if (address == NULL) +- fatal("%s: mm_malloc(%zu)", __func__, size); +- memset(address, 0, size); +- return (address); +-} +- +- +-/* Allocates data from a memory mapped area */ +- +-void * +-mm_malloc(struct mm_master *mm, size_t size) +-{ +- struct mm_share *mms, *tmp; +- +- if (size == 0) +- fatal("mm_malloc: try to allocate 0 space"); +- if (size > SIZE_MAX - MM_MINSIZE + 1) +- fatal("mm_malloc: size too big"); +- +- size = ((size + (MM_MINSIZE - 1)) / MM_MINSIZE) * MM_MINSIZE; +- +- RB_FOREACH(mms, mmtree, &mm->rb_free) { +- if (mms->size >= size) +- break; +- } +- +- if (mms == NULL) +- return (NULL); +- +- /* Debug */ +- memset(mms->address, 0xd0, size); +- +- tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); +- +- /* Does not change order in RB tree */ +- mms->size -= size; +- mms->address = (char *)mms->address + size; +- +- if (mms->size == 0) { +- RB_REMOVE(mmtree, &mm->rb_free, mms); +- if (mm->mmalloc == NULL) +- free(mms); +- else +- mm_free(mm->mmalloc, mms); +- } +- +- return (tmp->address); +-} +- +-/* Frees memory in a memory mapped area */ +- +-void +-mm_free(struct mm_master *mm, void *address) +-{ +- struct mm_share *mms, *prev, tmp; +- +- tmp.address = address; +- mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); +- if (mms == NULL) +- fatal("mm_free(%p): can not find %p", mm, address); +- +- /* Debug */ +- memset(mms->address, 0xd0, mms->size); +- +- /* Remove from allocated list and insert in free list */ +- RB_REMOVE(mmtree, &mm->rb_allocated, mms); +- if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) +- fatal("mm_free(%p): double address %p", mm, address); +- +- /* Find previous entry */ +- prev = mms; +- if (RB_LEFT(prev, next)) { +- prev = RB_LEFT(prev, next); +- while (RB_RIGHT(prev, next)) +- prev = RB_RIGHT(prev, next); +- } else { +- if (RB_PARENT(prev, next) && +- (prev == RB_RIGHT(RB_PARENT(prev, next), next))) +- prev = RB_PARENT(prev, next); +- else { +- while (RB_PARENT(prev, next) && +- (prev == RB_LEFT(RB_PARENT(prev, next), next))) +- prev = RB_PARENT(prev, next); +- prev = RB_PARENT(prev, next); +- } +- } +- +- /* Check if range does not overlap */ +- if (prev != NULL && MM_ADDRESS_END(prev) > address) +- fatal("mm_free: memory corruption: %p(%zu) > %p", +- prev->address, prev->size, address); +- +- /* See if we can merge backwards */ +- if (prev != NULL && MM_ADDRESS_END(prev) == address) { +- prev->size += mms->size; +- RB_REMOVE(mmtree, &mm->rb_free, mms); +- if (mm->mmalloc == NULL) +- free(mms); +- else +- mm_free(mm->mmalloc, mms); +- } else +- prev = mms; +- +- if (prev == NULL) +- return; +- +- /* Check if we can merge forwards */ +- mms = RB_NEXT(mmtree, &mm->rb_free, prev); +- if (mms == NULL) +- return; +- +- if (MM_ADDRESS_END(prev) > mms->address) +- fatal("mm_free: memory corruption: %p < %p(%zu)", +- mms->address, prev->address, prev->size); +- if (MM_ADDRESS_END(prev) != mms->address) +- return; +- +- prev->size += mms->size; +- RB_REMOVE(mmtree, &mm->rb_free, mms); +- +- if (mm->mmalloc == NULL) +- free(mms); +- else +- mm_free(mm->mmalloc, mms); +-} +- +-static void +-mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, +- struct mm_master *mm, struct mm_master *mmold) +-{ +- struct mm_master *mmalloc = mm->mmalloc; +- struct mm_share *mms, *new; +- +- /* Sync free list */ +- RB_FOREACH(mms, mmtree, oldtree) { +- /* Check the values */ +- mm_memvalid(mmold, mms, sizeof(struct mm_share)); +- mm_memvalid(mm, mms->address, mms->size); +- +- new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); +- memcpy(new, mms, sizeof(struct mm_share)); +- RB_INSERT(mmtree, newtree, new); +- } +-} +- +-void +-mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) +-{ +- struct mm_master *mm; +- struct mm_master *mmalloc; +- struct mm_master *mmold; +- struct mmtree rb_free, rb_allocated; +- +- debug3("%s: Share sync", __func__); +- +- mm = *pmm; +- mmold = mm->mmalloc; +- mm_memvalid(mmold, mm, sizeof(*mm)); +- +- mmalloc = mm_create(NULL, mm->size); +- mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); +- memcpy(mm, *pmm, sizeof(struct mm_master)); +- mm->mmalloc = mmalloc; +- +- rb_free = mm->rb_free; +- rb_allocated = mm->rb_allocated; +- +- RB_INIT(&mm->rb_free); +- RB_INIT(&mm->rb_allocated); +- +- mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); +- mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); +- +- mm_destroy(mmold); +- +- *pmm = mm; +- *pmmalloc = mmalloc; +- +- debug3("%s: Share sync end", __func__); +-} +- +-void +-mm_memvalid(struct mm_master *mm, void *address, size_t size) +-{ +- void *end = (char *)address + size; +- +- if (address < mm->address) +- fatal("mm_memvalid: address too small: %p", address); +- if (end < address) +- fatal("mm_memvalid: end < address: %p < %p", end, address); +- if (end > MM_ADDRESS_END(mm)) +- fatal("mm_memvalid: address too large: %p", address); +-} +diff --git a/openssh-7.2p2/monitor_mm.h b/openssh-7.2p2/monitor_mm.h +deleted file mode 100644 +--- a/openssh-7.2p2/monitor_mm.h ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* $OpenBSD: monitor_mm.h,v 1.6 2014/01/04 17:50:55 tedu Exp $ */ +- +-/* +- * Copyright 2002 Niels Provos +- * 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 _MM_H_ +-#define _MM_H_ +- +-struct mm_share { +- RB_ENTRY(mm_share) next; +- void *address; +- size_t size; +-}; +- +-struct mm_master { +- RB_HEAD(mmtree, mm_share) rb_free; +- struct mmtree rb_allocated; +- void *address; +- size_t size; +- +- struct mm_master *mmalloc; /* Used to completely share */ +-}; +- +-RB_PROTOTYPE(mmtree, mm_share, next, mm_compare) +- +-#define MM_MINSIZE 128 +- +-#define MM_ADDRESS_END(x) (void *)((char *)(x)->address + (x)->size) +- +-struct mm_master *mm_create(struct mm_master *, size_t); +-void mm_destroy(struct mm_master *); +- +-void mm_share_sync(struct mm_master **, struct mm_master **); +- +-void *mm_malloc(struct mm_master *, size_t); +-void *mm_xmalloc(struct mm_master *, size_t); +-void mm_free(struct mm_master *, void *); +- +-void mm_memvalid(struct mm_master *, void *, size_t); +-#endif /* _MM_H_ */ +diff --git a/openssh-7.2p2/monitor_wrap.h b/openssh-7.2p2/monitor_wrap.h +--- a/openssh-7.2p2/monitor_wrap.h ++++ b/openssh-7.2p2/monitor_wrap.h +@@ -107,12 +107,9 @@ void mm_send_keystate(struct monitor*); + /* bsdauth */ + int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); + int mm_bsdauth_respond(void *, u_int, char **); + + /* skey */ + int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **); + int mm_skey_respond(void *, u_int, char **); + +-/* zlib allocation hooks */ +-void mm_init_compression(struct mm_master *); +- + #endif /* _MM_WRAP_H_ */ +diff --git a/openssh-7.2p2/myproposal.h b/openssh-7.2p2/myproposal.h +--- a/openssh-7.2p2/myproposal.h ++++ b/openssh-7.2p2/myproposal.h +@@ -156,17 +156,17 @@ + "hmac-sha1" + + #define KEX_CLIENT_KEX KEX_SERVER_KEX + #define KEX_CLIENT_ENCRYPT KEX_SERVER_ENCRYPT + #define KEX_CLIENT_MAC KEX_SERVER_MAC + + #endif /* WITH_OPENSSL */ + +-#define KEX_DEFAULT_COMP "none,zlib@openssh.com,zlib" ++#define KEX_DEFAULT_COMP "none,zlib@openssh.com" + #define KEX_DEFAULT_LANG "" + + #define KEX_CLIENT \ + KEX_CLIENT_KEX, \ + KEX_DEFAULT_PK_ALG, \ + KEX_CLIENT_ENCRYPT, \ + KEX_CLIENT_ENCRYPT, \ + KEX_CLIENT_MAC, \ +diff --git a/openssh-7.2p2/opacket.h b/openssh-7.2p2/opacket.h +--- a/openssh-7.2p2/opacket.h ++++ b/openssh-7.2p2/opacket.h +@@ -128,19 +128,16 @@ void packet_disconnect(const char *, ... + #define packet_set_server() \ + ssh_packet_set_server(active_state) + #define packet_set_authenticated() \ + ssh_packet_set_authenticated(active_state) + #define packet_get_input() \ + ssh_packet_get_input(active_state) + #define packet_get_output() \ + ssh_packet_get_output(active_state) +-#define packet_set_compress_hooks(ctx, allocfunc, freefunc) \ +- ssh_packet_set_compress_hooks(active_state, ctx, \ +- allocfunc, freefunc); + #define packet_check_eom() \ + ssh_packet_check_eom(active_state) + #define set_newkeys(mode) \ + ssh_set_newkeys(active_state, (mode)) + #define packet_get_state(m) \ + ssh_packet_get_state(active_state, m) + #define packet_set_state(m) \ + ssh_packet_set_state(active_state, m) +diff --git a/openssh-7.2p2/openbsd-compat/Makefile.in b/openssh-7.2p2/openbsd-compat/Makefile.in +--- a/openssh-7.2p2/openbsd-compat/Makefile.in ++++ b/openssh-7.2p2/openbsd-compat/Makefile.in +@@ -13,17 +13,17 @@ CPPFLAGS=-I. -I.. -I$(srcdir) -I$(srcdir + LIBS=@LIBS@ + AR=@AR@ + RANLIB=@RANLIB@ + INSTALL=@INSTALL@ + LDFLAGS=-L. @LDFLAGS@ + + OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o + +-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 kludge-fd_set.o ++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 xcrypt.o kludge-fd_set.o + + PORTS=port-aix.o port-irix.o port-linux.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o + + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + + all: libopenbsd-compat.a + +diff --git a/openssh-7.2p2/openbsd-compat/openbsd-compat.h b/openssh-7.2p2/openbsd-compat/openbsd-compat.h +--- a/openssh-7.2p2/openbsd-compat/openbsd-compat.h ++++ b/openssh-7.2p2/openbsd-compat/openbsd-compat.h +@@ -259,17 +259,16 @@ int timingsafe_bcmp(const void *, const + int bcrypt_pbkdf(const char *, size_t, const u_int8_t *, size_t, + u_int8_t *, size_t, unsigned int); + #endif + + #ifndef HAVE_EXPLICIT_BZERO + void explicit_bzero(void *p, size_t n); + #endif + +-void *xmmap(size_t size); + char *xcrypt(const char *password, const char *salt); + char *shadow_pw(struct passwd *pw); + + /* rfc2553 socket API replacements */ + #include "fake-rfc2553.h" + + /* Routines for a single OS platform */ + #include "bsd-cray.h" +diff --git a/openssh-7.2p2/openbsd-compat/xmmap.c b/openssh-7.2p2/openbsd-compat/xmmap.c +deleted file mode 100644 +--- a/openssh-7.2p2/openbsd-compat/xmmap.c ++++ /dev/null +@@ -1,88 +0,0 @@ +-/* +- * Copyright (c) 2002 Tim Rice. All rights reserved. +- * MAP_FAILED code by Solar Designer. +- * +- * 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. +- */ +- +-/* $Id: xmmap.c,v 1.15 2009/02/16 04:21:40 djm Exp $ */ +- +-#include "includes.h" +- +-#include +-#ifdef HAVE_SYS_MMAN_H +-#include +-#endif +-#include +- +-#ifdef HAVE_FCNTL_H +-# include +-#endif +-#include +-#include +-#include +-#include +-#include +- +-#include "log.h" +- +-void * +-xmmap(size_t size) +-{ +-#ifdef HAVE_MMAP +- void *address; +- +-# ifdef MAP_ANON +- address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, +- -1, (off_t)0); +-# else +- address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, +- open("/dev/zero", O_RDWR), (off_t)0); +-# endif +- +-#define MM_SWAP_TEMPLATE "/var/run/sshd.mm.XXXXXXXX" +- if (address == (void *)MAP_FAILED) { +- char tmpname[sizeof(MM_SWAP_TEMPLATE)] = MM_SWAP_TEMPLATE; +- int tmpfd; +- mode_t old_umask; +- +- old_umask = umask(0177); +- tmpfd = mkstemp(tmpname); +- umask(old_umask); +- if (tmpfd == -1) +- fatal("mkstemp(\"%s\"): %s", +- MM_SWAP_TEMPLATE, strerror(errno)); +- unlink(tmpname); +- if (ftruncate(tmpfd, size) != 0) +- fatal("%s: ftruncate: %s", __func__, strerror(errno)); +- address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, +- tmpfd, (off_t)0); +- close(tmpfd); +- } +- +- return (address); +-#else +- fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", +- __func__); +-#endif /* HAVE_MMAP */ +- +-} +- +diff --git a/openssh-7.2p2/packet.c b/openssh-7.2p2/packet.c +--- a/openssh-7.2p2/packet.c ++++ b/openssh-7.2p2/packet.c +@@ -732,96 +732,16 @@ uncompress_buffer(struct ssh *ssh, struc + default: + ssh->state->compression_in_failures++; + return SSH_ERR_INTERNAL_ERROR; + } + } + /* NOTREACHED */ + } + +-/* Serialise compression state into a blob for privsep */ +-static int +-ssh_packet_get_compress_state(struct sshbuf *m, struct ssh *ssh) +-{ +- struct session_state *state = ssh->state; +- struct sshbuf *b; +- int r; +- +- if ((b = sshbuf_new()) == NULL) +- return SSH_ERR_ALLOC_FAIL; +- if (state->compression_in_started) { +- if ((r = sshbuf_put_string(b, &state->compression_in_stream, +- sizeof(state->compression_in_stream))) != 0) +- goto out; +- } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0) +- goto out; +- if (state->compression_out_started) { +- if ((r = sshbuf_put_string(b, &state->compression_out_stream, +- sizeof(state->compression_out_stream))) != 0) +- goto out; +- } else if ((r = sshbuf_put_string(b, NULL, 0)) != 0) +- goto out; +- r = sshbuf_put_stringb(m, b); +- out: +- sshbuf_free(b); +- return r; +-} +- +-/* Deserialise compression state from a blob for privsep */ +-static int +-ssh_packet_set_compress_state(struct ssh *ssh, struct sshbuf *m) +-{ +- struct session_state *state = ssh->state; +- struct sshbuf *b = NULL; +- int r; +- const u_char *inblob, *outblob; +- size_t inl, outl; +- +- if ((r = sshbuf_froms(m, &b)) != 0) +- goto out; +- if ((r = sshbuf_get_string_direct(b, &inblob, &inl)) != 0 || +- (r = sshbuf_get_string_direct(b, &outblob, &outl)) != 0) +- goto out; +- if (inl == 0) +- state->compression_in_started = 0; +- else if (inl != sizeof(state->compression_in_stream)) { +- r = SSH_ERR_INTERNAL_ERROR; +- goto out; +- } else { +- state->compression_in_started = 1; +- memcpy(&state->compression_in_stream, inblob, inl); +- } +- if (outl == 0) +- state->compression_out_started = 0; +- else if (outl != sizeof(state->compression_out_stream)) { +- r = SSH_ERR_INTERNAL_ERROR; +- goto out; +- } else { +- state->compression_out_started = 1; +- memcpy(&state->compression_out_stream, outblob, outl); +- } +- r = 0; +- out: +- sshbuf_free(b); +- return r; +-} +- +-void +-ssh_packet_set_compress_hooks(struct ssh *ssh, void *ctx, +- void *(*allocfunc)(void *, u_int, u_int), +- void (*freefunc)(void *, void *)) +-{ +- ssh->state->compression_out_stream.zalloc = (alloc_func)allocfunc; +- ssh->state->compression_out_stream.zfree = (free_func)freefunc; +- ssh->state->compression_out_stream.opaque = ctx; +- ssh->state->compression_in_stream.zalloc = (alloc_func)allocfunc; +- ssh->state->compression_in_stream.zfree = (free_func)freefunc; +- ssh->state->compression_in_stream.opaque = ctx; +-} +- + /* + * Causes any further packets to be encrypted using the given key. The same + * key is used for both sending and reception. However, both directions are + * encrypted independently of each other. + */ + + void + ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int keylen, int number) +@@ -2487,31 +2407,24 @@ packet_destroy_all(int audit_it, int pri + #endif + } + } + + /* Reset after_authentication and reset compression in post-auth privsep */ + static int + ssh_packet_set_postauth(struct ssh *ssh) + { +- struct sshcomp *comp; +- int r, mode; ++ int r; + + debug("%s: called", __func__); + /* This was set in net child, but is not visible in user child */ + ssh->state->after_authentication = 1; + ssh->state->rekeying = 0; +- for (mode = 0; mode < MODE_MAX; mode++) { +- if (ssh->state->newkeys[mode] == NULL) +- continue; +- comp = &ssh->state->newkeys[mode]->comp; +- if (comp && comp->enabled && +- (r = ssh_packet_init_compression(ssh)) != 0) +- return r; +- } ++ if ((r = ssh_packet_enable_delayed_compress(ssh)) != 0) ++ return r; + return 0; + } + + /* Packet state (de-)serialization for privsep */ + + /* turn kex into a blob for packet state serialization */ + static int + kex_to_blob(struct sshbuf *m, struct kex *kex) +@@ -2565,17 +2478,16 @@ newkeys_to_blob(struct sshbuf *m, struct + goto out; + if (cipher_authlen(enc->cipher) == 0) { + if ((r = sshbuf_put_cstring(b, mac->name)) != 0 || + (r = sshbuf_put_u32(b, mac->enabled)) != 0 || + (r = sshbuf_put_string(b, mac->key, mac->key_len)) != 0) + goto out; + } + if ((r = sshbuf_put_u32(b, comp->type)) != 0 || +- (r = sshbuf_put_u32(b, comp->enabled)) != 0 || + (r = sshbuf_put_cstring(b, comp->name)) != 0) + goto out; + r = sshbuf_put_stringb(m, b); + out: + sshbuf_free(b); + return r; + } + +@@ -2626,19 +2538,17 @@ ssh_packet_get_state(struct ssh *ssh, st + return r; + if (cipher_get_keycontext(&state->send_context, p) != (int)slen) + return SSH_ERR_INTERNAL_ERROR; + if ((r = sshbuf_put_u32(m, rlen)) != 0 || + (r = sshbuf_reserve(m, rlen, &p)) != 0) + return r; + if (cipher_get_keycontext(&state->receive_context, p) != (int)rlen) + return SSH_ERR_INTERNAL_ERROR; +- +- if ((r = ssh_packet_get_compress_state(m, ssh)) != 0 || +- (r = sshbuf_put_stringb(m, state->input)) != 0 || ++ if ((r = sshbuf_put_stringb(m, state->input)) != 0 || + (r = sshbuf_put_stringb(m, state->output)) != 0) + return r; + + return 0; + } + + /* restore key exchange results from blob for packet state de-serialization */ + static int +@@ -2682,17 +2592,16 @@ newkeys_from_blob(struct sshbuf *m, stru + goto out; + if (maclen > mac->key_len) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + mac->key_len = maclen; + } + if ((r = sshbuf_get_u32(b, &comp->type)) != 0 || +- (r = sshbuf_get_u32(b, (u_int *)&comp->enabled)) != 0 || + (r = sshbuf_get_cstring(b, &comp->name, NULL)) != 0) + goto out; + if (enc->name == NULL || + cipher_by_name(enc->name) != enc->cipher) { + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if (sshbuf_len(b) != 0) { +@@ -2810,18 +2719,17 @@ ssh_packet_set_state(struct ssh *ssh, st + (r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0) + return r; + if (cipher_get_keycontext(&state->send_context, NULL) != (int)slen || + cipher_get_keycontext(&state->receive_context, NULL) != (int)rlen) + return SSH_ERR_INVALID_FORMAT; + cipher_set_keycontext(&state->send_context, keyout); + cipher_set_keycontext(&state->receive_context, keyin); + +- if ((r = ssh_packet_set_compress_state(ssh, m)) != 0 || +- (r = ssh_packet_set_postauth(ssh)) != 0) ++ if ((r = ssh_packet_set_postauth(ssh)) != 0) + return r; + + sshbuf_reset(state->input); + sshbuf_reset(state->output); + if ((r = sshbuf_get_string_direct(m, &input, &ilen)) != 0 || + (r = sshbuf_get_string_direct(m, &output, &olen)) != 0 || + (r = sshbuf_put(state->input, input, ilen)) != 0 || + (r = sshbuf_put(state->output, output, olen)) != 0) +diff --git a/openssh-7.2p2/packet.h b/openssh-7.2p2/packet.h +--- a/openssh-7.2p2/packet.h ++++ b/openssh-7.2p2/packet.h +@@ -113,21 +113,16 @@ const void *ssh_packet_get_string_ptr(st + void ssh_packet_disconnect(struct ssh *, const char *fmt, ...) + __attribute__((format(printf, 2, 3))) + __attribute__((noreturn)); + void ssh_packet_send_debug(struct ssh *, const char *fmt, ...) __attribute__((format(printf, 2, 3))); + + int ssh_set_newkeys(struct ssh *, int mode); + void ssh_packet_get_bytes(struct ssh *, u_int64_t *, u_int64_t *); + +-typedef void *(ssh_packet_comp_alloc_func)(void *, u_int, u_int); +-typedef void (ssh_packet_comp_free_func)(void *, void *); +-void ssh_packet_set_compress_hooks(struct ssh *, void *, +- ssh_packet_comp_alloc_func *, ssh_packet_comp_free_func *); +- + int ssh_packet_write_poll(struct ssh *); + int ssh_packet_write_wait(struct ssh *); + int ssh_packet_have_data_to_write(struct ssh *); + int ssh_packet_not_very_much_data_to_write(struct ssh *); + + int ssh_packet_connection_is_on_socket(struct ssh *); + int ssh_packet_remaining(struct ssh *); + void ssh_packet_send_ignore(struct ssh *, int); +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -984,18 +984,18 @@ static const struct multistate multistat + { "without-password", PERMIT_NO_PASSWD }, + { "prohibit-password", PERMIT_NO_PASSWD }, + { "forced-commands-only", PERMIT_FORCED_ONLY }, + { "yes", PERMIT_YES }, + { "no", PERMIT_NO }, + { NULL, -1 } + }; + static const struct multistate multistate_compression[] = { ++ { "yes", COMP_DELAYED }, + { "delayed", COMP_DELAYED }, +- { "yes", COMP_ZLIB }, + { "no", COMP_NONE }, + { NULL, -1 } + }; + static const struct multistate multistate_gatewayports[] = { + { "clientspecified", 2 }, + { "yes", 1 }, + { "no", 0 }, + { NULL, -1 } +diff --git a/openssh-7.2p2/sshconnect2.c b/openssh-7.2p2/sshconnect2.c +--- a/openssh-7.2p2/sshconnect2.c ++++ b/openssh-7.2p2/sshconnect2.c +@@ -192,20 +192,20 @@ ssh_kex2(char *host, struct sockaddr *ho + fatal("%s: kex_names_cat", __func__); + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(options.ciphers); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(options.ciphers); + if (options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = +- myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,zlib,none"; ++ myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib@openssh.com,none"; + } else { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = +- myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com,zlib"; ++ myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; + } + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; + if (options.hostkeyalgorithms != NULL) { + if (kex_assemble_names(KEX_DEFAULT_PK_ALG, + &options.hostkeyalgorithms) != 0) + fatal("%s: kex_assemble_namelist", __func__); + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -112,17 +112,16 @@ + #include "canohost.h" + #include "hostfile.h" + #include "auth.h" + #include "authfd.h" + #include "msg.h" + #include "dispatch.h" + #include "channels.h" + #include "session.h" +-#include "monitor_mm.h" + #include "monitor.h" + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "audit.h" + #include "ssh-sandbox.h" + #include "version.h" +@@ -748,19 +747,16 @@ privsep_preauth(Authctxt *authctxt) + ssh_err(r)); + have_agent = 0; + } + } + if (box != NULL) + ssh_sandbox_parent_preauth(box, pid); + monitor_child_preauth(authctxt, pmonitor); + +- /* Sync memory */ +- monitor_sync(pmonitor); +- + /* Wait for the child's exit status */ + while (waitpid(pid, &status, 0) < 0) { + if (errno == EINTR) + continue; + pmonitor->m_pid = -1; + fatal("%s: waitpid: %s", __func__, strerror(errno)); + } + privsep_is_preauth = 0; +@@ -2761,19 +2757,16 @@ do_ssh2_kex(void) + myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal( + options.ciphers); + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; + + if (options.compression == COMP_NONE) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; +- } else if (options.compression == COMP_DELAYED) { +- myproposal[PROPOSAL_COMP_ALGS_CTOS] = +- myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; + } + + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits(options.rekey_limit, + (time_t)options.rekey_interval); + + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( + list_hostkey_types()); +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -530,25 +530,27 @@ will be disconnected after approximately + Sets a timeout interval in seconds after which if no data has been received + from the client, + .Xr sshd 8 + will send a message through the encrypted + channel to request a response from the client. + The default + is 0, indicating that these messages will not be sent to the client. + .It Cm Compression +-Specifies whether compression is allowed, or delayed until ++Specifies whether compression is enabled after + the user has authenticated successfully. + The argument must be + .Dq yes , +-.Dq delayed , ++.Dq delayed ++(a legacy synonym for ++.Dq yes ) + or + .Dq no . + The default is +-.Dq delayed . ++.Dq yes . + .It Cm DenyGroups + This keyword can be followed by a list of group name patterns, separated + by spaces. + Login is disallowed for users whose primary group or supplementary + group list matches one of the patterns. + Only group names are valid; a numerical group ID is not recognized. + By default, login is allowed for all groups. + The allow/deny directives are processed in the following order: diff --git a/openssh-7.6p1-disable_short_DH_parameters.patch b/openssh-7.2p2-disable_short_DH_parameters.patch similarity index 72% rename from openssh-7.6p1-disable_short_DH_parameters.patch rename to openssh-7.2p2-disable_short_DH_parameters.patch index f77d4a9..b08abba 100644 --- a/openssh-7.6p1-disable_short_DH_parameters.patch +++ b/openssh-7.2p2-disable_short_DH_parameters.patch @@ -1,5 +1,5 @@ # HG changeset patch -# Parent a5b0f249f564de9c9efd023c6430f607d9861acd +# Parent 7b5f436e0026923299fdd1994f8da8fd9948be7c Raise minimal size of DH group parameters to 2048 bits like upstream did in 7.2. 1024b values are believed to be in breaking range for state adversaries @@ -12,9 +12,9 @@ compliant) parameters. CVE-2015-4000 (LOGJAM) bsc#932483 -diff --git a/openssh-7.6p1/dh.c b/openssh-7.6p1/dh.c ---- a/openssh-7.6p1/dh.c -+++ b/openssh-7.6p1/dh.c +diff --git a/openssh-7.2p2/dh.c b/openssh-7.2p2/dh.c +--- a/openssh-7.2p2/dh.c ++++ b/openssh-7.2p2/dh.c @@ -37,16 +37,18 @@ #include @@ -34,10 +34,10 @@ diff --git a/openssh-7.6p1/dh.c b/openssh-7.6p1/dh.c const char *errstr = NULL; long long n; -diff --git a/openssh-7.6p1/dh.h b/openssh-7.6p1/dh.h ---- a/openssh-7.6p1/dh.h -+++ b/openssh-7.6p1/dh.h -@@ -45,16 +45,17 @@ int dh_gen_key(DH *, int); +diff --git a/openssh-7.2p2/dh.h b/openssh-7.2p2/dh.h +--- a/openssh-7.2p2/dh.h ++++ b/openssh-7.2p2/dh.h +@@ -43,16 +43,17 @@ int dh_gen_key(DH *, int); int dh_pub_is_valid(DH *, BIGNUM *); u_int dh_estimate(int); @@ -55,23 +55,23 @@ diff --git a/openssh-7.6p1/dh.h b/openssh-7.6p1/dh.h * Specifies the internal structure of the prime modulus. */ #define MODULI_TYPE_UNKNOWN (0) -diff --git a/openssh-7.6p1/kexgexc.c b/openssh-7.6p1/kexgexc.c ---- a/openssh-7.6p1/kexgexc.c -+++ b/openssh-7.6p1/kexgexc.c +diff --git a/openssh-7.2p2/kexgexc.c b/openssh-7.2p2/kexgexc.c +--- a/openssh-7.2p2/kexgexc.c ++++ b/openssh-7.2p2/kexgexc.c @@ -46,29 +46,32 @@ + #include "packet.h" #include "dh.h" #include "ssh2.h" #include "compat.h" #include "dispatch.h" #include "ssherr.h" #include "sshbuf.h" - #include "misc.h" +/* import from dh.c */ +extern int dh_grp_min; + - static int input_kex_dh_gex_group(int, u_int32_t, struct ssh *); - static int input_kex_dh_gex_reply(int, u_int32_t, struct ssh *); + static int input_kex_dh_gex_group(int, u_int32_t, void *); + static int input_kex_dh_gex_reply(int, u_int32_t, void *); int kexgex_client(struct ssh *ssh) @@ -87,12 +87,12 @@ diff --git a/openssh-7.6p1/kexgexc.c b/openssh-7.6p1/kexgexc.c kex->max = DH_GRP_MAX; kex->nbits = nbits; if (datafellows & SSH_BUG_DHGEX_LARGE) - kex->nbits = MINIMUM(kex->nbits, 4096); + kex->nbits = MIN(kex->nbits, 4096); /* New GEX request */ if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 || (r = sshpkt_put_u32(ssh, kex->min)) != 0 || (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || -@@ -103,16 +106,22 @@ input_kex_dh_gex_group(int type, u_int32 +@@ -104,16 +107,22 @@ input_kex_dh_gex_group(int type, u_int32 goto out; } if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || @@ -115,30 +115,30 @@ diff --git a/openssh-7.6p1/kexgexc.c b/openssh-7.6p1/kexgexc.c goto out; } p = g = NULL; /* belong to kex->dh now */ -diff --git a/openssh-7.6p1/kexgexs.c b/openssh-7.6p1/kexgexs.c ---- a/openssh-7.6p1/kexgexs.c -+++ b/openssh-7.6p1/kexgexs.c +diff --git a/openssh-7.2p2/kexgexs.c b/openssh-7.2p2/kexgexs.c +--- a/openssh-7.2p2/kexgexs.c ++++ b/openssh-7.2p2/kexgexs.c @@ -49,16 +49,19 @@ + #ifdef GSSAPI #include "ssh-gss.h" #endif #include "monitor_wrap.h" #include "dispatch.h" #include "ssherr.h" #include "sshbuf.h" - #include "misc.h" +/* import from dh.c */ +extern int dh_grp_min; + - static int input_kex_dh_gex_request(int, u_int32_t, struct ssh *); - static int input_kex_dh_gex_init(int, u_int32_t, struct ssh *); + static int input_kex_dh_gex_request(int, u_int32_t, void *); + static int input_kex_dh_gex_init(int, u_int32_t, void *); int kexgex_server(struct ssh *ssh) { ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, &input_kex_dh_gex_request); -@@ -77,23 +80,29 @@ input_kex_dh_gex_request(int type, u_int +@@ -78,23 +81,29 @@ input_kex_dh_gex_request(int type, u_int if ((r = sshpkt_get_u32(ssh, &min)) != 0 || (r = sshpkt_get_u32(ssh, &nbits)) != 0 || (r = sshpkt_get_u32(ssh, &max)) != 0 || @@ -147,15 +147,15 @@ diff --git a/openssh-7.6p1/kexgexs.c b/openssh-7.6p1/kexgexs.c kex->nbits = nbits; kex->min = min; kex->max = max; -- min = MAXIMUM(DH_GRP_MIN, min); -+ min = MAXIMUM(dh_grp_min, min); - max = MINIMUM(DH_GRP_MAX, max); -- nbits = MAXIMUM(DH_GRP_MIN, nbits); -+ nbits = MAXIMUM(dh_grp_min, nbits); - nbits = MINIMUM(DH_GRP_MAX, nbits); +- min = MAX(DH_GRP_MIN, min); ++ min = MAX(dh_grp_min, min); + max = MIN(DH_GRP_MAX, max); +- nbits = MAX(DH_GRP_MIN, nbits); ++ nbits = MAX(dh_grp_min, nbits); + nbits = MIN(DH_GRP_MAX, nbits); if (kex->max < kex->min || kex->nbits < kex->min || - kex->max < kex->nbits || kex->max < DH_GRP_MIN) { + kex->max < kex->nbits) { + if (kex->nbits < kex->min && kex->nbits >= DH_GRP_MIN_RFC) + logit("DH parameter requested by the client (%d bits) " + "is considered insecure. " @@ -170,10 +170,10 @@ diff --git a/openssh-7.6p1/kexgexs.c b/openssh-7.6p1/kexgexs.c kex->dh = PRIVSEP(choose_dh(min, nbits, max)); if (kex->dh == NULL) { sshpkt_disconnect(ssh, "no matching DH grp found"); -diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c ---- a/openssh-7.6p1/readconf.c -+++ b/openssh-7.6p1/readconf.c -@@ -61,16 +61,17 @@ +diff --git a/openssh-7.2p2/readconf.c b/openssh-7.2p2/readconf.c +--- a/openssh-7.2p2/readconf.c ++++ b/openssh-7.2p2/readconf.c +@@ -56,16 +56,17 @@ #include "misc.h" #include "readconf.h" #include "match.h" @@ -191,14 +191,14 @@ diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c # 2. user-specific file # 3. system-wide file # Any configuration value is only changed the first time it is set. -@@ -161,17 +162,18 @@ typedef enum { +@@ -148,17 +149,18 @@ typedef enum { + oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, - oTunnel, oTunnelDevice, - oLocalCommand, oPermitLocalCommand, oRemoteCommand, + oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oVisualHostKey, - oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oKexAlgorithms, oKexDHMin, @@ -207,18 +207,18 @@ diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, - oPubkeyAcceptedKeyTypes, oProxyJump, - oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported + oPubkeyAcceptedKeyTypes, + oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; -@@ -283,16 +285,17 @@ static struct { - { "include", oInclude }, +@@ -260,16 +262,17 @@ static struct { + { "hashknownhosts", oHashKnownHosts }, { "tunnel", oTunnel }, { "tunneldevice", oTunnelDevice }, { "localcommand", oLocalCommand }, { "permitlocalcommand", oPermitLocalCommand }, - { "remotecommand", oRemoteCommand }, { "visualhostkey", oVisualHostKey }, + { "useroaming", oDeprecated }, { "kexalgorithms", oKexAlgorithms }, + { "kexdhmin", oKexDHMin }, { "ipqos", oIPQoS }, @@ -229,11 +229,11 @@ diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c { "canonicalizehostname", oCanonicalizeHostname }, { "canonicalizemaxdots", oCanonicalizeMaxDots }, { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, -@@ -304,16 +307,19 @@ static struct { +@@ -280,16 +283,19 @@ static struct { + { "updatehostkeys", oUpdateHostkeys }, { "hostbasedkeytypes", oHostbasedKeyTypes }, { "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes }, { "ignoreunknown", oIgnoreUnknown }, - { "proxyjump", oProxyJump }, { NULL, oBadOption } }; @@ -249,9 +249,9 @@ diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c void add_local_forward(Options *options, const struct Forward *newfwd) { -@@ -1206,16 +1212,20 @@ parse_int: - if (*arg != '-' && - !kex_names_valid(*arg == '+' ? arg + 1 : arg)) +@@ -1157,16 +1163,20 @@ parse_int: + filename, linenum); + if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : ""); if (*activep && options->kex_algorithms == NULL) @@ -269,62 +269,63 @@ diff --git a/openssh-7.6p1/readconf.c b/openssh-7.6p1/readconf.c if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (*arg != '-' && -@@ -1803,16 +1813,17 @@ initialize_options(Options * options) - options->port = -1; + if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) +@@ -1664,16 +1674,17 @@ initialize_options(Options * options) options->address_family = -1; options->connection_attempts = -1; options->connection_timeout = -1; options->number_of_password_prompts = -1; + options->cipher = -1; options->ciphers = NULL; options->macs = NULL; options->kex_algorithms = NULL; + options->kex_dhmin = -1; options->hostkeyalgorithms = NULL; + options->protocol = SSH_PROTO_UNKNOWN; options->num_identity_files = 0; options->num_certificate_files = 0; options->hostname = NULL; options->host_key_alias = NULL; options->proxy_command = NULL; - options->jump_user = NULL; - options->jump_host = NULL; -@@ -1951,16 +1962,23 @@ fill_default_options(Options * options) - if (options->port == -1) - options->port = 0; /* Filled in ssh_connect. */ - if (options->address_family == -1) + options->user = NULL; +@@ -1805,16 +1816,23 @@ fill_default_options(Options * options) options->address_family = AF_UNSPEC; if (options->connection_attempts == -1) options->connection_attempts = 1; if (options->number_of_password_prompts == -1) options->number_of_password_prompts = 3; + /* Selected in ssh_login(). */ + if (options->cipher == -1) + options->cipher = SSH_CIPHER_NOT_SET; + if (options->kex_dhmin == -1) + options->kex_dhmin = DH_GRP_MIN_RFC; + else { -+ options->kex_dhmin = MAXIMUM(options->kex_dhmin, DH_GRP_MIN_RFC); -+ options->kex_dhmin = MINIMUM(options->kex_dhmin, DH_GRP_MAX); ++ options->kex_dhmin = MAX(options->kex_dhmin, DH_GRP_MIN_RFC); ++ options->kex_dhmin = MIN(options->kex_dhmin, DH_GRP_MAX); + } + dh_grp_min = options->kex_dhmin; /* options->hostkeyalgorithms, default set in myproposals.h */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_2; if (options->add_keys_to_agent == -1) options->add_keys_to_agent = 0; if (options->num_identity_files == 0) { - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_RSA, 0); - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); - #ifdef OPENSSL_HAS_ECC - add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); -diff --git a/openssh-7.6p1/readconf.h b/openssh-7.6p1/readconf.h ---- a/openssh-7.6p1/readconf.h -+++ b/openssh-7.6p1/readconf.h -@@ -64,16 +64,17 @@ typedef struct { - int connection_timeout; /* Max time (seconds) before + if (options->protocol & SSH_PROTO_1) { + add_identity_file(options, "~/", +diff --git a/openssh-7.2p2/readconf.h b/openssh-7.2p2/readconf.h +--- a/openssh-7.2p2/readconf.h ++++ b/openssh-7.2p2/readconf.h +@@ -69,16 +69,17 @@ typedef struct { * aborting connection attempt */ int number_of_password_prompts; /* Max number of password * prompts. */ + int cipher; /* Cipher to use. */ char *ciphers; /* SSH2 ciphers in order of preference. */ char *macs; /* SSH2 macs in order of preference. */ char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */ char *kex_algorithms; /* SSH2 kex methods in order of preference. */ + int kex_dhmin; /* minimum bit length of the DH group parameter */ + int protocol; /* Protocol in order of preference. */ char *hostname; /* Real host to connect. */ char *host_key_alias; /* hostname alias for .ssh/known_hosts */ char *proxy_command; /* Proxy command for connecting the host. */ @@ -332,10 +333,9 @@ diff --git a/openssh-7.6p1/readconf.h b/openssh-7.6p1/readconf.h int escape_char; /* Escape character; -2 = none */ u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ - char *system_hostfiles[SSH_MAX_HOSTS_FILES]; -diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c ---- a/openssh-7.6p1/servconf.c -+++ b/openssh-7.6p1/servconf.c +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c @@ -52,16 +52,20 @@ #include "channels.h" #include "groupaccess.h" @@ -357,7 +357,7 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c extern int use_privsep; extern Buffer cfg; -@@ -129,16 +133,17 @@ initialize_server_options(ServerOptions +@@ -134,16 +138,17 @@ initialize_server_options(ServerOptions options->allow_agent_forwarding = -1; options->num_allow_users = 0; options->num_deny_users = 0; @@ -367,6 +367,7 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c options->macs = NULL; options->kex_algorithms = NULL; + options->kex_dhmin = -1; + options->protocol = SSH_PROTO_UNKNOWN; options->fwd_opts.gateway_ports = -1; options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; options->fwd_opts.streamlocal_bind_unlink = -1; @@ -374,8 +375,7 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c options->max_startups_begin = -1; options->max_startups_rate = -1; options->max_startups = -1; - options->max_authtries = -1; -@@ -195,16 +200,24 @@ fill_default_server_options(ServerOption +@@ -199,16 +204,23 @@ fill_default_server_options(ServerOption int i; /* Portable-specific options */ @@ -387,20 +387,19 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c + if (options->kex_dhmin == -1) + options->kex_dhmin = DH_GRP_MIN_RFC; + else { -+ options->kex_dhmin = MAXIMUM(options->kex_dhmin, DH_GRP_MIN_RFC); -+ options->kex_dhmin = MINIMUM(options->kex_dhmin, DH_GRP_MAX); ++ options->kex_dhmin = MAX(options->kex_dhmin, DH_GRP_MIN_RFC); ++ options->kex_dhmin = MIN(options->kex_dhmin, DH_GRP_MAX); + } + dh_grp_min = options->kex_dhmin; -+ /* Standard Options */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_2; if (options->num_host_key_files == 0) { /* fill default hostkeys for protocols */ - options->host_key_files[options->num_host_key_files++] = - _PATH_HOST_RSA_KEY_FILE; - options->host_key_files[options->num_host_key_files++] = - _PATH_HOST_DSA_KEY_FILE; - #ifdef OPENSSL_HAS_ECC -@@ -414,17 +427,18 @@ typedef enum { + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = + _PATH_HOST_KEY_FILE; +@@ -423,17 +435,18 @@ typedef enum { sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, sAcceptEnv, sPermitTunnel, @@ -415,12 +414,12 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sStreamLocalBindMask, sStreamLocalBindUnlink, - sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, - sExposeAuthInfo, - sDeprecated, sIgnore, sUnsupported + sAllowStreamLocalForwarding, sFingerprintHash, + sDeprecated, sUnsupported } ServerOpCodes; -@@ -553,16 +567,17 @@ static struct { + #define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */ +@@ -561,16 +574,17 @@ static struct { { "permitopen", sPermitOpen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, @@ -438,9 +437,9 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, -@@ -1502,16 +1517,20 @@ process_server_config_line(ServerOptions - if (*arg != '-' && - !kex_names_valid(*arg == '+' ? arg + 1 : arg)) +@@ -1481,16 +1495,20 @@ process_server_config_line(ServerOptions + filename, linenum); + if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", filename, linenum, arg ? arg : ""); if (options->kex_algorithms == NULL) @@ -451,17 +450,17 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c + intptr = &options->kex_dhmin; + goto parse_int; + - case sSubsystem: - if (options->num_subsystems >= MAX_SUBSYSTEMS) { - fatal("%s line %d: too many subsystems defined.", - filename, linenum); - } + case sProtocol: + intptr = &options->protocol; arg = strdelim(&cp); if (!arg || *arg == '\0') - fatal("%s line %d: Missing subsystem name.", -@@ -2285,16 +2304,17 @@ dump_config(ServerOptions *o) - #endif + fatal("%s line %d: Missing argument.", filename, linenum); + value = proto_spec(arg); + if (value == SSH_PROTO_UNKNOWN) + fatal("%s line %d: Bad protocol spec '%s'.", +@@ -2247,16 +2265,17 @@ dump_config(ServerOptions *o) 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(sMaxAuthTries, o->max_authtries); dump_cfg_int(sMaxSessions, o->max_sessions); @@ -474,13 +473,13 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login); dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts); dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts); + dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication); dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication); dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly, - o->hostbased_uses_name_from_packet_only); -diff --git a/openssh-7.6p1/servconf.h b/openssh-7.6p1/servconf.h ---- a/openssh-7.6p1/servconf.h -+++ b/openssh-7.6p1/servconf.h -@@ -93,16 +93,17 @@ typedef struct { +diff --git a/openssh-7.2p2/servconf.h b/openssh-7.2p2/servconf.h +--- a/openssh-7.2p2/servconf.h ++++ b/openssh-7.2p2/servconf.h +@@ -88,16 +88,17 @@ typedef struct { int permit_user_rc; /* If false, deny ~/.ssh/rc execution */ int strict_modes; /* If true, require string home dir modes. */ int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */ @@ -490,17 +489,17 @@ diff --git a/openssh-7.6p1/servconf.h b/openssh-7.6p1/servconf.h char *macs; /* Supported SSH2 macs. */ char *kex_algorithms; /* SSH2 kex methods in order of preference. */ + int kex_dhmin; /* minimum bit length of the DH group parameter */ + int protocol; /* Supported protocol versions. */ struct ForwardOptions fwd_opts; /* forwarding options */ SyslogFacility log_facility; /* Facility for system logging. */ LogLevel log_level; /* Level for system logging. */ + int rhosts_rsa_authentication; /* If true, permit rhosts RSA + * authentication. */ int hostbased_authentication; /* If true, permit ssh2 hostbased auth */ int hostbased_uses_name_from_packet_only; /* experimental */ - char *hostbased_key_types; /* Key types allowed for hostbased */ - char *hostkeyalgorithms; /* SSH2 server key types */ - int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ -diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config ---- a/openssh-7.6p1/ssh_config -+++ b/openssh-7.6p1/ssh_config +diff --git a/openssh-7.2p2/ssh_config b/openssh-7.2p2/ssh_config +--- a/openssh-7.2p2/ssh_config ++++ b/openssh-7.2p2/ssh_config @@ -12,16 +12,21 @@ # Any configuration value is only changed the first time it is set. # Thus, host-specific definitions should be at the beginning of the @@ -523,17 +522,17 @@ diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config # should not forward X11 connections to your local X11-display for # security reasons: Someone stealing the authentification data on the # remote side (the "spoofed" X-server by the remote sshd) can read your -diff --git a/openssh-7.6p1/ssh_config.0 b/openssh-7.6p1/ssh_config.0 ---- a/openssh-7.6p1/ssh_config.0 -+++ b/openssh-7.6p1/ssh_config.0 -@@ -584,16 +584,33 @@ DESCRIPTION +diff --git a/openssh-7.2p2/ssh_config.0 b/openssh-7.2p2/ssh_config.0 +--- a/openssh-7.2p2/ssh_config.0 ++++ b/openssh-7.2p2/ssh_config.0 +@@ -606,16 +606,33 @@ DESCRIPTION ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1, diffie-hellman-group14-sha1 The list of available key exchange algorithms may also be - obtained using "ssh -Q kex". + obtained using the -Q option of ssh(1) with an argument of M-bM-^@M-^\kexM-bM-^@M-^]. + KexDHMin + Specifies the minimum accepted bit length of the DH group @@ -556,22 +555,22 @@ diff --git a/openssh-7.6p1/ssh_config.0 b/openssh-7.6p1/ssh_config.0 Specifies a command to execute on the local machine after successfully connecting to the server. The command string extends to the end of the line, and is executed with the user's - shell. Arguments to LocalCommand accept the tokens described in - the TOKENS section. - - The command is run synchronously and does not have access to the -diff --git a/openssh-7.6p1/ssh_config.5 b/openssh-7.6p1/ssh_config.5 ---- a/openssh-7.6p1/ssh_config.5 -+++ b/openssh-7.6p1/ssh_config.5 -@@ -1016,16 +1016,32 @@ 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 + shell. The following escape character substitutions will be + performed: M-bM-^@M-^X%dM-bM-^@M-^Y (local user's home directory), M-bM-^@M-^X%hM-bM-^@M-^Y (remote host + name), M-bM-^@M-^X%lM-bM-^@M-^Y (local host name), M-bM-^@M-^X%nM-bM-^@M-^Y (host name as provided on the + command line), M-bM-^@M-^X%pM-bM-^@M-^Y (remote port), M-bM-^@M-^X%rM-bM-^@M-^Y (remote user name) or +diff --git a/openssh-7.2p2/ssh_config.5 b/openssh-7.2p2/ssh_config.5 +--- a/openssh-7.2p2/ssh_config.5 ++++ b/openssh-7.2p2/ssh_config.5 +@@ -1092,16 +1092,32 @@ diffie-hellman-group14-sha1 .Ed .Pp - The list of available key exchange algorithms may also be obtained using - .Qq ssh -Q kex . + The list of available key exchange algorithms may also be obtained using the + .Fl Q + option of + .Xr ssh 1 + with an argument of + .Dq kex . +.It Cm KexDHMin +Specifies the minimum accepted bit length of the DH group +parameter p. @@ -593,16 +592,16 @@ diff --git a/openssh-7.6p1/ssh_config.5 b/openssh-7.6p1/ssh_config.5 connecting to the server. The command string extends to the end of the line, and is executed with the user's shell. - Arguments to - .Cm LocalCommand - accept the tokens described in the -diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config ---- a/openssh-7.6p1/sshd_config -+++ b/openssh-7.6p1/sshd_config -@@ -15,16 +15,21 @@ - #ListenAddress 0.0.0.0 - #ListenAddress :: - + The following escape character substitutions will be performed: + .Ql %d + (local user's home directory), +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -21,16 +21,21 @@ + # HostKey for protocol version 1 + #HostKey /etc/ssh/ssh_host_key + # HostKeys for protocol version 2 #HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key #HostKey /etc/ssh/ssh_host_ecdsa_key @@ -613,25 +612,25 @@ diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config +# Upstream default is identical to setting this to 2048. +#KexDHMin 1024 + + # Lifetime and size of ephemeral version 1 server key + #KeyRegenerationInterval 1h + #ServerKeyBits 1024 + # Ciphers and keying #RekeyLimit default none # Logging - #SyslogFacility AUTH - #LogLevel INFO - - # Authentication: -diff --git a/openssh-7.6p1/sshd_config.0 b/openssh-7.6p1/sshd_config.0 ---- a/openssh-7.6p1/sshd_config.0 -+++ b/openssh-7.6p1/sshd_config.0 -@@ -532,16 +532,33 @@ DESCRIPTION - curve25519-sha256,curve25519-sha256@libssh.org, +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -539,16 +539,33 @@ DESCRIPTION + curve25519-sha256@libssh.org, ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, diffie-hellman-group-exchange-sha256, diffie-hellman-group14-sha1 The list of available key exchange algorithms may also be - obtained using "ssh -Q kex". + obtained using the -Q option of ssh(1) with an argument of M-bM-^@M-^\kexM-bM-^@M-^]. + KexDHMin + Specifies the minimum accepted bit length of the DH group @@ -650,26 +649,26 @@ diff --git a/openssh-7.6p1/sshd_config.0 b/openssh-7.6p1/sshd_config.0 + resort and all efforts should be made to fix the (broken) + counterparty. + - ListenAddress - Specifies the local addresses sshd(8) should listen on. The - following forms may be used: + KeyRegenerationInterval + In protocol version 1, the ephemeral server key is automatically + regenerated after this many seconds (if it has been used). The + purpose of regeneration is to prevent decrypting captured + sessions by later breaking into the machine and stealing the + keys. The key is never stored anywhere. If the value is 0, the + key is never regenerated. The default is 3600 (seconds). - ListenAddress host|IPv4_addr|IPv6_addr - ListenAddress host|IPv4_addr:port - ListenAddress [host|IPv6_addr]:port - -diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 ---- a/openssh-7.6p1/sshd_config.5 -+++ b/openssh-7.6p1/sshd_config.5 -@@ -893,16 +893,32 @@ 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 +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -895,16 +895,32 @@ diffie-hellman-group14-sha1 .Ed .Pp - The list of available key exchange algorithms may also be obtained using - .Qq ssh -Q kex . + The list of available key exchange algorithms may also be obtained using the + .Fl Q + option of + .Xr ssh 1 + with an argument of + .Dq kex . +.It Cm KexDHMin +Specifies the minimum accepted bit length of the DH group +parameter p. @@ -686,11 +685,11 @@ diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 +security and thus should be viewed as a temporary fix of last +resort and all efforts should be made to fix the (broken) +counterparty. - .It Cm ListenAddress - Specifies the local addresses - .Xr sshd 8 - should listen on. - The following forms may be used: - .Pp - .Bl -item -offset indent -compact - .It + .It Cm KeyRegenerationInterval + In protocol version 1, the ephemeral server key is automatically regenerated + after this many seconds (if it has been used). + The purpose of regeneration is to prevent + decrypting captured sessions by later breaking into the machine and + stealing the keys. + The key is never stored anywhere. + If the value is 0, the key is never regenerated. diff --git a/openssh-7.2p2-dont_use_pthreads_in_PAM.patch b/openssh-7.2p2-dont_use_pthreads_in_PAM.patch new file mode 100644 index 0000000..f382f6a --- /dev/null +++ b/openssh-7.2p2-dont_use_pthreads_in_PAM.patch @@ -0,0 +1,29 @@ +# HG changeset patch +# Parent e4886597a8984ae1594b6866fe1b232370b23529 +# posix threads are generally not supported nor safe +# (see upstream log from 2005-05-24) +# --used to be called '-pam-fix3' + +diff --git a/openssh-7.2p2/auth-pam.c b/openssh-7.2p2/auth-pam.c +--- a/openssh-7.2p2/auth-pam.c ++++ b/openssh-7.2p2/auth-pam.c +@@ -782,17 +782,19 @@ sshpam_query(void *ctx, char **name, cha + } + if (type == PAM_SUCCESS) { + if (!sshpam_authctxt->valid || + (sshpam_authctxt->pw->pw_uid == 0 && + options.permit_root_login != PERMIT_YES)) + fatal("Internal error: PAM auth " + "succeeded when it should have " + "failed"); ++#ifndef UNSUPPORTED_POSIX_THREADS_HACK + import_environments(&buffer); ++#endif + *num = 0; + **echo_on = 0; + ctxt->pam_done = 1; + free(msg); + return (0); + } + error("PAM: %s for %s%.100s from %.100s", msg, + sshpam_authctxt->valid ? "" : "illegal user ", diff --git a/openssh-7.2p2-eal3.patch b/openssh-7.2p2-eal3.patch new file mode 100644 index 0000000..201a239 --- /dev/null +++ b/openssh-7.2p2-eal3.patch @@ -0,0 +1,87 @@ +# HG changeset patch +# Parent f19426f2fa9c634474e635bf33b86acea0518f6d +fix paths and references in sshd man pages + +diff --git a/openssh-7.2p2/sshd.8 b/openssh-7.2p2/sshd.8 +--- a/openssh-7.2p2/sshd.8 ++++ b/openssh-7.2p2/sshd.8 +@@ -901,17 +901,17 @@ See + If this file exists, + .Nm + refuses to let anyone except root log in. + The contents of the file + are displayed to anyone trying to log in, and non-root connections are + refused. + The file should be world-readable. + .Pp +-.It Pa /etc/shosts.equiv ++.It Pa /etc/ssh/shosts.equiv + This file is used in exactly the same way as + .Pa hosts.equiv , + but allows host-based authentication without permitting login with + rlogin/rsh. + .Pp + .It Pa /etc/ssh/ssh_host_key + .It Pa /etc/ssh/ssh_host_dsa_key + .It Pa /etc/ssh/ssh_host_ecdsa_key +@@ -981,17 +981,17 @@ The content of this file is not sensitiv + .Xr scp 1 , + .Xr sftp 1 , + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-agent 1 , + .Xr ssh-keygen 1 , + .Xr ssh-keyscan 1 , + .Xr chroot 2 , +-.Xr login.conf 5 , ++.Xr login.defs 5 , + .Xr moduli 5 , + .Xr sshd_config 5 , + .Xr inetd 8 , + .Xr sftp-server 8 + .Sh AUTHORS + OpenSSH is a derivative of the original and free + ssh 1.2.12 release by Tatu Ylonen. + Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -370,18 +370,17 @@ for details). + The contents of the specified file are sent to the remote user before + authentication is allowed. + If the argument is + .Dq none + then no banner is displayed. + By default, no banner is displayed. + .It Cm ChallengeResponseAuthentication + Specifies whether challenge-response authentication is allowed (e.g. via +-PAM or through authentication styles supported in +-.Xr login.conf 5 ) ++PAM) + The default is + .Dq yes . + .It Cm ChrootDirectory + Specifies the pathname of a directory to + .Xr chroot 2 + to after authentication. + At session startup + .Xr sshd 8 +@@ -766,17 +765,17 @@ and + .Pa .shosts + files will not be used in + .Cm RhostsRSAAuthentication + or + .Cm HostbasedAuthentication . + .Pp + .Pa /etc/hosts.equiv + and +-.Pa /etc/shosts.equiv ++.Pa /etc/ssh/shosts.equiv + are still used. + The default is + .Dq yes . + .It Cm IgnoreUserKnownHosts + Specifies whether + .Xr sshd 8 + should ignore the user's + .Pa ~/.ssh/known_hosts diff --git a/openssh-7.2p2-enable_PAM_by_default.patch b/openssh-7.2p2-enable_PAM_by_default.patch new file mode 100644 index 0000000..93bda5c --- /dev/null +++ b/openssh-7.2p2-enable_PAM_by_default.patch @@ -0,0 +1,47 @@ +# HG changeset patch +# Parent 980f301b2920c09b30577dd722546bca85d25fc1 +# force PAM in defaullt install (this was removed from upstream in 3.8p1) +# bnc#46749 +# --used to be called '-pam-fix2' + +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -64,17 +64,17 @@ AuthorizedKeysFile .ssh/authorized_keys + #HostbasedAuthentication no + # Change to yes if you don't trust ~/.ssh/known_hosts for + # RhostsRSAAuthentication and HostbasedAuthentication + #IgnoreUserKnownHosts no + # Don't read the user's ~/.rhosts and ~/.shosts files + #IgnoreRhosts yes + + # To disable tunneled clear text passwords, change to no here! +-#PasswordAuthentication yes ++PasswordAuthentication no + #PermitEmptyPasswords no + + # Change to no to disable s/key passwords + #ChallengeResponseAuthentication yes + + # Kerberos options + #KerberosAuthentication no + #KerberosOrLocalPasswd yes +@@ -89,17 +89,17 @@ AuthorizedKeysFile .ssh/authorized_keys + # and session processing. If this is enabled, PAM authentication will + # be allowed through the ChallengeResponseAuthentication and + # PasswordAuthentication. Depending on your PAM configuration, + # PAM authentication via ChallengeResponseAuthentication may bypass + # the setting of "PermitRootLogin without-password". + # If you just want the PAM account and session checks to run without + # PAM authentication, then enable this but set PasswordAuthentication + # and ChallengeResponseAuthentication to 'no'. +-#UsePAM no ++UsePAM yes + + #AllowAgentForwarding yes + #AllowTcpForwarding yes + #GatewayPorts no + X11Forwarding yes + #X11DisplayOffset 10 + #X11UseLocalhost yes + #PermitTTY yes diff --git a/openssh-7.2p2-fips.patch b/openssh-7.2p2-fips.patch new file mode 100644 index 0000000..4c3dbe4 --- /dev/null +++ b/openssh-7.2p2-fips.patch @@ -0,0 +1,1834 @@ +# HG changeset patch +# Parent 5f2b8faa3b60de28124d9d4a44ffa2635d67f601 +FIPS 140-2 compliance. Perform selftests on start and use only FIPS approved +algorithms. + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -89,16 +89,18 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ + 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 + ++LIBSSH_OBJS += fips.o ++ + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o + + SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ + audit.o audit-bsm.o audit-linux.o platform.o \ + sshpty.o sshlogin.o servconf.o serverloop.o \ + auth.o auth1.o auth2.o auth-options.o session.o \ + auth-chall.o auth2-chall.o groupaccess.o \ +diff --git a/openssh-7.2p2/auth-rsa.c b/openssh-7.2p2/auth-rsa.c +--- a/openssh-7.2p2/auth-rsa.c ++++ b/openssh-7.2p2/auth-rsa.c +@@ -46,16 +46,18 @@ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "ssh.h" + + #include "digest.h" + ++#include "fips.h" ++ + /* import */ + extern ServerOptions options; + + /* + * Session identifier that is used to bind key exchange and authentication + * responses to a particular session. + */ + extern u_char session_id[16]; +@@ -86,45 +88,52 @@ auth_rsa_generate_challenge(Key *key) + if (BN_mod(challenge, challenge, key->rsa->n, ctx) == 0) + fatal("auth_rsa_generate_challenge: BN_mod failed"); + BN_CTX_free(ctx); + + return challenge; + } + + int +-auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) ++auth_rsa_verify_response(Key *key, BIGNUM *challenge, ++ u_char response[SSH_DIGEST_MAX_LENGTH]) + { +- u_char buf[32], mdbuf[16]; ++ u_char buf[2 * SSH_DIGEST_MAX_LENGTH], mdbuf[SSH_DIGEST_MAX_LENGTH]; + struct ssh_digest_ctx *md; + int len; ++ int dgst; ++ size_t dgst_len; + + /* don't allow short keys */ + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error("%s: RSA modulus too small: %d < minimum %d bits", + __func__, + BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); + return (0); + } + +- /* The response is MD5 of decrypted challenge plus session id. */ ++ dgst = fips_correct_dgst(SSH_DIGEST_MD5); ++ dgst_len = ssh_digest_bytes(dgst); ++ ++ /* The response is a hash of decrypted challenge plus session id. ++ * Normally this is MD5, in FIPS mode a stronger function is used. */ + len = BN_num_bytes(challenge); +- if (len <= 0 || len > 32) ++ if (len <= 0 || (unsigned int)len > (2 * dgst_len)) + fatal("%s: bad challenge length %d", __func__, len); +- memset(buf, 0, 32); +- BN_bn2bin(challenge, buf + 32 - len); +- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || +- ssh_digest_update(md, buf, 32) < 0 || +- ssh_digest_update(md, session_id, 16) < 0 || ++ memset(buf, 0, sizeof(buf)); ++ BN_bn2bin(challenge, buf + 2 * dgst_len - len); ++ if ((md = ssh_digest_start(dgst)) == NULL || ++ ssh_digest_update(md, buf, 2 * dgst_len) < 0 || ++ ssh_digest_update(md, session_id, dgst_len) < 0 || + ssh_digest_final(md, mdbuf, sizeof(mdbuf)) < 0) + fatal("%s: md5 failed", __func__); + ssh_digest_free(md); + + /* Verify that the response is the original challenge. */ +- if (timingsafe_bcmp(response, mdbuf, 16) != 0) { ++ if (timingsafe_bcmp(response, mdbuf, dgst_len) != 0) { + /* Wrong answer. */ + return (0); + } + /* Correct answer. */ + return (1); + } + + /* +@@ -132,17 +141,17 @@ auth_rsa_verify_response(Key *key, BIGNU + * and returns true (non-zero) if the client gave the correct answer to + * our challenge; returns zero if the client gives a wrong answer. + */ + + int + auth_rsa_challenge_dialog(Key *key) + { + BIGNUM *challenge, *encrypted_challenge; +- u_char response[16]; ++ u_char response[SSH_DIGEST_MAX_LENGTH]; + int i, success; + + if ((encrypted_challenge = BN_new()) == NULL) + fatal("auth_rsa_challenge_dialog: BN_new() failed"); + + challenge = PRIVSEP(auth_rsa_generate_challenge(key)); + + /* Encrypt the challenge with the public key. */ +@@ -153,17 +162,17 @@ auth_rsa_challenge_dialog(Key *key) + packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); + packet_put_bignum(encrypted_challenge); + packet_send(); + BN_clear_free(encrypted_challenge); + packet_write_wait(); + + /* Wait for a response. */ + packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE); +- for (i = 0; i < 16; i++) ++ for (i = 0; i < ssh_digest_bytes(fips_dgst_min()); i++) + response[i] = (u_char)packet_get_char(); + packet_check_eom(); + + success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); + BN_clear_free(challenge); + return (success); + } + +diff --git a/openssh-7.2p2/cipher-ctr.c b/openssh-7.2p2/cipher-ctr.c +--- a/openssh-7.2p2/cipher-ctr.c ++++ b/openssh-7.2p2/cipher-ctr.c +@@ -22,16 +22,18 @@ + #include + #include + + #include + + #include "xmalloc.h" + #include "log.h" + ++#include "fips.h" ++ + /* compatibility with old or broken OpenSSL versions */ + #include "openbsd-compat/openssl-compat.h" + + #ifndef USE_BUILTIN_RIJNDAEL + #include + #endif + + struct ssh_aes_ctr_ctx +@@ -134,13 +136,15 @@ evp_aes_128_ctr(void) + aes_ctr.iv_len = AES_BLOCK_SIZE; + aes_ctr.key_len = 16; + aes_ctr.init = ssh_aes_ctr_init; + aes_ctr.cleanup = ssh_aes_ctr_cleanup; + aes_ctr.do_cipher = ssh_aes_ctr; + #ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; ++ if (fips_mode()) ++ aes_ctr.flags |= EVP_CIPH_FLAG_FIPS; + #endif + return (&aes_ctr); + } + + #endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_HAVE_EVPCTR) */ +diff --git a/openssh-7.2p2/cipher.c b/openssh-7.2p2/cipher.c +--- a/openssh-7.2p2/cipher.c ++++ b/openssh-7.2p2/cipher.c +@@ -46,16 +46,19 @@ + #include "cipher.h" + #include "misc.h" + #include "sshbuf.h" + #include "ssherr.h" + #include "digest.h" + + #include "openbsd-compat/openssl-compat.h" + ++#include "fips.h" ++#include "log.h" ++ + #ifdef WITH_SSH1 + extern const EVP_CIPHER *evp_ssh1_bf(void); + extern const EVP_CIPHER *evp_ssh1_3des(void); + extern int ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + #endif + + struct sshcipher { + char *name; +@@ -72,17 +75,17 @@ struct sshcipher { + #define CFLAG_NONE (1<<3) + #ifdef WITH_OPENSSL + const EVP_CIPHER *(*evptype)(void); + #else + void *ignored; + #endif + }; + +-static const struct sshcipher ciphers[] = { ++static const struct sshcipher ciphers_all[] = { + #ifdef WITH_SSH1 + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, + { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, + { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, + #endif /* WITH_SSH1 */ + #ifdef WITH_OPENSSL + { "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 }, +@@ -114,27 +117,75 @@ static const struct sshcipher ciphers[] + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL }, + #endif /* WITH_OPENSSL */ + { "chacha20-poly1305@openssh.com", + SSH_CIPHER_SSH2, 8, 64, 0, 16, 0, CFLAG_CHACHAPOLY, NULL }, + + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } + }; + ++static const struct sshcipher ciphers_fips140_2[] = { ++#ifdef WITH_SSH1 ++ { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, ++#endif /* WITH_SSH1 */ ++#ifdef WITH_OPENSSL ++ { "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 /* OPENSSL_HAVE_EVPGCM */ ++#else /* WITH_OPENSSL */ ++ { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, CFLAG_AESCTR, NULL }, ++ { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, CFLAG_AESCTR, NULL }, ++ { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, CFLAG_AESCTR, NULL }, ++ { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, CFLAG_NONE, NULL }, ++#endif /* WITH_OPENSSL */ ++ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } ++}; ++ + /*--*/ + ++/* Returns array of ciphers available depending on selected FIPS mode */ ++static const struct sshcipher * ++fips_select_ciphers(void) ++{ ++ int fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ return ciphers_all; ++ case 1: ++ return ciphers_fips140_2; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ return NULL; ++ } ++} ++ + /* Returns a comma-separated list of supported ciphers. */ + char * + cipher_alg_list(char sep, int auth_only) + { + char *tmp, *ret = NULL; + size_t nlen, rlen = 0; + const struct sshcipher *c; + +- for (c = ciphers; c->name != NULL; c++) { ++ for (c = fips_select_ciphers(); c->name != NULL; c++) { + if (c->number != SSH_CIPHER_SSH2) + continue; + if (auth_only && c->auth_len == 0) + continue; + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(c->name); + if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { +@@ -208,27 +259,27 @@ cipher_mask_ssh1(int client) + } + return mask; + } + + const struct sshcipher * + cipher_by_name(const char *name) + { + const struct sshcipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) + if (strcmp(c->name, name) == 0) + return c; + return NULL; + } + + const struct sshcipher * + cipher_by_number(int id) + { + const struct sshcipher *c; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) + if (c->number == id) + return c; + return NULL; + } + + #define CIPHER_SEP "," + int + ciphers_valid(const char *names) +@@ -259,17 +310,17 @@ ciphers_valid(const char *names) + */ + + int + cipher_number(const char *name) + { + const struct sshcipher *c; + if (name == NULL) + return -1; +- for (c = ciphers; c->name != NULL; c++) ++ for (c = fips_select_ciphers(); c->name != NULL; c++) + if (strcasecmp(c->name, name) == 0) + return c->number; + return -1; + } + + char * + cipher_name(int id) + { +@@ -477,25 +528,26 @@ cipher_cleanup(struct sshcipher_ctx *cc) + /* + * Selects the cipher, and keys if by computing the MD5 checksum of the + * passphrase and using the resulting 16 bytes as the key. + */ + int + cipher_set_key_string(struct sshcipher_ctx *cc, const struct sshcipher *cipher, + const char *passphrase, int do_encrypt) + { +- u_char digest[16]; ++ u_char digest[SSH_DIGEST_MAX_LENGTH]; ++ int dgst = fips_correct_dgst(SSH_DIGEST_MD5); + int r = SSH_ERR_INTERNAL_ERROR; + +- if ((r = ssh_digest_memory(SSH_DIGEST_MD5, ++ if ((r = ssh_digest_memory(dgst, + passphrase, strlen(passphrase), + digest, sizeof(digest))) != 0) + goto out; + +- r = cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); ++ r = cipher_init(cc, cipher, digest, ssh_digest_bytes(dgst), NULL, 0, do_encrypt); + out: + explicit_bzero(digest, sizeof(digest)); + return r; + } + + /* + * Exports an IV from the sshcipher_ctx required to export the key + * state back from the unprivileged child to the privileged parent +diff --git a/openssh-7.2p2/dh.h b/openssh-7.2p2/dh.h +--- a/openssh-7.2p2/dh.h ++++ b/openssh-7.2p2/dh.h +@@ -45,16 +45,17 @@ int dh_pub_is_valid(DH *, BIGNUM *); + u_int dh_estimate(int); + + /* + * Max value from RFC4419. + * Miniumum increased in light of DH precomputation attacks. + */ + #define DH_GRP_MIN_RFC 1024 + #define DH_GRP_MIN 2048 ++#define DH_GRP_MIN_FIPS 2048 + #define DH_GRP_MAX 8192 + + /* + * Values for "type" field of moduli(5) + * Specifies the internal structure of the prime modulus. + */ + #define MODULI_TYPE_UNKNOWN (0) + #define MODULI_TYPE_UNSTRUCTURED (1) +diff --git a/openssh-7.2p2/fips.c b/openssh-7.2p2/fips.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/fips.c +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (c) 2012 Petr Cerny. 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" ++ ++#include "fips.h" ++ ++#include "cipher.h" ++#include "dh.h" ++#include "digest.h" ++#include "kex.h" ++#include "key.h" ++#include "mac.h" ++#include "log.h" ++#include "xmalloc.h" ++ ++#include ++#include ++ ++/* import from dh.c */ ++extern int dh_grp_min; ++ ++static int fips_state = -1; ++ ++static int ++fips_check_required_env(void) ++{ ++ int fips_required = 0; ++ char *env = getenv(SSH_FORCE_FIPS_ENV); ++ ++ if (env) { ++ errno = 0; ++ fips_required = strtol(env, NULL, 10); ++ if (errno) { ++ debug("bogus value in the %s environment variable, ignoring\n" ++ , SSH_FORCE_FIPS_ENV); ++ fips_required = 0; ++ } else ++ fips_required = 1; ++ } ++ return fips_required; ++} ++ ++int ++fips_mode(void) ++{ ++ if (-1 == fips_state) { ++ fips_state = FIPS_mode(); ++ if (fips_state) ++ debug("FIPS mode initialized"); ++ else { ++ if (fips_check_required_env()) { ++ debug("FIPS mode requested through the environment variable '%s'" ++ , SSH_FORCE_FIPS_ENV); ++ if (!FIPS_mode_set(1)) ++ fatal("Unable to enter FIPS mode as requested through the environment variable '%s'" ++ , SSH_FORCE_FIPS_ENV); ++ fips_state = 1; ++ } ++ } ++ } ++ return fips_state; ++} ++ ++int ++fips_correct_dgst(int digest) ++{ ++ int fips; ++ int rv = -1; ++ ++ fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ rv = digest; ++ break; ++ case 1: ++ switch (digest) { ++ case SSH_DIGEST_MD5: ++ case SSH_DIGEST_RIPEMD160: ++ debug("MD5/RIPEMD160 digests not allowed in FIPS 140-2 mode" ++ "using SHA-256 instead."); ++ rv = SSH_DIGEST_SHA256; ++ break; ++ default: ++ rv = digest; ++ break; ++ } ++ break; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++ ++ return rv; ++} ++ ++/* ++ * filter out FIPS disallowed algorithms ++ * *crypto MUST be free()-able - it is assigned newly allocated memory and ++ * the previous one is freed ++ * ++ * returns zero if all algorithms were rejected, non-zero otherwise ++ */ ++int ++fips_filter_crypto(char **crypto, fips_filters filter) ++{ ++ char *token, *tmp, *tmp_sav, *new; ++ int plus = 0; ++ int valid; ++ int comma = 0; ++ int empty = 1; ++ size_t len; ++ ++ tmp = tmp_sav = xstrdup(*crypto); ++ ++ len = strlen(tmp) + 1; ++ new = xcalloc(1, len); ++ ++ if ('+' == *tmp) { ++ plus = 1; ++ tmp++; ++ } ++ ++ while ((token = strsep(&tmp, ",")) != NULL) { ++ switch(filter) { ++ case FIPS_FILTER_CIPHERS: ++ valid = ciphers_valid(token); ++ if (!valid) ++ debug("Cipher '%s' is not allowed in FIPS mode", ++ token); ++ break; ++ case FIPS_FILTER_MACS: ++ valid = mac_valid(token); ++ if (!valid) ++ debug("MAC '%s' is not allowed in FIPS mode", ++ token); ++ break; ++ case FIPS_FILTER_KEX_ALGS: ++ valid = kex_names_valid(token); ++ if (!valid) ++ debug("KEX '%s' is not allowed in FIPS mode", ++ token); ++ break; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS filter '%i' requested at %s:%u", ++ filter, __FILE__, __LINE__); ++ } ++ ++ if (valid) { ++ empty = 0; ++ if (plus) { ++ strlcat(new, "+", len); ++ plus = 0; ++ } ++ if (comma) ++ strlcat(new, ",", len); ++ else ++ comma = 1; ++ strlcat(new, token, len); ++ } ++ } ++ ++ /* free tmp and re-allocate shorter buffer for result if necessary */ ++ free(tmp_sav); ++ free(*crypto); ++ *crypto = new; ++ ++ return (!empty); ++} ++ ++int ++fips_dgst_min(void) ++{ ++ int fips; ++ int dgst; ++ ++ fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ dgst = SSH_DIGEST_MD5; ++ break; ++ case 1: ++ dgst = SSH_DIGEST_SHA1; ++ break; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++ return dgst; ++} ++ ++int ++fips_dh_grp_min(void) ++{ ++ int fips; ++ int dh; ++ ++ fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ dh = dh_grp_min; ++ break; ++ case 1: ++ dh = DH_GRP_MIN_FIPS; ++ break; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++ return dh; ++} ++ +diff --git a/openssh-7.2p2/fips.h b/openssh-7.2p2/fips.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/fips.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2012 Petr Cerny. 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 FIPS_H ++#define FIPS_H ++ ++#include "key.h" ++ ++#define SSH_FORCE_FIPS_ENV "SSH_FORCE_FIPS" ++ ++typedef enum { ++ FIPS_FILTER_CIPHERS, ++ FIPS_FILTER_MACS, ++ FIPS_FILTER_KEX_ALGS ++} fips_filters; ++ ++int fips_mode(void); ++int fips_correct_dgst(int); ++int fips_dgst_min(void); ++int fips_dh_grp_min(void); ++enum fp_type fips_correct_fp_type(enum fp_type); ++int fips_filter_crypto(char **, fips_filters); ++ ++#endif ++ +diff --git a/openssh-7.2p2/hmac.c b/openssh-7.2p2/hmac.c +--- a/openssh-7.2p2/hmac.c ++++ b/openssh-7.2p2/hmac.c +@@ -139,17 +139,17 @@ ssh_hmac_free(struct ssh_hmac_ctx *ctx) + /* cc -DTEST hmac.c digest.c buffer.c cleanup.c fatal.c log.c xmalloc.c -lcrypto */ + static void + hmac_test(void *key, size_t klen, void *m, size_t mlen, u_char *e, size_t elen) + { + struct ssh_hmac_ctx *ctx; + size_t i; + u_char digest[16]; + +- if ((ctx = ssh_hmac_start(SSH_DIGEST_MD5)) == NULL) ++ if ((ctx = ssh_hmac_start(fips_correct_dgst(SSH_DIGEST_MD5))) == NULL) + printf("ssh_hmac_start failed"); + if (ssh_hmac_init(ctx, key, klen) < 0 || + ssh_hmac_update(ctx, m, mlen) < 0 || + ssh_hmac_final(ctx, digest, sizeof(digest)) < 0) + printf("ssh_hmac_xxx failed"); + ssh_hmac_free(ctx); + + if (memcmp(e, digest, elen)) { +diff --git a/openssh-7.2p2/kex.c b/openssh-7.2p2/kex.c +--- a/openssh-7.2p2/kex.c ++++ b/openssh-7.2p2/kex.c +@@ -49,16 +49,18 @@ + #include "misc.h" + #include "dispatch.h" + #include "monitor.h" + + #include "ssherr.h" + #include "sshbuf.h" + #include "digest.h" + ++#include "fips.h" ++ + #if OPENSSL_VERSION_NUMBER >= 0x00907000L + # if defined(HAVE_EVP_SHA256) + # define evp_ssh_sha256 EVP_sha256 + # else + extern const EVP_MD *evp_ssh_sha256(void); + # endif + #endif + +@@ -80,17 +82,17 @@ static const char *proposal_names[PROPOS + }; + + struct kexalg { + char *name; + u_int type; + int ec_nid; + int hash_alg; + }; +-static const struct kexalg kexalgs[] = { ++static const struct kexalg kexalgs_all[] = { + #ifdef WITH_OPENSSL + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, + { 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 /* HAVE_EVP_SHA256 */ + #ifdef OPENSSL_HAS_ECC +@@ -105,24 +107,62 @@ static const struct kexalg kexalgs[] = { + #endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ + #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) + { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, + #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + { NULL, -1, -1, -1}, + }; + ++static const struct kexalg kexalgs_fips140_2[] = { ++#ifdef WITH_OPENSSL ++ { 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 /* HAVE_EVP_SHA256 */ ++#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 /* OPENSSL_HAS_NISTP521 */ ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ { NULL, -1, -1, -1}, ++}; ++ ++/* Returns array of macs available depending on selected FIPS mode */ ++static const struct kexalg * ++fips_select_kexalgs(void) ++{ ++ int fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ return kexalgs_all; ++ case 1: ++ return kexalgs_fips140_2; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++} ++ + char * + kex_alg_list(char sep) + { + char *ret = NULL, *tmp; + size_t nlen, rlen = 0; + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = fips_select_kexalgs(); k->name != NULL; k++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); + if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { + free(ret); + return NULL; + } + ret = tmp; +@@ -132,17 +172,17 @@ kex_alg_list(char sep) + return ret; + } + + static const struct kexalg * + kex_alg_by_name(const char *name) + { + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = fips_select_kexalgs(); k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; + } + return NULL; + } + + /* Validate KEX method name list */ + int +@@ -967,39 +1007,41 @@ kex_derive_keys_bn(struct ssh *ssh, u_ch + int + derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, + u_int8_t cookie[8], u_int8_t id[16]) + { + u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; + struct ssh_digest_ctx *hashctx = NULL; + size_t hlen, slen; + int r; ++ int digest; + + hlen = BN_num_bytes(host_modulus); + slen = BN_num_bytes(server_modulus); + if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) || + slen < (512 / 8) || (u_int)slen > sizeof(sbuf)) + return SSH_ERR_KEY_BITS_MISMATCH; + if (BN_bn2bin(host_modulus, hbuf) <= 0 || + BN_bn2bin(server_modulus, sbuf) <= 0) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) { ++ digest = fips_correct_dgst(SSH_DIGEST_MD5); ++ if ((hashctx = ssh_digest_start(digest)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (ssh_digest_update(hashctx, hbuf, hlen) != 0 || + ssh_digest_update(hashctx, sbuf, slen) != 0 || + ssh_digest_update(hashctx, cookie, 8) != 0 || + ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); ++ memcpy(id, obuf, ssh_digest_bytes(digest)); + r = 0; + out: + ssh_digest_free(hashctx); + explicit_bzero(hbuf, sizeof(hbuf)); + explicit_bzero(sbuf, sizeof(sbuf)); + explicit_bzero(obuf, sizeof(obuf)); + return r; + } +diff --git a/openssh-7.2p2/kexgexc.c b/openssh-7.2p2/kexgexc.c +--- a/openssh-7.2p2/kexgexc.c ++++ b/openssh-7.2p2/kexgexc.c +@@ -46,32 +46,31 @@ + #include "packet.h" + #include "dh.h" + #include "ssh2.h" + #include "compat.h" + #include "dispatch.h" + #include "ssherr.h" + #include "sshbuf.h" + +-/* import from dh.c */ +-extern int dh_grp_min; ++#include "fips.h" + + static int input_kex_dh_gex_group(int, u_int32_t, void *); + static int input_kex_dh_gex_reply(int, u_int32_t, void *); + + int + kexgex_client(struct ssh *ssh) + { + struct kex *kex = ssh->kex; + int r; + u_int nbits; + + nbits = dh_estimate(kex->dh_need * 8); + +- kex->min = dh_grp_min; ++ kex->min = fips_dh_grp_min(); + kex->max = DH_GRP_MAX; + kex->nbits = nbits; + if (datafellows & SSH_BUG_DHGEX_LARGE) + kex->nbits = MIN(kex->nbits, 4096); + /* New GEX request */ + if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 || + (r = sshpkt_put_u32(ssh, kex->min)) != 0 || + (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || +diff --git a/openssh-7.2p2/kexgexs.c b/openssh-7.2p2/kexgexs.c +--- a/openssh-7.2p2/kexgexs.c ++++ b/openssh-7.2p2/kexgexs.c +@@ -49,18 +49,17 @@ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "dispatch.h" + #include "ssherr.h" + #include "sshbuf.h" + +-/* import from dh.c */ +-extern int dh_grp_min; ++#include "fips.h" + + static int input_kex_dh_gex_request(int, u_int32_t, void *); + static int input_kex_dh_gex_init(int, u_int32_t, void *); + + int + kexgex_server(struct ssh *ssh) + { + ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, +@@ -81,19 +80,19 @@ input_kex_dh_gex_request(int type, u_int + if ((r = sshpkt_get_u32(ssh, &min)) != 0 || + (r = sshpkt_get_u32(ssh, &nbits)) != 0 || + (r = sshpkt_get_u32(ssh, &max)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + goto out; + kex->nbits = nbits; + kex->min = min; + kex->max = max; +- min = MAX(dh_grp_min, min); ++ min = MAX(fips_dh_grp_min(), min); + max = MIN(DH_GRP_MAX, max); +- nbits = MAX(dh_grp_min, nbits); ++ nbits = MAX(fips_dh_grp_min(), nbits); + nbits = MIN(DH_GRP_MAX, nbits); + + if (kex->max < kex->min || kex->nbits < kex->min || + kex->max < kex->nbits) { + if (kex->nbits < kex->min && kex->nbits >= DH_GRP_MIN_RFC) + logit("DH parameter requested by the client (%d bits) " + "is considered insecure. " + "You can lower the accepted minimum " +diff --git a/openssh-7.2p2/mac.c b/openssh-7.2p2/mac.c +--- a/openssh-7.2p2/mac.c ++++ b/openssh-7.2p2/mac.c +@@ -35,31 +35,34 @@ + #include "umac.h" + #include "mac.h" + #include "misc.h" + #include "ssherr.h" + #include "sshbuf.h" + + #include "openbsd-compat/openssl-compat.h" + ++#include "fips.h" ++#include "log.h" ++ + #define SSH_DIGEST 1 /* SSH_DIGEST_XXX */ + #define SSH_UMAC 2 /* UMAC (not integrated with OpenSSL) */ + #define SSH_UMAC128 3 + + struct macalg { + char *name; + int type; + int alg; + int truncatebits; /* truncate digest if != 0 */ + int key_len; /* just for UMAC */ + int len; /* just for UMAC */ + int etm; /* Encrypt-then-MAC */ + }; + +-static const struct macalg macs[] = { ++static const struct macalg macs_all[] = { + /* 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 }, + #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 + { "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 }, +@@ -80,25 +83,60 @@ static const struct macalg macs[] = { + { "hmac-md5-96-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_MD5, 96, 0, 0, 1 }, + { "hmac-ripemd160-etm@openssh.com", SSH_DIGEST, SSH_DIGEST_RIPEMD160, 0, 0, 0, 1 }, + { "umac-64-etm@openssh.com", SSH_UMAC, 0, 0, 128, 64, 1 }, + { "umac-128-etm@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 1 }, + + { NULL, 0, 0, 0, 0, 0, 0 } + }; + ++static const struct macalg macs_fips140_2[] = { ++ /* 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 array of macs available depending on selected FIPS mode */ ++static const struct macalg * ++fips_select_macs(void) ++{ ++ int fips = fips_mode(); ++ switch (fips) { ++ case 0: ++ return macs_all; ++ case 1: ++ return macs_fips140_2; ++ default: ++ /* should not be reached */ ++ fatal("Fatal error: incorrect FIPS mode '%i' at %s:%u", ++ fips, __FILE__, __LINE__); ++ } ++} ++ + /* Returns a list of supported MACs separated by the specified char. */ + char * + mac_alg_list(char sep) + { + char *ret = NULL, *tmp; + size_t nlen, rlen = 0; + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = fips_select_macs(); m->name != NULL; m++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(m->name); + if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { + free(ret); + return NULL; + } + ret = tmp; +@@ -127,17 +165,17 @@ mac_setup_by_alg(struct sshmac *mac, con + return 0; + } + + int + mac_setup(struct sshmac *mac, char *name) + { + const struct macalg *m; + +- for (m = macs; m->name != NULL; m++) { ++ for (m = fips_select_macs(); m->name != NULL; m++) { + if (strcmp(name, m->name) != 0) + continue; + if (mac != NULL) + return mac_setup_by_alg(mac, m); + return 0; + } + return SSH_ERR_INVALID_ARGUMENT; + } +diff --git a/openssh-7.2p2/myproposal.h b/openssh-7.2p2/myproposal.h +--- a/openssh-7.2p2/myproposal.h ++++ b/openssh-7.2p2/myproposal.h +@@ -128,16 +128,18 @@ + "hmac-sha2-256," \ + "hmac-sha2-512," \ + "hmac-sha1" + + #define KEX_CLIENT_MAC KEX_SERVER_MAC + + #else /* WITH_OPENSSL */ + ++#error "OpenSSL support is needed for FIPS mode to compile" ++ + #define KEX_SERVER_KEX \ + "curve25519-sha256@libssh.org" + #define KEX_DEFAULT_PK_ALG \ + "ssh-ed25519-cert-v01@openssh.com," \ + "ssh-ed25519" + #define KEX_SERVER_ENCRYPT \ + "chacha20-poly1305@openssh.com," \ + "aes128-ctr,aes192-ctr,aes256-ctr" +diff --git a/openssh-7.2p2/readconf.c b/openssh-7.2p2/readconf.c +--- a/openssh-7.2p2/readconf.c ++++ b/openssh-7.2p2/readconf.c +@@ -57,16 +57,17 @@ + #include "readconf.h" + #include "match.h" + #include "kex.h" + #include "mac.h" + #include "uidswap.h" + #include "myproposal.h" + #include "digest.h" + #include "dh.h" ++#include "fips.h" + + /* Format of the configuration file: + + # Configuration data is parsed as follows: + # 1. command line options + # 2. user-specific file + # 3. system-wide file + # Any configuration value is only changed the first time it is set. +@@ -1628,16 +1629,33 @@ read_config_file(const char *filename, s + + /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ + int + option_clear_or_none(const char *o) + { + return o == NULL || strcasecmp(o, "none") == 0; + } + ++/* remove algorithms not approved for use in FIPS mode, when running in FIPS ++ * mode ++ */ ++void ++filter_fips_algorithms(Options *o) ++{ ++ if (fips_mode()) { ++ if (!fips_filter_crypto(&o->ciphers, FIPS_FILTER_CIPHERS)) ++ fatal("None of selected ciphers can be used in FIPS mode"); ++ if (!fips_filter_crypto(&o->macs, FIPS_FILTER_MACS)) ++ fatal("None of selected MAC algorithms can be used in FIPS mode"); ++ if (!fips_filter_crypto(&o->kex_algorithms, FIPS_FILTER_KEX_ALGS)) ++ fatal("None of selected KEX algorithms can be used in FIPS mode"); ++ } ++ return; ++} ++ + /* + * Initializes options to special values that indicate that they have not yet + * been set. Read_config_file will only set options with this value. Options + * are processed in the following order: command line, user config file, + * system config file. Last, fill_default_options is called. + */ + + void +@@ -1817,19 +1835,20 @@ fill_default_options(Options * options) + if (options->connection_attempts == -1) + options->connection_attempts = 1; + if (options->number_of_password_prompts == -1) + options->number_of_password_prompts = 3; + /* Selected in ssh_login(). */ + if (options->cipher == -1) + options->cipher = SSH_CIPHER_NOT_SET; + if (options->kex_dhmin == -1) +- options->kex_dhmin = DH_GRP_MIN_RFC; ++ options->kex_dhmin = fips_dh_grp_min(); + else { +- options->kex_dhmin = MAX(options->kex_dhmin, DH_GRP_MIN_RFC); ++ options->kex_dhmin = MAX(options->kex_dhmin, ++ fips_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN_RFC); + options->kex_dhmin = MIN(options->kex_dhmin, DH_GRP_MAX); + } + dh_grp_min = options->kex_dhmin; + /* options->hostkeyalgorithms, default set in myproposals.h */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_2; + if (options->add_keys_to_agent == -1) + options->add_keys_to_agent = 0; +@@ -1914,26 +1933,29 @@ fill_default_options(Options * options) + if (options->canonicalize_max_dots == -1) + options->canonicalize_max_dots = 1; + if (options->canonicalize_fallback_local == -1) + 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; ++ options->fingerprint_hash = ++ fips_correct_dgst(options->fingerprint_hash); + if (options->update_hostkeys == -1) + options->update_hostkeys = 0; + if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 || + kex_assemble_names(KEX_CLIENT_MAC, &options->macs) != 0 || + kex_assemble_names(KEX_CLIENT_KEX, &options->kex_algorithms) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, + &options->hostbased_key_types) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, + &options->pubkey_key_types) != 0) + fatal("%s: kex_assemble_names failed", __func__); ++ filter_fips_algorithms(options); + + #define CLEAR_ON_NONE(v) \ + do { \ + if (option_clear_or_none(v)) { \ + free(v); \ + v = NULL; \ + } \ + } while(0) +diff --git a/openssh-7.2p2/readconf.h b/openssh-7.2p2/readconf.h +--- a/openssh-7.2p2/readconf.h ++++ b/openssh-7.2p2/readconf.h +@@ -180,16 +180,17 @@ typedef struct { + #define SSHCONF_CHECKPERM 1 /* check permissions on config file */ + #define SSHCONF_USERCONF 2 /* user provided config file not system */ + #define SSHCONF_POSTCANON 4 /* After hostname canonicalisation */ + + #define SSH_UPDATE_HOSTKEYS_NO 0 + #define SSH_UPDATE_HOSTKEYS_YES 1 + #define SSH_UPDATE_HOSTKEYS_ASK 2 + ++void filter_fips_algorithms(Options *o); + void initialize_options(Options *); + void fill_default_options(Options *); + void fill_default_options_for_canonicalization(Options *); + int process_config_line(Options *, struct passwd *, const char *, + const char *, char *, const char *, int, int *, int); + int read_config_file(const char *, struct passwd *, const char *, + const char *, Options *, int); + int parse_forward(struct Forward *, const char *, int, int); +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -53,16 +53,17 @@ + #include "groupaccess.h" + #include "canohost.h" + #include "packet.h" + #include "hostfile.h" + #include "auth.h" + #include "myproposal.h" + #include "digest.h" + #include "dh.h" ++#include "fips.h" + + /* import from dh.c */ + extern int dh_grp_min; + + static void add_listen_addr(ServerOptions *, char *, int); + static void add_one_listen_addr(ServerOptions *, char *, int); + + /* Use of privilege separation or not */ +@@ -179,45 +180,65 @@ initialize_server_options(ServerOptions + + /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ + static int + option_clear_or_none(const char *o) + { + return o == NULL || strcasecmp(o, "none") == 0; + } + ++/* remove algorithms not approved for use in FIPS mode, when running in FIPS ++ * mode ++ */ ++static void ++filter_fips_algorithms_s(ServerOptions *o) ++{ ++ if (fips_mode()) { ++ if (!fips_filter_crypto(&o->ciphers, FIPS_FILTER_CIPHERS)) ++ fatal("None of selected ciphers can be used in FIPS mode"); ++ if (!fips_filter_crypto(&o->macs, FIPS_FILTER_MACS)) ++ fatal("None of selected MAC algorithms can be used in FIPS mode"); ++ if (!fips_filter_crypto(&o->kex_algorithms, FIPS_FILTER_KEX_ALGS)) ++ fatal("None of selected KEX algorithms can be used in FIPS mode"); ++ } ++ return; ++} ++ + static void + assemble_algorithms(ServerOptions *o) + { + if (kex_assemble_names(KEX_SERVER_ENCRYPT, &o->ciphers) != 0 || + kex_assemble_names(KEX_SERVER_MAC, &o->macs) != 0 || + kex_assemble_names(KEX_SERVER_KEX, &o->kex_algorithms) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, + &o->hostkeyalgorithms) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, + &o->hostbased_key_types) != 0 || + kex_assemble_names(KEX_DEFAULT_PK_ALG, &o->pubkey_key_types) != 0) + fatal("kex_assemble_names failed"); ++ ++ filter_fips_algorithms_s(o); + } + + void + fill_default_server_options(ServerOptions *options) + { + int i; + + /* Portable-specific options */ + if (options->use_pam == -1) + options->use_pam = 0; + if (options->use_pam_check_locks == -1) + options->use_pam_check_locks = 0; + + if (options->kex_dhmin == -1) +- options->kex_dhmin = DH_GRP_MIN_RFC; ++ options->kex_dhmin = fips_dh_grp_min(); + else { +- options->kex_dhmin = MAX(options->kex_dhmin, DH_GRP_MIN_RFC); ++ options->kex_dhmin = MAX(options->kex_dhmin, ++ fips_mode() ? DH_GRP_MIN_FIPS : DH_GRP_MIN_RFC); + options->kex_dhmin = MIN(options->kex_dhmin, DH_GRP_MAX); + } + dh_grp_min = options->kex_dhmin; + /* Standard Options */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_2; + if (options->num_host_key_files == 0) { + /* fill default hostkeys for protocols */ +@@ -363,16 +384,18 @@ fill_default_server_options(ServerOption + if (options->version_addendum == NULL) + options->version_addendum = xstrdup(""); + 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) + options->fwd_opts.streamlocal_bind_unlink = 0; + if (options->fingerprint_hash == -1) + options->fingerprint_hash = SSH_FP_HASH_DEFAULT; ++ options->fingerprint_hash = ++ fips_correct_dgst(options->fingerprint_hash); + + assemble_algorithms(options); + + /* Turn privilege separation and sandboxing on by default */ + if (use_privsep == -1) + use_privsep = PRIVSEP_ON; + + #define CLEAR_ON_NONE(v) \ +@@ -980,17 +1003,17 @@ static const struct multistate multistat + { NULL, -1 } + }; + + int + process_server_config_line(ServerOptions *options, char *line, + const char *filename, int linenum, int *activep, + struct connection_info *connectinfo) + { +- char *cp, **charptr, *arg, *p; ++ char *cp, **charptr, *arg, *p, *tmp; + int cmdline = 0, *intptr, value, value2, n, port; + SyslogFacility *log_facility_ptr; + LogLevel *log_level_ptr; + ServerOpCodes opcode; + u_int i, flags = 0; + size_t len; + long long val64; + const struct multistate *multistate_ptr; +@@ -1465,44 +1488,72 @@ process_server_config_line(ServerOptions + xstrdup(arg); + } + break; + + case sCiphers: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); +- if (!ciphers_valid(*arg == '+' ? arg + 1 : arg)) ++ tmp = xstrdup(arg); ++ if (fips_mode()) { ++ if(!fips_filter_crypto(&tmp, FIPS_FILTER_CIPHERS)) ++ error("All ciphers were rejected " ++ "by the FIPS filter: '%s'.", arg); ++ } ++ if (!ciphers_valid(*tmp == '+' ? tmp + 1 : tmp)) + fatal("%s line %d: Bad SSH2 cipher spec '%s'.", + filename, linenum, arg ? arg : ""); + if (options->ciphers == NULL) +- options->ciphers = xstrdup(arg); ++ options->ciphers = tmp; ++ else ++ free(tmp); + break; + + case sMacs: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); +- if (!mac_valid(*arg == '+' ? arg + 1 : arg)) ++ tmp = xstrdup(arg); ++ if (fips_mode()) { ++ if(!fips_filter_crypto(&tmp, FIPS_FILTER_MACS)) ++ error("All ciphers were rejected " ++ "by the FIPS filter: '%s'.", arg); ++ } ++ if (!mac_valid(*tmp == '+' ? tmp + 1 : tmp)) ++ /* print the original line including any algorithms ++ * dropped by the FIPS filter */ + fatal("%s line %d: Bad SSH2 mac spec '%s'.", + filename, linenum, arg ? arg : ""); + if (options->macs == NULL) +- options->macs = xstrdup(arg); ++ options->macs = tmp; ++ else ++ free(tmp); + break; + + case sKexAlgorithms: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", + filename, linenum); +- if (!kex_names_valid(*arg == '+' ? arg + 1 : arg)) ++ tmp = xstrdup(arg); ++ if (fips_mode()) { ++ if(!fips_filter_crypto(&tmp, FIPS_FILTER_KEX_ALGS)) ++ error("All ciphers were rejected " ++ "by the FIPS filter: '%s'.", arg); ++ } ++ if (!kex_names_valid(*tmp == '+' ? tmp + 1 : tmp)) ++ /* print the original line including any algorithms ++ * dropped by the FIPS filter */ + fatal("%s line %d: Bad SSH2 KexAlgorithms '%s'.", + filename, linenum, arg ? arg : ""); + if (options->kex_algorithms == NULL) +- options->kex_algorithms = xstrdup(arg); ++ options->kex_algorithms = tmp; ++ else ++ free(tmp); + break; + + case sKexDHMin: + intptr = &options->kex_dhmin; + goto parse_int; + + case sProtocol: + intptr = &options->protocol; +diff --git a/openssh-7.2p2/ssh-keygen.c b/openssh-7.2p2/ssh-keygen.c +--- a/openssh-7.2p2/ssh-keygen.c ++++ b/openssh-7.2p2/ssh-keygen.c +@@ -53,16 +53,18 @@ + #include "ssh.h" + #include "ssh2.h" + #include "ssherr.h" + #include "ssh-pkcs11.h" + #include "atomicio.h" + #include "krl.h" + #include "digest.h" + ++#include "fips.h" ++ + #ifdef WITH_OPENSSL + # define DEFAULT_KEY_TYPE_NAME "rsa" + #else + # define DEFAULT_KEY_TYPE_NAME "ed25519" + #endif + + /* Number of bits in the RSA/DSA key. This value can be set on the command line. */ + #define DEFAULT_BITS 2048 +@@ -965,42 +967,61 @@ do_fingerprint(struct passwd *pw) + if (invalid) + fatal("%s is not a public key file.", path); + exit(0); + } + + static void + do_gen_all_hostkeys(struct passwd *pw) + { +- struct { ++ struct Key_types { + char *key_type; + char *key_type_display; + char *path; +- } key_types[] = { ++ }; ++ ++ struct Key_types key_types_all[] = { + #ifdef WITH_OPENSSL + #ifdef WITH_SSH1 + { "rsa1", "RSA1", _PATH_HOST_KEY_FILE }, + #endif /* WITH_SSH1 */ + { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, + { "dsa", "DSA", _PATH_HOST_DSA_KEY_FILE }, + #ifdef OPENSSL_HAS_ECC + { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, + #endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ + { "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE }, + { NULL, NULL, NULL } + }; + ++ struct Key_types key_types_fips140_2[] = { ++#ifdef WITH_OPENSSL ++ { "rsa", "RSA" ,_PATH_HOST_RSA_KEY_FILE }, ++#ifdef OPENSSL_HAS_ECC ++ { "ecdsa", "ECDSA",_PATH_HOST_ECDSA_KEY_FILE }, ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ { NULL, NULL, NULL } ++ }; ++ ++ struct Key_types *key_types; + int first = 0; + struct stat st; + struct sshkey *private, *public; + char comment[1024]; + int i, type, fd, r; + FILE *f; + ++ if (fips_mode()) { ++ key_types = key_types_fips140_2; ++ } else { ++ key_types = key_types_all; ++ } ++ + for (i = 0; key_types[i].key_type; i++) { + if (stat(key_types[i].path, &st) == 0) + continue; + if (errno != ENOENT) { + error("Could not stat %s: %s", key_types[i].path, + strerror(errno)); + first = 0; + continue; +@@ -2610,16 +2631,23 @@ main(int argc, char **argv) + do_gen_all_hostkeys(pw); + return (0); + } + + if (key_type_name == NULL) + key_type_name = DEFAULT_KEY_TYPE_NAME; + + type = sshkey_type_from_name(key_type_name); ++ ++ /* protocol v1 is not allowed in FIPS mode, DSA is not acceptable because ++ * it has to be 1024 bit due to RFC 4253 using SHA-1 which implies 1024 bit ++ * keys due to FIPS-186 specification for DSS */ ++ if (fips_mode() && (type == KEY_RSA1 || type == KEY_DSA)) ++ fatal("Key type %s not alowed in FIPS mode", key_type_name); ++ + type_bits_valid(type, key_type_name, &bits); + + if (!quiet) + printf("Generating public/private %s key pair.\n", + key_type_name); + if ((r = sshkey_generate(type, bits, &private)) != 0) + fatal("key_generate failed"); + if ((r = sshkey_from_private(private, &public)) != 0) +diff --git a/openssh-7.2p2/ssh.c b/openssh-7.2p2/ssh.c +--- a/openssh-7.2p2/ssh.c ++++ b/openssh-7.2p2/ssh.c +@@ -104,16 +104,18 @@ + #include "sshpty.h" + #include "match.h" + #include "msg.h" + #include "uidswap.h" + #include "version.h" + #include "ssherr.h" + #include "myproposal.h" + ++#include "fips.h" ++ + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" + #endif + + extern char *__progname; + + /* Saves a copy of argv for setproctitle emulation */ + #ifndef HAVE_SETPROCTITLE +@@ -604,16 +606,18 @@ main(int ac, char **av) + logfile = NULL; + argv0 = av[0]; + + again: + while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" + "ACD:E:F:GI: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': + options.protocol = SSH_PROTO_2; + break; + case '4': + options.address_family = AF_INET; + break; +@@ -1073,16 +1077,22 @@ main(int ac, char **av) + */ + if (addrs != NULL && options.port > 0) + set_addrinfo_port(addrs, options.port); + } + + /* Fill configuration defaults. */ + fill_default_options(&options); + ++ if (fips_mode()) { ++ options.protocol &= SSH_PROTO_2; ++ if (options.protocol == 0) ++ fatal("Protocol 2 disabled by configuration but required in the FIPS mode"); ++ } ++ + if (options.port == 0) + options.port = default_ssh_port(); + channel_set_af(options.address_family); + + /* Tidy and check options */ + if (options.host_key_alias != NULL) + lowercase(options.host_key_alias); + if (options.proxy_command != NULL && +diff --git a/openssh-7.2p2/ssh_config.0 b/openssh-7.2p2/ssh_config.0 +--- a/openssh-7.2p2/ssh_config.0 ++++ b/openssh-7.2p2/ssh_config.0 +@@ -376,16 +376,18 @@ DESCRIPTION + ultimate forwarding destination fail. The argument must be M-bM-^@M-^\yesM-bM-^@M-^] + or M-bM-^@M-^\noM-bM-^@M-^]. The default is M-bM-^@M-^\noM-bM-^@M-^]. + + FingerprintHash + Specifies the hash algorithm used when displaying key + fingerprints. Valid options are: M-bM-^@M-^\md5M-bM-^@M-^] and M-bM-^@M-^\sha256M-bM-^@M-^]. The + default is M-bM-^@M-^\sha256M-bM-^@M-^]. + ++ In the FIPS mode the minimum of SHA-1 is enforced. ++ + ForwardAgent + Specifies whether the connection to the authentication agent (if + any) will be forwarded to the remote machine. The argument must + be M-bM-^@M-^\yesM-bM-^@M-^] or M-bM-^@M-^\noM-bM-^@M-^]. The default is M-bM-^@M-^\noM-bM-^@M-^]. + + Agent forwarding should be enabled with caution. Users with the + ability to bypass file permissions on the remote host (for the + agent's Unix-domain socket) can access the local agent through +@@ -623,16 +625,19 @@ DESCRIPTION + only know short DH group parameters. + + Note, that while by default this option is set to 1024 to maintain + maximum backward compatibility, using it can severly impact + security and thus should be viewed as a temporary fix of last + resort and all efforts should be made to fix the (broken) + counterparty. + ++ In the FIPS mode the FIPS standard takes precedence over RFC and ++ forces the minimum to a higher value, currently 2048 bits. ++ + LocalCommand + Specifies a command to execute on the local machine after + successfully connecting to the server. The command string + extends to the end of the line, and is executed with the user's + shell. The following escape character substitutions will be + performed: M-bM-^@M-^X%dM-bM-^@M-^Y (local user's home directory), M-bM-^@M-^X%hM-bM-^@M-^Y (remote host + name), M-bM-^@M-^X%lM-bM-^@M-^Y (local host name), M-bM-^@M-^X%nM-bM-^@M-^Y (host name as provided on the + command line), M-bM-^@M-^X%pM-bM-^@M-^Y (remote port), M-bM-^@M-^X%rM-bM-^@M-^Y (remote user name) or +diff --git a/openssh-7.2p2/ssh_config.5 b/openssh-7.2p2/ssh_config.5 +--- a/openssh-7.2p2/ssh_config.5 ++++ b/openssh-7.2p2/ssh_config.5 +@@ -727,16 +727,18 @@ The default is + .It Cm FingerprintHash + Specifies the hash algorithm used when displaying key fingerprints. + Valid options are: + .Dq md5 + and + .Dq sha256 . + The default is + .Dq sha256 . ++.Pp ++In the FIPS mode the minimum of SHA-1 is enforced. + .It Cm ForwardAgent + Specifies whether the connection to the authentication agent (if any) + will be forwarded to the remote machine. + The argument must be + .Dq yes + or + .Dq no . + The default is +@@ -1108,16 +1110,19 @@ than the current minimum, down to the RF + Using this option may be needed when connecting to servers that + only know short DH group parameters. + .Pp + Note, that while by default this option is set to 1024 to maintain + maximum backward compatibility, using it can severly impact + security and thus should be viewed as a temporary fix of last + resort and all efforts should be made to fix the (broken) + counterparty. ++.Pp ++In the FIPS mode the FIPS standard takes precedence over RFC and ++forces the minimum to a higher value, currently 2048 bits. + .It Cm LocalCommand + Specifies a command to execute on the local machine after successfully + connecting to the server. + The command string extends to the end of the line, and is executed with + the user's shell. + The following escape character substitutions will be performed: + .Ql %d + (local user's home directory), +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -120,16 +120,18 @@ + #ifdef GSSAPI + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" + ++#include "fips.h" ++ + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif + + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) + #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) + #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) +@@ -1824,16 +1826,20 @@ main(int ac, char **av) + if ((fp = sshkey_fingerprint(pubkey, options.fingerprint_hash, + SSH_FP_DEFAULT)) == NULL) + fatal("sshkey_fingerprint failed"); + debug("%s host key #%d: %s %s", + key ? "private" : "agent", i, keytype == KEY_RSA1 ? + sshkey_type(pubkey) : sshkey_ssh_name(pubkey), fp); + free(fp); + } ++ 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; + } + 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; + } +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -344,16 +344,18 @@ DESCRIPTION + AllowUsers, DenyGroups, and finally AllowGroups. + + See PATTERNS in ssh_config(5) for more information on patterns. + + FingerprintHash + Specifies the hash algorithm used when logging key fingerprints. + Valid options are: M-bM-^@M-^\md5M-bM-^@M-^] and M-bM-^@M-^\sha256M-bM-^@M-^]. The default is M-bM-^@M-^\sha256M-bM-^@M-^]. + ++ In the FIPS mode the minimum of SHA-1 is enforced. ++ + ForceCommand + Forces the execution of the command specified by ForceCommand, + ignoring any command supplied by the client and ~/.ssh/rc if + present. The command is invoked by using the user's login shell + with the -c option. This applies to shell, command, or subsystem + execution. It is most useful inside a Match block. The command + originally supplied by the client is available in the + SSH_ORIGINAL_COMMAND environment variable. Specifying a command +@@ -556,16 +558,19 @@ DESCRIPTION + clients only know short DH group parameters. + + Note, that while by default this option is set to 1024 to maintain + maximum backward compatibility, using it can severly impact + security and thus should be viewed as a temporary fix of last + resort and all efforts should be made to fix the (broken) + counterparty. + ++ In the FIPS mode the FIPS standard takes precedence over RFC and ++ forces the minimum to a higher value, currently 2048 bits. ++ + KeyRegenerationInterval + In protocol version 1, the ephemeral server key is automatically + regenerated after this many seconds (if it has been used). The + purpose of regeneration is to prevent decrypting captured + sessions by later breaking into the machine and stealing the + keys. The key is never stored anywhere. If the value is 0, the + key is never regenerated. The default is 3600 (seconds). + +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -572,16 +572,18 @@ for more information on patterns. + .It Cm FingerprintHash + Specifies the hash algorithm used when logging key fingerprints. + Valid options are: + .Dq md5 + and + .Dq sha256 . + The default is + .Dq sha256 . ++.Pp ++In the FIPS mode the minimum of SHA-1 is enforced. + .It Cm ForceCommand + Forces the execution of the command specified by + .Cm ForceCommand , + ignoring any command supplied by the client and + .Pa ~/.ssh/rc + if present. + The command is invoked by using the user's login shell with the -c option. + This applies to shell, command, or subsystem execution. +@@ -911,16 +913,19 @@ than the current minimum, down to the RF + Using this option may be needed when some of the connectiong + clients only know short DH group parameters. + .Pp + Note, that while by default this option is set to 1024 to maintain + maximum backward compatibility, using it can severly impact + security and thus should be viewed as a temporary fix of last + resort and all efforts should be made to fix the (broken) + counterparty. ++.Pp ++In the FIPS mode the FIPS standard takes precedence over RFC and ++forces the minimum to a higher value, currently 2048 bits. + .It Cm KeyRegenerationInterval + In protocol version 1, the ephemeral server key is automatically regenerated + after this many seconds (if it has been used). + The purpose of regeneration is to prevent + decrypting captured sessions by later breaking into the machine and + stealing the keys. + The key is never stored anywhere. + If the value is 0, the key is never regenerated. diff --git a/openssh-7.2p2-fips_fixes.patch b/openssh-7.2p2-fips_fixes.patch new file mode 100644 index 0000000..1b5f924 --- /dev/null +++ b/openssh-7.2p2-fips_fixes.patch @@ -0,0 +1,31 @@ +# HG changeset patch +# Parent cb502e7e796ac9289a571167a97ad9ec91562efb +Silent warnings about unsupported KEX algorithms - synchronize behaviour with +that of MAC and cipher checking code paths. + +bsc#1006166 + +diff --git a/openssh-7.2p2/kex.c b/openssh-7.2p2/kex.c +--- a/openssh-7.2p2/kex.c ++++ b/openssh-7.2p2/kex.c +@@ -192,17 +192,20 @@ kex_names_valid(const char *names) + + if (names == NULL || strcmp(names, "") == 0) + return 0; + if ((s = cp = strdup(names)) == NULL) + return 0; + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (kex_alg_by_name(p) == NULL) { ++ /* do not complain here - MACs and ciphers checks ++ * are silent here + error("Unsupported KEX algorithm \"%.100s\"", p); ++ */ + free(s); + return 0; + } + } + debug3("kex names ok: [%s]", names); + free(s); + return 1; + } diff --git a/openssh-7.2p2-gssapi_key_exchange.patch b/openssh-7.2p2-gssapi_key_exchange.patch new file mode 100644 index 0000000..ebefacb --- /dev/null +++ b/openssh-7.2p2-gssapi_key_exchange.patch @@ -0,0 +1,3963 @@ +# HG changeset patch +# Parent df12d82287e3434a52c21a994b901302bd0c8064 +GSSAPI Key Exchange implementation + +diff --git a/openssh-7.2p2/ChangeLog.gssapi b/openssh-7.2p2/ChangeLog.gssapi +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ChangeLog.gssapi +@@ -0,0 +1,113 @@ ++20110101 ++ - Finally update for OpenSSH 5.6p1 ++ - Add GSSAPIServerIdentity option from Jim Basney ++ ++20100308 ++ - [ Makefile.in, key.c, key.h ] ++ Updates for OpenSSH 5.4p1 ++ - [ servconf.c ] ++ Include GSSAPI options in the sshd -T configuration dump, and flag ++ some older configuration options as being unsupported. Thanks to Colin ++ Watson. ++ - ++ ++20100124 ++ - [ sshconnect2.c ] ++ Adapt to deal with additional element in Authmethod structure. Thanks to ++ Colin Watson ++ ++20090615 ++ - [ gss-genr.c gss-serv.c kexgssc.c kexgsss.c monitor.c sshconnect2.c ++ sshd.c ] ++ Fix issues identified by Greg Hudson following a code review ++ Check return value of gss_indicate_mechs ++ Protect GSSAPI calls in monitor, so they can only be used if enabled ++ Check return values of bignum functions in key exchange ++ Use BN_clear_free to clear other side's DH value ++ Make ssh_gssapi_id_kex more robust ++ Only configure kex table pointers if GSSAPI is enabled ++ Don't leak mechanism list, or gss mechanism list ++ Cast data.length before printing ++ If serverkey isn't provided, use an empty string, rather than NULL ++ ++20090201 ++ - [ gss-genr.c gss-serv.c kex.h kexgssc.c readconf.c readconf.h ssh-gss.h ++ ssh_config.5 sshconnet2.c ] ++ Add support for the GSSAPIClientIdentity option, which allows the user ++ to specify which GSSAPI identity to use to contact a given server ++ ++20080404 ++ - [ gss-serv.c ] ++ Add code to actually implement GSSAPIStrictAcceptCheck, which had somehow ++ been omitted from a previous version of this patch. Reported by Borislav ++ Stoichkov ++ ++20070317 ++ - [ gss-serv-krb5.c ] ++ Remove C99ism, where new_ccname was being declared in the middle of a ++ function ++ ++20061220 ++ - [ servconf.c ] ++ Make default for GSSAPIStrictAcceptorCheck be Yes, to match previous, and ++ documented, behaviour. Reported by Dan Watson. ++ ++20060910 ++ - [ gss-genr.c kexgssc.c kexgsss.c kex.h monitor.c sshconnect2.c sshd.c ++ ssh-gss.h ] ++ add support for gss-group14-sha1 key exchange mechanisms ++ - [ gss-serv.c servconf.c servconf.h sshd_config sshd_config.5 ] ++ Add GSSAPIStrictAcceptorCheck option to allow the disabling of ++ acceptor principal checking on multi-homed machines. ++ ++ - [ sshd_config ssh_config ] ++ Add settings for GSSAPIKeyExchange and GSSAPITrustDNS to the sample ++ configuration files ++ - [ kexgss.c kegsss.c sshconnect2.c sshd.c ] ++ Code cleanup. Replace strlen/xmalloc/snprintf sequences with xasprintf() ++ Limit length of error messages displayed by client ++ ++20060909 ++ - [ gss-genr.c gss-serv.c ] ++ move ssh_gssapi_acquire_cred() and ssh_gssapi_server_ctx to be server ++ only, where they belong ++ ++ ++20060829 ++ - [ gss-serv-krb5.c ] ++ Fix CCAPI credentials cache name when creating KRB5CCNAME environment ++ variable ++ ++20060828 ++ - [ gss-genr.c ] ++ Avoid Heimdal context freeing problem ++ ++ ++20060818 ++ - [ gss-genr.c ssh-gss.h sshconnect2.c ] ++ Make sure that SPENGO is disabled ++ ++ ++20060421 ++ - [ gssgenr.c, sshconnect2.c ] ++ a few type changes (signed versus unsigned, int versus size_t) to ++ fix compiler errors/warnings ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ kexgssc.c, sshconnect2.c ] ++ fix uninitialized variable warnings ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ gssgenr.c ] ++ pass oid to gss_display_status (helpful when using GSSAPI mechglue) ++ (from jbasney AT ncsa.uiuc.edu) ++ ++ - [ gss-serv-krb5.c ] ++ #ifdef HAVE_GSSAPI_KRB5 should be #ifdef HAVE_GSSAPI_KRB5_H ++ (from jbasney AT ncsa.uiuc.edu) ++ ++ - [ readconf.c, readconf.h, ssh_config.5, sshconnect2.c ++ add client-side GssapiKeyExchange option ++ (from jbasney AT ncsa.uiuc.edu) ++ - [ sshconnect2.c ] ++ add support for GssapiTrustDns option for gssapi-with-mic ++ (from jbasney AT ncsa.uiuc.edu) ++ +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -89,18 +89,18 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + atomicio.o key.o dispatch.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 \ + 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 \ + ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \ + 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 \ ++ kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o kexgssc.o \ ++ kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o kexgsss.o \ + platform-pledge.o + + LIBSSH_OBJS += fips.o + + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ + sshconnect.o sshconnect1.o sshconnect2.o mux.o + + SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \ +diff --git a/openssh-7.2p2/auth-krb5.c b/openssh-7.2p2/auth-krb5.c +--- a/openssh-7.2p2/auth-krb5.c ++++ b/openssh-7.2p2/auth-krb5.c +@@ -178,18 +178,23 @@ auth_krb5_password(Authctxt *authctxt, c + if (problem) + goto out; + #endif + + authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + + len = strlen(authctxt->krb5_ticket_file) + 6; + authctxt->krb5_ccname = xmalloc(len); ++#ifdef USE_CCAPI ++ snprintf(authctxt->krb5_ccname, len, "API:%s", ++ authctxt->krb5_ticket_file); ++#else + snprintf(authctxt->krb5_ccname, len, "FILE:%s", + authctxt->krb5_ticket_file); ++#endif + + #ifdef USE_PAM + if (options.use_pam) + do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); + #endif + + out: + restore_uid(); +@@ -239,35 +244,42 @@ krb5_cleanup_proc(Authctxt *authctxt) + } + + #ifndef HEIMDAL + krb5_error_code + ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { + int tmpfd, ret, oerrno; + char ccname[40]; + mode_t old_umask; ++#ifdef USE_CCAPI ++ char cctemplate[] = "API:krb5cc_%d"; ++#else ++ char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX"; ++#endif + + ret = snprintf(ccname, sizeof(ccname), +- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); ++ cctemplate, geteuid()); + if (ret < 0 || (size_t)ret >= sizeof(ccname)) + return ENOMEM; + ++#ifndef USE_CCAPI + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); + oerrno = errno; + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(oerrno)); + return oerrno; + } + + if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + oerrno = errno; + logit("fchmod(): %.100s", strerror(oerrno)); + close(tmpfd); + return oerrno; + } + close(tmpfd); ++#endif + + return (krb5_cc_resolve(ctx, ccname, ccache)); + } + #endif /* !HEIMDAL */ + #endif /* KRB5 */ +diff --git a/openssh-7.2p2/auth2-gss.c b/openssh-7.2p2/auth2-gss.c +--- a/openssh-7.2p2/auth2-gss.c ++++ b/openssh-7.2p2/auth2-gss.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: auth2-gss.c,v 1.22 2015/01/19 20:07:45 markus Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 +@@ -48,16 +48,50 @@ + + extern ServerOptions options; + + static int input_gssapi_token(int type, u_int32_t plen, void *ctxt); + static int input_gssapi_mic(int type, u_int32_t plen, void *ctxt); + 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) + */ + static int + userauth_gssapi(Authctxt *authctxt) + { + gss_OID_desc goid = {0, NULL}; +@@ -233,17 +267,18 @@ input_gssapi_exchange_complete(int type, + + /* + * We don't need to check the status, because we're only enabled in + * the dispatcher once the exchange is complete + */ + + 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); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); + userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); + return 0; +@@ -269,31 +304,38 @@ input_gssapi_mic(int type, u_int32_t ple + + ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, + "gssapi-with-mic"); + + gssbuf.value = buffer_ptr(&b); + 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"); + + buffer_free(&b); + free(mic.value); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); + userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL); + return 0; + } + ++Authmethod method_gsskeyex = { ++ "gssapi-keyex", ++ userauth_gsskeyex, ++ &options.gss_authentication ++}; ++ + Authmethod method_gssapi = { + "gssapi-with-mic", + userauth_gssapi, + &options.gss_authentication + }; + + #endif /* GSSAPI */ +diff --git a/openssh-7.2p2/auth2.c b/openssh-7.2p2/auth2.c +--- a/openssh-7.2p2/auth2.c ++++ b/openssh-7.2p2/auth2.c +@@ -65,23 +65,25 @@ extern Buffer loginmsg; + /* methods */ + + extern Authmethod method_none; + extern Authmethod method_pubkey; + extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif + + Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + &method_passwd, + &method_kbdint, + &method_hostbased, + NULL + }; + +diff --git a/openssh-7.2p2/clientloop.c b/openssh-7.2p2/clientloop.c +--- a/openssh-7.2p2/clientloop.c ++++ b/openssh-7.2p2/clientloop.c +@@ -109,16 +109,20 @@ + #include "authfd.h" + #include "atomicio.h" + #include "sshpty.h" + #include "match.h" + #include "msg.h" + #include "ssherr.h" + #include "hostfile.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + /* import options */ + extern Options options; + + /* Flag indicating that stdin should be redirected from /dev/null. */ + extern int stdin_null_flag; + + /* Flag indicating that no shell has been requested */ + extern int no_shell_flag; +@@ -1657,19 +1661,28 @@ client_loop(int have_pty, int escape_cha + max_fd2 = max_fd; + client_wait_until_can_do_something(&readset, &writeset, + &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state)); + + if (quit_pending) + 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((Gssctxt *)NULL)) { ++ debug("credentials updated - forcing rekey"); ++ need_rekeying = 1; ++ } ++#endif ++ } ++ + /* Buffer input from the connection. */ + client_process_net_input(readset); + + if (quit_pending) + break; + + if (!compat20) { + /* Buffer data from stdin */ +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -627,16 +627,40 @@ main() { if (NSVersionOfRunTimeLibrary(" + AC_DEFINE([BROKEN_GLOB], [1], [OS X glob does not do what we expect]) + AC_DEFINE_UNQUOTED([BIND_8_COMPAT], [1], + [Define if your resolver libs need this for getrrsetbyname]) + AC_DEFINE([SSH_TUN_FREEBSD], [1], [Open tunnel devices the FreeBSD way]) + AC_DEFINE([SSH_TUN_COMPAT_AF], [1], + [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]) + [#include ] + AC_DEFINE([LASTLOG_WRITE_PUTUTXLINE], [1], + [Define if pututxline updates lastlog too]) + ) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV], +diff --git a/openssh-7.2p2/gss-genr.c b/openssh-7.2p2/gss-genr.c +--- a/openssh-7.2p2/gss-genr.c ++++ b/openssh-7.2p2/gss-genr.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: gss-genr.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */ + + /* +- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 +@@ -36,22 +36,177 @@ + #include + #include + #include + + #include "xmalloc.h" + #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) + { + return (ctx != NULL && ctx->oid != GSS_C_NO_OID && + ctx->oid->length == len && + memcmp(ctx->oid->elements, data, len) == 0); + } +@@ -194,17 +349,17 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de + int deleg_flag = 0; + + if (deleg_creds) { + deleg_flag = GSS_C_DELEG_FLAG; + debug("Delegating credentials"); + } + + 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); + + if (GSS_ERROR(ctx->major)) + ssh_gssapi_error(ctx); + + return (ctx->major); + } +@@ -224,60 +379,175 @@ ssh_gssapi_import_name(Gssctxt *ctx, con + &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) + ssh_gssapi_error(ctx); + + free(gssbuf.value); + return (ctx->major); + } + + OM_uint32 ++ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) ++{ ++ gss_buffer_desc gssbuf; ++ gss_name_t gssname; ++ OM_uint32 status; ++ gss_OID_set oidset; ++ ++ gssbuf.value = (void *) name; ++ gssbuf.length = strlen(gssbuf.value); ++ ++ gss_create_empty_oid_set(&status, &oidset); ++ gss_add_oid_set_member(&status, ctx->oid, &oidset); ++ ++ ctx->major = gss_import_name(&ctx->minor, &gssbuf, ++ GSS_C_NT_USER_NAME, &gssname); ++ ++ if (!ctx->major) ++ ctx->major = gss_acquire_cred(&ctx->minor, ++ gssname, 0, oidset, GSS_C_INITIATE, ++ &ctx->client_creds, NULL, NULL); ++ ++ gss_release_name(&status, &gssname); ++ gss_release_oid_set(&status, &oidset); ++ ++ if (ctx->major) ++ ssh_gssapi_error(ctx); ++ ++ return(ctx->major); ++} ++ ++OM_uint32 + ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) + { ++ if (ctx == NULL) ++ return -1; ++ + if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, + GSS_C_QOP_DEFAULT, buffer, hash))) + ssh_gssapi_error(ctx); + + 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) + { + buffer_init(b); + buffer_put_string(b, session_id2, session_id2_len); + buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(b, user); + buffer_put_cstring(b, service); + buffer_put_cstring(b, context); + } + + 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 && + (memcmp(oid->elements, spnego_oid.elements, oid->length) == 0)) + return 0; /* false */ + + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx, oid); + major = ssh_gssapi_import_name(*ctx, host); ++ ++ if (!GSS_ERROR(major) && client) ++ major = ssh_gssapi_client_identity(*ctx, client); ++ + if (!GSS_ERROR(major)) { + major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, + NULL); + gss_release_buffer(&minor, &token); + if ((*ctx)->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&minor, &(*ctx)->context, + 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; ++ /* TODO: recheck ++ 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/openssh-7.2p2/gss-serv-krb5.c b/openssh-7.2p2/gss-serv-krb5.c +--- a/openssh-7.2p2/gss-serv-krb5.c ++++ b/openssh-7.2p2/gss-serv-krb5.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: gss-serv-krb5.c,v 1.8 2013/07/20 01:55:13 djm Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * 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 +@@ -116,18 +116,21 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client + + static void + ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) + { + krb5_ccache ccache; + krb5_error_code problem; + krb5_principal princ; + OM_uint32 maj_status, min_status; ++ /* TODO: + int len; ++ */ + const char *errmsg; ++ const char *new_ccname; + + if (client->creds == NULL) { + debug("No credentials stored"); + return; + } + + if (ssh_gssapi_krb5_init() == 0) + return; +@@ -176,37 +179,108 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + + if ((maj_status = gss_krb5_copy_ccache(&min_status, + client->creds, ccache))) { + logit("gss_krb5_copy_ccache() failed"); + krb5_cc_destroy(krb_context, ccache); + return; + } + +- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); ++ new_ccname = krb5_cc_get_name(krb_context, ccache); ++ + client->store.envvar = "KRB5CCNAME"; +- len = strlen(client->store.filename) + 6; +- client->store.envval = xmalloc(len); +- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); ++#ifdef USE_CCAPI ++ xasprintf(&client->store.envval, "API:%s", new_ccname); ++ client->store.filename = NULL; ++#else ++ xasprintf(&client->store.envval, "FILE:%s", new_ccname); ++ client->store.filename = xstrdup(new_ccname); ++#endif + + #ifdef USE_PAM + if (options.use_pam) + do_pam_putenv(client->store.envvar, client->store.envval); + #endif + + krb5_cc_close(krb_context, ccache); + + 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", + {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, + NULL, + &ssh_gssapi_krb5_userok, + NULL, +- &ssh_gssapi_krb5_storecreds ++ &ssh_gssapi_krb5_storecreds, ++ &ssh_gssapi_krb5_updatecreds + }; + + #endif /* KRB5 */ + + #endif /* GSSAPI */ +diff --git a/openssh-7.2p2/gss-serv.c b/openssh-7.2p2/gss-serv.c +--- a/openssh-7.2p2/gss-serv.c ++++ b/openssh-7.2p2/gss-serv.c +@@ -1,12 +1,12 @@ + /* $OpenBSD: gss-serv.c,v 1.29 2015/05/22 03:50:02 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 + * 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 +@@ -40,27 +40,29 @@ + #include "key.h" + #include "hostfile.h" + #include "auth.h" + #include "log.h" + #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, 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; + #endif + + ssh_gssapi_mech* supported_mechs[]= { + #ifdef KRB5 + &gssapi_kerberos_mech, +@@ -137,26 +139,51 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss + if (*ctx) + ssh_gssapi_delete_ctx(ctx); + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx, oid); + return (ssh_gssapi_acquire_cred(*ctx)); + } + + /* 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) + { + int i = 0; + OM_uint32 min_status; + int present; + 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, + &supported_mechs[i]->oid, supported, &present))) + present = 0; + if (present) + gss_add_oid_set_member(&min_status, + &supported_mechs[i]->oid, oidset); +@@ -272,32 +299,79 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss + /* Extract the client details from a given context. This can only reliably + * be called once for a context */ + + /* Privileged (called from accept_secure_ctx) */ + 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; + +- gss_buffer_desc ename; ++ if (options.gss_store_rekey && client->used && ctx->client_creds) { ++ if (client->mech->oid.length != ctx->oid->length || ++ (memcmp(client->mech->oid.elements, ++ ctx->oid->elements, ctx->oid->length) !=0)) { ++ debug("Rekeyed credentials have different mechanism"); ++ return GSS_S_COMPLETE; ++ } ++ ++ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &new_name, ++ NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ ctx->major = gss_compare_name(&ctx->minor, client->name, ++ new_name, &equal); ++ ++ if (GSS_ERROR(ctx->major)) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ if (!equal) { ++ debug("Rekeyed credentials have different name"); ++ return GSS_S_COMPLETE; ++ } ++ ++ debug("Marking rekeyed credentials for export"); ++ ++ gss_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; + + while (supported_mechs[i]->name != NULL) { + if (supported_mechs[i]->oid.length == ctx->oid->length && + (memcmp(supported_mechs[i]->oid.elements, + ctx->oid->elements, ctx->oid->length) == 0)) + client->mech = supported_mechs[i]; + i++; + } + + 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); + return (ctx->major); + } + + if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, + &ename))) { +@@ -305,16 +379,18 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + return (ctx->major); + } + + if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, + &client->exportedname))) { + 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; + return (ctx->major); + } + + /* As user - called on fatal/exit */ + void +@@ -352,45 +428,124 @@ ssh_gssapi_do_child(char ***envp, u_int + gssapi_client.store.envval); + child_set_env(envp, envsizep, gssapi_client.store.envvar, + gssapi_client.store.envval); + } + } + + /* Privileged */ + int +-ssh_gssapi_userok(char *user) ++ssh_gssapi_userok(char *user, struct passwd *pw) + { + OM_uint32 lmin; + + if (gssapi_client.exportedname.length == 0 || + gssapi_client.exportedname.value == NULL) { + debug("No suitable client data"); + return 0; + } + if (gssapi_client.mech && gssapi_client.mech->userok) +- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) ++ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { ++ gssapi_client.used = 1; ++ gssapi_client.store.owner = pw; + return 1; +- else { ++ } else { + /* Destroy delegated credentials if userok fails */ + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); + gss_release_cred(&lmin, &gssapi_client.creds); + explicit_bzero(&gssapi_client, + sizeof(ssh_gssapi_client)); + return 0; + } + else + debug("ssh_gssapi_userok: Unknown GSSAPI mechanism"); + 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 ++ ++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"); + +- return (ctx->major); ++ /* 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/openssh-7.2p2/kex.c b/openssh-7.2p2/kex.c +--- a/openssh-7.2p2/kex.c ++++ b/openssh-7.2p2/kex.c +@@ -51,16 +51,20 @@ + #include "monitor.h" + + #include "ssherr.h" + #include "sshbuf.h" + #include "digest.h" + + #include "fips.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= 0x00907000L + # if defined(HAVE_EVP_SHA256) + # define evp_ssh_sha256 EVP_sha256 + # else + extern const EVP_MD *evp_ssh_sha256(void); + # endif + #endif + +@@ -104,16 +108,21 @@ static const struct kexalg kexalgs_all[] + { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, + SSH_DIGEST_SHA512 }, + # endif /* OPENSSL_HAS_NISTP521 */ + #endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ + #if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL) + { KEX_CURVE25519_SHA256, 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}, + }; + + static const struct kexalg kexalgs_fips140_2[] = { + #ifdef WITH_OPENSSL + { 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 +@@ -125,16 +134,20 @@ static const struct kexalg kexalgs_fips1 + { 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 /* OPENSSL_HAS_NISTP521 */ + #endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ ++#ifdef GSSAPI ++ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++#endif + { NULL, -1, -1, -1}, + }; + + /* Returns array of macs available depending on selected FIPS mode */ + static const struct kexalg * + fips_select_kexalgs(void) + { + int fips = fips_mode(); +@@ -175,16 +188,22 @@ kex_alg_list(char sep) + static const struct kexalg * + kex_alg_by_name(const char *name) + { + const struct kexalg *k; + + for (k = fips_select_kexalgs(); k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; ++#ifdef GSSAPI ++ if (strncmp(name, "gss-", 4) == 0) { ++ if (strncmp(k->name, name, strlen(k->name)) == 0) ++ return k; ++ } ++#endif + } + return NULL; + } + + /* Validate KEX method name list */ + int + kex_names_valid(const char *names) + { +diff --git a/openssh-7.2p2/kex.h b/openssh-7.2p2/kex.h +--- a/openssh-7.2p2/kex.h ++++ b/openssh-7.2p2/kex.h +@@ -87,16 +87,19 @@ enum kex_modes { + + enum kex_exchange { + KEX_DH_GRP1_SHA1, + KEX_DH_GRP14_SHA1, + KEX_DH_GEX_SHA1, + KEX_DH_GEX_SHA256, + KEX_ECDH_SHA2, + KEX_C25519_SHA256, ++ KEX_GSS_GRP1_SHA1, ++ KEX_GSS_GRP14_SHA1, ++ KEX_GSS_GEX_SHA1, + KEX_MAX + }; + + #define KEX_INIT_SENT 0x0001 + + struct sshenc { + char *name; + const struct sshcipher *cipher; +@@ -135,16 +138,22 @@ struct kex { + int rsa_sha2; + int ext_info_c; + struct sshbuf *my; + struct sshbuf *peer; + sig_atomic_t done; + 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; + int (*verify_host_key)(struct sshkey *, struct ssh *); + struct sshkey *(*load_host_public_key)(int, int, struct ssh *); + struct sshkey *(*load_host_private_key)(int, int, struct ssh *); + int (*host_key_index)(struct sshkey *, int, struct ssh *); + int (*sign)(struct sshkey *, struct sshkey *, u_char **, size_t *, +@@ -184,16 +193,21 @@ int kex_start_rekex(struct ssh *); + int kexdh_client(struct ssh *); + int kexdh_server(struct ssh *); + int kexgex_client(struct ssh *); + int kexgex_server(struct ssh *); + 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(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 *); + + int kexgex_hash(int, const char *, const char *, + const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, + int, int, int, +diff --git a/openssh-7.2p2/kexgssc.c b/openssh-7.2p2/kexgssc.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/kexgssc.c +@@ -0,0 +1,368 @@ ++/* ++ * 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 "digest.h" ++#include "kex.h" ++#include "log.h" ++#include "packet.h" ++#include "dh.h" ++ ++#include "ssh-gss.h" ++ ++#include "fips.h" ++ ++int ++kexgss_client(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->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, strlen; ++ size_t hashlen; ++ BIGNUM *dh_server_pub = NULL; ++ BIGNUM *shared_secret = NULL; ++ BIGNUM *p = NULL; ++ BIGNUM *g = NULL; ++ u_char *kbuf; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ u_char *serverhostkey = NULL; ++ u_char *empty = ""; ++ char *msg; ++ /* TODO: ++ char *lang; ++ */ ++ int type = 0; ++ int first = 1; ++ int nbits = 0, min = fips_dh_grp_min(), max = DH_GRP_MAX; ++ int p_bitlen; ++ int r; ++ ++ /* Initialise our GSSAPI world */ ++ ssh_gssapi_build_ctx(&ctxt); ++ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) ++ == GSS_C_NO_OID) ++ fatal("Couldn't identify host exchange"); ++ ++ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(ctxt, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ kex->dh = dh_new_group1(); ++ break; ++ case KEX_GSS_GRP14_SHA1: ++ kex->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); ++ p_bitlen = BN_num_bits(p); ++ if ((g = BN_new()) == NULL) ++ fatal("BN_new() failed"); ++ packet_get_bignum2(g); ++ packet_check_eom(); ++ ++ if (p_bitlen < min || p_bitlen > max) { ++ if (p_bitlen < min && p_bitlen >= DH_GRP_MIN_RFC) ++ logit("DH parameter offered by the server (%d bits) " ++ "is considered insecure. " ++ "You can lower the accepted minimum " ++ "via the KexDHMin option.", ++ p_bitlen); ++ fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", ++ min, p_bitlen, max); ++ } ++ ++ kex->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(kex->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(kex->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); ++ /* TODO: ++ 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(kex->dh, dh_server_pub)) ++ packet_disconnect("bad server public DH value"); ++ ++ /* compute K=f^x mod p */ ++ klen = DH_size(kex->dh); ++ kbuf = xmalloc(klen); ++ kout = DH_compute_key(kbuf, dh_server_pub, kex->dh); ++ if (kout < 0) ++ fatal("DH_compute_key: failed"); ++ ++ shared_secret = BN_new(); ++ if (shared_secret == NULL) ++ fatal("kexgss_client: BN_new failed"); ++ ++ if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) ++ fatal("kexdh_client: BN_bin2bn failed"); ++ ++ memset(kbuf, 0, klen); ++ free(kbuf); ++ ++ 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, ++ kex->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, ++ kex->dh->p, kex->dh->g, ++ kex->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); ++ ++ 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); ++ ++ if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++/* TODO: ++out: ++*/ ++ explicit_bzero(hash, sizeof(hash)); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ if (dh_server_pub) ++ BN_clear_free(dh_server_pub); ++ if (kbuf) { ++ explicit_bzero(kbuf, klen); ++ free(kbuf); ++ } ++ if (shared_secret) ++ BN_clear_free(shared_secret); ++ /* any errors should have finished as fatal */ ++ return r; ++} ++ ++#endif /* GSSAPI */ +diff --git a/openssh-7.2p2/kexgsss.c b/openssh-7.2p2/kexgsss.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/kexgsss.c +@@ -0,0 +1,317 @@ ++/* ++ * 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 "digest.h" ++#include "kex.h" ++#include "log.h" ++#include "packet.h" ++#include "dh.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "servconf.h" ++ ++#include "fips.h" ++ ++extern ServerOptions options; ++ ++void ssh_gssapi_rekey_creds(); ++ ++int ++kexgss_server(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ OM_uint32 maj_status, min_status; ++ ++ /* ++ * Some GSSAPI implementations use the input value of ret_flags (an ++ * output variable) as a means of triggering mechanism specific ++ * features. Initializing it to zero avoids inadvertently ++ * activating this non-standard behaviour. ++ */ ++ ++ OM_uint32 ret_flags = 0; ++ gss_buffer_desc gssbuf, recv_tok, msg_tok; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ Gssctxt *ctxt = NULL; ++ u_int slen, klen, kout; ++ size_t hashlen; ++ u_char *kbuf; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ int min = -1, max = -1, nbits = -1; ++ BIGNUM *shared_secret = NULL; ++ BIGNUM *dh_client_pub = NULL; ++ int type = 0; ++ gss_OID oid; ++ char *mechs; ++ int r; ++ ++ /* Initialise GSSAPI */ ++ ++ /* If we're rekeying, privsep means that some of the private structures ++ * in the GSSAPI code are no longer available. This kludges them back ++ * into life ++ */ ++ if (!ssh_gssapi_oid_table_ok()) ++ if ((mechs = ssh_gssapi_server_mechanisms())) ++ free(mechs); ++ ++ debug2("%s: Identifying %s", __func__, kex->name); ++ oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); ++ if (oid == GSS_C_NO_OID) ++ fatal("Unknown gssapi mechanism"); ++ ++ debug2("%s: Acquiring credentials", __func__); ++ ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ fatal("Unable to acquire credentials for the server"); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ kex->dh = dh_new_group1(); ++ break; ++ case KEX_GSS_GRP14_SHA1: ++ kex->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(fips_dh_grp_min(), min); ++ max = MIN(DH_GRP_MAX, max); ++ packet_check_eom(); ++ if (max < min || nbits < min || max < nbits) { ++ if (nbits < min && nbits >= DH_GRP_MIN_RFC) ++ logit("DH parameter requested by the client (%d bits) " ++ "is considered insecure. " ++ "You can lower the accepted minimum " ++ "via the KexDHMin option.", ++ nbits); ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", ++ min, nbits, max); ++ } ++ kex->dh = PRIVSEP(choose_dh(min, nbits, max)); ++ if (kex->dh == NULL) ++ packet_disconnect("Protocol error: no matching group found"); ++ ++ packet_start(SSH2_MSG_KEXGSS_GROUP); ++ packet_put_bignum2(kex->dh->p); ++ packet_put_bignum2(kex->dh->g); ++ packet_send(); ++ ++ packet_write_wait(); ++ break; ++ default: ++ fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); ++ } ++ ++ dh_gen_key(kex->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(kex->dh, dh_client_pub)) ++ packet_disconnect("bad client public DH value"); ++ ++ klen = DH_size(kex->dh); ++ kbuf = xmalloc(klen); ++ kout = DH_compute_key(kbuf, dh_client_pub, kex->dh); ++ if (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, kex->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, ++ kex->dh->p, kex->dh->g, ++ dh_client_pub, ++ kex->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(kex->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); ++ ++ if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++/* TODO: ++out: ++*/ ++ explicit_bzero(hash, sizeof(hash)); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ if (dh_client_pub) ++ BN_clear_free(dh_client_pub); ++ if (kbuf) { ++ explicit_bzero(kbuf, klen); ++ free(kbuf); ++ } ++ if (shared_secret) ++ BN_clear_free(shared_secret); ++ ++ /* If this was a rekey, then save out any delegated credentials we ++ * just exchanged. */ ++ if (options.gss_store_rekey) ++ ssh_gssapi_rekey_creds(); ++ ++ return r; ++} ++#endif /* GSSAPI */ +diff --git a/openssh-7.2p2/monitor.c b/openssh-7.2p2/monitor.c +--- a/openssh-7.2p2/monitor.c ++++ b/openssh-7.2p2/monitor.c +@@ -151,16 +151,18 @@ int mm_answer_pam_respond(int, Buffer *) + int mm_answer_pam_free_ctx(int, Buffer *); + #endif + + #ifdef GSSAPI + 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 + int mm_answer_audit_event(int, Buffer *); + int mm_answer_audit_command(int, Buffer *); + #endif + + static int monitor_read_log(struct monitor *); +@@ -228,21 +230,28 @@ struct mon_table mon_dispatch_proto20[] + #endif + {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, + {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, + #ifdef GSSAPI + {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, + {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 + #ifdef WITH_OPENSSL + {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, + #endif + {MONITOR_REQ_SIGN, 0, mm_answer_sign}, + {MONITOR_REQ_PTY, 0, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + #ifdef SSH_AUDIT_EVENTS +@@ -347,16 +356,20 @@ monitor_child_preauth(Authctxt *_authctx + authctxt->loginmsg = &loginmsg; + + if (compat20) { + mon_dispatch = mon_dispatch_proto20; + + /* 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; + + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + } + + /* The first few requests do not require asynchronous access */ + while (!authenticated) { +@@ -455,16 +468,20 @@ monitor_child_postauth(struct monitor *p + + if (compat20) { + mon_dispatch = mon_dispatch_postauth20; + + /* Permit requests for moduli and signatures */ + 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); + } + if (!no_pty_flag) { + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); + } +@@ -1856,16 +1873,23 @@ monitor_apply_keystate(struct monitor *p + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; + # ifdef OPENSSL_HAS_ECC + kex->kex[KEX_ECDH_SHA2] = kexecdh_server; + # 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; + kex->sign = sshd_hostkey_sign; + } + + /* Update with new address */ + if (options.compression) { +@@ -1955,16 +1979,19 @@ monitor_reinit(struct monitor *mon) + #ifdef GSSAPI + int + mm_answer_gss_setup_ctx(int sock, Buffer *m) + { + gss_OID_desc goid; + 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; + + major = ssh_gssapi_server_ctx(&gsscontext, &goid); + + free(goid.elements); + + buffer_clear(m); +@@ -1982,16 +2009,19 @@ int + mm_answer_gss_accept_ctx(int sock, Buffer *m) + { + gss_buffer_desc in; + gss_buffer_desc out = GSS_C_EMPTY_BUFFER; + OM_uint32 major, minor; + 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); + free(in.value); + + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_string(m, out.value, out.length); +@@ -1999,27 +2029,31 @@ mm_answer_gss_accept_ctx(int sock, Buffe + mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); + + gss_release_buffer(&minor, &out); + + if (major == GSS_S_COMPLETE) { + 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); + } + + int + mm_answer_gss_checkmic(int sock, Buffer *m) + { + gss_buffer_desc gssbuf, mic; + 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); + mic.length = len; + + ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); + + free(gssbuf.value); +@@ -2036,23 +2070,95 @@ mm_answer_gss_checkmic(int sock, Buffer + return (0); + } + + int + 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); + + debug3("%s: sending result %d", __func__, authenticated); + mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); + + auth_method = "gssapi-with-mic"; + + /* 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/openssh-7.2p2/monitor.h b/openssh-7.2p2/monitor.h +--- a/openssh-7.2p2/monitor.h ++++ b/openssh-7.2p2/monitor.h +@@ -60,16 +60,19 @@ enum monitor_reqtype { + 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, + 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_GSSSIGN = 201, MONITOR_ANS_GSSSIGN = 202, ++ MONITOR_REQ_GSSUPCREDS = 203, MONITOR_ANS_GSSUPCREDS = 204, ++ + }; + + struct mm_master; + struct monitor { + int m_recvfd; + int m_sendfd; + int m_log_recvfd; + int m_log_sendfd; +diff --git a/openssh-7.2p2/monitor_wrap.c b/openssh-7.2p2/monitor_wrap.c +--- a/openssh-7.2p2/monitor_wrap.c ++++ b/openssh-7.2p2/monitor_wrap.c +@@ -1063,27 +1063,72 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss + &m); + + major = buffer_get_int(&m); + buffer_free(&m); + return(major); + } + + int +-mm_ssh_gssapi_userok(char *user) ++mm_ssh_gssapi_userok(char *user, struct passwd *pw) + { + Buffer m; + int authenticated = 0; + + buffer_init(&m); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK, + &m); + + authenticated = buffer_get_int(&m); + + buffer_free(&m); + 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/openssh-7.2p2/monitor_wrap.h b/openssh-7.2p2/monitor_wrap.h +--- a/openssh-7.2p2/monitor_wrap.h ++++ b/openssh-7.2p2/monitor_wrap.h +@@ -53,18 +53,20 @@ int mm_key_verify(Key *, 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 *); + + #ifdef GSSAPI + 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 + void mm_start_pam(struct Authctxt *); + u_int mm_do_pam_account(void); + void *mm_sshpam_init_ctx(struct Authctxt *); + int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **); + int mm_sshpam_respond(void *, u_int, char **); +diff --git a/openssh-7.2p2/readconf.c b/openssh-7.2p2/readconf.c +--- a/openssh-7.2p2/readconf.c ++++ b/openssh-7.2p2/readconf.c +@@ -145,16 +145,18 @@ typedef enum { + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, + oPubkeyAuthentication, + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, + oHostKeyAlgorithms, oBindAddress, oPKCS11Provider, + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, ++ oGssTrustDns, oGssKeyEx, oGssClientIdentity, oGssRenewalRekey, ++ oGssServerIdentity, + oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oSendEnv, oControlPath, oControlMaster, oControlPersist, + oHashKnownHosts, + oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, + oVisualHostKey, + oKexAlgorithms, oKexDHMin, + oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, + oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, +@@ -191,20 +193,30 @@ static struct { + { "challengeresponseauthentication", oChallengeResponseAuthentication }, + { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ + { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ + { "kerberosauthentication", oUnsupported }, + { "kerberostgtpassing", oUnsupported }, + { "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 }, ++ { "gssapiserveridentity", oUnsupported }, ++ { "gssapirenewalforcesrekey", oUnsupported }, + #endif + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, + { "identityfile", oIdentityFile }, + { "identityfile2", oIdentityFile }, /* obsolete */ + { "identitiesonly", oIdentitiesOnly }, + { "certificatefile", oCertificateFile }, + { "addkeystoagent", oAddKeysToAgent }, +@@ -928,20 +940,40 @@ parse_time: + case oChallengeResponseAuthentication: + intptr = &options->challenge_response_authentication; + goto parse_flag; + + case oGssAuthentication: + 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; + + case oCheckHostIP: + intptr = &options->check_host_ip; + goto parse_flag; + +@@ -1671,17 +1703,22 @@ initialize_options(Options * options) + options->fwd_opts.gateway_ports = -1; + options->fwd_opts.streamlocal_bind_mask = (mode_t)-1; + options->fwd_opts.streamlocal_bind_unlink = -1; + options->use_privileged_port = -1; + options->rsa_authentication = -1; + 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; + options->rhosts_rsa_authentication = -1; + options->hostbased_authentication = -1; + options->batch_mode = -1; + options->check_host_ip = -1; + options->strict_host_key_checking = -1; +@@ -1801,18 +1838,24 @@ fill_default_options(Options * options) + if (options->rsa_authentication == -1) + options->rsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; + if (options->challenge_response_authentication == -1) + 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) + options->kbd_interactive_authentication = 1; + if (options->rhosts_rsa_authentication == -1) + options->rhosts_rsa_authentication = 0; + if (options->hostbased_authentication == -1) + options->hostbased_authentication = 0; +diff --git a/openssh-7.2p2/readconf.h b/openssh-7.2p2/readconf.h +--- a/openssh-7.2p2/readconf.h ++++ b/openssh-7.2p2/readconf.h +@@ -40,17 +40,22 @@ typedef struct { + int rhosts_rsa_authentication; /* Try rhosts with RSA + * authentication. */ + int rsa_authentication; /* Try RSA authentication. */ + int pubkey_authentication; /* Try ssh2 pubkey authentication. */ + int hostbased_authentication; /* ssh2's rhosts_rsa */ + 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. */ + char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */ + int batch_mode; /* Batch mode: do not ask for passwords. */ + int check_host_ip; /* Also keep track of keys for IP address */ + int strict_host_key_checking; /* Strict host key checking. */ + int compression; /* Compress packets in both directions. */ +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -118,18 +118,20 @@ initialize_server_options(ServerOptions + options->rsa_authentication = -1; + options->pubkey_authentication = -1; + options->pubkey_key_types = NULL; + options->kerberos_authentication = -1; + options->kerberos_or_local_passwd = -1; + 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; + options->permit_empty_passwd = -1; + options->permit_user_env = -1; + options->use_login = -1; + options->compression = -1; + options->rekey_limit = -1; +@@ -318,20 +320,24 @@ fill_default_server_options(ServerOption + if (options->kerberos_or_local_passwd == -1) + options->kerberos_or_local_passwd = 1; + if (options->kerberos_ticket_cleanup == -1) + options->kerberos_ticket_cleanup = 1; + if (options->kerberos_get_afs_token == -1) + 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) + options->kbd_interactive_authentication = 0; + if (options->challenge_response_authentication == -1) + options->challenge_response_authentication = 1; + if (options->permit_empty_passwd == -1) + options->permit_empty_passwd = 0; +@@ -452,16 +458,17 @@ typedef enum { + sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes, + sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, + sBanner, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, + sHostKeyAlgorithms, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, ++ sGssKeyEx, sGssStoreRekey, + sAcceptEnv, sPermitTunnel, + sMatch, sPermitOpen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, + sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, + sKexAlgorithms, sKexDHMin, + sIPQoS, sVersionAddendum, +@@ -529,21 +536,27 @@ static struct { + { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, + #endif + { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, + { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, + #ifdef GSSAPI + { "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 }, + { "skeyauthentication", sChallengeResponseAuthentication, SSHCFG_GLOBAL }, /* alias */ + { "checkmail", sDeprecated, SSHCFG_GLOBAL }, + { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, + { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, + { "printmotd", sPrintMotd, SSHCFG_GLOBAL }, +@@ -1282,24 +1295,32 @@ process_server_config_line(ServerOptions + case sKerberosGetAFSToken: + intptr = &options->kerberos_get_afs_token; + goto parse_flag; + + case sGssAuthentication: + 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; + + case sKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + +@@ -2051,16 +2072,20 @@ copy_set_server_options(ServerOptions *d + { + #define M_CP_INTOPT(n) do {\ + if (src->n != -1) \ + dst->n = src->n; \ + } while (0) + + M_CP_INTOPT(password_authentication); + M_CP_INTOPT(gss_authentication); ++ M_CP_INTOPT(gss_keyex); ++ M_CP_INTOPT(gss_cleanup_creds); ++ M_CP_INTOPT(gss_strict_acceptor); ++ M_CP_INTOPT(gss_store_rekey); + M_CP_INTOPT(rsa_authentication); + M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(kerberos_authentication); + M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(hostbased_uses_name_from_packet_only); + M_CP_INTOPT(kbd_interactive_authentication); + M_CP_INTOPT(permit_root_login); + M_CP_INTOPT(permit_empty_passwd); +@@ -2338,17 +2363,20 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sKerberosOrLocalPasswd, o->kerberos_or_local_passwd); + dump_cfg_fmtint(sKerberosTicketCleanup, o->kerberos_ticket_cleanup); + # ifdef USE_AFS + dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); + # endif + #endif + #ifdef GSSAPI + dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); ++ dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); + dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); ++ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); ++ dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, + o->kbd_interactive_authentication); + dump_cfg_fmtint(sChallengeResponseAuthentication, + o->challenge_response_authentication); + dump_cfg_fmtint(sPrintMotd, o->print_motd); + #ifndef DISABLE_LASTLOG +diff --git a/openssh-7.2p2/servconf.h b/openssh-7.2p2/servconf.h +--- a/openssh-7.2p2/servconf.h ++++ b/openssh-7.2p2/servconf.h +@@ -11,16 +11,18 @@ + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + + #ifndef SERVCONF_H + #define SERVCONF_H + ++#include "misc.h" ++ + #define MAX_PORTS 256 /* Max # ports. */ + + #define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ + #define MAX_DENY_USERS 256 /* Max # users on deny list. */ + #define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ + #define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ + #define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ + #define MAX_HOSTKEYS 256 /* Max # hostkeys. */ +@@ -114,18 +116,20 @@ typedef struct { + * authentication mechanism, + * such as SecurID or + * /etc/passwd */ + int kerberos_ticket_cleanup; /* If true, destroy ticket + * file on logout. */ + 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 */ + int challenge_response_authentication; + int permit_empty_passwd; /* If false, do not permit empty + * passwords. */ + int permit_user_env; /* If true, read ~/.ssh/environment */ + int use_login; /* If true, login(1) is used */ +diff --git a/openssh-7.2p2/ssh-gss.h b/openssh-7.2p2/ssh-gss.h +--- a/openssh-7.2p2/ssh-gss.h ++++ b/openssh-7.2p2/ssh-gss.h +@@ -1,11 +1,11 @@ + /* $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 + * 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 +@@ -56,53 +56,70 @@ + #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 + #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 + #define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 + #define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 + #define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 + + #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; + + 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 { + char *enc_name; + char *name; + gss_OID_desc oid; + int (*dochild) (ssh_gssapi_client *); + 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 { + OM_uint32 major; /* both */ + OM_uint32 minor; /* both */ + gss_ctx_id_t context; /* both */ + gss_name_t name; /* both */ + 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); + void ssh_gssapi_set_oid(Gssctxt *, gss_OID); + void ssh_gssapi_supported_oids(gss_OID_set *); + ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *); + void ssh_gssapi_prepare_supported_oids(void); + OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *); +@@ -114,21 +131,35 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); + OM_uint32 ssh_gssapi_getclient(Gssctxt *, ssh_gssapi_client *); + void ssh_gssapi_error(Gssctxt *); + char *ssh_gssapi_last_error(Gssctxt *, OM_uint32 *, OM_uint32 *); + 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/openssh-7.2p2/ssh_config b/openssh-7.2p2/ssh_config +--- a/openssh-7.2p2/ssh_config ++++ b/openssh-7.2p2/ssh_config +@@ -42,16 +42,18 @@ Host * + SendEnv LC_IDENTIFICATION LC_ALL + + # RhostsRSAAuthentication no + # RSAAuthentication yes + # PasswordAuthentication yes + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP yes + # AddressFamily any + # ConnectTimeout 0 + # StrictHostKeyChecking ask + # IdentityFile ~/.ssh/identity + # IdentityFile ~/.ssh/id_rsa + # IdentityFile ~/.ssh/id_dsa +diff --git a/openssh-7.2p2/ssh_config.0 b/openssh-7.2p2/ssh_config.0 +--- a/openssh-7.2p2/ssh_config.0 ++++ b/openssh-7.2p2/ssh_config.0 +@@ -445,20 +445,51 @@ DESCRIPTION + Specifies one or more files to use for the global host key + database, separated by whitespace. The default is + /etc/ssh/ssh_known_hosts, /etc/ssh/ssh_known_hosts2. + + GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is M-bM-^@M-^\noM-bM-^@M-^]. + ++ GSSAPIKeyExchange ++ Specifies whether key exchange based on GSSAPI may be used. When ++ using GSSAPI key exchange the server need not have a host key. ++ The default is no. ++ Note that this option applies to protocol version 2 only. ++ ++ GSSAPIClientIdentity ++ If set, specifies the GSSAPI client identity that ssh should use ++ when connecting to the server. The default is unset, which means ++ that the default identity will be used. ++ ++ GSSAPIServerIdentity ++ If set, specifies the GSSAPI server identity that ssh should expect ++ when connecting to the server. The default is unset, which means ++ that the expected GSSAPI server identity will be determined from ++ the target hostname. ++ + GSSAPIDelegateCredentials + Forward (delegate) credentials to the server. The default is + M-bM-^@M-^\noM-bM-^@M-^]. + ++ GSSAPIRenewalForcesRekey ++ If set to yes then renewal of the client's GSSAPI credentials will ++ force the rekeying of the ssh connection. With a compatible server, ++ this can delegate the renewed credentials to a session on the ++ server. The default is no. ++ ++ GSSAPITrustDns ++ Set to yes to indicate that the DNS is trusted to securely ++ canonicalize the name of the host being connected to. If no, the ++ hostname entered on the command line will be passed untouched to ++ the GSSAPI library. The default is no. ++ This option only applies to protocol version 2 connections using ++ GSSAPI. ++ + HashKnownHosts + Indicates that ssh(1) should hash host names and addresses when + they are added to ~/.ssh/known_hosts. These hashed names may be + used normally by ssh(1) and sshd(8), but they do not reveal + identifying information should the file's contents be disclosed. + The default is M-bM-^@M-^\noM-bM-^@M-^]. Note that existing names and addresses in + known hosts files will not be converted automatically, but may be + manually hashed using ssh-keygen(1). +diff --git a/openssh-7.2p2/ssh_config.5 b/openssh-7.2p2/ssh_config.5 +--- a/openssh-7.2p2/ssh_config.5 ++++ b/openssh-7.2p2/ssh_config.5 +@@ -823,20 +823,52 @@ Specifies one or more files to use for t + host key database, separated by whitespace. + The default is + .Pa /etc/ssh/ssh_known_hosts , + .Pa /etc/ssh/ssh_known_hosts2 . + .It Cm GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is + .Dq 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 . ++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 . ++.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 + should hash host names and addresses when they are added to + .Pa ~/.ssh/known_hosts . + These hashed names may be used normally by + .Xr ssh 1 + and +diff --git a/openssh-7.2p2/sshconnect2.c b/openssh-7.2p2/sshconnect2.c +--- a/openssh-7.2p2/sshconnect2.c ++++ b/openssh-7.2p2/sshconnect2.c +@@ -155,20 +155,44 @@ order_hostkeyalgs(char *host, struct soc + + void + ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) + { + char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; + char *s; + 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 = 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 ((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); + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(options.ciphers); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(options.ciphers); + if (options.compression) { +@@ -190,16 +214,27 @@ ssh_kex2(char *host, struct sockaddr *ho + /* Enforce default */ + options.hostkeyalgorithms = xstrdup(KEX_DEFAULT_PK_ALG); + /* Prefer algorithms that we already have keys for */ + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + compat_pkalg_proposal( + 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); + + /* start key exchange */ + if ((r = kex_setup(active_state, myproposal)) != 0) + fatal("kex_setup: %s", ssh_err(r)); + kex = active_state->kex; +@@ -208,20 +243,40 @@ ssh_kex2(char *host, struct sockaddr *ho + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; + # ifdef OPENSSL_HAS_ECC + kex->kex[KEX_ECDH_SHA2] = kexecdh_client; + # endif + #endif + kex->kex[KEX_C25519_SHA256] = kexc25519_client; ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client; ++ } ++#endif + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->verify_host_key=&verify_host_key_callback; + ++#ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->gss_deleg_creds = options.gss_deleg_creds; ++ kex->gss_trust_dns = options.gss_trust_dns; ++ kex->gss_client = options.gss_client_identity; ++ if (options.gss_server_identity) { ++ kex->gss_host = options.gss_server_identity; ++ } else { ++ kex->gss_host = gss_host; ++ } ++ } ++#endif ++ + dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); + + /* remove ext-info from the KEX proposals for rekeying */ + myproposal[PROPOSAL_KEX_ALGS] = + compat_kex_proposal(options.kex_algorithms); + if ((r = kex_prop2buf(kex->my, myproposal)) != 0) + fatal("kex_prop2buf: %s", ssh_err(r)); + +@@ -306,31 +361,37 @@ int userauth_hostbased(Authctxt *); + + #ifdef GSSAPI + int userauth_gssapi(Authctxt *authctxt); + int input_gssapi_response(int type, u_int32_t, void *); + int input_gssapi_token(int type, u_int32_t, void *); + 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 *); + + static int sign_and_send_pubkey(Authctxt *, Identity *); + static void pubkey_prepare(Authctxt *); + static void pubkey_cleanup(Authctxt *); + static Key *load_identity_file(Identity *); + + static Authmethod *authmethod_get(char *authlist); + static Authmethod *authmethod_lookup(const char *name); + static char *authmethods_get(void); + + Authmethod authmethods[] = { + #ifdef GSSAPI ++ {"gssapi-keyex", ++ userauth_gsskeyex, ++ NULL, ++ &options.gss_authentication, ++ NULL}, + {"gssapi-with-mic", + userauth_gssapi, + NULL, + &options.gss_authentication, + NULL}, + #endif + {"hostbased", + userauth_hostbased, +@@ -651,29 +712,41 @@ done: + int + userauth_gssapi(Authctxt *authctxt) + { + Gssctxt *gssctxt = NULL; + static gss_OID_set gss_supported = NULL; + 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++; + } + } + + if (!ok) + return 0; +@@ -760,18 +833,18 @@ process_gssapi_token(void *ctxt, gss_buf + } + + /* ARGSUSED */ + int + 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"); + gssctxt = authctxt->methoddata; + + /* Setup our OID */ + oidv = packet_get_string(&oidlen); + +@@ -874,16 +947,58 @@ input_gssapi_error(int type, u_int32_t p + + packet_check_eom(); + + debug("Server GSSAPI Error:\n%s", msg); + free(msg); + 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 + userauth_none(Authctxt *authctxt) + { + /* initial userauth request */ + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -124,16 +124,20 @@ + #endif + #include "monitor_wrap.h" + #include "ssh-sandbox.h" + #include "version.h" + #include "ssherr.h" + + #include "fips.h" + ++#ifdef USE_SECURITY_SESSION_API ++#include ++#endif ++ + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif + + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) + #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) + #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) +@@ -1847,20 +1851,23 @@ main(int ac, char **av) + 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; + } ++#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); + } + + /* + * Load certificates. They are stored in an array at identical + * indices to the public keys that they relate to. +@@ -2055,16 +2062,70 @@ main(int ac, char **av) + /* Accept a connection and return in a forked child */ + server_accept_loop(&sock_in, &sock_out, + &newsock, config_s); + } + + /* This is the child processing a new connection. */ + setproctitle("%s", "[accepted]"); + ++#ifdef USE_SECURITY_SESSION_API ++ /* ++ * Create a new security session for use by the new user login if ++ * the current session is the root session or we are not launched ++ * by inetd (eg: debugging mode or server mode). We do not ++ * necessarily need to create a session if we are launched from ++ * inetd because Panther xinetd will create a session for us. ++ * ++ * The only case where this logic will fail is if there is an ++ * inetd running in a non-root session which is not creating ++ * new sessions for us. Then all the users will end up in the ++ * same session (bad). ++ * ++ * When the client exits, the session will be destroyed for us ++ * automatically. ++ * ++ * We must create the session before any credentials are stored ++ * (including AFS pags, which happens a few lines below). ++ */ ++ { ++ OSStatus err = 0; ++ SecuritySessionId sid = 0; ++ SessionAttributeBits sattrs = 0; ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("Current Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ ++ if (inetd_flag && !(sattrs & sessionIsRoot)) ++ debug("Running in inetd mode in a non-root session... " ++ "assuming inetd created the session for us."); ++ else { ++ debug("Creating new security session..."); ++ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); ++ if (err) ++ error("SessionCreate() failed with error %.8X", ++ (unsigned) err); ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, ++ &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("New Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ } ++ } ++#endif ++ + /* + * Create a new session and process group since the 4.4BSD + * setlogin() affects the entire process group. We don't + * want the child to be able to affect the parent. + */ + #if !defined(SSHD_ACQUIRES_CTTY) + /* + * If setsid is called, on some platforms sshd will later acquire a +@@ -2165,16 +2226,70 @@ main(int ac, char **av) + #endif + + /* Log the connection. */ + laddr = get_local_ipaddr(sock_in); + verbose("Connection from %s port %d on %s port %d", + remote_ip, remote_port, laddr, get_local_port()); + free(laddr); + ++#ifdef USE_SECURITY_SESSION_API ++ /* ++ * Create a new security session for use by the new user login if ++ * the current session is the root session or we are not launched ++ * by inetd (eg: debugging mode or server mode). We do not ++ * necessarily need to create a session if we are launched from ++ * inetd because Panther xinetd will create a session for us. ++ * ++ * The only case where this logic will fail is if there is an ++ * inetd running in a non-root session which is not creating ++ * new sessions for us. Then all the users will end up in the ++ * same session (bad). ++ * ++ * When the client exits, the session will be destroyed for us ++ * automatically. ++ * ++ * We must create the session before any credentials are stored ++ * (including AFS pags, which happens a few lines below). ++ */ ++ { ++ OSStatus err = 0; ++ SecuritySessionId sid = 0; ++ SessionAttributeBits sattrs = 0; ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("Current Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ ++ if (inetd_flag && !(sattrs & sessionIsRoot)) ++ debug("Running in inetd mode in a non-root session... " ++ "assuming inetd created the session for us."); ++ else { ++ debug("Creating new security session..."); ++ err = SessionCreate(0, sessionHasTTY | sessionIsRemote); ++ if (err) ++ error("SessionCreate() failed with error %.8X", ++ (unsigned) err); ++ ++ err = SessionGetInfo(callerSecuritySession, &sid, ++ &sattrs); ++ if (err) ++ error("SessionGetInfo() failed with error %.8X", ++ (unsigned) err); ++ else ++ debug("New Session ID is %.8X / Session Attributes are %.8X", ++ (unsigned) sid, (unsigned) sattrs); ++ } ++ } ++#endif ++ + /* + * We don't want to listen forever unless the other side + * successfully authenticates itself. So we set up an alarm which is + * cleared after successful authentication. A limit of zero + * indicates no limit. Note that we don't set the alarm in debugging + * mode; it is just annoying to have the server exit just when you + * are about to discover the bug. + */ +@@ -2585,30 +2700,79 @@ do_ssh2_kex(void) + + if (options.rekey_limit || options.rekey_interval) + packet_set_rekey_limits(options.rekey_limit, + (time_t)options.rekey_interval); + + 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)); + kex = active_state->kex; + #ifdef WITH_OPENSSL + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; + # ifdef OPENSSL_HAS_ECC + kex->kex[KEX_ECDH_SHA2] = kexecdh_server; + # 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; + 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; + kex->sign = sshd_hostkey_sign; + +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -84,16 +84,18 @@ PasswordAuthentication no + #KerberosAuthentication no + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no + + # GSSAPI options + #GSSAPIAuthentication no + #GSSAPICleanupCredentials yes ++#GSSAPIStrictAcceptorCheck yes ++#GSSAPIKeyExchange no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will + # be allowed through the ChallengeResponseAuthentication and + # PasswordAuthentication. Depending on your PAM configuration, + # PAM authentication via ChallengeResponseAuthentication may bypass + # the setting of "PermitRootLogin without-password". + # If you just want the PAM account and session checks to run without +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -375,29 +375,41 @@ DESCRIPTION + force remote port forwardings to bind to the wildcard address, or + M-bM-^@M-^\clientspecifiedM-bM-^@M-^] to allow the client to select the address to + which the forwarding is bound. The default is M-bM-^@M-^\noM-bM-^@M-^]. + + GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is M-bM-^@M-^\noM-bM-^@M-^]. + ++ GSSAPIKeyExchange ++ Specifies whether key exchange based on GSSAPI is allowed. GSSAPI ++ key exchange doesn't rely on ssh keys to verify host identity. The ++ default is no. ++ Note that this option applies to protocol version 2 only. ++ + GSSAPICleanupCredentials + Specifies whether to automatically destroy the user's credentials + cache on logout. The default is M-bM-^@M-^\yesM-bM-^@M-^]. + + GSSAPIStrictAcceptorCheck + Determines whether to be strict about the identity of the GSSAPI + acceptor a client authenticates against. If set to M-bM-^@M-^\yesM-bM-^@M-^] then + the client must authenticate against the host service on the + current hostname. If set to M-bM-^@M-^\noM-bM-^@M-^] 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 M-bM-^@M-^\yesM-bM-^@M-^]. + ++ GSSAPIStoreCredentialsOnRekey ++ Controls whether the user's GSSAPI credentials should be updated ++ following a successful connection rekeying. This option can be used ++ to accepted renewed or updated credentials from a compatible ++ client. The default is no. ++ + HostbasedAcceptedKeyTypes + Specifies the key types that will be accepted for hostbased + authentication as a comma-separated pattern list. Alternately if + the specified value begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, then the + specified key types will be appended to the default set instead + of replacing them. The default for this option is: + + ecdsa-sha2-nistp256-cert-v01@openssh.com, +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -619,16 +619,22 @@ to force remote port forwardings to bind + .Dq clientspecified + to allow the client to select the address to which the forwarding is bound. + The default is + .Dq no . + .It Cm GSSAPIAuthentication + Specifies whether user authentication based on GSSAPI is allowed. + The default is + .Dq no . ++.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 . + .It Cm GSSAPIStrictAcceptorCheck + Determines whether to be strict about the identity of the GSSAPI acceptor + a client authenticates against. +@@ -639,16 +645,21 @@ then the client must authenticate agains + service on the current hostname. + If set to + .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 . ++.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. + Alternately if the specified value begins with a + .Sq + + character, then the specified key types will be appended to the default set + instead of replacing them. + The default for this option is: +diff --git a/openssh-7.2p2/sshkey.c b/openssh-7.2p2/sshkey.c +--- a/openssh-7.2p2/sshkey.c ++++ b/openssh-7.2p2/sshkey.c +@@ -110,16 +110,18 @@ static const struct keytype keytypes[] = + { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", + KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, + # ifdef OPENSSL_HAS_NISTP521 + { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", + KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, + # endif /* OPENSSL_HAS_NISTP521 */ + # endif /* OPENSSL_HAS_ECC */ + #endif /* WITH_OPENSSL */ ++ { "null", "null", ++ KEY_NULL, 0, 0 }, + { NULL, NULL, -1, -1, 0, 0 } + }; + + const char * + sshkey_type(const struct sshkey *k) + { + const struct keytype *kt; + +diff --git a/openssh-7.2p2/sshkey.h b/openssh-7.2p2/sshkey.h +--- a/openssh-7.2p2/sshkey.h ++++ b/openssh-7.2p2/sshkey.h +@@ -57,16 +57,17 @@ enum sshkey_types { + KEY_RSA, + KEY_DSA, + KEY_ECDSA, + KEY_ED25519, + KEY_RSA_CERT, + KEY_DSA_CERT, + KEY_ECDSA_CERT, + KEY_ED25519_CERT, ++ KEY_NULL, + KEY_UNSPEC + }; + + /* Default fingerprint hash */ + #define SSH_FP_HASH_DEFAULT SSH_DIGEST_SHA256 + + /* Fingerprint representation formats */ + enum sshkey_fp_rep { diff --git a/openssh-7.2p2-host_ident.patch b/openssh-7.2p2-host_ident.patch new file mode 100644 index 0000000..844ddb1 --- /dev/null +++ b/openssh-7.2p2-host_ident.patch @@ -0,0 +1,29 @@ +# HG changeset patch +# Parent e2f9b3303b4a4ed5d0e5f01009dd1ebea166890d +Suggest command line for removal of offending keys from known_hosts file + +diff --git a/openssh-7.2p2/sshconnect.c b/openssh-7.2p2/sshconnect.c +--- a/openssh-7.2p2/sshconnect.c ++++ b/openssh-7.2p2/sshconnect.c +@@ -1086,16 +1086,21 @@ check_host_key(char *hostname, struct so + ip_found->file, ip_found->line); + } + /* The host key has changed. */ + warn_changed_key(host_key); + error("Add correct host key in %.100s to get rid of this message.", + user_hostfiles[0]); + error("Offending %s key in %s:%lu", key_type(host_found->key), + host_found->file, host_found->line); ++ error("You can use following command to remove the offending key:"); ++ if (host_found->file) ++ error("ssh-keygen -R %s -f %s", host, host_found->file); ++ else ++ error("ssh-keygen -R %s", host); + + /* + * If strict host key checking is in use, the user will have + * to edit the key manually and we can only abort. + */ + if (options.strict_host_key_checking) { + error("%s host key for %.200s has changed and you have " + "requested strict checking.", type, host); diff --git a/openssh-7.6p1-hostname_changes_when_forwarding_X.patch b/openssh-7.2p2-hostname_changes_when_forwarding_X.patch similarity index 67% rename from openssh-7.6p1-hostname_changes_when_forwarding_X.patch rename to openssh-7.2p2-hostname_changes_when_forwarding_X.patch index c5b6676..4714d67 100644 --- a/openssh-7.6p1-hostname_changes_when_forwarding_X.patch +++ b/openssh-7.2p2-hostname_changes_when_forwarding_X.patch @@ -1,24 +1,24 @@ # HG changeset patch -# Parent e4a7e5799420a3d4b8047c5984c75c4bd4331951 +# Parent f7ba2081f120bd1e44dbe68737c898f078725aab # -- uset do be called '-xauthlocalhostname' handle hostname changes when forwarding X bnc#98627 -diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c ---- a/openssh-7.6p1/session.c -+++ b/openssh-7.6p1/session.c -@@ -953,17 +953,17 @@ copy_environment_blacklist(char **source +diff --git a/openssh-7.2p2/session.c b/openssh-7.2p2/session.c +--- a/openssh-7.2p2/session.c ++++ b/openssh-7.2p2/session.c +@@ -1154,17 +1154,17 @@ copy_environment(char **source, char *** + debug3("Copy environment: %s=%s", var_name, var_val); + child_set_env(env, envsize, var_name, var_val); - void - copy_environment(char **source, char ***env, u_int *envsize) - { - copy_environment_blacklist(source, env, envsize, NULL); + free(var_name); + } } static char ** --do_setup_env(struct ssh *ssh, Session *s, const char *shell) -+do_setup_env(struct ssh *ssh, Session *s, const char *shell, int *env_size) +-do_setup_env(Session *s, const char *shell) ++do_setup_env(Session *s, const char *shell, int *env_size) { char buf[256]; u_int i, envsize; @@ -27,7 +27,7 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c #if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN) char *path = NULL; #endif -@@ -1142,25 +1142,27 @@ do_setup_env(struct ssh *ssh, Session *s +@@ -1341,25 +1341,27 @@ do_setup_env(Session *s, const char *she read_environment_file(&env, &envsize, buf); } if (debug_flag) { @@ -56,7 +56,7 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c do_xauth = s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; -@@ -1205,22 +1207,30 @@ do_rc_files(Session *s, const char *shel +@@ -1404,22 +1406,30 @@ do_rc_files(Session *s, const char *shel "%.500s add %.100s %.100s %.100s\n", options.xauth_location, s->auth_display, s->auth_proto, s->auth_data); @@ -66,7 +66,7 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c f = popen(cmd, "w"); if (f) { + char hostname[MAXHOSTNAMELEN]; -+ ++ fprintf(f, "remove %s\n", s->auth_display); fprintf(f, "add %s %s %s\n", @@ -87,25 +87,25 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c } static void -@@ -1461,16 +1471,17 @@ child_close_fds(struct ssh *ssh) +@@ -1681,16 +1691,17 @@ child_close_fds(void) * ids, and executing the command or shell. */ #define ARGV_MAX 10 void - do_child(struct ssh *ssh, Session *s, const char *command) + do_child(Session *s, const char *command) { extern char **environ; char **env; + int env_size; char *argv[ARGV_MAX]; - const char *shell, *shell0; + const char *shell, *shell0, *hostname = NULL; struct passwd *pw = s->pw; int r = 0; /* remove hostkey from the child's memory */ destroy_sensitive_data(); - packet_clear_keys(); -@@ -1522,17 +1533,17 @@ do_child(struct ssh *ssh, Session *s, co + +@@ -1747,17 +1758,17 @@ do_child(Session *s, const char *command * legal, and means /bin/sh. */ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; @@ -114,18 +114,17 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c * Make sure $SHELL points to the shell from the password file, * even if shell is overridden from login.conf */ -- env = do_setup_env(ssh, s, shell); -+ env = do_setup_env(ssh, s, shell, &env_size); +- env = do_setup_env(s, shell); ++ env = do_setup_env(s, shell, &env_size); #ifdef HAVE_LOGIN_CAP shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); #endif - /* - * Close the connection descriptors; note that this is the child, and - * the server will still have the socket open, and it is important -@@ -1586,17 +1597,17 @@ do_child(struct ssh *ssh, Session *s, co - strerror(errno)); + /* we have to stash the hostname before we close our socket. */ + if (options.use_login) + hostname = get_remote_name_or_ip(utmp_len, +@@ -1816,17 +1827,17 @@ do_child(Session *s, const char *command } if (r) exit(1); @@ -133,8 +132,9 @@ diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c closefrom(STDERR_FILENO + 1); -- do_rc_files(s, shell); -+ do_rc_files(s, shell, env, &env_size); + if (!options.use_login) +- do_rc_files(s, shell); ++ do_rc_files(s, shell, env, &env_size); /* restore SIGPIPE for child */ signal(SIGPIPE, SIG_DFL); diff --git a/openssh-7.2p2-ignore_PAM_with_UseLogin.patch b/openssh-7.2p2-ignore_PAM_with_UseLogin.patch new file mode 100644 index 0000000..2c65bb2 --- /dev/null +++ b/openssh-7.2p2-ignore_PAM_with_UseLogin.patch @@ -0,0 +1,33 @@ +# HG changeset patch +# Parent 0f00e960e1069c6a6eec975cc184171343701077 + +Do not import PAM environment variables when using login, since it may have +security implications. + +CVE-2015-8325 +bsc#975865 + +Backport of upstream commit 85bdcd7c92fe7ff133bbc4e10a65c91810f88755 + +diff --git a/openssh-7.2p2/session.c b/openssh-7.2p2/session.c +--- a/openssh-7.2p2/session.c ++++ b/openssh-7.2p2/session.c +@@ -1351,17 +1351,17 @@ do_setup_env(Session *s, const char *she + child_set_env(&env, &envsize, "KRB5CCNAME", + s->authctxt->krb5_ccname); + #endif + #ifdef USE_PAM + /* + * 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(); + copy_environment(p, &env, &envsize); + free_pam_environment(p); + + p = fetch_pam_environment(); + copy_environment(p, &env, &envsize); diff --git a/openssh-7.2p2-keep_slogin.patch b/openssh-7.2p2-keep_slogin.patch new file mode 100644 index 0000000..6304aff --- /dev/null +++ b/openssh-7.2p2-keep_slogin.patch @@ -0,0 +1,66 @@ +# HG changeset patch +# Parent 7c29b31d3502bbf5b80e01f8d1db8b2733a3c7f4 +Add slogin back to the distribution, since it might be used downstreams + +Revert of cupstream commit 69fead5d7cdaa73bdece9fcba80f8e8e70b90346 + +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -354,16 +354,20 @@ install-files: + $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 + $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 + $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 + $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 + if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ + $(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 ++ ln -s ./ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1 + + install-sysconf: + if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ + $(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \ + fi + @if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config ]; then \ + $(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \ + else \ +@@ -415,16 +419,17 @@ uninstallall: uninstall + -rmdir $(DESTDIR)$(bindir) + -rmdir $(DESTDIR)$(sbindir) + -rmdir $(DESTDIR)$(mandir)/$(mansubdir)1 + -rmdir $(DESTDIR)$(mandir)/$(mansubdir)8 + -rmdir $(DESTDIR)$(mandir) + -rmdir $(DESTDIR)$(libexecdir) + + uninstall: ++ -rm -f $(DESTDIR)$(bindir)/slogin + -rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) + -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) +@@ -440,16 +445,17 @@ uninstall: + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 + -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-prep: + [ -d `pwd`/regress ] || mkdir -p `pwd`/regress + [ -d `pwd`/regress/unittests ] || mkdir -p `pwd`/regress/unittests + [ -d `pwd`/regress/unittests/test_helper ] || \ + mkdir -p `pwd`/regress/unittests/test_helper + [ -d `pwd`/regress/unittests/sshbuf ] || \ + mkdir -p `pwd`/regress/unittests/sshbuf diff --git a/openssh-7.2p2-kex_resource_depletion.patch b/openssh-7.2p2-kex_resource_depletion.patch new file mode 100644 index 0000000..5679548 --- /dev/null +++ b/openssh-7.2p2-kex_resource_depletion.patch @@ -0,0 +1,30 @@ +# HG changeset patch +# Parent 5d3b620e9c7c42bfb1d8f24eb7e0645a55d967fa +Prevent memory depletion during key exchange + +CVE-2016-8858 +bsc#1005480 + +upstream commit ec165c392ca54317dbe3064a8c200de6531e89ad + +diff --git a/openssh-7.2p2/kex.c b/openssh-7.2p2/kex.c +--- a/openssh-7.2p2/kex.c ++++ b/openssh-7.2p2/kex.c +@@ -523,16 +523,17 @@ kex_input_kexinit(int type, u_int32_t se + u_int i; + size_t dlen; + int r; + + debug("SSH2_MSG_KEXINIT received"); + if (kex == NULL) + return SSH_ERR_INVALID_ARGUMENT; + ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); + ptr = sshpkt_ptr(ssh, &dlen); + if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) + return r; + + /* discard packet */ + for (i = 0; i < KEX_COOKIE_LEN; i++) + if ((r = sshpkt_get_u8(ssh, NULL)) != 0) + return r; diff --git a/openssh-7.6p1-lastlog.patch b/openssh-7.2p2-lastlog.patch similarity index 77% rename from openssh-7.6p1-lastlog.patch rename to openssh-7.2p2-lastlog.patch index e51b4a4..2accb74 100644 --- a/openssh-7.6p1-lastlog.patch +++ b/openssh-7.2p2-lastlog.patch @@ -1,11 +1,11 @@ # HG changeset patch -# Parent b26f93cf21e4cfff1212ad2e61696ad099cfaf5e +# Parent 79c00e0f450c33b3f545ef104112b55186290e2c # set uid for functions that use it to seek in lastlog and wtmp files # bnc#18024 (was suse #3024) -diff --git a/openssh-7.6p1/sshlogin.c b/openssh-7.6p1/sshlogin.c ---- a/openssh-7.6p1/sshlogin.c -+++ b/openssh-7.6p1/sshlogin.c +diff --git a/openssh-7.2p2/sshlogin.c b/openssh-7.2p2/sshlogin.c +--- a/openssh-7.2p2/sshlogin.c ++++ b/openssh-7.2p2/sshlogin.c @@ -129,16 +129,17 @@ record_login(pid_t pid, const char *tty, { struct logininfo *li; diff --git a/openssh-7.2p2-ldap.patch b/openssh-7.2p2-ldap.patch new file mode 100644 index 0000000..42a8f34 --- /dev/null +++ b/openssh-7.2p2-ldap.patch @@ -0,0 +1,2838 @@ +# HG changeset patch +# Parent a47716db81c68026e9d37db568c2c313acc53f86 +# Helper app for retrieving keys from a LDAP server +# by Jan F. Chadima +# +# patch for openbsd-compat/base64.* introduces preprocessor macro +# USE_INTERNAL_B64 intended to enforce using ssh supplied functions. +# (The additional -lldap/-llber introduced in the patch cause configure to +# discover the base64 functions in glibc (libresolv) and not to build the +# internal versions. ssh-keyconverter consequently fails to link as it lacks +# the proper flags, and libopenbsd-compat doesn't contain the b64_* functions) + +diff --git a/openssh-7.2p2/HOWTO.ldap-keys b/openssh-7.2p2/HOWTO.ldap-keys +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/HOWTO.ldap-keys +@@ -0,0 +1,108 @@ ++ ++HOW TO START ++ ++1) configure LDAP server ++ * Use LDAP server documentation ++2) add appropriate LDAP schema ++ * For OpenLDAP or SunONE Use attached schema, otherwise you have to create ++ it. ++ * LDAP user entry ++ User entry: ++ - attached to the 'ldapPublicKey' objectclass ++ - attached to the 'posixAccount' objectclass ++ - with a filled 'sshPublicKey' attribute ++3) insert users into LDAP ++ * Use LDAP Tree management tool as useful ++ * Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' ++ which are defined in core.schema and the additionnal lpk.schema. ++ * Example: ++ dn: uid=captain,ou=commanders,dc=enterprise,dc=universe ++ objectclass: top ++ objectclass: person ++ objectclass: organizationalPerson ++ objectclass: posixAccount ++ objectclass: ldapPublicKey ++ description: Jonathan Archer ++ userPassword: Porthos ++ cn: onathan Archer ++ sn: onathan Archer ++ uid: captain ++ uidNumber: 1001 ++ gidNumber: 1001 ++ homeDirectory: /home/captain ++ sshPublicKey: ssh-rss AAAAB3.... =captain@universe ++ sshPublicKey: command="kill -9 1" ssh-rss AAAAM5... ++4) on the ssh side set in sshd_config ++ * Set up the backend ++ AuthorizedKeysCommand "@LIBEXECDIR@/ssh-ldap-wrapper" ++ AuthorizedKeysCommandRunAs ++ * Do not forget to set ++ PubkeyAuthentication yes ++ * Swith off unnecessary auth methods ++5) confugure ldap.conf ++ * Default ldap.conf is placed in /etc/ssh ++ * The configuration style is the same as other ldap based aplications ++6) if necessary edit ssh-ldap-wrapper ++ * There is a possibility to change ldap.conf location ++ * There are some debug options ++ * Example ++ @LIBEXECDIR@/ssh-ldap-wrapper -s -f /etc/ldap.conf -w -d >> /tmp/ldapdebuglog.txt ++ ++HOW TO MIGRATE FROM LPK ++ ++1) goto HOW TO START 4) .... the ldap schema is the same ++ ++2) convert the group requests to the appropriate LDAP requests ++ ++HOW TO SOLVE PROBLEMS ++ ++1) use debug in sshd ++ * /usr/sbin/sshd -d -d -d -d ++2) use debug in ssh-ldap-helper ++ * ssh-ldap-helper -d -d -d -d -s ++3) use tcpdump ... other ldap client etc. ++ ++ADVANTAGES ++ ++1) Blocking an user account can be done directly from LDAP (if sshd is using ++ PubkeyAuthentication + AuthorizedKeysCommand with ldap only). ++ ++DISADVANTAGES ++ ++1) LDAP must be well configured, getting the public key of some user is not ++ a problem, but if anonymous LDAP allows write to users dn, somebody could ++ replace some user's public key by his own and impersonate some of your users ++ in all your server farm -- be VERY CAREFUL. ++2) With incomplete PKI the MITM attack when sshd is requesting the public key, ++ could lead to a compromise of your servers allowing login as the ++ impersonated user. ++3) If LDAP server is down there may be no fallback on passwd auth. ++ ++MISC. ++ ++1) todo ++ * Possibility to reuse the ssh-ldap-helper. ++ * Tune the LDAP part to accept all possible LDAP configurations. ++ ++2) differences from original lpk ++ * No LDAP code in sshd. ++ * Support for various LDAP platforms and configurations. ++ * LDAP is configured in separate ldap.conf file. ++ ++3) docs/link ++ * http://pacsec.jp/core05/psj05-barisani-en.pdf ++ * http://fritz.potsdam.edu/projects/openssh-lpk/ ++ * http://fritz.potsdam.edu/projects/sshgate/ ++ * http://dev.inversepath.com/trac/openssh-lpk ++ * http://lam.sf.net/ ++ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm ) ++ ++4) contributors/ideas/greets ++ - Eric AUGE ++ - Andrea Barisani ++ - Falk Siemonsmeier. ++ - Jacob Rief. ++ - Michael Durchgraf. ++ - frederic peters. ++ - Finlay dobbie. ++ - Stefan Fisher. +diff --git a/openssh-7.2p2/Makefile.in b/openssh-7.2p2/Makefile.in +--- a/openssh-7.2p2/Makefile.in ++++ b/openssh-7.2p2/Makefile.in +@@ -21,16 +21,18 @@ top_srcdir=@top_srcdir@ + + DESTDIR= + VPATH=@srcdir@ + SSH_PROGRAM=@bindir@/ssh + ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper ++SSH_LDAP_HELPER=$(libexecdir)/ssh-ldap-helper ++SSH_LDAP_WRAPPER=$(libexecdir)/ssh-ldap-wrapper + CAVSTEST_CTR=$(libexecdir)/cavstest-ctr + CAVSTEST_KDF=$(libexecdir)/cavstest-kdf + PRIVSEP_PATH=@PRIVSEP_PATH@ + SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ + STRIP_OPT=@STRIP_OPT@ + TEST_SHELL=@TEST_SHELL@ + + PATHS= -DSSHDIR=\"$(sysconfdir)\" \ +@@ -63,16 +65,19 @@ XAUTH_PATH=@XAUTH_PATH@ + LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ + EXEEXT=@EXEEXT@ + MANFMT=@MANFMT@ + + 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 += cavstest-ctr$(EXEEXT) cavstest-kdf$(EXEEXT) + ++INSTALL_SSH_LDAP_HELPER=@INSTALL_SSH_LDAP_HELPER@ ++TARGETS += ssh-ldap-helper$(EXEEXT) ++ + LIBOPENSSH_OBJS=\ + ssh_api.o \ + ssherr.o \ + sshbuf.o \ + sshkey.o \ + sshbuf-getput-basic.o \ + sshbuf-misc.o \ + sshbuf-getput-crypto.o \ +@@ -114,18 +119,18 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passw + monitor_mm.o monitor.o monitor_wrap.o auth-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.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 \ + 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 ++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 ssh-ldap-helper.8.out ssh-ldap.conf.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 ssh-ldap-helper.8 ssh-ldap.conf.5 + MANTYPE = @MANTYPE@ + + CONFIGFILES=sshd_config.out ssh_config.out moduli.out + CONFIGFILES_IN=sshd_config ssh_config moduli + + PATHSUBS = \ + -e 's|/etc/ssh/ssh_config|$(sysconfdir)/ssh_config|g' \ + -e 's|/etc/ssh/ssh_known_hosts|$(sysconfdir)/ssh_known_hosts|g' \ +@@ -189,16 +194,19 @@ ssh-keysign$(EXEEXT): $(LIBCOMPAT) libss + $(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat $(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) + + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o + $(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + ++ssh-ldap-helper$(EXEEXT): $(LIBCOMPAT) libssh.a ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o ++ $(LD) -o $@ ldapconf.o ldapbody.o ldapmisc.o ldap-helper.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) ++ + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o + $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) + + sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o + $(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) + + # FIPS tests + cavstest-ctr$(EXEEXT): $(LIBCOMPAT) libssh.a cavstest-ctr.o +@@ -320,16 +328,20 @@ install-files: + $(INSTALL) -m 0755 $(STRIP_OPT) scp$(EXEEXT) $(DESTDIR)$(bindir)/scp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-add$(EXEEXT) $(DESTDIR)$(bindir)/ssh-add$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-agent$(EXEEXT) $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keygen$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keyscan$(EXEEXT) $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + $(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) ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-ldap-helper $(DESTDIR)$(SSH_LDAP_HELPER) ; \ ++ $(INSTALL) -m 0755 ssh-ldap-wrapper $(DESTDIR)$(SSH_LDAP_WRAPPER) ; \ ++ fi + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-ctr$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-ctr$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) cavstest-kdf$(EXEEXT) $(DESTDIR)$(libexecdir)/cavstest-kdf$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 + $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1 + $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1 + $(INSTALL) -m 644 ssh-agent.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 +@@ -338,16 +350,20 @@ install-files: + $(INSTALL) -m 644 moduli.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/moduli.5 + $(INSTALL) -m 644 sshd_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/sshd_config.5 + $(INSTALL) -m 644 ssh_config.5.out $(DESTDIR)$(mandir)/$(mansubdir)5/ssh_config.5 + $(INSTALL) -m 644 sshd.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 + $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 + $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8 + $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8 + $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8 ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ $(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 + + install-sysconf: + if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \ + $(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \ + fi + @if [ ! -f $(DESTDIR)$(sysconfdir)/ssh_config ]; then \ + $(INSTALL) -m 644 ssh_config.out $(DESTDIR)$(sysconfdir)/ssh_config; \ + else \ +@@ -363,16 +379,23 @@ install-sysconf: + echo "moving $(DESTDIR)$(sysconfdir)/primes to $(DESTDIR)$(sysconfdir)/moduli"; \ + mv "$(DESTDIR)$(sysconfdir)/primes" "$(DESTDIR)$(sysconfdir)/moduli"; \ + else \ + $(INSTALL) -m 644 moduli.out $(DESTDIR)$(sysconfdir)/moduli; \ + fi ; \ + else \ + echo "$(DESTDIR)$(sysconfdir)/moduli already exists, install will not overwrite"; \ + fi ++ if test ! -z "$(INSTALL_SSH_LDAP_HELPER)" ; then \ ++ if [ ! -f $(DESTDIR)$(sysconfdir)/ldap.conf ]; then \ ++ $(INSTALL) -m 644 ldap.conf $(DESTDIR)$(sysconfdir)/ldap.conf; \ ++ else \ ++ echo "$(DESTDIR)$(sysconfdir)/ldap.conf already exists, install will not overwrite"; \ ++ fi ; \ ++ fi + + host-key: ssh-keygen$(EXEEXT) + @if [ -z "$(DESTDIR)" ] ; then \ + ./ssh-keygen -A; \ + fi + + host-key-force: ssh-keygen$(EXEEXT) ssh$(EXEEXT) + if ./ssh -Q protocol-version | grep '^1$$' >/dev/null; then \ +@@ -403,27 +426,30 @@ uninstall: + -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT) + -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT) + -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT) + -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + -rm -f $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) + -rm -f $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) ++ -rm -f $(DESTDIR)$(SSH_LDAP_HELPER)$(EXEEXT) ++ -rm -f $(DESTDIR)$(SSH_LDAP_WRAPPER)$(EXEEXT) + -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 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8 + -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 + + regress-prep: + [ -d `pwd`/regress ] || mkdir -p `pwd`/regress + [ -d `pwd`/regress/unittests ] || mkdir -p `pwd`/regress/unittests + [ -d `pwd`/regress/unittests/test_helper ] || \ + mkdir -p `pwd`/regress/unittests/test_helper + [ -d `pwd`/regress/unittests/sshbuf ] || \ + mkdir -p `pwd`/regress/unittests/sshbuf +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -1644,16 +1644,116 @@ AC_ARG_WITH([audit], + AC_MSG_RESULT([no]) + ;; + *) + AC_MSG_ERROR([Unknown audit module $withval]) + ;; + esac ] + ) + ++# Check whether user wants LDAP support ++LDAP_MSG="no" ++INSTALL_SSH_LDAP_HELPER="" ++AC_ARG_WITH(ldap, ++ [ --with-ldap[[=PATH]] Enable LDAP pubkey support (optionally in PATH)], ++ [ ++ if test "x$withval" != "xno" ; then ++ ++ INSTALL_SSH_LDAP_HELPER="yes" ++ CPPFLAGS="$CPPFLAGS -DLDAP_DEPRECATED" ++ ++ if test "x$withval" != "xyes" ; then ++ CPPFLAGS="$CPPFLAGS -I${withval}/include" ++ LDFLAGS="$LDFLAGS -L${withval}/lib" ++ fi ++ ++ AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support]) ++ LDAP_MSG="yes" ++ ++ AC_CHECK_HEADERS(lber.h) ++ AC_CHECK_HEADERS(ldap.h, , AC_MSG_ERROR(could not locate )) ++ AC_CHECK_HEADERS(ldap_ssl.h) ++ ++ AC_ARG_WITH(ldap-lib, ++ [ --with-ldap-lib=type select ldap library [auto|netscape5|netscape4|netscape3|umich|openldap]]) ++ ++ if test -z "$with_ldap_lib"; then ++ with_ldap_lib=auto ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = umich -o $with_ldap_lib = openldap \); then ++ AC_CHECK_LIB(lber, main, LIBS="-llber $LIBS" found_ldap_lib=yes) ++ AC_CHECK_LIB(ldap, main, LIBS="-lldap $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape5 \); then ++ AC_CHECK_LIB(ldap50, main, LIBS="-lldap50 -lssldap50 -lssl3 -lnss3 -lnspr4 -lprldap50 -lplc4 -lplds4 $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape4 \); then ++ AC_CHECK_LIB(ldapssl41, main, LIBS="-lldapssl41 -lplc3 -lplds3 -lnspr3 $LIBS" found_ldap_lib=yes) ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldapssl40, main, LIBS="-lldapssl40 $LIBS" found_ldap_lib=yes) ++ fi ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldap41, main, LIBS="-lldap41 $LIBS" found_ldap_lib=yes) ++ fi ++ if test -z "$found_ldap_lib"; then ++ AC_CHECK_LIB(ldap40, main, LIBS="-lldap40 $LIBS" found_ldap_lib=yes) ++ fi ++ fi ++ ++ if test -z "$found_ldap_lib" -a \( $with_ldap_lib = auto -o $with_ldap_lib = netscape3 \); then ++ AC_CHECK_LIB(ldapssl30, main, LIBS="-lldapssl30 $LIBS" found_ldap_lib=yes) ++ fi ++ ++ if test -z "$found_ldap_lib"; then ++ AC_MSG_ERROR(could not locate a valid LDAP library) ++ fi ++ ++ AC_MSG_CHECKING([for working LDAP support]) ++ AC_TRY_COMPILE( ++ [#include ++ #include ], ++ [(void)ldap_init(0, 0);], ++ [AC_MSG_RESULT(yes)], ++ [ ++ AC_MSG_RESULT(no) ++ AC_MSG_ERROR([** Incomplete or missing ldap libraries **]) ++ ]) ++ AC_CHECK_FUNCS( \ ++ ldap_init \ ++ ldap_get_lderrno \ ++ ldap_set_lderrno \ ++ ldap_parse_result \ ++ ldap_memfree \ ++ ldap_controls_free \ ++ ldap_set_option \ ++ ldap_get_option \ ++ ldapssl_init \ ++ ldap_start_tls_s \ ++ ldap_pvt_tls_set_option \ ++ ldap_initialize \ ++ ) ++ AC_CHECK_FUNCS(ldap_set_rebind_proc, ++ AC_MSG_CHECKING([number arguments of ldap_set_rebind_proc]) ++ AC_TRY_COMPILE( ++ [#include ++ #include ], ++ [ldap_set_rebind_proc(0, 0, 0);], ++ [ac_cv_ldap_set_rebind_proc=3], ++ [ac_cv_ldap_set_rebind_proc=2]) ++ AC_MSG_RESULT($ac_cv_ldap_set_rebind_proc) ++ AC_DEFINE(LDAP_SET_REBIND_PROC_ARGS, $ac_cv_ldap_set_rebind_proc, [number arguments of ldap_set_rebind_proc]) ++ ) ++ fi ++ ] ++) ++AC_SUBST(INSTALL_SSH_LDAP_HELPER) ++ + AC_ARG_WITH([pie], + [ --with-pie Build Position Independent Executables if possible], [ + if test "x$withval" = "xno"; then + use_pie=no + fi + if test "x$withval" = "xyes"; then + use_pie=yes + fi +diff --git a/openssh-7.2p2/ldap-helper.c b/openssh-7.2p2/ldap-helper.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldap-helper.c +@@ -0,0 +1,155 @@ ++/* $OpenBSD: ssh-pka-ldap.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. All rights reserved. ++ * ++ * 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 "ldapincludes.h" ++#include "log.h" ++#include "misc.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include "ldapbody.h" ++#include ++#include ++ ++static int config_debug = 0; ++int config_exclusive_config_file = 0; ++static char *config_file_name = "/etc/ssh/ldap.conf"; ++static char *config_single_user = NULL; ++static int config_verbose = SYSLOG_LEVEL_VERBOSE; ++int config_warning_config_file = 0; ++extern char *__progname; ++ ++static void ++usage(void) ++{ ++ fprintf(stderr, "usage: %s [options]\n", ++ __progname); ++ fprintf(stderr, "Options:\n"); ++ fprintf(stderr, " -d Output the log messages to stderr.\n"); ++ fprintf(stderr, " -e Check the config file for unknown commands.\n"); ++ fprintf(stderr, " -f file Use alternate config file (default is /etc/ssh/ldap.conf).\n"); ++ fprintf(stderr, " -s user Do not demonize, send the user's key to stdout.\n"); ++ fprintf(stderr, " -v Increase verbosity of the debug output (implies -d).\n"); ++ fprintf(stderr, " -w Warn on unknown commands in the config file.\n"); ++ exit(1); ++} ++ ++/* ++ * Main program for the ssh pka ldap agent. ++ */ ++ ++int ++main(int ac, char **av) ++{ ++ int opt; ++ FILE *outfile = NULL; ++ ++ __progname = ssh_get_progname(av[0]); ++ ++ log_init(__progname, SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); ++ ++ /* ++ * Initialize option structure to indicate that no values have been ++ * set. ++ */ ++ initialize_options(); ++ ++ /* Parse command-line arguments. */ ++ while ((opt = getopt(ac, av, "def:s:vw")) != -1) { ++ switch (opt) { ++ case 'd': ++ config_debug = 1; ++ break; ++ ++ case 'e': ++ config_exclusive_config_file = 1; ++ config_warning_config_file = 1; ++ break; ++ ++ case 'f': ++ config_file_name = optarg; ++ break; ++ ++ case 's': ++ config_single_user = optarg; ++ outfile = fdopen (dup (fileno (stdout)), "w"); ++ break; ++ ++ case 'v': ++ config_debug = 1; ++ if (config_verbose < SYSLOG_LEVEL_DEBUG3) ++ config_verbose++; ++ break; ++ ++ case 'w': ++ config_warning_config_file = 1; ++ break; ++ ++ case '?': ++ default: ++ usage(); ++ break; ++ } ++ } ++ ++ /* Initialize loging */ ++ log_init(__progname, config_verbose, SYSLOG_FACILITY_AUTH, config_debug); ++ ++ if (ac != optind) ++ fatal ("illegal extra parameter %s", av[1]); ++ ++ /* Ensure that fds 0 and 2 are open or directed to /dev/null */ ++ if (config_debug == 0) ++ sanitise_stdfd(); ++ ++ /* Read config file */ ++ read_config_file(config_file_name); ++ fill_default_options(); ++ if (config_verbose == SYSLOG_LEVEL_DEBUG3) { ++ debug3 ("=== Configuration ==="); ++ dump_config(); ++ debug3 ("=== *** ==="); ++ } ++ ++ ldap_checkconfig(); ++ ldap_do_connect(); ++ ++ if (config_single_user) { ++ process_user (config_single_user, outfile); ++ } else { ++ usage(); ++ fatal ("Not yet implemented"); ++/* TODO ++ * open unix socket a run the loop on it ++ */ ++ } ++ ++ ldap_do_close(); ++ return 0; ++} ++ ++/* Ugly hack */ ++void *buffer_get_string(Buffer *b, u_int *l) { return NULL; } ++void buffer_put_string(Buffer *b, const void *f, u_int l) {} ++ +diff --git a/openssh-7.2p2/ldap-helper.h b/openssh-7.2p2/ldap-helper.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldap-helper.h +@@ -0,0 +1,32 @@ ++/* $OpenBSD: ldap-helper.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 LDAP_HELPER_H ++#define LDAP_HELPER_H ++ ++extern int config_exclusive_config_file; ++extern int config_warning_config_file; ++ ++#endif /* LDAP_HELPER_H */ +diff --git a/openssh-7.2p2/ldap.conf b/openssh-7.2p2/ldap.conf +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldap.conf +@@ -0,0 +1,88 @@ ++# $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 ++# LDAP backend ++# ++# see ssh-ldap.conf(5) ++# ++ ++# URI with your LDAP server name. This allows to use ++# Unix Domain Sockets to connect to a local LDAP Server. ++#uri ldap://127.0.0.1/ ++#uri ldaps://127.0.0.1/ ++#uri ldapi://%2fvar%2frun%2fldapi_sock/ ++# Note: %2f encodes the '/' used as directory separator ++ ++# Another way to specify your LDAP server is to provide an ++# host name and the port of our LDAP server. Host name ++# must be resolvable without using LDAP. ++# Multiple hosts may be specified, each separated by a ++# space. How long nss_ldap takes to failover depends on ++# whether your LDAP client library supports configurable ++# network or connect timeouts (see bind_timelimit). ++#host 127.0.0.1 ++ ++# The port. ++# Optional: default is 389. ++#port 389 ++ ++# The distinguished name to bind to the server with. ++# Optional: default is to bind anonymously. ++#binddn cn=openssh_keys,dc=example,dc=org ++ ++# The credentials to bind with. ++# Optional: default is no credential. ++#bindpw TopSecret ++ ++# The distinguished name of the search base. ++#base dc=example,dc=org ++ ++# The LDAP version to use (defaults to 3 ++# if supported by client library) ++#ldap_version 3 ++ ++# The search scope. ++#scope sub ++#scope one ++#scope base ++ ++# Search timelimit ++#timelimit 30 ++ ++# Bind/connect timelimit ++#bind_timelimit 30 ++ ++# Reconnect policy: hard (default) will retry connecting to ++# the software with exponential backoff, soft will fail ++# immediately. ++#bind_policy hard ++ ++# SSL setup, may be implied by URI also. ++#ssl no ++#ssl on ++#ssl start_tls ++ ++# OpenLDAP SSL options ++# Require and verify server certificate (yes/no) ++# Default is to use libldap's default behavior, which can be configured in ++# /etc/openldap/ldap.conf using the TLS_REQCERT setting. The default for ++# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes". ++#tls_checkpeer hard ++ ++# CA certificates for server certificate verification ++# At least one of these are required if tls_checkpeer is "yes" ++#tls_cacertfile /etc/ssl/ca.cert ++#tls_cacertdir /etc/pki/tls/certs ++ ++# Seed the PRNG if /dev/urandom is not provided ++#tls_randfile /var/run/egd-pool ++ ++# SSL cipher suite ++# See man ciphers for syntax ++#tls_ciphers TLSv1 ++ ++# Client certificate and key ++# Use these, if your server requires client authentication. ++#tls_cert ++#tls_key ++ +diff --git a/openssh-7.2p2/ldapbody.c b/openssh-7.2p2/ldapbody.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapbody.c +@@ -0,0 +1,494 @@ ++/* $OpenBSD: ldapbody.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 "ldapincludes.h" ++#include "log.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include "ldapmisc.h" ++#include "ldapbody.h" ++#include ++#include ++ ++#define LDAPSEARCH_FORMAT "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s)%s)" ++#define PUBKEYATTR "sshPublicKey" ++#define LDAP_LOGFILE "%s/ldap.%d" ++ ++static FILE *logfile = NULL; ++static LDAP *ld; ++ ++static char *attrs[] = { ++ PUBKEYATTR, ++ NULL ++}; ++ ++void ++ldap_checkconfig (void) ++{ ++#ifdef HAVE_LDAP_INITIALIZE ++ if (options.host == NULL && options.uri == NULL) ++#else ++ if (options.host == NULL) ++#endif ++ fatal ("missing \"host\" in config file"); ++} ++ ++#if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) ++static int ++_rebind_proc (LDAP * ld, LDAP_CONST char *url, int request, ber_int_t msgid) ++{ ++ struct timeval timeout; ++ int rc; ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ LDAPMessage *result; ++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ ++ ++ debug2 ("Doing LDAP rebind to %s", options.binddn); ++ if (options.ssl == SSL_START_TLS) { ++ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) { ++ error ("ldap_starttls_s: %s", ldap_err2string (rc)); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ } ++ ++#if !defined(HAVE_LDAP_PARSE_RESULT) || !defined(HAVE_LDAP_CONTROLS_FREE) ++ return ldap_simple_bind_s (ld, options.binddn, options.bindpw); ++#else ++ if (ldap_simple_bind(ld, options.binddn, options.bindpw) < 0) ++ fatal ("ldap_simple_bind %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); ++ ++ timeout.tv_sec = options.bind_timelimit; ++ timeout.tv_usec = 0; ++ result = NULL; ++ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { ++ error ("ldap_result %s", ldap_err2string (ldap_get_lderrno (ld, 0, 0))); ++ ldap_msgfree (result); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ debug3 ("LDAP rebind to %s succesfull", options.binddn); ++ return rc; ++#endif ++} ++#else ++ ++static int ++_rebind_proc (LDAP * ld, char **whop, char **credp, int *methodp, int freeit) ++{ ++ if (freeit) ++ return LDAP_SUCCESS; ++ ++ *whop = strdup (options.binddn); ++ *credp = strdup (options.bindpw); ++ *methodp = LDAP_AUTH_SIMPLE; ++ debug2 ("Doing LDAP rebind for %s", *whop); ++ return LDAP_SUCCESS; ++} ++#endif ++ ++void ++ldap_do_connect(void) ++{ ++ int rc, msgid, ld_errno = 0; ++ struct timeval timeout; ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ int parserc; ++ LDAPMessage *result; ++ LDAPControl **controls; ++ int reconnect = 0; ++#endif /* HAVE_LDAP_PARSE_RESULT && HAVE_LDAP_CONTROLS_FREE */ ++ ++ debug ("LDAP do connect"); ++ ++retry: ++ if (reconnect) { ++ debug3 ("Reconnecting with ld_errno %d", ld_errno); ++ if (options.bind_policy == 0 || ++ (ld_errno != LDAP_SERVER_DOWN && ld_errno != LDAP_TIMEOUT) || ++ reconnect > 5) ++ fatal ("Cannot connect to LDAP server"); ++ ++ if (reconnect > 1) ++ sleep (reconnect - 1); ++ ++ if (ld != NULL) { ++ ldap_unbind (ld); ++ ld = NULL; ++ } ++ logit("reconnecting to LDAP server..."); ++ } ++ ++ if (ld == NULL) { ++ int rc; ++ struct timeval tv; ++ ++#ifdef HAVE_LDAP_SET_OPTION ++ if (options.debug > 0) { ++#ifdef LBER_OPT_LOG_PRINT_FILE ++ if (options.logdir) { ++ char *logfilename; ++ int logfilenamelen; ++ ++ logfilenamelen = strlen (LDAP_LOGFILE) + strlen ("000000") + strlen (options.logdir); ++ logfilename = xmalloc (logfilenamelen); ++ snprintf (logfilename, logfilenamelen, LDAP_LOGFILE, options.logdir, (int) getpid ()); ++ logfilename[logfilenamelen - 1] = 0; ++ if ((logfile = fopen (logfilename, "a")) == NULL) ++ fatal ("cannot append to %s: %s", logfilename, strerror (errno)); ++ debug3 ("LDAP debug into %s", logfilename); ++ free (logfilename); ++ ber_set_option (NULL, LBER_OPT_LOG_PRINT_FILE, logfile); ++ } ++#endif ++ if (options.debug) { ++#ifdef LBER_OPT_DEBUG_LEVEL ++ ber_set_option (NULL, LBER_OPT_DEBUG_LEVEL, &options.debug); ++#endif /* LBER_OPT_DEBUG_LEVEL */ ++#ifdef LDAP_OPT_DEBUG_LEVEL ++ ldap_set_option (NULL, LDAP_OPT_DEBUG_LEVEL, &options.debug); ++#endif /* LDAP_OPT_DEBUG_LEVEL */ ++ debug3 ("Set LDAP debug to %d", options.debug); ++ } ++ } ++#endif /* HAVE_LDAP_SET_OPTION */ ++ ++ ld = NULL; ++#ifdef HAVE_LDAPSSL_INIT ++ if (options.host != NULL) { ++ if (options.ssl_on == SSL_LDAPS) { ++ if ((rc = ldapssl_client_init (options.sslpath, NULL)) != LDAP_SUCCESS) ++ fatal ("ldapssl_client_init %s", ldap_err2string (rc)); ++ debug3 ("LDAPssl client init"); ++ } ++ ++ if (options.ssl_on != SSL_OFF) { ++ if ((ld = ldapssl_init (options.host, options.port, TRUE)) == NULL) ++ fatal ("ldapssl_init failed"); ++ debug3 ("LDAPssl init"); ++ } ++ } ++#endif /* HAVE_LDAPSSL_INIT */ ++ ++ /* continue with opening */ ++ if (ld == NULL) { ++#if defined (HAVE_LDAP_START_TLS_S) || (defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)) ++ /* Some global TLS-specific options need to be set before we create our ++ * session context, so we set them here. */ ++ ++#ifdef LDAP_OPT_X_TLS_RANDOM_FILE ++ /* rand file */ ++ if (options.tls_randfile != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_RANDOM_FILE, ++ options.tls_randfile)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_RANDOM_FILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS random file %s", options.tls_randfile); ++ } ++#endif /* LDAP_OPT_X_TLS_RANDOM_FILE */ ++ ++ /* ca cert file */ ++ if (options.tls_cacertfile != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, ++ options.tls_cacertfile)) != LDAP_SUCCESS) ++ error ("ldap_set_option(LDAP_OPT_X_TLS_CACERTFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS CA cert file %s ", options.tls_cacertfile); ++ } ++ ++ /* ca cert directory */ ++ if (options.tls_cacertdir != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTDIR, ++ options.tls_cacertdir)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CACERTDIR): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS CA cert dir %s ", options.tls_cacertdir); ++ } ++ ++ /* require cert? */ ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, ++ &options.tls_checkpeer)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS check peer to %d ", options.tls_checkpeer); ++ ++ /* set cipher suite, certificate and private key: */ ++ if (options.tls_ciphers != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CIPHER_SUITE, ++ options.tls_ciphers)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CIPHER_SUITE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS ciphers to %s ", options.tls_ciphers); ++ } ++ ++ /* cert file */ ++ if (options.tls_cert != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, ++ options.tls_cert)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_CERTFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS cert file %s ", options.tls_cert); ++ } ++ ++ /* key file */ ++ if (options.tls_key != NULL) { ++ if ((rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, ++ options.tls_key)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS_KEYFILE): %s", ++ ldap_err2string (rc)); ++ debug3 ("Set TLS key file %s ", options.tls_key); ++ } ++#endif ++#ifdef HAVE_LDAP_INITIALIZE ++ if (options.uri != NULL) { ++ if ((rc = ldap_initialize (&ld, options.uri)) != LDAP_SUCCESS) ++ fatal ("ldap_initialize %s", ldap_err2string (rc)); ++ debug3 ("LDAP initialize %s", options.uri); ++ } ++ } ++#endif /* HAVE_LDAP_INTITIALIZE */ ++ ++ /* continue with opening */ ++ if ((ld == NULL) && (options.host != NULL)) { ++#ifdef HAVE_LDAP_INIT ++ if ((ld = ldap_init (options.host, options.port)) == NULL) ++ fatal ("ldap_init failed"); ++ debug3 ("LDAP init %s:%d", options.host, options.port); ++#else ++ if ((ld = ldap_open (options.host, options.port)) == NULL) ++ fatal ("ldap_open failed"); ++ debug3 ("LDAP open %s:%d", options.host, options.port); ++#endif /* HAVE_LDAP_INIT */ ++ } ++ ++ if (ld == NULL) ++ fatal ("no way to open ldap"); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) ++ if (options.ssl == SSL_LDAPS) { ++ if ((rc = ldap_set_option (ld, LDAP_OPT_X_TLS, &options.tls_checkpeer)) != LDAP_SUCCESS) ++ fatal ("ldap_set_option(LDAP_OPT_X_TLS) %s", ldap_err2string (rc)); ++ debug3 ("LDAP set LDAP_OPT_X_TLS_%d", options.tls_checkpeer); ++ } ++#endif /* LDAP_OPT_X_TLS */ ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_PROTOCOL_VERSION) ++ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, ++ &options.ldap_version); ++#else ++ ld->ld_version = options.ldap_version; ++#endif ++ debug3 ("LDAP set version to %d", options.ldap_version); ++ ++#if LDAP_SET_REBIND_PROC_ARGS == 3 ++ ldap_set_rebind_proc (ld, _rebind_proc, NULL); ++#elif LDAP_SET_REBIND_PROC_ARGS == 2 ++ ldap_set_rebind_proc (ld, _rebind_proc); ++#else ++#warning unknown LDAP_SET_REBIND_PROC_ARGS ++#endif ++ debug3 ("LDAP set rebind proc"); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_DEREF) ++ (void) ldap_set_option (ld, LDAP_OPT_DEREF, &options.deref); ++#else ++ ld->ld_deref = options.deref; ++#endif ++ debug3 ("LDAP set deref to %d", options.deref); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_TIMELIMIT) ++ (void) ldap_set_option (ld, LDAP_OPT_TIMELIMIT, ++ &options.timelimit); ++#else ++ ld->ld_timelimit = options.timelimit; ++#endif ++ debug3 ("LDAP set timelimit to %d", options.timelimit); ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_X_OPT_CONNECT_TIMEOUT) ++ /* ++ * This is a new option in the Netscape SDK which sets ++ * the TCP connect timeout. For want of a better value, ++ * we use the bind_timelimit to control this. ++ */ ++ timeout = options.bind_timelimit * 1000; ++ (void) ldap_set_option (ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout); ++ debug3 ("LDAP set opt connect timeout to %d", timeout); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_NETWORK_TIMEOUT) ++ tv.tv_sec = options.bind_timelimit; ++ tv.tv_usec = 0; ++ (void) ldap_set_option (ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); ++ debug3 ("LDAP set opt network timeout to %ld.0", tv.tv_sec); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_REFERRALS) ++ (void) ldap_set_option (ld, LDAP_OPT_REFERRALS, ++ options.referrals ? LDAP_OPT_ON : LDAP_OPT_OFF); ++ debug3 ("LDAP set referrals to %d", options.referrals); ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_RESTART) ++ (void) ldap_set_option (ld, LDAP_OPT_RESTART, ++ options.restart ? LDAP_OPT_ON : LDAP_OPT_OFF); ++ debug3 ("LDAP set restart to %d", options.restart); ++#endif ++ ++#ifdef HAVE_LDAP_START_TLS_S ++ if (options.ssl == SSL_START_TLS) { ++ int version; ++ ++ if (ldap_get_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version) ++ == LDAP_SUCCESS) { ++ if (version < LDAP_VERSION3) { ++ version = LDAP_VERSION3; ++ (void) ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, ++ &version); ++ debug3 ("LDAP set version to %d", version); ++ } ++ } ++ ++ if ((rc = ldap_start_tls_s (ld, NULL, NULL)) != LDAP_SUCCESS) ++ fatal ("ldap_starttls_s: %s", ldap_err2string (rc)); ++ debug3 ("LDAP start TLS"); ++ } ++#endif /* HAVE_LDAP_START_TLS_S */ ++ } ++ ++ if ((msgid = ldap_simple_bind (ld, options.binddn, ++ options.bindpw)) == -1) { ++ ld_errno = ldap_get_lderrno (ld, 0, 0); ++ ++ error ("ldap_simple_bind %s", ldap_err2string (ld_errno)); ++ reconnect++; ++ goto retry; ++ } ++ debug3 ("LDAP simple bind (%s)", options.binddn); ++ ++ timeout.tv_sec = options.bind_timelimit; ++ timeout.tv_usec = 0; ++ if ((rc = ldap_result (ld, msgid, FALSE, &timeout, &result)) < 1) { ++ ld_errno = ldap_get_lderrno (ld, 0, 0); ++ ++ error ("ldap_result %s", ldap_err2string (ld_errno)); ++ reconnect++; ++ goto retry; ++ } ++ debug3 ("LDAP result in time"); ++ ++#if defined(HAVE_LDAP_PARSE_RESULT) && defined(HAVE_LDAP_CONTROLS_FREE) ++ controls = NULL; ++ if ((parserc = ldap_parse_result (ld, result, &rc, 0, 0, 0, &controls, TRUE)) != LDAP_SUCCESS) ++ fatal ("ldap_parse_result %s", ldap_err2string (parserc)); ++ debug3 ("LDAP parse result OK"); ++ ++ if (controls != NULL) { ++ ldap_controls_free (controls); ++ } ++#else ++ rc = ldap_result2error (session->ld, result, TRUE); ++#endif ++ if (rc != LDAP_SUCCESS) ++ fatal ("error trying to bind as user \"%s\" (%s)", ++ options.binddn, ldap_err2string (rc)); ++ ++ debug2 ("LDAP do connect OK"); ++} ++ ++void ++process_user (const char *user, FILE *output) ++{ ++ LDAPMessage *res, *e; ++ char *buffer; ++ int bufflen, rc, i; ++ struct timeval timeout; ++ ++ debug ("LDAP process user"); ++ ++ /* quick check for attempts to be evil */ ++ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) || ++ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) { ++ logit ("illegal user name %s not processed", user); ++ return; ++ } ++ ++ /* build filter for LDAP request */ ++ bufflen = strlen (LDAPSEARCH_FORMAT) + strlen (user); ++ if (options.ssh_filter != NULL) ++ bufflen += strlen (options.ssh_filter); ++ buffer = xmalloc (bufflen); ++ snprintf(buffer, bufflen, LDAPSEARCH_FORMAT, user, (options.ssh_filter != NULL) ? options.ssh_filter : NULL); ++ buffer[bufflen - 1] = 0; ++ ++ debug3 ("LDAP search scope = %d %s", options.scope, buffer); ++ ++ timeout.tv_sec = options.timelimit; ++ timeout.tv_usec = 0; ++ if ((rc = ldap_search_st(ld, options.base, options.scope, buffer, attrs, 0, &timeout, &res)) != LDAP_SUCCESS) { ++ error ("ldap_search_st(): %s", ldap_err2string (rc)); ++ free (buffer); ++ return; ++ } ++ ++ /* free */ ++ free (buffer); ++ ++ for (e = ldap_first_entry(ld, res); e != NULL; e = ldap_next_entry(ld, e)) { ++ int num; ++ struct berval **keys; ++ ++ keys = ldap_get_values_len(ld, e, PUBKEYATTR); ++ num = ldap_count_values_len(keys); ++ for (i = 0 ; i < num ; i++) { ++ char *cp; //, *options = NULL; ++ ++ for (cp = keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++); ++ if (!*cp || *cp == '\n' || *cp == '#') ++ continue; ++ ++ /* We have found the desired key. */ ++ fprintf (output, "%s\n", keys[i]->bv_val); ++ } ++ ++ ldap_value_free_len(keys); ++ } ++ ++ ldap_msgfree(res); ++ debug2 ("LDAP process user finished"); ++} ++ ++void ++ldap_do_close(void) ++{ ++ int rc; ++ ++ debug ("LDAP do close"); ++ if ((rc = ldap_unbind_ext(ld, NULL, NULL)) != LDAP_SUCCESS) ++ fatal ("ldap_unbind_ext: %s", ++ ldap_err2string (rc)); ++ ++ ld = NULL; ++ debug2 ("LDAP do close OK"); ++ return; ++} ++ +diff --git a/openssh-7.2p2/ldapbody.h b/openssh-7.2p2/ldapbody.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapbody.h +@@ -0,0 +1,37 @@ ++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 LDAPBODY_H ++#define LDAPBODY_H ++ ++#include ++ ++void ldap_checkconfig(void); ++void ldap_do_connect(void); ++void process_user(const char *, FILE *); ++void ldap_do_close(void); ++ ++#endif /* LDAPBODY_H */ ++ +diff --git a/openssh-7.2p2/ldapconf.c b/openssh-7.2p2/ldapconf.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapconf.c +@@ -0,0 +1,711 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 "ldapincludes.h" ++#include "ldap-helper.h" ++#include "log.h" ++#include "misc.h" ++#include "xmalloc.h" ++#include "ldapconf.h" ++#include ++#include ++ ++/* Keyword tokens. */ ++ ++typedef enum { ++ lBadOption, ++ lHost, lURI, lBase, lBindDN, lBindPW, lRootBindDN, ++ lScope, lDeref, lPort, lTimeLimit, lBind_TimeLimit, ++ lLdap_Version, lBind_Policy, lSSLPath, lSSL, lReferrals, ++ lRestart, lTLS_CheckPeer, lTLS_CaCertFile, ++ lTLS_CaCertDir, lTLS_Ciphers, lTLS_Cert, lTLS_Key, ++ lTLS_RandFile, lLogDir, lDebug, lSSH_Filter, ++ lDeprecated, lUnsupported ++} OpCodes; ++ ++/* Textual representations of the tokens. */ ++ ++static struct { ++ const char *name; ++ OpCodes opcode; ++} keywords[] = { ++ { "URI", lURI }, ++ { "Base", lBase }, ++ { "BindDN", lBindDN }, ++ { "BindPW", lBindPW }, ++ { "RootBindDN", lRootBindDN }, ++ { "Host", lHost }, ++ { "Port", lPort }, ++ { "Scope", lScope }, ++ { "Deref", lDeref }, ++ { "TimeLimit", lTimeLimit }, ++ { "TimeOut", lTimeLimit }, ++ { "Bind_Timelimit", lBind_TimeLimit }, ++ { "Network_TimeOut", lBind_TimeLimit }, ++/* ++ * Todo ++ * SIZELIMIT ++ */ ++ { "Ldap_Version", lLdap_Version }, ++ { "Version", lLdap_Version }, ++ { "Bind_Policy", lBind_Policy }, ++ { "SSLPath", lSSLPath }, ++ { "SSL", lSSL }, ++ { "Referrals", lReferrals }, ++ { "Restart", lRestart }, ++ { "TLS_CheckPeer", lTLS_CheckPeer }, ++ { "TLS_ReqCert", lTLS_CheckPeer }, ++ { "TLS_CaCertFile", lTLS_CaCertFile }, ++ { "TLS_CaCert", lTLS_CaCertFile }, ++ { "TLS_CaCertDir", lTLS_CaCertDir }, ++ { "TLS_Ciphers", lTLS_Ciphers }, ++ { "TLS_Cipher_Suite", lTLS_Ciphers }, ++ { "TLS_Cert", lTLS_Cert }, ++ { "TLS_Certificate", lTLS_Cert }, ++ { "TLS_Key", lTLS_Key }, ++ { "TLS_RandFile", lTLS_RandFile }, ++/* ++ * Todo ++ * TLS_CRLCHECK ++ * TLS_CRLFILE ++ */ ++ { "LogDir", lLogDir }, ++ { "Debug", lDebug }, ++ { "SSH_Filter", lSSH_Filter }, ++ { NULL, lBadOption } ++}; ++ ++/* Configuration ptions. */ ++ ++Options options; ++ ++/* ++ * Returns the number of the token pointed to by cp or oBadOption. ++ */ ++ ++static OpCodes ++parse_token(const char *cp, const char *filename, int linenum) ++{ ++ u_int i; ++ ++ for (i = 0; keywords[i].name; i++) ++ if (strcasecmp(cp, keywords[i].name) == 0) ++ return keywords[i].opcode; ++ ++ if (config_warning_config_file) ++ logit("%s: line %d: Bad configuration option: %s", ++ filename, linenum, cp); ++ return lBadOption; ++} ++ ++/* ++ * Processes a single option line as used in the configuration files. This ++ * only sets those values that have not already been set. ++ */ ++#define WHITESPACE " \t\r\n" ++ ++static int ++process_config_line(char *line, const char *filename, int linenum) ++{ ++ char *s, **charptr, **xstringptr, *endofnumber, *keyword, *arg; ++ char *rootbinddn = NULL; ++ int opcode, *intptr, value; ++ size_t len; ++ ++ /* Strip trailing whitespace */ ++ for (len = strlen(line) - 1; len > 0; len--) { ++ if (strchr(WHITESPACE, line[len]) == NULL) ++ break; ++ line[len] = '\0'; ++ } ++ ++ s = line; ++ /* Get the keyword. (Each line is supposed to begin with a keyword). */ ++ if ((keyword = strdelim(&s)) == NULL) ++ return 0; ++ /* Ignore leading whitespace. */ ++ if (*keyword == '\0') ++ keyword = strdelim(&s); ++ if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') ++ return 0; ++ ++ opcode = parse_token(keyword, filename, linenum); ++ ++ switch (opcode) { ++ case lBadOption: ++ /* don't panic, but count bad options */ ++ return -1; ++ /* NOTREACHED */ ++ ++ case lHost: ++ xstringptr = &options.host; ++parse_xstring: ++ if (!s || *s == '\0') ++ fatal("%s line %d: missing dn",filename,linenum); ++ if (*xstringptr == NULL) ++ *xstringptr = xstrdup(s); ++ return 0; ++ ++ case lURI: ++ xstringptr = &options.uri; ++ goto parse_xstring; ++ ++ case lBase: ++ xstringptr = &options.base; ++ goto parse_xstring; ++ ++ case lBindDN: ++ xstringptr = &options.binddn; ++ goto parse_xstring; ++ ++ case lBindPW: ++ charptr = &options.bindpw; ++parse_string: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", filename, linenum); ++ if (*charptr == NULL) ++ *charptr = xstrdup(arg); ++ break; ++ ++ case lRootBindDN: ++ xstringptr = &rootbinddn; ++ goto parse_xstring; ++ ++ case lScope: ++ intptr = &options.scope; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing sub/one/base argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "sub") == 0 || ++ strcasecmp(arg, "subtree") == 0) ++ value = LDAP_SCOPE_SUBTREE; ++ else if (strcasecmp(arg, "one") == 0) ++ value = LDAP_SCOPE_ONELEVEL; ++ else if (strcasecmp(arg, "base") == 0) ++ value = LDAP_SCOPE_BASE; ++ else ++ fatal("%.200s line %d: Bad sub/one/base argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lDeref: ++ intptr = &options.scope; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing never/searching/finding/always argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (!strcasecmp(arg, "never")) ++ value = LDAP_DEREF_NEVER; ++ else if (!strcasecmp(arg, "searching")) ++ value = LDAP_DEREF_SEARCHING; ++ else if (!strcasecmp(arg, "finding")) ++ value = LDAP_DEREF_FINDING; ++ else if (!strcasecmp(arg, "always")) ++ value = LDAP_DEREF_ALWAYS; ++ else ++ fatal("%.200s line %d: Bad never/searching/finding/always argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lPort: ++ intptr = &options.port; ++parse_int: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing argument.", filename, linenum); ++ if (arg[0] < '0' || arg[0] > '9') ++ fatal("%.200s line %d: Bad number.", filename, linenum); ++ ++ /* Octal, decimal, or hex format? */ ++ value = strtol(arg, &endofnumber, 0); ++ if (arg == endofnumber) ++ fatal("%.200s line %d: Bad number.", filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lTimeLimit: ++ intptr = &options.timelimit; ++parse_time: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: missing time value.", ++ filename, linenum); ++ if ((value = convtime(arg)) == -1) ++ fatal("%s line %d: invalid time value.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lBind_TimeLimit: ++ intptr = &options.bind_timelimit; ++ goto parse_time; ++ ++ case lLdap_Version: ++ intptr = &options.ldap_version; ++ goto parse_int; ++ ++ case lBind_Policy: ++ intptr = &options.bind_policy; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing soft/hard argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "hard") == 0 || ++ strcasecmp(arg, "hard_open") == 0 || ++ strcasecmp(arg, "hard_init") == 0) ++ value = 1; ++ else if (strcasecmp(arg, "soft") == 0) ++ value = 0; ++ else ++ fatal("%.200s line %d: Bad soft/hard argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ break; ++ ++ case lSSLPath: ++ charptr = &options.sslpath; ++ goto parse_string; ++ ++ case lSSL: ++ intptr = &options.ssl; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing yes/no/start_tls argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "yes") == 0 || ++ strcasecmp(arg, "true") == 0 || ++ strcasecmp(arg, "on") == 0) ++ value = SSL_LDAPS; ++ else if (strcasecmp(arg, "no") == 0 || ++ strcasecmp(arg, "false") == 0 || ++ strcasecmp(arg, "off") == 0) ++ value = SSL_OFF; ++ else if (!strcasecmp (arg, "start_tls")) ++ value = SSL_START_TLS; ++ else ++ fatal("%.200s line %d: Bad yes/no/start_tls argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lReferrals: ++ intptr = &options.referrals; ++parse_flag: ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing yes/no argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "yes") == 0 || ++ strcasecmp(arg, "true") == 0 || ++ strcasecmp(arg, "on") == 0) ++ value = 1; ++ else if (strcasecmp(arg, "no") == 0 || ++ strcasecmp(arg, "false") == 0 || ++ strcasecmp(arg, "off") == 0) ++ value = 0; ++ else ++ fatal("%.200s line %d: Bad yes/no argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ *intptr = value; ++ break; ++ ++ case lRestart: ++ intptr = &options.restart; ++ goto parse_flag; ++ ++ case lTLS_CheckPeer: ++ intptr = &options.tls_checkpeer; ++ arg = strdelim(&s); ++ if (!arg || *arg == '\0') ++ fatal("%.200s line %d: Missing never/hard/demand/alow/try argument.", ++ filename, linenum); ++ value = 0; /* To avoid compiler warning... */ ++ if (strcasecmp(arg, "never") == 0 || ++ strcasecmp(arg, "no") == 0 || ++ strcasecmp(arg, "false") == 0 || ++ strcasecmp(arg, "off") == 0) ++ value = LDAP_OPT_X_TLS_NEVER; ++ else if (strcasecmp(arg, "hard") == 0 || ++ strcasecmp(arg, "yes") == 0 || ++ strcasecmp(arg, "true") == 0 || ++ strcasecmp(arg, "on") == 0) ++ value = LDAP_OPT_X_TLS_HARD; ++ else if (strcasecmp(arg, "demand") == 0) ++ value = LDAP_OPT_X_TLS_DEMAND; ++ else if (strcasecmp(arg, "allow") == 0) ++ value = LDAP_OPT_X_TLS_ALLOW; ++ else if (strcasecmp(arg, "try") == 0) ++ value = LDAP_OPT_X_TLS_TRY; ++ else ++ fatal("%.200s line %d: Bad never/hard/demand/alow/try argument.", ++ filename, linenum); ++ if (*intptr == -1) ++ break; ++ ++ case lTLS_CaCertFile: ++ charptr = &options.tls_cacertfile; ++ goto parse_string; ++ ++ case lTLS_CaCertDir: ++ charptr = &options.tls_cacertdir; ++ goto parse_string; ++ ++ case lTLS_Ciphers: ++ xstringptr = &options.tls_ciphers; ++ goto parse_xstring; ++ ++ case lTLS_Cert: ++ charptr = &options.tls_cert; ++ goto parse_string; ++ ++ case lTLS_Key: ++ charptr = &options.tls_key; ++ goto parse_string; ++ ++ case lTLS_RandFile: ++ charptr = &options.tls_randfile; ++ goto parse_string; ++ ++ case lLogDir: ++ charptr = &options.logdir; ++ goto parse_string; ++ ++ case lDebug: ++ intptr = &options.debug; ++ goto parse_int; ++ ++ case lSSH_Filter: ++ xstringptr = &options.ssh_filter; ++ goto parse_xstring; ++ ++ case lDeprecated: ++ debug("%s line %d: Deprecated option \"%s\"", ++ filename, linenum, keyword); ++ return 0; ++ ++ case lUnsupported: ++ error("%s line %d: Unsupported option \"%s\"", ++ filename, linenum, keyword); ++ return 0; ++ ++ default: ++ fatal("process_config_line: Unimplemented opcode %d", opcode); ++ } ++ ++ /* Check that there is no garbage at end of line. */ ++ if ((arg = strdelim(&s)) != NULL && *arg != '\0') { ++ fatal("%.200s line %d: garbage at end of line; \"%.200s\".", ++ filename, linenum, arg); ++ } ++ return 0; ++} ++ ++/* ++ * Reads the config file and modifies the options accordingly. Options ++ * should already be initialized before this call. This never returns if ++ * there is an error. If the file does not exist, this returns 0. ++ */ ++ ++void ++read_config_file(const char *filename) ++{ ++ FILE *f; ++ char line[1024]; ++ int active, linenum; ++ int bad_options = 0; ++ struct stat sb; ++ ++ if ((f = fopen(filename, "r")) == NULL) ++ fatal("fopen %s: %s", filename, strerror(errno)); ++ ++ if (fstat(fileno(f), &sb) == -1) ++ fatal("fstat %s: %s", filename, strerror(errno)); ++ if (((sb.st_uid != 0 && sb.st_uid != getuid()) || ++ (sb.st_mode & 022) != 0)) ++ fatal("Bad owner or permissions on %s", filename); ++ ++ debug("Reading configuration data %.200s", filename); ++ ++ /* ++ * 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. */ ++ linenum++; ++ if (process_config_line(line, filename, linenum) != 0) ++ bad_options++; ++ } ++ fclose(f); ++ if ((bad_options > 0) && config_exclusive_config_file) ++ fatal("%s: terminating, %d bad configuration options", ++ filename, bad_options); ++} ++ ++/* ++ * Initializes options to special values that indicate that they have not yet ++ * been set. Read_config_file will only set options with this value. Options ++ * are processed in the following order: command line, user config file, ++ * system config file. Last, fill_default_options is called. ++ */ ++ ++void ++initialize_options(void) ++{ ++ memset(&options, 'X', sizeof(options)); ++ options.host = NULL; ++ options.uri = NULL; ++ options.base = NULL; ++ options.binddn = NULL; ++ options.bindpw = NULL; ++ options.scope = -1; ++ options.deref = -1; ++ options.port = -1; ++ options.timelimit = -1; ++ options.bind_timelimit = -1; ++ options.ldap_version = -1; ++ options.bind_policy = -1; ++ options.sslpath = NULL; ++ options.ssl = -1; ++ options.referrals = -1; ++ options.restart = -1; ++ options.tls_checkpeer = -1; ++ options.tls_cacertfile = NULL; ++ options.tls_cacertdir = NULL; ++ options.tls_ciphers = NULL; ++ options.tls_cert = NULL; ++ options.tls_key = NULL; ++ options.tls_randfile = NULL; ++ options.logdir = NULL; ++ options.debug = -1; ++ options.ssh_filter = NULL; ++} ++ ++/* ++ * Called after processing other sources of option data, this fills those ++ * options for which no value has been specified with their default values. ++ */ ++ ++void ++fill_default_options(void) ++{ ++ if (options.uri != NULL) { ++ LDAPURLDesc *ludp; ++ ++ if (ldap_url_parse(options.uri, &ludp) == LDAP_SUCCESS) { ++ if (options.ssl == -1) { ++ if (strcmp(ludp->lud_scheme, "ldap") == 0) ++ options.ssl = 2; ++ if (strcmp(ludp->lud_scheme, "ldapi") == 0) ++ options.ssl = 0; ++ else if (strcmp(ludp->lud_scheme, "ldaps") == 0) ++ options.ssl = 1; ++ } ++ if (options.host == NULL) ++ options.host = xstrdup (ludp->lud_host); ++ if (options.port == -1) ++ options.port = ludp->lud_port; ++ ++ ldap_free_urldesc (ludp); ++ } ++ } ++ if (options.ssl == -1) ++ options.ssl = SSL_START_TLS; ++ if (options.port == -1) ++ options.port = (options.ssl == 0) ? 389 : 636; ++ if (options.uri == NULL) { ++ int len; ++#define MAXURILEN 4096 ++ ++ options.uri = xmalloc (MAXURILEN); ++ len = snprintf(options.uri, MAXURILEN, "ldap%s://%s:%d", ++ (options.ssl == 0) ? "" : "s", options.host, options.port); ++ options.uri[MAXURILEN - 1] = 0; ++ options.uri = xreallocarray(options.uri, len + 1, 1); ++ } ++ if (options.binddn == NULL) ++ options.binddn = ""; ++ if (options.bindpw == NULL) ++ options.bindpw = ""; ++ if (options.scope == -1) ++ options.scope = LDAP_SCOPE_SUBTREE; ++ if (options.deref == -1) ++ options.deref = LDAP_DEREF_NEVER; ++ if (options.timelimit == -1) ++ options.timelimit = 10; ++ if (options.bind_timelimit == -1) ++ options.bind_timelimit = 10; ++ if (options.ldap_version == -1) ++ options.ldap_version = 3; ++ if (options.bind_policy == -1) ++ options.bind_policy = 1; ++ if (options.referrals == -1) ++ options.referrals = 1; ++ if (options.restart == -1) ++ options.restart = 1; ++ if (options.tls_checkpeer == -1) ++ options.tls_checkpeer = LDAP_OPT_X_TLS_HARD; ++ if (options.debug == -1) ++ options.debug = 0; ++ if (options.ssh_filter == NULL) ++ options.ssh_filter = ""; ++} ++ ++static const char * ++lookup_opcode_name(OpCodes code) ++{ ++ u_int i; ++ ++ for (i = 0; keywords[i].name != NULL; i++) ++ if (keywords[i].opcode == code) ++ return(keywords[i].name); ++ return "UNKNOWN"; ++} ++ ++static void ++dump_cfg_string(OpCodes code, const char *val) ++{ ++ if (val == NULL) ++ debug3("%s ", lookup_opcode_name(code)); ++ else ++ debug3("%s %s", lookup_opcode_name(code), val); ++} ++ ++static void ++dump_cfg_int(OpCodes code, int val) ++{ ++ if (val == -1) ++ debug3("%s ", lookup_opcode_name(code)); ++ else ++ debug3("%s %d", lookup_opcode_name(code), val); ++} ++ ++struct names { ++ int value; ++ char *name; ++}; ++ ++static void ++dump_cfg_namedint(OpCodes code, int val, struct names *names) ++{ ++ u_int i; ++ ++ if (val == -1) ++ debug3("%s ", lookup_opcode_name(code)); ++ else { ++ for (i = 0; names[i].value != -1; i++) ++ if (names[i].value == val) { ++ debug3("%s %s", lookup_opcode_name(code), names[i].name); ++ return; ++ } ++ debug3("%s unknown: %d", lookup_opcode_name(code), val); ++ } ++} ++ ++static struct names _yesnotls[] = { ++ { 0, "No" }, ++ { 1, "Yes" }, ++ { 2, "Start_TLS" }, ++ { -1, NULL }}; ++ ++static struct names _scope[] = { ++ { LDAP_SCOPE_BASE, "Base" }, ++ { LDAP_SCOPE_ONELEVEL, "One" }, ++ { LDAP_SCOPE_SUBTREE, "Sub"}, ++ { -1, NULL }}; ++ ++static struct names _deref[] = { ++ { LDAP_DEREF_NEVER, "Never" }, ++ { LDAP_DEREF_SEARCHING, "Searching" }, ++ { LDAP_DEREF_FINDING, "Finding" }, ++ { LDAP_DEREF_ALWAYS, "Always" }, ++ { -1, NULL }}; ++ ++static struct names _yesno[] = { ++ { 0, "No" }, ++ { 1, "Yes" }, ++ { -1, NULL }}; ++ ++static struct names _bindpolicy[] = { ++ { 0, "Soft" }, ++ { 1, "Hard" }, ++ { -1, NULL }}; ++ ++static struct names _checkpeer[] = { ++ { LDAP_OPT_X_TLS_NEVER, "Never" }, ++ { LDAP_OPT_X_TLS_HARD, "Hard" }, ++ { LDAP_OPT_X_TLS_DEMAND, "Demand" }, ++ { LDAP_OPT_X_TLS_ALLOW, "Allow" }, ++ { LDAP_OPT_X_TLS_TRY, "TRY" }, ++ { -1, NULL }}; ++ ++void ++dump_config(void) ++{ ++ dump_cfg_string(lURI, options.uri); ++ dump_cfg_string(lHost, options.host); ++ dump_cfg_int(lPort, options.port); ++ dump_cfg_namedint(lSSL, options.ssl, _yesnotls); ++ dump_cfg_int(lLdap_Version, options.ldap_version); ++ dump_cfg_int(lTimeLimit, options.timelimit); ++ dump_cfg_int(lBind_TimeLimit, options.bind_timelimit); ++ dump_cfg_string(lBase, options.base); ++ dump_cfg_string(lBindDN, options.binddn); ++ dump_cfg_string(lBindPW, options.bindpw); ++ dump_cfg_namedint(lScope, options.scope, _scope); ++ dump_cfg_namedint(lDeref, options.deref, _deref); ++ dump_cfg_namedint(lReferrals, options.referrals, _yesno); ++ dump_cfg_namedint(lRestart, options.restart, _yesno); ++ dump_cfg_namedint(lBind_Policy, options.bind_policy, _bindpolicy); ++ dump_cfg_string(lSSLPath, options.sslpath); ++ dump_cfg_namedint(lTLS_CheckPeer, options.tls_checkpeer, _checkpeer); ++ dump_cfg_string(lTLS_CaCertFile, options.tls_cacertfile); ++ dump_cfg_string(lTLS_CaCertDir, options.tls_cacertdir); ++ dump_cfg_string(lTLS_Ciphers, options.tls_ciphers); ++ dump_cfg_string(lTLS_Cert, options.tls_cert); ++ dump_cfg_string(lTLS_Key, options.tls_key); ++ dump_cfg_string(lTLS_RandFile, options.tls_randfile); ++ dump_cfg_string(lLogDir, options.logdir); ++ dump_cfg_int(lDebug, options.debug); ++ dump_cfg_string(lSSH_Filter, options.ssh_filter); ++} ++ +diff --git a/openssh-7.2p2/ldapconf.h b/openssh-7.2p2/ldapconf.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapconf.h +@@ -0,0 +1,71 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 LDAPCONF_H ++#define LDAPCONF_H ++ ++#define SSL_OFF 0 ++#define SSL_LDAPS 1 ++#define SSL_START_TLS 2 ++ ++/* Data structure for representing option data. */ ++ ++typedef struct { ++ char *host; ++ char *uri; ++ char *base; ++ char *binddn; ++ char *bindpw; ++ int scope; ++ int deref; ++ int port; ++ int timelimit; ++ int bind_timelimit; ++ int ldap_version; ++ int bind_policy; ++ char *sslpath; ++ int ssl; ++ int referrals; ++ int restart; ++ int tls_checkpeer; ++ char *tls_cacertfile; ++ char *tls_cacertdir; ++ char *tls_ciphers; ++ char *tls_cert; ++ char *tls_key; ++ char *tls_randfile; ++ char *logdir; ++ int debug; ++ char *ssh_filter; ++} Options; ++ ++extern Options options; ++ ++void read_config_file(const char *); ++void initialize_options(void); ++void fill_default_options(void); ++void dump_config(void); ++ ++#endif /* LDAPCONF_H */ +diff --git a/openssh-7.2p2/ldapincludes.h b/openssh-7.2p2/ldapincludes.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapincludes.h +@@ -0,0 +1,41 @@ ++/* $OpenBSD: ldapconf.c,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 LDAPINCLUDES_H ++#define LDAPINCLUDES_H ++ ++#include "includes.h" ++ ++#ifdef HAVE_LBER_H ++#include ++#endif ++#ifdef HAVE_LDAP_H ++#include ++#endif ++#ifdef HAVE_LDAP_SSL_H ++#include ++#endif ++ ++#endif /* LDAPINCLUDES_H */ +diff --git a/openssh-7.2p2/ldapmisc.c b/openssh-7.2p2/ldapmisc.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapmisc.c +@@ -0,0 +1,79 @@ ++ ++#include "ldapincludes.h" ++#include "ldapmisc.h" ++ ++#ifndef HAVE_LDAP_GET_LDERRNO ++int ++ldap_get_lderrno (LDAP * ld, char **m, char **s) ++{ ++#ifdef HAVE_LDAP_GET_OPTION ++ int rc; ++#endif ++ int lderrno; ++ ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) ++ return rc; ++#else ++ lderrno = ld->ld_errno; ++#endif ++ ++ if (s != NULL) { ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_STRING) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) ++ return rc; ++#else ++ *s = ld->ld_error; ++#endif ++ } ++ ++ if (m != NULL) { ++#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_MATCHED_DN) ++ if ((rc = ldap_get_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) ++ return rc; ++#else ++ *m = ld->ld_matched; ++#endif ++ } ++ ++ return lderrno; ++} ++#endif ++ ++#ifndef HAVE_LDAP_SET_LDERRNO ++int ++ldap_set_lderrno (LDAP * ld, int lderrno, const char *m, const char *s) ++{ ++#ifdef HAVE_LDAP_SET_OPTION ++ int rc; ++#endif ++ ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_NUMBER, &lderrno)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_errno = lderrno; ++#endif ++ ++ if (s != NULL) { ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_ERROR_STRING) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_ERROR_STRING, s)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_error = s; ++#endif ++ } ++ ++ if (m != NULL) { ++#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_MATCHED_DN) ++ if ((rc = ldap_set_option (ld, LDAP_OPT_MATCHED_DN, m)) != LDAP_SUCCESS) ++ return rc; ++#else ++ ld->ld_matched = m; ++#endif ++ } ++ ++ return LDAP_SUCCESS; ++} ++#endif ++ +diff --git a/openssh-7.2p2/ldapmisc.h b/openssh-7.2p2/ldapmisc.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ldapmisc.h +@@ -0,0 +1,35 @@ ++/* $OpenBSD: ldapbody.h,v 1.1 2009/12/03 03:34:42 jfch Exp $ */ ++/* ++ * Copyright (c) 2009 Jan F. Chadima. 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 LDAPMISC_H ++#define LDAPMISC_H ++ ++#include "ldapincludes.h" ++ ++int ldap_get_lderrno (LDAP *, char **, char **); ++int ldap_set_lderrno (LDAP *, int, const char *, const char *); ++ ++#endif /* LDAPMISC_H */ ++ +diff --git a/openssh-7.2p2/openbsd-compat/base64.c b/openssh-7.2p2/openbsd-compat/base64.c +--- a/openssh-7.2p2/openbsd-compat/base64.c ++++ b/openssh-7.2p2/openbsd-compat/base64.c +@@ -41,17 +41,17 @@ + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + /* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + + #include "includes.h" + +-#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) ++#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) || defined(USE_INTERNAL_B64) + + #include + #include + #include + #include + #include + + #include +@@ -124,17 +124,17 @@ static const char Pad64 = '='; + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +-#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) ++#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) || defined(USE_INTERNAL_B64) + int + b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) + { + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + u_int i; + +@@ -180,17 +180,17 @@ b64_ntop(u_char const *src, size_t srcle + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); + } + #endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ + +-#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) ++#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) || defined(USE_INTERNAL_B64) + + /* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + + int +diff --git a/openssh-7.2p2/openbsd-compat/base64.h b/openssh-7.2p2/openbsd-compat/base64.h +--- a/openssh-7.2p2/openbsd-compat/base64.h ++++ b/openssh-7.2p2/openbsd-compat/base64.h +@@ -42,24 +42,24 @@ + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + + #ifndef _BSD_BASE64_H + #define _BSD_BASE64_H + + #include "includes.h" + +-#ifndef HAVE___B64_NTOP +-# ifndef HAVE_B64_NTOP ++#if !defined(HAVE___B64_NTOP) || defined(USE_INTERNAL_B64) ++# if !defined(HAVE_B64_NTOP) || defined(USE_INTERNAL_B64) + int b64_ntop(u_char const *src, size_t srclength, char *target, + size_t targsize); + # endif /* !HAVE_B64_NTOP */ + # define __b64_ntop(a,b,c,d) b64_ntop(a,b,c,d) + #endif /* HAVE___B64_NTOP */ + +-#ifndef HAVE___B64_PTON +-# ifndef HAVE_B64_PTON ++#if !defined(HAVE___B64_PTON) || defined(USE_INTERNAL_B64) ++# if !defined(HAVE_B64_PTON) || defined(USE_INTERNAL_B64) + int b64_pton(char const *src, u_char *target, size_t targsize); + # endif /* !HAVE_B64_PTON */ + # define __b64_pton(a,b,c) b64_pton(a,b,c) + #endif /* HAVE___B64_PTON */ + + #endif /* _BSD_BASE64_H */ +diff --git a/openssh-7.2p2/openssh-lpk-openldap.schema b/openssh-7.2p2/openssh-lpk-openldap.schema +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/openssh-lpk-openldap.schema +@@ -0,0 +1,21 @@ ++# ++# LDAP Public Key Patch schema for use with openssh-ldappubkey ++# useful with PKA-LDAP also ++# ++# Author: Eric AUGE ++# ++# Based on the proposal of : Mark Ruijter ++# ++ ++ ++# octetString SYNTAX ++attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' ++ DESC 'MANDATORY: OpenSSH Public key' ++ EQUALITY octetStringMatch ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) ++ ++# printableString SYNTAX yes|no ++objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY ++ DESC 'MANDATORY: OpenSSH LPK objectclass' ++ MUST ( sshPublicKey $ uid ) ++ ) +diff --git a/openssh-7.2p2/openssh-lpk-sun.schema b/openssh-7.2p2/openssh-lpk-sun.schema +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/openssh-lpk-sun.schema +@@ -0,0 +1,23 @@ ++# ++# LDAP Public Key Patch schema for use with openssh-ldappubkey ++# useful with PKA-LDAP also ++# ++# Author: Eric AUGE ++# ++# Schema for Sun Directory Server. ++# Based on the original schema, modified by Stefan Fischer. ++# ++ ++dn: cn=schema ++ ++# octetString SYNTAX ++attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' ++ DESC 'MANDATORY: OpenSSH Public key' ++ EQUALITY octetStringMatch ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) ++ ++# printableString SYNTAX yes|no ++objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY ++ DESC 'MANDATORY: OpenSSH LPK objectclass' ++ MUST ( sshPublicKey $ uid ) ++ ) +diff --git a/openssh-7.2p2/ssh-ldap-helper.8 b/openssh-7.2p2/ssh-ldap-helper.8 +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ssh-ldap-helper.8 +@@ -0,0 +1,79 @@ ++.\" $OpenBSD: ssh-ldap-helper.8,v 1.1 2010/02/10 23:20:38 markus Exp $ ++.\" ++.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. ++.\" ++.\" 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. ++.\" ++.Dd $Mdocdate: April 29 2010 $ ++.Dt SSH-LDAP-HELPER 8 ++.Os ++.Sh NAME ++.Nm ssh-ldap-helper ++.Nd sshd helper program for ldap support ++.Sh SYNOPSIS ++.Nm ssh-ldap-helper ++.Op Fl devw ++.Op Fl f Ar file ++.Op Fl s Ar user ++.Sh DESCRIPTION ++.Nm ++is used by ++.Xr sshd 1 ++to access keys provided by an LDAP. ++.Nm ++is disabled by default and can only be enabled in the ++sshd configuration file ++.Pa /etc/ssh/sshd_config ++by setting ++.Cm AuthorizedKeysCommand ++to ++.Dq @LIBEXECDIR@/ssh-ldap-wrapper . ++.Pp ++.Nm ++is not intended to be invoked by the user, but from ++.Xr sshd 8 via ++.Xr ssh-ldap-wrapper . ++.Pp ++The options are as follows: ++.Bl -tag -width Ds ++.It Fl d ++Set the debug mode; ++.Nm ++prints all logs to stderr instead of syslog. ++.It Fl e ++Implies \-w; ++.Nm ++halts if it encounters an unknown item in the ldap.conf file. ++.It Fl f ++.Nm ++uses this file as the ldap configuration file instead of /etc/ssh/ldap.conf (default). ++.It Fl s ++.Nm ++prints out the user's keys to stdout and exits. ++.It Fl v ++Implies \-d; ++increases verbosity. ++.It Fl w ++.Nm ++writes warnings about unknown items in the ldap.conf configuration file. ++.El ++.Sh SEE ALSO ++.Xr sshd 8 , ++.Xr sshd_config 5 , ++.Xr ssh-ldap.conf 5 , ++.Sh HISTORY ++.Nm ++first appeared in ++OpenSSH 5.5 + PKA-LDAP . ++.Sh AUTHORS ++.An Jan F. Chadima Aq jchadima@redhat.com +diff --git a/openssh-7.2p2/ssh-ldap-wrapper b/openssh-7.2p2/ssh-ldap-wrapper +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ssh-ldap-wrapper +@@ -0,0 +1,4 @@ ++#!/bin/sh ++ ++exec @LIBEXECDIR@/ssh-ldap-helper -s "$1" ++ +diff --git a/openssh-7.2p2/ssh-ldap.conf.5 b/openssh-7.2p2/ssh-ldap.conf.5 +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/ssh-ldap.conf.5 +@@ -0,0 +1,376 @@ ++.\" $OpenBSD: ssh-ldap.conf.5,v 1.1 2010/02/10 23:20:38 markus Exp $ ++.\" ++.\" Copyright (c) 2010 Jan F. Chadima. All rights reserved. ++.\" ++.\" 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. ++.\" ++.Dd $Mdocdate: may 12 2010 $ ++.Dt SSH-LDAP.CONF 5 ++.Os ++.Sh NAME ++.Nm ssh-ldap.conf ++.Nd configuration file for ssh-ldap-helper ++.Sh SYNOPSIS ++.Nm /etc/ssh/ldap.conf ++.Sh DESCRIPTION ++.Xr ssh-ldap-helper 8 ++reads configuration data from ++.Pa /etc/ssh/ldap.conf ++(or the file specified with ++.Fl f ++on the command line). ++The file contains keyword-argument pairs, one per line. ++Lines starting with ++.Ql # ++and empty lines are interpreted as comments. ++.Pp ++The value starts with the first non-blank character after ++the keyword's name, and terminates at the end of the line, ++or at the last sequence of blanks before the end of the line. ++Quoting values that contain blanks ++may be incorrect, as the quotes would become part of the value. ++The possible keywords and their meanings are as follows (note that ++keywords are case-insensitive, and arguments, on a case by case basis, may be case-sensitive). ++.Bl -tag -width Ds ++.It Cm URI ++The argument(s) are in the form ++.Pa ldap[si]://[name[:port]] ++and specify the URI(s) of an LDAP server(s) to which the ++.Xr ssh-ldap-helper 8 ++should connect. The URI scheme may be any of ++.Dq ldap , ++.Dq ldaps ++or ++.Dq ldapi , ++which refer to LDAP over TCP, LDAP over SSL (TLS) and LDAP ++over IPC (UNIX domain sockets), respectively. ++Each server's name can be specified as a ++domain-style name or an IP address literal. Optionally, the ++server's name can followed by a ':' and the port number the LDAP ++server is listening on. If no port number is provided, the default ++port for the scheme is used (389 for ldap://, 636 for ldaps://). ++For LDAP over IPC, name is the name of the socket, and no port ++is required, nor allowed; note that directory separators must be ++URL-encoded, like any other characters that are special to URLs; ++A space separated list of URIs may be provided. ++There is no default. ++.It Cm Base ++Specifies the default base Distinguished Name (DN) to use when performing ldap operations. ++The base must be specified as a DN in LDAP format. ++There is no default. ++.It Cm BindDN ++Specifies the default BIND DN to use when connecting to the ldap server. ++The bind DN must be specified as a Distinguished Name in LDAP format. ++There is no default. ++.It Cm BindPW ++Specifies the default password to use when connecting to the ldap server via ++.Cm BindDN . ++There is no default. ++.It Cm RootBindDN ++Intentionaly does nothing. Recognized for compatibility reasons. ++.It Cm Host ++The argument(s) specifies the name(s) of an LDAP server(s) to which the ++.Xr ssh-ldap-helper 8 ++should connect. Each server's name can be specified as a ++domain-style name or an IP address and optionally followed by a ':' and ++the port number the ldap server is listening on. A space-separated ++list of hosts may be provided. ++There is no default. ++.Cm Host ++is deprecated in favor of ++.Cm URI . ++.It Cm Port ++Specifies the default port used when connecting to LDAP servers(s). ++The port may be specified as a number. ++The default port is 389 for ldap:// or 636 for ldaps:// respectively. ++.Cm Port ++is deprecated in favor of ++.Cm URI . ++.It Cm Scope ++Specifies the starting point of an LDAP search and the depth from the base DN to which the search should descend. ++There are three options (values) that can be assigned to the ++.Cm Scope parameter: ++.Dq base , ++.Dq one ++and ++.Dq subtree . ++Alias for the subtree is ++.Dq sub . ++The value ++.Dq base ++is used to indicate searching only the entry at the base DN, resulting in only that entry being returned (keeping in mind that it also has to meet the search filter criteria!). ++The value ++.Dq one ++is used to indicate searching all entries one level under the base DN, but not including the base DN and not including any entries under that one level under the base DN. ++The value ++.Dq subtree ++is used to indicate searching of all entries at all levels under and including the specified base DN. ++The default is ++.Dq subtree . ++.It Cm Deref ++Specifies how alias dereferencing is done when performing a search. There are four ++possible values that can be assigned to the ++.Cm Deref ++parameter: ++.Dq never , ++.Dq searching , ++.Dq finding , ++and ++.Dq always . ++The value ++.Dq never ++means that the aliases are never dereferenced. ++The value ++.Dq searching ++means that the aliases are dereferenced in subordinates of the base object, but ++not in locating the base object of the search. ++The value ++.Dq finding ++means that the aliases are only dereferenced when locating the base object of the search. ++The value ++.Dq always ++means that the aliases are dereferenced both in searching and in locating the base object ++of the search. ++The default is ++.Dq never . ++.It Cm TimeLimit ++Specifies a time limit (in seconds) to use when performing searches. ++The number should be a non-negative integer. A ++.Cm TimeLimit ++of zero (0) specifies that the search time is unlimited. Please note that the server ++may still apply any server-side limit on the duration of a search operation. ++The default value is 10. ++.It Cm TimeOut ++Is an aliast to ++.Cm TimeLimit . ++.It Cm Bind_TimeLimit ++Specifies the timeout (in seconds) after which the poll(2)/select(2) ++following a connect(2) returns in case of no activity. ++The default value is 10. ++.It Cm Network_TimeOut ++Is an alias to ++.Cm Bind_TimeLimit . ++.It Cm Ldap_Version ++Specifies what version of the LDAP protocol should be used. ++The allowed values are 2 or 3. The default is 3. ++.It Cm Version ++Is an alias to ++.Cm Ldap_Version . ++.It Cm Bind_Policy ++Specifies the policy to use for reconnecting to an unavailable LDAP server. There are 2 available values: ++.Dq hard ++and ++.Dq soft. ++.Dq hard has 2 aliases ++.Dq hard_open ++and ++.Dq hard_init . ++The value ++.Dq hard ++means that reconects that the ++.Xr ssh-ldap-helper 8 ++tries to reconnect to the LDAP server 5 times before failure. There is exponential backoff before retrying. ++The value ++.Dq soft ++means that ++.Xr ssh-ldap-helper 8 ++fails immediately when it cannot connect to the LDAP seerver. ++The deault is ++.Dq hard . ++.It Cm SSLPath ++Specifies the path to the X.509 certificate database. ++There is no default. ++.It Cm SSL ++Specifies whether to use SSL/TLS or not. ++There are three allowed values: ++.Dq yes , ++.Dq no ++and ++.Dq start_tls ++Both ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++If ++.Dq start_tls ++is specified then StartTLS is used rather than raw LDAP over SSL. ++The default for ldap:// is ++.Dq start_tls , ++for ldaps:// ++.Dq yes ++and ++.Dq no ++for the ldapi:// . ++In case of host based configuration the default is ++.Dq start_tls . ++.It Cm Referrals ++Specifies if the client should automatically follow referrals returned ++by LDAP servers. ++The value can be or ++.Dq yes ++or ++.Dq no . ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++The default is yes. ++.It Cm Restart ++Specifies whether the LDAP client library should restart the select(2) system call when interrupted. ++The value can be or ++.Dq yes ++or ++.Dq no . ++.Dq true ++and ++.Dq on ++are the aliases for ++.Dq yes . ++.Dq false ++and ++.Dq off ++are the aliases for ++.Dq no . ++The default is yes. ++.It Cm TLS_CheckPeer ++Specifies what checks to perform on server certificates in a TLS session, ++if any. The value ++can be specified as one of the following keywords: ++.Dq never , ++.Dq hard , ++.Dq demand , ++.Dq allow ++and ++.Dq try . ++.Dq true , ++.Dq on ++and ++.Dq yes ++are aliases for ++.Dq hard . ++.Dq false , ++.Dq off ++and ++.Dq no ++are the aliases for ++.Dq never . ++The value ++.Dq never ++means that the client will not request or check any server certificate. ++The value ++.Dq allow ++means that the server certificate is requested. If no certificate is provided, ++the session proceeds normally. If a bad certificate is provided, it will ++be ignored and the session proceeds normally. ++The value ++.Dq try ++means that the server certificate is requested. If no certificate is provided, ++the session proceeds normally. If a bad certificate is provided, ++the session is immediately terminated. ++The value ++.Dq demand ++means that the server certificate is requested. If no ++certificate is provided, or a bad certificate is provided, the session ++is immediately terminated. ++The value ++.Dq hard ++is the same as ++.Dq demand . ++It requires an SSL connection. In the case of the plain conection the ++session is immediately terminated. ++The default is ++.Dq hard . ++.It Cm TLS_ReqCert ++Is an alias for ++.Cm TLS_CheckPeer . ++.It Cm TLS_CACertFile ++Specifies the file that contains certificates for all of the Certificate ++Authorities the client will recognize. ++There is no default. ++.It Cm TLS_CACert ++Is an alias for ++.Cm TLS_CACertFile . ++.It Cm TLS_CACertDIR ++Specifies the path of a directory that contains Certificate Authority ++certificates in separate individual files. The ++.Cm TLS_CACert ++is always used before ++.Cm TLS_CACertDir . ++The specified directory must be managed with the OpenSSL c_rehash utility. ++There is no default. ++.It Cm TLS_Ciphers ++Specifies acceptable cipher suite and preference order. ++The value should be a cipher specification for OpenSSL, ++e.g., ++.Dq HIGH:MEDIUM:+SSLv2 . ++The default is ++.Dq ALL . ++.It Cm TLS_Cipher_Suite ++Is an alias for ++.Cm TLS_Ciphers . ++.It Cm TLS_Cert ++Specifies the file that contains the client certificate. ++There is no default. ++.It Cm TLS_Certificate ++Is an alias for ++.Cm TLS_Cert . ++.It Cm TLS_Key ++Specifies the file that contains the private key that matches the certificate ++stored in the ++.Cm TLS_Cert ++file. Currently, the private key must not be protected with a password, so ++it is of critical importance that the key file is protected carefully. ++There is no default. ++.It Cm TLS_RandFile ++Specifies the file to obtain random bits from when /dev/[u]random is ++not available. Generally set to the name of the EGD/PRNGD socket. ++The environment variable RANDFILE can also be used to specify the filename. ++There is no default. ++.It Cm LogDir ++Specifies the directory used for logging by the LDAP client library. ++There is no default. ++.It Cm Debug ++Specifies the debug level used for logging by the LDAP client library. ++There is no default. ++.It Cm SSH_Filter ++Specifies the user filter applied on the LDAP serch. ++The default is no filter. ++.El ++.Sh FILES ++.Bl -tag -width Ds ++.It Pa /etc/ssh/ldap.conf ++Ldap configuration file for ++.Xr ssh-ldap-helper 8 . ++.El ++.Sh "SEE ALSO" ++.Xr ldap.conf 5 , ++.Xr ssh-ldap-helper 8 ++.Sh HISTORY ++.Nm ++first appeared in ++OpenSSH 5.5 + PKA-LDAP . ++.Sh AUTHORS ++.An Jan F. Chadima Aq jchadima@redhat.com diff --git a/openssh-7.2p2-limit_password_length.patch b/openssh-7.2p2-limit_password_length.patch new file mode 100644 index 0000000..b7e00ee --- /dev/null +++ b/openssh-7.2p2-limit_password_length.patch @@ -0,0 +1,52 @@ +# HG changeset patch +# Parent 9888bc3f536eab9f528d9c96e5e8a2501ed168f5 +Limit accepted passwords length to prevent DoS by resource consumption +(via crypt() eating CPU cycles). + +CVE-2016-6515 +bsc#992533 + +upstream commit: fcd135c9df440bcd2d5870405ad3311743d78d97 + +diff --git a/openssh-7.2p2/auth-passwd.c b/openssh-7.2p2/auth-passwd.c +--- a/openssh-7.2p2/auth-passwd.c ++++ b/openssh-7.2p2/auth-passwd.c +@@ -61,16 +61,18 @@ extern ServerOptions options; + #ifdef HAVE_LOGIN_CAP + extern login_cap_t *lc; + #endif + + + #define DAY (24L * 60 * 60) /* 1 day in seconds */ + #define TWO_WEEKS (2L * 7 * DAY) /* 2 weeks in seconds */ + ++#define MAX_PASSWORD_LEN 1024 ++ + void + disable_forwarding(void) + { + no_port_forwarding_flag = 1; + no_agent_forwarding_flag = 1; + no_x11_forwarding_flag = 1; + } + +@@ -82,16 +84,19 @@ int + auth_password(Authctxt *authctxt, const char *password) + { + struct passwd * pw = authctxt->pw; + int result, ok = authctxt->valid; + #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) + static int expire_checked = 0; + #endif + ++ if (strlen(password) > MAX_PASSWORD_LEN) ++ return 0; ++ + #ifndef HAVE_CYGWIN + if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES) + ok = 0; + #endif + if (*password == '\0' && options.permit_empty_passwd == 0) + return 0; + + #ifdef KRB5 diff --git a/openssh-7.2p2-login_options.patch b/openssh-7.2p2-login_options.patch new file mode 100644 index 0000000..cb4d1f1 --- /dev/null +++ b/openssh-7.2p2-login_options.patch @@ -0,0 +1,32 @@ +# HG changeset patch +# Parent b86c2190c93aeaf958c22fc7b224dcaf87100288 +# HG changeset patch +# Parent b262fd34c8ecd55e93d457b3ca5593abce716856 +# login-pam cannot handle the option terminator "--" as login from util-linux +# (this is correct behaviour considering its man-page), hence use option which +# selects the compile-time branch in the code which doesn't use the terminator +# +# bnc#833605 + +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -770,16 +770,18 @@ main() { if (NSVersionOfRunTimeLibrary(" + AC_DEFINE([_PATH_BTMP], ["/var/log/btmp"], [log for bad login attempts]) + AC_DEFINE([USE_BTMP], [1], [Use btmp to log bad logins]) + ;; + *-*-linux*) + no_dev_ptmx=1 + use_pie=auto + check_for_libcrypt_later=1 + check_for_openpty_ctty_bug=1 ++ AC_DEFINE([LOGIN_NO_ENDOPT], [1], ++ [Define if your login program cannot handle end of options ("--")]) + AC_DEFINE([PAM_TTY_KLUDGE], [1], + [Work around problematic Linux PAM modules handling of PAM_TTY]) + AC_DEFINE([LOCKED_PASSWD_PREFIX], ["!"], + [String used in /etc/passwd to denote locked account]) + AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV]) + AC_DEFINE([LINK_OPNOTSUPP_ERRNO], [EPERM], + [Define to whatever link() returns for "not supported" + if it doesn't return EOPNOTSUPP.]) diff --git a/openssh-7.2p2-no_fork-no_pid_file.patch b/openssh-7.2p2-no_fork-no_pid_file.patch new file mode 100644 index 0000000..4c331a9 --- /dev/null +++ b/openssh-7.2p2-no_fork-no_pid_file.patch @@ -0,0 +1,26 @@ +# HG changeset patch +# Parent 4011d0f5c00b663976c9940dc4ef79642605cf90 +Do not write a PID file when not daemonizing (e.g. when running from systemd) + +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -2107,17 +2107,17 @@ main(int ac, char **av) + signal(SIGCHLD, main_sigchld_handler); + signal(SIGTERM, sigterm_handler); + signal(SIGQUIT, sigterm_handler); + + /* + * Write out the pid file after the sigterm handler + * is setup and the listen sockets are bound + */ +- if (options.pid_file != NULL && !debug_flag) { ++ if (!no_daemon_flag && options.pid_file != NULL && !debug_flag) { + FILE *f = fopen(options.pid_file, "w"); + + if (f == NULL) { + error("Couldn't create pid file \"%s\": %s", + options.pid_file, strerror(errno)); + } else { + fprintf(f, "%ld\n", (long) getpid()); + fclose(f); diff --git a/openssh-7.6p1-pam_check_locks.patch b/openssh-7.2p2-pam_check_locks.patch similarity index 67% rename from openssh-7.6p1-pam_check_locks.patch rename to openssh-7.2p2-pam_check_locks.patch index eeb372d..ac8a767 100644 --- a/openssh-7.6p1-pam_check_locks.patch +++ b/openssh-7.2p2-pam_check_locks.patch @@ -1,14 +1,14 @@ # HG changeset patch -# Parent ee0459c1b5173da57f9b3a6e62b232dcf9b3a029 +# Parent ac7f843cd7ebec413691d51823cdc67b611abdff new option UsePAMCheckLocks to enforce checking for locked accounts while UsePAM is used bnc#708678, FATE#312033 -diff --git a/openssh-7.6p1/auth.c b/openssh-7.6p1/auth.c ---- a/openssh-7.6p1/auth.c -+++ b/openssh-7.6p1/auth.c -@@ -105,17 +105,17 @@ allowed_user(struct passwd * pw) +diff --git a/openssh-7.2p2/auth.c b/openssh-7.2p2/auth.c +--- a/openssh-7.2p2/auth.c ++++ b/openssh-7.2p2/auth.c +@@ -104,17 +104,17 @@ allowed_user(struct passwd * pw) struct spwd *spw = NULL; #endif @@ -27,7 +27,7 @@ diff --git a/openssh-7.6p1/auth.c b/openssh-7.6p1/auth.c #endif /* USE_SHADOW */ /* grab passwd field for locked account check */ -@@ -125,17 +125,17 @@ allowed_user(struct passwd * pw) +@@ -124,17 +124,17 @@ allowed_user(struct passwd * pw) #ifdef USE_LIBIAF passwd = get_iaf_password(pw); #else @@ -46,9 +46,9 @@ diff --git a/openssh-7.6p1/auth.c b/openssh-7.6p1/auth.c #endif #ifdef LOCKED_PASSWD_PREFIX if (strncmp(passwd, LOCKED_PASSWD_PREFIX, -diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c ---- a/openssh-7.6p1/servconf.c -+++ b/openssh-7.6p1/servconf.c +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c @@ -69,16 +69,17 @@ extern Buffer cfg; void @@ -67,7 +67,7 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c options->num_queued_listens = 0; options->listen_addrs = NULL; options->address_family = -1; -@@ -191,16 +192,18 @@ assemble_algorithms(ServerOptions *o) +@@ -195,16 +196,18 @@ assemble_algorithms(ServerOptions *o) void fill_default_server_options(ServerOptions *options) { @@ -80,13 +80,13 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c + options->use_pam_check_locks = 0; /* Standard Options */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_2; if (options->num_host_key_files == 0) { /* fill default hostkeys for protocols */ - options->host_key_files[options->num_host_key_files++] = - _PATH_HOST_RSA_KEY_FILE; - options->host_key_files[options->num_host_key_files++] = - _PATH_HOST_DSA_KEY_FILE; -@@ -382,17 +385,17 @@ fill_default_server_options(ServerOption + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = +@@ -391,17 +394,17 @@ fill_default_server_options(ServerOption #endif } @@ -98,14 +98,14 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c - sUsePAM, + sUsePAM, sUsePAMChecklocks, /* Standard Options */ - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, + sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, sRhostsRSAAuthentication, sRSAAuthentication, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, sKerberosGetAFSToken, sKerberosTgtPassing, sChallengeResponseAuthentication, sPasswordAuthentication, sKbdInteractiveAuthentication, -@@ -433,18 +436,20 @@ typedef enum { +@@ -441,18 +444,20 @@ typedef enum { static struct { const char *name; ServerOpCodes opcode; @@ -126,7 +126,7 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c { "hostdsakey", sHostKeyFile, SSHCFG_GLOBAL }, /* alias */ { "hostkeyagent", sHostKeyAgent, SSHCFG_GLOBAL }, { "pidfile", sPidFile, SSHCFG_GLOBAL }, -@@ -1040,16 +1045,19 @@ process_server_config_line(ServerOptions +@@ -1005,16 +1010,19 @@ process_server_config_line(ServerOptions } } @@ -146,10 +146,10 @@ diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c /* ignore ports from configfile if cmdline specifies ports */ if (options->ports_from_cmdline) return 0; -diff --git a/openssh-7.6p1/servconf.h b/openssh-7.6p1/servconf.h ---- a/openssh-7.6p1/servconf.h -+++ b/openssh-7.6p1/servconf.h -@@ -168,16 +168,17 @@ typedef struct { +diff --git a/openssh-7.2p2/servconf.h b/openssh-7.2p2/servconf.h +--- a/openssh-7.2p2/servconf.h ++++ b/openssh-7.2p2/servconf.h +@@ -167,16 +167,17 @@ typedef struct { */ u_int num_authkeys_files; /* Files containing public keys */ @@ -162,22 +162,22 @@ diff --git a/openssh-7.6p1/servconf.h b/openssh-7.6p1/servconf.h int permit_tun; - char **permitted_opens; - u_int num_permitted_opens; /* May also be one of PERMITOPEN_* */ + int num_permitted_opens; char *chroot_directory; char *revoked_keys_file; -diff --git a/openssh-7.6p1/sshd_config.0 b/openssh-7.6p1/sshd_config.0 ---- a/openssh-7.6p1/sshd_config.0 -+++ b/openssh-7.6p1/sshd_config.0 -@@ -901,16 +901,24 @@ DESCRIPTION + char *trusted_user_ca_keys; +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -946,16 +946,24 @@ DESCRIPTION Because PAM challenge-response authentication usually serves an equivalent role to password authentication, you should disable either PasswordAuthentication or ChallengeResponseAuthentication. If UsePAM is enabled, you will not be able to run sshd(8) as a - non-root user. The default is no. + non-root user. The default is M-bM-^@M-^\noM-bM-^@M-^]. + UsePAMCheckLocks + When set to ``yes'', the checks whether the account has been @@ -187,18 +187,18 @@ diff --git a/openssh-7.6p1/sshd_config.0 b/openssh-7.6p1/sshd_config.0 + to set up the session and some PAM modules will not check whether + the account is locked in this scenario). The default is ``no''. + - VersionAddendum - Optionally specifies additional text to append to the SSH - protocol banner sent by the server upon connection. The default - is none. - - X11DisplayOffset - Specifies the first display number available for sshd(8)'s X11 - forwarding. This prevents sshd from interfering with real X11 -diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 ---- a/openssh-7.6p1/sshd_config.5 -+++ b/openssh-7.6p1/sshd_config.5 -@@ -1496,16 +1496,28 @@ or + UsePrivilegeSeparation + Specifies whether sshd(8) separates privileges by creating an + unprivileged child process to deal with incoming network traffic. + After successful authentication, another process will be created + that has the privilege of the authenticated user. The goal of + privilege separation is to prevent privilege escalation by + containing any corruption within the unprivileged processes. The + argument must be M-bM-^@M-^\yesM-bM-^@M-^], M-bM-^@M-^\noM-bM-^@M-^], or M-bM-^@M-^\sandboxM-bM-^@M-^]. If +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -1578,16 +1578,28 @@ or .Pp If .Cm UsePAM @@ -206,7 +206,7 @@ diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 .Xr sshd 8 as a non-root user. The default is - .Cm no . + .Dq no . +.It Cm UsePAMCheckLocks +When set to +.Dq yes @@ -219,11 +219,11 @@ diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 +modules will not check whether the account is locked in this scenario). The +default is +.Dq no . - .It Cm VersionAddendum - Optionally specifies additional text to append to the SSH protocol banner - sent by the server upon connection. - The default is - .Cm none . - .It Cm X11DisplayOffset - Specifies the first display number available for - .Xr sshd 8 Ns 's + .It Cm UsePrivilegeSeparation + Specifies whether + .Xr sshd 8 + separates privileges by creating an unprivileged child process + to deal with incoming network traffic. + After successful authentication, another process will be created that has + the privilege of the authenticated user. + The goal of privilege separation is to prevent privilege diff --git a/openssh-7.2p2-prevent_private_key_leakage.patch b/openssh-7.2p2-prevent_private_key_leakage.patch new file mode 100644 index 0000000..e3e035b --- /dev/null +++ b/openssh-7.2p2-prevent_private_key_leakage.patch @@ -0,0 +1,188 @@ +# HG changeset patch +# Parent e2a8c999f737bca97bbc330ce6683de842ba195e +Pre-allocare buffer for private keys data to prevent leaking of sensitive data +via heap. + +CVE-2016-10011 +bsc#1016369 + +backported upstream commit 54d022026aae4f53fa74cc636e4a032d9689b64d +backported upstream commit a9c746088787549bb5b1ae3add7d06a1b6d93d5e + +diff --git a/openssh-7.2p2/authfile.c b/openssh-7.2p2/authfile.c +--- a/openssh-7.2p2/authfile.c ++++ b/openssh-7.2p2/authfile.c +@@ -95,23 +95,35 @@ sshkey_save_private(struct sshkey *key, + + /* Load a key from a fd into a buffer */ + int + sshkey_load_file(int fd, struct sshbuf *blob) + { + u_char buf[1024]; + size_t len; + struct stat st; +- int r; ++ int r, dontmax = 0; + + if (fstat(fd, &st) < 0) + return SSH_ERR_SYSTEM_ERROR; + if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && + st.st_size > MAX_KEY_FILE_SIZE) + return SSH_ERR_INVALID_FORMAT; ++ /* ++ * Pre-allocate the buffer used for the key contents and clamp its ++ * maximum size. This ensures that key contents are never leaked via ++ * implicit realloc() in the sshbuf code. ++ */ ++ if ((st.st_mode & S_IFREG) == 0 || st.st_size <= 0) { ++ st.st_size = 64*1024; /* 64k should be enough for anyone :) */ ++ dontmax = 1; ++ } ++ if ((r = sshbuf_allocate(blob, st.st_size)) != 0 || ++ (dontmax && (r = sshbuf_set_max_size(blob, st.st_size)) != 0)) ++ return r; + for (;;) { + if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { + if (errno == EPIPE) + break; + r = SSH_ERR_SYSTEM_ERROR; + goto out; + } + if ((r = sshbuf_put(blob, buf, len)) != 0) +diff --git a/openssh-7.2p2/sshbuf.c b/openssh-7.2p2/sshbuf.c +--- a/openssh-7.2p2/sshbuf.c ++++ b/openssh-7.2p2/sshbuf.c +@@ -311,63 +311,73 @@ sshbuf_check_reserve(const struct sshbuf + SSHBUF_TELL("check"); + /* Check that len is reasonable and that max_size + available < len */ + if (len > buf->max_size || buf->max_size - len < buf->size - buf->off) + return SSH_ERR_NO_BUFFER_SPACE; + return 0; + } + + int +-sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp) ++sshbuf_allocate(struct sshbuf *buf, size_t len) + { + size_t rlen, need; + u_char *dp; + int r; + +- if (dpp != NULL) +- *dpp = NULL; +- +- SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len)); ++ SSHBUF_DBG(("allocate buf = %p len = %zu", buf, len)); + if ((r = sshbuf_check_reserve(buf, len)) != 0) + return r; + /* + * If the requested allocation appended would push us past max_size + * then pack the buffer, zeroing buf->off. + */ + sshbuf_maybe_pack(buf, buf->size + len > buf->max_size); +- SSHBUF_TELL("reserve"); +- if (len + buf->size > buf->alloc) { +- /* +- * Prefer to alloc in SSHBUF_SIZE_INC units, but +- * allocate less if doing so would overflow max_size. +- */ +- need = len + buf->size - buf->alloc; +- rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC); +- SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen)); +- if (rlen > buf->max_size) +- rlen = buf->alloc + need; +- SSHBUF_DBG(("adjusted rlen %zu", rlen)); +- if ((dp = realloc(buf->d, rlen)) == NULL) { +- SSHBUF_DBG(("realloc fail")); +- if (dpp != NULL) +- *dpp = NULL; +- return SSH_ERR_ALLOC_FAIL; +- } +- buf->alloc = rlen; +- buf->cd = buf->d = dp; +- if ((r = sshbuf_check_reserve(buf, len)) < 0) { +- /* shouldn't fail */ +- if (dpp != NULL) +- *dpp = NULL; +- return r; +- } ++ SSHBUF_TELL("allocate"); ++ if (len + buf->size <= buf->alloc) ++ return 0; /* already have it. */ ++ ++ /* ++ * Prefer to alloc in SSHBUF_SIZE_INC units, but ++ * allocate less if doing so would overflow max_size. ++ */ ++ need = len + buf->size - buf->alloc; ++ rlen = roundup(buf->alloc + need, SSHBUF_SIZE_INC); ++ SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen)); ++ if (rlen > buf->max_size) ++ rlen = buf->alloc + need; ++ SSHBUF_DBG(("adjusted rlen %zu", rlen)); ++ if ((dp = realloc(buf->d, rlen)) == NULL) { ++ SSHBUF_DBG(("realloc fail")); ++ return SSH_ERR_ALLOC_FAIL; + } ++ buf->alloc = rlen; ++ buf->cd = buf->d = dp; ++ if ((r = sshbuf_check_reserve(buf, len)) < 0) { ++ /* shouldn't fail */ ++ return r; ++ } ++ SSHBUF_TELL("done"); ++ return 0; ++} ++ ++int ++sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp) ++{ ++ u_char *dp; ++ int r; ++ ++ if (dpp != NULL) ++ *dpp = NULL; ++ ++ SSHBUF_DBG(("reserve buf = %p len = %zu", buf, len)); ++ if ((r = sshbuf_allocate(buf, len)) != 0) ++ return r; ++ + dp = buf->d + buf->size; + buf->size += len; +- SSHBUF_TELL("done"); + if (dpp != NULL) + *dpp = dp; + return 0; + } + + int + sshbuf_consume(struct sshbuf *buf, size_t len) + { +diff --git a/openssh-7.2p2/sshbuf.h b/openssh-7.2p2/sshbuf.h +--- a/openssh-7.2p2/sshbuf.h ++++ b/openssh-7.2p2/sshbuf.h +@@ -134,16 +134,24 @@ u_char *sshbuf_mutable_ptr(const struct + * Check whether a reservation of size len will succeed in buf + * Safer to use than direct comparisons again sshbuf_avail as it copes + * with unsigned overflows correctly. + * Returns 0 on success, or a negative SSH_ERR_* error code on failure. + */ + int sshbuf_check_reserve(const struct sshbuf *buf, size_t len); + + /* ++ * Preallocates len additional bytes in buf. ++ * Useful for cases where the caller knows how many bytes will ultimately be ++ * required to avoid realloc in the buffer code. ++ * Returns 0 on success, or a negative SSH_ERR_* error code on failure. ++ */ ++int sshbuf_allocate(struct sshbuf *buf, size_t len); ++ ++/* + * Reserve len bytes in buf. + * Returns 0 on success and a pointer to the first reserved byte via the + * optional dpp parameter or a negative * SSH_ERR_* error code on failure. + */ + int sshbuf_reserve(struct sshbuf *buf, size_t len, u_char **dpp); + + /* + * Consume len bytes from the start of buf diff --git a/openssh-7.2p2-prevent_timing_user_enumeration.patch b/openssh-7.2p2-prevent_timing_user_enumeration.patch new file mode 100644 index 0000000..c16e3c2 --- /dev/null +++ b/openssh-7.2p2-prevent_timing_user_enumeration.patch @@ -0,0 +1,264 @@ +# HG changeset patch +# Parent 4a254abf4ef391358257310ad2fe15c9e12dee34 +Prevent user enumeration through password processing timing +CVE-2016-6210 +bsc#989363 + +non-PAM part: +upstream commit: 9286875a73b2de7736b5e50692739d314cd8d9dc + +PAM part: +upstream commit: 283b97ff33ea2c641161950849931bd578de6946 + +diff --git a/openssh-7.2p2/auth-pam.c b/openssh-7.2p2/auth-pam.c +--- a/openssh-7.2p2/auth-pam.c ++++ b/openssh-7.2p2/auth-pam.c +@@ -227,17 +227,16 @@ static pam_handle_t *sshpam_handle = NUL + static int sshpam_err = 0; + static int sshpam_authenticated = 0; + static int sshpam_session_open = 0; + static int sshpam_cred_established = 0; + static int sshpam_account_status = -1; + static char **sshpam_env = NULL; + static Authctxt *sshpam_authctxt = NULL; + static const char *sshpam_password = NULL; +-static char badpw[] = "\b\n\r\177INCORRECT"; + + /* Some PAM implementations don't implement this */ + #ifndef HAVE_PAM_GETENVLIST + static char ** + pam_getenvlist(pam_handle_t *pamh) + { + /* + * XXX - If necessary, we can still support envrionment passing +@@ -807,22 +806,45 @@ sshpam_query(void *ctx, char **name, cha + free(msg); + ctxt->pam_done = -1; + return (-1); + } + } + return (-1); + } + ++/* ++ * Returns a junk password of identical length to that the user supplied. ++ * Used to mitigate timing attacks against crypt(3)/PAM stacks that ++ * vary processing time in proportion to password length. ++ */ ++static char * ++fake_password(const char *wire_password) ++{ ++ const char junk[] = "\b\n\r\177INCORRECT"; ++ char *ret = NULL; ++ size_t i, l = wire_password != NULL ? strlen(wire_password) : 0; ++ ++ if (l >= INT_MAX) ++ fatal("%s: password length too long: %zu", __func__, l); ++ ++ ret = xmalloc(l + 1); ++ for (i = 0; i < l; i++) ++ ret[i] = junk[i % (sizeof(junk) - 1)]; ++ ret[i] = '\0'; ++ return ret; ++} ++ + /* XXX - see also comment in auth-chall.c:verify_response */ + static int + sshpam_respond(void *ctx, u_int num, char **resp) + { + Buffer buffer; + struct pam_ctxt *ctxt = ctx; ++ char *fake; + + debug2("PAM: %s entering, %u responses", __func__, num); + switch (ctxt->pam_done) { + case 1: + sshpam_authenticated = 1; + return (0); + case 0: + break; +@@ -833,18 +855,21 @@ sshpam_respond(void *ctx, u_int num, cha + error("PAM: expected one response, got %u", num); + return (-1); + } + buffer_init(&buffer); + if (sshpam_authctxt->valid && + (sshpam_authctxt->pw->pw_uid != 0 || + options.permit_root_login == PERMIT_YES)) + buffer_put_cstring(&buffer, *resp); +- else +- buffer_put_cstring(&buffer, badpw); ++ else { ++ fake = fake_password(*resp); ++ buffer_put_cstring(&buffer, fake); ++ free(fake); ++ } + if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { + buffer_free(&buffer); + return (-1); + } + buffer_free(&buffer); + return (1); + } + +@@ -1178,41 +1203,43 @@ static struct pam_conv passwd_conv = { s + /* + * Attempt password authentication via PAM + */ + int + sshpam_auth_passwd(Authctxt *authctxt, const char *password) + { + int flags = (options.permit_empty_passwd == 0 ? + PAM_DISALLOW_NULL_AUTHTOK : 0); ++ char *fake = NULL; + + if (!options.use_pam || sshpam_handle == NULL) + fatal("PAM: %s called when PAM disabled or failed to " + "initialise.", __func__); + + sshpam_password = password; + sshpam_authctxt = authctxt; + + /* + * If the user logging in is invalid, or is root but is not permitted + * by PermitRootLogin, use an invalid password to prevent leaking + * information via timing (eg if the PAM config has a delay on fail). + */ + if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && + options.permit_root_login != PERMIT_YES)) +- sshpam_password = badpw; ++ sshpam_password = fake = fake_password(password); + + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&passwd_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, + pam_strerror(sshpam_handle, sshpam_err)); + + sshpam_err = pam_authenticate(sshpam_handle, flags); + sshpam_password = NULL; ++ free(fake); + if (sshpam_err == PAM_SUCCESS && authctxt->valid) { + debug("PAM: password authentication accepted for %.100s", + authctxt->user); + return 1; + } else { + debug("PAM: password authentication failed for %.100s: %s", + authctxt->valid ? authctxt->user : "an illegal user", + pam_strerror(sshpam_handle, sshpam_err)); +diff --git a/openssh-7.2p2/auth-passwd.c b/openssh-7.2p2/auth-passwd.c +--- a/openssh-7.2p2/auth-passwd.c ++++ b/openssh-7.2p2/auth-passwd.c +@@ -188,28 +188,32 @@ sys_auth_passwd(Authctxt *authctxt, cons + return (auth_close(as)); + } + } + #elif !defined(CUSTOM_SYS_AUTH_PASSWD) + int + sys_auth_passwd(Authctxt *authctxt, const char *password) + { + struct passwd *pw = authctxt->pw; +- char *encrypted_password; ++ char *encrypted_password, *salt = NULL; + + /* Just use the supplied fake password if authctxt is invalid */ + char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; + + /* Check for users with no password. */ + if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) + return (1); + +- /* Encrypt the candidate password using the proper salt. */ +- encrypted_password = xcrypt(password, +- (pw_password[0] && pw_password[1]) ? pw_password : "xx"); ++ /* ++ * Encrypt the candidate password using the proper salt, or pass a ++ * NULL and let xcrypt pick one. ++ */ ++ if (authctxt->valid && pw_password[0] && pw_password[1]) ++ salt = pw_password; ++ encrypted_password = xcrypt(password, salt); + + /* + * Authentication is accepted if the encrypted passwords + * are identical. + */ + return encrypted_password != NULL && + strcmp(encrypted_password, pw_password) == 0; + } +diff --git a/openssh-7.2p2/openbsd-compat/xcrypt.c b/openssh-7.2p2/openbsd-compat/xcrypt.c +--- a/openssh-7.2p2/openbsd-compat/xcrypt.c ++++ b/openssh-7.2p2/openbsd-compat/xcrypt.c +@@ -20,16 +20,17 @@ + * 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" + + #include ++#include + #include + #include + + # if defined(HAVE_CRYPT_H) && !defined(HAVE_SECUREWARE) + # include + # endif + + # ifdef __hpux +@@ -57,21 +58,54 @@ + # include "md5crypt.h" + # endif + + # if defined(WITH_OPENSSL) && !defined(HAVE_CRYPT) && defined(HAVE_DES_CRYPT) + # include + # define crypt DES_crypt + # endif + ++/* ++ * Pick an appropriate password encryption type and salt for the running ++ * system. ++ */ ++static const char * ++pick_salt(void) ++{ ++ struct passwd *pw; ++ char *passwd, *p; ++ size_t typelen; ++ static char salt[32]; ++ ++ if (salt[0] != '\0') ++ return salt; ++ strlcpy(salt, "xx", sizeof(salt)); ++ if ((pw = getpwuid(0)) == NULL) ++ return salt; ++ passwd = shadow_pw(pw); ++ if (passwd[0] != '$' || (p = strrchr(passwd + 1, '$')) == NULL) ++ return salt; /* no $, DES */ ++ typelen = p - passwd + 1; ++ strlcpy(salt, passwd, MIN(typelen, sizeof(salt))); ++ explicit_bzero(passwd, strlen(passwd)); ++ return salt; ++} ++ + char * + xcrypt(const char *password, const char *salt) + { + char *crypted; + ++ /* ++ * If we don't have a salt we are encrypting a fake password for ++ * for timing purposes. Pick an appropriate salt. ++ */ ++ if (salt == NULL) ++ salt = pick_salt(); ++ + # ifdef HAVE_MD5_PASSWORDS + if (is_md5_salt(salt)) + crypted = md5_crypt(password, salt); + else + crypted = crypt(password, salt); + # elif defined(__hpux) && !defined(HAVE_SECUREWARE) + if (iscomsec()) + crypted = bigcrypt(password, salt); diff --git a/openssh-7.6p1-pts_names_formatting.patch b/openssh-7.2p2-pts_names_formatting.patch similarity index 88% rename from openssh-7.6p1-pts_names_formatting.patch rename to openssh-7.2p2-pts_names_formatting.patch index 96b2924..3973e17 100644 --- a/openssh-7.6p1-pts_names_formatting.patch +++ b/openssh-7.2p2-pts_names_formatting.patch @@ -1,12 +1,12 @@ # HG changeset patch -# Parent 6dd892b74f13d258dc1bb3a70db7397dfb46c5e0 +# Parent 787bc0aab11e5a7b6510c8dbf771958743ca25b0 # use same lines naming as utempter (prevents problems with using different # formats in ?tmp? files) # --used to be called '-pts' -diff --git a/openssh-7.6p1/loginrec.c b/openssh-7.6p1/loginrec.c ---- a/openssh-7.6p1/loginrec.c -+++ b/openssh-7.6p1/loginrec.c +diff --git a/openssh-7.2p2/loginrec.c b/openssh-7.2p2/loginrec.c +--- a/openssh-7.2p2/loginrec.c ++++ b/openssh-7.2p2/loginrec.c @@ -541,17 +541,17 @@ getlast_entry(struct logininfo *li) /* * 'line' string utility functions diff --git a/openssh-7.6p1-remove_xauth_cookies_on_exit.patch b/openssh-7.2p2-remove_xauth_cookies_on_exit.patch similarity index 80% rename from openssh-7.6p1-remove_xauth_cookies_on_exit.patch rename to openssh-7.2p2-remove_xauth_cookies_on_exit.patch index 0fafa80..47a3fdd 100644 --- a/openssh-7.6p1-remove_xauth_cookies_on_exit.patch +++ b/openssh-7.2p2-remove_xauth_cookies_on_exit.patch @@ -1,20 +1,20 @@ # HG changeset patch -# Parent 2c6d52d1229cbfd1cd4b7b356bb649470df4d3b3 +# Parent 18c2690afd988b9cb0fd0fa927d02cf5336dce9c # --used to be called '-xauth' try to remove xauth cookies on logout bnc#98815 -diff --git a/openssh-7.6p1/session.c b/openssh-7.6p1/session.c ---- a/openssh-7.6p1/session.c -+++ b/openssh-7.6p1/session.c -@@ -2294,16 +2294,44 @@ session_close(struct ssh *ssh, Session * +diff --git a/openssh-7.2p2/session.c b/openssh-7.2p2/session.c +--- a/openssh-7.2p2/session.c ++++ b/openssh-7.2p2/session.c +@@ -2540,16 +2540,44 @@ session_close(Session *s) u_int i; verbose("Close session: user %s from %.200s port %d id %d", s->pw->pw_name, - ssh_remote_ipaddr(ssh), - ssh_remote_port(ssh), + get_remote_ipaddr(), + get_remote_port(), s->self); + if ((s->display != NULL) && (s->auth_proto != NULL) && diff --git a/openssh-7.2p2-restrict_pkcs11-modules.patch b/openssh-7.2p2-restrict_pkcs11-modules.patch new file mode 100644 index 0000000..0b4204c --- /dev/null +++ b/openssh-7.2p2-restrict_pkcs11-modules.patch @@ -0,0 +1,297 @@ +# HG changeset patch +# Parent 22de9aeddbde2b36da9c23475cfa5dcd42e95287 +whitelist paths for loading of PKCS#11 modules in ssh-agent + +CVE-2016-10009 +bsc#1016366 + +upstream commit 786d5994da79151180cb14a6cf157ebbba61c0cc + +diff --git a/openssh-7.2p2/ssh-agent.1 b/openssh-7.2p2/ssh-agent.1 +--- a/openssh-7.2p2/ssh-agent.1 ++++ b/openssh-7.2p2/ssh-agent.1 +@@ -1,9 +1,9 @@ +-.\" $OpenBSD: ssh-agent.1,v 1.62 2015/11/15 23:54:15 jmc Exp $ ++.\" $OpenBSD: ssh-agent.1,v 1.63 2016/11/30 03:07:37 djm Exp $ + .\" + .\" Author: Tatu Ylonen + .\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + .\" All rights reserved + .\" + .\" As far as I am concerned, the code I have written for this software + .\" can be used freely for any purpose. Any derived versions of this + .\" software must be clearly marked as such, and if the derived work is +@@ -29,29 +29,30 @@ + .\" 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. + .\" +-.Dd $Mdocdate: November 15 2015 $ ++.Dd $Mdocdate: November 30 2016 $ + .Dt SSH-AGENT 1 + .Os + .Sh NAME + .Nm ssh-agent + .Nd authentication agent + .Sh SYNOPSIS + .Nm ssh-agent + .Op Fl c | s + .Op Fl \&Dd + .Op Fl a Ar bind_address + .Op Fl E Ar fingerprint_hash + .Op Fl t Ar life ++.Op Fl P Ar pkcs11_whitelist + .Op Ar command Op Ar arg ... + .Nm ssh-agent + .Op Fl c | s + .Fl k + .Sh DESCRIPTION + .Nm + is a program to hold private keys used for public key authentication + (RSA, DSA, ECDSA, Ed25519). +@@ -116,16 +117,28 @@ Valid options are: + and + .Dq sha256 . + The default is + .Dq sha256 . + .It Fl k + Kill the current agent (given by the + .Ev SSH_AGENT_PID + environment variable). ++.It Fl P ++Specify a pattern-list of acceptable paths for PKCS#11 shared libraries ++that may be added using the ++.Fl s ++option to ++.Xr ssh-add 1 . ++The default is to allow loading PKCS#11 libraries from ++.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 ++for a description of pattern-list syntax. + .It Fl s + Generate Bourne shell commands on + .Dv stdout . + This is the default if + .Ev SHELL + does not look like it's a csh style of shell. + .It Fl t Ar life + Set a default value for the maximum lifetime of identities added to the agent. +diff --git a/openssh-7.2p2/ssh-agent.c b/openssh-7.2p2/ssh-agent.c +--- a/openssh-7.2p2/ssh-agent.c ++++ b/openssh-7.2p2/ssh-agent.c +@@ -78,25 +78,30 @@ + #include "sshbuf.h" + #include "sshkey.h" + #include "authfd.h" + #include "compat.h" + #include "log.h" + #include "misc.h" + #include "digest.h" + #include "ssherr.h" ++#include "match.h" + + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" + #endif + + #if defined(HAVE_SYS_PRCTL_H) + #include /* For prctl() and PR_SET_DUMPABLE */ + #endif + ++#ifndef DEFAULT_PKCS11_WHITELIST ++# define DEFAULT_PKCS11_WHITELIST "/usr/lib/*,/usr/local/lib/*" ++#endif ++ + typedef enum { + AUTH_UNUSED, + AUTH_SOCKET, + AUTH_CONNECTION + } sock_type; + + typedef struct { + int fd; +@@ -134,16 +139,19 @@ time_t parent_alive_interval = 0; + + /* pid of process for which cleanup_socket is applicable */ + pid_t cleanup_pid = 0; + + /* pathname and directory for AUTH_SOCKET */ + char socket_name[PATH_MAX]; + char socket_dir[PATH_MAX]; + ++/* PKCS#11 path whitelist */ ++static char *pkcs11_whitelist; ++ + /* locking */ + #define LOCK_SIZE 32 + #define LOCK_SALT_SIZE 16 + #define LOCK_ROUNDS 1 + int locked = 0; + char lock_passwd[LOCK_SIZE]; + char lock_salt[LOCK_SALT_SIZE]; + +@@ -736,17 +744,17 @@ no_identities(SocketEntry *e, u_int type + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + sshbuf_free(msg); + } + + #ifdef ENABLE_PKCS11 + static void + process_add_smartcard_key(SocketEntry *e) + { +- char *provider = NULL, *pin; ++ char *provider = NULL, *pin, canonical_provider[PATH_MAX]; + int r, i, version, count = 0, success = 0, confirm = 0; + u_int seconds; + time_t death = 0; + u_char type; + struct sshkey **keys = NULL, *k; + Identity *id; + Idtab *tab; + +@@ -768,29 +776,40 @@ process_add_smartcard_key(SocketEntry *e + confirm = 1; + break; + default: + error("process_add_smartcard_key: " + "Unknown constraint type %d", type); + goto send; + } + } ++ if (realpath(provider, canonical_provider) == NULL) { ++ verbose("failed PKCS#11 add of \"%.100s\": realpath: %s", ++ provider, strerror(errno)); ++ goto send; ++ } ++ if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) { ++ verbose("refusing PKCS#11 add of \"%.100s\": " ++ "provider not whitelisted", canonical_provider); ++ goto send; ++ } ++ debug("%s: add %.100s", __func__, canonical_provider); + if (lifetime && !death) + death = monotime() + lifetime; + +- count = pkcs11_add_provider(provider, pin, &keys); ++ count = pkcs11_add_provider(canonical_provider, pin, &keys); + for (i = 0; i < count; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + tab = idtab_lookup(version); + if (lookup_identity(k, version) == NULL) { + id = xcalloc(1, sizeof(Identity)); + id->key = k; +- id->provider = xstrdup(provider); +- id->comment = xstrdup(provider); /* XXX */ ++ id->provider = xstrdup(canonical_provider); ++ id->comment = xstrdup(canonical_provider); /* XXX */ + id->death = death; + id->confirm = confirm; + TAILQ_INSERT_TAIL(&tab->idlist, id, next); + tab->nentries++; + success = 1; + } else { + sshkey_free(k); + } +@@ -1171,17 +1190,17 @@ check_parent_exists(void) + } + } + + static void + usage(void) + { + fprintf(stderr, + "usage: ssh-agent [-c | -s] [-Dd] [-a bind_address] [-E fingerprint_hash]\n" +- " [-t life] [command [arg ...]]\n" ++ " [-P pkcs11_whitelist] [-t life] [command [arg ...]]\n" + " ssh-agent [-c | -s] -k\n"); + exit(1); + } + + int + main(int ac, char **av) + { + int c_flag = 0, d_flag = 0, D_flag = 0, k_flag = 0, s_flag = 0; +@@ -1215,31 +1234,36 @@ main(int ac, char **av) + + #ifdef WITH_OPENSSL + OpenSSL_add_all_algorithms(); + #endif + + __progname = ssh_get_progname(av[0]); + seed_rng(); + +- while ((ch = getopt(ac, av, "cDdksE:a:t:")) != -1) { ++ while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { + switch (ch) { + case 'E': + fingerprint_hash = ssh_digest_alg_by_name(optarg); + if (fingerprint_hash == -1) + fatal("Invalid hash algorithm \"%s\"", optarg); + break; + case 'c': + if (s_flag) + usage(); + c_flag++; + break; + case 'k': + k_flag++; + break; ++ case 'P': ++ if (pkcs11_whitelist != NULL) ++ fatal("-P option already specified"); ++ pkcs11_whitelist = xstrdup(optarg); ++ break; + case 's': + if (c_flag) + usage(); + s_flag++; + break; + case 'd': + if (d_flag || D_flag) + usage(); +@@ -1264,16 +1288,19 @@ main(int ac, char **av) + } + } + ac -= optind; + av += optind; + + if (ac > 0 && (c_flag || k_flag || s_flag || d_flag || D_flag)) + usage(); + ++ if (pkcs11_whitelist == NULL) ++ pkcs11_whitelist = xstrdup(DEFAULT_PKCS11_WHITELIST); ++ + if (ac == 0 && !c_flag && !s_flag) { + shell = getenv("SHELL"); + if (shell != NULL && (len = strlen(shell)) > 2 && + strncmp(shell + len - 3, "csh", 3) == 0) + c_flag = 1; + } + if (k_flag) { + const char *errstr = NULL; +@@ -1411,17 +1438,17 @@ skip: + parent_alive_interval = 10; + idtab_init(); + signal(SIGPIPE, SIG_IGN); + signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN); + signal(SIGHUP, cleanup_handler); + signal(SIGTERM, cleanup_handler); + nalloc = 0; + +- if (pledge("stdio cpath unix id proc exec", NULL) == -1) ++ if (pledge("stdio rpath cpath unix id proc exec", NULL) == -1) + fatal("%s: pledge: %s", __progname, strerror(errno)); + platform_pledge_agent(); + + while (1) { + prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); + result = select(max_fd + 1, readsetp, writesetp, NULL, tvp); + saved_errno = errno; + if (parent_alive_interval != 0) diff --git a/openssh-7.2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch b/openssh-7.2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch new file mode 100644 index 0000000..6a6fdc3 --- /dev/null +++ b/openssh-7.2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch @@ -0,0 +1,82 @@ +# HG changeset patch +# Parent bb92b9f037cc3686a669cd84caa44a2716f34058 +Date: Tue, 9 May 2017 14:27:34 -0300 + +[PATCH 0/3] Allow syscalls for openssl engines +From: Eduardo Barretto +To: openssh-unix-dev@mindrot.org +In order to use the OpenSSL-ibmpkcs11 engine it is needed to allow flock +and ipc calls, because this engine calls OpenCryptoki (a PKCS#11 +implementation) which calls the libraries that will communicate with the +crypto cards. OpenCryptoki makes use of flock and ipc and, as of now, +this is only need on s390 architecture. + +The EP11 crypto card also needs to make an ioctl call, which receives an +specific argument. + +Signed-off-by: Eduardo Barretto + +related to bsc#1016709 + +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -150,16 +150,19 @@ static const struct sock_filter preauth_ + SC_ALLOW(stat), + #endif + #ifdef __NR_exit + SC_ALLOW(exit), + #endif + #ifdef __NR_exit_group + SC_ALLOW(exit_group), + #endif ++#if defined(__NR_flock) && defined(__s390__) ++ SC_ALLOW(flock), ++#endif + #ifdef __NR_getpgid + SC_ALLOW(getpgid), + #endif + #ifdef __NR_getpid + SC_ALLOW(getpid), + #endif + #ifdef __NR_getuid + SC_ALLOW(getuid), +@@ -180,16 +183,19 @@ static const struct sock_filter preauth_ + SC_ALLOW(gettimeofday), + #endif + #ifdef SSH_AUDIT_EVENTS + SC_ALLOW(getuid), + #ifdef __NR_getuid32 /* not defined on x86_64 */ + SC_ALLOW(getuid32), + #endif + #endif ++#if defined(__NR_ipc) && defined(__s390__) ++ SC_ALLOW(ipc), ++#endif + #ifdef __NR_madvise + SC_ALLOW(madvise), + #endif + #ifdef __NR_mmap + SC_ALLOW(mmap), + #endif + #ifdef __NR_mmap2 + SC_ALLOW(mmap2), +@@ -233,16 +239,18 @@ static const struct sock_filter preauth_ + #ifdef __NR_socketcall + SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), + #endif + #ifdef __NR_ioctl + #ifdef __s390__ + SC_ALLOW_ARG(ioctl, 1, Z90STAT_STATUS_MASK), + SC_ALLOW_ARG(ioctl, 1, ICARSAMODEXPO), + SC_ALLOW_ARG(ioctl, 1, ICARSACRT), ++ /* Allow ioctls for EP11 crypto card on s390 */ ++ SC_ALLOW_ARG(ioctl, 1, ZSENDEP11CPRB), + #endif + #endif + + /* Default deny */ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), + }; + + static const struct sock_fprog preauth_program = { diff --git a/openssh-7.2p2-s390_hw_crypto_syscalls.patch b/openssh-7.2p2-s390_hw_crypto_syscalls.patch new file mode 100644 index 0000000..9bd1dcb --- /dev/null +++ b/openssh-7.2p2-s390_hw_crypto_syscalls.patch @@ -0,0 +1,100 @@ +# HG changeset patch +# Parent 6d8637bec747de081eccba9874f640dcbc4fbb68 +This patch enables specific ioctl calls for ICA crypto card on s390 +platform. Without this patch, users using the IBMCA engine are not able +to perform ssh login as the filter blocks the communication with the +crypto card. + +Signed-off-by: Harald Freudenberger +Signed-off-by: Eduardo Barretto + +bsc#1016709 + +Upstreamed as: +5f1596e11d55539678c41f68aed358628d33d86f +58b8cfa2a062b72139d7229ae8de567f55776f24 + +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -54,42 +54,53 @@ + #include + #include + #include + #include /* for offsetof */ + #include + #include + #include + #include ++#include ++ ++#ifdef __s390__ ++#include ++#endif + + #include "log.h" + #include "ssh-sandbox.h" + #include "xmalloc.h" + + /* Linux seccomp_filter sandbox */ + #define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL + + /* Use a signal handler to emit violations when debugging */ + #ifdef SANDBOX_SECCOMP_FILTER_DEBUG + # undef SECCOMP_FILTER_FAIL + # define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP + #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */ + + /* Simple helpers to avoid manual errors (but larger BPF programs). */ ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) ++#elif __BYTE_ORDER == __BIG_ENDIAN ++#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(uint32_t) ++#else ++#error "Unknown endianness" ++#endif + #define SC_DENY(_nr, _errno) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)) + #define SC_ALLOW(_nr) \ + 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_STMT(BPF_LD+BPF_W+BPF_ABS, \ +- offsetof(struct seccomp_data, args[(_arg_nr)])), \ ++ /* load the syscall argument to check into accumulator */ \ ++ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(_arg_nr)), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_arg_val), 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, \ + offsetof(struct seccomp_data, nr)) + + /* Syscall filtering set for preauth. */ + static const struct sock_filter preauth_insns[] = { +@@ -217,16 +228,23 @@ static const struct sock_filter preauth_ + SC_ALLOW(time), + #endif + #ifdef __NR_write + SC_ALLOW(write), + #endif + #ifdef __NR_socketcall + SC_ALLOW_ARG(socketcall, 0, SYS_SHUTDOWN), + #endif ++#ifdef __NR_ioctl ++#ifdef __s390__ ++ SC_ALLOW_ARG(ioctl, 1, Z90STAT_STATUS_MASK), ++ SC_ALLOW_ARG(ioctl, 1, ICARSAMODEXPO), ++ SC_ALLOW_ARG(ioctl, 1, ICARSACRT), ++#endif ++#endif + + /* Default deny */ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL), + }; + + static const struct sock_fprog preauth_program = { + .len = (unsigned short)(sizeof(preauth_insns)/sizeof(preauth_insns[0])), + .filter = (struct sock_filter *)preauth_insns, diff --git a/openssh-7.2p2-seccomp_geteuid.patch b/openssh-7.2p2-seccomp_geteuid.patch new file mode 100644 index 0000000..d6a9ae6 --- /dev/null +++ b/openssh-7.2p2-seccomp_geteuid.patch @@ -0,0 +1,34 @@ +# HG changeset patch +# Parent b07f00d5d805c043f5bdc7b8cf6701d924879fa6 +Add the 'geteuid' syscall to allowed list, since it may becalled on the +mainframes when OpenSSL is using hardware crypto accelerator via libica +(via ibmica) + +bsc#1004258 + +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -148,16 +148,22 @@ static const struct sock_filter preauth_ + 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 + #ifdef __NR_gettimeofday + SC_ALLOW(gettimeofday), + #endif + #ifdef __NR_madvise + SC_ALLOW(madvise), diff --git a/openssh-7.2p2-seccomp_getuid.patch b/openssh-7.2p2-seccomp_getuid.patch new file mode 100644 index 0000000..a5c51c4 --- /dev/null +++ b/openssh-7.2p2-seccomp_getuid.patch @@ -0,0 +1,31 @@ +# HG changeset patch +# Parent d75417bf0f4d50cabd84299773bab4ac68f68caa +add 'getuid' syscall to list of allowed ones to prevent the sanboxed thread +from being killed by the seccomp filter + +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -142,16 +142,22 @@ static const struct sock_filter preauth_ + SC_ALLOW(exit_group), + #endif + #ifdef __NR_getpgid + SC_ALLOW(getpgid), + #endif + #ifdef __NR_getpid + SC_ALLOW(getpid), + #endif ++#ifdef __NR_getuid ++ SC_ALLOW(getuid), ++#endif ++#ifdef __NR_getuid32 ++ SC_ALLOW(getuid32), ++#endif + #ifdef __NR_getrandom + SC_ALLOW(getrandom), + #endif + #ifdef __NR_gettimeofday + SC_ALLOW(gettimeofday), + #endif + #ifdef __NR_madvise + SC_ALLOW(madvise), diff --git a/openssh-7.2p2-seccomp_stat.patch b/openssh-7.2p2-seccomp_stat.patch new file mode 100644 index 0000000..a50add4 --- /dev/null +++ b/openssh-7.2p2-seccomp_stat.patch @@ -0,0 +1,30 @@ +# HG changeset patch +# Parent 2153c4af090728c778931d2fad72d4b260294122 +Allow the stat() syscall for OpenSSL re-seed patch +(which causes OpenSSL use stat() on some file) + +bnc#912436 + +diff --git a/openssh-7.2p2/sandbox-seccomp-filter.c b/openssh-7.2p2/sandbox-seccomp-filter.c +--- a/openssh-7.2p2/sandbox-seccomp-filter.c ++++ b/openssh-7.2p2/sandbox-seccomp-filter.c +@@ -130,16 +130,19 @@ static const struct sock_filter preauth_ + SC_ALLOW(brk), + #endif + #ifdef __NR_clock_gettime + SC_ALLOW(clock_gettime), + #endif + #ifdef __NR_close + SC_ALLOW(close), + #endif ++#ifdef __NR_stat ++ SC_ALLOW(stat), ++#endif + #ifdef __NR_exit + SC_ALLOW(exit), + #endif + #ifdef __NR_exit_group + SC_ALLOW(exit_group), + #endif + #ifdef __NR_getpgid + SC_ALLOW(getpgid), diff --git a/openssh-7.2p2-secure_unix_sockets_forwarding.patch b/openssh-7.2p2-secure_unix_sockets_forwarding.patch new file mode 100644 index 0000000..ea7dad2 --- /dev/null +++ b/openssh-7.2p2-secure_unix_sockets_forwarding.patch @@ -0,0 +1,51 @@ +# HG changeset patch +# Parent 4e1fd41aaa9cafe8f7b07868ac38ed4dbdf594aa +Do not allow unix socket when running without privilege separation to prevent +privilege escalation through a socket created with root: ownership. + +CVE-2016-10010 +bsc#1016368 + +backported upstream commit b737e4d7433577403a31cff6614f6a1b0b5e22f4 + +diff --git a/openssh-7.2p2/serverloop.c b/openssh-7.2p2/serverloop.c +--- a/openssh-7.2p2/serverloop.c ++++ b/openssh-7.2p2/serverloop.c +@@ -990,17 +990,17 @@ server_request_direct_streamlocal(void) + originator_port = packet_get_int(); + packet_check_eom(); + + debug("server_request_direct_streamlocal: originator %s port %d, target %s", + originator, originator_port, target); + + /* XXX fine grained permissions */ + if ((options.allow_streamlocal_forwarding & FORWARD_LOCAL) != 0 && +- !no_port_forwarding_flag) { ++ !no_port_forwarding_flag && use_privsep) { + c = channel_connect_to_path(target, + "direct-streamlocal@openssh.com", "direct-streamlocal"); + } else { + logit("refused streamlocal port forward: " + "originator %s port %d, target %s", + originator, originator_port, target); + } + +@@ -1274,17 +1274,17 @@ server_input_global_request(int type, u_ + + memset(&fwd, 0, sizeof(fwd)); + fwd.listen_path = packet_get_string(NULL); + debug("server_input_global_request: streamlocal-forward listen path %s", + fwd.listen_path); + + /* check permissions */ + if ((options.allow_streamlocal_forwarding & FORWARD_REMOTE) == 0 +- || no_port_forwarding_flag) { ++ || no_port_forwarding_flag || !use_privsep) { + success = 0; + packet_send_debug("Server has disabled port forwarding."); + } else { + /* Start listening on the socket */ + success = channel_setup_remote_fwd_listener( + &fwd, NULL, &options.fwd_opts); + } + free(fwd.listen_path); diff --git a/openssh-7.2p2-seed-prng.patch b/openssh-7.2p2-seed-prng.patch new file mode 100644 index 0000000..8f9f690 --- /dev/null +++ b/openssh-7.2p2-seed-prng.patch @@ -0,0 +1,461 @@ +# HG changeset patch +# Parent 6ece65e11f754d75dd33d72b6f8e487a9d047f2e +# extended support for (re-)seeding the OpenSSL PRNG from /dev/random +# bnc#703221, FATE#312172 + +diff --git a/openssh-7.2p2/entropy.c b/openssh-7.2p2/entropy.c +--- a/openssh-7.2p2/entropy.c ++++ b/openssh-7.2p2/entropy.c +@@ -49,16 +49,17 @@ + + #include "ssh.h" + #include "misc.h" + #include "xmalloc.h" + #include "atomicio.h" + #include "pathnames.h" + #include "log.h" + #include "buffer.h" ++#include "openbsd-compat/port-linux.h" + + /* + * Portable OpenSSH PRNG seeding: + * If OpenSSL has not "internally seeded" itself (e.g. pulled data from + * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from + * PRNGd. + */ + #ifndef OPENSSL_PRNG_ONLY +@@ -224,16 +225,19 @@ seed_rng(void) + } + + if (seed_from_prngd(buf, sizeof(buf)) == -1) + fatal("Could not obtain seed from PRNGd"); + RAND_add(buf, sizeof(buf), sizeof(buf)); + memset(buf, '\0', sizeof(buf)); + + #endif /* OPENSSL_PRNG_ONLY */ ++ ++ linux_seed(); ++ + if (RAND_status() != 1) + fatal("PRNG is not seeded"); + } + + #else /* WITH_OPENSSL */ + + /* Handled in arc4random() */ + void +diff --git a/openssh-7.2p2/openbsd-compat/Makefile.in b/openssh-7.2p2/openbsd-compat/Makefile.in +--- a/openssh-7.2p2/openbsd-compat/Makefile.in ++++ b/openssh-7.2p2/openbsd-compat/Makefile.in +@@ -15,17 +15,17 @@ AR=@AR@ + RANLIB=@RANLIB@ + INSTALL=@INSTALL@ + LDFLAGS=-L. @LDFLAGS@ + + OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o + + 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 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-prng.o port-solaris.o port-tun.o port-uw.o + + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + + all: libopenbsd-compat.a + + $(COMPAT): ../config.h + $(OPENBSD): ../config.h +diff --git a/openssh-7.2p2/openbsd-compat/port-linux-prng.c b/openssh-7.2p2/openbsd-compat/port-linux-prng.c +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/openbsd-compat/port-linux-prng.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (c) 2011 Jan F. Chadima ++ * (c) 2011 Petr Cerny ++ * ++ * Permission to use, copy, modify, and distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Linux-specific portability code - prng support ++ */ ++ ++#include "includes.h" ++#include "defines.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "log.h" ++#include "port-linux.h" ++#include "fips.h" ++ ++#define RNG_BYTES_DEFAULT 6L ++#define RNG_ENV_VAR "SSH_USE_STRONG_RNG" ++ ++long rand_bytes = 0; ++char *rand_file = NULL; ++ ++static void ++linux_seed_init(void) ++{ ++ long elen = 0; ++ char *env = getenv(RNG_ENV_VAR); ++ ++ if (env) { ++ errno = 0; ++ elen = strtol(env, NULL, 10); ++ if (errno) { ++ elen = RNG_BYTES_DEFAULT; ++ debug("bogus value in the %s environment variable, " ++ "using %li bytes from /dev/random\n", ++ RNG_ENV_VAR, RNG_BYTES_DEFAULT); ++ } ++ } ++ ++ if (elen || fips_mode()) ++ rand_file = "/dev/random"; ++ else ++ rand_file = "/dev/urandom"; ++ ++ rand_bytes = MAX(elen, RNG_BYTES_DEFAULT); ++} ++ ++void ++linux_seed(void) ++{ ++ long len; ++ if (!rand_file) ++ linux_seed_init(); ++ ++ errno = 0; ++ len = RAND_load_file(rand_file, rand_bytes); ++ if (len != rand_bytes) { ++ if (errno) ++ fatal ("cannot read from %s, %s", rand_file, strerror(errno)); ++ else ++ fatal ("EOF reading %s", rand_file); ++ } ++} +diff --git a/openssh-7.2p2/openbsd-compat/port-linux.h b/openssh-7.2p2/openbsd-compat/port-linux.h +--- a/openssh-7.2p2/openbsd-compat/port-linux.h ++++ b/openssh-7.2p2/openbsd-compat/port-linux.h +@@ -14,16 +14,20 @@ + * 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. + */ + + #ifndef _PORT_LINUX_H + #define _PORT_LINUX_H + ++extern long rand_bytes; ++extern char *rand_file; ++void linux_seed(void); ++ + #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 *); + #endif + +diff --git a/openssh-7.2p2/ssh-add.1 b/openssh-7.2p2/ssh-add.1 +--- a/openssh-7.2p2/ssh-add.1 ++++ b/openssh-7.2p2/ssh-add.1 +@@ -166,16 +166,30 @@ or related script. + (Note that on some machines it + may be necessary to redirect the input from + .Pa /dev/null + to make this work.) + .It Ev SSH_AUTH_SOCK + Identifies the path of a + .Ux Ns -domain + socket used to communicate with the agent. ++.It Ev SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .El + .Sh FILES + .Bl -tag -width Ds + .It Pa ~/.ssh/identity + Contains the protocol version 1 RSA authentication identity of the user. + .It Pa ~/.ssh/id_dsa + Contains the protocol version 2 DSA authentication identity of the user. + .It Pa ~/.ssh/id_ecdsa +diff --git a/openssh-7.2p2/ssh-agent.1 b/openssh-7.2p2/ssh-agent.1 +--- a/openssh-7.2p2/ssh-agent.1 ++++ b/openssh-7.2p2/ssh-agent.1 +@@ -196,16 +196,33 @@ line terminates. + .Sh FILES + .Bl -tag -width Ds + .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt + .Ux Ns -domain + sockets used to contain the connection to the authentication agent. + These sockets should only be readable by the owner. + The sockets should get automatically removed when the agent exits. + .El ++.Sh ENVIRONMENT ++.Bl -tag -width Ds -compact ++.Pp ++.It Pa SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .Sh SEE ALSO + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-keygen 1 , + .Xr sshd 8 + .Sh AUTHORS + OpenSSH is a derivative of the original and free + ssh 1.2.12 release by Tatu Ylonen. +diff --git a/openssh-7.2p2/ssh-keygen.1 b/openssh-7.2p2/ssh-keygen.1 +--- a/openssh-7.2p2/ssh-keygen.1 ++++ b/openssh-7.2p2/ssh-keygen.1 +@@ -841,16 +841,33 @@ on all machines + where the user wishes to log in using public key authentication. + There is no need to keep the contents of this file secret. + .Pp + .It Pa /etc/moduli + Contains Diffie-Hellman groups used for DH-GEX. + The file format is described in + .Xr moduli 5 . + .El ++.Sh ENVIRONMENT ++.Bl -tag -width Ds -compact ++.Pp ++.It Pa SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .Sh SEE ALSO + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-agent 1 , + .Xr moduli 5 , + .Xr sshd 8 + .Rs + .%R RFC 4716 +diff --git a/openssh-7.2p2/ssh-keysign.8 b/openssh-7.2p2/ssh-keysign.8 +--- a/openssh-7.2p2/ssh-keysign.8 ++++ b/openssh-7.2p2/ssh-keysign.8 +@@ -75,16 +75,33 @@ must be set-uid root if host-based authe + .Pp + .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub + .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub + .It Pa /etc/ssh/ssh_host_ed25519_key-cert.pub + .It Pa /etc/ssh/ssh_host_rsa_key-cert.pub + If these files exist they are assumed to contain public certificate + information corresponding with the private keys above. + .El ++.Sh ENVIRONMENT ++.Bl -tag -width Ds -compact ++.Pp ++.It Pa SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .Sh SEE ALSO + .Xr ssh 1 , + .Xr ssh-keygen 1 , + .Xr ssh_config 5 , + .Xr sshd 8 + .Sh HISTORY + .Nm + first appeared in +diff --git a/openssh-7.2p2/ssh.1 b/openssh-7.2p2/ssh.1 +--- a/openssh-7.2p2/ssh.1 ++++ b/openssh-7.2p2/ssh.1 +@@ -1411,16 +1411,30 @@ reads + and adds lines of the format + .Dq VARNAME=value + to the environment if the file exists and users are allowed to + change their environment. + For more information, see the + .Cm PermitUserEnvironment + option in + .Xr sshd_config 5 . ++.It Ev SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .Sh FILES + .Bl -tag -width Ds -compact + .It Pa ~/.rhosts + This file is used for host-based authentication (see above). + On some machines this file may need to be + world-readable if the user's home directory is on an NFS partition, + because + .Xr sshd 8 +diff --git a/openssh-7.2p2/sshd.8 b/openssh-7.2p2/sshd.8 +--- a/openssh-7.2p2/sshd.8 ++++ b/openssh-7.2p2/sshd.8 +@@ -972,16 +972,33 @@ and not group or world-writable. + .It Pa /var/run/sshd.pid + Contains the process ID of the + .Nm + listening for connections (if there are several daemons running + concurrently for different ports, this contains the process ID of the one + started last). + The content of this file is not sensitive; it can be world-readable. + .El ++.Sh ENVIRONMENT ++.Bl -tag -width Ds -compact ++.Pp ++.It Pa SSH_USE_STRONG_RNG ++The reseeding of the OpenSSL random generator is usually done from ++.Cm /dev/urandom . ++If the ++.Cm SSH_USE_STRONG_RNG ++environment variable is set to value other than ++.Cm 0 ++the OpenSSL random generator is reseeded from ++.Cm /dev/random . ++The number of bytes read is defined by the SSH_USE_STRONG_RNG value. ++Minimum is 6 bytes. ++This setting is not recommended on the computers without the hardware ++random generator because insufficient entropy causes the connection to ++be blocked until enough entropy is available. + .Sh SEE ALSO + .Xr scp 1 , + .Xr sftp 1 , + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-agent 1 , + .Xr ssh-keygen 1 , + .Xr ssh-keyscan 1 , +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -50,16 +50,18 @@ + #ifdef HAVE_SYS_STAT_H + # include + #endif + #ifdef HAVE_SYS_TIME_H + # include + #endif + #include "openbsd-compat/sys-tree.h" + #include "openbsd-compat/sys-queue.h" ++#include "openbsd-compat/port-linux.h" ++ + #include + + #include + #include + #include + #ifdef HAVE_PATHS_H + #include + #endif +@@ -209,16 +211,23 @@ struct { + Key **host_pubkeys; /* all public host keys */ + Key **host_certificates; /* all public host certificates */ + int have_ssh1_key; + int have_ssh2_key; + u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; + } sensitive_data; + + /* ++ * Every RESEED_AFTERth connection triggers call to linux_seed() to re-seed the ++ * random pool. ++ */ ++#define RESEED_AFTER 100 ++static int re_seeding_counter = RESEED_AFTER; ++ ++/* + * Flag indicating whether the RSA server key needs to be regenerated. + * Is set in the SIGALRM handler and cleared when the key is regenerated. + */ + static volatile sig_atomic_t key_do_regen = 0; + + /* This is set to true when a signal is received. */ + static volatile sig_atomic_t received_sighup = 0; + static volatile sig_atomic_t received_sigterm = 0; +@@ -1343,16 +1352,20 @@ server_accept_loop(int *sock_in, int *so + for (j = 0; j < options.max_startups; j++) + if (startup_pipes[j] == -1) { + startup_pipes[j] = startup_p[0]; + if (maxfd < startup_p[0]) + maxfd = startup_p[0]; + startups++; + break; + } ++ if(!(--re_seeding_counter)) { ++ re_seeding_counter = RESEED_AFTER; ++ linux_seed(); ++ } + + /* + * Got connection. Fork a child to handle it, unless + * we are in debugging mode. + */ + if (debug_flag) { + /* + * In debugging mode. Close the listening diff --git a/openssh-7.6p1-send_locale.patch b/openssh-7.2p2-send_locale.patch similarity index 79% rename from openssh-7.6p1-send_locale.patch rename to openssh-7.2p2-send_locale.patch index 6e0b1ff..ac6aa63 100644 --- a/openssh-7.6p1-send_locale.patch +++ b/openssh-7.2p2-send_locale.patch @@ -1,11 +1,11 @@ # HG changeset patch -# Parent f258e8b7fc48a4b0f60fc436dc9ec72423a11bfc +# Parent dfcac093fca4d826a806b9d1c0bdc26e7ae8ee8e send locales in default configuration bnc#65747 -diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config ---- a/openssh-7.6p1/ssh_config -+++ b/openssh-7.6p1/ssh_config +diff --git a/openssh-7.2p2/ssh_config b/openssh-7.2p2/ssh_config +--- a/openssh-7.2p2/ssh_config ++++ b/openssh-7.2p2/ssh_config @@ -26,16 +26,21 @@ Host * # security reasons: Someone stealing the authentification data on the # remote side (the "spoofed" X-server by the remote sshd) can read your @@ -20,18 +20,18 @@ diff --git a/openssh-7.6p1/ssh_config b/openssh-7.6p1/ssh_config + SendEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT + SendEnv LC_IDENTIFICATION LC_ALL + + # RhostsRSAAuthentication no + # RSAAuthentication yes # PasswordAuthentication yes # HostbasedAuthentication no # GSSAPIAuthentication no # GSSAPIDelegateCredentials no # BatchMode no # CheckHostIP yes - # AddressFamily any - # ConnectTimeout 0 -diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config ---- a/openssh-7.6p1/sshd_config -+++ b/openssh-7.6p1/sshd_config -@@ -105,14 +105,19 @@ X11Forwarding yes +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -120,14 +120,19 @@ X11Forwarding yes #VersionAddendum none # no default banner path diff --git a/openssh-7.2p2-sftp_force_permissions.patch b/openssh-7.2p2-sftp_force_permissions.patch new file mode 100644 index 0000000..36aae5d --- /dev/null +++ b/openssh-7.2p2-sftp_force_permissions.patch @@ -0,0 +1,157 @@ +# HG changeset patch +# Parent 7b45c4f3fef6836db00c5b198736cce17290c5cd +additional option for sftp-server to force file mode for new files +FATE#312774 +http://lists.mindrot.org/pipermail/openssh-unix-dev/2010-November/029044.html +http://marc.info/?l=openssh-unix-dev&m=128896838930893 + +diff --git a/openssh-7.2p2/sftp-server.8 b/openssh-7.2p2/sftp-server.8 +--- a/openssh-7.2p2/sftp-server.8 ++++ b/openssh-7.2p2/sftp-server.8 +@@ -33,16 +33,17 @@ + .Bk -words + .Op Fl ehR + .Op Fl d Ar start_directory + .Op Fl f Ar log_facility + .Op Fl l Ar log_level + .Op Fl P Ar blacklisted_requests + .Op Fl p Ar whitelisted_requests + .Op Fl u Ar umask ++.Op Fl m Ar force_file_permissions + .Ek + .Nm + .Fl Q Ar protocol_feature + .Sh DESCRIPTION + .Nm + is a program that speaks the server side of SFTP protocol + to stdout and expects client requests from stdin. + .Nm +@@ -133,16 +134,20 @@ Places this instance of + into a read-only mode. + Attempts to open files for writing, as well as other operations that change + the state of the filesystem, will be denied. + .It Fl u Ar umask + Sets an explicit + .Xr umask 2 + to be applied to newly-created files and directories, instead of the + user's default mask. ++.It Fl m Ar force_file_permissions ++Sets explicit file permissions to be applied to newly-created files instead ++of the default or client requested mode. Numeric values include: ++777, 755, 750, 666, 644, 640, etc. Option -u is ineffective if -m is set. + .El + .Pp + On some systems, + .Nm + must be able to access + .Pa /dev/log + for logging to work, and use of + .Nm +diff --git a/openssh-7.2p2/sftp-server.c b/openssh-7.2p2/sftp-server.c +--- a/openssh-7.2p2/sftp-server.c ++++ b/openssh-7.2p2/sftp-server.c +@@ -73,16 +73,20 @@ static u_int version; + static int init_done; + + /* Disable writes */ + static int readonly; + + /* Requests that are allowed/denied */ + static char *request_whitelist, *request_blacklist; + ++/* Force file permissions */ ++int permforce = 0; ++long permforcemode; ++ + /* portable attributes, etc. */ + typedef struct Stat Stat; + + struct Stat { + char *name; + char *long_name; + Attrib attrib; + }; +@@ -687,16 +691,20 @@ process_open(u_int32_t id) + if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || + (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ + (r = decode_attrib(iqueue, &a)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + debug3("request %u: open flags %d", id, pflags); + flags = flags_from_portable(pflags); + mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; ++ if (permforce == 1) { ++ mode = permforcemode; ++ (void)umask(0); /* so umask does not interfere */ ++ } + logit("open \"%s\" flags %s mode 0%o", + name, string_from_portable(pflags), mode); + if (readonly && + ((flags & O_ACCMODE) == O_WRONLY || + (flags & O_ACCMODE) == O_RDWR)) { + verbose("Refusing open request in read-only mode"); + status = SSH2_FX_PERMISSION_DENIED; + } else { +@@ -1489,17 +1497,18 @@ sftp_server_cleanup_exit(int i) + static void + sftp_server_usage(void) + { + extern char *__progname; + + fprintf(stderr, + "usage: %s [-ehR] [-d start_directory] [-f log_facility] " + "[-l log_level]\n\t[-P blacklisted_requests] " +- "[-p whitelisted_requests] [-u umask]\n" ++ "[-p whitelisted_requests] [-u umask]\n\t" ++ "[-m force_file_permissions]\n" + " %s -Q protocol_feature\n", + __progname, __progname); + exit(1); + } + + int + sftp_server_main(int argc, char **argv, struct passwd *user_pw) + { +@@ -1515,17 +1524,17 @@ 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); + + pw = pwcopy(user_pw); + + while (!skipargs && (ch = getopt(argc, argv, +- "d:f:l:P:p:Q:u:cehR")) != -1) { ++ "d:f:l:P:p:Q:u:m:cehR")) != -1) { + switch (ch) { + case 'Q': + if (strcasecmp(optarg, "requests") != 0) { + fprintf(stderr, "Invalid query type\n"); + exit(1); + } + for (i = 0; handlers[i].handler != NULL; i++) + printf("%s\n", handlers[i].name); +@@ -1575,16 +1584,23 @@ sftp_server_main(int argc, char **argv, + case 'u': + errno = 0; + mask = strtol(optarg, &cp, 8); + if (mask < 0 || mask > 0777 || *cp != '\0' || + cp == optarg || (mask == 0 && errno != 0)) + fatal("Invalid umask \"%s\"", optarg); + (void)umask((mode_t)mask); + break; ++ case 'm': ++ permforce = 1; ++ permforcemode = strtol(optarg, &cp, 8); ++ if (permforcemode < 0 || permforcemode > 0777 || *cp != '\0' || ++ cp == optarg || (permforcemode == 0 && errno != 0)) ++ fatal("Invalid umask \"%s\"", optarg); ++ break; + case 'h': + default: + sftp_server_usage(); + } + } + + log_init(__progname, log_level, log_facility, log_stderr); + diff --git a/openssh-7.2p2-sftp_homechroot.patch b/openssh-7.2p2-sftp_homechroot.patch new file mode 100644 index 0000000..f60ac68 --- /dev/null +++ b/openssh-7.2p2-sftp_homechroot.patch @@ -0,0 +1,366 @@ +# HG changeset patch +# Parent fc81df6f2bf393e45e703c89976c3a0fe6e0a273 +run sftp sessions inside a chroot + +diff --git a/openssh-7.2p2/session.c b/openssh-7.2p2/session.c +--- a/openssh-7.2p2/session.c ++++ b/openssh-7.2p2/session.c +@@ -123,16 +123,18 @@ int do_exec(Session *, const char *); + void do_login(Session *, const char *); + #ifdef LOGIN_NEEDS_UTMPX + static void do_pre_login(Session *s); + #endif + void do_child(Session *, const char *); + void do_motd(void); + int check_quietlogin(Session *, const char *); + ++int chroot_no_tree = 0; ++ + static void do_authenticated1(Authctxt *); + static void do_authenticated2(Authctxt *); + + static int session_pty_req(Session *); + + /* import */ + extern ServerOptions options; + extern char *__progname; +@@ -838,16 +840,21 @@ do_exec(Session *s, const char *command) + "subsystem '%.900s'", s->subsys); + } else if (command == NULL) { + snprintf(session_type, sizeof(session_type), "shell"); + } else { + /* NB. we don't log unforced commands to preserve privacy */ + snprintf(session_type, sizeof(session_type), "command"); + } + ++ if ((s->is_subsystem != SUBSYSTEM_INT_SFTP) && chroot_no_tree) { ++ logit("You aren't welcomed, go away!"); ++ exit (1); ++ } ++ + if (s->ttyfd != -1) { + tty = s->tty; + if (strncmp(tty, "/dev/", 5) == 0) + tty += 5; + } + + verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", + session_type, +@@ -1492,58 +1499,123 @@ do_nologin(struct passwd *pw) + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stderr); + fclose(f); + } + exit(254); + } + + /* ++ * Test if filesystem is mounted nosuid and nodev ++ */ ++ ++static void ++test_nosuid (char * path, dev_t fs) ++{ ++ FILE *f; ++ struct stat st; ++ char buf[4096], *s, *on, *mountpoint, *opt; ++ int nodev, nosuid; ++ ++ if (!(f = popen ("/bin/mount", "r"))) ++ fatal ("%s: popen(\"/bin/mount\", \"r\"): %s", ++ __func__, strerror (errno)); ++ for (;;) { ++ s = fgets (buf, sizeof (buf), f); ++ if (ferror (f)) ++ fatal ("%s: read from popen: %s", __func__, ++ strerror (errno)); ++ if (!s) { ++ pclose (f); ++ fatal ("cannot find filesystem with the chroot directory"); ++ } ++ (void) strtok (buf, " "); ++ on = strtok (NULL, " "); ++ if (strcmp (on, "on")) { ++ pclose (f); ++ fatal ("bad format of mount output"); ++ } ++ mountpoint = strtok (NULL, " "); ++ if (memcmp (path, mountpoint, strlen (mountpoint))) ++ continue; ++ if (stat(mountpoint, &st) != 0) { ++ pclose (f); ++ fatal("%s: stat(\"%s\"): %s", __func__, ++ mountpoint, strerror(errno)); ++ } ++ if (fs != st.st_dev) ++ continue; ++ nodev = nosuid = 0; ++ for (opt = strtok (NULL, "("); opt; opt = strtok (NULL, " ,)")) { ++ if (!strcmp (opt, "nodev")) ++ nodev = 1; ++ else if (!strcmp (opt, "nosuid")) ++ nosuid = 1; ++ else if (!strcmp (opt, "noexec")) ++ nosuid = 1; ++ if (nodev && nosuid) { ++ pclose (f); ++ return; ++ } ++ } ++ fatal ("chroot into directory without nodev and either noexec or nosuid"); ++ } ++} ++ ++/* + * Chroot into a directory after checking it for safety: all path components + * must be root-owned directories with strict permissions. + */ + static void + safely_chroot(const char *path, uid_t uid) + { + const char *cp; + char component[PATH_MAX]; + struct stat st; ++ int last; + + if (*path != '/') + fatal("chroot path does not begin at root"); + if (strlen(path) >= sizeof(component)) + fatal("chroot path too long"); + + /* + * Descend the path, checking that each component is a + * root-owned directory with strict permissions. + */ + for (cp = path; cp != NULL;) { +- if ((cp = strchr(cp, '/')) == NULL) ++ if (last = ((cp = strchr(cp, '/')) == NULL)) + strlcpy(component, path, sizeof(component)); + else { + cp++; + memcpy(component, path, cp - path); + component[cp - path] = '\0'; + } + + debug3("%s: checking '%s'", __func__, component); + + if (stat(component, &st) != 0) + fatal("%s: stat(\"%s\"): %s", __func__, + component, strerror(errno)); +- if (st.st_uid != 0 || (st.st_mode & 022) != 0) ++ if ((st.st_uid != 0 || (st.st_mode & 022) != 0) && !(last && st.st_uid == uid)) + fatal("bad ownership or modes for chroot " + "directory %s\"%s\"", + cp == NULL ? "" : "component ", component); + if (!S_ISDIR(st.st_mode)) + fatal("chroot path %s\"%s\" is not a directory", + cp == NULL ? "" : "component ", component); + + } ++ setenv ("TZ", "/etc/localtime", 0); ++ tzset(); ++ ++ if (st.st_uid) { ++ test_nosuid(path, st.st_dev); ++ ++chroot_no_tree; ++ } + + if (chdir(path) == -1) + fatal("Unable to chdir to chroot path \"%s\": " + "%s", path, strerror(errno)); + if (chroot(path) == -1) + fatal("chroot(\"%s\"): %s", path, strerror(errno)); + if (chdir("/") == -1) + fatal("%s: chdir(/) after chroot: %s", +diff --git a/openssh-7.2p2/sftp-chrootenv.h b/openssh-7.2p2/sftp-chrootenv.h +new file mode 100644 +--- /dev/null ++++ b/openssh-7.2p2/sftp-chrootenv.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2009 Jan F Chadima. 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 CHROOTENV_H ++#define CHROOTENV_H ++ ++extern int chroot_no_tree; ++ ++#endif ++ +diff --git a/openssh-7.2p2/sftp-common.c b/openssh-7.2p2/sftp-common.c +--- a/openssh-7.2p2/sftp-common.c ++++ b/openssh-7.2p2/sftp-common.c +@@ -43,16 +43,17 @@ + + #include "xmalloc.h" + #include "ssherr.h" + #include "sshbuf.h" + #include "log.h" + + #include "sftp.h" + #include "sftp-common.h" ++#include "sftp-chrootenv.h" + + /* Clear contents of attributes structure */ + void + attrib_clear(Attrib *a) + { + a->flags = 0; + a->size = 0; + a->uid = 0; +@@ -216,23 +217,23 @@ ls_file(const char *name, const struct s + int ulen, glen, sz = 0; + struct tm *ltime = localtime(&st->st_mtime); + char *user, *group; + char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; + char sbuf[FMT_SCALED_STRSIZE]; + time_t now; + + strmode(st->st_mode, mode); +- if (!remote) { ++ if (!remote && !chroot_no_tree) { + user = user_from_uid(st->st_uid, 0); + } else { + snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); + user = ubuf; + } +- if (!remote) { ++ if (!remote && !chroot_no_tree) { + group = group_from_gid(st->st_gid, 0); + } else { + snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); + group = gbuf; + } + if (ltime != NULL) { + now = time(NULL); + if (now - (365*24*60*60)/2 < st->st_mtime && +diff --git a/openssh-7.2p2/sftp-server-main.c b/openssh-7.2p2/sftp-server-main.c +--- a/openssh-7.2p2/sftp-server-main.c ++++ b/openssh-7.2p2/sftp-server-main.c +@@ -17,22 +17,25 @@ + + #include "includes.h" + + #include + #include + #include + #include + #include ++//#include + + #include "log.h" + #include "sftp.h" + #include "misc.h" + #include "xmalloc.h" + ++int chroot_no_tree = 0; ++ + void + cleanup_exit(int i) + { + sftp_server_cleanup_exit(i); + } + + int + main(int argc, char **argv) +diff --git a/openssh-7.2p2/sftp.c b/openssh-7.2p2/sftp.c +--- a/openssh-7.2p2/sftp.c ++++ b/openssh-7.2p2/sftp.c +@@ -112,16 +112,18 @@ struct complete_ctx { + char **remote_pathp; + }; + + int remote_glob(struct sftp_conn *, const char *, int, + int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ + + extern char *__progname; + ++int chroot_no_tree = 0; ++ + /* Separators for interactive commands */ + #define WHITESPACE " \t\r\n" + + /* ls flags */ + #define LS_LONG_VIEW 0x0001 /* Full view ala ls -l */ + #define LS_SHORT_VIEW 0x0002 /* Single row view ala ls -1 */ + #define LS_NUMERIC_VIEW 0x0004 /* Long view with numeric uid/gid */ + #define LS_NAME_SORT 0x0008 /* Sort by name (default) */ +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -251,16 +251,24 @@ DESCRIPTION + directory on some operating systems (see sftp-server(8) for + details). + + For safety, it is very important that the directory hierarchy be + prevented from modification by other processes on the system + (especially those outside the jail). Misconfiguration can lead + to unsafe environments which sshd(8) cannot detect. + ++ In the special case when only sftp is used, not ssh nor scp, it ++ is possible to use ChrootDirectory %h or ChrootDirectory ++ /some/path/%u. The file system containing this directory must be ++ mounted with options nodev and either nosuid or noexec. The owner ++ of the directory should be the user. The ownership of the other ++ components of the path must fulfill the usual conditions. No adi- ++ tional files are required to be present in the directory. ++ + The default is M-bM-^@M-^\noneM-bM-^@M-^], indicating not to chroot(2). + + Ciphers + Specifies the ciphers allowed. Multiple ciphers must be comma- + separated. If the specified value begins with a M-bM-^@M-^X+M-bM-^@M-^Y character, + then the specified ciphers will be appended to the default set + instead of replacing them. + +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -424,16 +424,27 @@ for details). + .Pp + For safety, it is very important that the directory hierarchy be + prevented from modification by other processes on the system (especially + those outside the jail). + Misconfiguration can lead to unsafe environments which + .Xr sshd 8 + cannot detect. + .Pp ++In the special case when only sftp is used, not ssh nor scp, ++it is possible to use ++.Cm ChrootDirectory ++%h or ++.Cm ChrootDirectory ++/some/path/%u. The file system containing this directory must be ++mounted with options nodev and either nosuid or noexec. The owner of the ++directory should be the user. The ownership of the other components of the path ++must fulfill the usual conditions. No aditional files are required to be present ++in the directory. ++.Pp + The default is + .Dq none , + indicating not to + .Xr chroot 2 . + .It Cm Ciphers + Specifies the ciphers allowed. + Multiple ciphers must be comma-separated. + If the specified value begins with a diff --git a/openssh-7.2p2-sftp_print_diagnostic_messages.patch b/openssh-7.2p2-sftp_print_diagnostic_messages.patch new file mode 100644 index 0000000..825b40d --- /dev/null +++ b/openssh-7.2p2-sftp_print_diagnostic_messages.patch @@ -0,0 +1,130 @@ +# HG changeset patch +# Parent af7fb4f9e794f639262d9847e95c52a74017aaaf +Put back sftp client diagnostic messages in batch mode + +bsc#1023275 + +diff --git a/openssh-7.2p2/sftp.0 b/openssh-7.2p2/sftp.0 +--- a/openssh-7.2p2/sftp.0 ++++ b/openssh-7.2p2/sftp.0 +@@ -162,16 +162,19 @@ DESCRIPTION + VerifyHostKeyDNS + + -P port + Specifies the port to connect to on the remote host. + + -p Preserves modification times, access times, and modes from the + original files transferred. + ++ -Q Not-so-quiet batch mode: forces printing of diagnostic messages ++ in batch mode. ++ + -q Quiet mode: disables the progress meter as well as warning and + diagnostic messages from ssh(1). + + -R num_requests + Specify how many requests may be outstanding at any one time. + Increasing this may slightly improve file transfer speed but will + increase memory usage. The default is 64 outstanding requests. + +diff --git a/openssh-7.2p2/sftp.1 b/openssh-7.2p2/sftp.1 +--- a/openssh-7.2p2/sftp.1 ++++ b/openssh-7.2p2/sftp.1 +@@ -251,16 +251,19 @@ For full details of the options listed b + .It UserKnownHostsFile + .It VerifyHostKeyDNS + .El + .It Fl P Ar port + Specifies the port to connect to on the remote host. + .It Fl p + Preserves modification times, access times, and modes from the + original files transferred. ++.It Fl Q ++Not-so-quiet batch mode: forces printing of diagnostic messages ++in batch mode. + .It Fl q + Quiet mode: disables the progress meter as well as warning and + diagnostic messages from + .Xr ssh 1 . + .It Fl R Ar num_requests + Specify how many requests may be outstanding at any one time. + Increasing this may slightly improve file transfer speed + but will increase memory usage. +diff --git a/openssh-7.2p2/sftp.c b/openssh-7.2p2/sftp.c +--- a/openssh-7.2p2/sftp.c ++++ b/openssh-7.2p2/sftp.c +@@ -79,16 +79,18 @@ FILE* infile; + /* Are we in batchfile mode? */ + int batchmode = 0; + + /* PID of ssh transport process */ + static pid_t sshpid = -1; + + /* Suppress diagnositic messages */ + int quiet = 0; ++/* Force diagnositic messages in batch mode */ ++int loud = 0; + + /* This is set to 0 if the progressmeter is not desired. */ + int showprogress = 1; + + /* When this option is set, we always recursively download/upload directories */ + int global_rflag = 0; + + /* When this option is set, we resume download or upload if possible */ +@@ -2263,32 +2265,35 @@ main(int argc, char **argv) + addargs(&args, "-oForwardAgent no"); + addargs(&args, "-oPermitLocalCommand no"); + addargs(&args, "-oClearAllForwardings yes"); + + ll = SYSLOG_LEVEL_INFO; + infile = stdin; + + while ((ch = getopt(argc, argv, +- "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { ++ "1246afhpQqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { + switch (ch) { + /* Passed through to ssh(1) */ + case '4': + case '6': + case 'C': + addargs(&args, "-%c", ch); + break; + /* Passed through to ssh(1) with argument */ + case 'F': + case 'c': + case 'i': + case 'o': + addargs(&args, "-%c", ch); + addargs(&args, "%s", optarg); + break; ++ case 'Q': ++ loud = 1; ++ break; + case 'q': + ll = SYSLOG_LEVEL_ERROR; + quiet = 1; + showprogress = 0; + addargs(&args, "-%c", ch); + break; + case 'P': + addargs(&args, "-oPort %s", optarg); +@@ -2360,16 +2365,18 @@ main(int argc, char **argv) + ssh_program = optarg; + replacearg(&args, 0, "%s", ssh_program); + break; + case 'h': + default: + usage(); + } + } ++ if (batchmode && loud) ++ quiet = 0; + + if (!isatty(STDERR_FILENO)) + showprogress = 0; + + log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); + + if (sftp_direct == NULL) { + if (optind == argc || argc > (optind + 2)) diff --git a/openssh-7.2p2-ssh_case_insensitive_host_matching.patch b/openssh-7.2p2-ssh_case_insensitive_host_matching.patch new file mode 100644 index 0000000..0705af7 --- /dev/null +++ b/openssh-7.2p2-ssh_case_insensitive_host_matching.patch @@ -0,0 +1,87 @@ +# HG changeset patch +# Parent 1b99f71db584917a37c5e9140bf63dcb860e8b59 +Match hostnames in a case-insensitive manner. + +bsc#1017099 + +diff --git a/openssh-7.2p2/readconf.c b/openssh-7.2p2/readconf.c +--- a/openssh-7.2p2/readconf.c ++++ b/openssh-7.2p2/readconf.c +@@ -526,16 +526,17 @@ execute_in_shell(const char *cmd) + * Parse and execute a Match directive. + */ + static int + match_cfg_line(Options *options, char **condition, struct passwd *pw, + const char *host_arg, const char *original_host, int post_canon, + const char *filename, int linenum) + { + char *arg, *oattrib, *attrib, *cmd, *cp = *condition, *host, *criteria; ++ char *hostlc; + const char *ruser; + int r, port, this_result, result = 1, attributes = 0, negate; + char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; + + /* + * Configuration is likely to be incomplete at this point so we + * must be prepared to use default values. + */ +@@ -546,16 +547,20 @@ match_cfg_line(Options *options, char ** + } else if (options->hostname != NULL) { + /* NB. Please keep in sync with ssh.c:main() */ + host = percent_expand(options->hostname, + "h", host_arg, (char *)NULL); + } else { + host = xstrdup(host_arg); + } + ++ /* match_hostname() requires the hostname to be lowercase */ ++ hostlc = xstrdup(host); ++ lowercase(hostlc); ++ + debug2("checking match for '%s' host %s originally %s", + cp, host, original_host); + while ((oattrib = attrib = strdelim(&cp)) && *attrib != '\0') { + criteria = NULL; + this_result = 1; + if ((negate = attrib[0] == '!')) + attrib++; + /* criteria "all" and "canonical" have no argument */ +@@ -584,18 +589,18 @@ match_cfg_line(Options *options, char ** + } + /* All other criteria require an argument */ + if ((arg = strdelim(&cp)) == NULL || *arg == '\0') { + error("Missing Match criteria for %s", attrib); + result = -1; + goto out; + } + if (strcasecmp(attrib, "host") == 0) { +- criteria = xstrdup(host); +- r = match_hostname(host, arg) == 1; ++ criteria = xstrdup(hostlc); ++ r = match_hostname(hostlc, arg) == 1; + if (r == (negate ? 1 : 0)) + this_result = result = 0; + } else if (strcasecmp(attrib, "originalhost") == 0) { + criteria = xstrdup(original_host); + r = match_hostname(original_host, arg) == 1; + if (r == (negate ? 1 : 0)) + this_result = result = 0; + } else if (strcasecmp(attrib, "user") == 0) { +@@ -658,16 +663,17 @@ match_cfg_line(Options *options, char ** + error("One or more attributes required for Match"); + result = -1; + goto out; + } + out: + if (result != -1) + debug2("match %sfound", result ? "" : "not "); + *condition = cp; ++ free(hostlc); + free(host); + return result; + } + + /* Check and prepare a domain name: removes trailing '.' and lowercases */ + static void + valid_domain(char *name, const char *filename, int linenum) + { diff --git a/openssh-7.2p2-stricter_readonly_sftp.patch b/openssh-7.2p2-stricter_readonly_sftp.patch new file mode 100644 index 0000000..4bd9fc5 --- /dev/null +++ b/openssh-7.2p2-stricter_readonly_sftp.patch @@ -0,0 +1,32 @@ +# HG changeset patch +# Parent 70f144cf46b999eed1eebda70cb27cadc4e49b82 +Stricter checking for write actions in read-only mode in the stfp server +CVE-2017-15906 +bsc#1065000 + +backoported upstream commit 4d827f0d75a53d3952288ab882efbddea7ffadfe + +diff --git a/openssh-7.2p2/sftp-server.c b/openssh-7.2p2/sftp-server.c +--- a/openssh-7.2p2/sftp-server.c ++++ b/openssh-7.2p2/sftp-server.c +@@ -700,18 +700,18 @@ process_open(u_int32_t id) + mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; + if (permforce == 1) { + mode = permforcemode; + (void)umask(0); /* so umask does not interfere */ + } + logit("open \"%s\" flags %s mode 0%o", + name, string_from_portable(pflags), mode); + if (readonly && +- ((flags & O_ACCMODE) == O_WRONLY || +- (flags & O_ACCMODE) == O_RDWR)) { ++ ((flags & O_ACCMODE) != O_RDONLY || ++ (flags & (O_CREAT|O_TRUNC)) != 0)) { + verbose("Refusing open request in read-only mode"); + status = SSH2_FX_PERMISSION_DENIED; + } else { + fd = open(name, flags, mode); + if (fd < 0) { + status = errno_to_portable(errno); + } else { + handle = handle_new(HANDLE_FILE, name, fd, flags, NULL); diff --git a/openssh-7.2p2-systemd-notify.patch b/openssh-7.2p2-systemd-notify.patch new file mode 100644 index 0000000..6afd049 --- /dev/null +++ b/openssh-7.2p2-systemd-notify.patch @@ -0,0 +1,134 @@ +# HG changeset patch +# Parent 1ba8782c9cf18b104779c751839f3a2575c87954 +Send signals to systemd to prevent various race conditions +bsc#1048367 + +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -4326,16 +4326,40 @@ AC_ARG_WITH([kerberos5], + LIBS="$saved_LIBS" + + fi + ] + ) + AC_SUBST([GSSLIBS]) + AC_SUBST([K5LIBS]) + ++# Check whether user wants systemd support ++SYSTEMD_MSG="no" ++AC_ARG_WITH(systemd, ++ [ --with-systemd Enable systemd support], ++ [ if test "x$withval" != "xno" ; then ++ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) ++ if test "$PKGCONFIG" != "no"; then ++ AC_MSG_CHECKING([for libsystemd]) ++ if $PKGCONFIG --exists libsystemd; then ++ SYSTEMD_CFLAGS=`$PKGCONFIG --cflags libsystemd` ++ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` ++ CPPFLAGS="$CPPFLAGS $SYSTEMD_CFLAGS" ++ SSHDLIBS="$SSHDLIBS $SYSTEMD_LIBS" ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if you want systemd support.]) ++ SYSTEMD_MSG="yes" ++ else ++ AC_MSG_RESULT([no]) ++ fi ++ fi ++ fi ] ++) ++ ++ + # Looking for programs, paths and files + + PRIVSEP_PATH=/var/empty + AC_ARG_WITH([privsep-path], + [ --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)], + [ + if test -n "$withval" && test "x$withval" != "xno" && \ + test "x${withval}" != "xyes"; then +@@ -5140,16 +5164,17 @@ echo " KerberosV support + echo " SELinux support: $SELINUX_MSG" + echo " Smartcard support: $SCARD_MSG" + echo " S/KEY support: $SKEY_MSG" + echo " MD5 password support: $MD5_MSG" + echo " libedit support: $LIBEDIT_MSG" + echo " Solaris process contract support: $SPC_MSG" + echo " Solaris project support: $SP_MSG" + echo " Solaris privilege support: $SPP_MSG" ++echo " systemd support: $SYSTEMD_MSG" + echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" + echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" + echo " BSD Auth support: $BSD_AUTH_MSG" + echo " Random number source: $RAND_MSG" + echo " Privsep sandbox style: $SANDBOX_STYLE" + + echo "" + +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -82,16 +82,20 @@ + #include "openbsd-compat/openssl-compat.h" + #endif + + #ifdef HAVE_SECUREWARE + #include + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + #include "xmalloc.h" + #include "ssh.h" + #include "ssh1.h" + #include "ssh2.h" + #include "rsa.h" + #include "sshpty.h" + #include "packet.h" + #include "log.h" +@@ -328,16 +332,20 @@ sighup_handler(int sig) + + /* + * Called from the main program after receiving SIGHUP. + * Restarts the server. + */ + static void + sighup_restart(void) + { ++#ifdef HAVE_SYSTEMD ++ /* Signal systemd that we are reloading */ ++ sd_notify(0, "RELOADING=1"); ++#endif + logit("Received SIGHUP; restarting."); + platform_pre_restart(); + close_listen_socks(); + close_startup_pipes(); + alarm(0); /* alarm timer persists across exec */ + signal(SIGHUP, SIG_IGN); /* will be restored after exec */ + execv(saved_argv[0], saved_argv); + logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], +@@ -2119,16 +2127,21 @@ main(int ac, char **av) + error("Couldn't create pid file \"%s\": %s", + options.pid_file, strerror(errno)); + } else { + fprintf(f, "%ld\n", (long) getpid()); + fclose(f); + } + } + ++#ifdef HAVE_SYSTEMD ++ /* Signal systemd that we are ready to accept connections */ ++ sd_notify(0, "READY=1"); ++#endif ++ + /* Accept a connection and return in a forked child */ + server_accept_loop(&sock_in, &sock_out, + &newsock, config_s); + } + + /* This is the child processing a new connection. */ + setproctitle("%s", "[accepted]"); + diff --git a/openssh-7.2p2-tcpwrappers.patch b/openssh-7.2p2-tcpwrappers.patch new file mode 100644 index 0000000..e6b632d --- /dev/null +++ b/openssh-7.2p2-tcpwrappers.patch @@ -0,0 +1,433 @@ +# HG changeset patch +# Parent 20564b2e34b780c138dbd876c800dd5f28c91c23 +Forward port TCP wrappers support (libwrap) from OpenSSH 6.6p1. Make it +run-time switchable through the new UseTCPWrappers option for sshd. + +diff --git a/openssh-7.2p2/configure.ac b/openssh-7.2p2/configure.ac +--- a/openssh-7.2p2/configure.ac ++++ b/openssh-7.2p2/configure.ac +@@ -1501,16 +1501,72 @@ AC_ARG_WITH([skey], + function takes 4 arguments (NetBSD)])], + [ + AC_MSG_RESULT([no]) + ]) + fi + ] + ) + ++# Check whether user wants TCP wrappers support ++TCPW_MSG="no" ++AC_ARG_WITH([tcp-wrappers], ++ [ --with-tcp-wrappers[[=PATH]] Enable tcpwrappers support (optionally in PATH)], ++ [ ++ if test "x$withval" != "xno" ; then ++ saved_LIBS="$LIBS" ++ saved_LDFLAGS="$LDFLAGS" ++ saved_CPPFLAGS="$CPPFLAGS" ++ if test -n "${withval}" && \ ++ test "x${withval}" != "xyes"; then ++ if test -d "${withval}/lib"; then ++ if test -n "${need_dash_r}"; then ++ LDFLAGS="-L${withval}/lib -R${withval}/lib ${LDFLAGS}" ++ else ++ LDFLAGS="-L${withval}/lib ${LDFLAGS}" ++ fi ++ else ++ if test -n "${need_dash_r}"; then ++ LDFLAGS="-L${withval} -R${withval} ${LDFLAGS}" ++ else ++ LDFLAGS="-L${withval} ${LDFLAGS}" ++ fi ++ fi ++ if test -d "${withval}/include"; then ++ CPPFLAGS="-I${withval}/include ${CPPFLAGS}" ++ else ++ CPPFLAGS="-I${withval} ${CPPFLAGS}" ++ fi ++ fi ++ LIBS="-lwrap $LIBS" ++ AC_MSG_CHECKING([for libwrap]) ++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++#include ++int deny_severity = 0, allow_severity = 0; ++ ]], [[ ++ hosts_access(0); ++ ]])], [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE([LIBWRAP], [1], ++ [Define if you want ++ TCP Wrappers support]) ++ SSHDLIBS="$SSHDLIBS -lwrap" ++ TCPW_MSG="yes" ++ ], [ ++ AC_MSG_ERROR([*** libwrap missing]) ++ ++ ]) ++ LIBS="$saved_LIBS" ++ fi ++ ] ++) ++ + # Check whether user wants to use ldns + LDNS_MSG="no" + AC_ARG_WITH(ldns, + [ --with-ldns[[=PATH]] Use ldns for DNSSEC support (optionally in PATH)], + [ + if test "x$withval" != "xno" ; then + + if test "x$withval" != "xyes" ; then +@@ -5159,16 +5215,17 @@ echo " sshd superuser user PATH + fi + echo " Manpage format: $MANTYPE" + echo " PAM support: $PAM_MSG" + echo " OSF SIA support: $SIA_MSG" + echo " KerberosV support: $KRB5_MSG" + 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" + echo " Solaris project support: $SP_MSG" + echo " Solaris privilege support: $SPP_MSG" + echo " systemd support: $SYSTEMD_MSG" + echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" + echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -173,16 +173,17 @@ initialize_server_options(ServerOptions + options->trusted_user_ca_keys = NULL; + options->authorized_principals_file = NULL; + options->authorized_principals_command = NULL; + options->authorized_principals_command_user = NULL; + options->ip_qos_interactive = -1; + options->ip_qos_bulk = -1; + options->version_addendum = NULL; + options->fingerprint_hash = -1; ++ options->use_tcpwrappers = -1; + } + + /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ + static int + option_clear_or_none(const char *o) + { + return o == NULL || strcasecmp(o, "none") == 0; + } +@@ -392,16 +393,19 @@ fill_default_server_options(ServerOption + 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) + options->fwd_opts.streamlocal_bind_unlink = 0; + if (options->fingerprint_hash == -1) + options->fingerprint_hash = SSH_FP_HASH_DEFAULT; + options->fingerprint_hash = + fips_correct_dgst(options->fingerprint_hash); ++ if (options->use_tcpwrappers == -1) { ++ options->use_tcpwrappers = 0; ++ } + + assemble_algorithms(options); + + /* Turn privilege separation and sandboxing on by default */ + if (use_privsep == -1) + use_privsep = PRIVSEP_ON; + + #define CLEAR_ON_NONE(v) \ +@@ -471,16 +475,17 @@ typedef enum { + sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, + sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, + sKexAlgorithms, sKexDHMin, + sIPQoS, sVersionAddendum, + sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, + sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, + sStreamLocalBindMask, sStreamLocalBindUnlink, + sAllowStreamLocalForwarding, sFingerprintHash, ++ sUseTCPWrappers, + sDeprecated, sUnsupported + } ServerOpCodes; + + #define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */ + #define SSHCFG_MATCH 0x02 /* allowed inside a Match section */ + #define SSHCFG_ALL (SSHCFG_GLOBAL|SSHCFG_MATCH) + + /* Textual representation of the tokens. */ +@@ -622,16 +627,17 @@ static struct { + { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL }, + { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL }, + { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, + { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, + { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, + { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL }, + { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL }, + { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL }, ++ { "usetcpwrappers", sUseTCPWrappers, SSHCFG_GLOBAL }, + { NULL, sBadOption, 0 } + }; + + static struct { + int val; + char *text; + } tunmode_desc[] = { + { SSH_TUNMODE_NO, "no" }, +@@ -1245,16 +1251,20 @@ process_server_config_line(ServerOptions + case sHostbasedAuthentication: + intptr = &options->hostbased_authentication; + goto parse_flag; + + case sHostbasedUsesNameFromPacketOnly: + intptr = &options->hostbased_uses_name_from_packet_only; + goto parse_flag; + ++ case sUseTCPWrappers: ++ intptr = &options->use_tcpwrappers; ++ goto parse_flag; ++ + case sHostbasedAcceptedKeyTypes: + charptr = &options->hostbased_key_types; + parse_keytypes: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", + filename, linenum); + if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1)) +@@ -2400,16 +2410,17 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sCompression, o->compression); + dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); + 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(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); ++ dump_cfg_fmtint(sUseTCPWrappers, o->use_tcpwrappers); + + /* 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(sBanner, o->banner); + dump_cfg_string(sForceCommand, o->adm_forced_command); +diff --git a/openssh-7.2p2/servconf.h b/openssh-7.2p2/servconf.h +--- a/openssh-7.2p2/servconf.h ++++ b/openssh-7.2p2/servconf.h +@@ -196,16 +196,17 @@ typedef struct { + int rekey_interval; + + char *version_addendum; /* Appended to SSH banner */ + + u_int num_auth_methods; + char *auth_methods[MAX_AUTH_METHODS]; + + int fingerprint_hash; ++ int use_tcpwrappers; + } ServerOptions; + + /* Information about the incoming connection as used by Match */ + struct connection_info { + const char *user; + const char *host; /* possibly resolved hostname */ + const char *address; /* remote address */ + const char *laddress; /* local address */ +diff --git a/openssh-7.2p2/sshd.8 b/openssh-7.2p2/sshd.8 +--- a/openssh-7.2p2/sshd.8 ++++ b/openssh-7.2p2/sshd.8 +@@ -875,16 +875,22 @@ This file should be writable only by roo + can, but need not be, world-readable. + .Pp + .It Pa ~/.ssh/rc + Contains initialization routines to be run before + the user's home directory becomes accessible. + This file should be writable only by the user, and need not be + readable by anyone else. + .Pp ++.It Pa /etc/hosts.allow ++.It Pa /etc/hosts.deny ++Access controls that should be enforced by tcp-wrappers are defined here. ++Further details are described in ++.Xr hosts_access 5 . ++.Pp + .It Pa /etc/hosts.equiv + This file is for host-based authentication (see + .Xr ssh 1 ) . + It should only be writable by root. + .Pp + .It Pa /etc/moduli + Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange" + key exchange method. +@@ -998,16 +1004,17 @@ be blocked until enough entropy is avail + .Xr scp 1 , + .Xr sftp 1 , + .Xr ssh 1 , + .Xr ssh-add 1 , + .Xr ssh-agent 1 , + .Xr ssh-keygen 1 , + .Xr ssh-keyscan 1 , + .Xr chroot 2 , ++.Xr hosts_access 5 , + .Xr login.defs 5 , + .Xr moduli 5 , + .Xr sshd_config 5 , + .Xr inetd 8 , + .Xr sftp-server 8 + .Sh AUTHORS + OpenSSH is a derivative of the original and free + ssh 1.2.12 release by Tatu Ylonen. +diff --git a/openssh-7.2p2/sshd.c b/openssh-7.2p2/sshd.c +--- a/openssh-7.2p2/sshd.c ++++ b/openssh-7.2p2/sshd.c +@@ -132,16 +132,23 @@ + #include "ssherr.h" + + #include "fips.h" + + #ifdef USE_SECURITY_SESSION_API + #include + #endif + ++#ifdef LIBWRAP ++#include ++#include ++int allow_severity; ++int deny_severity; ++#endif /* LIBWRAP */ ++ + #ifndef O_NOCTTY + #define O_NOCTTY 0 + #endif + + /* Re-exec fds */ + #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) + #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) + #define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) +@@ -2298,16 +2305,37 @@ main(int ac, char **av) + * the socket goes away. + */ + remote_ip = get_remote_ipaddr(); + + #ifdef SSH_AUDIT_EVENTS + audit_connection_from(remote_ip, remote_port); + #endif + ++#ifdef LIBWRAP ++ if (options.use_tcpwrappers) { ++ 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); + verbose("Connection from %s port %d on %s port %d", + remote_ip, remote_port, laddr, get_local_port()); + free(laddr); + + #ifdef USE_SECURITY_SESSION_API + /* +diff --git a/openssh-7.2p2/sshd_config b/openssh-7.2p2/sshd_config +--- a/openssh-7.2p2/sshd_config ++++ b/openssh-7.2p2/sshd_config +@@ -120,16 +120,17 @@ X11Forwarding yes + #ClientAliveInterval 0 + #ClientAliveCountMax 3 + #UseDNS no + #PidFile /var/run/sshd.pid + #MaxStartups 10:30:100 + #PermitTunnel no + #ChrootDirectory none + #VersionAddendum none ++#UseTCPWrappers yes + + # no default banner path + #Banner none + + # override default of no subsystems + Subsystem sftp /usr/libexec/sftp-server + + # This enables accepting locale enviroment variables LC_* LANG, see sshd_config(5). +diff --git a/openssh-7.2p2/sshd_config.0 b/openssh-7.2p2/sshd_config.0 +--- a/openssh-7.2p2/sshd_config.0 ++++ b/openssh-7.2p2/sshd_config.0 +@@ -1008,16 +1008,27 @@ DESCRIPTION + that has the privilege of the authenticated user. The goal of + privilege separation is to prevent privilege escalation by + containing any corruption within the unprivileged processes. The + argument must be M-bM-^@M-^\yesM-bM-^@M-^], M-bM-^@M-^\noM-bM-^@M-^], or M-bM-^@M-^\sandboxM-bM-^@M-^]. If + UsePrivilegeSeparation is set to M-bM-^@M-^\sandboxM-bM-^@M-^] then the pre- + authentication unprivileged process is subject to additional + restrictions. The default is M-bM-^@M-^\sandboxM-bM-^@M-^]. + ++ UseTCPWrappers ++ When set to "yes" , TCP wrappers (libwrap) are used to determine ++ whether a connection from a remote system should be allowed as ++ specified in hosts_accept(5). The default is "yes". ++ ++ Warning: This functionality has been backported for backward ++ compatibility and should be avoided, since libwrap pulls in a ++ whole load of security issues. Moving to sshd's internal host ++ matching is highly recommended - see the Match keyword for ++ details. ++ + VersionAddendum + Optionally specifies additional text to append to the SSH + protocol banner sent by the server upon connection. The default + is M-bM-^@M-^\noneM-bM-^@M-^]. + + X11DisplayOffset + Specifies the first display number available for sshd(8)'s X11 + forwarding. This prevents sshd from interfering with real X11 +diff --git a/openssh-7.2p2/sshd_config.5 b/openssh-7.2p2/sshd_config.5 +--- a/openssh-7.2p2/sshd_config.5 ++++ b/openssh-7.2p2/sshd_config.5 +@@ -1657,16 +1657,32 @@ or + If + .Cm UsePrivilegeSeparation + is set to + .Dq sandbox + then the pre-authentication unprivileged process is subject to additional + restrictions. + The default is + .Dq sandbox . ++.It Cm UseTCPWrappers ++When set to ++.Dq yes ++, TCP wrappers (libwrap) are used to determine whether a connection from a ++remote system should be allowed as specified in ++.Xr hosts_accept 5 . ++The default is ++.Dq no . ++ ++.Em Warning: This functionality has been backported for backward \ ++compatibility and should be avoided, since libwrap pulls in a whole load of \ ++security issues. ++Moving to sshd's internal host matching is highly ++recommended - see the ++.Cm Match ++keyword for details. + .It Cm VersionAddendum + Optionally specifies additional text to append to the SSH protocol banner + sent by the server upon connection. + The default is + .Dq none . + .It Cm X11DisplayOffset + Specifies the first display number available for + .Xr sshd 8 Ns 's diff --git a/openssh-7.2p2-verify_CIDR_address_ranges.patch b/openssh-7.2p2-verify_CIDR_address_ranges.patch new file mode 100644 index 0000000..b4102cd --- /dev/null +++ b/openssh-7.2p2-verify_CIDR_address_ranges.patch @@ -0,0 +1,175 @@ +# HG changeset patch +# Parent 1b2dad1b57b086d094fe09327fcf1c490475a7cd +Check for invalid CIDR adress masks. +bsc#1005893 + +backported upstream commit: 010359b32659f455fddd2bd85fd7cc4d7a3b994a (7.4) +backported upstream commit: 1a6f9d2e2493d445cd9ee496e6e3c2a2f283f66a +backported upstream commit: fe06b68f824f8f55670442fb31f2c03526dd326c + +diff --git a/openssh-7.2p2/auth.c b/openssh-7.2p2/auth.c +--- a/openssh-7.2p2/auth.c ++++ b/openssh-7.2p2/auth.c +@@ -95,16 +95,17 @@ int auth_debug_init; + * Otherwise true is returned. + */ + int + allowed_user(struct passwd * pw) + { + struct stat st; + const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; + u_int i; ++ int r; + #ifdef USE_SHADOW + struct spwd *spw = NULL; + #endif + + /* Shouldn't be called if pw is NULL, but better safe than sorry... */ + if (!pw || !pw->pw_name) + return 0; + +@@ -183,31 +184,41 @@ allowed_user(struct passwd * pw) + if (options.num_deny_users > 0 || options.num_allow_users > 0 || + options.num_deny_groups > 0 || options.num_allow_groups > 0) { + hostname = get_canonical_hostname(options.use_dns); + ipaddr = get_remote_ipaddr(); + } + + /* Return false if user is listed in DenyUsers */ + if (options.num_deny_users > 0) { +- for (i = 0; i < options.num_deny_users; i++) +- if (match_user(pw->pw_name, hostname, ipaddr, +- options.deny_users[i])) { ++ for (i = 0; i < options.num_deny_users; i++) { ++ r = match_user(pw->pw_name, hostname, ipaddr, ++ options.deny_users[i]); ++ if (r < 0) { ++ fatal("Invalid DenyUsers pattern \"%.100s\"", ++ options.deny_users[i]); ++ } else if (r != 0) { + logit("User %.100s from %.100s not allowed " + "because listed in DenyUsers", + pw->pw_name, hostname); + return 0; + } ++ } + } + /* Return false if AllowUsers isn't empty and user isn't listed there */ + if (options.num_allow_users > 0) { +- for (i = 0; i < options.num_allow_users; i++) +- if (match_user(pw->pw_name, hostname, ipaddr, +- options.allow_users[i])) ++ for (i = 0; i < options.num_allow_users; i++) { ++ r = match_user(pw->pw_name, hostname, ipaddr, ++ options.allow_users[i]); ++ if (r < 0) { ++ fatal("Invalid AllowUsers pattern \"%.100s\"", ++ options.allow_users[i]); ++ } else if (r == 1) + break; ++ } + /* i < options.num_allow_users iff we break for loop */ + if (i >= options.num_allow_users) { + logit("User %.100s from %.100s not allowed because " + "not listed in AllowUsers", pw->pw_name, hostname); + return 0; + } + } + if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { +diff --git a/openssh-7.2p2/match.c b/openssh-7.2p2/match.c +--- a/openssh-7.2p2/match.c ++++ b/openssh-7.2p2/match.c +@@ -186,41 +186,50 @@ match_hostname(const char *host, const c + * successful match. + */ + int + match_host_and_ip(const char *host, const char *ipaddr, + const char *patterns) + { + int mhost, mip; + +- /* error in ipaddr match */ + if ((mip = addr_match_list(ipaddr, patterns)) == -2) +- return -1; +- else if (mip == -1) /* negative ip address match */ +- return 0; ++ return -1; /* error in ipaddr match */ ++ else if (host == NULL || ipaddr == NULL || mip == -1) ++ return 0; /* negative ip address match, or testing pattern */ + + /* negative hostname match */ + if ((mhost = match_hostname(host, patterns)) == -1) + return 0; + /* no match at all */ + if (mhost == 0 && mip == 0) + return 0; + return 1; + } + + /* +- * match user, user@host_or_ip, user@host_or_ip_list against pattern ++ * Match user, user@host_or_ip, user@host_or_ip_list against pattern. ++ * If user, host and ipaddr are all NULL then validate pattern/ ++ * Returns -1 on invalid pattern, 0 on no match, 1 on match. + */ + int + match_user(const char *user, const char *host, const char *ipaddr, + const char *pattern) + { + char *p, *pat; + int ret; + ++ /* test mode */ ++ if (user == NULL && host == NULL && ipaddr == NULL) { ++ if ((p = strchr(pattern, '@')) != NULL && ++ match_host_and_ip(NULL, NULL, p + 1) < 0) ++ return -1; ++ return 0; ++ } ++ + if ((p = strchr(pattern,'@')) == NULL) + return match_pattern(user, pattern); + + pat = xstrdup(pattern); + p = strchr(pat, '@'); + *p++ = '\0'; + + if ((ret = match_pattern(user, pat)) == 1) +diff --git a/openssh-7.2p2/servconf.c b/openssh-7.2p2/servconf.c +--- a/openssh-7.2p2/servconf.c ++++ b/openssh-7.2p2/servconf.c +@@ -1462,28 +1462,34 @@ process_server_config_line(ServerOptions + multistate_ptr = multistate_privsep; + goto parse_multistate; + + case sAllowUsers: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_allow_users >= MAX_ALLOW_USERS) + fatal("%s line %d: too many allow users.", + filename, linenum); ++ if (match_user(NULL, NULL, NULL, arg) == -1) ++ fatal("%s line %d: invalid AllowUsers pattern: " ++ "\"%.100s\"", filename, linenum, arg); + if (!*activep) + continue; + options->allow_users[options->num_allow_users++] = + xstrdup(arg); + } + break; + + case sDenyUsers: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_deny_users >= MAX_DENY_USERS) + fatal("%s line %d: too many deny users.", + filename, linenum); ++ if (match_user(NULL, NULL, NULL, arg) == -1) ++ fatal("%s line %d: invalid DenyUsers pattern: " ++ "\"%.100s\"", filename, linenum, arg); + if (!*activep) + continue; + options->deny_users[options->num_deny_users++] = + xstrdup(arg); + } + break; + + case sAllowGroups: diff --git a/openssh-7.2p2.tar.gz b/openssh-7.2p2.tar.gz new file mode 100644 index 0000000..41c8e60 --- /dev/null +++ b/openssh-7.2p2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a72781d1a043876a224ff1b0032daa4094d87565a68528759c1c2cab5482548c +size 1499808 diff --git a/openssh-7.2p2.tar.gz.asc b/openssh-7.2p2.tar.gz.asc new file mode 100644 index 0000000..53f4de5 --- /dev/null +++ b/openssh-7.2p2.tar.gz.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2 + +iQGsBAABCgAGBQJW4HGiAAoJENPl9Wttkg0w8uUMfRnuvFkcQWBAHy+idRJoL/9W +aPis5PRMJW9ENNLUI2eiSNAhcIsAXKZXv3W2S/tuVrztwYv2+ckrlnaOg2GiMc9N +l66ZFpoZBNNPqImG88rgl28idkvGlYMwaKoE+YihPdB9BvPvHzZUEKdPtf/HsvI/ +2vVTKYg2dbIb7M9h8RIXGvSW8UoGd+6pSbjnJaLHsxVsnBXk8ZYqUgq9PT+slS4d +/yp9OdZr99JcQqIFEpWs9WG93JxBbRBUif6OdymV3JAGJxfrpA0a0EPbiCNedxkY +TB+XZ53ydKx0s9Gv3k2wFfpT4VOIXvlrcPgYyTs7SVbigvT6TomNyK3TUfMQemN6 +rTP4qt4b74cXne7zfcmr/Axmr3+xg1LybJn4L1IIH7TWAjj5dhPHJwqLRw3owaFB +Y8I+5ViCHGNCsBiil8oBOgdg09BITriL76Xs9WEY7+hC+FP/A286ggPDi+De3GPK +L7nB1FZgfo3gCGGJVVAH1i8P/ZZEedJHo/AXAYlNax7g6ZDkfmzt1KaVNhtoNvI= +=yfYj +-----END PGP SIGNATURE----- diff --git a/openssh-7.6p1-allow_root_password_login.patch b/openssh-7.6p1-allow_root_password_login.patch deleted file mode 100644 index 1bd47a9..0000000 --- a/openssh-7.6p1-allow_root_password_login.patch +++ /dev/null @@ -1,95 +0,0 @@ -# HG changeset patch -# Parent af43d436bc7fe818dd976c923ad99b89051eb299 -Allow root login with password by default. While less secure than upstream -default of forbidding access to the root account with a password, we are -temporarily introducing this change to keep the default used in older OpenSSH -versions shipped with SLE. - -diff --git a/openssh-7.6p1/servconf.c b/openssh-7.6p1/servconf.c ---- a/openssh-7.6p1/servconf.c -+++ b/openssh-7.6p1/servconf.c -@@ -218,17 +218,17 @@ fill_default_server_options(ServerOption - options->address_family = AF_UNSPEC; - if (options->listen_addrs == NULL) - add_listen_addr(options, NULL, 0); - if (options->pid_file == NULL) - options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE); - 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) - options->ignore_user_known_hosts = 0; - if (options->print_motd == -1) - options->print_motd = 1; - if (options->print_lastlog == -1) - options->print_lastlog = 1; -diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config ---- a/openssh-7.6p1/sshd_config -+++ b/openssh-7.6p1/sshd_config -@@ -25,17 +25,17 @@ - - # Logging - #SyslogFacility AUTH - #LogLevel INFO - - # Authentication: - - #LoginGraceTime 2m --#PermitRootLogin prohibit-password -+#PermitRootLogin yes - #StrictModes yes - #MaxAuthTries 6 - #MaxSessions 10 - - #PubkeyAuthentication yes - - # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 - # but this is overridden so installations will only check .ssh/authorized_keys -diff --git a/openssh-7.6p1/sshd_config.0 b/openssh-7.6p1/sshd_config.0 ---- a/openssh-7.6p1/sshd_config.0 -+++ b/openssh-7.6p1/sshd_config.0 -@@ -696,17 +696,17 @@ DESCRIPTION - none can be used to prohibit all forwarding requests. The - wildcard M-bM-^@M-^X*M-bM-^@M-^Y can be used for host or port to allow all hosts or - ports, respectively. By default all port forwarding requests are - permitted. - - PermitRootLogin - Specifies whether root can log in using ssh(1). The argument - must be yes, prohibit-password, without-password, -- forced-commands-only, or no. The default is prohibit-password. -+ forced-commands-only, or no. The default is yes. - - If this option is set to prohibit-password or without-password, - password and keyboard-interactive authentication are disabled for - root. - - If this option is set to forced-commands-only, root login with - public key authentication will be allowed, but only if the - command option has been specified (which may be useful for taking -diff --git a/openssh-7.6p1/sshd_config.5 b/openssh-7.6p1/sshd_config.5 ---- a/openssh-7.6p1/sshd_config.5 -+++ b/openssh-7.6p1/sshd_config.5 -@@ -1188,17 +1188,17 @@ Specifies whether root can log in using - The argument must be - .Cm yes , - .Cm prohibit-password , - .Cm without-password , - .Cm forced-commands-only , - or - .Cm no . - The default is --.Cm prohibit-password . -+.Cm yes . - .Pp - If this option is set to - .Cm prohibit-password - or - .Cm without-password , - password and keyboard-interactive authentication are disabled for root. - .Pp - If this option is set to diff --git a/openssh-7.6p1-eal3.patch b/openssh-7.6p1-eal3.patch deleted file mode 100644 index 488fc92..0000000 --- a/openssh-7.6p1-eal3.patch +++ /dev/null @@ -1,27 +0,0 @@ -# HG changeset patch -# Parent 9797aecac98b26573a295fd75128b7c68dfc5aad -fix paths and references in sshd man pages - -diff --git a/openssh-7.6p1/Makefile.in b/openssh-7.6p1/Makefile.in ---- a/openssh-7.6p1/Makefile.in -+++ b/openssh-7.6p1/Makefile.in -@@ -119,17 +119,18 @@ MANTYPE = @MANTYPE@ - CONFIGFILES=sshd_config.out ssh_config.out moduli.out - CONFIGFILES_IN=sshd_config ssh_config moduli - - PATHSUBS = \ - -e 's|/etc/ssh/ssh_config|$(sysconfdir)/ssh_config|g' \ - -e 's|/etc/ssh/ssh_known_hosts|$(sysconfdir)/ssh_known_hosts|g' \ - -e 's|/etc/ssh/sshd_config|$(sysconfdir)/sshd_config|g' \ - -e 's|/usr/libexec|$(libexecdir)|g' \ -- -e 's|/etc/shosts.equiv|$(sysconfdir)/shosts.equiv|g' \ -+ -e 's|login\.conf|login.defs|g' \ -+ -e 's|/etc/shosts.equiv|$(sysconfdir)/ssh/shosts.equiv|g' \ - -e 's|/etc/ssh/ssh_host_key|$(sysconfdir)/ssh_host_key|g' \ - -e 's|/etc/ssh/ssh_host_ecdsa_key|$(sysconfdir)/ssh_host_ecdsa_key|g' \ - -e 's|/etc/ssh/ssh_host_dsa_key|$(sysconfdir)/ssh_host_dsa_key|g' \ - -e 's|/etc/ssh/ssh_host_rsa_key|$(sysconfdir)/ssh_host_rsa_key|g' \ - -e 's|/etc/ssh/ssh_host_ed25519_key|$(sysconfdir)/ssh_host_ed25519_key|g' \ - -e 's|/var/run/sshd.pid|$(piddir)/sshd.pid|g' \ - -e 's|/etc/moduli|$(sysconfdir)/moduli|g' \ - -e 's|/etc/ssh/moduli|$(sysconfdir)/moduli|g' \ diff --git a/openssh-7.6p1-enable_PAM_by_default.patch b/openssh-7.6p1-enable_PAM_by_default.patch deleted file mode 100644 index d1ad001..0000000 --- a/openssh-7.6p1-enable_PAM_by_default.patch +++ /dev/null @@ -1,28 +0,0 @@ -# HG changeset patch -# Parent d47e806f23ad0649ef38b24e8cb9d5617e5d5d15 -# force PAM in defaullt install (this was removed from upstream in 3.8p1) -# bnc#46749 -# --used to be called '-pam-fix2' - -diff --git a/openssh-7.6p1/sshd_config b/openssh-7.6p1/sshd_config ---- a/openssh-7.6p1/sshd_config -+++ b/openssh-7.6p1/sshd_config -@@ -75,17 +75,17 @@ AuthorizedKeysFile .ssh/authorized_keys - # and session processing. If this is enabled, PAM authentication will - # be allowed through the ChallengeResponseAuthentication and - # PasswordAuthentication. Depending on your PAM configuration, - # PAM authentication via ChallengeResponseAuthentication may bypass - # the setting of "PermitRootLogin without-password". - # If you just want the PAM account and session checks to run without - # PAM authentication, then enable this but set PasswordAuthentication - # and ChallengeResponseAuthentication to 'no'. --#UsePAM no -+UsePAM yes - - #AllowAgentForwarding yes - #AllowTcpForwarding yes - #GatewayPorts no - X11Forwarding yes - #X11DisplayOffset 10 - #X11UseLocalhost yes - #PermitTTY yes diff --git a/openssh-7.6p1-seccomp_geteuid.patch b/openssh-7.6p1-seccomp_geteuid.patch deleted file mode 100644 index f0ee178..0000000 --- a/openssh-7.6p1-seccomp_geteuid.patch +++ /dev/null @@ -1,34 +0,0 @@ -# HG changeset patch -# Parent 85f3cd6c8291c7feb0c1e7a0a3645c130532d206 -Add the 'geteuid' syscall to allowed list, since it may becalled on the -mainframes when OpenSSL is using hardware crypto accelerator via libica -(via ibmica) - -bsc#1004258 - -diff --git a/openssh-7.6p1/sandbox-seccomp-filter.c b/openssh-7.6p1/sandbox-seccomp-filter.c ---- a/openssh-7.6p1/sandbox-seccomp-filter.c -+++ b/openssh-7.6p1/sandbox-seccomp-filter.c -@@ -161,16 +161,22 @@ static const struct sock_filter preauth_ - SC_ALLOW(__NR_close), - #endif - #ifdef __NR_exit - SC_ALLOW(__NR_exit), - #endif - #ifdef __NR_exit_group - SC_ALLOW(__NR_exit_group), - #endif -+#ifdef __NR_geteuid -+ SC_ALLOW(__NR_geteuid), -+#endif -+#ifdef __NR_geteuid32 -+ SC_ALLOW(__NR_geteuid32), -+#endif - #ifdef __NR_getpgid - SC_ALLOW(__NR_getpgid), - #endif - #ifdef __NR_getpid - SC_ALLOW(__NR_getpid), - #endif - #ifdef __NR_getrandom - SC_ALLOW(__NR_getrandom), diff --git a/openssh-7.6p1-seccomp_getuid.patch b/openssh-7.6p1-seccomp_getuid.patch deleted file mode 100644 index d2f0111..0000000 --- a/openssh-7.6p1-seccomp_getuid.patch +++ /dev/null @@ -1,31 +0,0 @@ -# HG changeset patch -# Parent 004731f82470b22b9bd563ef3216034cf00ba133 -add 'getuid' syscall to list of allowed ones to prevent the sanboxed thread -from being killed by the seccomp filter - -diff --git a/openssh-7.6p1/sandbox-seccomp-filter.c b/openssh-7.6p1/sandbox-seccomp-filter.c ---- a/openssh-7.6p1/sandbox-seccomp-filter.c -+++ b/openssh-7.6p1/sandbox-seccomp-filter.c -@@ -173,16 +173,22 @@ static const struct sock_filter preauth_ - SC_ALLOW(__NR_getpid), - #endif - #ifdef __NR_getrandom - SC_ALLOW(__NR_getrandom), - #endif - #ifdef __NR_gettimeofday - SC_ALLOW(__NR_gettimeofday), - #endif -+#ifdef __NR_getuid -+ SC_ALLOW(__NR_getuid), -+#endif -+#ifdef __NR_getuid32 -+ SC_ALLOW(__NR_getuid32), -+#endif - #ifdef __NR_madvise - SC_ALLOW(__NR_madvise), - #endif - #ifdef __NR_mmap - SC_ALLOW(__NR_mmap), - #endif - #ifdef __NR_mmap2 - SC_ALLOW(__NR_mmap2), diff --git a/openssh-7.6p1-seccomp_stat.patch b/openssh-7.6p1-seccomp_stat.patch deleted file mode 100644 index 151e352..0000000 --- a/openssh-7.6p1-seccomp_stat.patch +++ /dev/null @@ -1,30 +0,0 @@ -# HG changeset patch -# Parent ddbb42a2825e7e837d7b0387b79a9542c7869174 -Allow the stat() syscall for OpenSSL re-seed patch -(which causes OpenSSL use stat() on some file) - -bnc#912436 - -diff --git a/openssh-7.6p1/sandbox-seccomp-filter.c b/openssh-7.6p1/sandbox-seccomp-filter.c ---- a/openssh-7.6p1/sandbox-seccomp-filter.c -+++ b/openssh-7.6p1/sandbox-seccomp-filter.c -@@ -224,16 +224,19 @@ static const struct sock_filter preauth_ - SC_ALLOW(__NR_select), - #endif - #ifdef __NR_shutdown - SC_ALLOW(__NR_shutdown), - #endif - #ifdef __NR_sigprocmask - SC_ALLOW(__NR_sigprocmask), - #endif -+#ifdef __NR_stat -+ SC_ALLOW(__NR_stat), -+#endif - #ifdef __NR_time - SC_ALLOW(__NR_time), - #endif - #ifdef __NR_write - SC_ALLOW(__NR_write), - #endif - #ifdef __NR_socketcall - SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN), diff --git a/openssh-7.6p1.tar.gz b/openssh-7.6p1.tar.gz deleted file mode 100644 index 8a5be6b..0000000 --- a/openssh-7.6p1.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a323caeeddfe145baaa0db16e98d784b1fbc7dd436a6bf1f479dfd5cd1d21723 -size 1489788 diff --git a/openssh-7.6p1.tar.gz.asc b/openssh-7.6p1.tar.gz.asc deleted file mode 100644 index d49752a..0000000 --- a/openssh-7.6p1.tar.gz.asc +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQHDBAABCgAdFiEEWcIRjtIG2SfmZ+vj0+X1a22SDTAFAlnTtXUACgkQ0+X1a22S -DTCQxgx+MJ1JjIWwVjXUxwpFfjj4aBv5xSqiKqwzGgVjnlmwtpTn+tqdGiACts3K -46fh/8ujknJJ5lBIlWKBfqhKzC7A+gCBaFiLoXiad8Q3NIESbXGxRkuMe6jxFtR7 -SHidUjRqmn1kLCy1TSkj8mqg0/UZ5UZAJcsldQTmEAnxFVbK1l8CLB7vn4rJnj+v -PdbtsSdw8ZHtakkoNHiqQD+mwy+FXY5QcN7IUEX2/E0hKx0wou1S/36j8k89UQf8 -Jbntg31N4EUOQ0fRwuxdRkHSUrJJpPgwWO4XgHw4u9yghsOCYr+X9Pa1+LCtL4PE -o4+08UoD92VORzRETH5Cbtv1XmdUWrpHVHUjVORTgYxVgXbbnoDuzxfsrbfJRRLE -NBsFxodltDxfdljL27PReBqpneWBxNJd6ruaY5wYxhu1qTEcszCGXuSd583TJ49b -hhkWrk5+knErwFdDbtOy+l3L1pvxXvuyIuWl/aXaoVSPDwtPFui94Dl2G7QbSeEb -PQDWU6PReeP+SRsMyYJSoxwgbZIzaQ== -=K6iy ------END PGP SIGNATURE----- diff --git a/openssh-askpass-gnome.changes b/openssh-askpass-gnome.changes index 6c3f71f..5126c21 100644 --- a/openssh-askpass-gnome.changes +++ b/openssh-askpass-gnome.changes @@ -1,9 +1,3 @@ -------------------------------------------------------------------- -Fri Nov 3 12:27:18 UTC 2017 - pcerny@suse.com - -- upgrade to 7.6p1 - see main package changelog for details - ------------------------------------------------------------------- Mon Jul 25 13:45:53 UTC 2016 - meissner@suse.com diff --git a/openssh-askpass-gnome.spec b/openssh-askpass-gnome.spec index 8135f06..f64bb63 100644 --- a/openssh-askpass-gnome.spec +++ b/openssh-askpass-gnome.spec @@ -26,7 +26,7 @@ BuildRequires: openssl-devel BuildRequires: pam-devel BuildRequires: tcpd-devel BuildRequires: update-desktop-files -Version: 7.6p1 +Version: 7.2p2 Release: 0 Requires: openssh = %{version} Summary: A GNOME-Based Passphrase Dialog for OpenSSH diff --git a/openssh.changes b/openssh.changes index 96a6794..1156fe8 100644 --- a/openssh.changes +++ b/openssh.changes @@ -1,581 +1,26 @@ ------------------------------------------------------------------- -Thu Nov 23 13:38:52 UTC 2017 - rbrown@suse.com +Fri Dec 1 13:18:24 UTC 2017 - pcerny@suse.com -- Replace references to /var/adm/fillup-templates with new - %_fillupdir macro (boo#1069468) - -------------------------------------------------------------------- -Fri Nov 3 12:27:18 UTC 2017 - pcerny@suse.com - -- Update to vanilla 7.6p1 - Most important changes (more details below): - * complete removal of the ancient SSHv1 protocol - * sshd(8) cannot run without privilege separation - * removal of suport for arcfourm blowfish and CAST ciphers - and RIPE-MD160 HMAC - * refuse RSA keys shorter than 1024 bits - Distilled upstream log: -- OpenSSH 7.3 - ---- Security - * sshd(8): Mitigate a potential denial-of-service attack - against the system's crypt(3) function via sshd(8). An - attacker could send very long passwords that would cause - excessive CPU use in crypt(3). sshd(8) now refuses to accept - password authentication requests of length greater than 1024 - characters. Independently reported by Tomas Kuthan (Oracle), - Andres Rojas and Javier Nieto. - * sshd(8): Mitigate timing differences in password - authentication that could be used to discern valid from - invalid account names when long passwords were sent and - particular password hashing algorithms are in use on the - server. CVE-2016-6210, reported by EddieEzra.Harari at - verint.com - * ssh(1), sshd(8): Fix observable timing weakness in the CBC - padding oracle countermeasures. Reported by Jean Paul - Degabriele, Kenny Paterson, Torben Hansen and Martin - Albrecht. Note that CBC ciphers are disabled by default and - only included for legacy compatibility. - * ssh(1), sshd(8): Improve operation ordering of MAC - verification for Encrypt-then-MAC (EtM) mode transport MAC - algorithms to verify the MAC before decrypting any - ciphertext. This removes the possibility of timing - differences leaking facts about the plaintext, though no such - leakage has been observed. Reported by Jean Paul Degabriele, - Kenny Paterson, Torben Hansen and Martin Albrecht. - * sshd(8): (portable only) 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. - ---- New Features - * ssh(1): Add a ProxyJump option and corresponding -J - command-line flag to allow simplified indirection through a - one or more SSH bastions or "jump hosts". - * ssh(1): Add an IdentityAgent option to allow specifying - specific agent sockets instead of accepting one from the - environment. - * ssh(1): Allow ExitOnForwardFailure and ClearAllForwardings to - be optionally overridden when using ssh -W. bz#2577 - * ssh(1), sshd(8): Implement support for the IUTF8 terminal - mode as per draft-sgtatham-secsh-iutf8-00. - * ssh(1), sshd(8): Add support for additional fixed - Diffie-Hellman 2K, 4K and 8K groups from - draft-ietf-curdle-ssh-kex-sha2-03. - * ssh-keygen(1), ssh(1), sshd(8): support SHA256 and SHA512 RSA - signatures in certificates; - * ssh(1): Add an Include directive for ssh_config(5) files. - * ssh(1): Permit UTF-8 characters in pre-authentication banners - sent from the server. bz#2058 - ---- Bugfixes - * ssh(1), sshd(8): Reduce the syslog level of some relatively - common protocol events from LOG_CRIT. bz#2585 - * sshd(8): Refuse AuthenticationMethods="" in configurations - and accept AuthenticationMethods=any for the default - behaviour of not requiring multiple authentication. bz#2398 - * sshd(8): Remove obsolete and misleading "POSSIBLE BREAK-IN - ATTEMPT!" message when forward and reverse DNS don't match. - bz#2585 - * ssh(1): Close ControlPersist background process stderr except - in debug mode or when logging to syslog. bz#1988 - * misc: Make PROTOCOL description for - direct-streamlocal@openssh.com channel open messages match - deployed code. bz#2529 - * ssh(1): Deduplicate LocalForward and RemoteForward entries to - fix failures when both ExitOnForwardFailure and hostname - canonicalisation are enabled. bz#2562 - * sshd(8): Remove fallback from moduli to obsolete "primes" - file that was deprecated in 2001. bz#2559. - * sshd_config(5): Correct description of UseDNS: it affects ssh - hostname processing for authorized_keys, not known_hosts; - bz#2554 - * ssh(1): Fix authentication using lone certificate keys in an - agent without corresponding private keys on the filesystem. - bz#2550 - * sshd(8): Send ClientAliveInterval pings when a time-based - RekeyLimit is set; previously keepalive packets were not - being sent. bz#2252 - ---- Portability - * ssh(1), sshd(8): Fix compilation by automatically disabling - ciphers not supported by OpenSSL. bz#2466 - * misc: Fix compilation failures on some versions of AIX's - compiler related to the definition of the VA_COPY macro. - bz#2589 - * sshd(8): Whitelist more architectures to enable the - seccomp-bpf sandbox. bz#2590 - * ssh-agent(1), sftp-server(8): Disable process tracing on - Solaris using setpflags(__PROC_PROTECT, ...). bz#2584 - * sshd(8): On Solaris, don't call Solaris setproject() with - UsePAM=yes it's PAM's responsibility. bz#2425 -- OpenSSH 7.4 - ---- Potentially-incompatible changes - * ssh(1): Remove 3des-cbc from the client's default proposal. - 64-bit block ciphers are not safe in 2016 and we don't want - to wait until attacks like SWEET32 are extended to SSH. As - 3des-cbc was the only mandatory cipher in the SSH RFCs, this - may cause problems connecting to older devices using the - default configuration, but it's highly likely that such - devices already need explicit configuration for key exchange - and hostkey algorithms already anyway. - * sshd(8): Remove support for pre-authentication compression. - Doing compression early in the protocol probably seemed - reasonable in the 1990s, but today it's clearly a bad idea in - terms of both cryptography (cf. multiple compression oracle - attacks in TLS) and attack surface. Pre-auth compression - support has been disabled by default for >10 years. Support - remains in the client. - * ssh-agent will refuse to load PKCS#11 modules outside a - whitelist of trusted paths by default. The path whitelist may - be specified at run-time. - * sshd(8): When a forced-command appears in both a certificate - and an authorized keys/principals command= restriction, sshd - will now refuse to accept the certificate unless they are - identical. The previous (documented) behaviour of having the - certificate forced-command override the other could be a bit - confusing and error-prone. - * sshd(8): Remove the UseLogin configuration directive and - support for having /bin/login manage login sessions. - ---- Security - * ssh-agent(1): Will now refuse to load PKCS#11 modules from - paths outside a trusted whitelist (run-time configurable). - Requests to load modules could be passed via agent forwarding - and an attacker could attempt to load a hostile PKCS#11 - module across the forwarded agent channel: PKCS#11 modules - are shared libraries, so this would result in code execution - on the system running the ssh-agent if the attacker has - control of the forwarded agent-socket (on the host running - the sshd server) and the ability to write to the filesystem - of the host running ssh-agent (usually the host running the - ssh client). Reported by Jann Horn of Project Zero. - * sshd(8): When privilege separation is disabled, forwarded - Unix- domain sockets would be created by sshd(8) with the - privileges of 'root' instead of the authenticated user. This - release refuses Unix-domain socket forwarding when privilege - separation is disabled (Privilege separation has been enabled - by default for 14 years). Reported by Jann Horn of Project - Zero. - * sshd(8): Avoid theoretical leak of host private key material - to privilege-separated child processes via realloc() when - reading keys. No such leak was observed in practice for - normal-sized keys, nor does a leak to the child processes - directly expose key material to unprivileged users. Reported - by Jann Horn of Project Zero. - * sshd(8): The shared memory manager used by pre-authentication - compression support had a bounds checks that could be elided - by some optimising compilers. Additionally, this memory - manager was incorrectly accessible when pre-authentication - compression was disabled. This could potentially allow - attacks against the privileged monitor process from the - sandboxed privilege-separation process (a compromise of the - latter would be required first). This release removes - support for pre-authentication compression from sshd(8). - Reported by Guido Vranken using the Stack unstable - optimisation identification tool - (http://css.csail.mit.edu/stack/) - * sshd(8): Fix denial-of-service condition where an attacker - who sends multiple KEXINIT messages may consume up to 128MB - per connection. Reported by Shi Lei of Gear Team, Qihoo 360. - * sshd(8): Validate address ranges for AllowUser and DenyUsers - directives at configuration load time and refuse to accept - invalid ones. It was previously possible to specify invalid - CIDR address ranges (e.g. user@127.1.2.3/55) and these would - always match, possibly resulting in granting access where it - was not intended. Reported by Laurence Parry. - ---- New Features - * ssh(1): Add a proxy multiplexing mode to ssh(1) inspired by - the version in PuTTY by Simon Tatham. This allows a - multiplexing client to communicate with the master process - using a subset of the SSH packet and channels protocol over a - Unix-domain socket, with the main process acting as a proxy - that translates channel IDs, etc. This allows multiplexing - mode to run on systems that lack file- descriptor passing - (used by current multiplexing code) and potentially, in - conjunction with Unix-domain socket forwarding, with the - client and multiplexing master process on different machines. - Multiplexing proxy mode may be invoked using "ssh -O proxy - ..." - * sshd(8): Add a sshd_config DisableForwarding option that - disables X11, agent, TCP, tunnel and Unix domain socket - forwarding, as well as anything else we might implement in - the future. Like the 'restrict' authorized_keys flag, this is - intended to be a simple and future-proof way of restricting - an account. - * sshd(8), ssh(1): Support the "curve25519-sha256" key exchange - method. This is identical to the currently-supported method - named "curve25519-sha256@libssh.org". - * sshd(8): Improve handling of SIGHUP by checking to see if - sshd is already daemonised at startup and skipping the call - to daemon(3) if it is. This ensures that a SIGHUP restart of - sshd(8) will retain the same process-ID as the initial - execution. sshd(8) will also now unlink the PidFile prior to - SIGHUP restart and re-create it after a successful restart, - rather than leaving a stale file in the case of a - configuration error. bz#2641 - * sshd(8): Allow ClientAliveInterval and ClientAliveCountMax - directives to appear in sshd_config Match blocks. - * sshd(8): Add %-escapes to AuthorizedPrincipalsCommand to - match those supported by AuthorizedKeysCommand (key, key - type, fingerprint, etc.) and a few more to provide access to - the contents of the certificate being offered. - * Added regression tests for string matching, address matching - and string sanitisation functions. - * Improved the key exchange fuzzer harness. - ---- Bugfixes - * ssh(1): Allow IdentityFile to successfully load and use - certificates that have no corresponding bare public key. - bz#2617 certificate id_rsa-cert.pub (and no id_rsa.pub). - * ssh(1): Fix public key authentication when multiple - authentication is in use and publickey is not just the first - method attempted. bz#2642 - * regress: Allow the PuTTY interop tests to run unattended. - bz#2639 - * ssh-agent(1), ssh(1): improve reporting when attempting to - load keys from PKCS#11 tokens with fewer useless log messages - and more detail in debug messages. bz#2610 - * ssh(1): When tearing down ControlMaster connections, don't - pollute stderr when LogLevel=quiet. - * sftp(1): On ^Z wait for underlying ssh(1) to suspend before - suspending sftp(1) to ensure that ssh(1) restores the - terminal mode correctly if suspended during a password - prompt. - * ssh(1): Avoid busy-wait when ssh(1) is suspended during a - password prompt. - * ssh(1), sshd(8): Correctly report errors during sending of - ext- info messages. - * sshd(8): fix NULL-deref crash if sshd(8) received an out-of- - sequence NEWKEYS message. - * sshd(8): Correct list of supported signature algorithms sent - in the server-sig-algs extension. bz#2547 - * sshd(8): Fix sending ext_info message if privsep is disabled. - * sshd(8): more strictly enforce the expected ordering of - privilege separation monitor calls used for authentication - and allow them only when their respective authentication - methods are enabled in the configuration - * sshd(8): Fix uninitialised optlen in getsockopt() call; - harmless on Unix/BSD but potentially crashy on Cygwin. - * Fix false positive reports caused by explicit_bzero(3) not - being recognised as a memory initialiser when compiled with - -fsanitize-memory. - * sshd_config(5): Use 2001:db8::/32, the official IPv6 subnet - for configuration examples. - ---- Portability - * On environments configured with Turkish locales, fall back to - the C/POSIX locale to avoid errors in configuration parsing - caused by that locale's unique handling of the letters 'i' - and 'I'. bz#2643 - * sftp-server(8), ssh-agent(1): Deny ptrace on OS X using - ptrace(PT_DENY_ATTACH, ..) - * ssh(1), sshd(8): Unbreak AES-CTR ciphers on old (~0.9.8) - OpenSSL. - * Fix compilation for libcrypto compiled without RIPEMD160 - support. - * contrib: Add a gnome-ssh-askpass3 with GTK+3 support. bz#2640 - * sshd(8): Improve PRNG reseeding across privilege separation - and force libcrypto to obtain a high-quality seed before - chroot or sandboxing. - * All: Explicitly test for broken strnvis. NetBSD added an - strnvis and unfortunately made it incompatible with the - existing one in OpenBSD and Linux's libbsd (the former having - existed for over ten years). Try to detect this mess, and - assume the only safe option if we're cross compiling. -- OpenSSH 7.5 - ---- Potentially-incompatible changes - * This release deprecates the sshd_config - UsePrivilegeSeparation option, thereby making privilege - separation mandatory. Privilege separation has been on by - default for almost 15 years and sandboxing has been on by - default for almost the last five. - * The format of several log messages emitted by the packet code - has changed to include additional information about the user - and their authentication state. Software that monitors - ssh/sshd logs may need to account for these changes. For - example: - Connection closed by user x 1.1.1.1 port 1234 [preauth] - Connection closed by authenticating user x 10.1.1.1 port 1234 - [preauth] Connection closed by invalid user x 1.1.1.1 port - 1234 [preauth] - Affected messages include connection closure, timeout, remote - disconnection, negotiation failure and some other fatal - messages generated by the packet code. - * [Portable OpenSSH only] This version removes support for - building against OpenSSL versions prior to 1.0.1. OpenSSL - stopped supporting versions prior to 1.0.1 over 12 months ago - (i.e. they no longer receive fixes for security bugs). - ---- Security - * ssh(1), sshd(8): Fix weakness in CBC padding oracle - countermeasures that allowed a variant of the attack fixed in - OpenSSH 7.3 to proceed. Note that the OpenSSH client - disables CBC ciphers by default, sshd offers them as - lowest-preference options and will remove them by default - entriely in the next release. Reported by Jean Paul - Degabriele, Kenny Paterson, Martin Albrecht and Torben Hansen - of Royal Holloway, University of London. - * sftp-client(1): [portable OpenSSH only] On Cygwin, a client - making a recursive file transfer could be maniuplated by a - hostile server to perform a path-traversal attack. creating - or modifying files outside of the intended target directory. - Reported by Jann Horn of Google Project Zero. - ---- New Features - * ssh(1), sshd(8): Support "=-" syntax to easily remove methods - from algorithm lists, e.g. Ciphers=-*cbc. bz#2671 - ---- Bugfixes - * sshd(1): Fix NULL dereference crash when key exchange start - messages are sent out of sequence. - * ssh(1), sshd(8): Allow form-feed characters to appear in - configuration files. - * sshd(8): Fix regression in OpenSSH 7.4 support for the - server-sig-algs extension, where SHA2 RSA signature methods - were not being correctly advertised. bz#2680 - * ssh(1), ssh-keygen(1): Fix a number of case-sensitivity bugs - in known_hosts processing. bz#2591 bz#2685 - * ssh(1): Allow ssh to use certificates accompanied by a - private key file but no corresponding plain *.pub public key. - bz#2617 - * ssh(1): When updating hostkeys using the UpdateHostKeys - option, accept RSA keys if HostkeyAlgorithms contains any RSA - keytype. Previously, ssh could ignore RSA keys when only the - ssh-rsa-sha2-* methods were enabled in HostkeyAlgorithms and - not the old ssh-rsa method. bz#2650 - * ssh(1): Detect and report excessively long configuration file - lines. bz#2651 - * Merge a number of fixes found by Coverity and reported via - Redhat and FreeBSD. Includes fixes for some memory and file - descriptor leaks in error paths. bz#2687 - * ssh-keyscan(1): Correctly hash hosts with a port number. - bz#2692 - * ssh(1), sshd(8): When logging long messages to stderr, don't - truncate "\r\n" if the length of the message exceeds the - buffer. bz#2688 - * ssh(1): Fully quote [host]:port in generated ProxyJump/-J - command- line; avoid confusion over IPv6 addresses and shells - that treat square bracket characters specially. - * ssh-keygen(1): Fix corruption of known_hosts when running - "ssh-keygen -H" on a known_hosts containing already-hashed - entries. - * Fix various fallout and sharp edges caused by removing SSH - protocol 1 support from the server, including the server - banner string being incorrectly terminated with only \n - (instead of \r\n), confusing error messages from ssh-keyscan - bz#2583 and a segfault in sshd if protocol v.1 was enabled - for the client and sshd_config contained references to legacy - keys bz#2686. - * ssh(1), sshd(8): Free fd_set on connection timeout. bz#2683 - * sshd(8): Fix Unix domain socket forwarding for root - (regression in OpenSSH 7.4). - * sftp(1): Fix division by zero crash in "df" output when - server returns zero total filesystem blocks/inodes. - * ssh(1), ssh-add(1), ssh-keygen(1), sshd(8): Translate OpenSSL - errors encountered during key loading to more meaningful - error codes. bz#2522 bz#2523 - * ssh-keygen(1): Sanitise escape sequences in key comments sent - to printf but preserve valid UTF-8 when the locale supports - it; bz#2520 - * ssh(1), sshd(8): Return reason for port forwarding failures - where feasible rather than always "administratively - prohibited". bz#2674 - * sshd(8): Fix deadlock when AuthorizedKeysCommand or - AuthorizedPrincipalsCommand produces a lot of output and a - key is matched early. bz#2655 - * Regression tests: several reliability fixes. bz#2654 bz#2658 - bz#2659 - * ssh(1): Fix typo in ~C error message for bad port forward - cancellation. bz#2672 - * ssh(1): Show a useful error message when included config - files can't be opened; bz#2653 - * sshd(8): Make sshd set GSSAPIStrictAcceptorCheck=yes as the - manual page (previously incorrectly) advertised. bz#2637 - * sshd_config(5): Repair accidentally-deleted mention of %k - token in AuthorizedKeysCommand; bz#2656 - * sshd(8): Remove vestiges of previously removed LOGIN_PROGRAM; - bz#2665 - * ssh-agent(1): Relax PKCS#11 whitelist to include libexec and - common 32-bit compatibility library directories. - * sftp-client(1): Fix non-exploitable integer overflow in - SSH2_FXP_NAME response handling. - * ssh-agent(1): Fix regression in 7.4 of deleting - PKCS#11-hosted keys. It was not possible to delete them - except by specifying their full physical path. bz#2682 - ---- Portability - * sshd(8): Avoid sandbox errors for Linux S390 systems using an - ICA crypto coprocessor. - * sshd(8): Fix non-exploitable weakness in seccomp-bpf sandbox - arg inspection. - * ssh(1): Fix X11 forwarding on OSX where X11 was being started - by launchd. bz#2341 - * ssh-keygen(1), ssh(1), sftp(1): Fix output truncation for - various that contain non-printable characters where the - codeset in use is ASCII. - * build: Fix builds that attempt to link a kerberised libldns. - bz#2603 - * build: Fix compilation problems caused by unconditionally - defining _XOPEN_SOURCE in wide character detection. - * sshd(8): Fix sandbox violations for clock_gettime VSDO - syscall fallback on some Linux/X32 kernels. bz#2142 -- OpenSSH 7.6 - ---- Potentially-incompatible changes - This release includes a number of changes that may affect - existing configurations: - * ssh(1): delete SSH protocol version 1 support, associated - configuration options and documentation. - * ssh(1)/sshd(8): remove support for the hmac-ripemd160 MAC. - * ssh(1)/sshd(8): remove support for the arcfour, blowfish and - CAST ciphers. - * Refuse RSA keys <1024 bits in length and improve reporting - for keys that do not meet this requirement. - * ssh(1): do not offer CBC ciphers by default. - ---- Security - * sftp-server(8): in read-only mode, sftp-server was - incorrectly permitting creation of zero-length files. - Reported by Michal Zalewski. - ---- New Features - * ssh(1): add RemoteCommand option to specify a command in the - ssh config file instead of giving it on the client's command - line. This allows the configuration file to specify the - command that will be executed on the remote host. - * sshd(8): add ExposeAuthInfo option that enables writing - details of the authentication methods used (including public - keys where applicable) to a file that is exposed via a - $SSH_USER_AUTH environment variable in the subsequent - session. - * ssh(1): add support for reverse dynamic forwarding. In this - mode, ssh will act as a SOCKS4/5 proxy and forward - connections to destinations requested by the remote SOCKS - client. This mode is requested using extended syntax for the - -R and RemoteForward options and, because it is implemented - solely at the client, does not require the server be updated - to be supported. - * sshd(8): allow LogLevel directive in sshd_config Match - blocks; bz#2717 - * ssh-keygen(1): allow inclusion of arbitrary string or flag - certificate extensions and critical options. - * ssh-keygen(1): allow ssh-keygen to use a key held in - ssh-agent as a CA when signing certificates. bz#2377 - * ssh(1)/sshd(8): allow IPQoS=none in ssh/sshd to not set an - explicit ToS/DSCP value and just use the operating system - default. - * ssh-add(1): added -q option to make ssh-add quiet on success. - * ssh(1): expand the StrictHostKeyChecking option with two new - settings. The first "accept-new" will automatically accept - hitherto-unseen keys but will refuse connections for changed - or invalid hostkeys. This is a safer subset of the current - behaviour of StrictHostKeyChecking=no. The second setting - "off", is a synonym for the current behaviour of - StrictHostKeyChecking=no: accept new host keys, and continue - connection for hosts with incorrect hostkeys. A future - release will change the meaning of StrictHostKeyChecking=no - to the behaviour of "accept-new". bz#2400 - * ssh(1): add SyslogFacility option to ssh(1) matching the - equivalent option in sshd(8). bz#2705 - ---- Bugfixes - * ssh(1): use HostKeyAlias if specified instead of hostname for - matching host certificate principal names; bz#2728 - * sftp(1): implement sorting for globbed ls; bz#2649 - * ssh(1): add a user@host prefix to client's "Permission - denied" messages, useful in particular when using "stacked" - connections (e.g. ssh -J) where it's not clear which host is - denying. bz#2720 - * ssh(1): accept unknown EXT_INFO extension values that contain - \0 characters. These are legal, but would previously cause - fatal connection errors if received. - * ssh(1)/sshd(8): repair compression statistics printed at - connection exit - * sftp(1): print '?' instead of incorrect link count (that the - protocol doesn't provide) for remote listings. bz#2710 - * ssh(1): return failure rather than fatal() for more cases - during session multiplexing negotiations. Causes the session - to fall back to a non-mux connection if they occur. bz#2707 - * ssh(1): mention that the server may send debug messages to - explain public key authentication problems under some - circumstances; bz#2709 - * Translate OpenSSL error codes to better report incorrect - passphrase errors when loading private keys; bz#2699 - * sshd(8): adjust compatibility patterns for WinSCP to - correctly identify versions that implement only the legacy DH - group exchange scheme. bz#2748 - * ssh(1): print the "Killed by signal 1" message only at - LogLevel verbose so that it is not shown at the default - level; prevents it from appearing during ssh -J and - equivalent ProxyCommand configs. bz#1906, bz#2744 - * ssh-keygen(1): when generating all hostkeys (ssh-keygen -A), - clobber existing keys if they exist but are zero length. - zero-length keys could previously be made if ssh-keygen - failed or was interrupted part way through generating them. - bz#2561 - * ssh(1): fix pledge(2) violation in the escape sequence "~&" - used to place the current session in the background. - * ssh-keyscan(1): avoid double-close() on file descriptors; - bz#2734 - * sshd(8): avoid reliance on shared use of pointers shared - between monitor and child sshd processes. bz#2704 - * sshd_config(8): document available AuthenticationMethods; - bz#2453 - * ssh(1): avoid truncation in some login prompts; bz#2768 - * sshd(8): Fix various compilations failures, inc bz#2767 - * ssh(1): make "--" before the hostname terminate argument - processing after the hostname too. - * ssh-keygen(1): switch from aes256-cbc to aes256-ctr for - encrypting new-style private keys. Fixes problems related to - private key handling for no-OpenSSL builds. bz#2754 - * ssh(1): warn and do not attempt to use keys when the public - and private halves do not match. bz#2737 - * sftp(1): don't print verbose error message when ssh - disconnects from under sftp. bz#2750 - * sshd(8): fix keepalive scheduling problem: activity on a - forwarded port from preventing the keepalive from being sent; - bz#2756 - * sshd(8): when started without root privileges, don't require - the privilege separation user or path to exist. Makes running - the regression tests easier without touching the filesystem. - * Make integrity.sh regression tests more robust against - timeouts. bz#2658 - * ssh(1)/sshd(8): correctness fix for channels implementation: - accept channel IDs greater than 0x7FFFFFFF. - ---- Portability - * sshd(9): drop two more privileges in the Solaris sandbox: - PRIV_DAX_ACCESS and PRIV_SYS_IB_INFO; bz#2723 - * sshd(8): expose list of completed authentication methods to - PAM via the SSH_AUTH_INFO_0 PAM environment variable. bz#2408 - * ssh(1)/sshd(8): fix several problems in the tun/tap - forwarding code, mostly to do with host/network byte order - confusion. bz#2735 - * Add --with-cflags-after and --with-ldflags-after configure - flags to allow setting CFLAGS/LDFLAGS after configure has - completed. These are useful for setting sanitiser/fuzzing - options that may interfere with configure's operation. - * sshd(8): avoid Linux seccomp violations on ppc64le over the - socketcall syscall. - * Fix use of ldns when using ldns-config; bz#2697 - * configure: set cache variables when cross-compiling. The - cross- compiling fallback message was saying it assumed the - test passed, but it wasn't actually set the cache variables - and this would cause later tests to fail. - * Add clang libFuzzer harnesses for public key parsing and - signature verification. -- packaging: - * removal of all 7.2 patches - * first round of rebased patches: - [openssh-7.6p1-X11_trusted_forwarding.patch] - [openssh-7.6p1-allow_root_password_login.patch] - [openssh-7.6p1-blocksigalrm.patch] - [openssh-7.6p1-disable_short_DH_parameters.patch] - [openssh-7.6p1-eal3.patch] - [openssh-7.6p1-enable_PAM_by_default.patch] - [openssh-7.6p1-hostname_changes_when_forwarding_X.patch] - [openssh-7.6p1-lastlog.patch] - [openssh-7.6p1-pam_check_locks.patch] - [openssh-7.6p1-pts_names_formatting.patch] - [openssh-7.6p1-remove_xauth_cookies_on_exit.patch] - [openssh-7.6p1-seccomp_geteuid.patch] - [openssh-7.6p1-seccomp_getuid.patch] - [openssh-7.6p1-seccomp_stat.patch] - [openssh-7.6p1-send_locale.patch] - * not rebased (obsoleted) patches (so far): - [openssh-7.2p2-saveargv-fix.diff] - [openssh-7.2p2-dont_use_pthreads_in_PAM.diff] - [openssh-7.2p2-gssapimitm.diff] - [openssh-7.2p2-eal3_obsolete.diff] - [openssh-7.2p2-default_protocol.diff] - [openssh-7.2p2-additional_seccomp_archs.patch] +- Silent complaints about unsupported key exchange methods + (bsc#1006166) + [openssh-7.2p2-fips_fixes.patch] +- Stricter checking of operations in read-only mode in sftp server + (CVE-2017-15906, bsc#1065000) + [openssh-7.2p2-stricter_readonly_sftp.patch] +- Refine handling of sockets for X11 forwarding to remove + reintroduced CVE-2008-1483 (bsc#1069509) +- systemd integration to work around various race conditions + (bsc#1048367) + [openssh-7.2p2-systemd-notify.patch] +- Add back support for TCP wrappers removed by the upgrade + to 7.2p2. TCP wrappers support will be dripped with the next + version upgrade. + [openssh-7.2p2-tcpwrappers.patch] +- fix regression of (bsc#823710) + [openssh-7.2p2-audit_fixes.patch] +- new switch for printing diagnostic messages in sftp client's + batch mode (bsc#1023275) + [openssh-7.2p2-sftp_print_diagnostic_messages.patch] ------------------------------------------------------------------- Wed Oct 25 15:09:06 UTC 2017 - jsegitz@suse.com diff --git a/openssh.spec b/openssh.spec index b854bee..9d92786 100644 --- a/openssh.spec +++ b/openssh.spec @@ -16,11 +16,6 @@ # -#Compat macro for new _fillupdir macro introduced in Nov 2017 -%if ! %{defined _fillupdir} - %define _fillupdir /var/adm/fillup-templates -%endif - %if 0%{suse_version} >= 1100 %define has_fw_dir 1 %else @@ -98,7 +93,7 @@ PreReq: pwdutils %{fillup_prereq} coreutils %if ! %{uses_systemd} PreReq: %{insserv_prereq} %endif -Version: 7.6p1 +Version: 7.2p2 Release: 0 Summary: Secure Shell Client and Server (Remote Login Program) License: BSD-2-Clause and MIT @@ -118,21 +113,58 @@ Source9: sshd-gen-keys-start Source10: sshd.service Source11: README.FIPS Source12: cavs_driver-ssh.pl -Patch00: openssh-7.6p1-allow_root_password_login.patch -Patch01: openssh-7.6p1-X11_trusted_forwarding.patch -Patch02: openssh-7.6p1-lastlog.patch -Patch03: openssh-7.6p1-enable_PAM_by_default.patch -Patch04: openssh-7.6p1-eal3.patch -Patch05: openssh-7.6p1-blocksigalrm.patch -Patch06: openssh-7.6p1-send_locale.patch -Patch07: openssh-7.6p1-hostname_changes_when_forwarding_X.patch -Patch08: openssh-7.6p1-remove_xauth_cookies_on_exit.patch -Patch09: openssh-7.6p1-pts_names_formatting.patch -Patch10: openssh-7.6p1-pam_check_locks.patch -Patch11: openssh-7.6p1-disable_short_DH_parameters.patch -Patch12: openssh-7.6p1-seccomp_getuid.patch -Patch13: openssh-7.6p1-seccomp_geteuid.patch -Patch14: openssh-7.6p1-seccomp_stat.patch +Patch00: openssh-7.2p2-allow_root_password_login.patch +Patch01: openssh-7.2p2-allow_DSS_by_default.patch +Patch02: openssh-7.2p2-X11_trusted_forwarding.patch +Patch03: openssh-7.2p2-lastlog.patch +Patch04: openssh-7.2p2-enable_PAM_by_default.patch +Patch05: openssh-7.2p2-dont_use_pthreads_in_PAM.patch +Patch06: openssh-7.2p2-eal3.patch +Patch07: openssh-7.2p2-blocksigalrm.patch +Patch08: openssh-7.2p2-send_locale.patch +Patch09: openssh-7.2p2-hostname_changes_when_forwarding_X.patch +Patch10: openssh-7.2p2-remove_xauth_cookies_on_exit.patch +Patch11: openssh-7.2p2-pts_names_formatting.patch +Patch12: openssh-7.2p2-pam_check_locks.patch +Patch13: openssh-7.2p2-disable_short_DH_parameters.patch +Patch14: openssh-7.2p2-seccomp_getuid.patch +Patch15: openssh-7.2p2-seccomp_geteuid.patch +Patch16: openssh-7.2p2-seccomp_stat.patch +Patch17: openssh-7.2p2-additional_seccomp_archs.patch +Patch18: openssh-7.2p2-fips.patch +Patch19: openssh-7.2p2-fips_fixes.patch +Patch21: openssh-7.2p2-cavstest-ctr.patch +Patch22: openssh-7.2p2-cavstest-kdf.patch +Patch23: openssh-7.2p2-seed-prng.patch +Patch24: openssh-7.2p2-gssapi_key_exchange.patch +Patch25: openssh-7.2p2-audit.patch +Patch26: openssh-7.2p2-audit_fixes.patch +Patch27: openssh-7.2p2-audit_seed_prng.patch +Patch28: openssh-7.2p2-login_options.patch +Patch29: openssh-7.2p2-disable_openssl_abi_check.patch +Patch30: openssh-7.2p2-no_fork-no_pid_file.patch +Patch31: openssh-7.2p2-host_ident.patch +Patch32: openssh-7.2p2-sftp_homechroot.patch +Patch33: openssh-7.2p2-sftp_force_permissions.patch +Patch34: openssh-7.2p2-X_forward_with_disabled_ipv6.patch +Patch35: openssh-7.2p2-ldap.patch +Patch36: openssh-7.2p2-IPv6_X_forwarding.patch +Patch37: openssh-7.2p2-ignore_PAM_with_UseLogin.patch +Patch38: openssh-7.2p2-prevent_timing_user_enumeration.patch +Patch39: openssh-7.2p2-limit_password_length.patch +Patch40: openssh-7.2p2-keep_slogin.patch +Patch41: openssh-7.2p2-kex_resource_depletion.patch +Patch42: openssh-7.2p2-verify_CIDR_address_ranges.patch +Patch43: openssh-7.2p2-restrict_pkcs11-modules.patch +Patch44: openssh-7.2p2-prevent_private_key_leakage.patch +Patch45: openssh-7.2p2-secure_unix_sockets_forwarding.patch +Patch46: openssh-7.2p2-ssh_case_insensitive_host_matching.patch +Patch47: openssh-7.2p2-disable_preauth_compression.patch +Patch48: openssh-7.2p2-s390_hw_crypto_syscalls.patch +Patch49: openssh-7.2p2-s390_OpenSSL-ibmpkcs11_syscalls.patch +Patch50: openssh-7.2p2-sftp_print_diagnostic_messages.patch +Patch51: openssh-7.2p2-stricter_readonly_sftp.patch +Patch52: openssh-7.2p2-tcpwrappers.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build Conflicts: nonfreessh Recommends: audit @@ -199,14 +231,51 @@ FIPS140 CAVS tests related parts of the OpenSSH package %patch12 -p2 %patch13 -p2 %patch14 -p2 +%patch15 -p2 +%patch16 -p2 +%patch17 -p2 +%patch18 -p2 +%patch19 -p2 +%patch21 -p2 +%patch22 -p2 +%patch23 -p2 +%patch24 -p2 +%patch25 -p2 +%patch26 -p2 +%patch27 -p2 +%patch28 -p2 +%patch29 -p2 +%patch30 -p2 +%patch31 -p2 +%patch32 -p2 +%patch33 -p2 +%patch34 -p2 +%patch35 -p2 +%patch36 -p2 +%patch37 -p2 +%patch38 -p2 +%patch39 -p2 +%patch40 -p2 +%patch41 -p2 +%patch42 -p2 +%patch43 -p2 +%patch44 -p2 +%patch45 -p2 +%patch46 -p2 +%patch47 -p2 +%patch48 -p2 +%patch49 -p2 +%patch50 -p2 +%patch51 -p2 +%patch52 -p2 cp %{SOURCE3} %{SOURCE4} %{SOURCE11} . %build -### TODO: # set libexec dir in the LDAP patch -### TODO: sed -i.libexec 's,@LIBEXECDIR@,%{_libexecdir}/ssh,' \ -### TODO: $( grep -Rl @LIBEXECDIR@ \ -### TODO: $( grep "^+++" %{PATCH33} | sed -r 's@^.+/([^/\t ]+).*$@\1@' ) -### TODO: ) +# set libexec dir in the LDAP patch +sed -i.libexec 's,@LIBEXECDIR@,%{_libexecdir}/ssh,' \ + $( grep -Rl @LIBEXECDIR@ \ + $( grep "^+++" %{PATCH35} | sed -r 's@^.+/([^/\t ]+).*$@\1@' ) + ) autoreconf -fiv %ifarch s390 s390x %sparc @@ -278,8 +347,8 @@ install -D -m 0755 %{SOURCE1} %{buildroot}%{_initddir}/sshd install -m 0644 %{SOURCE10} . ln -s ../..%{_initddir}/sshd %{buildroot}%{_sbindir}/rcsshd %endif -install -d -m 755 %{buildroot}%{_fillupdir} -install -m 644 %{SOURCE8} %{buildroot}%{_fillupdir} +install -d -m 755 %{buildroot}/var/adm/fillup-templates +install -m 644 %{SOURCE8} %{buildroot}/var/adm/fillup-templates # install shell script to automate the process of adding your public key to a remote machine install -m 755 contrib/ssh-copy-id %{buildroot}%{_bindir} install -m 644 contrib/ssh-copy-id.1 %{buildroot}%{_mandir}/man1 @@ -388,7 +457,7 @@ rpm -q openssh-fips >& /dev/null && DISABLE_RESTART_ON_UPDATE=yes %attr(0444,root,root) %doc %{_mandir}/man8/* %dir %{_sysconfdir}/slp.reg.d %config %{_sysconfdir}/slp.reg.d/ssh.reg -%{_fillupdir}/sysconfig.ssh +/var/adm/fillup-templates/sysconfig.ssh %if %{has_fw_dir} %if %{needs_all_dirs} %dir %{_fwdir} @@ -400,10 +469,10 @@ rpm -q openssh-fips >& /dev/null && DISABLE_RESTART_ON_UPDATE=yes %files helpers %defattr(-,root,root) %attr(0755,root,root) %dir %{_sysconfdir}/ssh -#verify(not mode) %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ldap.conf +%verify(not mode) %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ssh/ldap.conf %attr(0755,root,root) %dir %{_libexecdir}/ssh -#attr(0755,root,root) %{_libexecdir}/ssh/ssh-ldap* -#doc HOWTO.ldap-keys openssh-lpk-openldap.schema openssh-lpk-sun.schema +%attr(0755,root,root) %{_libexecdir}/ssh/ssh-ldap* +%doc HOWTO.ldap-keys openssh-lpk-openldap.schema openssh-lpk-sun.schema %files fips %defattr(-,root,root)